diff --git a/.github/workflows/pr_build.yml b/.github/workflows/pr_build.yml index 4173052fa7e..5b84f4a8e64 100644 --- a/.github/workflows/pr_build.yml +++ b/.github/workflows/pr_build.yml @@ -45,7 +45,7 @@ jobs: runner: ubuntu-latest arch: amd64 build_type: full - qt_source: system + qt_source: source rendering_backend: OpenGL - os: Ubuntu 22.04 Vulkan image: docker.io/overte/overte-full-build:2025-10-24-ubuntu-22.04-amd64 # Container image used for building. Built from /tools/ci-script/linux-ci/Dockerfile_x @@ -64,7 +64,7 @@ jobs: runner: ubuntu-24.04-arm arch: aarch64 build_type: full - qt_source: system + qt_source: source rendering_backend: GLES - os: Ubuntu 22.04 Vulkan image: docker.io/overte/overte-full-build:2026-01-01-ubuntu-22.04-aarch64 diff --git a/CMakeLists.txt b/CMakeLists.txt index 43eb5858a1c..9590b9f2d73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ if (ANDROID) add_definitions(-DANDROID_APP_INTERFACE) endif() else () - set(PLATFORM_QT_COMPONENTS WebEngine Xml) + set(PLATFORM_QT_COMPONENTS WebEngineCore Xml) endif() @@ -168,7 +168,7 @@ else() endif() foreach(PLATFORM_QT_COMPONENT ${PLATFORM_QT_COMPONENTS}) - list(APPEND PLATFORM_QT_LIBRARIES "Qt5::${PLATFORM_QT_COMPONENT}") + list(APPEND PLATFORM_QT_LIBRARIES "Qt6::${PLATFORM_QT_COMPONENT}") endforeach() message(STATUS "Use optimized IK: " ${OVERTE_USE_OPTIMIZED_IK}) diff --git a/android/apps/framePlayer/src/main/cpp/qml/main.qml b/android/apps/framePlayer/src/main/cpp/qml/main.qml index 34c4507f9de..a8fd27d907e 100644 --- a/android/apps/framePlayer/src/main/cpp/qml/main.qml +++ b/android/apps/framePlayer/src/main/cpp/qml/main.qml @@ -1,5 +1,5 @@ import QtQuick 2.2 -import QtQuick.Dialogs 1.1 +import QtQuick.Dialogs import Qt.labs.folderlistmodel 2.11 Item { diff --git a/android/apps/interface/src/main/cpp/native.cpp b/android/apps/interface/src/main/cpp/native.cpp index 42118d89db0..b8ade2f8452 100644 --- a/android/apps/interface/src/main/cpp/native.cpp +++ b/android/apps/interface/src/main/cpp/native.cpp @@ -407,7 +407,7 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_retrieveAccessToken(JN QMetaObject::invokeMethod(accountManager.data(), "requestAccessTokenWithAuthCode", Q_ARG(const QString&, authCode), Q_ARG(const QString&, clientId), - Q_ARG(const QString&, clientSecret), Q_ARG(const QString&, redirectUri)); + Q_GENERIC_ARG(const QString&, clientSecret), Q_GENERIC_ARG(const QString&, redirectUri)); } diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 246fd22cbb0..b7379d39ab9 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -748,7 +748,7 @@ void Agent::processAgentAvatarAudio() { if (_numAvatarSoundSentBytes == (int)audioData->getNumBytes()) { // we're done with this sound object - so set our pointer back to NULL // and our sent bytes back to zero - _avatarSound.clear(); + _avatarSound.reset(); _numAvatarSoundSentBytes = 0; _flushEncoder = true; diff --git a/assignment-client/src/AgentScriptingInterface.h b/assignment-client/src/AgentScriptingInterface.h index 1146c4006ba..277ed3d773f 100644 --- a/assignment-client/src/AgentScriptingInterface.h +++ b/assignment-client/src/AgentScriptingInterface.h @@ -101,7 +101,7 @@ public slots: * }, 1000); * }()); */ - void playAvatarSound(SharedSoundPointer avatarSound) const { _agent->playAvatarSound(avatarSound); } + void playAvatarSound(std::shared_ptr avatarSound) const { _agent->playAvatarSound(avatarSound); } private: Agent* _agent; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 026b2e3dae8..36e1a892293 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -288,7 +288,8 @@ void AssignmentClientMonitor::spawnChildClient() { void AssignmentClientMonitor::checkSpares() { auto nodeList = DependencyManager::get(); - QUuid aSpareId = ""; + // QT6TODO: it was originally composed for empty QString, is it null UUID? + QUuid aSpareId {}; unsigned int spareCount = 0; unsigned int totalCount = 0; diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 731687b6374..d3da1d759cf 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -434,7 +435,7 @@ void AssetServer::completeSetup() { // Check the asset directory to output some information about what we have auto files = _filesDirectory.entryList(QDir::Files); - QRegExp hashFileRegex { AssetUtils::ASSET_HASH_REGEX_STRING }; + QRegularExpression hashFileRegex { AssetUtils::ASSET_HASH_REGEX_STRING }; auto hashedFiles = files.filter(hashFileRegex); qCInfo(asset_server) << "There are" << hashedFiles.size() << "asset files in the asset directory."; diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index a1db33fbc87..112753b84df 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -64,14 +64,14 @@ void ScriptableAvatar::stopAnimation() { QMetaObject::invokeMethod(this, "stopAnimation"); return; } - _animation.clear(); + _animation.reset(); } AnimationDetails ScriptableAvatar::getAnimationDetails() { if (QThread::currentThread() != thread()) { AnimationDetails result; BLOCKING_INVOKE_METHOD(this, "getAnimationDetails", - Q_RETURN_ARG(AnimationDetails, result)); + Q_GENERIC_RETURN_ARG(AnimationDetails, result)); return result; } return _animationDetails; @@ -222,7 +222,7 @@ void ScriptableAvatar::update(float deltatime) { } } else { - _animation.clear(); + _animation.reset(); } } } diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.h b/assignment-client/src/octree/OctreeHeadlessViewer.h index 2c256c8516c..58044bf3d95 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.h +++ b/assignment-client/src/octree/OctreeHeadlessViewer.h @@ -43,14 +43,14 @@ public slots: * @function EntityViewer.setPosition * @param {Vec3} position - The position of the view frustum. */ - void setPosition(const glm::vec3& position) { _hasViewFrustum = true; _viewFrustum.setPosition(position); } + void setPosition(const glm::vec<3,float,glm::packed_highp>& position) { _hasViewFrustum = true; _viewFrustum.setPosition(position); } /*@jsdoc * Sets the orientation of the view frustum. * @function EntityViewer.setOrientation * @param {Quat} orientation - The orientation of the view frustum. */ - void setOrientation(const glm::quat& orientation) { _hasViewFrustum = true; _viewFrustum.setOrientation(orientation); } + void setOrientation(const glm::qua& orientation) { _hasViewFrustum = true; _viewFrustum.setOrientation(orientation); } /*@jsdoc * Sets the radius of the center "keyhole" in the view frustum. @@ -99,14 +99,14 @@ public slots: * @function EntityViewer.getPosition * @returns {Vec3} The position of the view frustum. */ - const glm::vec3& getPosition() const { return _viewFrustum.getPosition(); } + const glm::vec<3,float,glm::packed_highp>& getPosition() const { return _viewFrustum.getPosition(); } /*@jsdoc * Gets the orientation of the view frustum. * @function EntityViewer.getOrientation * @returns {Quat} The orientation of the view frustum. */ - const glm::quat& getOrientation() const { return _viewFrustum.getOrientation(); } + const glm::qua& getOrientation() const { return _viewFrustum.getOrientation(); } // getters for LOD and PPS diff --git a/cmake/macros/MemoryDebugger.cmake b/cmake/macros/MemoryDebugger.cmake index dde55e26ddf..4225ef4f46d 100644 --- a/cmake/macros/MemoryDebugger.cmake +++ b/cmake/macros/MemoryDebugger.cmake @@ -49,9 +49,9 @@ if ( OVERTE_MEMORY_DEBUGGING) # The '-DSTACK_PROTECTOR' argument below disables the usage of this function in the code. This should be fine as it only works on the latest Intel hardware, # and is an optimization that should make no functional difference. - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak -U_FORTIFY_SOURCE -DSTACK_PROTECTOR -fstack-protector-strong -fno-omit-frame-pointer") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak ") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak -U_FORTIFY_SOURCE -DSTACK_PROTECTOR -fstack-protector-strong -fno-omit-frame-pointer -fsanitize-recover=address") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak -fsanitize-recover=address") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address -fsanitize=leak -fsanitize-recover=address") elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") # https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-160 # Supported experimentally starting from VS2019 v16.4, and officially from v16.9. diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 65d8e200618..e4207190602 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -14,7 +14,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) if (WIN32) set(PLUGIN_PATH "plugins") - get_target_property(Qt_Core_Location Qt5::Core LOCATION) + get_target_property(Qt_Core_Location Qt6::Core LOCATION) get_filename_component(QT_BIN_DIR ${Qt_Core_Location} DIRECTORY) find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_BIN_DIR}) @@ -23,7 +23,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) endif () # add a post-build command to call windeployqt to copy Qt plugins - set(CMD "${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} --no-compiler-runtime --no-opengl-sw --no-angle -no-system-d3d-compiler") + set(CMD "${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} --no-compiler-runtime --no-opengl-sw -no-system-d3d-compiler") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/windeploy-${TARGET_NAME}.bat" "${CMD} %*") add_custom_command( diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index aa37b2a3a87..cbc090c9f76 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -64,13 +64,13 @@ macro(SETUP_HIFI_LIBRARY) endif () set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN}) - list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core) + list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core Core5Compat) # find these Qt modules and link them to our own target - find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) + find_package(Qt6 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) - target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) + target_link_libraries(${TARGET_NAME} Qt6::${QT_MODULE}) endforeach() # Don't make scribed shaders, generated entity files, generated pipelines, or QT resource files cumulative diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index a4da4a3a056..4b5dc0eb130 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -28,10 +28,10 @@ macro(SETUP_HIFI_PROJECT) target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN}) - list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core) + list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core Core5Compat) # find these Qt modules and link them to our own target - find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED) + find_package(Qt6 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED) # disable /OPT:REF and /OPT:ICF for the Debug builds # This will prevent the following linker warnings @@ -41,7 +41,7 @@ macro(SETUP_HIFI_PROJECT) endif() foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) - target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) + target_link_libraries(${TARGET_NAME} Qt6::${QT_MODULE}) endforeach() target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/cmake/macros/SetupHifiTestCase.cmake b/cmake/macros/SetupHifiTestCase.cmake index 017a0222f55..4df4829dc4a 100644 --- a/cmake/macros/SetupHifiTestCase.cmake +++ b/cmake/macros/SetupHifiTestCase.cmake @@ -108,10 +108,10 @@ macro(SETUP_HIFI_TESTCASE) list(APPEND ${TARGET_NAME}_DEPENDENCY_QT_MODULES Core Test) # find these Qt modules and link them to our own target - find_package(Qt5 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED) + find_package(Qt6 COMPONENTS ${${TARGET_NAME}_DEPENDENCY_QT_MODULES} REQUIRED) foreach(QT_MODULE ${${TARGET_NAME}_DEPENDENCY_QT_MODULES}) - target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) + target_link_libraries(${TARGET_NAME} Qt6::${QT_MODULE}) endforeach() target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/cmake/macros/TargetQuazip.cmake b/cmake/macros/TargetQuazip.cmake index bf495536475..a37a9197ec8 100644 --- a/cmake/macros/TargetQuazip.cmake +++ b/cmake/macros/TargetQuazip.cmake @@ -1,18 +1,26 @@ -# +# # Copyright 2015 High Fidelity, Inc. +# Copyright 2025 Overte e.V. # Created by Leonardo Murillo on 2015/11/20 # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# macro(TARGET_QUAZIP) + # System QuaZip sets `IMPORTED_GLOBAL` for itself when finding it using find_package(). + # Running find_package() a second time shouldn't do anything, since the package was already found, + # yet it fails with: + # `Attempt to promote imported target "QuaZip::QuaZip" to global scope (by setting IMPORTED_GLOBAL) which is not built in this directory.` + # We avoid this error by guarding against running find_package() multiple times. if(OVERTE_USE_SYSTEM_LIBS) find_package(PkgConfig REQUIRED) - pkg_check_modules(QuaZip REQUIRED quazip1-qt5) + pkg_check_modules(QuaZip REQUIRED quazip1-qt6) target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${QuaZip_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${QuaZip_LINK_LIBRARIES}) else() - find_package(QuaZip-Qt5 REQUIRED) - target_link_libraries(${TARGET_NAME} QuaZip::QuaZip) + if(NOT TARGET QuaZip::QuaZip) # if target doesn't exist. + find_package(QuaZip-Qt6 REQUIRED) + endif() + target_link_libraries(${TARGET_NAME} QuaZip::QuaZip) endif() endmacro() diff --git a/cmake/modules/FindQt5LinguistToolsMacros.cmake b/cmake/modules/FindQt5LinguistToolsMacros.cmake index bd9d55cb160..90e1bbb6dcc 100644 --- a/cmake/modules/FindQt5LinguistToolsMacros.cmake +++ b/cmake/modules/FindQt5LinguistToolsMacros.cmake @@ -30,7 +30,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #============================================================================= -function(QT5_CREATE_TRANSLATION_CUSTOM _qm_files) +function(QT6_CREATE_TRANSLATION_CUSTOM _qm_files) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) @@ -76,7 +76,7 @@ function(QT5_CREATE_TRANSLATION_CUSTOM _qm_files) get_source_file_property(_qm_output_location ${_ts_file} OUTPUT_LOCATION) add_custom_command( OUTPUT ${_tmpts_file} - COMMAND ${Qt5_LUPDATE_EXECUTABLE} + COMMAND ${Qt6_LUPDATE_EXECUTABLE} ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file} COMMAND ${CMAKE_COMMAND} -E copy ${_ts_file} ${_tmpts_file} DEPENDS ${_my_sources} ${_ts_lst_file} VERBATIM) @@ -84,12 +84,12 @@ function(QT5_CREATE_TRANSLATION_CUSTOM _qm_files) set_property(SOURCE ${_tmpts_file} PROPERTY OUTPUT_LOCATION ${_qm_output_location}) endif() endforeach() - qt5_add_translation(${_qm_files} ${_my_temptsfiles}) + qt6_add_translation(${_qm_files} ${_my_temptsfiles}) set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() -function(QT5_ADD_TRANSLATION _qm_files) +function(QT6_ADD_TRANSLATION _qm_files) foreach(_current_FILE ${ARGN}) get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE) get_filename_component(qm ${_abs_FILE} NAME_WE) @@ -102,7 +102,7 @@ function(QT5_ADD_TRANSLATION _qm_files) endif() add_custom_command(OUTPUT ${qm} - COMMAND ${Qt5_LRELEASE_EXECUTABLE} + COMMAND ${Qt6_LRELEASE_EXECUTABLE} ARGS ${_abs_FILE} -qm ${qm} DEPENDS ${_abs_FILE} VERBATIM ) diff --git a/conanfile.py b/conanfile.py index 8f5abfba046..14331c91896 100644 --- a/conanfile.py +++ b/conanfile.py @@ -24,6 +24,7 @@ class Overte(ConanFile): "openssl*:shared": "True", "qt*:shared": "True", "qt*:gui": "True", + "qt*:qt5compat": "True", # Required by Quazip 1.4 and probably us "qt*:qtdeclarative": "True", "qt*:qtimageformats": "True", # WebP texture support "qt*:qtlocation": "True", @@ -38,6 +39,12 @@ class Overte(ConanFile): "qt*:qtwebview": "True", "qt*:qtxmlpatterns": "True", "qt*:qttools": "True", # windeployqt for Windows + "qt*:with_dbus": "True", # Required for Qt on Linux. Can be disabled for Windows. + "fontconfig*:shared": "True", # For Qt on Linux. Building with static fontconfig and freetype fails: https://github.com/conan-io/conan-center-index/issues/17142 + "freetype*:shared": "True", # For Qt on Linux. + "nss*:shared": "True", # Dependency of Qt. "NSS recipe cannot yet build static library." + "nspr*:shared": "True", # NSS, which is a dependency of Qt, cannot link to statis NSPR. + "sqlite*:shared": "True", # Avoid `undefined symbol` errors when building NSS. "glad*:spec": "gl", "glad*:gl_profile": "core", "glad*:gl_version": "4.5", @@ -97,7 +104,7 @@ def requirements(self): elif self.options.qt_source == "aqt": self.requires("qt/5.15.2@overte/aqt", force=True) else: - self.requires("qt/5.15.17-2025.06.07@overte/stable#550a40fc9cbe089ea59a727a3f038a31", force=True) + self.requires("qt/6.8.3", force=True) if self.settings.os == "Windows": self.requires("neuron/12.2@overte/prebuild") @@ -137,8 +144,8 @@ def generate(self): if self.settings.compiler == "gcc": self.output.status("GCC compiler detected, setting default flags.") tc.cache_variables.update({ - "CMAKE_CXX_FLAGS_DEBUG_INIT": "-Og -ggdb3", - "CMAKE_C_FLAGS_DEBUG_INIT": "-Og -ggdb3", + "CMAKE_CXX_FLAGS_DEBUG_INIT": "-O0 -ggdb3", + "CMAKE_C_FLAGS_DEBUG_INIT": "-O0 -ggdb3", "CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT": "-O2 -DNDEBUG -ggdb2", "CMAKE_C_FLAGS_RELWITHDEBINFO_INIT": "-O2 -DNDEBUG -ggdb2", "CMAKE_CXX_FLAGS_RELEASE_INIT": "-O3 -DNDEBUG", @@ -147,8 +154,8 @@ def generate(self): elif self.settings.compiler == "clang": self.output.status("Clang compiler detected, setting default flags.") tc.cache_variables.update({ - "CMAKE_CXX_FLAGS_DEBUG_INIT": "-Og -g", - "CMAKE_C_FLAGS_DEBUG_INIT": "-Og -g", + "CMAKE_CXX_FLAGS_DEBUG_INIT": "-O0 -g", + "CMAKE_C_FLAGS_DEBUG_INIT": "-O0 -g", "CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT": "-O2 -DNDEBUG -g", "CMAKE_C_FLAGS_RELWITHDEBINFO_INIT": "-O2 -DNDEBUG -g", "CMAKE_CXX_FLAGS_RELEASE_INIT": "-O3 -DNDEBUG", diff --git a/domain-server/src/ContentSettingsBackupHandler.cpp b/domain-server/src/ContentSettingsBackupHandler.cpp index 90f95349347..dfc75f7e58b 100644 --- a/domain-server/src/ContentSettingsBackupHandler.cpp +++ b/domain-server/src/ContentSettingsBackupHandler.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #if !defined(__clang__) && defined(__GNUC__) #pragma GCC diagnostic pop @@ -102,7 +103,7 @@ std::pair ContentSettingsBackupHandler::recoverBackup(const QStri zipFile.close(); if (zipFile.getZipError() != UNZ_OK) { - QString errorStr("Failed to unzip " + CONTENT_SETTINGS_BACKUP_FILENAME + ": " + zipFile.getZipError()); + QString errorStr("Failed to unzip " + CONTENT_SETTINGS_BACKUP_FILENAME + ": " + QString::number(zipFile.getZipError())); qCritical() << errorStr; return { false, errorStr }; } diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp index b22b001144f..0d7f86e0341 100644 --- a/domain-server/src/DomainContentBackupManager.cpp +++ b/domain-server/src/DomainContentBackupManager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -81,7 +82,7 @@ void DomainContentBackupManager::parseBackupRules(const QVariantList& backupRule int count = map["maxBackupVersions"].toInt(); auto name = map["Name"].toString(); auto format = name.toLower(); - QRegExp matchDisallowedCharacters { "[^a-zA-Z0-9\\-_]+" }; + QRegularExpression matchDisallowedCharacters { "[^a-zA-Z0-9\\-_]+" }; format.replace(matchDisallowedCharacters, "_"); qCDebug(domain_server) << " Name:" << name; @@ -313,8 +314,8 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, }; if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "recoverFromBackup", Q_ARG(MiniPromise::Promise, promise), - Q_ARG(const QString&, backupName), Q_ARG(const QString&, username)); + QMetaObject::invokeMethod(this, "recoverFromBackup", Q_GENERIC_ARG(MiniPromise::Promise, promise), + Q_GENERIC_ARG(const QString&, backupName), Q_GENERIC_ARG(const QString&, username)); return; } diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 3844db12f57..432e8a57495 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -340,7 +341,7 @@ void DomainGatekeeper::updateNodePermissions() { // authentication and verifiedUsername is only set once they user's key has been confirmed. QString verifiedUsername = node->getPermissions().getVerifiedUserName(); QString verifiedDomainUserName = node->getPermissions().getVerifiedDomainUserName(); - NodePermissions userPerms(NodePermissionsKey(verifiedUsername, 0)); + NodePermissions userPerms(NodePermissionsKey(verifiedUsername, QUuid())); if (node->getPermissions().isAssignment) { // this node is an assignment-client @@ -469,7 +470,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect auto limitedNodeList = DependencyManager::get(); // start with empty permissions - NodePermissions userPerms(NodePermissionsKey(username, 0)); + NodePermissions userPerms(NodePermissionsKey(username, QUuid())); userPerms.setAll(false); // check if this user is on our local machine - if this is true set permissions to those for a "localhost" connection @@ -1094,11 +1095,11 @@ void DomainGatekeeper::getIsGroupMemberJSONCallback(QNetworkReply* requestReply) QJsonObject groups = data["groups"].toObject(); QString username = data["username"].toString(); _server->_settingsManager.clearGroupMemberships(username); - foreach (auto groupID, groups.keys()) { + for (const auto &groupID: groups.keys()) { QJsonObject group = groups[groupID].toObject(); QJsonObject rank = group["rank"].toObject(); QUuid rankID = QUuid(rank["id"].toString()); - _server->_settingsManager.recordGroupMembership(username, groupID, rankID); + _server->_settingsManager.recordGroupMembership(username, QUuid::fromString(groupID), rankID); } } else { qDebug() << "getIsGroupMember api call returned:" << QJsonDocument(jsonObject).toJson(QJsonDocument::Compact); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2f13fe30587..9b71a18027e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -255,7 +255,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : ch.setEnabled(_settingsManager.valueOrDefaultValueForKeyPath(CRASH_REPORTER).toBool()); qRegisterMetaType("DomainServerWebSessionData"); - qRegisterMetaTypeStreamOperators("DomainServerWebSessionData"); + //qRegisterMetaTypeStreamOperators("DomainServerWebSessionData"); // make sure we hear about newly connected nodes from our gatekeeper connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode); @@ -699,7 +699,7 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply* requestReply) { // store the new token to the account info auto accountManager = DependencyManager::get(); - accountManager->setTemporaryDomain(id, key); + accountManager->setTemporaryDomain(QUuid::fromString(id), key); // change our domain ID immediately DependencyManager::get()->setSessionUUID(QUuid { id }); @@ -831,7 +831,7 @@ void DomainServer::setupNodeListAndAssignments() { } else { QVariant idValueVariant = _settingsManager.valueForKeyPath(METAVERSE_DOMAIN_ID_KEY_PATH); if (idValueVariant.isValid()) { - nodeList->setSessionUUID(idValueVariant.toString()); + nodeList->setSessionUUID(QUuid::fromString(idValueVariant.toString())); isMetaverseDomain = true; // if we have an ID, we'll assume we're a metaverse domain } else { nodeList->setSessionUUID(QUuid::createUuid()); // Use random UUID @@ -1002,7 +1002,7 @@ bool DomainServer::resetAccountManagerAccessToken() { if (accessToken.isEmpty()) { QVariant accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH); - if (accessTokenVariant.canConvert(QMetaType::QString)) { + if (accessTokenVariant.canConvert(QMetaType(QMetaType::QString))) { accessToken = accessTokenVariant.toString(); } else { qWarning() << "No access token is present. Some operations that use the directory services API will fail."; @@ -1207,7 +1207,7 @@ void DomainServer::createStaticAssignmentsForType(Assignment::Type type, const Q int configCounter = 0; foreach(const QVariant& configVariant, configList) { - if (configVariant.canConvert(QMetaType::QVariantMap)) { + if (configVariant.canConvert(QMetaType(QMetaType::QVariantMap))) { QVariantMap configMap = configVariant.toMap(); // check the config string for a pool @@ -2849,11 +2849,12 @@ std::pair DomainServer::isAuthenticatedRequest(HTTPConnection* c if (_oauthEnable) { QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY); - QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); + QRegularExpression cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); QUuid cookieUUID; - if (cookieString.indexOf(cookieUUIDRegex) != -1) { - cookieUUID = cookieUUIDRegex.cap(1); + auto matches = cookieUUIDRegex.match(cookieString); + if (matches.hasMatch()) { + cookieUUID = QUuid::fromString(matches.captured(1)); } if (_settingsManager.valueForKeyPath(BASIC_AUTH_USERNAME_KEY_PATH).isValid()) { @@ -2950,7 +2951,7 @@ std::pair DomainServer::isAuthenticatedRequest(HTTPConnection* c QString settingsPassword = settingsPasswordVariant.isValid() ? settingsPasswordVariant.toString() : ""; QString hexHeaderPassword = headerPassword.isEmpty() ? - "" : QString(QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex()); + QByteArray("") : QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex(); if (settingsUsername == headerUsername && hexHeaderPassword == settingsPassword) { qCInfo(domain_server_auth) << httpPeerAddress << "- Basic:" << headerUsername << "-" @@ -3025,7 +3026,7 @@ Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileR // setup expiry for cookie to 1 month from today QDateTime cookieExpiry = QDateTime::currentDateTimeUtc().addMonths(1); - QString cookieString = HIFI_SESSION_COOKIE_KEY + "=" + uuidStringWithoutCurlyBraces(cookieUUID.toString()); + QString cookieString = HIFI_SESSION_COOKIE_KEY + "=" + uuidStringWithoutCurlyBraces(cookieUUID); cookieString += "; expires=" + cookieExpiry.toString("ddd, dd MMM yyyy HH:mm:ss") + " GMT"; cookieString += "; domain=" + _hostname + "; path=/"; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index fe13c29df21..7eec5c1c56d 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -256,7 +256,7 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena QVariant* allowedUsers = _configMap.valueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH); if (allowedUsers - && allowedUsers->canConvert(QMetaType::QVariantList) + && allowedUsers->canConvert(QMetaType(QMetaType::QVariantList)) && reinterpret_cast(allowedUsers)->size() > 0) { qDebug() << "Forcing security.restricted_access to TRUE since there was an" @@ -277,7 +277,7 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena // this was prior to change of poorly named entitiesFileName to entitiesFilePath QVariant* persistFileNameVariant = _configMap.valueForKeyPath(ENTITY_SERVER_SETTINGS_KEY + "." + ENTITY_FILE_NAME_KEY); - if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType::QString)) { + if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType(QMetaType::QString))) { QString persistFileName = persistFileNameVariant->toString(); qDebug() << "Migrating persistFilename to persistFilePath for entity-server settings"; @@ -290,7 +290,7 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena // remove the old setting QVariant* entityServerVariant = _configMap.valueForKeyPath(ENTITY_SERVER_SETTINGS_KEY); - if (entityServerVariant && entityServerVariant->canConvert(QMetaType::QVariantMap)) { + if (entityServerVariant && entityServerVariant->canConvert(QMetaType(QMetaType::QVariantMap))) { QVariantMap entityServerMap = entityServerVariant->toMap(); entityServerMap.remove(ENTITY_FILE_NAME_KEY); @@ -307,7 +307,7 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena QVariant* passwordVariant = _configMap.valueForKeyPath(BASIC_AUTH_PASSWORD_KEY_PATH); - if (passwordVariant && passwordVariant->canConvert(QMetaType::QString)) { + if (passwordVariant && passwordVariant->canConvert(QMetaType(QMetaType::QString))) { QString plaintextPassword = passwordVariant->toString(); qDebug() << "Migrating plaintext password to SHA256 hash in domain-server settings."; @@ -343,12 +343,12 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena foreach (QString allowedUser, allowedUsers) { // even if isRestrictedAccess is false, we have to add explicit rows for these users. - _agentPermissions[NodePermissionsKey(allowedUser, 0)].reset(new NodePermissions(allowedUser)); - _agentPermissions[NodePermissionsKey(allowedUser, 0)]->set(NodePermissions::Permission::canConnectToDomain); + _agentPermissions[NodePermissionsKey(allowedUser, QUuid())].reset(new NodePermissions(allowedUser)); + _agentPermissions[NodePermissionsKey(allowedUser, QUuid())]->set(NodePermissions::Permission::canConnectToDomain); } foreach (QString allowedEditor, allowedEditors) { - NodePermissionsKey editorKey(allowedEditor, 0); + NodePermissionsKey editorKey(allowedEditor, QUuid()); if (!_agentPermissions.contains(editorKey)) { _agentPermissions[editorKey].reset(new NodePermissions(allowedEditor)); if (isRestrictedAccess) { @@ -613,13 +613,13 @@ void DomainServerSettingsManager::packPermissionsForMap(QString mapName, // find (or create) the "security" section of the settings map QVariant* security = _configMap.valueForKeyPath("security", true); - if (!security->canConvert(QMetaType::QVariantMap)) { + if (!security->canConvert(QMetaType(QMetaType::QVariantMap))) { (*security) = QVariantMap(); } // find (or create) whichever subsection of "security" we are packing QVariant* permissions = _configMap.valueForKeyPath(keyPath, true); - if (!permissions->canConvert(QMetaType::QVariantList)) { + if (!permissions->canConvert(QMetaType(QMetaType::QVariantList))) { (*permissions) = QVariantList(); } @@ -707,7 +707,7 @@ bool DomainServerSettingsManager::unpackPermissionsForKeypath(const QString& key return false; } - if (!permissions.canConvert(QMetaType::QVariantList)) { + if (!permissions.canConvert(QMetaType(QMetaType::QVariantList))) { qDebug() << "Failed to extract permissions for key path" << keyPath << "from settings."; } @@ -969,7 +969,7 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointergetMachineFingerprint().toString(), 0); + NodePermissionsKey machineFingerprintKey(nodeData->getMachineFingerprint().toString(), QUuid()); // check if there were already permissions for the fingerprint bool hadFingerprintPermissions = hasPermissionsForMachineFingerprint(nodeData->getMachineFingerprint()); @@ -1115,7 +1115,7 @@ NodePermissions DomainServerSettingsManager::getStandardPermissionsForName(const } NodePermissions DomainServerSettingsManager::getPermissionsForName(const QString& name) const { - NodePermissionsKey nameKey = NodePermissionsKey(name, 0); + NodePermissionsKey nameKey = NodePermissionsKey(name, QUuid()); if (_agentPermissions.contains(nameKey)) { return *(_agentPermissions[nameKey].get()); } @@ -1125,7 +1125,7 @@ NodePermissions DomainServerSettingsManager::getPermissionsForName(const QString } NodePermissions DomainServerSettingsManager::getPermissionsForIP(const QHostAddress& address) const { - NodePermissionsKey ipKey = NodePermissionsKey(address.toString(), 0); + NodePermissionsKey ipKey = NodePermissionsKey(address.toString(), QUuid()); if (_ipPermissions.contains(ipKey)) { return *(_ipPermissions[ipKey].get()); } @@ -1135,7 +1135,7 @@ NodePermissions DomainServerSettingsManager::getPermissionsForIP(const QHostAddr } NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString& macAddress) const { - NodePermissionsKey macKey = NodePermissionsKey(macAddress, 0); + NodePermissionsKey macKey = NodePermissionsKey(macAddress, QUuid()); if (_macPermissions.contains(macKey)) { return *(_macPermissions[macKey].get()); } @@ -1145,7 +1145,7 @@ NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString& } NodePermissions DomainServerSettingsManager::getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const { - NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), 0); + NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), QUuid()); if (_machineFingerprintPermissions.contains(fingerprintKey)) { return *(_machineFingerprintPermissions[fingerprintKey].get()); } @@ -1672,7 +1672,7 @@ void DomainServerSettingsManager::updateSetting(const QString& key, const QJsonV QVariant& possibleMap = settingMap[key]; - if (!possibleMap.canConvert(QMetaType::QVariantMap)) { + if (!possibleMap.canConvert(QMetaType(QMetaType::QVariantMap))) { // if this isn't a map then we need to make it one, otherwise we're about to crash qDebug() << "Value at" << key << "was not the expected QVariantMap while updating DS settings" << "- removing existing value and making it a QVariantMap"; @@ -1890,8 +1890,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ // Compare two members of a permissions list bool permissionVariantLessThan(const QVariant &v1, const QVariant &v2) { - if (!v1.canConvert(QMetaType::QVariantMap) || - !v2.canConvert(QMetaType::QVariantMap)) { + if (!v1.canConvert(QMetaType(QMetaType::QVariantMap)) || + !v2.canConvert(QMetaType(QMetaType::QVariantMap))) { return v1.toString() < v2.toString(); } QVariantMap m1 = v1.toMap(); @@ -1916,22 +1916,22 @@ void DomainServerSettingsManager::sortPermissions() { // sort the permission-names QVariant* standardPermissions = _configMap.valueForKeyPath(AGENT_STANDARD_PERMISSIONS_KEYPATH); - if (standardPermissions && standardPermissions->canConvert(QMetaType::QVariantList)) { + if (standardPermissions && standardPermissions->canConvert(QMetaType(QMetaType::QVariantList))) { QList* standardPermissionsList = reinterpret_cast(standardPermissions); std::sort((*standardPermissionsList).begin(), (*standardPermissionsList).end(), permissionVariantLessThan); } QVariant* permissions = _configMap.valueForKeyPath(AGENT_PERMISSIONS_KEYPATH); - if (permissions && permissions->canConvert(QMetaType::QVariantList)) { + if (permissions && permissions->canConvert(QMetaType(QMetaType::QVariantList))) { QList* permissionsList = reinterpret_cast(permissions); std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); } QVariant* groupPermissions = _configMap.valueForKeyPath(GROUP_PERMISSIONS_KEYPATH); - if (groupPermissions && groupPermissions->canConvert(QMetaType::QVariantList)) { + if (groupPermissions && groupPermissions->canConvert(QMetaType(QMetaType::QVariantList))) { QList* permissionsList = reinterpret_cast(groupPermissions); std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); } QVariant* forbiddenPermissions = _configMap.valueForKeyPath(GROUP_FORBIDDENS_KEYPATH); - if (forbiddenPermissions && forbiddenPermissions->canConvert(QMetaType::QVariantList)) { + if (forbiddenPermissions && forbiddenPermissions->canConvert(QMetaType(QMetaType::QVariantList))) { QList* permissionsList = reinterpret_cast(forbiddenPermissions); std::sort((*permissionsList).begin(), (*permissionsList).end(), permissionVariantLessThan); } @@ -2173,11 +2173,11 @@ void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply* re if (jsonObject["status"].toString() == "success") { QJsonObject groups = jsonObject["data"].toObject()["groups"].toObject(); - foreach (auto groupID, groups.keys()) { + for (auto const &groupID: groups.keys()) { QJsonObject group = groups[groupID].toObject(); QJsonArray ranks = group["ranks"].toArray(); - QHash& ranksForGroup = _groupRanks[groupID]; + QHash& ranksForGroup = _groupRanks[QUuid::fromString(groupID)]; QHash idsFromThisUpdate; for (int rankIndex = 0; rankIndex < ranks.size(); rankIndex++) { @@ -2199,7 +2199,7 @@ void DomainServerSettingsManager::apiGetGroupRanksJSONCallback(QNetworkReply* re } // clean up any that went away - foreach (QUuid rankID, ranksForGroup.keys()) { + for (const QUuid &rankID: ranksForGroup.keys()) { if (!idsFromThisUpdate.contains(rankID)) { ranksForGroup.remove(rankID); } diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 3c7959291cb..c443662761b 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -95,25 +95,25 @@ class DomainServerSettingsManager : public QObject { bool containsKeyPath(const QString& keyPath) { return valueForKeyPath(keyPath).isValid(); } // these give access to anonymous/localhost/logged-in settings from the domain-server settings page - bool haveStandardPermissionsForName(const QString& name) const { return _standardAgentPermissions.contains(name, 0); } + bool haveStandardPermissionsForName(const QString& name) const { return _standardAgentPermissions.contains(name, QUuid()); } NodePermissions getStandardPermissionsForName(const NodePermissionsKey& name) const; // these give access to permissions for specific user-names from the domain-server settings page - bool havePermissionsForName(const QString& name) const { return _agentPermissions.contains(name, 0); } + bool havePermissionsForName(const QString& name) const { return _agentPermissions.contains(name, QUuid()); } NodePermissions getPermissionsForName(const QString& name) const; NodePermissions getPermissionsForName(const NodePermissionsKey& key) const { return getPermissionsForName(key.first); } QStringList getAllNames() const; // these give access to permissions for specific IPs from the domain-server settings page - bool hasPermissionsForIP(const QHostAddress& address) const { return _ipPermissions.contains(address.toString(), 0); } + bool hasPermissionsForIP(const QHostAddress& address) const { return _ipPermissions.contains(address.toString(), QUuid()); } NodePermissions getPermissionsForIP(const QHostAddress& address) const; // these give access to permissions for specific MACs from the domain-server settings page - bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); } + bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, QUuid()); } NodePermissions getPermissionsForMAC(const QString& macAddress) const; // these give access to permissions for specific machine fingerprints from the domain-server settings page - bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); } + bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), QUuid()); } NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const; // these give access to permissions for specific groups from the domain-server settings page diff --git a/domain-server/src/EntitiesBackupHandler.cpp b/domain-server/src/EntitiesBackupHandler.cpp index 526bf30a5c6..5346353da30 100644 --- a/domain-server/src/EntitiesBackupHandler.cpp +++ b/domain-server/src/EntitiesBackupHandler.cpp @@ -74,7 +74,7 @@ std::pair EntitiesBackupHandler::recoverBackup(const QString& bac zipFile.close(); if (zipFile.getZipError() != UNZ_OK) { - QString errorStr("Failed to unzip " + ENTITIES_BACKUP_FILENAME + ": " + zipFile.getZipError()); + QString errorStr("Failed to unzip " + ENTITIES_BACKUP_FILENAME + ": " + QString::number(zipFile.getZipError())); qCritical() << errorStr; return { false, errorStr }; } diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index d7d813e3df3..c6fa8134291 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -23,7 +23,7 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c // Read out the protocol version signature from the connect message char* rawBytes; - uint length; + qsizetype length; dataStream.readBytes(rawBytes, length); newHeader.protocolVersion = QByteArray(rawBytes, length); diff --git a/flake.lock b/flake.lock index cc94b9578f5..e94db617d34 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1754487366, - "narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=", + "lastModified": 1767609335, + "narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18", + "rev": "250481aafeb741edfe23d29195671c19b36b6dca", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1756542300, - "narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=", + "lastModified": 1767640445, + "narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d7600c775f877cd87b4f5a831c28aa94137377aa", + "rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5", "type": "github" }, "original": { @@ -36,11 +36,11 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1753579242, - "narHash": "sha256-zvaMGVn14/Zz8hnp4VWT9xVnhc8vuL3TStRqwk22biA=", + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", "owner": "nix-community", "repo": "nixpkgs.lib", - "rev": "0f36c44e01a6129be94e3ade315a5883f0228a6e", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4e95ccfcffd..992c02657b2 100644 --- a/flake.nix +++ b/flake.nix @@ -24,14 +24,15 @@ }: { packages = { - glad = pkgs.callPackage ./nix/glad.nix { }; - etc2comp = pkgs.callPackage ./nix/etc2comp.nix { }; + cmake3 = pkgs.callPackage ./nix/cmake3 { }; + glad = pkgs.callPackage ./nix/glad.nix { cmake = self'.packages.cmake3; }; + etc2comp = pkgs.callPackage ./nix/etc2comp.nix { cmake = self'.packages.cmake3; }; cgltf = pkgs.callPackage ./nix/cgltf.nix { }; artery-font-format = pkgs.callPackage ./nix/artery-font-format.nix { }; - polyvox = pkgs.callPackage ./nix/polyvox.nix { }; + polyvox = pkgs.callPackage ./nix/polyvox.nix { cmake = self'.packages.cmake3; }; gif_creator = pkgs.callPackage ./nix/gif_creator.nix { }; @@ -55,7 +56,7 @@ # TODO: update/remove when overte updates to more modern version draco = pkgs.callPackage ./nix/draco.nix { }; - glm = pkgs.callPackage ./nix/glm.nix { }; + glm = pkgs.callPackage ./nix/glm.nix { cmake = self'.packages.cmake3; }; default = self'.packages.overte-full; }; @@ -67,8 +68,10 @@ ]; inputsFrom = [ self'.packages.overte-full ]; - buildInputs = [ pkgs.libsForQt5.full ]; + buildInputs = [ (pkgs.qt6.env "overte-devenv" [ self'.packages.overte-full.buildInputs ]) ]; + # TODO: remote set QT_QPA_PLATOFORM, when wayland works + QT_QPA_PLATFORM = "xcb"; inherit (self'.packages.overte-full) NVTT_DIR CXXFLAGS diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 92ac16c68bd..62422d20201 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -25,7 +25,7 @@ endfunction() set(CUSTOM_INTERFACE_QRC_PATHS "") find_package( - Qt5 COMPONENTS + Qt6 COMPONENTS Gui Widgets Multimedia Network Qml Quick Svg WebEngineCore WebEngineWidgets ${PLATFORM_QT_COMPONENTS} WebChannel WebSockets @@ -43,9 +43,9 @@ generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources if (ANDROID) # on Android, don't compress the rcc binary - qt5_add_binary_resources(resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}" OPTIONS -no-compress) + qt6_add_binary_resources(resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}" OPTIONS -no-compress) else () - qt5_add_binary_resources(resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}") + qt6_add_binary_resources(resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}") endif() if (OVERTE_BUILD_TOOLS AND JSDOC_ENABLED) @@ -105,7 +105,7 @@ endif () file (GLOB_RECURSE QT_UI_FILES ui/*.ui) source_group("UI Files" FILES ${QT_UI_FILES}) # have qt5 wrap them and generate the appropriate header files -qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") +qt6_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") # add them to the interface source files set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") @@ -113,7 +113,7 @@ set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}") # translation disabled until we strip out the line numbers # set(QM ${TARGET_NAME}_en.qm) # set(TS ${TARGET_NAME}_en.ts) -# qt5_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS}) +# qt6_create_translation_custom(${QM} ${INTERFACE_SRCS} ${QT_UI_FILES} ${TS}) # setup the android parameters that will help us produce an APK if (ANDROID) @@ -295,11 +295,13 @@ if (ANDROID) target_link_libraries(${TARGET_NAME} ${ANDROID_LOG_LIB}) endif () +find_package(Qt6GuiPrivate) + target_link_libraries( ${TARGET_NAME} - Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::Widgets - Qt5::Qml Qt5::Quick Qt5::Svg - Qt5::WebChannel Qt5::WebEngineCore Qt5::WebEngineWidgets + Qt6::Gui Qt6::GuiPrivate Qt6::Network Qt6::Multimedia Qt6::Widgets + Qt6::Qml Qt6::Quick Qt6::Svg + Qt6::WebChannel Qt6::WebEngineCore Qt6::WebEngineWidgets ${PLATFORM_QT_LIBRARIES} ) diff --git a/interface/resources/QtWebEngine/UIDelegates/ConfirmDialog.qml b/interface/resources/QtWebEngine/UIDelegates/ConfirmDialog.qml index 97d83f43049..6fd28a47032 100644 --- a/interface/resources/QtWebEngine/UIDelegates/ConfirmDialog.qml +++ b/interface/resources/QtWebEngine/UIDelegates/ConfirmDialog.qml @@ -1,6 +1,6 @@ import QtQuick 2.4 -import QtQuick.Dialogs 1.1 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import "../../qml/dialogs" diff --git a/interface/resources/fonts/Roboto-Bold.ttf b/interface/resources/fonts/Roboto-Bold.ttf new file mode 100644 index 00000000000..4658f9a67b1 Binary files /dev/null and b/interface/resources/fonts/Roboto-Bold.ttf differ diff --git a/interface/resources/fonts/Roboto-BoldItalic.ttf b/interface/resources/fonts/Roboto-BoldItalic.ttf new file mode 100644 index 00000000000..2ee0765ce17 Binary files /dev/null and b/interface/resources/fonts/Roboto-BoldItalic.ttf differ diff --git a/interface/resources/fonts/Roboto-Italic.ttf b/interface/resources/fonts/Roboto-Italic.ttf new file mode 100644 index 00000000000..c3abaefb284 Binary files /dev/null and b/interface/resources/fonts/Roboto-Italic.ttf differ diff --git a/interface/resources/fonts/Roboto-Regular.ttf b/interface/resources/fonts/Roboto-Regular.ttf new file mode 100644 index 00000000000..7e3bb2f8ce7 Binary files /dev/null and b/interface/resources/fonts/Roboto-Regular.ttf differ diff --git a/interface/resources/fonts/Roboto.license b/interface/resources/fonts/Roboto.license new file mode 100644 index 00000000000..a417551aa4a --- /dev/null +++ b/interface/resources/fonts/Roboto.license @@ -0,0 +1,93 @@ +Copyright 2011 The Roboto Project Authors (https://github.com/googlefonts/roboto-classic) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/interface/resources/fonts/RobotoMono-Bold.ttf b/interface/resources/fonts/RobotoMono-Bold.ttf new file mode 100644 index 00000000000..bef439f3b9a Binary files /dev/null and b/interface/resources/fonts/RobotoMono-Bold.ttf differ diff --git a/interface/resources/fonts/RobotoMono-BoldItalic.ttf b/interface/resources/fonts/RobotoMono-BoldItalic.ttf new file mode 100644 index 00000000000..642dd0589f0 Binary files /dev/null and b/interface/resources/fonts/RobotoMono-BoldItalic.ttf differ diff --git a/interface/resources/fonts/RobotoMono-Italic.ttf b/interface/resources/fonts/RobotoMono-Italic.ttf new file mode 100644 index 00000000000..781eff8c0a7 Binary files /dev/null and b/interface/resources/fonts/RobotoMono-Italic.ttf differ diff --git a/interface/resources/fonts/RobotoMono-Regular.ttf b/interface/resources/fonts/RobotoMono-Regular.ttf new file mode 100644 index 00000000000..3806bfb1101 Binary files /dev/null and b/interface/resources/fonts/RobotoMono-Regular.ttf differ diff --git a/interface/resources/icons/tablet-icons/chat-a.svg b/interface/resources/icons/tablet-icons/chat-a.svg new file mode 100644 index 00000000000..e3793aaf022 --- /dev/null +++ b/interface/resources/icons/tablet-icons/chat-a.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/icons/tablet-icons/chat-i.svg b/interface/resources/icons/tablet-icons/chat-i.svg new file mode 100644 index 00000000000..c5d26819952 --- /dev/null +++ b/interface/resources/icons/tablet-icons/chat-i.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/+android_interface/Web3DSurfaceAndroid.qml b/interface/resources/qml/+android_interface/Web3DSurfaceAndroid.qml index 6a9f76bc739..135c966c63f 100644 --- a/interface/resources/qml/+android_interface/Web3DSurfaceAndroid.qml +++ b/interface/resources/qml/+android_interface/Web3DSurfaceAndroid.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { diff --git a/interface/resources/qml/+webengine/BrowserWebView.qml b/interface/resources/qml/+webengine/BrowserWebView.qml index 291859c3ec6..7ce14553969 100644 --- a/interface/resources/qml/+webengine/BrowserWebView.qml +++ b/interface/resources/qml/+webengine/BrowserWebView.qml @@ -1,8 +1,8 @@ -import QtQuick 2.5 -import QtWebChannel 1.0 -import QtWebEngine 1.5 +import QtQuick +import QtWebChannel +import QtWebEngine -import controlsUit 1.0 +import controlsUit WebView { id: webview @@ -10,23 +10,20 @@ WebView { profile: FileTypeProfile; property var parentRoot: null - // Create a global EventBridge object for raiseAndLowerKeyboard. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.Deferred - worldId: WebEngineScript.MainWorld - } - - // Detect when may want to raise and lower keyboard. - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ] + userScripts.collection: [ + // Create a global EventBridge object for raiseAndLowerKeyboard. + { + sourceCode: eventBridgeJavaScriptToInject, + injectionPoint: WebEngineScript.Deferred, + worldId: WebEngineScript.MainWorld, + }, + // Detect when may want to raise and lower keyboard. + { + injectionPoint: WebEngineScript.Deferred, + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js", + worldId: WebEngineScript.MainWorld, + } + ] onLoadingChanged: { if (loadRequest.status === WebEngineView.LoadSucceededStatus) { diff --git a/interface/resources/qml/+webengine/QmlWebWindowView.qml b/interface/resources/qml/+webengine/QmlWebWindowView.qml index 84ab61ad28b..441267975a3 100644 --- a/interface/resources/qml/+webengine/QmlWebWindowView.qml +++ b/interface/resources/qml/+webengine/QmlWebWindowView.qml @@ -1,9 +1,9 @@ -import QtQuick 2.5 -import QtWebEngine 1.1 -import QtWebChannel 1.0 +import QtQuick +import QtWebEngine +import QtWebChannel -import controlsUit 1.0 as Controls -import stylesUit 1.0 +import controlsUit as Controls +import stylesUit Controls.WebView { id: webview url: "about:blank" @@ -14,30 +14,28 @@ Controls.WebView { property string userScriptUrl: "" // Create a global EventBridge object for raiseAndLowerKeyboard. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // Detect when may want to raise and lower keyboard. - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: webview.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + userScripts.collection: [ { + name: "createGlobalEventBridge", + id: createGlobalEventBridge, + sourceCode: eventBridgeJavaScriptToInject, + injectionPoint: WebEngineScript.DocumentCreation, + worldId: WebEngineScript.MainWorld + }, + { + name: "raiseAndLowerKeyboardScript", + id: raiseAndLowerKeyboard, + injectionPoint: WebEngineScript.Deferred, + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js", + worldId: WebEngineScript.MainWorld + }, + { + name: "userWebEngineScript", + id: userScript, + sourceUrl: webview.userScriptUrl, + injectionPoint: WebEngineScript.DocumentReady, // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } ] function onWebEventReceived(event) { if (typeof event === "string" && event.slice(0, 17) === "CLARA.IO DOWNLOAD") { diff --git a/interface/resources/qml/+webengine/TabletBrowser.qml b/interface/resources/qml/+webengine/TabletBrowser.qml index 49b87e51dd7..367b0872c56 100644 --- a/interface/resources/qml/+webengine/TabletBrowser.qml +++ b/interface/resources/qml/+webengine/TabletBrowser.qml @@ -1,11 +1,11 @@ -import QtQuick 2.5 -import QtWebChannel 1.0 -import QtWebEngine 1.5 +import QtQuick +import QtWebChannel +import QtWebEngine import "controls" -import controlsUit 1.0 as HifiControls +import controlsUit as HifiControls import "styles" as HifiStyles -import stylesUit 1.0 +import stylesUit import "windows" Item { diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index 75a71a32c5f..01f2e023baa 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit diff --git a/interface/resources/qml/AvatarInputsBar.qml b/interface/resources/qml/AvatarInputsBar.qml index 9230111cb64..3997d28340d 100644 --- a/interface/resources/qml/AvatarInputsBar.qml +++ b/interface/resources/qml/AvatarInputsBar.qml @@ -8,7 +8,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "./hifi/audio" as HifiAudio diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 2fefb6bff47..8727d558f9e 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -163,7 +163,7 @@ ScrollingWindow { anchors.leftMargin: 0 anchors.verticalCenter: parent.verticalCenter focus: true - colorScheme: hifi.colorSchemes.dark + //colorScheme: hifi.colorSchemes.dark placeholderText: "Enter URL" inputMethodHints: Qt.ImhUrlCharactersOnly Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") @@ -229,8 +229,8 @@ ScrollingWindow { Button { id:allow text: "Allow" - color: hifi.buttons.blue - colorScheme: root.colorScheme + //color: hifi.buttons.blue + //colorScheme: root.colorScheme width: 120 enabled: true onClicked: root.allowPermissions(); @@ -240,8 +240,8 @@ ScrollingWindow { Button { id:block text: "Block" - color: hifi.buttons.red - colorScheme: root.colorScheme + //color: hifi.buttons.red + //colorScheme: root.colorScheme width: 120 enabled: true onClicked: root.hidePermissionsBar(); diff --git a/interface/resources/qml/BubbleIcon.qml b/interface/resources/qml/BubbleIcon.qml index b5a7ddb2d86..0ec3a927357 100644 --- a/interface/resources/qml/BubbleIcon.qml +++ b/interface/resources/qml/BubbleIcon.qml @@ -8,7 +8,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "./hifi/audio" as HifiAudio diff --git a/interface/resources/qml/ConnectionFailureDialog.qml b/interface/resources/qml/ConnectionFailureDialog.qml index cb6c9db4576..a3186fa642b 100644 --- a/interface/resources/qml/ConnectionFailureDialog.qml +++ b/interface/resources/qml/ConnectionFailureDialog.qml @@ -1,4 +1,4 @@ -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import "dialogs" diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 4ea45041c3d..7a7cfa382f0 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/interface/resources/qml/InteractiveWindow.qml b/interface/resources/qml/InteractiveWindow.qml index a8b27762d6c..740717ca973 100644 --- a/interface/resources/qml/InteractiveWindow.qml +++ b/interface/resources/qml/InteractiveWindow.qml @@ -76,10 +76,11 @@ Windows.Window { } function updateInteractiveWindowPositionForMode() { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { x = interactiveWindowPosition.x; y = interactiveWindowPosition.y; - } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { + } else if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow) { if (interactiveWindowPosition.x === 0 && interactiveWindowPosition.y === 0) { // default position for native window in center of main application window nativeWindow.x = Math.floor(Window.x + (Window.innerWidth / 2) - (interactiveWindowSize.width / 2)); @@ -97,28 +98,31 @@ Windows.Window { contentHolder.width = interactiveWindowSize.width; contentHolder.height = interactiveWindowSize.height; - if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow) { nativeWindow.width = interactiveWindowSize.width; nativeWindow.height = interactiveWindowSize.height; } } function updateContentParent() { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { contentHolder.parent = root; - } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { + } else if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow) { contentHolder.parent = nativeWindow.contentItem; } } function setupPresentationMode() { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { if (nativeWindow) { nativeWindow.setVisible(false); } updateInteractiveWindowPositionForMode(); shown = interactiveWindowVisible; - } else if (presentationMode === Desktop.PresentationMode.NATIVE) { + } else if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1) { shown = false; if (nativeWindow) { updateInteractiveWindowPositionForMode(); @@ -175,25 +179,29 @@ Windows.Window { nativeWindow.height = interactiveWindowSize.height; nativeWindow.xChanged.connect(function() { - if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow.visible) { interactiveWindowPosition = Qt.point(nativeWindow.x, interactiveWindowPosition.y); } }); nativeWindow.yChanged.connect(function() { - if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow.visible) { interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, nativeWindow.y); } }); nativeWindow.widthChanged.connect(function() { - if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow.visible) { interactiveWindowSize = Qt.size(nativeWindow.width, interactiveWindowSize.height); } }); nativeWindow.heightChanged.connect(function() { - if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow.visible) { interactiveWindowSize = Qt.size(interactiveWindowSize.width, nativeWindow.height); } }); @@ -223,9 +231,10 @@ Windows.Window { } function raiseWindow() { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { raise(); - } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { + } else if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow) { nativeWindow.raise(); } } @@ -271,9 +280,10 @@ Windows.Window { } onInteractiveWindowVisibleChanged: { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { shown = interactiveWindowVisible; - } else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) { + } else if (presentationMode === /*Desktop.PresentationMode.NATIVE*/ 1 && nativeWindow) { if (!nativeWindow.visible && interactiveWindowVisible) { nativeWindow.showNormal(); } else { @@ -289,25 +299,29 @@ Windows.Window { } onXChanged: { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { interactiveWindowPosition = Qt.point(x, interactiveWindowPosition.y); } } onYChanged: { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, y); } } onWidthChanged: { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { interactiveWindowSize = Qt.size(width, interactiveWindowSize.height); } } onHeightChanged: { - if (presentationMode === Desktop.PresentationMode.VIRTUAL) { + // QT6TODO: Desktop isn't being passed to QML? + if (presentationMode === /*Desktop.PresentationMode.VIRTUAL*/ 0) { interactiveWindowSize = Qt.size(interactiveWindowSize.width, height); } } diff --git a/interface/resources/qml/LoginDialog/+android_interface/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android_interface/LinkAccountBody.qml index 8570273bde7..39852afeccc 100644 --- a/interface/resources/qml/LoginDialog/+android_interface/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android_interface/LinkAccountBody.qml @@ -10,8 +10,8 @@ import Hifi 1.0 import QtQuick 2.4 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +import QtQuick.Controls 2.3 +////import QtQuick.Controls.Styles as OriginalStyles import controlsUit 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/LoginDialog/+android_interface/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android_interface/SignUpBody.qml index f2329c065c5..9b1bc80a5fd 100644 --- a/interface/resources/qml/LoginDialog/+android_interface/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/+android_interface/SignUpBody.qml @@ -10,8 +10,8 @@ import Hifi 1.0 import QtQuick 2.4 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +import QtQuick.Controls 2.3 +////import QtQuick.Controls.Styles as OriginalStyles import controlsUit 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml index b8744251323..0ae8eda186d 100644 --- a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml +++ b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +////import QtQuick.Controls.Styles as OriginalStyles import controlsUit 1.0 as HifiControlsUit import stylesUit 1.0 as HifiStylesUit diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 25aa7504ee3..550210451cc 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +import QtQuick.Controls 2.3 +////import QtQuick.Controls.Styles as OriginalStyles import "." as LoginDialog diff --git a/interface/resources/qml/LoginDialog/LoggingInBody.qml b/interface/resources/qml/LoginDialog/LoggingInBody.qml index 1c8250cfa8e..d8cfd618d66 100644 --- a/interface/resources/qml/LoginDialog/LoggingInBody.qml +++ b/interface/resources/qml/LoginDialog/LoggingInBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +import QtQuick.Controls 2.3 +////import QtQuick.Controls.Styles as OriginalStyles import controlsUit 1.0 as HifiControlsUit import stylesUit 1.0 as HifiStylesUit diff --git a/interface/resources/qml/LoginDialog/LoginDialogLightbox.qml b/interface/resources/qml/LoginDialog/LoginDialogLightbox.qml index 8995ecd2613..e49cc8a27f4 100644 --- a/interface/resources/qml/LoginDialog/LoginDialogLightbox.qml +++ b/interface/resources/qml/LoginDialog/LoginDialogLightbox.qml @@ -13,7 +13,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit import "qrc:////qml//controls" as HifiControls diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index b1335232110..b3ca2451a01 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles +import QtQuick.Controls 2.3 +////import QtQuick.Controls.Styles as OriginalStyles import controlsUit 1.0 as HifiControlsUit import stylesUit 1.0 as HifiStylesUit diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index 86f60bc067d..5911c3ff860 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import controlsUit 1.0 as HifiControlsUit import stylesUit 1.0 as HifiStylesUit diff --git a/interface/resources/qml/OverlayWindowTest.qml b/interface/resources/qml/OverlayWindowTest.qml index 9c1b993ba84..16692e4083c 100644 --- a/interface/resources/qml/OverlayWindowTest.qml +++ b/interface/resources/qml/OverlayWindowTest.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 Rectangle { width: 100 diff --git a/interface/resources/qml/UpdateDialog.qml b/interface/resources/qml/UpdateDialog.qml index 4aaefb5cce9..27f6202665c 100644 --- a/interface/resources/qml/UpdateDialog.qml +++ b/interface/resources/qml/UpdateDialog.qml @@ -1,8 +1,8 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.3 -import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 +import QtQuick.Controls +//import QtQuick.Controls.Styles +import Qt5Compat.GraphicalEffects import controlsUit 1.0 import "styles" as HifiStyles diff --git a/interface/resources/qml/Web3DSurface.qml b/interface/resources/qml/Web3DSurface.qml index 3380eabeac1..fb845debfda 100644 --- a/interface/resources/qml/Web3DSurface.qml +++ b/interface/resources/qml/Web3DSurface.qml @@ -17,7 +17,7 @@ Item { id: root anchors.fill: parent property string url: "" - property string scriptUrl: null + property string scriptUrl: "" property bool useBackground: true property string userAgent: "" @@ -83,7 +83,7 @@ Item { if (root.webViewLoaded) { loader.item.url = "about:blank" } - loader.setSource(undefined); + loader.setSource(""); } if (url.match(/\.qml$/)) { @@ -93,7 +93,7 @@ Item { root.webViewLoaded = true; loader.setSource("./controls/WebView.qml", { url: url, - scriptUrl: scriptUrl, + //scriptUrl: scriptUrl, // Qt6 TODO useBackground: useBackground, userAgent: userAgent }); diff --git a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml index 9a08a3d0f8a..00cb44e48fa 100644 --- a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml @@ -1,11 +1,11 @@ -import QtQuick 2.7 -import QtWebEngine 1.5 -import QtWebChannel 1.0 +import QtQuick +import QtWebEngine +import QtWebChannel -import QtQuick.Controls 2.2 +import QtQuick.Controls -import stylesUit 1.0 as StylesUIt -import controlsUit 1.0 as ControlsUit +import stylesUit as StylesUIt +import controlsUit as ControlsUit Item { id: flick @@ -24,7 +24,7 @@ Item { property string urlTag: "noDownload=false"; signal newViewRequestedCallback(var request) - signal loadingChangedCallback(var loadRequest) + signal loadingChangedCallback(var loadingInfo) width: parent.width @@ -112,33 +112,56 @@ Item { settings.touchIconsEnabled: true settings.allowRunningInsecureContent: true - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: flick.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + // QT6TODO causes a crash + // Even empty collection causes a crash + // userScripts.collection: [] + //userScripts.collection: [ + // creates a global EventBridge object. + /*{ + sourceCode: eventBridgeJavaScriptToInject, + injectionPoint: WebEngineScript.DocumentCreation, + worldId: WebEngineScript.MainWorld, + }, + + // detects when to raise and lower virtual keyboard + { + injectionPoint: WebEngineScript.Deferred, + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js", + worldId: WebEngineScript.MainWorld, + }, + + // User script. + { + sourceUrl: flick.userScriptUrl, + injectionPoint: WebEngineScript.DocumentReady, // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld, + },*/ + //] Component.onCompleted: { + // QT6TODO: previous way of doing it crashes and this one doesn't? unless it crashes later + userScripts.collection = [ + // creates a global EventBridge object. + { + sourceCode: eventBridgeJavaScriptToInject, + injectionPoint: WebEngineScript.DocumentCreation, + worldId: WebEngineScript.MainWorld, + }, + + // detects when to raise and lower virtual keyboard + { + injectionPoint: WebEngineScript.Deferred, + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js", + worldId: WebEngineScript.MainWorld, + }, + + // User script. + { + sourceUrl: flick.userScriptUrl, + injectionPoint: WebEngineScript.DocumentReady, // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld, + }, + ] webChannel.registerObject("eventBridge", eventBridge); webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); @@ -172,9 +195,10 @@ Item { request.accepted = true; } - onNewViewRequested: { + // Qt6 TODO + /*onNewViewRequested: { newViewRequestedCallback(request) - } + }*/ // Prior to 5.10, the WebEngineView loading property is true during initial page loading and then stays false // as in-page javascript adds more html content. However, in 5.10 there is a bug such that adding html turns @@ -182,15 +206,18 @@ Item { // when QT fixes this. property bool safeLoading: false property bool loadingLatched: false - property var loadingRequest: null - onLoadingChanged: { - webViewCore.loadingRequest = loadRequest; + property var loadInfo: null + // QT6TODO: useBackground was missing here in Qt5, but I cannot find it anywhere in Qt documentation, so I just defined it here. + property bool useBackground: true + + function onLoadingChanged(loadingInfo) { + webViewCore.loadInfo = loadingInfo; webViewCore.safeLoading = webViewCore.loading && !loadingLatched; webViewCore.loadingLatched |= webViewCore.loading; } onSafeLoadingChanged: { - flick.onLoadingChanged(webViewCore.loadingRequest) - loadingChangedCallback(webViewCore.loadingRequest) + flick.onLoadingChanged(webViewCore.loadInfo) + loadingChangedCallback(webViewCore.loadInfo) } } diff --git a/interface/resources/qml/controls/ButtonAwesome.qml b/interface/resources/qml/controls/ButtonAwesome.qml index 12f2a6b40d4..e772ce544d9 100644 --- a/interface/resources/qml/controls/ButtonAwesome.qml +++ b/interface/resources/qml/controls/ButtonAwesome.qml @@ -1,6 +1,6 @@ import QtQuick 2.3 -import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 as OriginalStyles +import QtQuick.Controls as Original +////import QtQuick.Controls.Styles as OriginalStyles import "." import "../styles" @@ -11,7 +11,8 @@ Original.Button { property real size: 32 SystemPalette { id: palette; colorGroup: SystemPalette.Active } SystemPalette { id: disabledPalette; colorGroup: SystemPalette.Disabled } - style: OriginalStyles.ButtonStyle { + // QT6TODO + /*style: OriginalStyles.ButtonStyle { label: FontAwesome { verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter @@ -48,7 +49,7 @@ Original.Button { onStopped: if (control.activeFocus) { start(); } } } - } + }*/ Keys.onEnterPressed: root.clicked(); Keys.onReturnPressed: root.clicked(); } diff --git a/interface/resources/qml/controls/CheckBox.qml b/interface/resources/qml/controls/CheckBox.qml index 91586299a72..f7a6e1c1353 100644 --- a/interface/resources/qml/controls/CheckBox.qml +++ b/interface/resources/qml/controls/CheckBox.qml @@ -1,5 +1,5 @@ -import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls as Original +//import QtQuick.Controls.Styles import "../styles" import "." Original.CheckBox { diff --git a/interface/resources/qml/controls/ComboBox.qml b/interface/resources/qml/controls/ComboBox.qml index 960ae8127aa..50244af7320 100644 --- a/interface/resources/qml/controls/ComboBox.qml +++ b/interface/resources/qml/controls/ComboBox.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import "." as VrControls diff --git a/interface/resources/qml/controls/Player.qml b/interface/resources/qml/controls/Player.qml index 8af0b1527dc..35ce91528a3 100644 --- a/interface/resources/qml/controls/Player.qml +++ b/interface/resources/qml/controls/Player.qml @@ -12,7 +12,7 @@ import QtQuick 2.4 import QtQuick.Controls 1.2 import QtQuick.Dialogs 1.2 -import QtQuick.Controls.Styles 1.2 +//import QtQuick.Controls.Styles import "../styles" Item { diff --git a/interface/resources/qml/controls/RadioButton.qml b/interface/resources/qml/controls/RadioButton.qml index 6bd9c860d2f..dcbae3491bb 100644 --- a/interface/resources/qml/controls/RadioButton.qml +++ b/interface/resources/qml/controls/RadioButton.qml @@ -1,5 +1,5 @@ import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 +//import QtQuick.Controls.Styles import "../styles" import "." Original.RadioButton { diff --git a/interface/resources/qml/controls/Slider.qml b/interface/resources/qml/controls/Slider.qml index ace20f1e682..3c53bbe62d9 100644 --- a/interface/resources/qml/controls/Slider.qml +++ b/interface/resources/qml/controls/Slider.qml @@ -1,5 +1,5 @@ import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 +//import QtQuick.Controls.Styles import "../styles" import "." diff --git a/interface/resources/qml/controls/SpinBox.qml b/interface/resources/qml/controls/SpinBox.qml index 1acba57409e..c317ca96288 100644 --- a/interface/resources/qml/controls/SpinBox.qml +++ b/interface/resources/qml/controls/SpinBox.qml @@ -1,6 +1,6 @@ import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 +//import QtQuick.Controls.Styles import "../styles" import "." diff --git a/interface/resources/qml/controls/TextField.qml b/interface/resources/qml/controls/TextField.qml index df536a1de53..c4900b069ed 100644 --- a/interface/resources/qml/controls/TextField.qml +++ b/interface/resources/qml/controls/TextField.qml @@ -1,7 +1,8 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles TextField { - style: TextFieldStyle { renderType: Text.QtRendering } + //QT6TODO + //style: TextFieldStyle { renderType: Text.QtRendering } } diff --git a/interface/resources/qml/controls/WrappedMenu.qml b/interface/resources/qml/controls/WrappedMenu.qml new file mode 100644 index 00000000000..43fc2d438e3 --- /dev/null +++ b/interface/resources/qml/controls/WrappedMenu.qml @@ -0,0 +1,13 @@ +import QtQuick.Controls + +Menu { + id: wrappedMenu + objectName: "wrappedMenu" + + function addMenuWrap(menu) { + return addMenu(menu); + } + function addItemWrap(item) { + addItem(item); + } +} \ No newline at end of file diff --git a/interface/resources/qml/controlsUit/AttachmentsTable.qml b/interface/resources/qml/controlsUit/AttachmentsTable.qml index a2677962daa..c20bea08180 100644 --- a/interface/resources/qml/controlsUit/AttachmentsTable.qml +++ b/interface/resources/qml/controlsUit/AttachmentsTable.qml @@ -9,8 +9,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.XmlListModel 2.0 import "../stylesUit" diff --git a/interface/resources/qml/controlsUit/ContentSection.qml b/interface/resources/qml/controlsUit/ContentSection.qml index 262c29220fd..a45f45c2956 100644 --- a/interface/resources/qml/controlsUit/ContentSection.qml +++ b/interface/resources/qml/controlsUit/ContentSection.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "../stylesUit" diff --git a/interface/resources/qml/controlsUit/FilterBar.qml b/interface/resources/qml/controlsUit/FilterBar.qml index 0892018913c..e57e7dd3b49 100644 --- a/interface/resources/qml/controlsUit/FilterBar.qml +++ b/interface/resources/qml/controlsUit/FilterBar.qml @@ -10,7 +10,7 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "../stylesUit" import "." as HifiControls diff --git a/interface/resources/qml/controlsUit/Keyboard.qml b/interface/resources/qml/controlsUit/Keyboard.qml index a55523f34ac..f2842f488eb 100644 --- a/interface/resources/qml/controlsUit/Keyboard.qml +++ b/interface/resources/qml/controlsUit/Keyboard.qml @@ -9,7 +9,7 @@ // import QtQuick 2.7 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." Rectangle { diff --git a/interface/resources/qml/controlsUit/Table.qml b/interface/resources/qml/controlsUit/Table.qml index ab743610460..680a2c42310 100644 --- a/interface/resources/qml/controlsUit/Table.qml +++ b/interface/resources/qml/controlsUit/Table.qml @@ -8,10 +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.Controls.Styles 1.4 -import QtQuick.Controls 2.3 as QQC2 +import QtQuick +import QtQuick.Controls +//import QtQuick.Controls.Styles import "../stylesUit" @@ -30,12 +29,14 @@ TableView { model: ListModel { } Component.onCompleted: { - if (flickableItem !== null && flickableItem !== undefined) { + // QT6TODO: ReferenceError: flickableItem is not defined + /*if (flickableItem !== null && flickableItem !== undefined) { tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar - } + }*/ } - QQC2.ScrollBar { + // QT6TODO: this errors out with: QML ScrollBar: Cannot anchor to an item that isn't a parent or sibling. + ScrollBar { id: scrollbar parent: tableView.flickableItem policy: QQC2.ScrollBar.AsNeeded @@ -68,8 +69,10 @@ TableView { } } - headerVisible: false - headerDelegate: Rectangle { + // QT6TODO: not available on Qt6 + //headerVisible: false + // QT6TODO: I don't know how to port this + /*headerDelegate: Rectangle { height: hifi.dimensions.tableHeaderHeight color: isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark @@ -130,10 +133,11 @@ TableView { } color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight } - } + }*/ // Use rectangle to draw border with rounded corners. - frameVisible: false + // QT6TODO: does not exist in Qt 6? + //frameVisible: false Rectangle { color: "#00000000" anchors { fill: parent; margins: -2 } @@ -142,19 +146,28 @@ TableView { } anchors.margins: 2 // Shrink TableView to lie within border. - backgroundVisible: true + // QT6TODO: this doesn't exist in Qt 6? + //backgroundVisible: true - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff + // QT6TODO: these don't exist in Qt 6? + //horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + //verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff - style: TableViewStyle { + // QT6TODO: how to port this + /*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 - } + }*/ + + // QT6TODO: I'm not sure if this is correct + // was originally rowDelegate + delegate: Rectangle { + // QT6TODO: I added these, but I'm not sure if these are needed + required property bool current + required property bool selected - rowDelegate: Rectangle { height: (styleData.selected && expandSelectedRow ? 1.8 : 1) * hifi.dimensions.tableRowHeight color: styleData.selected ? hifi.colors.primaryHighlight diff --git a/interface/resources/qml/controlsUit/TabletContentSection.qml b/interface/resources/qml/controlsUit/TabletContentSection.qml index dccaf31bbec..c349baa0265 100644 --- a/interface/resources/qml/controlsUit/TabletContentSection.qml +++ b/interface/resources/qml/controlsUit/TabletContentSection.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "../stylesUit" diff --git a/interface/resources/qml/controlsUit/TextField.qml b/interface/resources/qml/controlsUit/TextField.qml index 86707395e35..6577bd9c293 100644 --- a/interface/resources/qml/controlsUit/TextField.qml +++ b/interface/resources/qml/controlsUit/TextField.qml @@ -9,8 +9,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import "../stylesUit" import "." as HifiControls @@ -44,7 +44,7 @@ TextField { y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0 // workaround for https://bugreports.qt.io/browse/QTBUG-49297 - Keys.onPressed: { + Keys.onPressed: event => { switch (event.key) { case Qt.Key_Return: case Qt.Key_Enter: @@ -57,6 +57,8 @@ TextField { } } + // QT6TODO + /* style: TextFieldStyle { id: style; textColor: { @@ -159,7 +161,7 @@ TextField { 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 renderType: textField.styleRenderType - } + }*/ HifiControls.Label { id: textFieldLabel diff --git a/interface/resources/qml/controlsUit/Tree.qml b/interface/resources/qml/controlsUit/Tree.qml index f2c49095b12..930e3a09998 100644 --- a/interface/resources/qml/controlsUit/Tree.qml +++ b/interface/resources/qml/controlsUit/Tree.qml @@ -8,11 +8,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQml.Models 2.2 -import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Controls 2.2 as QQC2 +import QtQml.Models +import QtQuick +import QtQuick.Controls +//import QtQuick.Controls.Styles +import QtQuick.Controls as QQC2 import "../stylesUit" diff --git a/interface/resources/qml/controlsUit/WebView.qml b/interface/resources/qml/controlsUit/WebView.qml index 2895f36944d..b3bff4e8b36 100644 --- a/interface/resources/qml/controlsUit/WebView.qml +++ b/interface/resources/qml/controlsUit/WebView.qml @@ -12,10 +12,11 @@ import QtQuick 2.5 import "." BaseWebView { - onNewViewRequested: { + // Qt6 TODO + /*onNewViewRequested: { // Load dialog via OffscreenUi so that JavaScript EventBridge is available. var browser = OffscreenUi.load("Browser.qml"); request.openIn(browser.webView); browser.webView.forceActiveFocus(); - } + }*/ } diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 971fb064148..0a04f76863b 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -8,12 +8,14 @@ // 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 QtQuick.Controls 2.3 as QQC2 +import QtQuick +import QtQuick.Controls import "../dialogs" import "../js/Utils.js" as Utils +import "../controls" as OverteControls + +import "../overte/compat" as OverteCompat // This is our primary 'desktop' object to which all VR dialogs and windows are childed. FocusScope { @@ -51,16 +53,21 @@ FocusScope { property bool desktopRoot: true // The VR version of the primary menu - property var rootMenu: Menu { + property var rootMenu: OverteControls.WrappedMenu { id: rootMenuId objectName: "rootMenu" property var exclusionGroups: ({}); property Component exclusiveGroupMaker: Component { - ExclusiveGroup { + //ExclusiveGroup { //QT6TODO + ButtonGroup { } } + function addMenuWrap(menu) { + return addMenu(menu); + } + function addExclusionGroup(qmlAction, exclusionGroup) { var exclusionGroupId = exclusionGroup.toString(); @@ -68,6 +75,7 @@ FocusScope { exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId); } + //QT6TODO: qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId] } } @@ -532,12 +540,13 @@ FocusScope { return customInputDialogBuilder.createObject(desktop, properties); } - Component { id: fileDialogBuilder; FileDialog { } } + Component { id: fileDialogBuilder; OverteCompat.CompatFileDialog { } } function fileDialog(properties) { return fileDialogBuilder.createObject(desktop, properties); } - Component { id: assetDialogBuilder; AssetDialog { } } + // TODO: is this actually used? + Component { id: assetDialogBuilder; Item {}}//AssetDialog { } } function assetDialog(properties) { return assetDialogBuilder.createObject(desktop, properties); } @@ -582,7 +591,7 @@ FocusScope { ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 } } - QQC2.Action { + Action { text: "Toggle Focus Debugger" shortcut: "Ctrl+Shift+F" enabled: DebugQML diff --git a/interface/resources/qml/dialogs/AssetDialog.qml b/interface/resources/qml/dialogs/AssetDialog.qml index b8eaab0b8df..694c37740cd 100644 --- a/interface/resources/qml/dialogs/AssetDialog.qml +++ b/interface/resources/qml/dialogs/AssetDialog.qml @@ -8,8 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +import QtCore import QtQuick 2.5 -import Qt.labs.settings 1.0 import stylesUit 1.0 import "../windows" diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 2497781db0d..3839313453f 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.7; -import QtQuick.Dialogs 1.2 as OriginalDialogs; +import QtQuick.Dialogs as OriginalDialogs; import QtQuick.Controls 2.3 import controlsUit 1.0 diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index fa4d911b653..c575058f39a 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.7 -import Qt.labs.folderlistmodel 2.2 -import Qt.labs.settings 1.0 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import QtQuick.Controls 1.4 as QQC1 -import QtQuick.Controls 2.3 +import QtCore +import QtQuick +import Qt.labs.folderlistmodel +import Qt.labs.qmlmodels +import QtQuick.Dialogs as OriginalDialogs +import QtQuick.Controls import ".." import controlsUit 1.0 @@ -34,7 +34,7 @@ ModalWindow { HifiConstants { id: hifi } - property var filesModel: ListModel { } + property var filesModel: TableModel { } Settings { category: "FileDialog" @@ -76,8 +76,8 @@ ModalWindow { selected(button); destroy(); } - - property int clickedButton: OriginalDialogs.StandardButton.NoButton; + + property int clickedButton: OriginalDialogs.MessageDialog.NoButton; Component.onCompleted: { fileDialogItem.keyboardEnabled = HMD.active; @@ -261,7 +261,7 @@ ModalWindow { QtObject { id: d property var currentSelectionUrl; - readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl); + readonly property string currentSelectionPath: currentSelectionUrl === undefined ? "" : helper.urlToPath(currentSelectionUrl); property bool currentSelectionIsFolder; property var backStack: [] property var tableViewConnection: Connections { target: fileTableView; function onCurrentRowChanged() { d.update(); } } @@ -311,8 +311,9 @@ ModalWindow { } function clearSelection() { - fileTableView.selection.clear(); - fileTableView.currentRow = -1; + // QT6TODO + //fileTableView.selection.clear(); + //fileTableView.currentRow = -1; update(); } } @@ -374,7 +375,25 @@ ModalWindow { Component { id: filesModelBuilder - ListModel { } + TableModel { + TableModelColumn { + //id: fileNameColumn + display: "fileName" + //title: "Name" + //width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width + } + TableModelColumn { + //id: fileModifiedColumn + display: "fileModified" + //title: "Date" + //width: 0.3 * fileTableView.width + } + TableModelColumn { + display: "fileSize" + //title: "Size" + //width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width + } + } } QtObject { @@ -429,11 +448,11 @@ ModalWindow { if (row === -1) { return false; } - return filesModel.get(row).fileIsDir; + return filesModel.getRow(row).fileIsDir; } function get(row) { - return filesModel.get(row) + return filesModel.getRow(row) } function update() { @@ -473,7 +492,7 @@ ModalWindow { while (lower < upper) { middle = Math.floor((lower + upper) / 2); var lessThan; - if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) { + if (comparisonFunction(sortValue, filesModel.getRow(middle)[sortField])) { lessThan = true; upper = middle; } else { @@ -482,7 +501,7 @@ ModalWindow { } } - filesModel.insert(lower, { + filesModel.insertRow(lower, { fileName: fileName, fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")), fileSize: model.getItem(i, "fileSize"), @@ -496,9 +515,10 @@ ModalWindow { } } - Table { + TableView { id: fileTableView - colorScheme: hifi.colorSchemes.light + // QT6TODO: + //colorScheme: hifi.colorSchemes.light anchors { top: navControls.bottom topMargin: hifi.dimensions.contentSpacing.y @@ -507,15 +527,17 @@ ModalWindow { bottom: currentSelection.top bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height } - headerVisible: !selectDirectory - onDoubleClicked: navigateToRow(row); + // QT6TODO: + //headerVisible: !selectDirectory + //onDoubleClicked: navigateToRow(row); Keys.onReturnPressed: navigateToCurrentRow(); Keys.onEnterPressed: navigateToCurrentRow(); - sortIndicatorColumn: 0 - sortIndicatorOrder: Qt.AscendingOrder - sortIndicatorVisible: true + property int sortIndicatorColumn: 0 + property var sortIndicatorOrder: Qt.AscendingOrder + property bool sortIndicatorVisible: true + // QT6TODO model: filesModel function updateSort() { @@ -528,7 +550,20 @@ ModalWindow { onSortIndicatorOrderChanged: { updateSort(); } - itemDelegate: Item { + delegate: TextInput { + text: model.display + padding: 12 + selectByMouse: true + + onAccepted: model.display = text + + Rectangle { + anchors.fill: parent + color: "#efefef" + z: -1 + } + } + /*delegate: Item { clip: true FiraSansSemiBold { @@ -571,33 +606,35 @@ ModalWindow { return size + " " + suffixes[suffixIndex]; } } - } - - QQC1.TableViewColumn { - id: fileNameColumn - role: "fileName" - title: "Name" - width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width - movable: false - resizable: true - } - QQC1.TableViewColumn { - id: fileModifiedColumn - role: "fileModified" - title: "Date" - width: 0.3 * fileTableView.width - movable: false - resizable: true - visible: !selectDirectory - } - QQC1.TableViewColumn { - role: "fileSize" - title: "Size" - width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width - movable: false - resizable: true - visible: !selectDirectory - } + }*/ + + /*model: TableModel { + TableModelColumn { + id: fileNameColumn + role: "fileName" + title: "Name" + width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width + movable: false + resizable: true + } + TableModelColumn { + id: fileModifiedColumn + role: "fileModified" + title: "Date" + width: 0.3 * fileTableView.width + movable: false + resizable: true + visible: !selectDirectory + } + TableModelColumn { + role: "fileSize" + title: "Size" + width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width + movable: false + resizable: true + visible: !selectDirectory + } + }*/ function navigateToRow(row) { currentRow = row; @@ -651,7 +688,7 @@ ModalWindow { onTriggered: fileTableView.prefix = ""; } - Keys.onPressed: { + Keys.onPressed: event => { switch (event.key) { case Qt.Key_Backspace: case Qt.Key_Tab: @@ -820,7 +857,7 @@ ModalWindow { } } - Keys.onPressed: { + Keys.onPressed: event => { switch (event.key) { case Qt.Key_Backspace: event.accepted = d.navigateUp(); diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index 629027ab2af..ed272669d7b 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import controlsUit 1.0 import stylesUit 1.0 @@ -36,26 +36,26 @@ ModalWindow { return OffscreenUi.waitForMessageBoxResult(root); } - Keys.onRightPressed: if (defaultButton === OriginalDialogs.StandardButton.Yes) { + Keys.onRightPressed: if (defaultButton === OriginalDialogs.MessageDialog.Yes) { yesButton.forceActiveFocus() - } else if (defaultButton === OriginalDialogs.StandardButton.Ok) { + } else if (defaultButton === OriginalDialogs.MessageDialog.Ok) { okButton.forceActiveFocus() } - Keys.onTabPressed: if (defaultButton === OriginalDialogs.StandardButton.Yes) { + Keys.onTabPressed: if (defaultButton === OriginalDialogs.MessageDialog.Yes) { yesButton.forceActiveFocus() - } else if (defaultButton === OriginalDialogs.StandardButton.Ok) { + } else if (defaultButton === OriginalDialogs.MessageDialog.Ok) { okButton.forceActiveFocus() } property alias detailedText: detailedText.text property alias text: mainTextContainer.text property alias informativeText: informativeTextContainer.text - property int buttons: OriginalDialogs.StandardButton.Ok + property int buttons: OriginalDialogs.MessageDialog.Ok property int icon: OriginalDialogs.StandardIcon.NoIcon property string iconText: "" property int iconSize: 50 onIconChanged: updateIcon(); - property int defaultButton: OriginalDialogs.StandardButton.NoButton; - property int clickedButton: OriginalDialogs.StandardButton.NoButton; + property int defaultButton: OriginalDialogs.MessageDialog.NoButton; + property int clickedButton: OriginalDialogs.MessageDialog.NoButton; property int titleWidth: 0 onTitleWidthChanged: d.resize(); @@ -136,41 +136,41 @@ ModalWindow { margins: 0 topMargin: 2 * hifi.dimensions.contentSpacing.y } - MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.StandardButton.Close; } - MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.StandardButton.Abort; } - MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.StandardButton.Cancel; } - MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.StandardButton.RestoreDefaults; } - MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.StandardButton.Reset; } - MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.StandardButton.Discard; } - MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.StandardButton.NoToAll; } + MessageDialogButton { dialog: root; text: qsTr("Close"); button: OriginalDialogs.MessageDialog.Close; } + MessageDialogButton { dialog: root; text: qsTr("Abort"); button: OriginalDialogs.MessageDialog.Abort; } + MessageDialogButton { dialog: root; text: qsTr("Cancel"); button: OriginalDialogs.MessageDialog.Cancel; } + MessageDialogButton { dialog: root; text: qsTr("Restore Defaults"); button: OriginalDialogs.MessageDialog.RestoreDefaults; } + MessageDialogButton { dialog: root; text: qsTr("Reset"); button: OriginalDialogs.MessageDialog.Reset; } + MessageDialogButton { dialog: root; text: qsTr("Discard"); button: OriginalDialogs.MessageDialog.Discard; } + MessageDialogButton { dialog: root; text: qsTr("No to All"); button: OriginalDialogs.MessageDialog.NoToAll; } MessageDialogButton { id: noButton dialog: root text: qsTr("No") - button: OriginalDialogs.StandardButton.No + button: OriginalDialogs.MessageDialog.No KeyNavigation.left: yesButton KeyNavigation.backtab: yesButton } - MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.StandardButton.YesToAll; } + MessageDialogButton { dialog: root; text: qsTr("Yes to All"); button: OriginalDialogs.MessageDialog.YesToAll; } MessageDialogButton { id: yesButton dialog: root text: qsTr("Yes") - button: OriginalDialogs.StandardButton.Yes + button: OriginalDialogs.MessageDialog.Yes KeyNavigation.right: noButton KeyNavigation.tab: noButton } - MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.StandardButton.Apply; } - MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.StandardButton.Ignore; } - MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.StandardButton.Retry; } - MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.StandardButton.SaveAll; } - MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.StandardButton.Save; } - MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.StandardButton.Open; } + MessageDialogButton { dialog: root; text: qsTr("Apply"); button: OriginalDialogs.MessageDialog.Apply; } + MessageDialogButton { dialog: root; text: qsTr("Ignore"); button: OriginalDialogs.MessageDialog.Ignore; } + MessageDialogButton { dialog: root; text: qsTr("Retry"); button: OriginalDialogs.MessageDialog.Retry; } + MessageDialogButton { dialog: root; text: qsTr("Save All"); button: OriginalDialogs.MessageDialog.SaveAll; } + MessageDialogButton { dialog: root; text: qsTr("Save"); button: OriginalDialogs.MessageDialog.Save; } + MessageDialogButton { dialog: root; text: qsTr("Open"); button: OriginalDialogs.MessageDialog.Open; } MessageDialogButton { id: okButton dialog: root text: qsTr("OK") - button: OriginalDialogs.StandardButton.Ok + button: OriginalDialogs.MessageDialog.Ok } Button { @@ -180,7 +180,7 @@ ModalWindow { onClicked: { content.state = (content.state === "" ? "expanded" : "") } visible: detailedText && detailedText.length > 0 } - MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.StandardButton.Help; } + MessageDialogButton { dialog: root; text: qsTr("Help"); button: OriginalDialogs.MessageDialog.Help; } } Item { @@ -256,7 +256,7 @@ ModalWindow { case Qt.Key_Escape: case Qt.Key_Back: event.accepted = true - root.click(OriginalDialogs.StandardButton.Cancel) + root.click(OriginalDialogs.MessageDialog.Cancel) break } } diff --git a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml index 3b3f7fb2d74..bece7b980c7 100644 --- a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml +++ b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml @@ -11,7 +11,7 @@ import Hifi 1.0 import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs Item { Component.onCompleted: { diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index c7772984abd..a9566e12f9c 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.7 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import QtQuick.Controls 2.3 import controlsUit 1.0 diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index 4ee53d44ef9..a5f912d367f 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -11,8 +11,7 @@ import QtQuick 2.7 import Qt.labs.folderlistmodel 2.2 import Qt.labs.settings 1.0 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import QtQuick.Controls 1.4 as QQC1 +import QtQuick.Dialogs as OriginalDialogs import QtQuick.Controls 2.3 import ".." @@ -460,7 +459,7 @@ TabletModalWindow { } } - Table { + TableView { id: fileTableView colorScheme: hifi.colorSchemes.light anchors { @@ -472,14 +471,14 @@ TabletModalWindow { bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height } headerVisible: !selectDirectory - onDoubleClicked: navigateToRow(row); + //onDoubleClicked: navigateToRow(row); focus: true Keys.onReturnPressed: navigateToCurrentRow(); Keys.onEnterPressed: navigateToCurrentRow(); - sortIndicatorColumn: 0 - sortIndicatorOrder: Qt.AscendingOrder - sortIndicatorVisible: true + property int sortIndicatorColumn: 0 + property var sortIndicatorOrder: Qt.AscendingOrder + property bool sortIndicatorVisible: true model: filesModel @@ -493,7 +492,7 @@ TabletModalWindow { onSortIndicatorOrderChanged: { updateSort(); } - itemDelegate: Item { + delegate: Item { clip: true FiraSansSemiBold { @@ -538,7 +537,7 @@ TabletModalWindow { } } - QQC1.TableViewColumn { + /*QQC1.TableViewColumn { id: fileNameColumn role: "fileName" title: "Name" @@ -562,7 +561,7 @@ TabletModalWindow { movable: false resizable: true visible: !selectDirectory - } + }*/ function navigateToRow(row) { currentRow = row; diff --git a/interface/resources/qml/dialogs/TabletMessageBox.qml b/interface/resources/qml/dialogs/TabletMessageBox.qml index 4411651a0f0..a28ff5575e3 100644 --- a/interface/resources/qml/dialogs/TabletMessageBox.qml +++ b/interface/resources/qml/dialogs/TabletMessageBox.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import controlsUit 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/dialogs/TabletQueryDialog.qml b/interface/resources/qml/dialogs/TabletQueryDialog.qml index 8f63730b8e9..4724ac28162 100644 --- a/interface/resources/qml/dialogs/TabletQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletQueryDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.7 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import QtQuick.Controls 2.3 import controlsUit 1.0 diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index eaf1d72fea2..6eacd58c816 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -10,7 +10,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 -import QtQuick.Controls 1.5 as QQC1 +import QtQuick.Controls 2.3 as QQC1 import controlsUit 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml index f5715fa2c22..a791b1d0406 100644 --- a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml +++ b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml @@ -9,13 +9,13 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 +import QtQuick.Dialogs import controlsUit 1.0 Button { property var dialog; - property int button: StandardButton.Ok; + property int button: MessageDialog.Ok; color: focus ? hifi.buttons.blue : hifi.buttons.white onClicked: dialog.click(button) diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index 48d29405b02..f668a22a64e 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.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 import controlsUit 1.0 import "../../hifi/tablet/tabletWindows/preferences" @@ -63,8 +63,8 @@ Preference { placeholderText: root.placeholderText text: preference.value colorScheme: dataTextField.acceptableInput ? hifi.colorSchemes.dark : hifi.colorSchemes.light - validator: RegExpValidator { - regExp: /.*\.(?:fst).*\?*/ig + validator: RegularExpressionValidator { + regularExpression: /.*\.(?:fst).*\?*/ig } anchors { left: parent.left diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index a9b755ad83f..038738cacbd 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import Hifi 1.0 import controlsUit 1.0 as HiFiControls diff --git a/interface/resources/qml/hifi/+android_interface/ActionBar.qml b/interface/resources/qml/hifi/+android_interface/ActionBar.qml index 3c58156f304..4b44cd3c798 100644 --- a/interface/resources/qml/hifi/+android_interface/ActionBar.qml +++ b/interface/resources/qml/hifi/+android_interface/ActionBar.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/+android_interface/AudioBar.qml b/interface/resources/qml/hifi/+android_interface/AudioBar.qml index 912572fdf8a..c5ff5775cf0 100644 --- a/interface/resources/qml/hifi/+android_interface/AudioBar.qml +++ b/interface/resources/qml/hifi/+android_interface/AudioBar.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/+android_interface/Desktop.qml b/interface/resources/qml/hifi/+android_interface/Desktop.qml index 99d792b664f..86d09ec64da 100644 --- a/interface/resources/qml/hifi/+android_interface/Desktop.qml +++ b/interface/resources/qml/hifi/+android_interface/Desktop.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import Qt.labs.settings 1.0 diff --git a/interface/resources/qml/hifi/+android_interface/StatsBar.qml b/interface/resources/qml/hifi/+android_interface/StatsBar.qml index 64e93b4a088..2435d742fba 100644 --- a/interface/resources/qml/hifi/+android_interface/StatsBar.qml +++ b/interface/resources/qml/hifi/+android_interface/StatsBar.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/+android_interface/WindowHeader.qml b/interface/resources/qml/hifi/+android_interface/WindowHeader.qml index 5316fc4786b..43448bada85 100644 --- a/interface/resources/qml/hifi/+android_interface/WindowHeader.qml +++ b/interface/resources/qml/hifi/+android_interface/WindowHeader.qml @@ -10,8 +10,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "." diff --git a/interface/resources/qml/hifi/+android_interface/bottomHudOptions.qml b/interface/resources/qml/hifi/+android_interface/bottomHudOptions.qml index 6b830d94c25..e459e904c1e 100644 --- a/interface/resources/qml/hifi/+android_interface/bottomHudOptions.qml +++ b/interface/resources/qml/hifi/+android_interface/bottomHudOptions.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "../../styles" as HifiStyles diff --git a/interface/resources/qml/hifi/+android_interface/button.qml b/interface/resources/qml/hifi/+android_interface/button.qml index a4c65b3c6f1..d83dd41d123 100644 --- a/interface/resources/qml/hifi/+android_interface/button.qml +++ b/interface/resources/qml/hifi/+android_interface/button.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 Item { diff --git a/interface/resources/qml/hifi/+android_interface/modesbar.qml b/interface/resources/qml/hifi/+android_interface/modesbar.qml index 1bf04fb8d98..f20e7c8ca0c 100644 --- a/interface/resources/qml/hifi/+android_interface/modesbar.qml +++ b/interface/resources/qml/hifi/+android_interface/modesbar.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 75d7370c80a..baff11c7ded 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -8,11 +8,11 @@ // 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.Dialogs 1.2 as OriginalDialogs -import Qt.labs.settings 1.0 +import QtQuick +import QtQuick.Controls +//import QtQuick.Controls.Styles +import QtQuick.Dialogs as OriginalDialogs +import Qt.labs.settings import stylesUit 1.0 import controlsUit 1.0 as HifiControls @@ -677,6 +677,8 @@ Windows.ScrollingWindow { font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight + //QT6TODO + /* style: TextFieldStyle { textColor: readOnly ? hifi.colors.black @@ -691,10 +693,10 @@ Windows.ScrollingWindow { selectionColor: hifi.colors.primaryHighlight padding.left: readOnly ? 0 : hifi.dimensions.textPadding padding.right: readOnly ? 0 : hifi.dimensions.textPadding - } + }*/ - validator: RegExpValidator { - regExp: /[^/]+/ + validator: RegularExpressionValidator { + regularExpression: /[^/]+/ } Keys.onPressed: { diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index 0a02418a8bf..582d1a468e9 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -1,8 +1,8 @@ -import QtQuick 2.6 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQml.Models 2.1 -import QtGraphicalEffects 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQml.Models +import Qt5Compat.GraphicalEffects import controlsUit 1.0 as HifiControls import stylesUit 1.0 import "avatarapp" diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 9fb8067371c..2ba146af976 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -13,7 +13,7 @@ import Hifi 1.0 import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import TabletScriptingInterface 1.0 import "toolbars" diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 3239471a00f..e3644504e23 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -1,5 +1,5 @@ +import QtCore import QtQuick 2.7 -import Qt.labs.settings 1.0 as QtSettings import QtQuick.Controls 2.3 @@ -12,9 +12,13 @@ import controlsUit 1.0 OriginalDesktop.Desktop { id: desktop + // QT6TODO: Desktop just eats all mouse inputs + visible: true + property alias toolbarObjectName: sysToolbar.objectName - MouseArea { + // QT6TODO: this breaks VR mouse cursor since + /*MouseArea { id: hoverWatch anchors.fill: parent hoverEnabled: true @@ -23,7 +27,7 @@ OriginalDesktop.Desktop { onEntered: if (typeof ApplicationCompositor !== "undefined") ApplicationCompositor.reticleOverDesktop = true onExited: if (typeof ApplicationCompositor !== "undefined") ApplicationCompositor.reticleOverDesktop = false acceptedButtons: Qt.NoButton - } + }*/ Action { text: "Open Browser" @@ -79,7 +83,7 @@ OriginalDesktop.Desktop { } signal toolbarVisibleChanged(bool isVisible, string toolbarName); - QtSettings.Settings { + Settings { id: settings; category: "toolbar"; property bool constrainToolbarToCenterX: true; diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index a9fde05d8d4..8c057244617 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -13,7 +13,7 @@ import Hifi 1.0 import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "toolbars" import stylesUit 1.0 import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 0dd29b9e0f4..e7f0100325f 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -10,9 +10,9 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import controlsUit 1.0 as HifiControls import "toolbars" @@ -534,10 +534,12 @@ Item { anchors.left: nameCardVUMeter.left; // Properties visible: (!isMyCard && (selected && pal.activeTab == "nearbyTab")) && isPresent; - minimumValue: -60.0 - maximumValue: 20.0 + // QT6TODO + //minimumValue: -60.0 + //maximumValue: 20.0 stepSize: 5 - updateValueWhileDragging: true + // QT6TODO + //updateValueWhileDragging: true value: Users.getAvatarGain(uuid) onValueChanged: { updateGainFromQML(uuid, value, false); @@ -565,7 +567,8 @@ Item { mouse.accepted = false } } - style: SliderStyle { + // QT6TODO + /*style: SliderStyle { groove: Rectangle { color: "#c5c5c5" implicitWidth: gainSlider.width @@ -579,7 +582,7 @@ Item { implicitWidth: 10 implicitHeight: 16 } - } + }*/ } function updateGainFromQML(avatarUuid, sliderValue, isReleased) { diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index b842b736d42..39cbaacceb8 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -12,8 +12,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtGraphicalEffects 1.0 +import QtQuick.Controls 2.3 +import Qt5Compat.GraphicalEffects import Qt.labs.settings 1.0 import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit @@ -118,6 +118,7 @@ Rectangle { comboDialog.populateComboListViewModel(); comboDialog.visible = true; } + // QT6TODO: this is deprecated Settings { id: settings; category: "pal"; @@ -427,16 +428,18 @@ Rectangle { // This TableView refers to the Nearby Table (on the "Nearby" tab below the current user's NameCard) HifiControlsUit.Table { id: nearbyTable; - flickableItem.interactive: true; + // QT6TODO + //flickableItem.interactive: true; // Anchors anchors.fill: parent; // Properties centerHeaderText: true; - sortIndicatorVisible: true; - headerVisible: true; - sortIndicatorColumn: settings.nearbySortIndicatorColumn; - sortIndicatorOrder: settings.nearbySortIndicatorOrder; - onSortIndicatorColumnChanged: { + // QT6TODO + //sortIndicatorVisible: true; + //headerVisible: true; + //sortIndicatorColumn: settings.nearbySortIndicatorColumn; + //sortIndicatorOrder: settings.nearbySortIndicatorOrder; + /*onSortIndicatorColumnChanged: { if (sortIndicatorColumn > 2) { // these are not sortable, switch back to last column sortIndicatorColumn = settings.nearbySortIndicatorColumn; @@ -444,13 +447,15 @@ Rectangle { settings.nearbySortIndicatorColumn = sortIndicatorColumn; sortModel(); } - } - onSortIndicatorOrderChanged: { + }*/ + // Qt6TODO + /*onSortIndicatorOrderChanged: { settings.nearbySortIndicatorOrder = sortIndicatorOrder; sortModel(); - } + }*/ - TableViewColumn { + // QT6TODO: how to port these? + /*TableViewColumn { role: "avgAudioLevel"; title: "LOUD"; width: actionButtonWidth; @@ -489,20 +494,22 @@ Rectangle { width: actionButtonWidth; movable: false; resizable: false; - } + }*/ model: ListModel { id: nearbyUserModel; } // This Rectangle refers to each Row in the nearbyTable. - rowDelegate: Rectangle { // The only way I know to specify a row height. + // QT6TODO + /*rowDelegate: Rectangle { // The only way I know to specify a row height. // Size height: rowHeight + (styleData.selected ? 15 : 0); color: nearbyRowColor(styleData.selected, styleData.alternate); - } + }*/ // This Item refers to the contents of each Cell - itemDelegate: Item { + // QT6TODO + /*itemDelegate: Item { id: itemCell; property bool isCheckBox: styleData.role === "personalMute" || styleData.role === "ignore"; property bool isButton: styleData.role === "mute" || styleData.role === "kick"; @@ -664,7 +671,7 @@ Rectangle { : hifi.buttons.disabledTextColor[actionButton.colorScheme]; } } - } + }*/ } // Separator between user and admin functions @@ -824,24 +831,27 @@ Rectangle { // This TableView refers to the Connections Table (on the "Connections" tab below the current user's NameCard) HifiControlsUit.Table { id: connectionsTable; - flickableItem.interactive: true; + // QT6TODO + //flickableItem.interactive: true; visible: !connectionsLoading.visible; // Anchors anchors.fill: parent; // Properties centerHeaderText: true; - sortIndicatorVisible: true; - headerVisible: true; - sortIndicatorColumn: settings.connectionsSortIndicatorColumn; + // QT6TODO + //sortIndicatorVisible: true; + //headerVisible: true; + /*sortIndicatorColumn: settings.connectionsSortIndicatorColumn; sortIndicatorOrder: settings.connectionsSortIndicatorOrder; onSortIndicatorColumnChanged: { settings.connectionsSortIndicatorColumn = sortIndicatorColumn; } onSortIndicatorOrderChanged: { settings.connectionsSortIndicatorOrder = sortIndicatorOrder; - } + }*/ - TableViewColumn { + // QT6TODO: how to port these? + /*TableViewColumn { id: connectionsUserNameHeader; role: "userName"; title: connectionsUserModel.totalEntries + (connectionsUserModel.totalEntries === 1 ? " NAME" : " NAMES"); @@ -862,19 +872,21 @@ Rectangle { width: actionButtonWidth; movable: false; resizable: false; - } + }*/ model: connectionsUserModel; // This Rectangle refers to each Row in the connectionsTable. - rowDelegate: Rectangle { + // QT6TODO + /*rowDelegate: Rectangle { // Size height: rowHeight + (styleData.selected ? 15 : 0); color: connectionsRowColor(styleData.selected, styleData.alternate); - } + }*/ // This Item refers to the contents of each Cell - itemDelegate: Item { + // QT6TODO + /*itemDelegate: Item { id: connectionsItemCell; // This NameCard refers to the cell that contains a connection's UserName @@ -947,7 +959,7 @@ Rectangle { UserActivityLogger["palAction"](checked ? styleData.role : "un-" + styleData.role, model.sessionId); } } - } + }*/ } // "Make a Connection" instructions diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 7bfdf028891..c93e28b28e6 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -15,7 +15,7 @@ import QtQuick 2.10 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit diff --git a/interface/resources/qml/hifi/audio/InputPeak.qml b/interface/resources/qml/hifi/audio/InputPeak.qml index d8b166cee49..c6b5ce99900 100644 --- a/interface/resources/qml/hifi/audio/InputPeak.qml +++ b/interface/resources/qml/hifi/audio/InputPeak.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { property var peak; diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index 55378589ecc..637a02adab0 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/hifi/audio/MicBarApplication.qml b/interface/resources/qml/hifi/audio/MicBarApplication.qml index d77668e5bfe..798c77f3f59 100644 --- a/interface/resources/qml/hifi/audio/MicBarApplication.qml +++ b/interface/resources/qml/hifi/audio/MicBarApplication.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml index be9fe932e0b..9d78f68147d 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml @@ -2,7 +2,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQml.Models 2.1 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import Hifi.AvatarPackager.AvatarProjectStatus 1.0 import "../../controlsUit" 1.0 as HifiControls import "../../stylesUit" 1.0 diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml index 2b06d7e99ee..f1b55e1b69e 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml @@ -1,7 +1,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Controls 2.2 as Original diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml index 21d0683fb11..58d22675ea9 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml @@ -1,5 +1,5 @@ import QtQuick 2.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "../../controlsUit" 1.0 as HifiControls import "../../stylesUit" 1.0 diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml index 68f465f514f..4f5acd88734 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProjectUpload.qml @@ -1,7 +1,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Controls 2.2 as Original diff --git a/interface/resources/qml/hifi/avatarPackager/LoadingCircle.qml b/interface/resources/qml/hifi/avatarPackager/LoadingCircle.qml index a1fac72ae4c..1160e8474a6 100644 --- a/interface/resources/qml/hifi/avatarPackager/LoadingCircle.qml +++ b/interface/resources/qml/hifi/avatarPackager/LoadingCircle.qml @@ -1,7 +1,7 @@ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects AnimatedImage { id: root diff --git a/interface/resources/qml/hifi/avatarapp/AvatarThumbnail.qml b/interface/resources/qml/hifi/avatarapp/AvatarThumbnail.qml index 8582b9249bd..41bb864caee 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarThumbnail.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarThumbnail.qml @@ -1,5 +1,5 @@ import QtQuick 2.9 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { width: 92 diff --git a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml index 5d72bef43da..666fbf0b932 100644 --- a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml +++ b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml @@ -13,7 +13,7 @@ Rectangle { property string titleText: 'Create Favorite' property string favoriteNameText: favoriteName.text - property string avatarImageUrl: null + property string avatarImageUrl: "" property int wearablesCount: 0 property string button1color: hifi.buttons.noneBorderlessGray; diff --git a/interface/resources/qml/hifi/avatarapp/MessageBox.qml b/interface/resources/qml/hifi/avatarapp/MessageBox.qml index 88f7f888cb0..ecfb193a2a7 100644 --- a/interface/resources/qml/hifi/avatarapp/MessageBox.qml +++ b/interface/resources/qml/hifi/avatarapp/MessageBox.qml @@ -16,7 +16,7 @@ Rectangle { property alias inputText: input; property alias dialogButtons: buttons - property string imageSource: null + property string imageSource: "" property string button1color: hifi.buttons.noneBorderlessGray; property string button1text: '' @@ -70,6 +70,7 @@ Rectangle { width: Math.max(parent.width * 0.8, 400) property int margin: 30; + // QT6TODO: QML QQuickRectangle*: Binding loop detected for property "height" height: childrenRect.height + margin * 2 onHeightChanged: { console.debug('mainContainer: height = ', height) diff --git a/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml b/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml index 68df6d68f5b..5faaf91b5e1 100644 --- a/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml +++ b/interface/resources/qml/hifi/avatarapp/MessageBoxes.qml @@ -1,4 +1,4 @@ -import QtQuick 2.5 +import QtQuick MessageBox { id: popup diff --git a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml index a2c84fad472..7cf7b2ac03d 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml @@ -1,6 +1,6 @@ import stylesUit 1.0 import QtQuick 2.9 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { property alias text: glyph.text diff --git a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml index 51e10437025..1b66bfa20d0 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml @@ -1,6 +1,6 @@ import stylesUit 1.0 import QtQuick 2.9 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { property alias source: image.source diff --git a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml index 3968fcb1ff2..a719627509c 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml @@ -1,6 +1,6 @@ import stylesUit 1.0 import QtQuick 2.9 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { property alias color: rectangle.color diff --git a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml index 69aff47373c..2615df7f783 100644 --- a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml +++ b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml @@ -1,7 +1,7 @@ import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit import QtQuick 2.9 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { id: root diff --git a/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml b/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml index c8ac5f47782..7af7d554ed1 100644 --- a/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml +++ b/interface/resources/qml/hifi/avatarapp/TransparencyMask.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick Item { property alias source: sourceImage.sourceItem @@ -15,7 +15,8 @@ Item { hideSource: true } - ShaderEffect { + // QT6TODO: this needs to be ported to Qt6 - probably converting into .qsb is needed +/* ShaderEffect { id: maskEffect anchors.fill: parent @@ -40,5 +41,5 @@ void main() } " } - } + }*/ } \ No newline at end of file diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index b9cfe113f08..8c52ce41d19 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -9,8 +9,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 2.3 +import QtQuick.Dialogs as OriginalDialogs import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 6374e85ada5..c9e2572a24a 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -9,9 +9,9 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 2.3 +//import QtQuick.Controls.Styles +import QtQuick.Dialogs as OriginalDialogs import Qt.labs.settings 1.0 import stylesUit 1.0 @@ -675,6 +675,8 @@ Rectangle { font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.dimensions.tableRowHeight + //QT6TODO + /* style: TextFieldStyle { textColor: readOnly ? hifi.colors.black @@ -689,10 +691,10 @@ Rectangle { selectionColor: hifi.colors.primaryHighlight padding.left: readOnly ? 0 : hifi.dimensions.textPadding padding.right: readOnly ? 0 : hifi.dimensions.textPadding - } + }*/ - validator: RegExpValidator { - regExp: /[^/]+/ + validator: RegularExpressionValidator { + regularExpression: /[^/]+/ } Keys.onPressed: { diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 4aeeada1e5a..9bb91f20c13 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -9,8 +9,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 2.3 +import QtQuick.Dialogs as OriginalDialogs import Qt.labs.settings 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/dialogs/security/Security.qml b/interface/resources/qml/hifi/dialogs/security/Security.qml index 8942a451970..a8bb5874681 100644 --- a/interface/resources/qml/hifi/dialogs/security/Security.qml +++ b/interface/resources/qml/hifi/dialogs/security/Security.qml @@ -13,7 +13,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 as HifiStylesUit import controlsUit 1.0 as HifiControlsUit import "qrc:////qml//controls" as HifiControls diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml index f3fbb88c078..dce25783938 100644 --- a/interface/resources/qml/hifi/overlays/ImageOverlay.qml +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -1,5 +1,5 @@ import QtQuick 2.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." diff --git a/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/AvatarAppListDelegate.qml b/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/AvatarAppListDelegate.qml index a14f5d7bdef..1cd5003a568 100644 --- a/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/AvatarAppListDelegate.qml +++ b/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/AvatarAppListDelegate.qml @@ -12,7 +12,7 @@ import QtQuick 2.10 import "../../simplifiedConstants" as SimplifiedConstants import "../../simplifiedControls" as SimplifiedControls import stylesUit 1.0 as HifiStylesUit -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Rectangle { id: root diff --git a/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/DisplayNameHeader.qml b/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/DisplayNameHeader.qml index e039734e731..e032150b0b5 100644 --- a/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/DisplayNameHeader.qml +++ b/interface/resources/qml/hifi/simplifiedUI/avatarApp/components/DisplayNameHeader.qml @@ -13,7 +13,7 @@ import "../../simplifiedConstants" as SimplifiedConstants import "../../simplifiedControls" as SimplifiedControls import stylesUit 1.0 as HifiStylesUit import controlsUit 1.0 as HifiControlsUit -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { id: root diff --git a/interface/resources/qml/hifi/simplifiedUI/inputDeviceButton/InputDeviceButton.qml b/interface/resources/qml/hifi/simplifiedUI/inputDeviceButton/InputDeviceButton.qml index 9e02820168e..a893f397158 100644 --- a/interface/resources/qml/hifi/simplifiedUI/inputDeviceButton/InputDeviceButton.qml +++ b/interface/resources/qml/hifi/simplifiedUI/inputDeviceButton/InputDeviceButton.qml @@ -10,7 +10,7 @@ // import QtQuick 2.10 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import TabletScriptingInterface 1.0 import "../simplifiedConstants" as SimplifiedConstants diff --git a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/InputPeak.qml b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/InputPeak.qml index c8440dc7d64..89d8f62d7fa 100644 --- a/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/InputPeak.qml +++ b/interface/resources/qml/hifi/simplifiedUI/simplifiedControls/InputPeak.qml @@ -9,7 +9,7 @@ // import QtQuick 2.10 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects Item { property var peak diff --git a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml index 1f0cd9008b2..20a9f77d24b 100644 --- a/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml +++ b/interface/resources/qml/hifi/simplifiedUI/topBar/SimplifiedTopBar.qml @@ -14,7 +14,7 @@ import "../simplifiedConstants" as SimplifiedConstants import "../inputDeviceButton" as InputDeviceButton import stylesUit 1.0 as HifiStylesUit import TabletScriptingInterface 1.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. Rectangle { diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index 6b2aa331e8d..13e713388a9 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -8,7 +8,7 @@ import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import "../../controls" diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index ee4865258e4..0e2df1a4e98 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick.Window 2.2 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import Qt.labs.settings 1.0 import stylesUit 1.0 import "../../controls" diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 20a68237cf3..8fdb8b478ef 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Controls 2.2 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/tablet/TADLightbox.qml b/interface/resources/qml/hifi/tablet/TADLightbox.qml index 35a01aeec31..abfd3a19ca9 100644 --- a/interface/resources/qml/hifi/tablet/TADLightbox.qml +++ b/interface/resources/qml/hifi/tablet/TADLightbox.qml @@ -13,7 +13,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit import "qrc:////qml//controls" as HifiControls diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index fdb05c8a35f..96858c855b8 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls 2.2 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 +//import QtQuick.Controls.Styles +import Qt5Compat.GraphicalEffects import "../../controls" import "../../styles" import "../../windows" diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index bea2d31e2bd..2b1afce685d 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -1,5 +1,5 @@ import QtQuick 2.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import TabletScriptingInterface 1.0 Item { diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 1a1e0a96ff2..10f8a5eb542 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -1,6 +1,6 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Layouts 1.3 import TabletScriptingInterface 1.0 @@ -188,7 +188,7 @@ Item { Repeater { id: pageRepeater model: tabletProxy != null ? Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage) : 0 - onItemAdded: { + onItemAdded: (index, item) => { item.proxyModel.sourceModel = tabletProxy != null ? tabletProxy.buttons : null; item.proxyModel.pageIndex = index; } @@ -272,7 +272,7 @@ Item { Connections { target: modelData; - onPropertiesChanged: { + function onPropertiesChanged() { updateProperties(); } } diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 5f06e4fbab7..bc97b515c7d 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 +import Qt5Compat.GraphicalEffects +import QtQuick.Controls 2.3 import QtQml 2.2 @@ -15,7 +15,7 @@ FocusScope { width: parent.width height: parent.height - property var rootMenu: Menu { objectName:"rootMenu" } + property var rootMenu: WrappedMenu { objectName:"rootMenu" } property var point: Qt.point(50, 50); TabletMenuStack { id: menuPopperUpper } property string subMenu: "" diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml index 25db90c771a..a127c79161f 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import controlsUit 1.0 import stylesUit 1.0 diff --git a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml index 76d170cba84..2e427b016af 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "." diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 5e90696adc6..cc11fb7c617 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -27,30 +27,30 @@ Rectangle { option = value; } - Component { id: inputDialogBuilder; TabletQueryDialog { } } + Component { id: inputDialogBuilder; Item {}}//TabletQueryDialog { } } function inputDialog(properties) { openModal = inputDialogBuilder.createObject(tabletRoot, properties); return openModal; } - Component { id: messageBoxBuilder; TabletMessageBox { } } + Component { id: messageBoxBuilder; Item {}}//TabletMessageBox { } } function messageBox(properties) { openMessage = messageBoxBuilder.createObject(tabletRoot, properties); return openMessage; } - Component { id: customInputDialogBuilder; TabletCustomQueryDialog { } } + Component { id: customInputDialogBuilder; Item {}}//TabletCustomQueryDialog { } } function customInputDialog(properties) { openModal = customInputDialogBuilder.createObject(tabletRoot, properties); return openModal; } - Component { id: fileDialogBuilder; TabletFileDialog { } } + Component { id: fileDialogBuilder; Item { }}//TabletFileDialog { } } function fileDialog(properties) { openModal = fileDialogBuilder.createObject(tabletRoot, properties); return openModal; } - Component { id: assetDialogBuilder; TabletAssetDialog { } } + Component { id: assetDialogBuilder; Item { }}//TabletAssetDialog { } } function assetDialog(properties) { openModal = assetDialogBuilder.createObject(tabletRoot, properties); return openModal; @@ -287,7 +287,7 @@ Rectangle { } width: 480 - height: 706 + height: 720 function setShown(value) { if (value === true) { diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index dcdc711936e..4f3d10aee92 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -11,11 +11,10 @@ // TODO: FIXME: this is practically identical to TabletRoot.qml import "../../windows" as Windows +import QtCore import QtQuick 2.0 import Hifi 1.0 -import Qt.labs.settings 1.0 - Windows.ScrollingWindow { id: tabletRoot objectName: "tabletRoot" @@ -32,7 +31,7 @@ Windows.ScrollingWindow { id: settings category: "WindowRoot.Windows" property real width: 480 - property real height: 706 + property real height: 720 } onResizableChanged: { @@ -41,7 +40,7 @@ Windows.ScrollingWindow { settings.width = tabletRoot.width settings.height = tabletRoot.height tabletRoot.width = 480 - tabletRoot.height = 706 + tabletRoot.height = 720 } else { tabletRoot.width = settings.width tabletRoot.height = settings.height @@ -205,7 +204,6 @@ Windows.ScrollingWindow { } } - implicitWidth: 480 - implicitHeight: 706 + implicitHeight: 720 } diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml index 91dc6fe5684..796a93fa39d 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import Qt.labs.folderlistmodel 2.2 import Qt.labs.settings 1.0 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import QtQuick.Controls 1.4 as QQC1 +import QtQuick.Dialogs as OriginalDialogs +import QtQuick.Controls 2.3 as QQC1 import QtQuick.Controls 2.3 import ".." @@ -466,15 +466,17 @@ Rectangle { bottom: currentSelection.top bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height } - headerVisible: !selectDirectory - onDoubleClicked: navigateToRow(row); + // QT6TODO: doesn't exist on Qt 6. + //headerVisible: !selectDirectory + //onDoubleClicked: navigateToRow(row); focus: true Keys.onReturnPressed: navigateToCurrentRow(); Keys.onEnterPressed: navigateToCurrentRow(); - sortIndicatorColumn: 0 - sortIndicatorOrder: Qt.AscendingOrder - sortIndicatorVisible: true + // QT6TODO: doesn't exist on Qt 6. + //sortIndicatorColumn: 0 + //sortIndicatorOrder: Qt.AscendingOrder + //sortIndicatorVisible: true model: filesModel @@ -484,11 +486,14 @@ Rectangle { fileTableModel.update(); } - onSortIndicatorColumnChanged: { updateSort(); } + // QT6TODO: doesn't exist on Qt 6. + //onSortIndicatorColumnChanged: { updateSort(); } - onSortIndicatorOrderChanged: { updateSort(); } + // QT6TODO: doesn't exist on Qt 6. + //onSortIndicatorOrderChanged: { updateSort(); } - itemDelegate: Item { + // QT6TODO: How to port this? + /*itemDelegate: Item { clip: true FiraSansSemiBold { @@ -531,9 +536,10 @@ Rectangle { return size + " " + suffixes[suffixIndex]; } } - } + }*/ - QQC1.TableViewColumn { + // QT6TODO: I have no idea how to port this + /*QQC1.TableViewColumn { id: fileNameColumn role: "fileName" title: "Name" @@ -557,7 +563,7 @@ Rectangle { movable: false resizable: true visible: !selectDirectory - } + }*/ function navigateToRow(row) { currentRow = row; diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml index 57fdeb482b7..2af1857e5cf 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.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 import Hifi 1.0 import "../../../../dialogs/preferences" diff --git a/interface/resources/qml/hifi/toolbars/Toolbar.qml b/interface/resources/qml/hifi/toolbars/Toolbar.qml index 56028d71f05..b4db726566d 100644 --- a/interface/resources/qml/hifi/toolbars/Toolbar.qml +++ b/interface/resources/qml/hifi/toolbars/Toolbar.qml @@ -1,5 +1,5 @@ +import QtCore import QtQuick 2.5 -import Qt.labs.settings 1.0 import "../../windows" import "." diff --git a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml index 303712b4f70..f503e93f0f3 100644 --- a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml +++ b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml @@ -1,5 +1,7 @@ import QtQuick 2.5 +// TODO: figure out a way of hooking these up to +// the theme constants without too much breakage StateImage { id: button diff --git a/interface/resources/qml/overte/BodyText.qml b/interface/resources/qml/overte/BodyText.qml new file mode 100644 index 00000000000..303301567bd --- /dev/null +++ b/interface/resources/qml/overte/BodyText.qml @@ -0,0 +1,29 @@ +import QtQuick +import QtQuick.Controls + +import "." + +TextEdit { + selectByMouse: true + readOnly: true + + font.pixelSize: Theme.fontPixelSize + font.family: Theme.bodyFontFamily + color: Theme.paletteActive.text + + textFormat: TextEdit.PlainText + wrapMode: TextEdit.Wrap + + selectedTextColor: Theme.paletteActive.highlightedText + selectionColor: Theme.paletteActive.highlight + + // TODO: should we continue supporting the in-game browser + // or should we transition to always using the system one? + // Qt doesn't make it easy to theme rich text + onLinkActivated: link => Qt.openUrlExternally(link) + + HoverHandler { + enabled: parent.hoveredLink + cursorShape: Qt.PointingHandCursor + } +} diff --git a/interface/resources/qml/overte/Button.qml b/interface/resources/qml/overte/Button.qml new file mode 100644 index 00000000000..bcc255b0fbb --- /dev/null +++ b/interface/resources/qml/overte/Button.qml @@ -0,0 +1,55 @@ +import QtQuick +import QtQuick.Controls +import "." + +Button { + id: button + property color backgroundColor: Theme.paletteActive.button + property color color: Theme.paletteActive.buttonText + + palette.buttonText: color + font.family: Theme.fontFamily + font.pixelSize: Theme.fontPixelSize + horizontalPadding: 12 + verticalPadding: 8 + hoverEnabled: true + + opacity: enabled ? 1.0 : 0.5 + + background: Rectangle { + opacity: flat ? 0.0 : 1.0 + + id: buttonBg + radius: Theme.borderRadius + border.width: button.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: ( + button.activeFocus ? + Theme.paletteActive.focusRing : + ( + Theme.highContrast ? + Theme.paletteActive.buttonText : + Qt.darker(button.backgroundColor, Theme.borderDarker) + ) + ) + color: { + if (button.down || button.checked) { + return Qt.darker(button.backgroundColor, Theme.checkedDarker); + } else if (button.hovered && button.enabled) { + return Qt.lighter(button.backgroundColor, Theme.hoverLighter); + } else { + return button.backgroundColor; + } + } + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(buttonBg.color, (button.down || button.checked) ? 0.9 : 1.1) + } + GradientStop { + position: 0.5; color: buttonBg.color + } + GradientStop { + position: 1.0; color: Qt.darker(buttonBg.color, (button.down || button.checked) ? 0.9 : 1.1) + } + } + } +} diff --git a/interface/resources/qml/overte/ComboBox.qml b/interface/resources/qml/overte/ComboBox.qml new file mode 100644 index 00000000000..89a6741ad93 --- /dev/null +++ b/interface/resources/qml/overte/ComboBox.qml @@ -0,0 +1,141 @@ +import QtQuick +import QtQuick.Controls +import "." + +ComboBox { + id: control + + property color backgroundColor: flat ? "#00000000" : Theme.paletteActive.window + property color color: Theme.paletteActive.windowText + + implicitHeight: Theme.fontPixelSize * 2 + + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + + indicator: Button { + anchors.right: control.right + width: control.height + height: control.height + + horizontalPadding: 2 + verticalPadding: 2 + focusPolicy: Qt.NoFocus + flat: control.flat + + icon.source: "./icons/triangle_down.svg" + icon.width: 24 + icon.height: 24 + icon.color: Theme.paletteActive.buttonText + + onClicked: { + control.forceActiveFocus(); + + if (control.popup.opened) { + control.popup.close(); + } else { + control.popup.open(); + } + } + } + + contentItem: Text { + leftPadding: 6 + rightPadding: control.indicator.width + control.spacing + text: control.displayText + font: control.font + color: control.color + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + opacity: enabled ? 1.0 : 0.5 + } + + background: Rectangle { + opacity: enabled ? 1.0 : 0.5 + width: (control.width - control.indicator.width) + Theme.borderWidth + radius: Theme.borderRadius + border.width: control.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: { + if (control.activeFocus) { + return Theme.paletteActive.focusRing; + } else if (control.flat) { + return "#00000000"; + } else if (Theme.highContrast) { + return parent.color; + } else { + return Qt.darker(control.backgroundColor, Theme.borderDarker); + } + } + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.darker(control.backgroundColor, control.flat ? 1.0 : 1.02) } + GradientStop { position: 0.5; color: control.backgroundColor } + GradientStop { position: 1.0; color: Qt.lighter(control.backgroundColor, control.flat ? 1.0 : 1.02) } + } + } + + delegate: ItemDelegate { + id: delegate + + required property var model + required property int index + + width: control.width + contentItem: Text { + text: delegate.model[control.textRole] + color: highlighted ? Theme.paletteActive.highlightedText : Theme.paletteActive.tooltipText + font: control.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + background: Rectangle { + color: highlighted ? Theme.paletteActive.highlight : Theme.paletteActive.tooltip + } + + highlighted: control.highlightedIndex === index + } + + popup: Popup { + y: control.height - Theme.borderWidth + width: control.width + (contentItem.ScrollBar.vertical.opacity > 0.0 ? contentItem.ScrollBar.vertical.width : 0) + height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin) + padding: 3 + + contentItem: ListView { + clip: true + implicitHeight: contentHeight + (parent.padding * 2) + model: control.popup.visible ? control.delegateModel : null + currentIndex: control.highlightedIndex + + ScrollBar.vertical: ScrollBar { + interactive: false + } + } + + background: Item { + // drop shadow + Rectangle { + x: 3 + y: 3 + width: parent.width + height: parent.height + + radius: Theme.borderRadius + color: "#a0000000" + } + + Rectangle { + x: 0 + y: 0 + width: parent.width + height: parent.height + + radius: Theme.borderRadius + border.width: Theme.borderWidth + border.color: Qt.darker(Theme.paletteActive.tooltip, 2.5) + color: Theme.paletteActive.tooltip + } + } + } +} + diff --git a/interface/resources/qml/overte/Dialog.qml b/interface/resources/qml/overte/Dialog.qml new file mode 100644 index 00000000000..6df695b25bb --- /dev/null +++ b/interface/resources/qml/overte/Dialog.qml @@ -0,0 +1,81 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Dialogs + +import "." + +Rectangle { + id: dialog + visible: false + + default property alias content: dialogWindow.children + + property int maxWidth: 480 + property int maxHeight: -1 + + property bool shadedBackground: true + + function open() { + visible = true; + opacity = Theme.reducedMotion ? 1 : 0; + } + + function close() { + visible = false; + opacity = 0; + } + + color: !shadedBackground ? "transparent" : Theme.paletteActive.dialogShade + + opacity: Theme.reducedMotion ? 1 : 0 + OpacityAnimator on opacity { + from: Theme.reducedMotion ? 1 : 0 + to: 1 + duration: 150 + easing.type: Easing.InQuad + running: dialog.visible + } + + // block any inputs from underneath + MouseArea { + enabled: parent.visible + anchors.fill: parent + hoverEnabled: true + } + + Rectangle { + id: dialogWindow + width: Math.min( + (maxWidth == -1 ? Infinity : maxWidth), + children[0].implicitWidth + (children[0].anchors.margins * 2), + parent.width - 8 + ) + height: Math.min( + (maxHeight == -1 ? Infinity : maxHeight), + children[0].implicitHeight + (children[0].anchors.margins * 2), + parent.height - 8 + ) + anchors.centerIn: parent + + color: Theme.paletteActive.base + radius: 8 + border.width: 2 + border.color: Theme.highContrast ? Theme.paletteActive.text : Qt.darker(Theme.paletteActive.base, Theme.borderDarker) + + OpacityAnimator on opacity { + from: Theme.reducedMotion ? 1 : 0 + to: 1 + easing.type: Easing.OutQuad + duration: 200 + running: dialog.visible + } + + ScaleAnimator on scale { + from: Theme.reducedMotion ? 1 : 0.9 + to: 1 + easing.type: Easing.OutQuad + duration: 200 + running: dialog.visible + } + } +} diff --git a/interface/resources/qml/overte/Label.qml b/interface/resources/qml/overte/Label.qml new file mode 100644 index 00000000000..86fc51694cd --- /dev/null +++ b/interface/resources/qml/overte/Label.qml @@ -0,0 +1,9 @@ +import QtQuick +import QtQuick.Controls +import "." + +Label { + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + color: Theme.paletteActive.text +} diff --git a/interface/resources/qml/overte/MessageDialog.qml b/interface/resources/qml/overte/MessageDialog.qml new file mode 100644 index 00000000000..33cd5dcde0d --- /dev/null +++ b/interface/resources/qml/overte/MessageDialog.qml @@ -0,0 +1,114 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Dialogs + +import "." + +Dialog { + id: root + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + readonly property var buttonRoles: [ + { label: qsTr("Ok"), flag: MessageDialog.Ok, role: MessageDialog.AcceptRole }, + { label: qsTr("Save"), flag: MessageDialog.Save, role: MessageDialog.AcceptRole }, + { label: qsTr("Yes"), flag: MessageDialog.Yes, role: MessageDialog.YesRole }, + { label: qsTr("Cancel"), flag: MessageDialog.Cancel, role: MessageDialog.RejectRole }, + { label: qsTr("Discard"), flag: MessageDialog.Discard, role: MessageDialog.DestructiveRole }, + { label: qsTr("No"), flag: MessageDialog.No, role: MessageDialog.NoRole }, + ] + + property string text: "Oops! Your ModalDialog doesn't have any text." + property string descriptiveText: "" + property int buttons: MessageDialog.Ok | MessageDialog.Cancel + property int result: MessageDialog.Ok + + property list buttonDataModel: { + let list = []; + + for (let role of buttonRoles) { + if ((role.flag & buttons) !== 0) { + list.push(role); + } + } + + return list.reverse(); + } + + signal accepted + signal rejected + signal buttonClicked(button: int, role: int) + + function reject() { + rejected(); + close(); + } + + function accept() { + accepted(); + close(); + } + + onButtonClicked: (button, role) => { + result = button; + + switch (role) { + case MessageDialog.AcceptRole: + case MessageDialog.YesRole: + accept(); + break; + + case MessageDialog.RejectRole: + case MessageDialog.NoRole: + reject(); + break; + } + } + + ColumnLayout { + id: layout + anchors.fill: parent + anchors.margins: 8 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.margins: 8 + + visible: root.text !== "" + text: root.text + wrapMode: Text.Wrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.margins: 8 + + visible: root.descriptiveText !== "" + text: root.descriptiveText + wrapMode: Text.Wrap + } + + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignRight + + Repeater { + model: buttonDataModel + delegate: Button { + required property string label + required property int flag + required property int role + + Layout.fillWidth: true + Layout.minimumWidth: 96 + Layout.preferredWidth: 96 + + text: label + onClicked: buttonClicked(flag, role); + } + } + } + } +} diff --git a/interface/resources/qml/overte/README.md b/interface/resources/qml/overte/README.md new file mode 100644 index 00000000000..4fb88540c35 --- /dev/null +++ b/interface/resources/qml/overte/README.md @@ -0,0 +1,19 @@ +# TODO List + +## Critical +- [ ] Virtual keyboard support for text fields +- [x] Asset browser +- [x] Running scripts window +- [ ] Actually saving the color scheme and contrast settings + +## High +- [x] Avatar picker +- [x] People app +- [x] World list + +## Low +- [x] More app +- [ ] Desktop apps bar/tablet app picker +- [ ] Create app +- [ ] Dashboard +- [ ] Hook up chat bubbles background opacity to high contrast mode diff --git a/interface/resources/qml/overte/RoundButton.qml b/interface/resources/qml/overte/RoundButton.qml new file mode 100644 index 00000000000..5deec714cde --- /dev/null +++ b/interface/resources/qml/overte/RoundButton.qml @@ -0,0 +1,52 @@ +import QtQuick +import QtQuick.Controls +import "." + +Button { + id: button + property color backgroundColor: Theme.paletteActive.button + + palette.buttonText: Theme.paletteActive.buttonText + font.family: Theme.fontFamily + font.pixelSize: Theme.fontPixelSize + horizontalPadding: 2 + verticalPadding: 2 + hoverEnabled: true + implicitHeight: font.pixelSize * 2 + implicitWidth: font.pixelSize * 2 + + background: Rectangle { + id: buttonBg + radius: button.height / 2 + border.width: parent.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: ( + button.activeFocus ? + Theme.paletteActive.focusRing : + ( + Theme.highContrast ? + Theme.paletteActive.buttonText : + Qt.darker(button.backgroundColor, Theme.borderDarker) + ) + ) + color: ( + (button.down || button.checked) ? + Qt.darker(button.backgroundColor, Theme.checkedDarker) : + ( + (button.hovered && button.enabled) ? + Qt.lighter(button.backgroundColor, Theme.hoverLighter) : + button.backgroundColor + ) + ) + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(buttonBg.color, (button.down || button.checked) ? 0.9 : 1.1) + } + GradientStop { + position: 0.5; color: buttonBg.color + } + GradientStop { + position: 1.0; color: Qt.darker(buttonBg.color, (button.down || button.checked) ? 0.9 : 1.1) + } + } + } +} diff --git a/interface/resources/qml/overte/Ruler.qml b/interface/resources/qml/overte/Ruler.qml new file mode 100644 index 00000000000..522c6208169 --- /dev/null +++ b/interface/resources/qml/overte/Ruler.qml @@ -0,0 +1,29 @@ +import QtQuick + +import "." + +Item { + property color color: ( + Theme.highContrast ? + Theme.paletteActive.text : + Theme.paletteActive.base + ) + + implicitHeight: 4 + + Rectangle { + x: 0 + y: 0 + height: Math.floor(parent.height / 2) + width: parent.width + color: Qt.darker(parent.color, Theme.depthDarker) + } + + Rectangle { + x: 0 + y: Math.floor(parent.height / 2) + height: Math.floor(parent.height / 2) + width: parent.width + color: Qt.lighter(parent.color, Theme.depthLighter) + } +} diff --git a/interface/resources/qml/overte/ScrollBar.qml b/interface/resources/qml/overte/ScrollBar.qml new file mode 100644 index 00000000000..6fa5d7f985c --- /dev/null +++ b/interface/resources/qml/overte/ScrollBar.qml @@ -0,0 +1,150 @@ +import QtQuick +import QtQuick.Controls +import "." + +ScrollBar { + id: control + opacity: { + if ( + control.policy === ScrollBar.AlwaysOn || + (control.policy === ScrollBar.AsNeeded && interactive && control.size < 1.0) + ) { + return 1.0; + } else if (control.active && control.size < 1.0) { + return 0.75; + } else { + return 0.0; + } + } + + Behavior on opacity { + NumberAnimation {} + } + + property color backgroundColor: Theme.paletteActive.button + + readonly property bool hasButtons: Theme.scrollbarButtons && interactive + readonly property int thumbWidth: Theme.scrollbarWidth - (horizontalPadding * 2) + readonly property bool isHorizontal: orientation === Qt.Horizontal + + //horizontalPadding: Theme.borderWidth + //verticalPadding: Theme.borderWidth + horizontalPadding: 0 + verticalPadding: 0 + + // TODO: magic numbers? minimumSize is weird and confusing, + // 0.32 doesn't work on short scrollbars + stepSize: 0.03 + minimumSize: 0.32 + + background: Rectangle { + color: Qt.darker( + Theme.paletteActive.base, + Theme.highContrast ? 1.0 : (Theme.darkMode ? 1.2 : 1.1) + ) + implicitWidth: Theme.scrollbarWidth + implicitHeight: Theme.scrollbarWidth + } + + contentItem: Item { + implicitWidth: horizontal ? 32 : thumbWidth + implicitHeight: horizontal ? thumbWidth : 32 + + Rectangle { + // pad away from the scroll buttons, but allow a border width of sink-in + // so there isn't a double-border when the thumbs are at their min/max + anchors.topMargin: control.hasButtons && !control.isHorizontal ? thumbWidth - Theme.borderWidth : 0 + anchors.bottomMargin: control.hasButtons && !control.isHorizontal ? thumbWidth - Theme.borderWidth: 0 + anchors.leftMargin: control.hasButtons && control.isHorizontal ? thumbWidth - Theme.borderWidth: 0 + anchors.rightMargin: control.hasButtons && control.isHorizontal ? thumbWidth - Theme.borderWidth : 0 + anchors.fill: parent + + id: buttonBg + radius: Theme.borderRadius + border.width: Theme.borderWidth + border.color: Theme.highContrast ? Theme.paletteActive.buttonText : Qt.darker(control.backgroundColor, Theme.borderDarker) + color: Theme.highContrast ? Theme.paletteActive.buttonText : control.backgroundColor; + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(buttonBg.color, 1.05) + } + GradientStop { + position: 0.5; color: buttonBg.color + } + GradientStop { + position: 1.0; color: Qt.darker(buttonBg.color, 1.05) + } + } + } + } + + Button { + anchors.right: !control.isHorizontal ? control.right : undefined + anchors.rightMargin: !control.isHorizontal ? control.horizontalPadding : undefined + + anchors.left: control.isHorizontal ? control.left : undefined + anchors.leftMargin: control.isHorizontal ? control.horizontalPadding : undefined + + anchors.top: control.top + anchors.topMargin: control.verticalPadding + + width: thumbWidth + height: width + + id: scrollLessButton + visible: control.hasButtons + focusPolicy: Qt.NoFocus + + icon.source: ( + !control.isHorizontal ? + "./icons/triangle_up.svg" : + "./icons/triangle_left.svg" + ) + icon.width: width - 4 + icon.height: height - 4 + icon.color: Theme.paletteActive.buttonText + display: AbstractButton.IconOnly + horizontalPadding: 0 + verticalPadding: 0 + autoRepeat: true + + onClicked: { + control.position = Math.max(0.0, control.position - control.stepSize); + } + } + + Button { + anchors.right: control.isHorizontal ? control.right : undefined + anchors.rightMargin: control.isHorizontal ? control.horizontalPadding : undefined + + anchors.left: !control.isHorizontal ? control.left : undefined + anchors.leftMargin: !control.isHorizontal ? control.horizontalPadding : undefined + + anchors.bottom: control.bottom + anchors.bottomMargin: control.verticalPadding + + width: thumbWidth + height: width + + id: scrollMoreButton + visible: control.hasButtons + focusPolicy: Qt.NoFocus + display: AbstractButton.IconOnly + horizontalPadding: 0 + verticalPadding: 0 + autoRepeat: true + + icon.source: ( + !control.isHorizontal ? + "./icons/triangle_down.svg" : + "./icons/triangle_right.svg" + ) + icon.width: width - 4 + icon.height: height - 4 + icon.color: Theme.paletteActive.buttonText + + onClicked: { + control.position = Math.min(1.0 - control.size, control.position + control.stepSize); + } + } +} diff --git a/interface/resources/qml/overte/Slider.qml b/interface/resources/qml/overte/Slider.qml new file mode 100644 index 00000000000..89ce00528e7 --- /dev/null +++ b/interface/resources/qml/overte/Slider.qml @@ -0,0 +1,70 @@ +import QtQuick +import QtQuick.Controls + +import "." + +Slider { + id: control + + background: Rectangle { + y: control.topPadding + control.availableHeight / 2 - height / 2 + implicitWidth: 200 + height: 8 + radius: height / 2 + color: Theme.paletteActive.base + + border.width: Theme.borderWidth + border.color: Qt.darker(color, Theme.borderDarker) + + Rectangle { + width: control.visualPosition * parent.width + height: parent.height + radius: parent.radius + color: Theme.paletteActive.highlight + + border.color: Qt.darker(color, Theme.borderDarker) + border.width: Theme.borderWidth + } + } + + handle: Rectangle { + implicitWidth: 26 + implicitHeight: 26 + radius: height / 2 + + x: control.leftPadding + control.visualPosition * (control.availableWidth - width) + y: control.topPadding + control.availableHeight / 2 - height / 2 + + id: handle + border.width: control.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: ( + control.activeFocus ? + Theme.paletteActive.focusRing : + ( + Theme.highContrast ? + Theme.paletteActive.buttonText : + Qt.darker(Theme.paletteActive.button, Theme.borderDarker) + ) + ) + color: { + if (control.hovered && control.enabled) { + return Qt.lighter(Theme.paletteActive.button, Theme.hoverLighter); + } else if (!control.enabled) { + return Theme.paletteActive.base; + } else { + return Theme.paletteActive.button; + } + } + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(handle.color, control.enabled ? 1.1 : 1.0) + } + GradientStop { + position: 0.5; color: handle.color + } + GradientStop { + position: 1.0; color: Qt.darker(handle.color, control.enabled ? 1.1 : 1.0) + } + } + } +} diff --git a/interface/resources/qml/overte/SpinBox.qml b/interface/resources/qml/overte/SpinBox.qml new file mode 100644 index 00000000000..edcf5cdc70b --- /dev/null +++ b/interface/resources/qml/overte/SpinBox.qml @@ -0,0 +1,143 @@ +import QtQuick +import QtQuick.Controls + +import "." + +SpinBox { + id: control + + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + + background: Rectangle { + anchors.left: control.down.indicator.right + anchors.right: control.up.indicator.left + anchors.leftMargin: -Theme.borderWidth + anchors.rightMargin: -Theme.borderWidth + + implicitHeight: Theme.fontPixelSize * 2 + implicitWidth: 180 + // no radius so the borders can mix into the scroll button borders + //radius: Theme.borderRadius + border.width: control.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: ( + parent.activeFocus ? + Theme.paletteActive.focusRing : + ( + Theme.highContrast ? + Theme.paletteActive.windowText : + Qt.darker(Theme.paletteActive.window, Theme.borderDarker) + ) + ) + color: Theme.paletteActive.window + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.darker(control.background.color, 1.02) } + GradientStop { position: 0.5; color: control.background.color } + GradientStop { position: 1.0; color: Qt.lighter(control.background.color, 1.02) } + } + } + + contentItem: TextInput { + anchors.left: control.down.indicator.right + anchors.right: control.up.indicator.left + + font: control.font + color: Theme.paletteActive.windowText + selectionColor: Theme.paletteActive.highlight + selectedTextColor: Theme.paletteActive.highlightedText + text: control.textFromValue(control.value, control.locale) + + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + + readOnly: !control.editable + validator: control.validator + inputMethodHints: Qt.ImhFormattedNumbersOnly + } + + down.indicator: Rectangle{ + id: downIndicator + x: 0 + width: Theme.fontPixelSize * 2 + height: parent.height + color: ( + control.down.down ? + Qt.darker(Theme.paletteActive.button, Theme.checkedDarker) : + ( + (control.down.hovered && control.enabled) ? + Qt.lighter(Theme.paletteActive.button, Theme.hoverLighter) : + Theme.paletteActive.button + ) + ) + opacity: control.value > control.from ? 1.0 : 0.5 + + radius: 0 + topLeftRadius: Theme.borderRadius + bottomLeftRadius: Theme.borderRadius + + border.width: Theme.borderWidth + border.color: ( + Theme.highContrast ? + Theme.paletteActive.windowText : + Qt.darker(Theme.paletteActive.button, Theme.borderDarker) + ) + + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.lighter(downIndicator.color, 1.05) } + GradientStop { position: 0.5; color: downIndicator.color } + GradientStop { position: 1.0; color: Qt.darker(downIndicator.color, 1.05) } + } + + Text { + anchors.fill: parent + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + color: Theme.paletteActive.buttonText + font: control.font + text: "-" + } + } + + up.indicator: Rectangle{ + id: upIndicator + x: parent.width - width + width: Theme.fontPixelSize * 2 + height: parent.height + color: ( + control.up.down ? + Qt.darker(Theme.paletteActive.button, Theme.checkedDarker) : + ( + (control.up.hovered && control.enabled) ? + Qt.lighter(Theme.paletteActive.button, Theme.hoverLighter) : + Theme.paletteActive.button + ) + ) + opacity: control.value < control.to ? 1.0 : 0.5 + + radius: 0 + topRightRadius: Theme.borderRadius + bottomRightRadius: Theme.borderRadius + + border.width: Theme.borderWidth + border.color: ( + Theme.highContrast ? + Theme.paletteActive.windowText : + Qt.darker(Theme.paletteActive.button, Theme.borderDarker) + ) + + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.lighter(upIndicator.color, 1.05) } + GradientStop { position: 0.5; color: upIndicator.color } + GradientStop { position: 1.0; color: Qt.darker(upIndicator.color, 1.05) } + } + + Text { + anchors.fill: parent + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + color: Theme.paletteActive.buttonText + font: control.font + text: "+" + } + } +} diff --git a/interface/resources/qml/overte/StackView.qml b/interface/resources/qml/overte/StackView.qml new file mode 100644 index 00000000000..197a5931107 --- /dev/null +++ b/interface/resources/qml/overte/StackView.qml @@ -0,0 +1,74 @@ +import QtQuick +import QtQuick.Controls + +import "." + +// a stack view with reasonable defaults for the +// animations, respecting the theme reduced motion settings +StackView { + pushEnter: Transition { + PropertyAnimation { + property: "opacity" + from: Theme.reducedMotion ? 0 : 1 + to: 1 + duration: 80 + } + + PropertyAnimation { + property: "x" + from: Theme.reducedMotion ? 0 : width + to: 0 + duration: 350 + easing.type: Easing.OutQuad + } + } + pushExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to: Theme.reducedMotion ? 0 : 1 + duration: 80 + } + + PropertyAnimation { + property: "x" + to: Theme.reducedMotion ? 0 : -width + from: 0 + duration: 350 + easing.type: Easing.OutQuad + } + } + + popEnter: Transition { + PropertyAnimation { + property: "opacity" + from: Theme.reducedMotion ? 0 : 1 + to: 1 + duration: 80 + } + + PropertyAnimation { + property: "x" + from: Theme.reducedMotion ? 0 : -width + to: 0 + duration: 350 + easing.type: Easing.OutQuad + } + } + popExit: Transition { + PropertyAnimation { + property: "opacity" + from: 1 + to: Theme.reducedMotion ? 0 : 1 + duration: 80 + } + + PropertyAnimation { + property: "x" + to: Theme.reducedMotion ? 0 : width + from: 0 + duration: 350 + easing.type: Easing.OutQuad + } + } +} diff --git a/interface/resources/qml/overte/Switch.qml b/interface/resources/qml/overte/Switch.qml new file mode 100644 index 00000000000..5ff772162ed --- /dev/null +++ b/interface/resources/qml/overte/Switch.qml @@ -0,0 +1,74 @@ +import QtQuick +import QtQuick.Controls +import "." + +Switch { + id: control + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + opacity: control.enabled ? 1.0 : 0.5 + + Rectangle { + anchors.fill: indicator + anchors.margins: -Theme.borderWidthFocused + color: Theme.paletteActive.focusRing + visible: control.activeFocus + radius: indicator.radius + } + + indicator: Rectangle { + implicitWidth: 48 + implicitHeight: 24 + x: control.leftPadding + y: parent.height / 2 - height / 2 + radius: 24 + color: { + if (Theme.highContrast) { + return control.checked ? Theme.paletteActive.buttonText : Theme.paletteActive.button; + } else if (control.checked) { + return Theme.paletteActive.highlight; + } else { + return Qt.darker(Theme.paletteActive.base, Theme.checkedDarker); + } + } + border.color: ( + Theme.highContrast ? + Theme.paletteActive.buttonText : + Qt.darker(color, Theme.borderDarker) + ) + border.width: Theme.borderWidth + + Rectangle { + x: control.checked ? parent.width - width : 0 + width: 24 + height: 24 + radius: 24 + color: ( + control.down ? + Qt.darker(Theme.paletteActive.button, Theme.depthDarker) : + ( + control.hovered && control.enabled ? + Qt.lighter(Theme.paletteActive.button, Theme.depthLighter) : + Theme.paletteActive.button + ) + ); + border.color: { + if (Theme.highContrast) { + return Theme.paletteActive.buttonText; + } else { + return Qt.darker(Theme.paletteActive.button, Theme.borderDarker); + } + } + border.width: Theme.borderWidth + } + } + + contentItem: Text { + text: control.text + font: control.font + color: Theme.paletteActive.text + opacity: enabled ? 1.0 : 0.3 + verticalAlignment: Text.AlignVCenter + leftPadding: control.indicator.width + control.spacing + } +} diff --git a/interface/resources/qml/overte/TabBar.qml b/interface/resources/qml/overte/TabBar.qml new file mode 100644 index 00000000000..9f7a3c60fec --- /dev/null +++ b/interface/resources/qml/overte/TabBar.qml @@ -0,0 +1,22 @@ +import QtQuick +import QtQuick.Controls +import "." + +TabBar { + id: tabBar + spacing: 2 + clip: true + + background: Item { + Rectangle { anchors.fill: parent; color: Theme.paletteActive.base } + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: Theme.borderWidth + color: Qt.darker(Theme.paletteActive.base) + } + } + + implicitHeight: Theme.fontPixelSize + 16 +} diff --git a/interface/resources/qml/overte/TabButton.qml b/interface/resources/qml/overte/TabButton.qml new file mode 100644 index 00000000000..a3a4bb550fc --- /dev/null +++ b/interface/resources/qml/overte/TabButton.qml @@ -0,0 +1,56 @@ +import QtQuick +import QtQuick.Controls +import "." + +TabButton { + id: button + property color backgroundColor: Theme.paletteActive.base + + readonly property int borderWidth: checked ? Theme.borderWidth * 2 : Theme.borderWidth + + font.family: Theme.fontFamily + font.pixelSize: Theme.fontPixelSize + horizontalPadding: 12 + verticalPadding: 8 + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: checked ? 2 : 6 + anchors.bottomMargin: -borderWidth + implicitHeight: Theme.fontPixelSize + 16 + + contentItem: Text { + text: button.text + font: button.font + color: Theme.paletteActive.text + opacity: enabled ? 1.0 : 0.3 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + id: buttonBg + border.width: parent.borderWidth + border.color: { + if (parent.activeFocus) { + return Theme.paletteActive.focusRing; + } else if (parent.checked) { + return Theme.paletteActive.highlight; + } else if (Theme.highContrast) { + return Theme.paletteActive.buttonText; + } else { + return Qt.darker(parent.backgroundColor, Theme.borderDarker); + } + } + color: parent.backgroundColor; + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(buttonBg.color, 1.2) + } + GradientStop { + position: 1.0; color: buttonBg.color + } + } + } +} diff --git a/interface/resources/qml/overte/TextArea.qml b/interface/resources/qml/overte/TextArea.qml new file mode 100644 index 00000000000..785b1f3ea99 --- /dev/null +++ b/interface/resources/qml/overte/TextArea.qml @@ -0,0 +1,35 @@ +import QtQuick +import QtQuick.Controls +import "." + +TextArea { + id: textArea + selectByMouse: true + + property color backgroundColor: Theme.paletteActive.window + + color: Theme.paletteActive.windowText + placeholderTextColor: Theme.paletteActive.placeholderText + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + selectionColor: Theme.paletteActive.highlight + selectedTextColor: Theme.paletteActive.highlightedText + + leftPadding: 6 + rightPadding: 6 + topPadding: 8 + bottomPadding: 8 + + background: Rectangle { + radius: Theme.borderRadius + border.width: parent.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: textArea.activeFocus ? + Theme.paletteActive.focusRing : + (Theme.highContrast ? Theme.paletteActive.windowText : Qt.darker(textArea.backgroundColor, Theme.borderDarker)) + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.darker(textArea.backgroundColor, 1.02) } + GradientStop { position: 0.5; color: textArea.backgroundColor } + GradientStop { position: 1.0; color: Qt.lighter(textArea.backgroundColor, 1.02) } + } + } +} diff --git a/interface/resources/qml/overte/TextField.qml b/interface/resources/qml/overte/TextField.qml new file mode 100644 index 00000000000..0e57c268edc --- /dev/null +++ b/interface/resources/qml/overte/TextField.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Controls +import "." + +TextField { + id: textField + selectByMouse: true + + property color backgroundColor: Theme.paletteActive.window + + color: Theme.paletteActive.windowText + placeholderTextColor: Theme.paletteActive.placeholderText + font.pixelSize: Theme.fontPixelSize + font.family: Theme.fontFamily + selectionColor: Theme.paletteActive.highlight + selectedTextColor: Theme.paletteActive.highlightedText + + leftPadding: 6 + rightPadding: 6 + topPadding: 8 + bottomPadding: 8 + + background: Rectangle { + implicitHeight: Theme.fontPixelSize * 2 + radius: Theme.borderRadius + border.width: parent.activeFocus ? Theme.borderWidthFocused : Theme.borderWidth + border.color: parent.activeFocus ? + Theme.paletteActive.focusRing : + (Theme.highContrast ? Theme.paletteActive.windowText : Qt.darker(parent.backgroundColor, Theme.borderDarker)) + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.darker(textField.backgroundColor, 1.02) } + GradientStop { position: 0.5; color: textField.backgroundColor } + GradientStop { position: 1.0; color: Qt.lighter(textField.backgroundColor, 1.02) } + } + } +} diff --git a/interface/resources/qml/overte/Theme.qml b/interface/resources/qml/overte/Theme.qml new file mode 100644 index 00000000000..53d70dcbc11 --- /dev/null +++ b/interface/resources/qml/overte/Theme.qml @@ -0,0 +1,238 @@ +import QtQuick + +pragma Singleton +QtObject { + property bool useSystemColorScheme: true + property bool useSystemContrastMode: true + + // https://github.com/overte-org/overte/issues/1733 + property bool darkMode: ( + useSystemColorScheme ? + Qt.application.styleHints.colorScheme !== Qt.ColorScheme.Light : + true + ) + property bool highContrast: ( + useSystemContrastMode ? + Qt.application.styleHints.accessibility.contrastPreference === Qt.ContrastPreference.HighContrast : + false + ) + property bool reducedMotion: false + + // font face for UI elements + readonly property string fontFamily: "Roboto" + + // font face for document text + readonly property string bodyFontFamily: "Roboto" + + // font face for code editors + readonly property string monoFontFamily: "Roboto Mono" + + readonly property int fontPixelSize: 18 + readonly property int fontPixelSizeSmall: 14 + readonly property int fontPixelSizeXSmall: 11 + + readonly property real borderRadius: 4.0 + readonly property real borderWidth: 2.0 + readonly property real borderWidthFocused: highContrast ? borderWidth * 2 : borderWidth + + // TODO: set these on mobile where scroll buttons aren't useful + readonly property int scrollbarWidth: 24 + readonly property bool scrollbarButtons: true + + // Qt.lighten and Qt.darken constants for subtle 3D effect + readonly property real borderDarker: darkMode ? 2.5 : 1.5 + readonly property real depthLighter: highContrast ? 1.0 : 1.2 + readonly property real depthDarker: highContrast ? 1.0 : 1.3 + readonly property real checkedDarker: highContrast ? 1.5 : 1.2 + readonly property real hoverLighter: { + if (darkMode) { + // don't apply hover lightness on dark high contrast + return highContrast ? 1.0 : 1.3; + } else { + // 1.3 blows out the button colors to white on the light theme + return 1.1; + } + } + + readonly property var paletteActive: ( + highContrast ? + (darkMode ? paletteDarkContrast : paletteLightContrast) : + (darkMode ? paletteDark : paletteLight) + ) + + readonly property var paletteDark: QtObject { + readonly property color alternateBase: Qt.darker(base, 1.1) + readonly property color base: "#403849" + readonly property color text: "#eeeeee" + readonly property color button: "#605868" + readonly property color buttonText: "#eeeeee" + readonly property color window: "#524c59" + readonly property color windowText: "#eeeeee" + readonly property color highlight: "#0a9dce" + readonly property color highlightedText: "#ffffff" + + readonly property color focusRing: "#f4801a" + readonly property color placeholderText: "#80eeeeee" + + readonly property color tooltip: "#524c59" + readonly property color tooltipText: "#eeeeee" + + readonly property color buttonDestructive: "#823d3d" + readonly property color buttonAdd: "#3a753a" + readonly property color buttonInfo: "#1e6591" + readonly property color buttonFavorite: "#b28c01" + + readonly property color statusOffline: "#808080" + readonly property color statusFriendsOnly: "orange" + readonly property color statusContacts: "lime" + readonly property color statusEveryone: "cyan" + + readonly property color link: highlight + readonly property color dialogShade: "#d0000000" + + readonly property color activeWindowTitleBg: Qt.darker("#403849", 1.2) + readonly property color activeWindowTitleFg: text + + readonly property color userCountEmpty: "#b0b0b0" + readonly property color userCountActive: "#22ef22" + readonly property color userCountFull: "#ef2f1f" + + readonly property color appIconBackground: "#202020" + readonly property color appInstalledRunning: statusContacts + readonly property color appInstalledNotRunning: statusFriendsOnly + readonly property color appNotInstalledRunning: "red" + readonly property color appNotInstalled: statusOffline + } + + readonly property var paletteLight: QtObject { + readonly property color alternateBase: Qt.darker(base, 1.05) + readonly property color base: "#f5f5f5" + readonly property color text: "#111111" + readonly property color button: "#f3f2f4" + readonly property color buttonText: "#111111" + readonly property color window: "#eeeeee" + readonly property color windowText: "#111111" + readonly property color highlight: "#0b3ebf" + readonly property color highlightedText: "#ffffff" + + readonly property color focusRing: "#f4801a" + readonly property color placeholderText: "#60000000" + + readonly property color tooltip: "#fffecc" + readonly property color tooltipText: "#111111" + + readonly property color buttonDestructive: "#fccccc" + readonly property color buttonAdd: "#bef4c5" + readonly property color buttonInfo: "#bfe5fc" + readonly property color buttonFavorite: "#eddda6" + + readonly property color statusOffline: "#808080" + readonly property color statusFriendsOnly: "brown" + readonly property color statusContacts: "green" + readonly property color statusEveryone: "teal" + + readonly property color link: highlight + readonly property color dialogShade: "#d0808080" + + readonly property color activeWindowTitleBg: "#000080" + readonly property color activeWindowTitleFg: "white" + + readonly property color userCountEmpty: "#303030" + readonly property color userCountActive: "#008000" + readonly property color userCountFull: "#800000" + + readonly property color appIconBackground: "#202020" + readonly property color appInstalledRunning: "#00ff00" + readonly property color appInstalledNotRunning: "#ffaf00" + readonly property color appNotInstalledRunning: "red" + readonly property color appNotInstalled: statusOffline + } + + readonly property var paletteDarkContrast: QtObject { + readonly property color alternateBase: Qt.darker(base, 1.1) + readonly property color base: "#000000" + readonly property color text: "#f0f0f0" + readonly property color button: "#000000" + readonly property color buttonText: "#f0f0f0" + readonly property color window: "#000000" + readonly property color windowText: "#f0f0f0" + readonly property color highlight: "#ffffff" + readonly property color highlightedText: "#000000" + + readonly property color focusRing: "#ff00ff" + readonly property color placeholderText: "#00ff00" + + readonly property color tooltip: "#000000" + readonly property color tooltipText: "#ffff00" + + readonly property color buttonDestructive: "#600000" + readonly property color buttonAdd: "#006000" + readonly property color buttonInfo: "#000080" + readonly property color buttonFavorite: "#606000" + + readonly property color statusOffline: "#808080" + readonly property color statusFriendsOnly: "orange" + readonly property color statusContacts: "lime" + readonly property color statusEveryone: "cyan" + + readonly property color link: "#ffff00" + readonly property color dialogShade: "#e8000000" + + readonly property color activeWindowTitleBg: base + readonly property color activeWindowTitleFg: "white" + + readonly property color userCountEmpty: text + readonly property color userCountActive: "#00ff00" + readonly property color userCountFull: "#ff00ff" + + readonly property color appIconBackground: "black" + readonly property color appInstalledRunning: statusContacts + readonly property color appInstalledNotRunning: statusFriendsOnly + readonly property color appNotInstalledRunning: "red" + readonly property color appNotInstalled: statusOffline + } + + readonly property var paletteLightContrast: QtObject { + readonly property color alternateBase: Qt.darker(base, 1.05) + readonly property color base: "#f5f5f5" + readonly property color text: "#000000" + readonly property color button: "#f5f5f5" + readonly property color buttonText: "#000000" + readonly property color window: "#f0f0f0" + readonly property color windowText: "#000000" + readonly property color highlight: "#600060" + readonly property color highlightedText: "#ffffff" + + readonly property color focusRing: "#ff00ff" + readonly property color placeholderText: "#007000" + + readonly property color tooltip: "#fffeee" + readonly property color tooltipText: "#111111" + + readonly property color buttonDestructive: "#ffdddd" + readonly property color buttonAdd: "#ddffdd" + readonly property color buttonInfo: "#ddffff" + readonly property color buttonFavorite: "#ffffdd" + + readonly property color statusOffline: "#808080" + readonly property color statusFriendsOnly: "brown" + readonly property color statusContacts: "green" + readonly property color statusEveryone: "teal" + + readonly property color link: "#000080" + readonly property color dialogShade: "#fad0d0d0" + + readonly property color activeWindowTitleBg: base + readonly property color activeWindowTitleFg: "black" + + readonly property color userCountEmpty: text + readonly property color userCountActive: "#006000" + readonly property color userCountFull: "#600060" + + readonly property color appIconBackground: "black" + readonly property color appInstalledRunning: "#00ff00" + readonly property color appInstalledNotRunning: "#ffaf00" + readonly property color appNotInstalledRunning: "red" + readonly property color appNotInstalled: statusOffline + } +} diff --git a/interface/resources/qml/overte/ToolTip.qml b/interface/resources/qml/overte/ToolTip.qml new file mode 100644 index 00000000000..01391f8204f --- /dev/null +++ b/interface/resources/qml/overte/ToolTip.qml @@ -0,0 +1,47 @@ +import QtQuick +import QtQuick.Controls +import "." + +ToolTip { + id: control + delay: 500 + + // NOTE: this default is for Controls, + // if you're using something else then override this + visible: parent.hovered + + font.family: Theme.fontFamily + font.pixelSize: Theme.fontPixelSizeSmall + + background: Item { + // drop shadow + Rectangle { + x: 3 + y: 3 + width: parent.width + height: parent.height + + radius: Theme.borderRadius + color: "#a0000000" + } + + Rectangle { + x: 0 + y: 0 + width: parent.width + height: parent.height + + radius: Theme.borderRadius + border.width: Theme.borderWidth + border.color: Theme.highContrast ? Theme.paletteActive.tooltipText : Qt.darker(Theme.paletteActive.tooltip, Theme.borderDarker) + color: Theme.paletteActive.tooltip + } + } + + contentItem: Text { + text: control.text + font: control.font + color: Theme.paletteActive.tooltipText + wrapMode: Text.Wrap + } +} diff --git a/interface/resources/qml/overte/WidgetZoo.qml b/interface/resources/qml/overte/WidgetZoo.qml new file mode 100644 index 00000000000..c2d08878a50 --- /dev/null +++ b/interface/resources/qml/overte/WidgetZoo.qml @@ -0,0 +1,148 @@ +import QtQuick +import QtQuick.Window +import QtQuick.Layouts +import QtQuick.Controls + +import "." as Overte + +// debugging test case to view the themed widgets +Rectangle { + id: root + width: 480 + height: 720 + visible: true + color: Overte.Theme.paletteActive.base + + Overte.TabBar { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + id: tabBar + Overte.TabButton { text: "Tab 1"; width: 120 } + Overte.TabButton { text: "Tab 2"; width: 120 } + Overte.TabButton { text: "Tab 3"; width: 120 } + Overte.TabButton { text: "Tab 4"; width: 120 } + Overte.TabButton { text: "Tab 5"; width: 120 } + Overte.TabButton { text: "Tab 6"; width: 120 } + Overte.TabButton { text: "Tab 7"; width: 120 } + Overte.TabButton { text: "Tab 8"; width: 120 } + } + + ColumnLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: tabBar.bottom + anchors.leftMargin: 16 + anchors.rightMargin: 16 + anchors.topMargin: 16 + spacing: 8 + + RowLayout { + Layout.fillWidth: true + spacing: 8 + Overte.Button { + text: "Button" + } + Overte.Button { + text: "Destroy" + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + } + Overte.Button { + text: "Add" + backgroundColor: Overte.Theme.paletteActive.buttonAdd + } + Overte.Button { + text: "Info" + backgroundColor: Overte.Theme.paletteActive.buttonInfo + } + Overte.RoundButton { + icon.source: "./icons/folder.svg" + icon.width: 24 + icon.height: 24 + } + } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: "Text field" + } + Overte.TextArea { + Layout.fillWidth: true + Layout.preferredHeight: 64 + placeholderText: "Text area" + } + Overte.TextArea { + Layout.fillWidth: true + Layout.preferredHeight: 80 + placeholderText: "Code area" + font.family: Overte.Theme.monoFontFamily + text: "function doSomething() {\n console.info(\"Hello, world\");\n}\n" + } + Overte.Switch { + text: "Switch" + } + Overte.Slider { + value: 0.5 + } + Overte.SpinBox { + editable: true + } + Overte.Ruler { Layout.fillWidth: true } + Row { + spacing: 16 + + Overte.ComboBox { + model: [ + "ComboBox", + "Singing Dogs", + "Golden Combs", + "Swirly Bombs", + ] + } + + Overte.Label { + font.pixelSize: Overte.Theme.fontPixelSizeSmall + text: "This is a note label." + } + } + + Overte.BodyText { + Layout.fillWidth: true + text: "This is body text. It's meant for selectable text documents or chat messages." + } + + ScrollView { + id: scrollView + Layout.fillWidth: true + Layout.preferredHeight: 256 + + clip: true + contentWidth: 1024 + contentHeight: 1024 + + ScrollBar.vertical: Overte.ScrollBar { + anchors.top: scrollView.top + anchors.bottom: scrollView.bottom + anchors.right: scrollView.right + anchors.bottomMargin: Theme.scrollbarWidth + } + ScrollBar.horizontal: Overte.ScrollBar { + anchors.bottom: scrollView.bottom + anchors.left: scrollView.left + anchors.right: scrollView.right + anchors.rightMargin: Theme.scrollbarWidth + } + + Image { + anchors.fill: parent + source: "./icons/unset_avatar.svg" + fillMode: Image.Tile + opacity: 0.2 + } + + Overte.Label { + text: "ScrollView and ScrollBar" + } + } + } +} diff --git a/interface/resources/qml/overte/avatar_picker/AvatarItem.qml b/interface/resources/qml/overte/avatar_picker/AvatarItem.qml new file mode 100644 index 00000000000..d4f957c70d6 --- /dev/null +++ b/interface/resources/qml/overte/avatar_picker/AvatarItem.qml @@ -0,0 +1,113 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.VectorImage + +import "../" as Overte + +Item { + id: item + required property int index + required property string name + required property url avatarUrl + required property url iconUrl + required property list tags + required property string description + + implicitWidth: GridView.view.cellWidth + implicitHeight: GridView.view.cellHeight + + Overte.Button { + anchors.fill: parent + anchors.margins: 4 + + id: avatarButton + + Overte.ToolTip { + visible: description !== "" && parent.hovered + text: description + delay: 500 + } + + Image { + id: buttonIcon + source: item.iconUrl + fillMode: Image.PreserveAspectFit + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: buttonLabel.top + anchors.margins: 4 + } + + Overte.Label { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: buttonLabel.top + anchors.margins: 4 + visible: buttonIcon.status !== Image.Ready + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: buttonIcon.status === Image.Loading ? qsTr("Loading…") : qsTr("No icon") + } + + Overte.Label { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 4 + + text: item.name + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + wrapMode: Text.Wrap + + id: buttonLabel + } + + onClicked: AvatarBookmarks.loadBookmark(item.name) + } + + Overte.RoundButton { + id: deleteButton + anchors.top: parent.top + anchors.left: parent.left + + visible: root.editable && (hovered || editButton.hovered || avatarButton.hovered) + opacity: hovered || Overte.Theme.highContrast ? 1.0 : 0.75 + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + + implicitWidth: 44 + implicitHeight: 44 + + icon.source: "../icons/delete.svg" + icon.width: 32 + icon.height: 32 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: root.requestDelete(item.index, item.name) + } + + Overte.RoundButton { + id: editButton + anchors.top: parent.top + anchors.right: parent.right + + visible: root.editable && (hovered || deleteButton.hovered || avatarButton.hovered) + opacity: hovered || Overte.Theme.highContrast ? 1.0 : 0.75 + backgroundColor: Overte.Theme.paletteActive.buttonInfo + + implicitWidth: 44 + implicitHeight: 44 + + icon.source: "../icons/pencil.svg" + icon.width: 32 + icon.height: 32 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: root.requestEdit(item.index) + } +} diff --git a/interface/resources/qml/overte/avatar_picker/AvatarPicker.qml b/interface/resources/qml/overte/avatar_picker/AvatarPicker.qml new file mode 100644 index 00000000000..f0833f4f675 --- /dev/null +++ b/interface/resources/qml/overte/avatar_picker/AvatarPicker.qml @@ -0,0 +1,387 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Dialogs as QtDialogs + +import "../" as Overte +import "." + +Rectangle { + id: root + anchors.fill: parent + color: Overte.Theme.paletteActive.base + implicitWidth: 480 + implicitHeight: 720 + + property bool editable: true + property list availableTags: [] + property string searchExpression: ".*" + property var avatarModel: [] + + function updateBookmarkModel() { + const data = AvatarBookmarks.getBookmarks(); + let tmp = []; + + for (const [name, avatar] of Object.entries(data)) { + let iconUrl; + + if (avatar.avatarIcon !== "") { + iconUrl = avatar.avatarIcon; + } else { + iconUrl = new URL(avatar.avatarUrl); + iconUrl.pathname = iconUrl.pathname.replace(/[.](?:fst|glb|fbx|vrm)$/i, ".jpg"); + iconUrl = iconUrl.toString(); + } + + tmp.push({ + name: name, + avatarUrl: avatar.avatarUrl, + iconUrl: iconUrl, + description: "", + }); + } + + tmp.sort((a, b) => a.name.localeCompare(b.name)); + + avatarModel = tmp; + } + + Component.onCompleted: updateBookmarkModel() + + Connections { + target: AvatarBookmarks + + function onBookmarkAdded() { updateBookmarkModel(); } + function onBookmarkDeleted() { updateBookmarkModel(); } + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Layout.margins: 4 + + Overte.TextField { + Layout.fillWidth: true + + id: searchField + placeholderText: qsTr("Search…") + + Keys.onEnterPressed: { + searchButton.click(); + forceActiveFocus(); + } + Keys.onReturnPressed: { + searchButton.click(); + forceActiveFocus(); + } + } + + Overte.RoundButton { + id: searchButton + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + searchExpression = searchField.text === "" ? ".*" : searchField.text; + } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.rightMargin: 8 + visible: root.availableTags.length !== 0 + + Overte.Label { + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + text: qsTr("Tags") + } + + ListView { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.fillWidth: true + implicitHeight: Overte.Theme.fontPixelSize * 2 + orientation: Qt.Horizontal + spacing: 2 + clip: true + + model: root.availableTags + delegate: Overte.Button { + required property int index + + implicitHeight: Overte.Theme.fontPixelSize * 2 + text: qsTr(ListView.view.model[index]) + checkable: true + checked: true + + palette.buttonText: checked ? Overte.Theme.paletteActive.highlightedText : Overte.Theme.paletteActive.button + backgroundColor: checked ? Overte.Theme.paletteActive.highlight : Overte.Theme.paletteActive.button + } + } + } + + GridView { + Layout.fillWidth: true + Layout.fillHeight: true + + // QT6TODO: remove this once mouse inputs work properly + interactive: false + + clip: true + // scales the cells to never leave dead space, but looks bad when scaling window + //cellWidth: (width - ScrollBar.vertical.width) / Math.floor(3 * (width / 480)) + cellWidth: Math.floor((480 - ScrollBar.vertical.width) / 3) + cellHeight: cellWidth + Overte.Theme.fontPixelSize + 6 + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + interactive: true + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + delegate: AvatarItem {} + + model: { + const searchRegex = new RegExp(searchExpression, "i"); + let tmp = []; + + for (const item of root.avatarModel) { + if (item.name.match(searchRegex)) { + let modelItem = item; + + if (!modelItem.iconUrl) { + modelItem.iconUrl = "../icons/no_avatar_icon.svg"; + } + + if (!modelItem.tags) { modelItem.tags = []; } + if (!modelItem.description) { modelItem.description = ""; } + + tmp.push(modelItem); + } + } + + return tmp; + } + } + + RowLayout { + Layout.margins: 4 + spacing: 8 + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: qsTr("%1 avatar(s)").arg(avatarModel.length) + } + + Overte.Label { + Layout.fillWidth: true + visible: editable + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: qsTr("Add new avatar") + } + + Overte.RoundButton { + icon.source: "../icons/plus.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + backgroundColor: Overte.Theme.paletteActive.buttonAdd + implicitWidth: 48 + implicitHeight: 48 + visible: editable + + onClicked: { + editDialog.editExisting = false; + editDialog.avatarName = ""; + editDialog.avatarUrl = ""; + editDialog.avatarDescription = ""; + + avatarNameField.text = ""; + avatarUrlField.text = ""; + avatarDescriptionField.text = ""; + + editDialog.open(); + } + } + } + } + + property int requestedDeleteIndex: -1 + property int requestedEditIndex: -1 + + function requestDelete(index, name) { + requestedDeleteIndex = index; + deleteWarningDialog.text = qsTr("Are you sure you want to delete %1?").arg(name); + deleteWarningDialog.open(); + } + + function requestEdit(index) { + requestedEditIndex = index; + editDialog.editExisting = true; + editDialog.avatarName = avatarModel[index].name; + editDialog.avatarUrl = avatarModel[index].avatarUrl; + editDialog.avatarDescription = avatarModel[index].description; + avatarNameField.text = editDialog.avatarName; + avatarUrlField.text = editDialog.avatarUrl; + avatarDescriptionField.text = editDialog.avatarDescription; + editDialog.open(); + } + + Overte.MessageDialog { + id: deleteWarningDialog + anchors.fill: parent + buttons: QtDialogs.MessageDialog.Yes | QtDialogs.MessageDialog.No + + onAccepted: { + AvatarBookmarks.removeBookmark(avatarModel[requestedDeleteIndex].name); + requestedDeleteIndex = -1; + } + } + + Overte.Dialog { + id: editDialog + anchors.fill: parent + maxWidth: -1 + + property bool editExisting: false + property string avatarName: "" + property string avatarUrl: "" + property string avatarDescription: "" + + signal accepted + signal rejected + + onAccepted: { + const prevData = AvatarBookmarks.getBookmark(editDialog.avatarName); + + if (editDialog.avatarName !== avatarNameField.text) { + AvatarBookmarks.removeBookmark(editDialog.avatarName); + } + + // Qt's V4 doesn't support { ...spread } syntax :( + let newData = prevData; + + if (avatarUrlField.text !== "") { + newData.avatarUrl = avatarUrlField.text; + } + + AvatarBookmarks.setBookmarkData(avatarNameField.text, newData); + close(); + } + + onRejected: close() + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: editDialog.editExisting ? qsTr("Edit avatar") : qsTr("Add new avatar") + } + Overte.Ruler { Layout.fillWidth: true } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: qsTr("Avatar name") + text: editDialog.avatarName + id: avatarNameField + } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: qsTr("Avatar URL (.fst, .glb, .vrm, .fbx)") + text: editDialog.avatarUrl + id: avatarUrlField + } + + ScrollView { + // TODO: support avatar descriptions + visible: false + + Layout.preferredHeight: Overte.Theme.fontPixelSize * 8 + Layout.fillWidth: true + + ScrollBar.vertical: Overte.ScrollBar { + interactive: false + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + contentWidth: availableWidth + + Overte.TextArea { + id: avatarDescriptionField + placeholderText: qsTr("Description (optional)") + text: editDialog.avatarDescription + wrapMode: Text.Wrap + font.pixelSize: Overte.Theme.fontPixelSizeSmall + } + } + + RowLayout { + Layout.preferredWidth: 720 + Layout.fillWidth: true + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + text: qsTr("Cancel") + + onClicked: { + editDialog.rejected(); + requestedEditIndex = -1; + } + } + + Item { + visible: editDialog.editExisting + Layout.preferredWidth: 1 + Layout.fillWidth: true + } + + Overte.Button { + visible: !editDialog.editExisting + Layout.fillWidth: true + Layout.preferredWidth: 1 + + backgroundColor: Overte.Theme.paletteActive.buttonAdd + enabled: avatarNameField.text !== "" + text: qsTr("Add Current") + + onClicked: { + avatarUrlField.text = MyAvatar.skeletonModelURL; + editDialog.accepted(); + requestedEditIndex = -1; + } + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: editDialog.editExisting ? qsTr("Apply") : qsTr("Add") + enabled: avatarNameField.text !== "" && avatarUrlField.text !== "" + + onClicked: { + editDialog.accepted(); + requestedEditIndex = -1; + } + } + } + } + } +} diff --git a/interface/resources/qml/overte/avatar_picker/qmldir b/interface/resources/qml/overte/avatar_picker/qmldir new file mode 100644 index 00000000000..c5538c484bb --- /dev/null +++ b/interface/resources/qml/overte/avatar_picker/qmldir @@ -0,0 +1,3 @@ +module AvatarPicker +AvatarPicker 1.0 AvatarPicker.qml +AvatarItem 1.0 AvatarItem.qml diff --git a/interface/resources/qml/overte/chat/Chat.qml b/interface/resources/qml/overte/chat/Chat.qml new file mode 100644 index 00000000000..d46f2062571 --- /dev/null +++ b/interface/resources/qml/overte/chat/Chat.qml @@ -0,0 +1,151 @@ +import QtQuick +import QtQuick.Controls + +import "../" as Overte +import "." as OverteChat + +Rectangle { + id: root + anchors.fill: parent + color: Overte.Theme.paletteActive.base + + // stop the StackView from leaking out of overlay windows + clip: true + + property bool settingJoinNotifications: true + property bool settingBroadcast: false + property bool settingChatBubbles: true + property bool settingDesktopWindow: false + + property var typingIndicatorNames: ({}) + + // When the window gets closed, the chat history is forgotten. + // Keep a log of events we've received so we can replay them + // when recreating the window. + property list eventsLog: [] + + Component.onCompleted: { + // fullPrivate so it's never accessible from other scripts, + // we don't want entity client scripts that are able to scrape chat history + const savedEvents = SettingsInterface.getValue("fullPrivate/chat/eventsLog") ?? []; + for (let event of savedEvents) { + fromScript(event); + } + } + + Component.onDestruction: { + SettingsInterface.setValue("fullPrivate/chat/eventsLog", eventsLog); + } + + onMessagesCleared: { + eventsLog = []; + SettingsInterface.setValue("fullPrivate/chat/eventsLog", eventsLog); + } + + // NOTE: "int" makes sense here as the timestamps are whole milliseconds, + // but it's 32 bits and overflows, so we need real's ~53 bits to work properly + signal messagePushed(name: string, body: string, timestamp: real) + signal notificationPushed(text: string, timestamp: real) + signal messagesCleared() + + function toScript(obj) { + sendToScript(JSON.stringify(obj)); + } + + function fromScript(rawObj) { + let obj = (typeof(rawObj) === "string") ? JSON.parse(rawObj) : rawObj; + const timestamp = obj.timestamp ?? Date.now(); + + // keep chat events in the log + if ( + obj.event !== "start_typing" && + obj.event !== "end_typing" && + obj.event !== "change_setting" + ) { + if (!obj.timestamp) { + obj.timestamp = Date.now(); + } + eventsLog.push(obj); + + // TODO: is this a performance problem? i'm not sure how else we could handle this robustly + // FIXME: every time this is set it logs "SettingsScriptingInterface::setValue -- allowing restricted write" + SettingsInterface.setValue("fullPrivate/chat/eventsLog", eventsLog); + } + + switch (obj.event) { + case "recv_message": + messagePushed(obj.name ? obj.name : "", obj.body, timestamp); + break; + + case "user_joined": if (settingJoinNotifications) { + notificationPushed(qsTr("%1 joined").arg(obj.name), timestamp); + } break; + + case "user_left": if (settingJoinNotifications) { + notificationPushed(qsTr("%1 left").arg(obj.name), timestamp); + } break; + + case "user_name_changed": + notificationPushed( + qsTr("%1 changed their name to %2").arg(obj.old_name).arg(obj.new_name), + timestamp + ); + break; + + case "start_typing": + typingIndicatorNames[obj.uuid] = obj.name; + // propChanged is only fired by Qt on variable assignments, not property changes + typingIndicatorNamesChanged(); + break; + + case "end_typing": + delete typingIndicatorNames[obj.uuid]; + // propChanged is only fired by Qt on variable assignments, not property changes + typingIndicatorNamesChanged(); + break; + + case "change_setting": + updateSetting(obj.name, obj.value); + break; + + default: + console.error(`fromScript: Unknown event type "${obj.event}"`); + console.error(JSON.stringify(obj)); + break; + } + } + + function updateSetting(name, value) { + switch (name) { + case "join_notify": + settingJoinNotifications = value; + break; + + case "broadcast": + settingBroadcast = value; + break; + + case "chat_bubbles": + settingChatBubbles = value; + break; + + case "desktop_window": + settingDesktopWindow = value; + break; + } + } + + function sendSettingsUpdate() { + toScript({event: "change_setting", setting: "join_notify", value: settingJoinNotifications}); + toScript({event: "change_setting", setting: "broadcast", value: settingBroadcast}); + toScript({event: "change_setting", setting: "chat_bubbles", value: settingChatBubbles}); + toScript({event: "change_setting", setting: "desktop_window", value: settingDesktopWindow}); + } + + Overte.StackView { + anchors.fill: parent + + id: stack + initialItem: OverteChat.ChatPage {} + } +} diff --git a/interface/resources/qml/overte/chat/ChatPage.qml b/interface/resources/qml/overte/chat/ChatPage.qml new file mode 100644 index 00000000000..d9cfd6ee440 --- /dev/null +++ b/interface/resources/qml/overte/chat/ChatPage.qml @@ -0,0 +1,270 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import "../" as Overte +import "../settings" as OverteSettings +import "." as OverteChat + +ColumnLayout { + id: chatPage + + RowLayout { + Layout.fillWidth: true + + // push everything to the right + Item { Layout.fillWidth: true } + + Overte.RoundButton { + Overte.ToolTip { text: qsTr("Clear chat history") } + + backgroundColor: ( + hovered ? + Overte.Theme.paletteActive.buttonDestructive : + Overte.Theme.paletteActive.button + ) + + implicitWidth: 36 + implicitHeight: 36 + horizontalPadding: 2 + verticalPadding: 2 + + icon.source: "../icons/delete.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: root.messagesCleared() + } + + Overte.RoundButton { + Overte.ToolTip { text: qsTr("Broadcast messages to whole domain") } + + backgroundColor: ( + checked ? + Overte.Theme.paletteActive.highlight : + Overte.Theme.paletteActive.button + ) + color: ( + checked ? + Overte.Theme.paletteActive.highlightedText : + Overte.Theme.paletteActive.buttonText + ) + + implicitWidth: 36 + implicitHeight: 36 + horizontalPadding: 2 + verticalPadding: 2 + + icon.source: "../icons/broadcast.svg" + icon.width: 24 + icon.height: 24 + icon.color: color + + checkable: true + checked: root.settingBroadcast + onToggled: { + root.settingBroadcast = checked; + root.sendSettingsUpdate(); + } + } + + Overte.RoundButton { + Overte.ToolTip { text: qsTr("Settings") } + + implicitWidth: 36 + implicitHeight: 36 + horizontalPadding: 2 + verticalPadding: 2 + + icon.source: "../icons/settings_cog.svg" + icon.width: 24 + icon.height: 24 + + onClicked: stack.push("./SettingsPage.qml") + } + } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + visible: chatLog.model.length === 0 + + id: noMessagesLabel + text: qsTr("No messages") + opacity: 0.5 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical: Overte.ScrollBar { + interactive: true + policy: ScrollBar.AlwaysOn + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + visible: chatLog.model.length > 0 + + ListView { + id: chatLog + clip: true + spacing: 8 + + model: [] + delegate: MessageBlock {} + + Connections { + target: root + + function onMessagesCleared() { + chatLog.model = []; + } + + function onMessagePushed(name, body, timestamp) { + const imageUrlRegex = /(https?:\/\/\S+\.(?:png|jpg|jpeg|gif|webp|svg)\S*)/gmi; + let detectedImageUrls = body.match(imageUrlRegex) ?? []; + + chatLog.model.push({ + name: name, + body: ( + body + .replace(/\&/g, "&") + .replace(/\[/g, "[") + .replace(/\]/g, "]") + .replace(/\/g, ">") + .replace(/\'/g, "'") + .replace(/\"/g, """) + .replace(/\n/g, "
") + // strip any image links, as they're + // embedded and clickable anyway + .replace(imageUrlRegex, "") + ), + notification: "", + timestamp: timestamp, + imageEmbeds: detectedImageUrls, + }); + chatLog.currentIndex = chatLog.model.length - 1; + } + + function onNotificationPushed(text, timestamp) { + chatLog.model.push({ + name: "", + body: "", + notification: text, + timestamp: timestamp, + imageEmbeds: [], + }); + chatLog.currentIndex = chatLog.model.length - 1; + } + } + } + } + + Overte.Label { + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.rightMargin: 8 + + id: typingIndicator + + text: "" + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + wrapMode: Text.Wrap + font.pixelSize: Overte.Theme.fontPixelSizeSmall + font.italic: true + + Connections { + target: root + + function onTypingIndicatorNamesChanged() { + const values = Object.values(root.typingIndicatorNames); + + if (values.length === 0) { + typingIndicator.text = ""; + } else { + typingIndicator.text = values.join(", ") + qsTr(" typing…"); + } + } + } + } + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: Overte.Theme.fontPixelSize * 6 + + ScrollBar.vertical: Overte.ScrollBar { + interactive: false + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + Overte.TextArea { + id: messageInput + placeholderText: ( + root.settingBroadcast ? + qsTr("Broadcast chat message…") : + qsTr("Local chat message…") + ) + wrapMode: TextEdit.Wrap + KeyNavigation.priority: KeyNavigation.BeforeItem + KeyNavigation.tab: messageSend + + Keys.onPressed: event => { + if ( + (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && + !(event.modifiers & Qt.ShiftModifier) + ) { + messageSend.clicked(); + event.accepted = true; + } + } + + property bool hadText: false + + onTextChanged: { + if (text === "") { + toScript({event: "end_typing"}); + hadText = false; + } else if (!hadText) { + toScript({event: "start_typing"}); + hadText = true; + } + } + } + } + + Overte.RoundButton { + id: messageSend + Layout.fillHeight: true + Layout.preferredWidth: 40 + horizontalPadding: 2 + verticalPadding: 2 + + icon.source: "../icons/send.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + let text = messageInput.text.trim(); + messageInput.text = ""; + + if (text === "") { return; } + + toScript({event: "send_message", body: text}); + } + } + } +} diff --git a/interface/resources/qml/overte/chat/MessageBlock.qml b/interface/resources/qml/overte/chat/MessageBlock.qml new file mode 100644 index 00000000000..29f43f0d7ca --- /dev/null +++ b/interface/resources/qml/overte/chat/MessageBlock.qml @@ -0,0 +1,171 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte + +ColumnLayout { + required property int index + required property string name + required property string body + required property string notification + required property real timestamp + required property list imageEmbeds + + id: messageBlock + + anchors.left: parent ? parent.left : undefined + anchors.right: parent ? parent.right : undefined + anchors.leftMargin: 4 + anchors.rightMargin: Overte.Theme.scrollbarWidth + + Rectangle { + Layout.fillWidth: true + implicitHeight: 3 + color: Overte.Theme.paletteActive.highlight + + ColorAnimation on color { + to: Overte.Theme.paletteActive.alternateBase + duration: 500 + } + } + + RowLayout { + Layout.leftMargin: 6 + Layout.rightMargin: 8 + Layout.fillWidth: true + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + + Overte.Label { + Layout.fillWidth: true + id: nameLabel + text: notification ? notification : name + font.pixelSize: Overte.Theme.fontPixelSizeSmall + font.bold: true + elide: Text.ElideRight + children: truncated ? [nameTooltipArea] : [] + + MouseArea { + id: nameTooltipArea + anchors.fill: parent + cursorShape: Qt.WhatsThisCursor + hoverEnabled: true + + Overte.ToolTip { + visible: parent.containsMouse + text: nameLabel.text + } + } + } + + Overte.Label { + Layout.alignment: Qt.AlignRight + horizontalAlignment: Text.AlignRight + font.pixelSize: Overte.Theme.fontPixelSizeSmall + text: (new Date(timestamp)).toLocaleTimeString(undefined, Locale.ShortFormat) + + MouseArea { + anchors.fill: parent + cursorShape: Qt.WhatsThisCursor + hoverEnabled: true + + Overte.ToolTip { + visible: parent.containsMouse + text: (new Date(timestamp)).toLocaleString(undefined, Locale.LongFormat) + } + } + } + } + + Overte.BodyText { + Layout.leftMargin: 6 + Layout.rightMargin: 16 + // If we used Layout.fillWidth, then the entire block width would be selectable. + // With this hack we only use the width we really need to + Layout.maximumWidth: parent.width - parent.anchors.leftMargin - parent.anchors.rightMargin + + visible: text.length > 0 + + // MD support is cool, but it'd only work properly in the QML chat + // app and not chat bubbles, where formatting isn't supported in Text entities. + //textFormat: TextEdit.MarkdownText + textFormat: TextEdit.RichText + + text: { + if (notification) { return ""; } + + return ( + body + .replace( + /(https?:\/\/\S+)/gi, + `$1` + ) + ); + } + } + + Repeater { + model: imageEmbeds + + Rectangle { + required property string modelData + + color: Overte.Theme.paletteActive.alternateBase + radius: Overte.Theme.borderRadius + + Layout.maximumWidth: messageBlock.width - 64 + Layout.maximumHeight: 320 + + implicitWidth: ( + embeddedImage.status === Image.Ready ? + embeddedImage.sourceSize.width + (Overte.Theme.borderWidth * 2) : + messageBlock.width - 64 + ) + implicitHeight: Math.max( + Overte.Theme.fontPixelSize * 2, + embeddedImage.sourceSize.width + (Overte.Theme.borderWidth * 2) + ) + + AnimatedImage { + anchors.fill: parent + anchors.margins: Overte.Theme.borderWidth + + id: embeddedImage + fillMode: Image.PreserveAspectFit + autoTransform: true + source: modelData + //sourceSize.width: width + //sourceSize.height: height + + MouseArea { + anchors.fill: parent + id: embedMouseArea + + hoverEnabled: true + propagateComposedEvents: true + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.LeftButton + + onClicked: Qt.openUrlExternally(modelData) + } + } + + Overte.ToolTip { + text: modelData + visible: embedMouseArea.containsMouse + } + + Overte.Label { + visible: embeddedImage.status !== Image.Ready + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: ( + embeddedImage.status === Image.Loading ? + qsTr("Loading image… %1%%").arg(Math.floor(embeddedImage.progress * 100)) : + qsTr("Error loading image") + ) + } + } + } +} diff --git a/interface/resources/qml/overte/chat/SettingsPage.qml b/interface/resources/qml/overte/chat/SettingsPage.qml new file mode 100644 index 00000000000..b014635307a --- /dev/null +++ b/interface/resources/qml/overte/chat/SettingsPage.qml @@ -0,0 +1,71 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import "../" as Overte +import "../settings" as OverteSettings + +Column { + id: settingsPage + spacing: 16 + + Item { + anchors.left: parent.left + anchors.right: parent.right + implicitHeight: Math.max(settingsBackBtn.implicitHeight, settingsTitleLabel.implicitHeight) + + Overte.Label { + anchors.fill: parent + + id: settingsTitleLabel + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Settings - Chat") + } + + Overte.Button { + id: settingsBackBtn + icon.source: "../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + text: qsTr("Back", "Return to previous page") + + onClicked: { + stack.pop(); + } + } + } + + OverteSettings.SwitchSetting { + text: qsTr("Join/Leave Notifications") + + value: root.settingJoinNotifications + onValueChanged: { + root.settingJoinNotifications = value; + root.sendSettingsUpdate(); + } + } + + OverteSettings.SwitchSetting { + text: qsTr("Chat Bubbles") + + value: root.settingChatBubbles + onValueChanged: { + root.settingChatBubbles = value; + root.sendSettingsUpdate(); + } + } + + OverteSettings.SwitchSetting { + text: qsTr("Desktop Window") + + value: root.settingDesktopWindow + onValueChanged: { + root.settingDesktopWindow = value; + root.sendSettingsUpdate(); + } + } +} diff --git a/interface/resources/qml/overte/compat/CompatAssetDialog.qml b/interface/resources/qml/overte/compat/CompatAssetDialog.qml new file mode 100644 index 00000000000..addf54b4102 --- /dev/null +++ b/interface/resources/qml/overte/compat/CompatAssetDialog.qml @@ -0,0 +1,33 @@ +import QtCore +import QtQuick + +import ".." as Overte +import "../dialogs" as OverteDialogs + +import "../../windows" as HifiWindows + +// compatibility shim with Hifi FileDialog +HifiWindows.Window { + id: root + resizable: true + implicitWidth: 480 + implicitHeight: 480 + minSize: Qt.vector2d(480, 360) + destroyOnHidden: true + objectName: "AssetServer" + title: qsTr("Asset Browser") + opacity: parent.opacity + + Settings { + category: "Overlay.AssetServer" + property alias width: root.width + property alias height: root.height + property alias x: root.x + property alias y: root.y + } + + OverteDialogs.AssetDialog { + anchors.fill: parent + id: assetDialog + } +} diff --git a/interface/resources/qml/overte/compat/CompatFileDialog.qml b/interface/resources/qml/overte/compat/CompatFileDialog.qml new file mode 100644 index 00000000000..3d93c1feec1 --- /dev/null +++ b/interface/resources/qml/overte/compat/CompatFileDialog.qml @@ -0,0 +1,72 @@ +import QtCore +import QtQuick + +import ".." as Overte +import "../dialogs" as OverteDialogs + +import "../../windows" as HifiWindows + +// compatibility shim with Hifi FileDialog +HifiWindows.Window { + id: root + resizable: true + implicitWidth: 480 + implicitHeight: 360 + minSize: Qt.vector2d(360, 240) + destroyOnCloseButton: true + destroyOnHidden: true + modality: Qt.ApplicationModal + + Settings { + category: "FileDialog" + property alias width: root.width + property alias height: root.height + property alias x: root.x + property alias y: root.y + } + + property alias caption: root.title + property string dir: "" + property var filter // maybe not necessary? + + property bool selectDirectory: false + property bool multiSelect: false // unused + property bool saveDialog: false + + property var options + + signal selectedFile(var file) + signal canceled + + onSelectedFile: root.destroy() + onCanceled: root.destroy() + onWindowClosed: canceled() + + Component.onCompleted: { + if (dir !== "") { + fileDialog.currentFolder = dir; + } + } + + OverteDialogs.FileDialog { + anchors.fill: parent + + id: fileDialog + visible: true + + fileMode: { + if (root.selectDirectory) { + return OverteDialogs.FileDialog.FileMode.OpenFolder; + } else if (root.saveDialog) { + return OverteDialogs.FileDialog.FileMode.SaveFile; + } else if (root.multiSelect) { + return OverteDialogs.FileDialog.FileMode.OpenFiles; + } else { + return OverteDialogs.FileDialog.FileMode.OpenFile; + } + } + + onAccepted: root.selectedFile(fileDialog.selectedFile) + onRejected: root.canceled() + } +} diff --git a/interface/resources/qml/overte/compat/RunningScripts_Window.qml b/interface/resources/qml/overte/compat/RunningScripts_Window.qml new file mode 100644 index 00000000000..b5a45d86ccc --- /dev/null +++ b/interface/resources/qml/overte/compat/RunningScripts_Window.qml @@ -0,0 +1,14 @@ +import ".." as Overte +import "../dialogs" as OverteDialogs + +import "../../windows" as HifiWindows + +HifiWindows.Window { + objectName: "RunningScripts" + title: qsTr("Running Scripts") + opacity: parent.opacity + resizable: true + minSize: Qt.vector2d(384, 192) + + OverteDialogs.RunningScriptsDialog {} +} diff --git a/interface/resources/qml/overte/compat/qmldir b/interface/resources/qml/overte/compat/qmldir new file mode 100644 index 00000000000..66496dbc57d --- /dev/null +++ b/interface/resources/qml/overte/compat/qmldir @@ -0,0 +1,4 @@ +module Compat +RunningScripts_Window 1.0 RunningScripts_Window.qml +CompatFileDialog 1.0 CompatFileDialog.qml +CompatAssetDialog 1.0 CompatAssetDialog.qml diff --git a/interface/resources/qml/overte/contacts/AccountAvatar.qml b/interface/resources/qml/overte/contacts/AccountAvatar.qml new file mode 100644 index 00000000000..b1530d75937 --- /dev/null +++ b/interface/resources/qml/overte/contacts/AccountAvatar.qml @@ -0,0 +1,59 @@ +import QtQuick +import QtQuick.Effects + +import ".." as Overte + +Rectangle { + required property int status + property alias source: avatarImage.source + property alias retainWhileLoading: avatarImage.retainWhileLoading + + color: "transparent" + + implicitWidth: 64 + border.width + implicitHeight: 64 + border.width + + id: avatar + radius: Overte.Theme.borderRadius + border.width: Math.max(2, Overte.Theme.borderWidth) + border.color: { + switch (status) { + case -1: return Overte.Theme.paletteActive.statusOffline; + case 0: return Overte.Theme.paletteActive.statusOffline; + case 1: return Overte.Theme.paletteActive.statusFriendsOnly; + case 2: return Overte.Theme.paletteActive.statusContacts; + case 3: return Overte.Theme.paletteActive.statusEveryone; + } + } + + Image { + anchors.fill: avatar + anchors.margins: avatar.border.width + fillMode: Image.PreserveAspectCrop + + id: avatarImage + sourceSize.width: width + sourceSize.height: height + + layer.enabled: true + layer.effect: MultiEffect { + anchors.fill: avatarImage + source: avatarImage + maskEnabled: true + maskSource: mask + } + } + + Item { + id: mask + anchors.fill: avatar + visible: false + + layer.enabled: true + Rectangle { + anchors.fill: parent + radius: avatar.radius + color: "black" + } + } +} diff --git a/interface/resources/qml/overte/contacts/AccountContact.qml b/interface/resources/qml/overte/contacts/AccountContact.qml new file mode 100644 index 00000000000..fce5036b66d --- /dev/null +++ b/interface/resources/qml/overte/contacts/AccountContact.qml @@ -0,0 +1,111 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import ".." as Overte +import "." + +Rectangle { + id: control + color: index % 2 === 0 ? Overte.Theme.paletteActive.base : Overte.Theme.paletteActive.alternateBase + implicitWidth: ListView.view.contentWidth + implicitHeight: 96 + + required property int index + + // directory username + required property string user + required property url avatarUrl + required property int status + required property bool friend + required property string currentPlaceName + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + anchors.leftMargin: 8 + anchors.rightMargin: 8 + + RowLayout { + Layout.fillWidth: true + spacing: 16 + + AccountAvatar { + source: avatarUrl + status: control.status + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + text: user + } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + verticalAlignment: Text.AlignVCenter + + color: { + switch (control.status) { + case 0: return Overte.Theme.paletteActive.text; + case 1: return Overte.Theme.paletteActive.statusFriendsOnly; + case 2: return Overte.Theme.paletteActive.statusContacts; + case 3: return Overte.Theme.paletteActive.statusEveryone; + } + } + + text: { + switch (control.status) { + case 0: return qsTr("Offline"); + case 1: return qsTr("Friends Only"); + case 2: return qsTr("Contacts") + case 3: return qsTr("Everyone") + } + } + } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.8 + verticalAlignment: Text.AlignVCenter + text: currentPlaceName + visible: currentPlaceName !== "" + } + } + + Overte.RoundButton { + // TODO + visible: false + enabled: false + + backgroundColor: ( + control.friend ? + Overte.Theme.paletteActive.buttonDestructive : + Overte.Theme.paletteActive.buttonAdd + ) + icon.source: ( + control.friend ? + "../icons/remove_friend.svg" : + "../icons/add_friend.svg" + ) + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + // TODO + control.friend = !control.friend; + } + } + } + } +} diff --git a/interface/resources/qml/overte/contacts/ContactsList.qml b/interface/resources/qml/overte/contacts/ContactsList.qml new file mode 100644 index 00000000000..aa9de3aed6f --- /dev/null +++ b/interface/resources/qml/overte/contacts/ContactsList.qml @@ -0,0 +1,431 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import ".." as Overte +import "." + +Rectangle { + id: contactsList + anchors.fill: parent + implicitWidth: 480 + implicitHeight: 720 + color: Overte.Theme.paletteActive.base + + property string localSearchExpression: ".*" + property string accountSearchExpression: ".*" + + property list localContactsModel: [] + property list accountContactsModel: [] + property var adminData: ({}) + + property var waitingRequestCallbacks: ({}) + + function fromScript(message) { + const data = JSON.parse(message); + + switch (data.action) { + case "system:auth_request": { + if (contactsList.waitingRequestCallbacks[data.data.cookie]) { + contactsList.waitingRequestCallbacks[data.data.cookie](data.data); + delete contactsList.waitingRequestCallbacks[data.data.cookie]; + } + } break; + } + } + + function authRequest(data) { + let cookie = Date.now() + Math.floor(Math.random() * (1000 - -1000) + -1000); + + contactsList.waitingRequestCallbacks[cookie] = data.callback; + + sendToScript(JSON.stringify({ + action: "system:auth_request", + data: { + method: data.method ?? "GET", + url: data.url, + body: data.body, + cookie: cookie, + } + })); + } + + function updateLocalContacts() { + const palData = AvatarManager.getPalData().data; + let tmp = []; + + for (const data of palData) { + // don't add ourselves to the contacts list + if (!data.sessionUUID) { continue; } + + if (!contactsList.adminData[data.sessionUUID]) { + Users.requestUsernameFromID(data.sessionUUID); + } + + tmp.push({ + uuid: data.sessionUUID, + name: data.sessionDisplayName ? data.sessionDisplayName : `${qsTr("Unnamed")} ${data.sessionUUID}`, + volume: Users.getAvatarGain(data.sessionUUID), + }); + } + + localContactsModel = tmp; + } + + function updateAccountContactsImpl(accounts) { + console.debug("Contacts list data received"); + let tmp = []; + + for (const entry of accounts) { + // FIXME: /api/v1/users/connections doesn't give you the availability + // of a connection, only whether they're on a server or not + let status = entry.location?.online ? 2 : 0; + + let img = entry.images?.tiny ?? entry.images?.thumbnail; + + // some accounts have a bugged default avatar that doesn't exist + if ( + img === "assets/brand-icon-256.png" || + !(img && img.match(/^https?:\/\//)) + ) { + img = undefined; + } + + tmp.push({ + user: entry.username, + avatarUrl: img ?? "../icons/unset_avatar.svg", + status: status, + currentPlaceName: "", + friend: entry.connection === "friend", + }); + } + + tmp.sort((a, b) => ( + ((a.status !== 0 ? 1 : 0) - (b.status !== 0 ? 1 : 0)) || + a.user.localeCompare(b.user) + )); + + accountContactsModel = tmp; + } + + function updateAccountContacts() { + if (!AccountServices.loggedIn) { + accountContactsModel = []; + return; + } + + console.debug("Requesting contacts list…"); + authRequest({ + method: "GET", + url: `${AccountServices.metaverseServerURL}/api/v1/users/connections`, + callback: response => { + try { + let data = JSON.parse(response.responseText); + if (data.status === "success" && data?.data?.users) { + updateAccountContactsImpl(data.data.users); + } else { + console.error("Failed to get contacts list"); + console.debug(response.responseText); + } + } catch (e) { + console.error(e); + } + }, + }); + } + + Connections { + target: Users + + function usernameFromIDReply(sessionUUID, username, _fingerprint, isAdmin) { + contactsList.adminData[sessionUUID] = { + username: username, + badge: isAdmin ? "../icons/admin_shield.svg" : "" + }; + + // only assignments are checked, not property changes, so force the update signal + contactsList.adminDataChanged(); + } + + function avatarRemovedEvent(sessionUUID) { + delete contactsList.adminData[sessionUUID]; + updateLocalContacts(); + } + + function avatarAddedEvent(sessionUUID) { + updateLocalContacts(); + } + } + + Connections { + target: AccountServices + + function loggedInChanged(_loggedIn) { + updateAccountContacts(); + } + } + + Component.onCompleted: { + updateLocalContacts(); + updateAccountContacts(); + } + + ColumnLayout { + anchors.fill: contactsList + + MyAccountInfo { + Layout.fillWidth: true + id: myAccountInfo + } + + Overte.TabBar { + Layout.fillWidth: true + id: tabBar + + Overte.TabButton { text: qsTr("Local") } + Overte.TabButton { text: qsTr("Account") } + } + + StackLayout { + currentIndex: tabBar.currentIndex + + // Local + ColumnLayout { + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + + visible: !localContactsList.visible + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + text: qsTr("It's just you here") + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: localContactsList + visible: model.length > 0 + clip: true + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + } + + contentWidth: contactsList.width - Overte.Theme.scrollbarWidth + + model: { + const regex = new RegExp(localSearchExpression, "i"); + let tmp = []; + + for (const item of localContactsModel) { + if (item.name.match(regex) || item.user.match(regex)) { + tmp.push(item); + } + } + + return tmp; + } + delegate: SessionContact {} + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 4 + Layout.rightMargin: 4 + + Overte.TextField { + Layout.fillWidth: true + + Keys.onEnterPressed: { + localSearchButton.clicked(); + forceActiveFocus(); + } + + Keys.onReturnPressed: { + localSearchButton.clicked(); + forceActiveFocus(); + } + + placeholderText: qsTr("Search…") + id: localSearchField + } + + Overte.RoundButton { + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + id: localSearchButton + + onClicked: localSearchExpression = localSearchField.text + } + } + } + + // Account + ColumnLayout { + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + visible: myAccountInfo.status !== MyAccountInfo.Status.LoggedOut + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + } + + contentWidth: contactsList.width - Overte.Theme.scrollbarWidth + + model: { + const regex = new RegExp(accountSearchExpression, "i"); + let tmp = []; + + for (const item of accountContactsModel) { + if (item.user.match(regex)) { + tmp.push(item); + } + } + + return tmp; + } + delegate: AccountContact {} + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 4 + Layout.rightMargin: 4 + visible: myAccountInfo.status !== MyAccountInfo.Status.LoggedOut + + Overte.TextField { + Layout.fillWidth: true + + Keys.onEnterPressed: { + accountSearchButton.clicked(); + forceActiveFocus(); + } + + Keys.onReturnPressed: { + accountSearchButton.clicked(); + forceActiveFocus(); + } + + placeholderText: qsTr("Search…") + id: accountSearchField + } + + Overte.RoundButton { + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + id: accountSearchButton + + onClicked: accountSearchExpression = accountSearchField.text + } + } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + visible: myAccountInfo.status === MyAccountInfo.Status.LoggedOut + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Log in to track contacts") + } + } + } + } + + Overte.Dialog { + id: changeAvatarDialog + anchors.fill: parent + maxWidth: -1 + + signal accepted + signal rejected + + onAccepted: { + myAccountInfo.avatarUrl = avatarChangeUrlField.text; + + authRequest({ + method: "POST", + url: `${AccountServices.metaverseServerURL}/api/v1/account/${AccountServices.username}/field/images_tiny`, + body: JSON.stringify({ set: myAccountInfo.avatarUrl }), + }); + + avatarChangeUrlField.text = ""; + close(); + } + + onRejected: { + avatarChangeUrlField.text = ""; + close(); + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: qsTr("Change profile picture") + } + Overte.Ruler { Layout.fillWidth: true } + + Overte.Label { + Layout.topMargin: 12 + Layout.bottomMargin: 12 + Layout.fillWidth: true + wrapMode: Text.Wrap + font.pixelSize: Overte.Theme.fontPixelSizeSmall + text: qsTr("Profile pictures aren't stored on the directory server, so you need to supply a URL to your profile picture.\n\nSome services that let you upload images will give you links that will expire and stop working after a while.\n\n100x100 JPEG or WebP is recommended.") + } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: qsTr("Profile picture URL") + id: avatarChangeUrlField + } + + RowLayout { + Layout.preferredWidth: 720 + Layout.fillWidth: true + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + text: qsTr("Cancel") + + onClicked: changeAvatarDialog.rejected(); + } + + Item { + Layout.preferredWidth: 1 + Layout.fillWidth: true + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Apply") + enabled: ( + avatarChangeUrlField.text !== "" && + avatarChangeUrlField.text.match(/^https?:\/\//) + ) + + onClicked: changeAvatarDialog.accepted() + } + } + } + } +} diff --git a/interface/resources/qml/overte/contacts/MyAccountInfo.qml b/interface/resources/qml/overte/contacts/MyAccountInfo.qml new file mode 100644 index 00000000000..ded4de11954 --- /dev/null +++ b/interface/resources/qml/overte/contacts/MyAccountInfo.qml @@ -0,0 +1,213 @@ +import QtCore as QtCore +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import ".." as Overte +import "." + +Rectangle { + id: root + radius: 8 + border.width: Overte.Theme.borderWidth + border.color: Qt.darker(color, 1.2) + color: Overte.Theme.paletteActive.base + + implicitHeight: 96 + implicitWidth: 320 + + enum Status { + LoggedOut = -1, + Invisible, + FriendsOnly, + Contacts, + Everyone + } + + // cache the last avatar image url so there's not a few + // seconds of placeholder avatar while the profile loads + QtCore.Settings { + id: settings + category: "MyAccountInfo" + property url cachedAvatarUrl: "../icons/unset_avatar.svg" + } + + Connections { + target: AccountServices + + function loggedInChanged(loggedIn) { + updateStatus(); + } + } + + Component.onCompleted: updateStatus() + + function updateStatus() { + if (status === MyAccountInfo.Status.LoggedOut && AccountServices.loggedIn) { + contactsList.authRequest({ + url: `${AccountServices.metaverseServerURL}/api/v1/account/${AccountServices.username}/field/images_tiny`, + callback: response => { + const data = JSON.parse(response.responseText); + if (data.data) { + root.avatarUrl = data.data; + } + }, + }); + } + + if (!AccountServices.loggedIn) { + status = MyAccountInfo.Status.LoggedOut; + } else { + switch (AccountServices.findableBy) { + case "none": status = MyAccountInfo.Status.Invisible; break; + case "friends": status = MyAccountInfo.Status.FriendsOnly; break; + case "contacts": status = MyAccountInfo.Status.Contacts; break; + case "all": status = MyAccountInfo.Status.Everyone; break; + } + } + } + + property int status: MyAccountInfo.Status.LoggedOut + + property string avatarUrl: settings.cachedAvatarUrl + + onAvatarUrlChanged: settings.cachedAvatarUrl = avatarUrl + + readonly property color currentStatusColor: { + switch (status) { + case MyAccountInfo.Status.LoggedOut: + return Overte.Theme.paletteActive.statusOffline; + + case MyAccountInfo.Status.Invisible: + return Overte.Theme.paletteActive.statusOffline; + + case MyAccountInfo.Status.FriendsOnly: + return Overte.Theme.paletteActive.statusFriendsOnly; + + case MyAccountInfo.Status.Contacts: + return Overte.Theme.paletteActive.statusContacts; + + case MyAccountInfo.Status.Everyone: + return Overte.Theme.paletteActive.statusEveryone; + } + } + + readonly property string currentStatusName: { + switch (status) { + case MyAccountInfo.Status.LoggedOut: + return qsTr("Logged Out"); + + case MyAccountInfo.Status.Invisible: + return qsTr("Invisible"); + + case MyAccountInfo.Status.FriendsOnly: + return qsTr("Friends Only"); + + case MyAccountInfo.Status.Contacts: + return qsTr("Contacts"); + + case MyAccountInfo.Status.Everyone: + return qsTr("Everyone"); + } + } + + RowLayout { + anchors.fill: parent + + AccountAvatar { + id: avatarImg + source: ( + root.status !== MyAccountInfo.Status.LoggedOut ? + root.avatarUrl : + "../icons/unset_avatar.svg" + ) + status: root.status + retainWhileLoading: true + Layout.preferredWidth: 64 + Layout.preferredHeight: 64 + Layout.leftMargin: 8 + Layout.rightMargin: 8 + + Overte.Button { + anchors.fill: parent + anchors.margins: Overte.Theme.borderWidth + + backgroundColor: Overte.Theme.paletteActive.buttonAdd + opacity: hovered ? (Overte.Theme.highContrast ? 1.0 : 0.7) : 0 + enabled: AccountServices.loggedIn + visible: AccountServices.loggedIn + + icon.source: "../icons/plus.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: changeAvatarDialog.open() + + Overte.ToolTip { text: qsTr("Change profile picture") } + } + } + + ColumnLayout { + Layout.rightMargin: 8 + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + + Overte.TextField { + Layout.fillWidth: true + verticalAlignment: Text.AlignVCenter + + id: displayName + text: MyAvatar.displayName + placeholderText: AccountServices.username + + onEditingFinished: MyAvatar.displayName = text + } + + RowLayout { + Layout.fillWidth: true + + Overte.Label { + text: root.status === MyAccountInfo.Status.Invisible ? "â—‹" : "â—" + color: root.currentStatusColor + } + + Overte.ComboBox { + Layout.fillWidth: true + + id: statusBox + flat: true + color: root.status === MyAccountInfo.Status.Invisible ? Overte.Theme.paletteActive.windowText : root.currentStatusColor + textRole: "text" + valueRole: "value" + visible: root.status !== MyAccountInfo.Status.LoggedOut + + onActivated: index => { + root.status = index; + + switch (index) { + case 0: AccountServices.findableBy = "none"; break; + case 1: AccountServices.findableBy = "friends"; break; + case 2: AccountServices.findableBy = "connections"; break; + case 3: AccountServices.findableBy = "all"; break; + } + } + + currentIndex: root.status + model: [ + { value: MyAccountInfo.Status.Invisible, text: qsTr("Invisible") }, + { value: MyAccountInfo.Status.FriendsOnly, text: qsTr("Friends Only") }, + { value: MyAccountInfo.Status.Contacts, text: qsTr("Contacts") }, + { value: MyAccountInfo.Status.Everyone, text: qsTr("Everyone") }, + ] + } + + Overte.Label { + Layout.fillWidth: true + visible: root.status === MyAccountInfo.Status.LoggedOut + verticalAlignment: Text.AlignVCenter + text: qsTr("Logged Out") + } + } + } + } +} diff --git a/interface/resources/qml/overte/contacts/SessionContact.qml b/interface/resources/qml/overte/contacts/SessionContact.qml new file mode 100644 index 00000000000..e0c37949f66 --- /dev/null +++ b/interface/resources/qml/overte/contacts/SessionContact.qml @@ -0,0 +1,114 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import ".." as Overte + +Rectangle { + id: control + color: index % 2 === 0 ? Overte.Theme.paletteActive.base : Overte.Theme.paletteActive.alternateBase + implicitWidth: ListView.view.contentWidth + implicitHeight: 96 + + required property int index + + required property string uuid + required property string name + required property real volume + + readonly property string username: contactsList.adminData[uuid]?.username ?? "" + readonly property url badgeIconSource: contactsList.adminData[uuid]?.badge ?? "" + + // TODO: does this work? + function dbToReal(x) { + return 1.0 - (x / 100); + } + + function realToDb(x) { + return (1.0 - x) * 100; + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 4 + anchors.leftMargin: 8 + anchors.rightMargin: 8 + + RowLayout { + Layout.fillWidth: true + spacing: 16 + + Image { + Layout.leftMargin: 6 + Layout.preferredWidth: 24 + Layout.preferredHeight: 24 + source: badgeIconSource + } + + ColumnLayout { + Layout.fillWidth: true + + Overte.Label { + Layout.fillWidth: true + elide: Text.ElideRight + text: name + } + + Overte.BodyText { + font.pixelSize: Overte.Theme.fontPixelSizeSmall + visible: username !== "" + //elide: Text.ElideRight + text: username + palette.buttonText: Overte.Theme.paletteActive.link + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + } + } + + Item { Layout.fillWidth: true } + + // TODO: find a way of disabling this if the target is already in the account + // contacts, might be tricky with how usernames are hidden from non-admins + /*Overte.RoundButton { + icon.source: "../icons/add_friend.svg" + icon.width: 24 + icon.height: 24 + + backgroundColor: hovered ? Overte.Theme.paletteActive.buttonAdd : Overte.Theme.paletteActive.button + + Overte.ToolTip { text: qsTr("Send contact request") } + + onClicked: console.warn("TODO") + }*/ + } + + RowLayout { + Overte.RoundButton { + icon.source: volumeSlider.value === 0.0 ? "../icons/speaker_muted.svg" : "../icons/speaker_active.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: volumeSlider.value = 0.0 + } + + Overte.Slider { + Layout.fillWidth: true + id: volumeSlider + from: 0.0 + to: 1.2 + stepSize: 0.1 + snapMode: Slider.SnapAlways + value: dbToReal(volume) + + onMoved: Users.setAvatarGain(control.uuid, realToDb(value)) + } + + Overte.Label { + Layout.preferredWidth: Overte.Theme.fontPixelSize * 3 + //text: `${Math.round(volumeSlider.value * 100)}%` + // why did hifi have to use decibels for avatar volume?? + text: `${Math.round(volumeSlider.value * 100)}%\n${volume} db` + } + } + } +} diff --git a/interface/resources/qml/overte/contacts/qmldir b/interface/resources/qml/overte/contacts/qmldir new file mode 100644 index 00000000000..f32fee462df --- /dev/null +++ b/interface/resources/qml/overte/contacts/qmldir @@ -0,0 +1,6 @@ +module Contacts +ContactsList 1.0 ContactsList.qml +AccountAvatar 1.0 AccountAvatar.qml +SessionContact 1.0 SessionContact.qml +AccountContact 1.0 AccountContact.qml +MyAccountInfo 1.0 MyAccountInfo.qml diff --git a/interface/resources/qml/overte/dialogs/AssetDialog.qml b/interface/resources/qml/overte/dialogs/AssetDialog.qml new file mode 100644 index 00000000000..5fda22bdceb --- /dev/null +++ b/interface/resources/qml/overte/dialogs/AssetDialog.qml @@ -0,0 +1,384 @@ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt.labs.folderlistmodel +import Qt.labs.qmlmodels + +import ".." as Overte + +Rectangle { + id: dialog + color: Overte.Theme.paletteActive.base + + property url selectedFile: "" + property string searchExpression: ".*" + + // FIXME: "Could not convert argument 0 from [object Object] to EntityItemProperties" + //readonly property var spawnableRegex: /\.(gltf|glb|vrm|fbx|fst|obj|png|jpeg|jpg|webp)$/i + readonly property var spawnableRegex: /\.(gltf|glb|vrm|fbx|fst|obj)$/i + + property var assetMappingModel: ({}) + + Component.onCompleted: refreshModel() + + function refreshModel() { + Assets.getAllMappings((error, maps) => { + if (error === "") { + assetMappingModel = maps; + tableModel.rows = getDirectoryModel(); + } else { + console.error(error); + } + }); + } + + // this seems suboptimal but i can't figure out how else to use the Assets models + function getDirectoryModel() { + let tmp = []; + + for (const [name, hash] of Object.entries(assetMappingModel)) { + if (!name.slice(1).match(new RegExp(searchExpression, "i"))) { + continue; + } + + tmp.push({ + // trim off the leading slash + name: name.slice(1), + path: name, + hash: hash, + }); + } + + tmp.sort((a, b) => a.name.localeCompare(b.name)); + + return tmp; + } + + component TableDelegate: Rectangle { + required property TableView tableView + required property int row + required property bool current + + property string name: tableModel.rows[row]?.name ?? "undefined" + + implicitWidth: Math.max(tableView.contentWidth, label.implicitWidth) + implicitHeight: Overte.Theme.fontPixelSize * 2 + + color: { + if (current) { + return Overte.Theme.paletteActive.highlight; + } else if (row % 2 === 0) { + return Overte.Theme.paletteActive.base; + } else { + return Overte.Theme.paletteActive.alternateBase; + } + } + + Overte.Label { + id: label + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + anchors.leftMargin: 4 + verticalAlignment: Text.AlignVCenter + color: current ? Overte.Theme.paletteActive.highlightedText : Overte.Theme.paletteActive.buttonText + text: name + } + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Layout.fillWidth: true + Layout.margins: 4 + + Overte.Button { + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Upload File") + + // TODO + enabled: false + onClicked: {} + } + + Overte.TextField { + Layout.fillWidth: true + Layout.preferredHeight: parent.height + + id: searchField + placeholderText: qsTr("Search…") + + Keys.onEnterPressed: { + searchButton.click(); + searchField.forceActiveFocus(); + } + + Keys.onReturnPressed: { + searchButton.click(); + searchField.forceActiveFocus(); + } + } + + Overte.RoundButton { + id: searchButton + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + searchExpression = searchField.text === "" ? ".*" : searchField.text; + + // refresh the listing model + tableModel.rows = getDirectoryModel(); + } + } + } + + TableView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: tableView + clip: true + selectionBehavior: TableView.SelectRows + selectionMode: TableView.SingleSelection + pixelAligned: true + rowSpacing: 1 + columnSpacing: 0 + boundsBehavior: Flickable.StopAtBounds + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AlwaysOn + interactive: true + } + + ScrollBar.horizontal: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + interactive: true + } + + contentWidth: width - ScrollBar.vertical.width + + model: TableModel { + id: tableModel + + TableModelColumn { display: "name" } + + rows: [] + } + + selectionModel: ItemSelectionModel {} + delegate: TableDelegate {} + } + + GridLayout { + rows: 2 + columns: 2 + Layout.fillWidth: true + Layout.margins: 8 + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + // TODO: might work, don't have a way of testing atm + //enabled: tableView.currentRow !== -1 + enabled: false + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + text: qsTr("Delete") + + onClicked: { + const data = tableModel.rows[tableView.currentRow]; + deleteWarningDialog.entryToDelete = data.name; + deleteWarningDialog.open(); + } + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + enabled: tableView.currentRow !== -1 + backgroundColor: Overte.Theme.paletteActive.buttonInfo + text: qsTr("Copy Link") + + onClicked: { + const data = tableModel.rows[tableView.currentRow]; + WindowScriptingInterface.copyToClipboard(`atp:${data.path}`); + } + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + // TODO: might work, don't have a way of testing atm + // enabled: tableView.currentRow !== -1 + enabled: false + text: qsTr("Rename") + + onClicked: { + const data = tableModel.rows[tableView.currentRow]; + renameDialog.entryToRename = data.name; + renameDialog.open(); + } + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + enabled: { + if (tableView.currentRow === -1) { return false; } + return tableModel.rows[tableView.currentRow].name.match(spawnableRegex); + } + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Create Entity") + + onClicked: { + const data = tableModel.rows[tableView.currentRow]; + spawnEntity(data.path); + } + } + } + } + + Overte.MessageDialog { + id: deleteWarningDialog + anchors.fill: parent + + property string entryToDelete: "" + text: qsTr("Are you sure you want to delete %1?").arg(entryToDelete) + + onAccepted: { + // put the leading slash back on + Assets.deleteMapping(`/${entryToDelete}`); + entryToDelete = ""; + close(); + } + + onRejected: { + entryToDelete = ""; + close(); + } + } + + Overte.Dialog { + id: renameDialog + anchors.fill: parent + + property string entryToRename: "" + + signal accepted + signal rejected + + onAccepted: { + // put the leading slash back on + Assets.renameMapping(`/${entryToRename}`, `/${assetRenameField.text}`, refreshModel); + assetRenameField.text = ""; + entryToRename = ""; + close(); + } + + onRejected: { + assetRenameField.text = ""; + entryToRename = ""; + close(); + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: qsTr("Rename asset") + } + Overte.Ruler { Layout.fillWidth: true } + + Overte.TextField { + Layout.preferredWidth: 720 + Layout.fillWidth: true + placeholderText: qsTr("New asset name") + text: renameDialog.entryToRename + id: assetRenameField + } + + RowLayout { + Overte.Button { + Layout.minimumWidth: 128 + Layout.fillWidth: true + text: qsTr("Cancel") + + onClicked: renameDialog.rejected() + } + + Item { Layout.fillWidth: true } + + Overte.Button { + Layout.minimumWidth: 128 + Layout.fillWidth: true + + enabled: assetRenameField.text !== "" + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Rename") + + onClicked: renameDialog.accepted() + } + } + } + } + + function spawnEntity(path) { + let isImage = path.match(/\.(png|jpeg|jpg|webp)$/i); + let isMesh = path.match(/\.(gltf|glb|vrm|fbx|fst|obj)$/i); + + // FIXME: "Could not convert argument 0 from [object Object] to EntityItemProperties" + if (isImage) { + /*Entities.addEntity({ + type: "Image", + imageURL: `atp:${path}`, + emissive: true, + keepAspectRatio: true, + rotation: MyAvatar.orientation, + position: Vec3.sum( + MyAvatar.position, + Vec3.multiply(2, Quat.getForward(MyAvatar.orientation)) + ), + });*/ + } else if (isMesh) { + /*Entities.addEntity({ + type: "Model", + modelURL: `atp:${path}`, + shapeType: "simple-hull", + rotation: MyAvatar.orientation, + position: Vec3.sum( + MyAvatar.position, + Vec3.multiply(2, Quat.getForward(MyAvatar.orientation)) + ), + });*/ + Entities.addModelEntity( + /* name */ path, + /* modelUrl */ `atp:${path}`, + /* textures */ "", + /* shapeType */ "simple-hull", + /* dynamic */ false, + /* collisionless */ false, + /* grabbable */ true, + /* position */ Vec3.sum( + MyAvatar.position, + Vec3.multiply(2, Quat.getForward(MyAvatar.orientation)) + ), + /* gravity */ Vec3.ZERO + ); + } else { + console.error(`spawnEntity called with path that wasn't image or mesh! ${path}`); + } + } +} diff --git a/interface/resources/qml/overte/dialogs/BuiltinScriptsDialog.qml b/interface/resources/qml/overte/dialogs/BuiltinScriptsDialog.qml new file mode 100644 index 00000000000..0a19fa61147 --- /dev/null +++ b/interface/resources/qml/overte/dialogs/BuiltinScriptsDialog.qml @@ -0,0 +1,195 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt.labs.qmlmodels + +import ".." as Overte + +Rectangle { + anchors.fill: parent + implicitWidth: 400 + implicitHeight: 500 + visible: false + color: Overte.Theme.paletteActive.base + id: picker + + signal accepted(file: url) + signal rejected + + onAccepted: visible = false + onRejected: visible = false + + function open() { + visible = true; + } + + function getDirectoryModel(parentIndex = undefined) { + const DISPLAY_ROLE = 0; + const PATH_ROLE = 256; + const sourceModel = ScriptDiscoveryService.scriptsModel; + const sourceModelRootLength = sourceModel.rowCount(parentIndex); + let tmp = []; + + for (let i = 0; i < sourceModelRootLength; i++) { + const index = sourceModel.index(i, 0, parentIndex); + + const name = sourceModel.data(index, DISPLAY_ROLE); + const path = sourceModel.data(index, PATH_ROLE); + const hasChildren = sourceModel.hasChildren(index); + + if (hasChildren) { + tmp.push({ + name: name, + path: path, + rows: getDirectoryModel(index) + }); + } else { + tmp.push({ + name: name, + path: path, + }); + } + } + + tmp.sort((a, b) => ((b.rows ? 1 : 0) - (a.rows ? 1 : 0)) || a.name.localeCompare(b.name)); + + return tmp; + } + + component TreeDelegate: Rectangle { + required property TreeView treeView + required property int depth + required property int row + required property bool current + required property bool expanded + required property bool hasChildren + + property string name: treeView.model.getRow(treeView.index(row, 0)).name + + implicitWidth: treeView.contentWidth + implicitHeight: Overte.Theme.fontPixelSize * 2 + + color: { + if (current) { + return Overte.Theme.paletteActive.highlight; + } else if (row % 2 === 0) { + return Overte.Theme.paletteActive.base; + } else { + return Overte.Theme.paletteActive.alternateBase; + } + } + + // IconImage and ColorImage are private in Qt 6.10, + // so hijack AbstractButton's icon + Overte.Button { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.leftMargin: Overte.Theme.fontPixelSize * depth + id: indicator + + visible: hasChildren + width: parent.height + height: width + + flat: true + horizontalPadding: 0 + verticalPadding: 0 + + icon.source: expanded ? "../icons/triangle_down.svg" : "../icons/triangle_right.svg" + icon.width: Math.min(24, width) + icon.height: Math.min(24, width) + icon.color: current ? Overte.Theme.paletteActive.highlightedText : Overte.Theme.paletteActive.buttonText + + onClicked: treeView.toggleExpanded(row) + } + + Overte.Label { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: indicator.right + anchors.leftMargin: 4 + verticalAlignment: Text.AlignVCenter + color: current ? Overte.Theme.paletteActive.highlightedText : Overte.Theme.paletteActive.buttonText + text: name + } + } + + ColumnLayout { + anchors.fill: parent + + Overte.Label { + Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + wrapMode: Text.Wrap + text: qsTr("Load built-in script") + } + + Overte.Ruler { + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + } + + TreeView { + Layout.fillWidth: true + Layout.fillHeight: true + id: treeView + clip: true + + // QT6TODO: remove this once mouse input is working properly again, + // this needs to be false until then or the expander arrows are entirely unusable + interactive: false + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AlwaysOn + } + + contentWidth: width - ScrollBar.vertical.width + flickableDirection: Flickable.VerticalFlick + selectionModel: ItemSelectionModel {} + + model: TreeModel { + id: treeModel + + TableModelColumn { display: "name" } + + rows: getDirectoryModel() + } + + delegate: TreeDelegate {} + } + + RowLayout { + Layout.margins: 8 + Layout.fillWidth: true + + Item { Layout.fillWidth: true } + + Overte.Button { + Layout.preferredWidth: 128 + text: qsTr("Cancel") + + onClicked: rejected() + } + + Overte.Button { + Layout.preferredWidth: 128 + + enabled: { + if (treeView.selectionModel.currentIndex === -1) { return false; } + + const data = treeModel.getRow(treeView.selectionModel.currentIndex); + return !data?.rows; + } + text: qsTr("Load") + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + onClicked: { + const data = treeModel.getRow(treeView.selectionModel.currentIndex); + accepted(data.path); + } + } + } + } +} diff --git a/interface/resources/qml/overte/dialogs/FileDialog.qml b/interface/resources/qml/overte/dialogs/FileDialog.qml new file mode 100644 index 00000000000..beca7d6d55a --- /dev/null +++ b/interface/resources/qml/overte/dialogs/FileDialog.qml @@ -0,0 +1,610 @@ +import QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs as QtDialogs +import Qt.labs.folderlistmodel +import Qt.labs.qmlmodels + +import ".." +import "." + +Rectangle { + enum FileMode { + OpenFile, + OpenFiles, + SaveFile, + OpenFolder + } + + id: fileDialog + color: Theme.paletteActive.base + visible: false + + signal accepted + signal rejected + + property url currentFolder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + property list nameFilters: ["*"] + property int fileMode: FileDialog.OpenFile + + property url selectedFile: "" + property list selectedFiles: [] + + // TODO, FIXME + property list history: [] + property int historyIndex: 0 + + property string searchExpression: ".*" + + onAccepted: { + visible = false; + } + + onRejected: { + visible = false; + } + + function open() { + visible = true; + } + + function close() { + visible = false; + } + + function urlToPathString(urlRaw) { + const url = new URL(urlRaw); + + if (url.protocol !== "file:") { + return url; + } + + return url.pathname; + } + + function directoryRowActivated(currentData) { + const parentDir = new URL(currentFolder).pathname.match(/^\/?(.*)/)[1]; + const path = `file:///${parentDir}${parentDir ? "/" : ""}${currentData.fileName}`; + + if (currentData.fileIsDir) { + currentFolder = path; + tableView.selectionModel.clear(); + } else { + selectedFile = path; + selectedFiles = []; + + let possibleConflict = false; + + for (const index of tableView.selectionModel.selectedRows(0)) { + const rowData = tableView.model.getRow(index.row); + selectedFiles.push(`${currentFolder.toString()}/${rowData.fileName}`); + + if (rowData.fileName === saveName.text) { + possibleConflict = true; + } + } + + if (fileMode === FileDialog.FileMode.SaveFile && possibleConflict) { + replaceWarningDialog.text = qsTr("Are you sure you want to replace %1?").arg(saveName.text); + replaceWarningDialog.open(); + } else { + fileDialog.accepted(); + } + } + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.rightMargin: 8 + Layout.topMargin: 8 + + RoundButton { + icon.source: "../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Theme.paletteActive.buttonText + + enabled: historyIndex > 0 + + // TODO + onClicked: {} + } + RoundButton { + icon.source: "../icons/triangle_right.svg" + icon.width: 24 + icon.height: 24 + icon.color: Theme.paletteActive.buttonText + + enabled: historyIndex < history.length - 1 + + // TODO + onClicked: {} + } + + RoundButton { + icon.source: "../icons/arrow_up.svg" + icon.width: 24 + icon.height: 24 + icon.color: Theme.paletteActive.buttonText + + enabled: folderModel.parentFolder.toString() !== "" + + onClicked: { + currentFolder = folderModel.parentFolder; + } + } + + TextField { + Layout.fillWidth: true + Layout.preferredHeight: parent.height + + text: urlToPathString(fileDialog.currentFolder) + visible: pathEditToggle.checked + + Keys.onEnterPressed: { + fileDialog.currentFolder = `file:///${text.match(/^\/?(.*)/)[1]}`; + } + Keys.onReturnPressed: { + fileDialog.currentFolder = `file:///${text.match(/^\/?(.*)/)[1]}`; + } + } + + ListView { + Layout.fillWidth: true + Layout.preferredHeight: parent.height + + id: breadcrumbBar + visible: !pathEditToggle.checked + clip: true + pixelAligned: true + boundsBehavior: Flickable.StopAtBounds + orientation: Qt.Horizontal + + onCountChanged: { + positionViewAtEnd(); + } + + model: { + let breadcrumbs = []; + + let parts = new URL(currentFolder).pathname.split("/").filter(Boolean); + + if (SystemInformation.kernelType !== "winnt") { + parts.unshift(""); + } + + for (let i = 0; i < parts.length; i++) { + let targetUrl = parts.slice(1, i + 1).join("/"); + if (targetUrl === "") { + targetUrl = "file:///"; + } else { + targetUrl = "file:///" + targetUrl; + } + + breadcrumbs.push({ + label: parts[i] === "" ? "/" : parts[i], + targetUrl: targetUrl, + }); + } + + return breadcrumbs; + } + + delegate: Button { + required property string label + required property url targetUrl + + height: breadcrumbBar.height + text: label + + onClicked: { + currentFolder = targetUrl; + } + } + } + + RoundButton { + checkable: true + icon.source: "../icons/pencil.svg" + icon.color: Theme.paletteActive.buttonText + icon.width: 24 + icon.height: 24 + + id: pathEditToggle + } + } + + RowLayout { + Layout.fillWidth: true + + TextField { + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.preferredHeight: parent.height + + id: searchField + placeholderText: qsTr("Search…") + + Keys.onEnterPressed: searchButton.click() + Keys.onReturnPressed: searchButton.click() + } + + RoundButton { + Layout.rightMargin: 8 + + id: searchButton + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Theme.paletteActive.buttonText + + onClicked: { + searchExpression = searchField.text === "" ? ".*" : searchField.text; + + // force a refresh + folderModel.folder = ""; + folderModel.folder = fileDialog.currentFolder; + } + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + visible: folderModel.status === FolderListModel.Null + + ColumnLayout { + anchors.centerIn: parent + spacing: 8 + + Label { + Layout.fillWidth: true + + text: qsTr("Invalid or unreachable folder") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + } + + Button { + Layout.alignment: Qt.AlignHCenter + + text: qsTr("Go Home") + onClicked: { + currentFolder = StandardPaths.writableLocation(StandardPaths.HomeLocation); + } + } + } + } + + TableView { + Layout.fillWidth: true + Layout.fillHeight: true + visible: folderModel.status !== FolderListModel.Null + + // QT6TODO: Double-clicking on stuff flat out doesn't work yet, + // remove this once clicks on the overlay desktop work again + interactive: false + + ScrollBar.vertical: ScrollBar { + policy: ScrollBar.AlwaysOn + interactive: true + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + rightMargin: ScrollBar.vertical.width + + id: tableView + clip: true + selectionBehavior: TableView.SelectRows + selectionMode: ( + fileDialog.fileMode === FileDialog.FileMode.OpenFiles ? + TableView.ExtendedSelection : + TableView.SingleSelection + ) + pixelAligned: true + rowSpacing: 1 + columnSpacing: 0 + boundsBehavior: Flickable.StopAtBounds + + model: TableModel { + TableModelColumn { + display: "fileName" + textAlignment: () => Text.AlignLeft + } + TableModelColumn { + display: "fileModified" + textAlignment: () => Text.AlignRight + } + TableModelColumn { + display: "fileSize" + textAlignment: () => Text.AlignLeft + } + } + + FolderListModel { + id: folderModel + nameFilters: fileDialog.nameFilters + folder: fileDialog.currentFolder + showDirsFirst: true + showFiles: fileDialog.fileMode !== FileDialog.OpenFolder + showOnlyReadable: true + caseSensitive: false + sortCaseSensitive: false + + // TableModel can't have a ListModel for its rows, + // so we have to turn it into a JS array + onStatusChanged: { + if (folderModel.status === FolderListModel.Ready) { + if (folder === "") { return; } + + let data = []; + + for (let i = 0; i < folderModel.count; i++) { + let datum = { + fileName: folderModel.get(i, "fileName"), + fileModified: folderModel.get(i, "fileModified").toLocaleString(null, Locale.ShortFormat), + fileSize: folderModel.get(i, "fileSize"), + fileIsDir: folderModel.get(i, "fileIsDir"), + }; + + if (!datum.fileName.match(new RegExp(searchExpression, "i"))) { + continue; + } + + if (datum.fileSize > 1024 * 1024 * 1024) { + let value = datum.fileSize / (1024 * 1024 * 1024); + value = Math.round(value * 100) / 100; + datum.fileSize = `${value} GiB`; + } else if (datum.fileSize > 1024 * 1024) { + let value = datum.fileSize / (1024 * 1024); + value = Math.round(value * 100) / 100; + datum.fileSize = `${value} MiB`; + } else if (datum.fileSize > 1024) { + let value = datum.fileSize / 1024; + value = Math.round(value * 100) / 100; + datum.fileSize = `${value} KiB`; + } else { + datum.fileSize = qsTr("%n byte(s)", "", datum.fileSize); + } + + if (datum.fileIsDir) { + datum.fileSize = qsTr("Folder"); + } + + data.push(datum); + } + + tableView.model.rows = data; + } else { + tableView.model.rows = []; + } + + tableView.positionViewAtRow(0, TableView.AlignVCenter, Qt.point(0, 0), Qt.rect(0, 0, 0, 0)); + } + } + + selectionModel: ItemSelectionModel { + onCurrentChanged: (index, _) => { + if (index.row === -1) { return; } + + const data = tableView.model.getRow(index.row); + selectedFile = `${currentFolder.toString()}/${data.fileName}`; + } + } + + delegate: Rectangle { + required property bool selected + required property string display + required property int textAlignment + + color: ( + selected ? + Theme.paletteActive.highlight : + (row % 2 !== 0) ? Theme.paletteActive.alternateBase : Theme.paletteActive.base + ) + + id: cell + implicitHeight: { + // hide the mtime column if the window isn't big enough to fit it comfortably + if (column === 1 && tableView.width < 720) { + return 0; + } else { + return text.implicitHeight * 2 + } + } + implicitWidth: { + let nameWidth = tableView.width; + let mtimeWidth = tableView.width * (1 / 4); + let sizeWidth = tableView.width * (1 / 4); + + // qt doesn't let us do stretchy columns so emulate it ourselves + nameWidth -= sizeWidth; + nameWidth -= mtimeWidth; + + // hide the mtime column if the window isn't big enough to fit it comfortably + if (tableView.width < 720) { + // can't be zero or qt complains + nameWidth += mtimeWidth; + mtimeWidth = 1; + } + + // how come there's one extra pixel? + nameWidth -= tableView.rightMargin + 1; + + switch (column) { + case 0: return nameWidth; + case 1: return mtimeWidth; + case 2: return sizeWidth; + } + } + + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + + onPressed: mouse => { + parent.forceActiveFocus(); + + const index = tableView.model.index(row, column); + + if ( + fileMode === FileDialog.FileMode.OpenFiles && + (mouse.modifiers & Qt.ControlModifier) === Qt.ControlModifier + ) { + tableView.selectionModel.select( + index, + ItemSelectionModel.Toggle | ItemSelectionModel.Rows + ); + } else if ( + fileMode === FileDialog.FileMode.OpenFiles && + (mouse.modifiers & Qt.ShiftModifier) === Qt.ShiftModifier + ) { + const prevRow = tableView.selectionModel.currentIndex.row; + const currentRow = row; + const start = prevRow < currentRow ? prevRow : currentRow; + const end = prevRow < currentRow ? currentRow : prevRow; + + // select everything between the previous "current" row and the next "current" row + for (let i = start; i <= end; i++) { + tableView.selectionModel.select( + tableView.model.index(i, 0), + ItemSelectionModel.Select | ItemSelectionModel.Rows + ); + } + } else { + tableView.selectionModel.select( + index, + ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Rows + ); + } + + tableView.selectionModel.setCurrentIndex(index, ItemSelectionModel.Current); + + if (fileMode === FileDialog.FileMode.SaveFile) { + const rowData = tableView.model.getRow(index.row); + saveName.text = !rowData.fileIsDir ? rowData.fileName : ""; + } + } + + onDoubleClicked: { + directoryRowActivated(tableView.model.getRow(row)); + } + } + + Text { + id: text + anchors.fill: parent + anchors.leftMargin: 6 + anchors.rightMargin: 6 + + visible: parent.implicitWidth > 1 + text: cell.display + color: ( + selected ? + Theme.paletteActive.highlightedText : + Theme.paletteActive.text + ) + font.family: Theme.fontFamily + font.pixelSize: Theme.fontPixelSize + horizontalAlignment: cell.textAlignment + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + } + } + } + + RowLayout { + visible: fileMode === FileDialog.FileMode.SaveFile + + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.rightMargin: 8 + + TextField { + Layout.fillWidth: true + + id: saveName + placeholderText: qsTr("Saved file name") + } + } + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 8 + Layout.rightMargin: 8 + Layout.bottomMargin: 8 + + Label { + Layout.fillWidth: true + Layout.rightMargin: 8 + Layout.preferredHeight: parent.height + + text: nameFilters.join(", ") + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + Button { + implicitWidth: 128 + text: qsTr("Cancel") + + Component.onCompleted: { + clicked.connect(fileDialog.rejected) + } + } + + Button { + implicitWidth: 128 + backgroundColor: Theme.paletteActive.buttonAdd + text: { + if (fileMode === FileDialog.FileMode.OpenFolder) { + return qsTr("Open Here"); + } + + let text = fileMode === FileDialog.FileMode.SaveFile ? qsTr("Save") : qsTr("Open"); + + const currentRow = tableView.selectionModel.currentIndex.row; + if (currentRow !== -1) { + const currentData = tableView.model.getRow(currentRow); + + if (currentData.fileIsDir) { + text = qsTr("Open"); + } + } + + return text; + } + + enabled: tableView.selectionModel.hasSelection || fileMode === FileDialog.FileMode.OpenFolder + onClicked: { + if (fileMode === FileDialog.FileMode.OpenFolder) { + selectedFile = currentFolder; + fileDialog.accepted(); + } else { + const currentRow = tableView.selectionModel.currentIndex.row; + const currentData = tableView.model.getRow(currentRow); + directoryRowActivated(currentData); + } + } + } + } + } + + MessageDialog { + id: replaceWarningDialog + anchors.fill: parent + buttons: QtDialogs.MessageDialog.Yes | QtDialogs.MessageDialog.No + + onAccepted: { + fileDialog.accepted(); + } + } +} diff --git a/interface/resources/qml/overte/dialogs/README.md b/interface/resources/qml/overte/dialogs/README.md new file mode 100644 index 00000000000..cffd0b0ea75 --- /dev/null +++ b/interface/resources/qml/overte/dialogs/README.md @@ -0,0 +1 @@ +These are top-level windowed dialogs. They aren't derived from Dialog, which is an inline modal popup. diff --git a/interface/resources/qml/overte/dialogs/RunningScriptsDialog.qml b/interface/resources/qml/overte/dialogs/RunningScriptsDialog.qml new file mode 100644 index 00000000000..674d0cbd4a4 --- /dev/null +++ b/interface/resources/qml/overte/dialogs/RunningScriptsDialog.qml @@ -0,0 +1,312 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import ".." as Overte +import "." as OverteDialogs + +Rectangle { + anchors.fill: parent + + id: root + implicitWidth: 480 + implicitHeight: 720 + color: Overte.Theme.paletteActive.base + + property list runningScriptsModel: [] + + function refreshRunningScriptsModel() { + let tmp = []; + + for (const script of ScriptDiscoveryService.getRunning()) { + tmp.push({ + name: script.name, + url: script.url, + }); + } + + tmp.sort((a, b) => a.name.localeCompare(b.name)); + + runningScriptsModel = tmp; + } + + Connections { + target: ScriptDiscoveryService + + function onScriptCountChanged() { + refreshRunningScriptsModel(); + } + } + + Component.onCompleted: refreshRunningScriptsModel() + + component ScriptDelegate: Rectangle { + required property int index + required property string name + required property string url + + width: runningList.width - Overte.Theme.scrollbarWidth + height: layout.implicitHeight + + color: ( + index % 2 == 0 ? + Overte.Theme.paletteActive.base : + Overte.Theme.paletteActive.alternateBase + ) + + RowLayout { + id: layout + anchors.fill: parent + + ColumnLayout { + Layout.margins: 8 + + Overte.Label { + Layout.alignment: Qt.AlignLeft | Qt.AlignTop + Layout.fillWidth: true + elide: Text.ElideRight + text: name.replace(/(.*).js$/, "$1"); + } + + Overte.Label { + Layout.alignment: Qt.AlignLeft | Qt.AlignBottom + Layout.fillWidth: true + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + elide: Text.ElideRight + text: { + if (url.startsWith("qrc:")) { + return qsTr("Built-in: %1").arg(url.toString().replace(/qrc:\/+(.*)$/, "$1")); + } else if (url.startsWith("file:///~/")) { + return qsTr("Built-in: %1").arg(url.toString().replace(/file:\/+\~\/+(.*)$/, "$1")); + } else { + return url; + } + } + } + } + + Row { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.margins: 8 + spacing: 2 + + Overte.RoundButton { + backgroundColor: Overte.Theme.paletteActive.buttonInfo + + icon.source: "../icons/copy.svg" + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 20 + icon.height: 20 + + implicitWidth: 28 + implicitHeight: 28 + horizontalPadding: 0 + verticalPadding: 0 + + onClicked: WindowScriptingInterface.copyToClipboard(url) + + Overte.ToolTip { text: qsTr("Copy URL to clipboard") } + } + + Overte.RoundButton { + icon.source: "../icons/reload.svg" + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 20 + icon.height: 20 + + implicitWidth: 28 + implicitHeight: 28 + horizontalPadding: 0 + verticalPadding: 0 + + // restart the script + onClicked: ScriptDiscoveryService.stopScript(url, true) + + Overte.ToolTip { text: qsTr("Reload") } + } + + Overte.RoundButton { + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + + icon.source: "../icons/close.svg" + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 20 + icon.height: 20 + + implicitWidth: 28 + implicitHeight: 28 + horizontalPadding: 0 + verticalPadding: 0 + + onClicked: ScriptDiscoveryService.stopScript(url) + + Overte.ToolTip { text: qsTr("Stop and remove") } + } + } + } + } + + ColumnLayout { + anchors.fill: parent + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AlwaysOn + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + } + + id: runningList + clip: true + model: root.runningScriptsModel + delegate: ScriptDelegate {} + } + + Overte.Ruler { Layout.fillWidth: true } + + Overte.Label { + Layout.fillWidth: true + + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: qsTr("Add new script from...") + } + + RowLayout { + Layout.margins: 8 + Layout.fillHeight: true + + Overte.Button { + // force equal button widths + Layout.preferredWidth: 1 + Layout.fillWidth: true + + text: qsTr("File") + + onClicked: fileDialog.open() + } + + Overte.Button { + // force equal button widths + Layout.preferredWidth: 1 + Layout.fillWidth: true + + text: qsTr("URL") + + onClicked: addFromUrlDialog.open() + } + + Overte.Button { + // force equal button widths + Layout.preferredWidth: 1 + Layout.fillWidth: true + + text: qsTr("Built-in") + + onClicked: builtinDialog.open() + } + } + } + + Overte.Dialog { + id: addFromUrlDialog + anchors.fill: parent + maxWidth: -1 + + signal accepted + signal rejected + + onAccepted: { + ScriptDiscoveryService.loadScript(targetUrlField.text, !oneSessionSwitch.checked); + close(); + + targetUrlField.text = ""; + oneSessionSwitch.checked = false; + } + + onRejected: { + close(); + + targetUrlField.text = ""; + oneSessionSwitch.checked = false; + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: qsTr("Load script from URL") + } + Overte.Ruler { Layout.fillWidth: true } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: qsTr("Script URL") + id: targetUrlField + } + + Overte.Switch { + id: oneSessionSwitch + text: qsTr("Only for this session") + } + + RowLayout { + Layout.preferredWidth: 720 + Layout.fillWidth: true + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + text: qsTr("Cancel") + + onClicked: { + addFromUrlDialog.rejected(); + } + } + + Item { + Layout.preferredWidth: 1 + Layout.fillWidth: true + } + + Overte.Button { + Layout.fillWidth: true + Layout.preferredWidth: 1 + + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Load") + enabled: targetUrlField.text !== "" + + onClicked: { + addFromUrlDialog.accepted(); + } + } + } + } + } + + OverteDialogs.BuiltinScriptsDialog { + anchors.fill: parent + id: builtinDialog + + onAccepted: file => ScriptDiscoveryService.loadScript(file, true) + } + + OverteDialogs.FileDialog { + anchors.fill: parent + id: fileDialog + + nameFilters: ["*.js"] + + onAccepted: ScriptDiscoveryService.loadScript(fileDialog.selectedFile, true) + } +} diff --git a/interface/resources/qml/overte/dialogs/qmldir b/interface/resources/qml/overte/dialogs/qmldir new file mode 100644 index 00000000000..86450bd753a --- /dev/null +++ b/interface/resources/qml/overte/dialogs/qmldir @@ -0,0 +1,5 @@ +module Dialogs +FileDialog 1.0 FileDialog.qml +AssetDialog 1.0 AssetDialog.qml +RunningScriptsDialog 1.0 RunningScriptsDialog.qml +BuiltinScriptsDialog 1.0 BuiltinScriptsDialog.qml diff --git a/interface/resources/qml/overte/icons/add_friend.svg b/interface/resources/qml/overte/icons/add_friend.svg new file mode 100644 index 00000000000..3894d6a3b95 --- /dev/null +++ b/interface/resources/qml/overte/icons/add_friend.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/admin_shield.svg b/interface/resources/qml/overte/icons/admin_shield.svg new file mode 100644 index 00000000000..14dc66daab1 --- /dev/null +++ b/interface/resources/qml/overte/icons/admin_shield.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/arrow_up.svg b/interface/resources/qml/overte/icons/arrow_up.svg new file mode 100644 index 00000000000..b313e472a5c --- /dev/null +++ b/interface/resources/qml/overte/icons/arrow_up.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/broadcast.svg b/interface/resources/qml/overte/icons/broadcast.svg new file mode 100644 index 00000000000..e3887ffe945 --- /dev/null +++ b/interface/resources/qml/overte/icons/broadcast.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/close.svg b/interface/resources/qml/overte/icons/close.svg new file mode 100644 index 00000000000..c640a18e28d --- /dev/null +++ b/interface/resources/qml/overte/icons/close.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/copy.svg b/interface/resources/qml/overte/icons/copy.svg new file mode 100644 index 00000000000..98cde8781af --- /dev/null +++ b/interface/resources/qml/overte/icons/copy.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/delete.svg b/interface/resources/qml/overte/icons/delete.svg new file mode 100644 index 00000000000..26fd93f4e17 --- /dev/null +++ b/interface/resources/qml/overte/icons/delete.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/eye_closed.svg b/interface/resources/qml/overte/icons/eye_closed.svg new file mode 100644 index 00000000000..35905a61f5b --- /dev/null +++ b/interface/resources/qml/overte/icons/eye_closed.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/eye_open.svg b/interface/resources/qml/overte/icons/eye_open.svg new file mode 100644 index 00000000000..983636e21f7 --- /dev/null +++ b/interface/resources/qml/overte/icons/eye_open.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/filter.svg b/interface/resources/qml/overte/icons/filter.svg new file mode 100644 index 00000000000..75e22db7db6 --- /dev/null +++ b/interface/resources/qml/overte/icons/filter.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/folder.svg b/interface/resources/qml/overte/icons/folder.svg new file mode 100644 index 00000000000..6e1d56a35ce --- /dev/null +++ b/interface/resources/qml/overte/icons/folder.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/gold_star.svg b/interface/resources/qml/overte/icons/gold_star.svg new file mode 100644 index 00000000000..22cbc130ee8 --- /dev/null +++ b/interface/resources/qml/overte/icons/gold_star.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/home.svg b/interface/resources/qml/overte/icons/home.svg new file mode 100644 index 00000000000..f0f8acf355b --- /dev/null +++ b/interface/resources/qml/overte/icons/home.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/info.svg b/interface/resources/qml/overte/icons/info.svg new file mode 100644 index 00000000000..057d846de31 --- /dev/null +++ b/interface/resources/qml/overte/icons/info.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/pause.svg b/interface/resources/qml/overte/icons/pause.svg new file mode 100644 index 00000000000..aed337a41ef --- /dev/null +++ b/interface/resources/qml/overte/icons/pause.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/pencil.svg b/interface/resources/qml/overte/icons/pencil.svg new file mode 100644 index 00000000000..2882fb5b046 --- /dev/null +++ b/interface/resources/qml/overte/icons/pencil.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/plus.svg b/interface/resources/qml/overte/icons/plus.svg new file mode 100644 index 00000000000..e910fffc74d --- /dev/null +++ b/interface/resources/qml/overte/icons/plus.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/reload.svg b/interface/resources/qml/overte/icons/reload.svg new file mode 100644 index 00000000000..3c641fa6b4c --- /dev/null +++ b/interface/resources/qml/overte/icons/reload.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/remove_friend.svg b/interface/resources/qml/overte/icons/remove_friend.svg new file mode 100644 index 00000000000..1858c67f977 --- /dev/null +++ b/interface/resources/qml/overte/icons/remove_friend.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/search.svg b/interface/resources/qml/overte/icons/search.svg new file mode 100644 index 00000000000..dc72dcea553 --- /dev/null +++ b/interface/resources/qml/overte/icons/search.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/send.svg b/interface/resources/qml/overte/icons/send.svg new file mode 100644 index 00000000000..9d81595d392 --- /dev/null +++ b/interface/resources/qml/overte/icons/send.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/settings_cog.svg b/interface/resources/qml/overte/icons/settings_cog.svg new file mode 100644 index 00000000000..1662ccd361b --- /dev/null +++ b/interface/resources/qml/overte/icons/settings_cog.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/skip_backward.svg b/interface/resources/qml/overte/icons/skip_backward.svg new file mode 100644 index 00000000000..d8075f911c1 --- /dev/null +++ b/interface/resources/qml/overte/icons/skip_backward.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/skip_forward.svg b/interface/resources/qml/overte/icons/skip_forward.svg new file mode 100644 index 00000000000..c4696316862 --- /dev/null +++ b/interface/resources/qml/overte/icons/skip_forward.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/speaker_active.svg b/interface/resources/qml/overte/icons/speaker_active.svg new file mode 100644 index 00000000000..3f9a72c1118 --- /dev/null +++ b/interface/resources/qml/overte/icons/speaker_active.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/speaker_inactive.svg b/interface/resources/qml/overte/icons/speaker_inactive.svg new file mode 100644 index 00000000000..2ba23eb8023 --- /dev/null +++ b/interface/resources/qml/overte/icons/speaker_inactive.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/speaker_muted.svg b/interface/resources/qml/overte/icons/speaker_muted.svg new file mode 100644 index 00000000000..88baaa884cf --- /dev/null +++ b/interface/resources/qml/overte/icons/speaker_muted.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/triangle_down.svg b/interface/resources/qml/overte/icons/triangle_down.svg new file mode 100644 index 00000000000..be961ea6755 --- /dev/null +++ b/interface/resources/qml/overte/icons/triangle_down.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/triangle_left.svg b/interface/resources/qml/overte/icons/triangle_left.svg new file mode 100644 index 00000000000..400b2a50bdf --- /dev/null +++ b/interface/resources/qml/overte/icons/triangle_left.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/triangle_right.svg b/interface/resources/qml/overte/icons/triangle_right.svg new file mode 100644 index 00000000000..0c09d409d9b --- /dev/null +++ b/interface/resources/qml/overte/icons/triangle_right.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/triangle_up.svg b/interface/resources/qml/overte/icons/triangle_up.svg new file mode 100644 index 00000000000..4f683634316 --- /dev/null +++ b/interface/resources/qml/overte/icons/triangle_up.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/unset_avatar.svg b/interface/resources/qml/overte/icons/unset_avatar.svg new file mode 100644 index 00000000000..033a6abaf3b --- /dev/null +++ b/interface/resources/qml/overte/icons/unset_avatar.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons/users.svg b/interface/resources/qml/overte/icons/users.svg new file mode 100644 index 00000000000..ba42470f859 --- /dev/null +++ b/interface/resources/qml/overte/icons/users.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons_src/add_friend.svg b/interface/resources/qml/overte/icons_src/add_friend.svg new file mode 100644 index 00000000000..3894d6a3b95 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/add_friend.svg @@ -0,0 +1,2 @@ + + diff --git a/interface/resources/qml/overte/icons_src/admin_shield.svg b/interface/resources/qml/overte/icons_src/admin_shield.svg new file mode 100644 index 00000000000..1414c45e590 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/admin_shield.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/arrow_up.svg b/interface/resources/qml/overte/icons_src/arrow_up.svg new file mode 100644 index 00000000000..86a760fb64a --- /dev/null +++ b/interface/resources/qml/overte/icons_src/arrow_up.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/broadcast.svg b/interface/resources/qml/overte/icons_src/broadcast.svg new file mode 100644 index 00000000000..ea3f6b9f853 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/broadcast.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/close.svg b/interface/resources/qml/overte/icons_src/close.svg new file mode 100644 index 00000000000..a1fef407dc0 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/close.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/copy.svg b/interface/resources/qml/overte/icons_src/copy.svg new file mode 100644 index 00000000000..7c67bf09ee7 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/copy.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/delete.svg b/interface/resources/qml/overte/icons_src/delete.svg new file mode 100644 index 00000000000..1783ffb0565 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/delete.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/eye_closed.svg b/interface/resources/qml/overte/icons_src/eye_closed.svg new file mode 100644 index 00000000000..963d827da6a --- /dev/null +++ b/interface/resources/qml/overte/icons_src/eye_closed.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/eye_open.svg b/interface/resources/qml/overte/icons_src/eye_open.svg new file mode 100644 index 00000000000..d5988f287bc --- /dev/null +++ b/interface/resources/qml/overte/icons_src/eye_open.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/filter.svg b/interface/resources/qml/overte/icons_src/filter.svg new file mode 100644 index 00000000000..913041ad0d0 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/filter.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/folder.svg b/interface/resources/qml/overte/icons_src/folder.svg new file mode 100644 index 00000000000..f05c66fda90 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/folder.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/gold_star.svg b/interface/resources/qml/overte/icons_src/gold_star.svg new file mode 100644 index 00000000000..3cf28b19080 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/gold_star.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/home.svg b/interface/resources/qml/overte/icons_src/home.svg new file mode 100644 index 00000000000..bb60859c10f --- /dev/null +++ b/interface/resources/qml/overte/icons_src/home.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/info.svg b/interface/resources/qml/overte/icons_src/info.svg new file mode 100644 index 00000000000..fe836b5fb48 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/info.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/pause.svg b/interface/resources/qml/overte/icons_src/pause.svg new file mode 100644 index 00000000000..8e537ed0743 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/pause.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/pencil.svg b/interface/resources/qml/overte/icons_src/pencil.svg new file mode 100644 index 00000000000..fef919a80a6 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/pencil.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/plus.svg b/interface/resources/qml/overte/icons_src/plus.svg new file mode 100644 index 00000000000..74b09c41340 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/plus.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/reload.svg b/interface/resources/qml/overte/icons_src/reload.svg new file mode 100644 index 00000000000..8e315f2b86a --- /dev/null +++ b/interface/resources/qml/overte/icons_src/reload.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/remove_friend.svg b/interface/resources/qml/overte/icons_src/remove_friend.svg new file mode 100644 index 00000000000..d5906ccfb3d --- /dev/null +++ b/interface/resources/qml/overte/icons_src/remove_friend.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/search.svg b/interface/resources/qml/overte/icons_src/search.svg new file mode 100644 index 00000000000..b1a0037eb00 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/search.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/send.svg b/interface/resources/qml/overte/icons_src/send.svg new file mode 100644 index 00000000000..f6d42c4c67b --- /dev/null +++ b/interface/resources/qml/overte/icons_src/send.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/settings_cog.svg b/interface/resources/qml/overte/icons_src/settings_cog.svg new file mode 100644 index 00000000000..06f58ef8537 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/settings_cog.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/skip_backward.svg b/interface/resources/qml/overte/icons_src/skip_backward.svg new file mode 100644 index 00000000000..9ff33f128fc --- /dev/null +++ b/interface/resources/qml/overte/icons_src/skip_backward.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/skip_forward.svg b/interface/resources/qml/overte/icons_src/skip_forward.svg new file mode 100644 index 00000000000..92c5ac673c3 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/skip_forward.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/speaker.svg b/interface/resources/qml/overte/icons_src/speaker.svg new file mode 100644 index 00000000000..c45eb64b1ad --- /dev/null +++ b/interface/resources/qml/overte/icons_src/speaker.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/triangle_down.svg b/interface/resources/qml/overte/icons_src/triangle_down.svg new file mode 100644 index 00000000000..61077b34108 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/triangle_down.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/triangle_left.svg b/interface/resources/qml/overte/icons_src/triangle_left.svg new file mode 100644 index 00000000000..d5c80b69e90 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/triangle_left.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/triangle_right.svg b/interface/resources/qml/overte/icons_src/triangle_right.svg new file mode 100644 index 00000000000..5e81b99d186 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/triangle_right.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/triangle_up.svg b/interface/resources/qml/overte/icons_src/triangle_up.svg new file mode 100644 index 00000000000..ec54a2ae794 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/triangle_up.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/unset_avatar.svg b/interface/resources/qml/overte/icons_src/unset_avatar.svg new file mode 100644 index 00000000000..32efcc20c69 --- /dev/null +++ b/interface/resources/qml/overte/icons_src/unset_avatar.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/icons_src/users.svg b/interface/resources/qml/overte/icons_src/users.svg new file mode 100644 index 00000000000..68c2b0e27bc --- /dev/null +++ b/interface/resources/qml/overte/icons_src/users.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + diff --git a/interface/resources/qml/overte/more_apps/AppDelegate.qml b/interface/resources/qml/overte/more_apps/AppDelegate.qml new file mode 100644 index 00000000000..d2b1197d41d --- /dev/null +++ b/interface/resources/qml/overte/more_apps/AppDelegate.qml @@ -0,0 +1,229 @@ +import QtQuick +import QtQuick.Layouts + +import ".." as Overte + +Rectangle { + id: item + width: ListView.view.contentWidth + implicitHeight: column.implicitHeight + color: index % 2 === 0 ? Overte.Theme.paletteActive.base : Overte.Theme.paletteActive.alternateBase + + required property int index + + required property string name + required property string description + required property url icon + required property string author + required property string scriptUrl + required property string appID + required property string repoHost + + property bool running: moreApps.runningScripts.includes(scriptUrl) + property bool installed: moreApps.installedScripts.includes(scriptUrl) + property bool processing: false + + Connections { + target: moreApps + ignoreUnknownSignals: false + + function onRunningScriptsChanged() { + processing = false; + } + } + + ColumnLayout { + anchors.fill: parent + id: column + + RowLayout { + Layout.margins: 8 + Layout.fillWidth: true + + Overte.RoundButton { + id: dropdownButton + checkable: true + icon.source: checked ? "../icons/triangle_up.svg" : "../icons/triangle_down.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + } + + Rectangle { + Layout.preferredWidth: 64 + Layout.preferredHeight: 64 + color: Overte.Theme.paletteActive.appIconBackground + radius: Overte.Theme.borderRadius + + border.width: Math.max(2, Overte.Theme.borderWidth) + border.color: { + if (installed && running) { + return Overte.Theme.paletteActive.appInstalledRunning; + } else if (installed && !running) { + return Overte.Theme.paletteActive.appInstalledNotRunning; + } else if (!installed && running) { + return Overte.Theme.paletteActive.appNotInstalledRunning; + } else { + return Overte.Theme.paletteActive.appNotInstalled; + } + } + + Image { + anchors.fill: parent + anchors.margins: 8 + source: icon + sourceSize.width: width + sourceSize.height: height + } + } + + ColumnLayout { + Layout.fillWidth: true + + Overte.Label { + Layout.fillWidth: true + wrapMode: Text.Wrap + text: name + } + + Overte.Label { + Layout.fillWidth: true + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + visible: !dropdownButton.checked + elide: Text.ElideRight + text: description + } + + Overte.Label { + Layout.fillWidth: true + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + visible: dropdownButton.checked + wrapMode: Text.Wrap + text: { + if (running && installed) { + return qsTr("Running"); + } else if (running && !installed) { + return qsTr("Running, not installed"); + } else if (!running && installed) { + return qsTr("Paused"); + } else { + return ""; + } + } + } + } + + Overte.RoundButton { + visible: installed || running + enabled: !processing + icon.source: "../icons/delete.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + + onClicked: { + processing = true; + ScriptDiscoveryService.stopScript(scriptUrl); + + // only variable assignments are automatically tracked by Qt + const indexOf = moreApps.installedScripts.indexOf(scriptUrl); + moreApps.installedScripts.splice(indexOf); + moreApps.installedScriptsChanged(); + + moreApps.refreshRunningScripts(); + moreApps.refreshFilteredModel(); + } + } + + Overte.RoundButton { + enabled: !processing + visible: installed && running + icon.source: "../icons/reload.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + onClicked: ScriptDiscoveryService.stopScript(scriptUrl, true) + } + + Overte.RoundButton { + enabled: !processing + visible: installed + icon.source: running ? "../icons/pause.svg" : "../icons/triangle_right.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + onClicked: { + if (running) { + ScriptDiscoveryService.stopScript(scriptUrl, false); + } else { + ScriptDiscoveryService.loadScript(scriptUrl, false); + } + + processing = true; + moreApps.refreshRunningScripts(); + moreApps.refreshFilteredModel(); + } + } + + Overte.RoundButton { + id: installButton + enabled: !processing + visible: !installed + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + icon.source: "../icons/plus.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + processing = true; + ScriptDiscoveryService.loadScript(scriptUrl, false); + + // only variable assignments are automatically tracked by Qt + moreApps.installedScripts.push(scriptUrl); + moreApps.installedScriptsChanged(); + + moreApps.refreshRunningScripts(); + moreApps.refreshFilteredModel(); + } + } + } + + RowLayout { + Layout.leftMargin: 8 + Layout.rightMargin: 8 + Layout.fillWidth: true + visible: dropdownButton.checked + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + text: qsTr("By %1").arg(author) + } + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignRight + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.7 + text: `${appID} @ ${repoHost}` + } + } + + Overte.Label { + Layout.leftMargin: 8 + Layout.rightMargin: 8 + Layout.bottomMargin: 8 + Layout.fillWidth: true + visible: dropdownButton.checked + wrapMode: Text.Wrap + text: description + } + } +} diff --git a/interface/resources/qml/overte/more_apps/MoreApps.qml b/interface/resources/qml/overte/more_apps/MoreApps.qml new file mode 100644 index 00000000000..7adff94d1c9 --- /dev/null +++ b/interface/resources/qml/overte/more_apps/MoreApps.qml @@ -0,0 +1,468 @@ +import QtCore as QtCore +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import ".." as Overte +import "." + +Rectangle { + id: moreApps + implicitWidth: 480 + implicitHeight: 720 + color: Overte.Theme.paletteActive.base + + QtCore.Settings { + id: settings + category: "moreApp" + property list installedScripts: [] + property list repoSources: [] + } + + property alias installedScripts: settings.installedScripts + property alias repoSources: settings.repoSources + + property string searchExpression: ".*" + property list rawListModel: [] + property list filteredModel: [] + + property list runningScripts: [] + + // the running scripts list doesn't immediately update, so give it a bit to update + Timer { + id: runningScriptsRefreshTimer + running: false + repeat: false + interval: 500 + + onTriggered: { + runningScripts = ScriptDiscoveryService.getRunning().map(x => x.url); + } + } + + function refreshRunningScripts() { + runningScriptsRefreshTimer.start(); + } + + function refreshFilteredModel() { + const searchRegex = new RegExp(searchExpression, "i"); + let tmp = []; + + for (const item of rawListModel) { + // if onlyInstalled is checked and we're not running or installed, skip + if (onlyInstalled.checked) { + if ( + !runningScripts.includes(item.scriptUrl) && + !installedScripts.includes(item.scriptUrl) + ) { + continue; + } + } + + if ( + item.name.match(searchRegex) || + item.id.match(searchRegex) || + item.description.match(searchRegex) + ) { + tmp.push(item); + } + } + + tmp.sort((a, b) => ( + a.name.localeCompare(b.name) + )); + + filteredModel = tmp; + } + + onRawListModelChanged: refreshFilteredModel() + + function parseList(list, repo) { + if (list.version !== 2) { + console.warn(`App list "${list}" is version ${list.version}, expected 2`); + return; + } + const repoHost = (new URL(repo)).hostname; + + let tmp = []; + + for (const item of list.applicationList) { + if (!item.appActive) { continue; } + + const baseUrl = `${repo}/applications`; + const scriptUrl = `${baseUrl}/${item.appBaseDirectory}/${item.appScriptVersions.Stable}`; + + tmp.push({ + appID: item.appBaseDirectory, + name: item.appName, + description: item.appDescription, + scriptUrl: scriptUrl, + author: item.appAuthor, + icon: `${baseUrl}/${item.appBaseDirectory}/${item.appIcon}`, + repoHost: repoHost, + }); + } + + rawListModel = rawListModel.concat(tmp); + } + + property var pendingRequests: ({}) + + function fetchList(repo) { + let xhr = new XMLHttpRequest(); + + pendingRequests[repo] = { + abort: () => xhr.abort(), + expectedSize: 1, + currentSize: 0, + }; + + xhr.onreadystatechange = () => { + if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) { + const length = xhr.getResponseHeader("Content-Length"); + if (length !== "") { + pendingRequests[repo].expectedSize = Number(length); + } + } else if (xhr.readyState === XMLHttpRequest.LOADING) { + pendingRequests[repo].currentSize = xhr.response.length; + } else if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status !== 200) { + console.warn(repo, xhr.status, xhr.statusText); + downloadProgressLabel.updateText(); + delete pendingRequests[repo]; + pendingRequestsChanged(); + return; + } + + pendingRequests[repo].currentSize = xhr.response.length; + + try { + const data = JSON.parse(xhr.response); + parseList(data, repo); + } catch(e) { + console.error(repo, e); + } + + delete pendingRequests[repo]; + } + + downloadProgressLabel.updateText(); + pendingRequestsChanged(); + }; + + xhr.open("GET", `${repo}/applications/metadata.json`); + xhr.send(); + + pendingRequestsChanged(); + downloadProgressLabel.updateText(); + } + + function clearAllPendingRequests() { + for (const req of Object.values(pendingRequests)) { + req.abort(); + } + + pendingRequests = []; + } + + function fetchAllLists() { + // cancel any downloads that are already in-flight + // so we don't accidentally get two responses for the same repo + clearAllPendingRequests(); + + rawListModel = []; + filteredModel = []; + + for (const repo of repoSources) { + fetchList(repo); + } + } + + onRepoSourcesChanged: { + refreshRunningScripts(); + fetchAllLists(); + } + + Component.onCompleted: { + // don't put this in the default because it'll load + // the default first, *then* the actual repos stored + // in the settings. this way we don't double up on requests + if (repoSources.length === 0) { + repoSources.push("https://more.overte.org"); + } + } + + Component.onDestruction: { + // we're quitting, cancel any downloads that are already in-flight + // so they don't try to update items that have been destroyed + clearAllPendingRequests(); + } + + Component { + id: settingsPage + + ColumnLayout { + RowLayout { + Layout.fillWidth: true + + Overte.RoundButton { + icon.source: "../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + onClicked: stack.pop() + } + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Settings - More Apps") + } + } + + Item { + Layout.fillWidth: true + implicitHeight: 12 + } + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + text: qsTr("App Sources") + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + } + + Overte.Ruler { Layout.fillWidth: true } + + ListView { + Layout.fillWidth: true + + // QT6TODO: remove this when mouse inputs are working properly + interactive: false + + clip: true + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AlwaysOn + } + contentWidth: width - ScrollBar.vertical.width + + implicitHeight: (Overte.Theme.fontPixelSizeSmall * 3) * 6 + + model: moreApps.repoSources + delegate: Rectangle { + required property int index + readonly property var text: moreApps.repoSources[index] + + width: ListView.view.contentWidth + implicitHeight: Overte.Theme.fontPixelSizeSmall * 3 + color: index % 2 === 0 ? Overte.Theme.paletteActive.base : Overte.Theme.paletteActive.alternateBase + + Overte.Label { + anchors.margins: 4 + anchors.left: parent.left + anchors.right: sourceRemoveButton.right + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Overte.Theme.fontPixelSizeSmall + elide: Text.ElideRight + + // FIXME: shouldn't ever be undefined, but sometimes is anyway? + text: parent.text ?? "undefined" + } + + Overte.RoundButton { + id: sourceRemoveButton + anchors.margins: 4 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + backgroundColor: ( + (hovered || Overte.Theme.highContrast) ? + Overte.Theme.paletteActive.buttonDestructive : + Overte.Theme.paletteActive.button + ) + + horizontalPadding: 0 + verticalPadding: 0 + implicitWidth: 32 + implicitHeight: 32 + + icon.source: "../icons/close.svg" + icon.width: 18 + icon.height: 18 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + // FIXME: this throws an error about not being able to + // resolve "moreApps", but it seems to work fine anyway? + moreApps.repoSources.splice(index, 1) + moreApps.repoSourcesChanged() + } + } + } + } + + RowLayout { + Layout.fillWidth: true + + Overte.TextField { + Layout.fillWidth: true + + id: newSourceField + placeholderText: qsTr("App list source URL") + } + + Overte.RoundButton { + icon.source: "../icons/plus.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + enabled: !!newSourceField.text.match(/^https?:\/\/.+/i) + + onClicked: { + moreApps.repoSources.push(newSourceField.text.replace(/\/$/g, "")); + moreApps.repoSourcesChanged(); + newSourceField.text = ""; + } + } + } + + // spacer + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } + + Overte.StackView { + id: stack + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: downloadProgressLabel.top + + initialItem: ColumnLayout { + RowLayout { + Layout.margins: 4 + + Overte.RoundButton { + icon.source: "../icons/settings_cog.svg" + icon.width: 24 + icon.height: 24 + + onClicked: stack.push(settingsPage.createObject(stack)) + } + + Overte.RoundButton { + // TODO: is the eye icon acceptable here? it feels too vague to grok + icon.source: checked ? "../icons/eye_closed.svg" : "../icons/eye_open.svg" + icon.width: 24 + icon.height: 24 + + id: onlyInstalled + checkable: true + onToggled: refreshFilteredModel() + + backgroundColor: ( + checked ? + Overte.Theme.paletteActive.highlight : + Overte.Theme.paletteActive.button + ) + color: ( + checked ? + Overte.Theme.paletteActive.highlightedText : + Overte.Theme.paletteActive.buttonText + ) + + Overte.ToolTip { text: qsTr("Only show installed and running apps") } + } + + Overte.TextField { + Layout.fillWidth: true + placeholderText: qsTr("Search…") + id: searchField + + Keys.onEnterPressed: { + searchButton.clicked(); + forceActiveFocus(); + } + + Keys.onReturnPressed: { + searchButton.clicked(); + forceActiveFocus(); + } + } + + Overte.RoundButton { + icon.source: "../icons/search.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + id: searchButton + + onClicked: { + moreApps.searchExpression = searchField.text; + moreApps.refreshFilteredModel(); + } + } + } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Loading %n app source(s)…", "", repoSources.length) + visible: rawListModel.length === 0 + } + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + visible: rawListModel.length > 0 + clip: true + + // QT6TODO: broken mouse input, remove when that's fixed + interactive: false + + ScrollBar.vertical: Overte.ScrollBar {} + contentWidth: width - ScrollBar.vertical.width + + model: filteredModel + delegate: AppDelegate {} + } + } + } + + Overte.Label { + anchors.margins: 4 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + id: downloadProgressLabel + visible: Object.values(pendingRequests).length !== 0 + + function updateText() { + const requests = Object.values(pendingRequests); + + if (requests.length === 0) { + this.text = ""; + return; + } + + let accum = 0; + + for (const req of requests) { + accum = (req.currentSize / req.expectedSize); + } + + const percent = Math.round((accum / requests.length) * 100); + this.text = `${qsTr("Downloading…")} ${percent}%`; + } + } +} diff --git a/interface/resources/qml/overte/more_apps/qmldir b/interface/resources/qml/overte/more_apps/qmldir new file mode 100644 index 00000000000..31d350227ae --- /dev/null +++ b/interface/resources/qml/overte/more_apps/qmldir @@ -0,0 +1,3 @@ +module MoreApps +MoreApps 1.0 MoreApps.qml +AppDelegate 1.0 AppDelegate.qml diff --git a/interface/resources/qml/overte/place_picker/PlaceItem.qml b/interface/resources/qml/overte/place_picker/PlaceItem.qml new file mode 100644 index 00000000000..bdfcc20f433 --- /dev/null +++ b/interface/resources/qml/overte/place_picker/PlaceItem.qml @@ -0,0 +1,184 @@ +import QtQuick +import QtQuick.Layouts + +import ".." as Overte + +Rectangle { + id: item + color: compatible ? Overte.Theme.paletteActive.alternateBase : Overte.Theme.paletteActive.buttonDestructive + + implicitWidth: gridView.cellWidth + implicitHeight: gridView.cellHeight + + required property int index + readonly property var modelData: gridView.model[index] + + required property string name + readonly property string domainName: modelData.domain.name + readonly property url thumbnail: modelData.thumbnail ?? "" + readonly property bool compatible: modelData.compatibleProtocol ?? true + readonly property url placeUrl: `hifi://${name}${modelData.path}` + + readonly property int currentUsers: modelData.current_attendance ?? 0 + readonly property int maxUsers: { + const capacity = modelData.domain.capacity; + return (capacity !== 0) ? capacity : 9999; + } + + readonly property color textBackgroundColor: { + if (Overte.Theme.highContrast) { + return Overte.Theme.darkMode ? "black" : "white" + } else { + return Overte.Theme.darkMode ? "#d0000000" : "#e0ffffff" + } + } + + readonly property bool hovered: mouseArea.containsMouse || infoButton.hovered || joinButton.hovered + + Overte.Label { + anchors.margins: Overte.Theme.borderWidth + anchors.fill: item + visible: thumbnailImage.status !== Image.Ready + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: thumbnailImage.status === Image.Loading ? "Loading…" : "No icon" + } + + Image { + anchors.margins: Overte.Theme.borderWidth + anchors.fill: item + id: thumbnailImage + + source: thumbnail + sourceSize.width: width + sourceSize.height: height + fillMode: Image.PreserveAspectCrop + } + + Rectangle { + anchors.margins: Overte.Theme.borderWidth + anchors.top: item.top + anchors.left: item.left + + width: Math.min(titleText.implicitWidth + 8, item.width - (2 * item.border.width)) + height: Math.min(titleText.implicitHeight + 8, item.height - (2 * item.border.width)) + color: textBackgroundColor + + Overte.Label { + anchors.margins: 4 + anchors.fill: parent + + id: titleText + text: name + font.bold: true + font.pixelSize: Overte.Theme.fontPixelSizeSmall + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignTop + } + } + + Rectangle { + anchors.margins: Overte.Theme.borderWidth + anchors.bottom: item.bottom + anchors.left: item.left + + width: Math.min(userCountText.implicitWidth + 8, item.width - (2 * item.border.width)) + height: Math.min(userCountText.implicitHeight + 8, item.height - (2 * item.border.width)) + color: textBackgroundColor + + Overte.Label { + anchors.margins: 4 + anchors.fill: parent + + id: userCountText + text: { + if (maxUsers === 9999) { + return `${domainName}: ${currentUsers}`; + } else { + return `${domainName}: ${currentUsers}/${maxUsers}`; + } + } + color: { + if (currentUsers === 0) { + return Overte.Theme.paletteActive.userCountEmpty; + } else if (currentUsers < maxUsers) { + return Overte.Theme.paletteActive.userCountActive; + } else { + return Overte.Theme.paletteActive.userCountFull; + } + } + font.bold: true + font.pixelSize: Overte.Theme.fontPixelSizeXSmall + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignTop + elide: Text.ElideLeft + } + } + + MouseArea { + anchors.fill: item + hoverEnabled: true + propagateComposedEvents: true + id: mouseArea + } + + Overte.RoundButton { + anchors.margins: 4 + anchors.top: item.top + anchors.right: item.right + id: infoButton + + implicitWidth: 32 + implicitHeight: 32 + horizontalPadding: 0 + verticalPadding: 0 + + opacity: { + if (item.hovered) { + return Overte.Theme.highContrast || hovered ? 1.0 : 0.9; + } else { + return 0.0; + } + } + backgroundColor: Overte.Theme.paletteActive.buttonInfo + + icon.source: "../icons/info.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: infoDialog.open(index) + } + + Overte.RoundButton { + anchors.margins: 4 + anchors.bottom: item.bottom + anchors.right: item.right + id: joinButton + + implicitWidth: 40 + implicitHeight: 40 + horizontalPadding: 0 + verticalPadding: 0 + + enabled: item.compatible + visible: item.compatible + opacity: { + if (item.hovered) { + return Overte.Theme.highContrast || hovered ? 1.0 : 0.9; + } else { + return 0.0; + } + } + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + icon.source: "../icons/triangle_right.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: placePicker.goToLocation(placeUrl) + } +} diff --git a/interface/resources/qml/overte/place_picker/PlacePicker.qml b/interface/resources/qml/overte/place_picker/PlacePicker.qml new file mode 100644 index 00000000000..0cef61fe0fa --- /dev/null +++ b/interface/resources/qml/overte/place_picker/PlacePicker.qml @@ -0,0 +1,675 @@ +import QtCore as QtCore +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Dialogs as QtDialogs + +import "../" as Overte +import "." + +Rectangle { + id: placePicker + anchors.fill: parent + color: Overte.Theme.paletteActive.base + implicitWidth: 480 + implicitHeight: 720 + + property bool hasHomeButton: true + + readonly property string protocolSignature: WindowScriptingInterface.protocolSignature() + + QtCore.Settings { + id: filters + category: "placesApp" + property string searchExpression: ".*" + property bool includeIncompatible: false + property list maturity: [ + "everyone", + "teen", + "mature", + "adult", + "unrated", + ] + property list favoritedPlaceIds: [] + } + + function goBack() { + let cookie = Date.now() + Math.floor(Math.random() * (1000 - -1000) + -1000); + + sendToScript(JSON.stringify({ + action: "system:location_go_back", + data: { cookie: cookie }, + })); + } + + function goForward() { + let cookie = Date.now() + Math.floor(Math.random() * (1000 - -1000) + -1000); + + sendToScript(JSON.stringify({ + action: "system:location_go_forward", + data: { cookie: cookie }, + })); + } + + function goToLocation(path) { + let cookie = Date.now() + Math.floor(Math.random() * (1000 - -1000) + -1000); + + sendToScript(JSON.stringify({ + action: "system:location_go_to", + data: { + cookie: cookie, + path: path, + }, + })); + } + + // The mv.overte.org directory listing is about 300KiB + // and takes about 10 seconds to download. Is there something + // we could use to safely cache the last results and only refresh + // after a set period? + property list rawPlaces: [] + property real downloadProgress: 0.0 + + function delayedShuffleHash(x) { + const ONE_DAY_MS = 24 * 3600 * 1000; + const SHUFFLE_CYCLE_MS = 5 * ONE_DAY_MS; + + const FNV_OFFSET = 0x811c9dc5; + const FNV_PRIME = 0x01000193; + const ALL_32BIT = 0xffffffff; + + let hashAccum = (FNV_OFFSET + Math.floor(Date.now() / SHUFFLE_CYCLE_MS)) & ALL_32BIT; + for (let p of x) { + // not quite FNV-1a, because we're counting 32-bit codepoints rather than bytes + hashAccum ^= p; + hashAccum = (hashAccum * FNV_PRIME) & ALL_32BIT; + } + + return hashAccum; + } + + function filterPlaces() { + // TODO: federation support + const hostname = (new URL(AccountServices.metaverseServerURL)).hostname; + const searchExpression = new RegExp(filters.searchExpression, "i"); + const ONE_DAY_SECS = 60 * 60 * 24; + let tmp = []; + + for (let place of rawPlaces) { + const compatibleProtocol = place.domain.protocol_version === protocolSignature; + // ?status=active should filter out dead places already + //const recentHeartbeat = ((Date.now() - parseInt(place.domain.time_of_last_heartbeat_s)) / 1000) < ONE_DAY_SECS; + const filterName = Boolean(place.name.match(searchExpression)); + const filterDomain = Boolean(place.domain.name.match(searchExpression)); + const filterDesc = Boolean(place.description.match(searchExpression)); + const filterMaturity = filters.maturity.includes(place.maturity); + const filterHasUsers = !onlyShowActiveButton.checked || place.current_attendance > 0; + + if ( + (compatibleProtocol || filters.includeIncompatible) && + (filterName || filterDomain || filterDesc) && + filterMaturity && + filterHasUsers + ) { + place.directoryHost = hostname; + place.compatibleProtocol = compatibleProtocol; + tmp.push(place); + } + } + + tmp.sort((a, b) => ( + // if "show incompatible servers" is on, sort compatible ones first + ((b.compatibleProtocol ? 1 : 0) - (a.compatibleProtocol ? 1 : 0)) || + // sort favorited places up + ((filters.favoritedPlaceIds.includes(b.placeId) ? 1 : 0) - (filters.favoritedPlaceIds.includes(a.placeId) ? 1 : 0)) || + // prefer places with a thumbnail + ((b.thumbnail ? 1 : 0) - (a.thumbnail ? 1 : 0)) || + // random shuffle that's stable for a few days to mix things up + delayedShuffleHash(b.placeId) - delayedShuffleHash(a.placeId) + )); + + gridView.model = tmp; + } + + Component.onCompleted: { + let fileSize = 1; + let xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = () => { + if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) { + const length = xhr.getResponseHeader("Content-Length"); + if (length !== "") { fileSize = Number(length); } + } else if (xhr.readyState === XMLHttpRequest.LOADING) { + downloadProgress = xhr.response.length / fileSize; + } else if (xhr.readyState === XMLHttpRequest.DONE) { + console.debug("Finished downloading place list"); + downloadProgress = 1.0; + + try { + const body = JSON.parse(xhr.responseText); + rawPlaces = body.data.places; + filterPlaces(); + } catch (e) { + console.error(e); + } + } + }; + + console.debug("Downloading place list…"); + downloadProgress = 0.0; + + // TODO: federation support, multiple directory sources + xhr.open("GET", `${AccountServices.metaverseServerURL}/api/v1/places?status=online`); + xhr.send(); + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + RowLayout { + Layout.margins: 4 + + Overte.RoundButton { + visible: placePicker.hasHomeButton + + icon.source: "../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: placePicker.goBack() + } + + Overte.RoundButton { + visible: placePicker.hasHomeButton + + icon.source: "../icons/triangle_right.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: placePicker.goForward() + } + + Overte.RoundButton { + visible: placePicker.hasHomeButton + + icon.source: "../icons/home.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: placePicker.goToLocation(LocationBookmarks.getHomeLocationAddress()) + + Overte.ToolTip { text: qsTr("Go to Home bookmark") } + } + + Overte.TextField { + Layout.fillWidth: true + + id: searchField + placeholderText: qsTr("Search…") + + Keys.onEnterPressed: { + searchButton.click(); + forceActiveFocus(); + } + Keys.onReturnPressed: { + searchButton.click(); + forceActiveFocus(); + } + } + + Overte.RoundButton { + id: searchButton + icon.source: ( + searchField.text.match(/(?:hifi|https?|file):\/\//) ? + "../icons/send.svg" : + "../icons/search.svg" + ) + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + if (searchField.text.startsWith("hifi://")) { + placePicker.goToLocation(infoDialog.placeUrl); + searchField.text = ""; + } else { + filters.searchExpression = searchField.text === "" ? ".*" : searchField.text; + filterPlaces(); + } + } + } + + Overte.RoundButton { + id: onlyShowActiveButton + icon.source: "../icons/users.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + checkable: true + + Overte.ToolTip { text: qsTr("Only show places with users") } + + onClicked: filterPlaces() + } + + Overte.RoundButton { + id: filterButton + icon.source: "../icons/filter.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: filterDialog.open() + + Overte.ToolTip { text: qsTr("Search options") } + } + } + + Overte.TabBar { + Layout.fillWidth: true + id: tabBar + + Overte.TabButton { text: qsTr("Public") } + Overte.TabButton { text: qsTr("Bookmarks") } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + visible: rawPlaces.length === 0 + + Item { Layout.fillHeight: true } + + Overte.Label { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: qsTr("Loading…") + } + + Rectangle { + Layout.margins: 8 + Layout.leftMargin: 64 + Layout.rightMargin: 64 + Layout.fillWidth: true + + implicitWidth: 256 + implicitHeight: Overte.Theme.fontPixelSize + (Overte.Theme.borderWidth * 2) + color: Overte.Theme.paletteActive.base + border.color: Qt.darker(color, Overte.Theme.borderDarker) + border.width: Overte.Theme.borderWidth + radius: Overte.Theme.borderRadius + + Rectangle { + x: parent.border.width + y: parent.border.width + height: parent.height - (parent.border.width * 2) + width: downloadProgress * (parent.width - (parent.border.width * 2)) + radius: parent.radius - Overte.Theme.borderWidth + color: Overte.Theme.paletteActive.highlight + } + } + + Item { Layout.fillHeight: true } + } + + StackLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + GridView { + // QT6TODO: remove this once mouse inputs work properly + interactive: false + + id: gridView + visible: rawPlaces.length !== 0 + // fit two cells onto the default tablet + cellWidth: (480 - Overte.Theme.scrollbarWidth) / 2 + cellHeight: Math.floor(cellWidth * 0.6) + clip: true + + ScrollBar.vertical: Overte.ScrollBar {} + rightMargin: ScrollBar.vertical.width + + model: [] + delegate: PlaceItem {} + } + } + + RowLayout { + Layout.margins: 2 + Layout.fillWidth: true + + Overte.Label { + Layout.fillWidth: true + verticalAlignment: Text.AlignVCenter + text: ( + gridView.model.length !== 0 ? + qsTr("%1 place(s)").arg(gridView.model.length) : + "" + ) + } + + Overte.RoundButton { + id: settingsButton + icon.source: "../icons/settings_cog.svg" + icon.width: 24 + icon.height: 24 + + onClicked: console.error("TODO: settings") + visible: false + } + } + } + + Overte.Dialog { + id: filterDialog + visible: false + anchors.fill: placePicker + + function open() { + filterControlMaturityEveryone.checked = filters.maturity.includes("everyone"); + filterControlMaturityTeen.checked = filters.maturity.includes("teen"); + filterControlMaturityMature.checked = filters.maturity.includes("mature"); + filterControlMaturityAdult.checked = filters.maturity.includes("adult"); + filterControlIncludeIncompatible.checked = filters.includeIncompatible; + + visible = true; + opacity = Overte.Theme.reducedMotion ? 1 : 0; + } + + function accept() { + let maturityList = []; + + if (filterControlMaturityEveryone.checked) { + maturityList.push("everyone"); + } + + if (filterControlMaturityTeen.checked) { + maturityList.push("teen"); + } + + if (filterControlMaturityMature.checked) { + maturityList.push("mature"); + } + + if (filterControlMaturityAdult.checked) { + maturityList.push("adult"); + } + + // if everything is enabled or disabled, include unrated places too + if (maturityList.length === 0 || maturityList.length === 4) { + maturityList.push("unrated"); + } + + filters.includeIncompatible = filterControlIncludeIncompatible.checked; + filters.maturity = maturityList; + placePicker.filterPlaces(); + close(); + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + text: qsTr("Filters") + horizontalAlignment: Text.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + } + + Overte.Ruler { Layout.fillWidth: true } + + RowLayout { + Overte.Label { + Layout.fillWidth: true + text: qsTr("Maturity ratings") + } + + GridLayout { + Layout.alignment: Qt.AlignRight + columns: 2 + + Overte.Switch { + id: filterControlMaturityEveryone + text: qsTr("Everyone") + } + + Overte.Switch { + id: filterControlMaturityTeen + text: qsTr("Teen") + } + + Overte.Switch { + id: filterControlMaturityMature + text: qsTr("Mature") + } + + Overte.Switch { + id: filterControlMaturityAdult + text: qsTr("Adult") + } + } + } + + RowLayout { + Layout.fillWidth: true + + Overte.Label { + Layout.fillWidth: true + text: qsTr("Show incompatible servers") + } + + Overte.Switch { id: filterControlIncludeIncompatible } + } + + RowLayout { + Layout.preferredWidth: 480 + + Overte.Button { + Layout.preferredWidth: 1 + Layout.fillWidth: true + text: qsTr("Cancel") + onClicked: filterDialog.close() + } + + Item { Layout.fillWidth: true } + + Overte.Button { + Layout.preferredWidth: 1 + Layout.fillWidth: true + backgroundColor: Overte.Theme.paletteActive.buttonAdd + text: qsTr("Apply") + onClicked: filterDialog.accept() + } + } + } + } + + Overte.Dialog { + id: infoDialog + visible: false + anchors.fill: placePicker + + property string placeName: "" + property string placeDesc: "" + property string domainName: "" + property string directoryHost: "" + property int currentUsers: 0 + property int maxUsers: 0 + property list managers: [] + property url placeUrl: "" + property bool compatible: true + property string placeId: "" + + function open(index) { + const data = gridView.model[index]; + placeName = data.name; + domainName = data.domain.name; + placeDesc = data.description; + directoryHost = data.directoryHost; + compatible = data.compatibleProtocol; + + // ignore the redundant default place description + if ( + placeDesc === `A place in ${domainName}` || + placeDesc === `A place in ${placeName}` + ) { + placeDesc = ""; + } + + currentUsers = data.current_attendance; + maxUsers = data.domain.capacity; + managers = data.managers; + placeUrl = data.finalPlaceUrl ?? `hifi://${placeName}${data.path}`; + placeId = data.placeId; + + visible = true; + opacity = Overte.Theme.reducedMotion ? 1 : 0; + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 8 + + ColumnLayout { + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + Layout.fillWidth: true + + Overte.Label { + // leave space for the close button + Layout.rightMargin: 44 + Layout.fillWidth: true + font.bold: true + text: infoDialog.placeName + } + + Overte.Label { + // leave space for the close button + Layout.rightMargin: 44 + font.pixelSize: Overte.Theme.fontPixelSizeSmall + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + text: `${infoDialog.domainName} @ ${infoDialog.directoryHost}` + } + + Overte.Label { + Layout.fillWidth: true + wrapMode: Text.Wrap + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + font.pixelSize: Overte.Theme.fontPixelSizeSmall + text: qsTr("Managed by %1").arg(infoDialog.managers.join(", ")) + } + + Overte.Ruler { Layout.fillWidth: true } + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + wrapMode: Text.Wrap + font.pixelSize: Overte.Theme.fontPixelSizeSmall + text: infoDialog.placeDesc + } + } + + RowLayout { + implicitWidth: 480 + Layout.preferredWidth: 480 + Layout.fillWidth: true + + Overte.Button { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 1 + text: qsTr("Copy URL") + onClicked: WindowScriptingInterface.copyToClipboard(infoDialog.placeUrl) + } + + Overte.Button { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 1 + backgroundColor: Overte.Theme.paletteActive.buttonInfo + enabled: infoDialog.compatible + text: qsTr("Portal") + onClicked: { + infoDialog.close(); + Messages.sendMessage("org.overte.PlacePortal.Create", JSON.stringify({ + place_name: infoDialog.placeName, + place_url: infoDialog.placeUrl, + })); + } + } + + Overte.Button { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 1 + backgroundColor: Overte.Theme.paletteActive.buttonAdd + enabled: infoDialog.compatible + text: infoDialog.compatible ? qsTr("Join") : qsTr("Incompatible") + onClicked: { + infoDialog.close(); + placePicker.goToLocation(infoDialog.placeUrl); + } + } + } + } + + Row { + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: 8 + spacing: 4 + + Overte.RoundButton { + implicitWidth: 28 + implicitHeight: 28 + + icon.source: "../icons/gold_star.svg" + icon.width: 20 + icon.height: 20 + icon.color: ( + checked ? + Overte.Theme.paletteActive.buttonText : + Overte.Theme.paletteActive.placeholderText + ) + + backgroundColor: checked ? Overte.Theme.paletteActive.buttonFavorite : Overte.Theme.paletteActive.button + checkable: true + checked: filters.favoritedPlaceIds.includes(infoDialog.placeId) + + onToggled: { + if (!checked) { + const index = filters.favoritedPlaceIds.indexOf(infoDialog.placeId); + filters.favoritedPlaceIds.splice(index); + } else { + filters.favoritedPlaceIds.push(infoDialog.placeId); + } + + filterPlaces(); + } + + Overte.ToolTip { text: qsTr("Favorite\nSorts this place before unfavorited places.") } + } + + Overte.RoundButton { + implicitWidth: 28 + implicitHeight: 28 + + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + + icon.source: "../icons/close.svg" + icon.width: 18 + icon.height: 18 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: infoDialog.close() + } + } + } +} diff --git a/interface/resources/qml/overte/place_picker/qmldir b/interface/resources/qml/overte/place_picker/qmldir new file mode 100644 index 00000000000..5b37f768aef --- /dev/null +++ b/interface/resources/qml/overte/place_picker/qmldir @@ -0,0 +1,3 @@ +module PlacePicker +PlacePicker 1.0 PlacePicker.qml +PlaceItem 1.0 PlaceItem.qml diff --git a/interface/resources/qml/overte/qmldir b/interface/resources/qml/overte/qmldir new file mode 100644 index 00000000000..f5e84c0e293 --- /dev/null +++ b/interface/resources/qml/overte/qmldir @@ -0,0 +1,19 @@ +module Overte +singleton Theme 1.0 Theme.qml +Button 1.0 Button.qml +TextField 1.0 TextField.qml +Switch 1.0 Switch.qml +TabBar 1.0 TabBar.qml +TabButton 1.0 TabButton.qml +Label 1.0 Label.qml +AppButton 1.0 AppButton.qml +RoundButton 1.0 RoundButton.qml +ScrollBar 1.0 ScrollBar.qml +ToolTip 1.0 ToolTip.qml +NodeGraph 1.0 NodeGraph.qml +Node 1.0 Node.qml +FileDialog 1.0 FileDialog.qml +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +BodyText 1.0 BodyText.qml +StackView 1.0 StackView.qml diff --git a/interface/resources/qml/overte/settings/ComboSetting.qml b/interface/resources/qml/overte/settings/ComboSetting.qml new file mode 100644 index 00000000000..467aa35cda0 --- /dev/null +++ b/interface/resources/qml/overte/settings/ComboSetting.qml @@ -0,0 +1,37 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../" as Overte + +RowLayout { + property alias text: labelItem.text + property alias model: comboItem.model + property alias textRole: comboItem.textRole + property alias valueRole: comboItem.valueRole + property alias currentIndex: comboItem.currentIndex + property alias enabled: comboItem.enabled + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 16 + + Overte.Label { + // equally sized items + Layout.preferredWidth: 1 + Layout.fillWidth: true + + id: labelItem + wrapMode: Text.Wrap + } + + Overte.ComboBox { + // equally sized items + Layout.preferredWidth: 1 + Layout.fillWidth: true + + id: comboItem + } +} diff --git a/interface/resources/qml/overte/settings/FolderSetting.qml b/interface/resources/qml/overte/settings/FolderSetting.qml new file mode 100644 index 00000000000..dbf7001c290 --- /dev/null +++ b/interface/resources/qml/overte/settings/FolderSetting.qml @@ -0,0 +1,49 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte +import "../dialogs" as OverteDialogs + +ColumnLayout { + property alias text: labelItem.text + property alias value: textFieldItem.text + property bool enabled: true + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 4 + + Overte.Label { + Layout.alignment: Qt.AlignBottom + id: labelItem + wrapMode: Text.Wrap + } + + RowLayout { + Layout.fillWidth: true + + Overte.TextField { + Layout.fillWidth: true + + id: textFieldItem + enabled: item.enabled + } + + Overte.RoundButton { + enabled: item.enabled + + icon.source: "../icons/folder.svg" + icon.width: 24 + icon.height: 24 + + onClicked: settingsRoot.openFolderPicker( + folder => { + value = folder; + }, + value + ); + } + } +} diff --git a/interface/resources/qml/overte/settings/Header.qml b/interface/resources/qml/overte/settings/Header.qml new file mode 100644 index 00000000000..e5e5e9901c7 --- /dev/null +++ b/interface/resources/qml/overte/settings/Header.qml @@ -0,0 +1,27 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte + +ColumnLayout { + property alias text: labelItem.text + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 2 + height: Overte.Theme.fontPixelSize * 3 + + Overte.Label { + id: labelItem + Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + opacity: Overte.Theme.highContrast ? 1.0 : 0.6 + wrapMode: Text.Wrap + } + + Overte.Ruler { + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + } +} diff --git a/interface/resources/qml/overte/settings/SettingNote.qml b/interface/resources/qml/overte/settings/SettingNote.qml new file mode 100644 index 00000000000..4844b6af065 --- /dev/null +++ b/interface/resources/qml/overte/settings/SettingNote.qml @@ -0,0 +1,13 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte + +Overte.Label { + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + wrapMode: Text.Wrap + font.pixelSize: Overte.Theme.fontPixelSizeSmall +} diff --git a/interface/resources/qml/overte/settings/Settings.qml b/interface/resources/qml/overte/settings/Settings.qml new file mode 100644 index 00000000000..b69937cf422 --- /dev/null +++ b/interface/resources/qml/overte/settings/Settings.qml @@ -0,0 +1,71 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +import "../" as Overte +import "." as OverteSettings +import "./pages" as SettingsPages +import "../dialogs" as OverteDialogs + +Rectangle { + id: settingsRoot + width: 480 + height: 720 + visible: true + anchors.fill: parent + color: Overte.Theme.paletteActive.base + + Overte.TabBar { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + id: tabBar + + Overte.TabButton { text: qsTr("General") } + Overte.TabButton { text: qsTr("Graphics") } + Overte.TabButton { text: qsTr("Controls") } + Overte.TabButton { text: qsTr("Audio") } + } + + StackLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: tabBar.bottom + anchors.bottom: parent.bottom + anchors.topMargin: Overte.Theme.fontPixelSize + currentIndex: tabBar.currentIndex + + SettingsPages.General {} + + SettingsPages.Graphics {} + + SettingsPages.Controls {} + + SettingsPages.Audio {} + } + + OverteDialogs.FileDialog { + anchors.fill: settingsRoot + visible: false + + id: folderDialog + + property var acceptedCallback: folder => {} + fileMode: OverteDialogs.FileDialog.OpenFolder + + onAccepted: { + acceptedCallback(new URL(folderDialog.selectedFile).pathname); + close(); + } + + onRejected: close() + } + + function openFolderPicker(callback, root) { + folderDialog.acceptedCallback = callback; + if (root) { + folderDialog.currentFolder = `file://${root}`; + } + folderDialog.open(); + } +} diff --git a/interface/resources/qml/overte/settings/SettingsPage.qml b/interface/resources/qml/overte/settings/SettingsPage.qml new file mode 100644 index 00000000000..9ce3826428c --- /dev/null +++ b/interface/resources/qml/overte/settings/SettingsPage.qml @@ -0,0 +1,23 @@ +import QtQuick +import QtQuick.Controls + +import "../" as Overte + +ScrollView { + default property alias children: column.children + + ScrollBar.vertical: Overte.ScrollBar { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + policy: ScrollBar.AsNeeded + } + contentWidth: width - ScrollBar.vertical.width + + Column { + id: column + anchors.fill: parent + spacing: 8 + padding: 16 + } +} diff --git a/interface/resources/qml/overte/settings/SliderSetting.qml b/interface/resources/qml/overte/settings/SliderSetting.qml new file mode 100644 index 00000000000..da70e463cfe --- /dev/null +++ b/interface/resources/qml/overte/settings/SliderSetting.qml @@ -0,0 +1,76 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../" as Overte + +ColumnLayout { + property alias text: labelItem.text + property alias value: sliderItem.value + property alias from: sliderItem.from + property alias to: sliderItem.to + property alias stepSize: sliderItem.stepSize + property alias enabled: sliderItem.enabled + property string valueText: valueToText() + property bool fineTweakButtons: false + + property var valueToText: () => value.toString() + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 16 + + RowLayout { + Overte.Label { + Layout.fillWidth: true + + id: labelItem + wrapMode: Text.Wrap + } + + Overte.Label { + text: valueText + wrapMode: Text.Wrap + } + } + + RowLayout { + Overte.RoundButton { + visible: fineTweakButtons + + icon.width: 24 + icon.height: 24 + icon.source: "../icons/triangle_left.svg" + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + sliderItem.value -= item.stepSize; + } + } + + Overte.Slider { + Layout.fillWidth: true + + id: sliderItem + snapMode: Slider.SnapAlways + } + + Overte.RoundButton { + visible: fineTweakButtons + + icon.width: 24 + icon.height: 24 + icon.source: "../icons/triangle_right.svg" + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + sliderItem.value += item.stepSize; + } + } + } + + // an extra spacer so the slider doesn't crowd with the setting below + Item {} +} diff --git a/interface/resources/qml/overte/settings/SpinBoxSetting.qml b/interface/resources/qml/overte/settings/SpinBoxSetting.qml new file mode 100644 index 00000000000..afe9fb1e922 --- /dev/null +++ b/interface/resources/qml/overte/settings/SpinBoxSetting.qml @@ -0,0 +1,34 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../" as Overte + +RowLayout { + property alias text: labelItem.text + property alias value: spinboxItem.value + property alias from: spinboxItem.from + property alias to: spinboxItem.to + property alias enabled: spinboxItem.enabled + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 16 + + Overte.Label { + // equally sized items + Layout.preferredWidth: 1 + Layout.fillWidth: true + + id: labelItem + wrapMode: Text.Wrap + } + + Overte.SpinBox { + Layout.alignment: Qt.AlignRight + + id: spinboxItem + } +} diff --git a/interface/resources/qml/overte/settings/SwitchSetting.qml b/interface/resources/qml/overte/settings/SwitchSetting.qml new file mode 100644 index 00000000000..3d928cf80fa --- /dev/null +++ b/interface/resources/qml/overte/settings/SwitchSetting.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte + +RowLayout { + property alias text: labelItem.text + property alias value: switchItem.checked + property bool enabled: true + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 16 + + Overte.Label { + Layout.fillWidth: true + + id: labelItem + wrapMode: Text.Wrap + } + + Overte.Switch { + id: switchItem + enabled: item.enabled + } +} diff --git a/interface/resources/qml/overte/settings/WideComboSetting.qml b/interface/resources/qml/overte/settings/WideComboSetting.qml new file mode 100644 index 00000000000..15490ba2c6d --- /dev/null +++ b/interface/resources/qml/overte/settings/WideComboSetting.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../" as Overte + +ColumnLayout { + property alias text: labelItem.text + property alias model: comboItem.model + property alias textRole: comboItem.textRole + property alias valueRole: comboItem.valueRole + property alias currentIndex: comboItem.currentIndex + property alias enabled: comboItem.enabled + + id: item + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 16 + spacing: 4 + + Overte.Label { + Layout.fillWidth: true + + id: labelItem + } + + Overte.ComboBox { + Layout.fillWidth: true + + id: comboItem + font.pixelSize: Overte.Theme.fontPixelSizeSmall + } +} diff --git a/interface/resources/qml/overte/settings/pages/Audio.qml b/interface/resources/qml/overte/settings/pages/Audio.qml new file mode 100644 index 00000000000..0d8c8affe1a --- /dev/null +++ b/interface/resources/qml/overte/settings/pages/Audio.qml @@ -0,0 +1,64 @@ +import "../../" as Overte +import "../" + +SettingsPage { + SwitchSetting { + text: "Mute Microphone" + + value: AudioScriptingInterface.muted + onValueChanged: AudioScriptingInterface.muted = value + } + + SwitchSetting { + text: "Push-to-Talk" + + value: AudioScriptingInterface.pushToTalk + onValueChanged: AudioScriptingInterface.pushToTalk = value + } + + SettingNote { + text: "Push [T] or squeeze both controller grips to talk." + } + + Header { text: qsTr("Audio Devices") } + + WideComboSetting { + text: "Output Device" + model: { + let tmp = []; + const source = AudioScriptingInterface.devices.output; + + for (let i = 0; i < source.rowCount(); i++) { + tmp.push(source.data(source.index(i, 0), /* DeviceNameRole */ 0x100)); + } + + return tmp; + } + + // TODO: how do these work??? + //currentIndex: 0 + //onCurrentIndexChanged: AudioScriptingInterface.setOutputDevice(currentIndex, false) + } + + WideComboSetting { + text: "Input Device" + model: { + let tmp = []; + const source = AudioScriptingInterface.devices.input; + + for (let i = 0; i < source.rowCount(); i++) { + tmp.push(source.data(source.index(i, 0), /* DeviceNameRole */ 0x100)); + } + + return tmp; + } + + // TODO: how do these work??? + //currentIndex: 0 + //onCurrentIndexChanged: AudioScriptingInterface.setInputDevice(currentIndex, false) + } + + SettingNote { + text: qsTr("Most VR runtimes will automatically switch the default audio devices to your headset.") + } +} diff --git a/interface/resources/qml/overte/settings/pages/Controls.qml b/interface/resources/qml/overte/settings/pages/Controls.qml new file mode 100644 index 00000000000..6b80c57d7fa --- /dev/null +++ b/interface/resources/qml/overte/settings/pages/Controls.qml @@ -0,0 +1,210 @@ +import "../../" as Overte +import "../" + +// NOTE: There's a lot of "x depends on non-bindable properties" warnings, +// there's not much that can be done about them and I don't think there's +// a way of explicitly telling QML to not try binding to stuff. +SettingsPage { + Header { + text: qsTr("Desktop") + + // Hack to reduce the dead space on the top of the page + height: implicitHeight + } + + SwitchSetting { + id: invertMouseY + text: qsTr("Invert Y") + + value: MyAvatar.pitchSpeed < 0 + onValueChanged: { + MyAvatar.pitchSpeed = mouseSensitivity.value * (value ? -75 : 75); + } + } + + SliderSetting { + id: mouseSensitivity + text: qsTr("Mouse Sensitivity") + stepSize: 0.1 + from: 0.1 + to: 5.0 + valueToText: () => `${value.toLocaleString()}`; + + value: MyAvatar.yawSpeed / 75 + onValueChanged: { + MyAvatar.yawSpeed = value * 75; + MyAvatar.pitchSpeed = value * (invertMouseY.value ? -75 : 75); + } + } + + Header { text: qsTr("VR User") } + + SliderSetting { + text: qsTr("Height") + fineTweakButtons: true + stepSize: 0.01 + from: 0.8 + to: 2.5 + + valueToText: () => { + let meters = value.toLocaleString(); + let totalInches = Math.round(value * 39.37008); + + let feet = Math.floor(totalInches / 12); + let inches = totalInches % 12; + + return `${feet}'${inches}" ${meters.toLocaleString()}m`; + } + + value: MyAvatar.userHeight + onValueChanged: MyAvatar.userHeight = value + } + + ComboSetting { + text: qsTr("Dominant Hand") + model: [ + qsTr("Left"), + qsTr("Right"), + ] + + currentIndex: MyAvatar.getDominantHand() === "left" ? 0 : 1 + onCurrentIndexChanged: MyAvatar.setDominantHand(currentIndex === 0 ? "left" : "right") + } + + SwitchSetting { + text: qsTr("Seated Mode") + value: MyAvatar.userRecenterModel === MyAvatar.ForceSit + onValueChanged: { + MyAvatar.userRecenterModel = value ? MyAvatar.ForceSit : MyAvatar.ForceStand; + } + } + + Header { text: qsTr("VR Movement") } + + SliderSetting { + text: qsTr("Turning Speed") + stepSize: 10 + from: 40 + to: 400 + valueToText: () => value < 50 ? qsTr("Snap turning") : `${value.toLocaleString()}`; + + value: MyAvatar.hmdYawSpeed + onValueChanged: { + MyAvatar.setSnapTurn(value < 50); + MyAvatar.HMDYawSpeed = value; + } + } + + SliderSetting { + id: walkingSpeed + text: qsTr("Walking Speed") + stepSize: 0.5 + from: 1.0 + to: 9 + valueToText: () => value < 1.5 ? qsTr("Teleport Only") : `${value.toLocaleString()} m/s`; + //enabled: !useAvatarDefaultWalkingSpeed.value + + // QT6TODO: change to vrWalkSpeed when we rebase on master + value: MyAvatar.analogPlusWalkSpeed + onValueChanged: { + if (value === 0.0) { + MyAvatar.useAdvancedMovementControls = false; + } else { + MyAvatar.useAdvancedMovementControls = true; + MyAvatar.analogPlusWalkSpeed = value; + } + } + } + + ComboSetting { + text: qsTr("Movement Relative To") + enabled: walkingSpeed.value >= 1.5 + model: [ + qsTr("Head"), + qsTr("Hand"), + ] + + currentIndex: MyAvatar.getMovementReference() + onCurrentIndexChanged: MyAvatar.setMovementReference(currentIndex) + } + + /*SwitchSetting { + id: useAvatarDefaultWalkingSpeed + text: qsTr("Use equipped avatar's default walking speed if available") + + // TODO + value: false + }*/ + + Header { text: qsTr("VR UI") } + + ComboSetting { + text: qsTr("Tablet Input") + + // keep this in the same order as MyAvatar.TabletInputMode + model: [ + qsTr("Laser"), + qsTr("Stylus"), + qsTr("Finger Touch"), + ] + + currentIndex: MyAvatar.tabletInputMode + onCurrentIndexChanged: MyAvatar.tabletInputMode = currentIndex; + } + + ComboSetting { + text: qsTr("Virtual Keyboard Input") + model: [ + qsTr("Lasers"), + qsTr("Mallets"), + ] + + currentIndex: KeyboardScriptingInterface.preferMalletsOverLasers ? 1 : 0 + onCurrentIndexChanged: { + KeyboardScriptingInterface.preferMalletsOverLasers = currentIndex == 1; + } + } + + SliderSetting { + text: qsTr("Laser Smoothing Delay") + stepSize: 0.05 + from: 0.0 + to: 2.0 + valueToText: () => `${value.toLocaleString()}s`; + + value: PickScriptingInterface.handLaserDelay + onValueChanged: PickScriptingInterface.handLaserDelay = value + } + + // for later, once the gesture scripts are stable and merged + /* + Header { text: qsTr("VR Gestures") } + + SwitchSetting { + text: qsTr("Take Photo") + value: true + } + + SettingNote { + text: qsTr("Double-click the trigger on your dominant hand near your ear to take a photo, or hold the trigger to take an animated screenshot.") + } + + SwitchSetting { + text: qsTr("Laser Toggle") + value: true + } + + SettingNote { + text: qsTr("Click both triggers with your hands behind your head to toggle the interaction lasers.") + } + + SwitchSetting { + text: qsTr("Seated Mode Toggle") + value: true + } + + SettingNote { + text: qsTr("Double-tap the controller grip on your non-dominant hand near your ear to switch between seated and standing mode.") + } + */ +} diff --git a/interface/resources/qml/overte/settings/pages/General.qml b/interface/resources/qml/overte/settings/pages/General.qml new file mode 100644 index 00000000000..e23139cb223 --- /dev/null +++ b/interface/resources/qml/overte/settings/pages/General.qml @@ -0,0 +1,197 @@ +import "../../" as Overte +import "../" + +SettingsPage { + id: page + + Header { + text: qsTr("UI") + + // Hack to reduce the dead space on the top of the page + height: implicitHeight + } + + ComboSetting { + text: qsTr("Color Scheme") + model: [ + qsTr("Dark"), + qsTr("Light"), + qsTr("System"), + ] + + currentIndex: { + if (Overte.Theme.useSystemColorScheme) { + return 2; + } else if (Overte.Theme.darkMode) { + return 0; + } else { + return 1; + } + } + + onCurrentIndexChanged: { + switch (currentIndex) { + case 0: + Overte.Theme.useSystemColorScheme = false; + Overte.Theme.darkMode = true; + break; + + case 1: + Overte.Theme.useSystemColorScheme = false; + Overte.Theme.darkMode = false; + break; + + case 2: + Overte.Theme.useSystemColorScheme = true; + Overte.Theme.darkMode = true; + break; + } + } + } + + ComboSetting { + text: qsTr("Contrast") + model: [ + qsTr("Standard"), + qsTr("High"), + qsTr("System"), + ] + + currentIndex: { + if (Overte.Theme.useSystemContrastMode) { + return 2; + } else if (Overte.Theme.highContrast) { + return 1; + } else { + return 0; + } + } + + onCurrentIndexChanged: { + switch (currentIndex) { + case 0: + Overte.useSystemContrastMode = false; + Overte.Theme.highContrast = false; + break; + + case 1: + Overte.useSystemContrastMode = false; + Overte.Theme.highContrast = true; + break; + + case 2: + Overte.useSystemContrastMode = true; + Overte.Theme.highContrast = false; + break; + } + } + } + + SwitchSetting { + text: qsTr("Reduced Motion") + value: Overte.Theme.reducedMotion + onValueChanged: () => Overte.Theme.reducedMotion = value + } + + SettingNote { + text: qsTr("This setting will disable UI animations that slide or scale.") + } + + ComboSetting { + text: qsTr("Avatar Nametags") + textRole: "text" + valueRole: "value" + model: [ + { text: qsTr("Never "), value: "off" }, + { text: qsTr("When clicked"), value: "on" }, + { text: qsTr("Always"), value: "alwaysOn" }, + ] + + currentIndex: { + const setting = SettingsInterface.getValue("simplifiedNametag/avatarNametagMode", "on"); + switch (setting) { + case "off": return 0; + case "on": return 1; + case "alwaysOn": return 2; + } + } + + onCurrentIndexChanged: SettingsInterface.setValue("simplifiedNametag/avatarNametagMode", model[currentIndex].value) + } + + SliderSetting { + text: qsTr("VR Tablet Scale") + stepSize: 5 + from: 50 + to: 150 + valueToText: () => `${value}%` + + value: SettingsInterface.getValue("hmdTabletScale", 75) + onValueChanged: SettingsInterface.setValue("hmdTabletScale", value) + } + + Header { text: qsTr("Screenshots") } + + FolderSetting { + text: qsTr("Folder") + value: Snapshot.getSnapshotsLocation() + onValueChanged: Snapshot.setSnapshotsLocation(value) + } + + ComboSetting { + text: qsTr("Format") + model: [ + "png", + "jpg", + "webp", + ] + + currentIndex: { + let current = Snapshot.getSnapshotFormat(); + for (let i in model) { + if (model[i] === current) { return i; } + } + return 0; + } + onCurrentIndexChanged: Snapshot.setSnapshotFormat(model[currentIndex]) + } + + SpinBoxSetting { + text: qsTr("Animation Duration") + from: 1 + to: 30 + + value: SettingsInterface.getValue("snapshotAnimatedDuration", 3) + onValueChanged: SettingsInterface.setValue("snapshotAnimatedDuration", value) + } + + SettingNote { + text: "Animated screenshots are saved as GIFs." + } + + Header { text: qsTr("Privacy") } + + SwitchSetting { + text: qsTr("Send Crash Reports") + + // FIXME: MenuScriptingInterface is super cursed, we shouldn't be relying on + // the *names* of the menu items to access them, especially once they're translated. + // Why are these even menu items in the first place? + value: MenuInterface.isOptionChecked("Enable Crash Reporting") + onValueChanged: MenuInterface.setIsOptionChecked("Enable Crash Reporting", value) + } + + SettingNote { + text: qsTr("Sending crash reports helps Overte development.") + } + + SwitchSetting { + text: qsTr("Discord Rich Presence") + value: SettingsInterface.getValue("useDiscordPresence", true) + onValueChanged: SettingsInterface.setValue("useDiscordPresence", value) + } + + SettingNote { + text: qsTr("If this setting is enabled, your current world will be shown on your Discord profile.") + } +} diff --git a/interface/resources/qml/overte/settings/pages/Graphics.qml b/interface/resources/qml/overte/settings/pages/Graphics.qml new file mode 100644 index 00000000000..6333cef4a2a --- /dev/null +++ b/interface/resources/qml/overte/settings/pages/Graphics.qml @@ -0,0 +1,203 @@ +import "../../" as Overte +import "../" + +SettingsPage { + SliderSetting { + text: qsTr("Field of View") + stepSize: 5 + from: 20 + to: 130 + valueToText: () => `${value}°`; + + value: Render.getVerticalFieldOfView() + onValueChanged: Render.setVerticalFieldOfView(value) + } + + SliderSetting { + text: qsTr("Resolution Scale") + stepSize: 10 + from: 10 + to: 200 + valueToText: () => `${value}%`; + + value: Render.viewportResolutionScale * 100 + onValueChanged: Render.viewportResolutionScale = value / 100 + } + + ComboSetting { + enabled: advRenderingEnabled.value + + text: qsTr("Anti-Aliasing") + + model: [ + // TODO: separate none and MSAA? + // RenderMainView.PreparePrimaryBufferForward.numSamples is a massive hack + advRenderingEnabled.value ? qsTr("None") : qsTr("4x MSAA"), + qsTr("TAA"), + qsTr("FXAA"), + ] + + currentIndex: advRenderingEnabled.value ? Render.getAntialiasingMode() : 0 + onCurrentIndexChanged: Render.setAntialiasingMode(currentIndex) + } + + ComboSetting { + text: qsTr("Level-of-Detail") + textRole: "text" + valueRole: "mode" + + model: [ + { text: qsTr("High"), mode: 0 }, + { text: qsTr("Medium"), mode: 1 }, + { text: qsTr("Low"), mode: 2 }, + ] + + currentIndex: LODManager.worldDetailQuality + onCurrentIndexChanged: LODManager.worldDetailQuality = model[currentIndex].mode + } + + SwitchSetting { + text: qsTr("Custom Shaders") + + value: Render.proceduralMaterialsEnabled + onValueChanged: Render.proceduralMaterialsEnabled = value + } + + SwitchSetting { + text: qsTr("Allow third-person camera to pass through walls") + + value: !Render.getCameraClippingEnabled() + onValueChanged: !Render.setCameraClippingEnabled(value) + } + + Header { text: qsTr("Advanced") } + + SettingNote { + text: qsTr("These settings are incompatible with MSAA and may reduce performance.") + } + + SwitchSetting { + id: advRenderingEnabled + text: qsTr("Rendering Effects") + + value: Render.renderMethod === 0 + onValueChanged: Render.renderMethod = value ? 0 : 1 + } + + SwitchSetting { + enabled: advRenderingEnabled.value + text: qsTr("Shadows") + + value: Render.shadowsEnabled + onValueChanged: Render.shadowsEnabled = value + } + + SwitchSetting { + enabled: advRenderingEnabled.value + text: qsTr("Bloom") + + value: Render.bloomEnabled + onValueChanged: Render.bloomEnabled = value + } + + SwitchSetting { + enabled: advRenderingEnabled.value + text: qsTr("Ambient Occlusion") + + value: Render.ambientOcclusionEnabled + onValueChanged: Render.ambientOcclusionEnabled = value + } + + Header { text: qsTr("Desktop Window") } + + ComboSetting { + text: qsTr("Fullscreen Monitor") + model: Render.getScreens() + + currentIndex: { + const index = model.indexOf(Render.getFullScreenScreen()); + return index !== -1 ? index : 0; + } + onCurrentIndexChanged: Render.setFullScreenScreen(model[currentIndex]) + } + + ComboSetting { + id: fpsLimit + text: qsTr("Framerate Limit") + model: [ + // see Performance.RefreshRateProfile + qsTr("20 FPS"), + qsTr("30 FPS"), + qsTr("60 FPS"), + qsTr("Custom"), + ] + + currentIndex: Performance.getRefreshRateProfile() + onCurrentIndexChanged: Performance.setRefreshRateProfile(currentIndex) + } + + SettingNote { + text: qsTr("Higher settings may increase battery usage. VR is always run at your headset's native framerate when possible.") + } + + Header { + text: qsTr("Custom Framerate Limit") + visible: fpsLimit.currentIndex === 3 + } + + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Focused Active") + from: 5 + to: 500 + value: Performance.getCustomRefreshRate(0 /* FOCUS_ACTIVE */) + onValueChanged: Performance.setCustomRefreshRate(0 /* FOCUS_ACTIVE */, value) + } + + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Focused AFK") + from: 1 + to: 500 + value: Performance.getCustomRefreshRate(1 /* FOCUS_INACTIVE */) + onValueChanged: Performance.setCustomRefreshRate(1 /* FOCUS_INACTIVE */, value) + } + + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Unfocused") + from: 1 + to: 500 + value: Performance.getCustomRefreshRate(2 /* UNFOCUS */) + onValueChanged: Performance.setCustomRefreshRate(2 /* FOCUS */, value) + } + + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Minimized") + from: 1 + to: 500 + value: Performance.getCustomRefreshRate(3 /* MINIMIZED */) + onValueChanged: Performance.setCustomRefreshRate(3 /* MINIMIZED */, value) + } + + // FIXME: Does anybody actually care about these? Are they useful? + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Startup") + from: 5 + to: 500 + value: Performance.getCustomRefreshRate(4 /* STARTUP */) + onValueChanged: Performance.setCustomRefreshRate(4 /* STARTUP */, value) + } + + SpinBoxSetting { + visible: fpsLimit.currentIndex === 3 + text: qsTr("Shutdown") + from: 5 + to: 500 + value: Performance.getCustomRefreshRate(5 /* SHUTDOWN */) + onValueChanged: Performance.setCustomRefreshRate(5 /* SHUTDOWN */, value) + } +} + diff --git a/interface/resources/qml/overte/settings/pages/qmldir b/interface/resources/qml/overte/settings/pages/qmldir new file mode 100644 index 00000000000..db33df213d5 --- /dev/null +++ b/interface/resources/qml/overte/settings/pages/qmldir @@ -0,0 +1,5 @@ +module SettingsPages +General 1.0 General.qml +Graphics 1.0 Graphics.qml +Controls 1.0 Controls.qml +Audio 1.0 Audio.qml diff --git a/interface/resources/qml/overte/settings/qmldir b/interface/resources/qml/overte/settings/qmldir new file mode 100644 index 00000000000..88909ca8660 --- /dev/null +++ b/interface/resources/qml/overte/settings/qmldir @@ -0,0 +1,11 @@ +module Settings +Settings 1.0 Settings.qml +SettingsPage 1.0 SettingsPage.qml +SettingNote 1.0 SettingNote.qml +Header 1.0 Header.qml +SwitchSetting 1.0 SwitchSetting.qml +FolderSetting 1.0 FolderSetting.qml +ComboSetting 1.0 ComboSetting.qml +WideComboSetting 1.0 WideComboSetting.qml +SpinBoxSetting 1.0 SpinBoxSetting.qml +SliderSetting 1.0 SliderSetting.qml diff --git a/interface/resources/qml/overte/staging/MediaPlayer.qml b/interface/resources/qml/overte/staging/MediaPlayer.qml new file mode 100644 index 00000000000..0e4a6c39a14 --- /dev/null +++ b/interface/resources/qml/overte/staging/MediaPlayer.qml @@ -0,0 +1,386 @@ +import QtQuick +import QtQuick.Layouts +import QtMultimedia + +import ".." as Overte + +Rectangle { + property url source: "file:///home/ada/var/livestream/clips/corrupted-seagull.mp4" + + anchors.fill: parent + + id: root + radius: 8 + color: Qt.darker(Overte.Theme.paletteActive.base) + border.width: Overte.Theme.borderWidth + border.color: Overte.Theme.paletteActive.base + + implicitWidth: 854 + implicitHeight: 480 + + MediaPlayer { + id: mediaPlayer + source: root.source + audioOutput: audioOutput + videoOutput: videoOutput + } + + AudioOutput { + id: audioOutput + volume: volumeSlider.value + } + + VideoOutput { + anchors.fill: parent + anchors.margins: root.border.width + + id: videoOutput + } + + Item { + id: controlsOverlay + anchors.fill: root + anchors.margins: root.border.width + opacity: 0.0 + + transitions: Transition { + NumberAnimation { + properties: "opacity" + easing.type: Easing.OutExpo + duration: 500 + } + } + + states: [ + State { + name: "idle" + when: !hoverArea.hovered + + PropertyChanges { + target: controlsOverlay + opacity: 0.0 + } + }, + State { + name: "hovered" + when: hoverArea.hovered + + PropertyChanges { + target: controlsOverlay + opacity: 1.0 + } + } + ] + + HoverHandler { + id: hoverArea + target: parent + } + + Rectangle { + anchors.top: controlsOverlay.top + anchors.left: controlsOverlay.left + anchors.margins: 8 + width: childrenRect.width + height: childrenRect.height + radius: 8 + color: Overte.Theme.highContrast ? "black" : "#80000000" + visible: titleLabel.text !== "" || statusLabel.text !== "" + + ColumnLayout { + id: statusColumn + + Overte.Label { + Layout.margins: 8 + + id: titleLabel + visible: text !== "" + + // metadata title > extracted filename > raw url + text: { + const metaTitle = mediaPlayer.metaData.value(MediaMetaData.Title); + + if (metaTitle) { + return metaTitle; + } else { + const file = new URL(root.source).pathname.replace(/^.+?([^\/]+?)(?:\..+)?$/, "$1") + + if (file) { + return file; + } else { + return root.source; + } + } + } + } + + Overte.Label { + Layout.margins: 8 + + id: statusLabel + visible: text !== "" + + text: { + switch (mediaPlayer.mediaStatus) { + case MediaPlayer.LoadingMedia: + return qsTr("Loading…"); + + case MediaPlayer.BufferingMedia: + return qsTr("Buffering…"); + + case MediaPlayer.StalledMedia: + return qsTr("Stalled! Connection may have been lost."); + + case MediaPlayer.InvalidMedia: + return qsTr("Media file is not playable."); + + default: return ""; + } + } + } + } + } + + Overte.RoundButton { + anchors.top: controlsOverlay.top + anchors.right: controlsOverlay.right + anchors.margins: 8 + + icon.color: Overte.Theme.paletteActive.buttonText + icon.source: "../icons/info.svg" + icon.width: 24 + icon.height: 24 + + id: infoButton + checkable: true + } + + Rectangle { + anchors.right: infoButton.left + anchors.top: infoButton.top + anchors.rightMargin: 8 + radius: 8 + color: Overte.Theme.highContrast ? "black" : "#80000000" + visible: infoButton.checked + + width: Math.min(controlsOverlay.width / 2, metadataColumn.implicitWidth + 16) + height: metadataColumn.implicitHeight + 16 + + ColumnLayout { + id: metadataColumn + anchors.fill: parent + anchors.margins: 8 + + Overte.Label { + Layout.fillWidth: true + font.family: Overte.Theme.monoFontFamily + font.pixelSize: Overte.Theme.fontPixelSizeSmall + elide: Text.ElideMiddle + text: root.source + } + + Overte.Label { + Layout.fillWidth: true + text: { + const containerNames = new Map([ + [0, "WMV"], + [1, "AVI"], + [2, "Matroska (mkv)"], + [3, "MPEG-4 (mp4)"], + [4, "Ogg"], + [5, "QuickTime (mov)"], + [6, "WebM"], + [7, "MPEG-4 Audio"], + [8, "AAC"], + [9, "WMA"], + [10, "MP3"], + [11, "FLAC"], + [12, "WAV"], + ]); + const vcodecNames = new Map([ + [0, "MPEG-1"], + [1, "MPEG-2"], + [2, "MPEG-4"], + [3, "H.264"], + [4, "H.265"], + [5, "VP8"], + [6, "VP9"], + [7, "AV1"], + [8, "Theora"], + [9, "WMV Video"], + [10, "Motion JPEG"], + ]); + const acodecNames = new Map([ + [0, "MP3"], + [1, "AAC"], + [2, "Dolby AC3"], + [3, "Dolby EAC3"], + [4, "FLAC"], + [5, "Dolby TrueHD"], + [6, "Opus"], + [7, "Ogg Vorbis"], + [8, "WAV"], + [9, "WMA"], + [10, "ALAC"], + ]); + let chunks = []; + + if ( + mediaPlayer.mediaStatus === MediaPlayer.NoMedia || + mediaPlayer.mediaStatus === MediaPlayer.InvalidMedia + ) { + return qsTr("Unloaded"); + } + + const containerName = containerNames.get(mediaPlayer.metaData.value(MediaMetaData.FileFormat)); + chunks.push(`${qsTr("Container:")} ${containerName ?? qsTr("Other")}`); + + if (mediaPlayer.hasVideo) { + const track = mediaPlayer.videoTracks[mediaPlayer.activeVideoTrack]; + const codecName = vcodecNames.get(track.value(MediaMetaData.VideoCodec)); + const fps = track.value(MediaMetaData.VideoFrameRate); + const resolution = track.value(MediaMetaData.Resolution); + chunks.push(`${qsTr("Video:")} ${resolution.width}x${resolution.height}@${fps.toFixed(2)} ${codecName ?? qsTr("Other")}`); + } + + if (mediaPlayer.hasAudio) { + const track = mediaPlayer.audioTracks[mediaPlayer.activeAudioTrack]; + const codecName = acodecNames.get(track.value(MediaMetaData.AudioCodec)); + const bitrate = Math.round(track.value(MediaMetaData.AudioBitRate) / 1000); + chunks.push(`${qsTr("Audio:")} ${bitrate} kbps ${codecName ?? qsTr("Other")}`); + } + + return chunks.join("\n"); + } + } + } + } + + Rectangle { + anchors.left: controlsOverlay.left + anchors.right: controlsOverlay.right + anchors.bottom: controlsOverlay.bottom + anchors.margins: 8 + height: mediaControlsLayout.implicitHeight + 16 + radius: 16 + color: Overte.Theme.highContrast ? "black" : "#80000000" + + RowLayout { + anchors.fill: parent + anchors.margins: 8 + id: mediaControlsLayout + + Overte.RoundButton { + implicitWidth: 48 + implicitHeight: 48 + icon.source: ( + mediaPlayer.playbackState === MediaPlayer.PlayingState ? + "../icons/pause.svg" : + "../icons/triangle_right.svg" + ) + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 32 + icon.height: 32 + + onClicked: { + if (mediaPlayer.playbackState === MediaPlayer.PlayingState) { + mediaPlayer.pause(); + } else { + mediaPlayer.play(); + } + } + } + + ColumnLayout { + RowLayout { + Overte.Label { + font.family: Overte.Theme.monoFontFamily + text: { + const totalSeconds = Math.floor(mediaPlayer.position / 1000); + + const seconds = (totalSeconds % 60).toString().padStart(2, "0"); + const minutes = (Math.floor(totalSeconds / 60) % 60).toString().padStart(2, "0"); + const hours = Math.floor(totalSeconds / 60 / 60).toString().padStart(2, "0"); + + return `${hours}:${minutes}:${seconds}`; + } + } + + Item { Layout.fillWidth: true } + + Overte.Label { + font.family: Overte.Theme.monoFontFamily + text: { + const totalSeconds = Math.floor(mediaPlayer.duration / 1000); + + const seconds = (totalSeconds % 60).toString().padStart(2, "0"); + const minutes = (Math.floor(totalSeconds / 60) % 60).toString().padStart(2, "0"); + const hours = Math.floor(totalSeconds / 60 / 60).toString().padStart(2, "0"); + + return `${hours}:${minutes}:${seconds}`; + } + } + } + + RowLayout { + Overte.RoundButton { + icon.source: "../icons/skip_backward.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + onClicked: mediaPlayer.position -= 5000 + } + + Overte.Slider { + Layout.fillWidth: true + value: mediaPlayer.position / mediaPlayer.duration + + onMoved: { + mediaPlayer.position = value * mediaPlayer.duration; + } + } + + Overte.RoundButton { + icon.source: "../icons/skip_forward.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + onClicked: mediaPlayer.position += 5000 + } + } + } + + Overte.RoundButton { + id: muteButton + icon.source: { + if (audioOutput.muted) { + return "../icons/speaker_muted.svg"; + } else if (audioOutput.volume === 0) { + return "../icons/speaker_inactive.svg" + } else { + return "../icons/speaker_active.svg"; + } + } + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 24 + icon.height: 24 + checkable: true + checked: audioOutput.muted + + onClicked: audioOutput.muted = !audioOutput.muted; + } + + Overte.Slider { + Layout.preferredWidth: 96 + + id: volumeSlider + value: 0.75 + + onValueChanged: { + audioOutput.muted = false; + } + } + } + } + } +} diff --git a/interface/resources/qml/overte/staging/Node.qml b/interface/resources/qml/overte/staging/Node.qml new file mode 100644 index 00000000000..3c8a07ba543 --- /dev/null +++ b/interface/resources/qml/overte/staging/Node.qml @@ -0,0 +1,181 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Effects + +import ".." as Overte + +Rectangle { + property color titleColor: "#a000a0" + property string title: "Error" + property string bodyText: "" + property string helpText: "" + + property list inputs: [] + property list outputs: [] + + DragHandler { + dragThreshold: Overte.Theme.fontPixelSize + cursorShape: Qt.DragMoveCursor + } + + width: { + let accum = 0; + + accum += titleLayout.implicitWidth; + + return accum; + } + + height: { + let accum = 0; + + if (title !== "") { accum += titlebar.height + 4; } + + let inputsAccum = 0, outputsAccum = 0; + for (const input of inputs) { inputsAccum += 24 + 4; } + for (const output of outputs) { outputsAccum += 24 + 4; } + accum += Math.max(inputsAccum, outputsAccum) + 4; + + return accum; + } + + id: control + radius: Overte.Theme.borderRadius + topLeftRadius: control.radius * 3 + topRightRadius: control.radius * 3 + + border.width: Overte.Theme.borderWidth + border.color: ( + Overte.Theme.highContrast ? + Overte.Theme.paletteActive.buttonText : + Qt.darker(Overte.Theme.paletteActive.base, Overte.Theme.borderDarker) + ) + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(Overte.Theme.paletteActive.base, 1.1) + } + GradientStop { + position: 0.5; color: Overte.Theme.paletteActive.base + } + GradientStop { + position: 1.0; color: Qt.darker(Overte.Theme.paletteActive.base, 1.1) + } + } + + Rectangle { + anchors.fill: titleLayout + visible: control.title !== "" + id: titlebar + + topLeftRadius: control.radius * 2 + topRightRadius: control.radius * 2 + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.lighter(control.titleColor, 1.1) + } + GradientStop { + position: 0.2 + color: Qt.darker(control.titleColor, 1.1) + } + GradientStop { + position: 0.8 + color: control.titleColor + } + GradientStop { + position: 1.0 + color: Qt.darker(control.titleColor, 1.3) + } + } + } + + RowLayout { + anchors.left: control.left + anchors.right: control.right + anchors.top: control.top + anchors.margins: Overte.Theme.borderWidth + + id: titleLayout + spacing: 4 + + Overte.Label { + Layout.margins: 6 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: Overte.Theme.fontPixelSize * 1.5 + visible: control.title !== "" + verticalAlignment: Text.AlignVCenter + text: control.title + id: titleText + color: "white" + + layer.enabled: true + layer.effect: MultiEffect { + shadowEnabled: true + shadowVerticalOffset: 2 + shadowHorizontalOffset: 2 + shadowColor: Qt.darker(control.titleColor, 2.0) + shadowBlur: 0.2 + } + } + + Overte.RoundButton { + Layout.margins: 4 + Layout.alignment: Qt.AlignCenter + visible: control.helpText !== "" + implicitWidth: Overte.Theme.fontPixelSize + 8 + implicitHeight: Overte.Theme.fontPixelSize + 8 + text: "?" + } + } + + Column { + anchors.left: control.left + anchors.top: titlebar.bottom + anchors.topMargin: 4 + spacing: 4 + id: leftPlugs + + Repeater { + model: control.inputs + delegate: NodePlug { + required property string type + + x: -10 + color: Overte.Theme.paletteActive.scriptTypeColors[type] ?? "#ff00ff" + } + } + } + + Overte.Label { + anchors.margins: 8 + anchors.bottom: control.bottom + anchors.left: leftPlugs.right + anchors.right: rightPlugs.left + anchors.top: control.title !== "" ? titlebar.bottom : control.top + visible: control.bodyText !== "" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + font.pixelSize: control.height / 2 + text: control.bodyText + } + + Column { + anchors.right: control.right + anchors.top: titlebar.bottom + anchors.topMargin: 4 + spacing: 4 + id: rightPlugs + + Repeater { + model: control.outputs + delegate: NodePlug { + required property string type + + x: 10 + color: Overte.Theme.paletteActive.scriptTypeColors[type] ?? "#ff00ff" + } + } + } +} diff --git a/interface/resources/qml/overte/staging/NodeGraph.qml b/interface/resources/qml/overte/staging/NodeGraph.qml new file mode 100644 index 00000000000..974fdcbff60 --- /dev/null +++ b/interface/resources/qml/overte/staging/NodeGraph.qml @@ -0,0 +1,29 @@ +import QtQuick + +import ".." as Overte +import "." + +Rectangle { + id: nodeGraph + color: Qt.darker(Overte.Theme.paletteActive.base, 1.1) + + Overte.Switch { + onToggled: Overte.Theme.darkMode = checked + } + + Node { + x: 64 + y: 64 + + titleColor: "#00a000" + title: qsTr("Flush Entity Properties") + helpText: qsTr("Commits all changes to an entity's properties at once.") + inputs: [ + { type: "exec" }, + { type: "entity" }, + ] + outputs: [ + { type: "exec" }, + ] + } +} diff --git a/interface/resources/qml/overte/staging/NodePlug.qml b/interface/resources/qml/overte/staging/NodePlug.qml new file mode 100644 index 00000000000..d80277d3593 --- /dev/null +++ b/interface/resources/qml/overte/staging/NodePlug.qml @@ -0,0 +1,52 @@ +import QtQuick + +import ".." as Overte + +Rectangle { + property bool active: false + + implicitWidth: 24 + implicitHeight: 24 + + id: plug + radius: height / 2 + border.width: Overte.Theme.borderWidth + border.color: Qt.darker(color, Overte.Theme.borderDarker) + color: "#a000a0" + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.lighter(plug.color, 1.3) + } + GradientStop { + position: 0.5 + color: plug.color + } + GradientStop { + position: 1.0 + color: Qt.darker(plug.color, 1.3) + } + } + + Rectangle { + anchors.fill: plug + anchors.margins: plug.height / 5 + radius: height / 2 + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.lighter(plug.color, plug.active ? 2.5 : 0.6) + } + GradientStop { + position: 0.5 + color: Qt.lighter(plug.color, plug.active ? 1.5 : 0.7) + } + GradientStop { + position: 1.0 + color: Qt.lighter(plug.color, plug.active ? 1.0 : 0.8) + } + } + } +} diff --git a/interface/resources/qml/overte/staging/README.md b/interface/resources/qml/overte/staging/README.md new file mode 100644 index 00000000000..05b0f5676c1 --- /dev/null +++ b/interface/resources/qml/overte/staging/README.md @@ -0,0 +1 @@ +Stuff in this folder isn't ready yet. They're here so they can be picked up later. diff --git a/interface/resources/qml/overte/staging/desktop/AppToolbar.qml b/interface/resources/qml/overte/staging/desktop/AppToolbar.qml new file mode 100644 index 00000000000..07a0b1b5d3e --- /dev/null +++ b/interface/resources/qml/overte/staging/desktop/AppToolbar.qml @@ -0,0 +1,82 @@ +import QtQuick +import QtQuick.Controls + +import ".." as Overte + +Item { + readonly property int buttonSize: 80 + + id: root + implicitHeight: buttonSize + (buttonList.anchors.margins * 2) + Overte.Theme.scrollbarWidth + 4 + implicitWidth: 8 * (buttonSize + buttonList.spacing) + buttonList.anchors.margins + + Rectangle { + anchors.fill: root + radius: Overte.Theme.borderRadius + color: Overte.Theme.paletteActive.dialogShade + } + + ListView { + anchors.fill: parent + anchors.margins: 4 + + id: buttonList + orientation: Qt.Horizontal + spacing: 4 + clip: true + + ScrollBar.horizontal: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + } + + model: [ + {name: "Mute", iconSource: "../icons/speaker_muted.svg", checkable: true}, + {name: "Settings", iconSource: "../icons/settings_cog.svg", checkable: true}, + {name: "Contacts", iconSource: "../icons/add_friend.svg", checkable: true}, + {name: "Body Paint", iconSource: "../icons/pencil.svg", checkable: true}, + {name: "Eyes", iconSource: "../icons/eye_open.svg", checkable: false}, + + {name: "Star", iconSource: "../icons/gold_star.svg", checkable: false}, + {name: "Star", iconSource: "../icons/gold_star.svg", checkable: false}, + {name: "Star", iconSource: "../icons/gold_star.svg", checkable: false}, + {name: "Star", iconSource: "../icons/gold_star.svg", checkable: false}, + {name: "Star", iconSource: "../icons/gold_star.svg", checkable: false}, + ] + delegate: Overte.Button { + required property url iconSource + required property string name + required checkable + + implicitWidth: buttonSize + implicitHeight: buttonSize + + Image { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: buttonLabel.top + anchors.margins: 2 + + source: iconSource + sourceSize.width: width + sourceSize.height: height + + fillMode: Image.PreserveAspectFit + } + + Overte.Label { + id: buttonLabel + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 2 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + text: name + + font.pixelSize: Overte.Theme.fontPixelSizeSmall + } + } + } +} diff --git a/interface/resources/qml/overte/staging/desktop/Desktop.qml b/interface/resources/qml/overte/staging/desktop/Desktop.qml new file mode 100644 index 00000000000..00e52b1085d --- /dev/null +++ b/interface/resources/qml/overte/staging/desktop/Desktop.qml @@ -0,0 +1,70 @@ +import QtQuick + +import ".." as Overte +import "." + +//Item { +Rectangle { + color: "#303030" + + anchors.fill: parent + implicitWidth: 800 + implicitHeight: 600 + + id: desktopRoot + + Item { + id: toolbarContainer + anchors.horizontalCenter: desktopRoot.horizontalCenter + anchors.bottom: toolbarToggleButton.top + anchors.margins: 4 + height: appToolbar.height + + AppToolbar { + id: appToolbar + x: -width / 2 + y: Overte.Theme.reducedMotion ? 0 : height * 2 + opacity: 0.0 + + states: State { + name: "open" + when: toolbarToggleButton.checked + PropertyChanges { + target: appToolbar + y: 0 + opacity: 1.0 + } + } + + transitions: Transition { + reversible: true + + NumberAnimation { + properties: "y" + easing.type: Easing.OutExpo + duration: 500 + } + + NumberAnimation { + properties: "opacity" + easing.type: Easing.OutExpo + duration: 500 + } + } + } + } + + Overte.RoundButton { + anchors.horizontalCenter: desktopRoot.horizontalCenter + anchors.bottom: desktopRoot.bottom + anchors.margins: 16 + focusPolicy: Qt.NoFocus + + id: toolbarToggleButton + checkable: true + icon.source: checked ? "../icons/triangle_down.svg" : "../icons/triangle_up.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + } +} diff --git a/interface/resources/qml/overte/staging/desktop/qmldir b/interface/resources/qml/overte/staging/desktop/qmldir new file mode 100644 index 00000000000..5621c982de8 --- /dev/null +++ b/interface/resources/qml/overte/staging/desktop/qmldir @@ -0,0 +1,3 @@ +module Desktop +Desktop 1.0 Desktop.qml +AppToolbar 1.0 AppToolbar.qml diff --git a/interface/resources/qml/overte/staging/keyboard/Keyboard.qml b/interface/resources/qml/overte/staging/keyboard/Keyboard.qml new file mode 100644 index 00000000000..ce92428a7d7 --- /dev/null +++ b/interface/resources/qml/overte/staging/keyboard/Keyboard.qml @@ -0,0 +1,192 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte +import "." as OverteKeyboard + +Rectangle { + id: keyboardRoot + color: Overte.Theme.paletteActive.base + border.color: Qt.lighter(color) + border.width: 2 + radius: 12 + width: 1300 + height: 380 + + PropertyAnimation on opacity { + from: 0 + to: 1 + duration: 500 + } + + // TODO: replace this with Keybaord.layout or something + Component.onCompleted: { + const xhr = new XMLHttpRequest; + xhr.open("GET", "../../keyboard_ansi.json"); + xhr.onreadystatechange = () => { + if (xhr.readyState === XMLHttpRequest.DONE) { + buildLayout(JSON.parse(xhr.responseText)); + } + }; + xhr.send(); + } + + function keyPressed(key) { + // TODO + print(`Press ${key.legend}, ${key.unshifted_keycode}`); + + if (key.unshifted_char !== "") { + modifiers = 0; + } + } + + function keyReleased(key) { + // TODO + print(`Release ${key.legend}, ${key.unshifted_keycode}`); + + switch (key.unshifted_keycode) { + case Qt.Key_Shift: modifiers ^= Qt.ShiftModifier; break; + case Qt.Key_Control: modifiers ^= Qt.ControlModifier; break; + case Qt.Key_Alt: modifiers ^= Qt.AltModifier; break; + case Qt.Key_Meta: modifiers ^= Qt.MetaModifier; break; + } + } + + property int modifiers: 0 + + Component { + id: columnLayout + ColumnLayout { + property real horizontalSpan: 1.0 + property real verticalSpan: 1.0 + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.horizontalStretchFactor: Math.round(horizontalSpan * 1000) + Layout.verticalStretchFactor: Math.round(verticalSpan * 1000) + } + } + Component { + id: rowLayout + RowLayout { + property real horizontalSpan: 1.0 + property real verticalSpan: 1.0 + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.horizontalStretchFactor: Math.round(horizontalSpan * 1000) + Layout.verticalStretchFactor: Math.round(verticalSpan * 1000) + } + } + Component { + id: item + + Item { + property real horizontalSpan: 1.0 + property real verticalSpan: 1.0 + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.horizontalStretchFactor: Math.round(horizontalSpan * 1000) + Layout.verticalStretchFactor: Math.round(verticalSpan * 1000) + implicitWidth: 1 + implicitHeight: 1 + } + } + Component { + id: keyboardKey + KeyboardKey { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.horizontalStretchFactor: Math.round(span * 1000) + implicitWidth: 1 + implicitHeight: 1 + } + } + + function buildLayout(layout) { + for (const topColumn of layout) { + let topColumnSpan = 1.0; + if (!isNaN(topColumn[0])) { + topColumnSpan = topColumn[0]; + } + + const topColumnItem = columnLayout.createObject(layoutRoot, { + horizontalSpan: topColumnSpan, + }); + + for (const row of topColumn) { + // the span width we handled earlier + if (!isNaN(parseFloat(row))) { continue; } + + // vertical spacer + if (!Array.isArray(row)) { + item.createObject(topColumnItem, { + verticalSpan: row.verticalSpan ?? 1.0, + }); + continue; + } + + const rowItem = rowLayout.createObject(topColumnItem); + + for (const key of row) { + if (key.legend) { + const o = keyboardKey.createObject(rowItem, { + unshifted_keycode: Qt[key.keycode ?? key.unshifted_keycode] ?? 0, + shifted_keycode: Qt[key.keycode ?? key.shifted_keycode] ?? 0, + unshifted_char: key.unshifted_char ?? "", + shifted_char: key.shifted_char ?? "", + legend: key.legend ?? "", + span: key.span ?? 1.0, + }); + + if ( + o.unshifted_keycode === Qt.Key_Insert || + o.unshifted_keycode === Qt.Key_Home || + o.unshifted_keycode === Qt.Key_PageUp || + o.unshifted_keycode === Qt.Key_Delete || + o.unshifted_keycode === Qt.Key_End || + o.unshifted_keycode === Qt.Key_PageDown + ) { + o.font.pixelSize = Overte.Theme.fontPixelSizeSmall; + } + + if ( + o.unshifted_keycode === Qt.Key_CapsLock || + o.unshifted_keycode === Qt.Key_Shift || + o.unshifted_keycode === Qt.Key_Control || + o.unshifted_keycode === Qt.Key_Alt || + o.unshifted_keycode === Qt.Key_Meta + ) { + o.checkable = true; + } + } else { + // horizontal spacer + item.createObject(rowItem, { + horizontalSpan: key.span ?? 1.0, + }); + } + } + } + } + } + + RowLayout { + id: layoutRoot + anchors.fill: parent + anchors.margins: 12 + } + + Overte.RoundButton { + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: 6 + horizontalPadding: 2 + verticalPadding: 2 + width: 40 + height: 40 + + backgroundColor: Overte.Theme.paletteActive.buttonDestructive + text: "🗙" + } +} diff --git a/interface/resources/qml/overte/staging/keyboard/KeyboardKey.qml b/interface/resources/qml/overte/staging/keyboard/KeyboardKey.qml new file mode 100644 index 00000000000..9aaa7e7b6bb --- /dev/null +++ b/interface/resources/qml/overte/staging/keyboard/KeyboardKey.qml @@ -0,0 +1,82 @@ +import QtQuick + +import "../" + +Button { + property int unshifted_keycode: 0 + property int shifted_keycode: 0 + + property string unshifted_char: "" + property string shifted_char: "" + + property string legend: "" + property real span: 1.0 + + id: control + text: legend + focusPolicy: Qt.NoFocus + horizontalPadding: 4 + verticalPadding: 4 + + onPressed: keyboardRoot.keyPressed(this) + onReleased: keyboardRoot.keyReleased(this) + + Connections { + target: keyboardRoot + + function onModifiersChanged() { + const value = keyboardRoot.modifiers; + + switch (unshifted_keycode) { + case Qt.Key_Shift: + checked = (value & Qt.ShiftModifier) !== 0; + break; + + case Qt.Key_Control: + checked = (value & Qt.ControlModifier) !== 0; + break; + + case Qt.Key_Alt: + checked = (value & Qt.AltModifier) !== 0; + break; + + case Qt.Key_Meta: + checked = (value & Qt.MetaModifier) !== 0; + break; + } + } + } + + contentItem: Text { + text: control.text + font.family: control.font.family + font.pixelSize: control.height / 3 + color: Theme.paletteActive.buttonText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideNone + } + + background: Rectangle { + id: controlBg + radius: Theme.borderRadius + border.width: Theme.borderWidth + border.color: control.checked ? + Theme.paletteActive.focusRing : + (Theme.highContrast ? Theme.paletteActive.controlText : Qt.darker(control.backgroundColor, Theme.borderDarker)) + color: (control.down || control.checked) ? Qt.darker(control.backgroundColor, Theme.checkedDarker) : + control.hovered ? Qt.lighter(control.backgroundColor, Theme.hoverLighter) : + control.backgroundColor; + gradient: Gradient { + GradientStop { + position: 0.0; color: Qt.lighter(controlBg.color, (control.down || control.checked) ? 0.9 : 1.1) + } + GradientStop { + position: 0.5; color: controlBg.color + } + GradientStop { + position: 1.0; color: Qt.darker(controlBg.color, (control.down || control.checked) ? 0.9 : 1.1) + } + } + } +} diff --git a/interface/resources/qml/overte/staging/keyboard/keyboard_ansi.json b/interface/resources/qml/overte/staging/keyboard/keyboard_ansi.json new file mode 100644 index 00000000000..e812db21438 --- /dev/null +++ b/interface/resources/qml/overte/staging/keyboard/keyboard_ansi.json @@ -0,0 +1,506 @@ +[ + [ + [ + { + "legend": "Esc", + "keycode": "Key_Escape" + }, + { "span": 0.25 }, + { + "legend": "F1", + "keycode": "Key_F1" + }, + { + "legend": "F2", + "keycode": "Key_F2" + }, + { + "legend": "F3", + "keycode": "Key_F3" + }, + { + "legend": "F4", + "keycode": "Key_F4" + }, + { "span": 0.25 }, + { + "legend": "F5", + "keycode": "Key_F5" + }, + { + "legend": "F6", + "keycode": "Key_F6" + }, + { + "legend": "F7", + "keycode": "Key_F7" + }, + { + "legend": "F8", + "keycode": "Key_F8" + }, + { "span": 0.25 }, + { + "legend": "F9", + "keycode": "Key_F9" + }, + { + "legend": "F10", + "keycode": "Key_F10" + }, + { + "legend": "F11", + "keycode": "Key_F11" + }, + { + "legend": "F12", + "keycode": "Key_F12" + } + ], + { "verticalSpan": 0.003 }, + [ + { + "legend": "`\n~", + "unshifted_keycode": "Key_QuoteLeft", + "shifted_keycode": "Key_Tilde", + "unshifted_char": "`", + "shifted_char": "~" + }, + { + "legend": "!\n1", + "unshifted_keycode": "Key_1", + "shifted_keycode": "Key_Exclam", + "unshifted_char": "1", + "shifted_char": "!" + }, + { + "legend": "@\n2", + "unshifted_keycode": "Key_2", + "shifted_keycode": "Key_At", + "unshifted_char": "2", + "shifted_char": "@" + }, + { + "legend": "#\n3", + "unshifted_keycode": "Key_3", + "shifted_keycode": "Key_NumberSign", + "unshifted_char": "3", + "shifted_char": "#" + }, + { + "legend": "$\n4", + "unshifted_keycode": "Key_4", + "shifted_keycode": "Key_Dollar", + "unshifted_char": "4", + "shifted_char": "#" + }, + { + "legend": "%\n5", + "unshifted_keycode": "Key_5", + "shifted_keycode": "Key_Percent", + "unshifted_char": "5", + "shifted_char": "%" + }, + { + "legend": "^\n6", + "unshifted_keycode": "Key_6", + "shifted_keycode": "Key_AsciiCircum", + "unshifted_char": "6", + "shifted_char": "^" + }, + { + "legend": "&\n7", + "unshifted_keycode": "Key_7", + "shifted_keycode": "Key_Ampersand", + "unshifted_char": "7", + "shifted_char": "&" + }, + { + "legend": "*\n8", + "unshifted_keycode": "Key_8", + "shifted_keycode": "Key_Asterisk", + "unshifted_char": "8", + "shifted_char": "*" + }, + { + "legend": "(\n9", + "unshifted_keycode": "Key_9", + "shifted_keycode": "Key_ParenLeft", + "unshifted_key": "9", + "shifted_key": "(" + }, + { + "legend": ")\n0", + "unshifted_keycode": "Key_0", + "shifted_keycode": "Key_ParentRight", + "unshifted_key": "0", + "shifted_key": ")" + }, + { + "legend": "_\n-", + "unshifted_keycode": "Key_Minus", + "shifted_keycode": "Key_Underscore", + "unshifted_char": "-", + "shifted_char": "_" + }, + { + "legend": "+\n=", + "unshifted_keycode": "Key_Equals", + "shifted_keycode": "Key_Plus", + "unshifted_char": "=", + "shifted_char": "+" + }, + { + "legend": "Backspace", + "keycode": "Key_Backspace", + "span": 1.5 + } + ], + [ + { + "legend": "Tab", + "keycode": "Key_Tab", + "span": 1.1 + }, + { + "legend": "Q", + "keycode": "Key_Q", + "unshifted_char": "q", + "shifted_char": "Q" + }, + { + "legend": "W", + "keycode": "Key_W", + "unshifted_char": "w", + "shifted_char": "W" + }, + { + "legend": "E", + "keycode": "Key_E", + "unshifted_char": "e", + "shifted_char": "E" + }, + { + "legend": "R", + "keycode": "Key_R", + "unshifted_char": "r", + "shifted_char": "R" + }, + { + "legend": "T", + "keycode": "Key_T", + "unshifted_char": "t", + "shifted_char": "T" + }, + { + "legend": "Y", + "keycode": "Key_Y", + "unshifted_char": "y", + "shifted_char": "Y" + }, + { + "legend": "U", + "keycode": "Key_U", + "unshifted_char": "u", + "shifted_char": "U" + }, + { + "legend": "I", + "keycode": "Key_I", + "unshifted_char": "i", + "shifted_char": "I" + }, + { + "legend": "O", + "keycode": "Key_O", + "unshifted_char": "o", + "shifted_char": "O" + }, + { + "legend": "P", + "keycode": "Key_P", + "unshifted_char": "p", + "shifted_char": "P" + }, + { + "legend": "{\n[", + "unshifted_keycode": "Key_BracketLeft", + "unshifted_keycode": "Key_BraceLeft", + "unshifted_char": "[", + "shifted_char": "{" + }, + { + "legend": "}\n]", + "unshifted_keycode": "Key_BracketRight", + "unshifted_keycode": "Key_BraceRight", + "unshifted_char": "]", + "shifted_char": "}" + }, + { + "legend": "|\n\\", + "unshifted_keycode": "Key_Backslash", + "unshifted_keycode": "Key_Bar", + "unshifted_char": "\\", + "shifted_char": "|", + "span": 1.3 + } + ], + [ + { + "legend": "Caps", + "keycode": "Key_CapsLock", + "span": 1.3 + }, + { + "legend": "A", + "keycode": "Key_A", + "unshifted_char": "a", + "shifted_char": "A" + }, + { + "legend": "S", + "keycode": "Key_S", + "unshifted_char": "s", + "shifted_char": "S" + }, + { + "legend": "D", + "keycode": "Key_D", + "unshifted_char": "d", + "shifted_char": "D" + }, + { + "legend": "F", + "keycode": "Key_F", + "unshifted_char": "f", + "shifted_char": "F" + }, + { + "legend": "G", + "keycode": "Key_G", + "unshifted_char": "g", + "shifted_char": "G" + }, + { + "legend": "H", + "keycode": "Key_H", + "unshifted_char": "h", + "shifted_char": "H" + }, + { + "legend": "J", + "keycode": "Key_J", + "unshifted_char": "j", + "shifted_char": "J" + }, + { + "legend": "K", + "keycode": "Key_K", + "unshifted_char": "k", + "shifted_char": "K" + }, + { + "legend": "L", + "keycode": "Key_L", + "unshifted_char": "l", + "shifted_char": "L" + }, + { + "legend": ":\n;", + "unshifted_keycode": "Key_Semicolon", + "shifted_keycode": "Key_Colon", + "unshifted_char": ";", + "shifted_char": ":" + }, + { + "legend": "\"\n'", + "unshifted_keycode": "Key_Apostrophe", + "shifted_keycode": "Key_QuoteDbl", + "unshifted_char": "'", + "shifted_char": "\"" + }, + { + "legend": "Return", + "keycode": "Key_Return", + "span": 1.5 + } + ], + [ + { + "legend": "Shift", + "keycode": "Key_Shift", + "span": 1.4 + }, + { + "legend": "Z", + "keycode": "Key_Z", + "unshifted_char": "z", + "shifted_char": "Z" + }, + { + "legend": "X", + "keycode": "Key_X", + "unshifted_char": "x", + "shifted_char": "X" + }, + { + "legend": "C", + "keycode": "Key_C", + "unshifted_char": "c", + "shifted_char": "C" + }, + { + "legend": "V", + "keycode": "Key_V", + "unshifted_char": "v", + "shifted_char": "V" + }, + { + "legend": "B", + "keycode": "Key_B", + "unshifted_char": "b", + "shifted_char": "B" + }, + { + "legend": "N", + "keycode": "Key_N", + "unshifted_char": "n", + "shifted_char": "N" + }, + { + "legend": "M", + "keycode": "Key_M", + "unshifted_char": "m", + "shifted_char": "M" + }, + { + "legend": "<\n,", + "unshifted_keycode": "Key_Comma", + "shifted_keycode": "Key_Less", + "unshifted_char": ",", + "shifted_char": "<" + }, + { + "legend": ">\n.", + "unshifted_keycode": "Key_Period", + "shifted_keycode": "Key_Greater", + "unshifted_char": ".", + "shifted_char": ">" + }, + { + "legend": "?\n/", + "unshifted_keycode": "Key_Slash", + "shifted_keycode": "Key_Question", + "unshifted_char": "/", + "shifted_char": "?" + }, + { + "legend": "Shift", + "keycode": "Key_Shift", + "span": 1.6 + } + ], + [ + { + "legend": "Ctrl", + "keycode": "Key_Control" + }, + { + "legend": "⌘", + "keycode": "Key_Meta" + }, + { + "legend": "Alt", + "keycode": "Key_Alt" + }, + { + "legend": " ", + "keycode": "Key_Space", + "unshifted_char": " ", + "shifted_char": " ", + "span": 4.0 + }, + { + "legend": "Alt", + "keycode": "Key_Alt" + }, + { + "legend": "⌘", + "keycode": "Key_Meta" + }, + { + "legend": "≡", + "keycode": "Key_Menu" + }, + { + "legend": "Ctrl", + "keycode": "Key_Control" + } + ] + ], + [ 0.003 ], + [ + 0.15, + [ + { + "legend": "🗗" + }, + { + "legend": "📋" + }, + {} + ], + { "verticalSpan": 0.003 }, + [ + { + "legend": "Ins", + "keycode": "Key_Insert" + }, + { + "legend": "Home", + "keycode": "Key_Home" + }, + { + "legend": "Page\nUp", + "keycode": "Key_PageUp" + } + ], + [ + { + "legend": "Del", + "keycode": "Key_Delete" + }, + { + "legend": "End", + "keycode": "Key_End" + }, + { + "legend": "Page\nDown", + "keycode": "Key_PageDown" + } + ], + {}, + [ + {}, + { + "legend": "↑", + "keycode": "Key_Up" + }, + {} + ], + [ + { + "legend": "â†", + "keycode": "Key_Left" + }, + { + "legend": "↓", + "keycode": "Key_Down" + }, + { + "legend": "→", + "keycode": "Key_Right" + } + ] + ] +] diff --git a/interface/resources/qml/overte/staging/keyboard/qmldir b/interface/resources/qml/overte/staging/keyboard/qmldir new file mode 100644 index 00000000000..0cd7e02edd0 --- /dev/null +++ b/interface/resources/qml/overte/staging/keyboard/qmldir @@ -0,0 +1,3 @@ +module Keyboard +Keyboard 1.0 Keyboard.qml +KeyboardKey 1.0 KeyboardKey.qml diff --git a/interface/resources/qml/overte/staging/login/LoginScreen.qml b/interface/resources/qml/overte/staging/login/LoginScreen.qml new file mode 100644 index 00000000000..550126e7528 --- /dev/null +++ b/interface/resources/qml/overte/staging/login/LoginScreen.qml @@ -0,0 +1,52 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick.Effects + +import "../" as Overte +import "./pages" as Pages + +Rectangle { + anchors.fill: parent + implicitWidth: 480 + implicitHeight: 720 + id: root + + color: Overte.Theme.paletteActive.base + + Image { + visible: !Overte.Theme.highContrast + anchors.fill: parent + source: "./assets/background.png" + + layer.enabled: true + layer.effect: MultiEffect { + blurEnabled: true + blurMax: 64 + blur: 1.0 + contrast: Overte.Theme.darkMode ? -0.7 : -0.8 + brightness: Overte.Theme.darkMode ? -0.2 : 0.25 + } + } + + ColumnLayout { + anchors.fill: parent + + Image { + Layout.fillWidth: true + + id: logo + fillMode: Image.PreserveAspectFit + + source: Overte.Theme.darkMode ? "./assets/logo_dark.png" : "./assets/logo_light.png" + } + + Overte.StackView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: stack + initialItem: Pages.StartPage {} + } + } +} diff --git a/interface/resources/qml/overte/staging/login/assets/background.png b/interface/resources/qml/overte/staging/login/assets/background.png new file mode 100644 index 00000000000..9b18c52b57a Binary files /dev/null and b/interface/resources/qml/overte/staging/login/assets/background.png differ diff --git a/interface/resources/qml/overte/staging/login/assets/logo_dark.png b/interface/resources/qml/overte/staging/login/assets/logo_dark.png new file mode 100644 index 00000000000..bf3380a55d3 Binary files /dev/null and b/interface/resources/qml/overte/staging/login/assets/logo_dark.png differ diff --git a/interface/resources/qml/overte/staging/login/assets/logo_light.png b/interface/resources/qml/overte/staging/login/assets/logo_light.png new file mode 100644 index 00000000000..35285a0a0e3 Binary files /dev/null and b/interface/resources/qml/overte/staging/login/assets/logo_light.png differ diff --git a/interface/resources/qml/overte/staging/login/pages/LoginPage.qml b/interface/resources/qml/overte/staging/login/pages/LoginPage.qml new file mode 100644 index 00000000000..a22dc08c53a --- /dev/null +++ b/interface/resources/qml/overte/staging/login/pages/LoginPage.qml @@ -0,0 +1,137 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../../" as Overte + +Item { + // TODO: once the account server can accept + // usernames starting with numbers or underscores, modify this + readonly property var usernameRegex: /[a-zA-Z][0-9a-zA-Z_.-]{2,}/ + + // passwords must be at least 6 characters + readonly property var passwordRegex: /.{6,}/ + + ColumnLayout { + anchors.fill: parent + anchors.margins: 32 + spacing: Overte.Theme.fontPixelSize * 2 + + Overte.Label { + Layout.fillWidth: true + + text: qsTr("Log In") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Overte.TextField { + Layout.fillWidth: true + + id: usernameField + placeholderText: qsTr("Username") + + validator: RegularExpressionValidator { + regularExpression: usernameRegex + } + + Overte.ToolTip { + visible: parent.activeFocus && !parent.text.match(usernameRegex) + text: qsTr("Usernames must start with a letter and be at least 3 characters long.") + } + } + + RowLayout { + Layout.fillWidth: true + + Overte.TextField { + id: passwordField + Layout.fillWidth: true + placeholderText: qsTr("Password") + echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password + passwordMaskDelay: 500 + + validator: RegularExpressionValidator { + regularExpression: passwordRegex + } + + Overte.ToolTip { + visible: parent.activeFocus && !parent.text.match(usernameRegex) + text: qsTr("Passwords must be at least 6 characters.") + } + } + + Overte.RoundButton { + id: showPassword + checkable: true + icon.source: checked ? "../../icons/eye_closed.svg" : "../../icons/eye_open.svg" + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 24 + icon.height: 24 + } + } + + Overte.TextField { + Layout.fillWidth: true + + id: accountServerField + placeholderText: qsTr("Account server (Optional)") + } + + RowLayout { + spacing: 16 + Layout.maximumHeight: Overte.Theme.fontPixelSize * 3 + + Overte.Button { + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Back", "Return to previous page") + icon.source: "../../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + stack.pop(); + } + } + + Overte.Button { + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Log in", "Log in button") + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + enabled: usernameField.text.match(usernameRegex) && passwordField.text.match(passwordRegex) + + onClicked: { + let props = { + mode: "login", + username: usernameField.text, + // don't let stray newlines through + // or stuff can break + password: ( + passwordField.text + .replace("\n", "") + .replace("\r", "") + ), + }; + + if (accountServerField.text !== "") { + props.accountServer = accountServerField.text; + } + + stack.push("./ProgressPage.qml", props); + } + } + } + } +} diff --git a/interface/resources/qml/overte/staging/login/pages/ProgressPage.qml b/interface/resources/qml/overte/staging/login/pages/ProgressPage.qml new file mode 100644 index 00000000000..2dfd8e4e5fd --- /dev/null +++ b/interface/resources/qml/overte/staging/login/pages/ProgressPage.qml @@ -0,0 +1,83 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../../" as Overte + +Item { + required property string mode + required property string username + required property string password + property url accountServer: "https://mv.overte.org/server" + + function loginError(desc) { + let topLine = ( + mode === "register" ? + qsTr("Failed to register!") : + qsTr("Failed to log in!") + ); + statusText.text = `${topLine}\n\n${qsTr(desc)}`; + backButton.visible = true; + } + + // DEBUG + Timer { + interval: 1000 + running: true + onTriggered: { + loginError("Debug mode! Not connected to anything."); + } + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: 32 + spacing: Overte.Theme.fontPixelSize * 2 + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + + id: statusText + text: mode === "register" ? qsTr("Registering…") : qsTr("Logging in…") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + RowLayout { + spacing: 16 + Layout.minimumHeight: Overte.Theme.fontPixelSize * 3 + Layout.maximumHeight: Overte.Theme.fontPixelSize * 3 + + Overte.Button { + id: backButton + visible: false + + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Back", "Return to previous page") + icon.source: "../../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + stack.pop(); + } + } + + Item { + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + } + } + } +} + diff --git a/interface/resources/qml/overte/staging/login/pages/RegisterPage.qml b/interface/resources/qml/overte/staging/login/pages/RegisterPage.qml new file mode 100644 index 00000000000..250aa3d9c08 --- /dev/null +++ b/interface/resources/qml/overte/staging/login/pages/RegisterPage.qml @@ -0,0 +1,137 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../../" as Overte + +Item { + // TODO: once the account server can accept + // usernames starting with numbers or underscores, modify this + readonly property var usernameRegex: /[a-zA-Z][0-9a-zA-Z_.-]{2,}/ + + // passwords must be at least 6 characters + readonly property var passwordRegex: /.{6,}/ + + ColumnLayout { + anchors.fill: parent + anchors.margins: 32 + spacing: Overte.Theme.fontPixelSize * 2 + + Overte.Label { + Layout.fillWidth: true + + text: qsTr("Register") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Overte.TextField { + Layout.fillWidth: true + + id: usernameField + placeholderText: qsTr("Username") + + validator: RegularExpressionValidator { + regularExpression: usernameRegex + } + + Overte.ToolTip { + visible: parent.activeFocus && !parent.text.match(usernameRegex) + text: qsTr("Usernames must start with a letter and be at least 3 characters long.") + } + } + + RowLayout { + Layout.fillWidth: true + + Overte.TextField { + id: passwordField + Layout.fillWidth: true + placeholderText: qsTr("Password") + echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password + passwordMaskDelay: 500 + + validator: RegularExpressionValidator { + regularExpression: passwordRegex + } + + Overte.ToolTip { + visible: parent.activeFocus && !parent.text.match(usernameRegex) + text: qsTr("Passwords must be at least 6 characters.") + } + } + + Overte.RoundButton { + id: showPassword + checkable: true + icon.source: checked ? "../../icons/eye_closed.svg" : "../../icons/eye_open.svg" + icon.color: Overte.Theme.paletteActive.buttonText + icon.width: 24 + icon.height: 24 + } + } + + Overte.TextField { + Layout.fillWidth: true + + id: accountServerField + placeholderText: qsTr("Account server (Optional)") + } + + RowLayout { + spacing: 16 + Layout.maximumHeight: Overte.Theme.fontPixelSize * 3 + + Overte.Button { + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Back", "Return to previous page") + icon.source: "../../icons/triangle_left.svg" + icon.width: 24 + icon.height: 24 + icon.color: Overte.Theme.paletteActive.buttonText + + onClicked: { + stack.pop(); + } + } + + Overte.Button { + // make the buttons equal size + Layout.preferredWidth: 1 + Layout.preferredHeight: 1 + Layout.fillWidth: true + Layout.fillHeight: true + + text: qsTr("Register", "Register button") + backgroundColor: Overte.Theme.paletteActive.buttonAdd + + enabled: usernameField.text.match(usernameRegex) && passwordField.text.match(passwordRegex) + + onClicked: { + let props = { + mode: "register", + username: usernameField.text, + // don't let stray newlines through + // or stuff can break + password: ( + passwordField.text + .replace("\n", "") + .replace("\r", "") + ), + }; + + if (accountServerField.text !== "") { + props.accountServer = accountServerField.text; + } + + stack.push("./ProgressPage.qml", props); + } + } + } + } +} diff --git a/interface/resources/qml/overte/staging/login/pages/StartPage.qml b/interface/resources/qml/overte/staging/login/pages/StartPage.qml new file mode 100644 index 00000000000..9ab8c4b8624 --- /dev/null +++ b/interface/resources/qml/overte/staging/login/pages/StartPage.qml @@ -0,0 +1,69 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../../" as Overte + +Item { + readonly property url codeOfConduct: "https://overte.org/code_of_conduct.html" + + ColumnLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 32 + spacing: Overte.Theme.fontPixelSize * 2 + + Overte.Label { + Layout.fillWidth: true + + text: qsTr("Welcome to Overte!\n\nAn account gives you a contacts list and lets you publish to the public worlds list.\n\nAccounts are entirely optional.") + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + } + + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + spacing: 16 + + Overte.Button { + Layout.alignment: Qt.AlignCenter + Layout.fillWidth: true + + // force equally sized buttons + Layout.preferredWidth: 1 + + text: qsTr("Register") + + onClicked: { + stack.push("./RegisterPage.qml"); + } + } + + Overte.Button { + Layout.alignment: Qt.AlignCenter + Layout.fillWidth: true + + // force equally sized buttons + Layout.preferredWidth: 1 + + text: qsTr("Log in") + + onClicked: { + stack.push("./LoginPage.qml"); + } + } + } + + Overte.Button { + Layout.alignment: Qt.AlignCenter + Layout.fillWidth: true + + text: qsTr("Code of Conduct") + + onClicked: () => Qt.openUrlExternally(codeOfConduct) + } + } +} diff --git a/interface/resources/qml/overte/staging/login/pages/qmldir b/interface/resources/qml/overte/staging/login/pages/qmldir new file mode 100644 index 00000000000..816c3d70cec --- /dev/null +++ b/interface/resources/qml/overte/staging/login/pages/qmldir @@ -0,0 +1,4 @@ +module LoginPages +StartPage 1.0 StartPage.qml +LoginPage 1.0 LoginPage.qml +RegisterPage 1.0 RegisterPage.qml diff --git a/interface/resources/qml/overte/staging/login/qmldir b/interface/resources/qml/overte/staging/login/qmldir new file mode 100644 index 00000000000..02fe9379c9c --- /dev/null +++ b/interface/resources/qml/overte/staging/login/qmldir @@ -0,0 +1,2 @@ +module Login +LoginScreen 1.0 LoginScreen.qml diff --git a/interface/resources/qml/overte/staging/tutorial/AvatarPicker.qml b/interface/resources/qml/overte/staging/tutorial/AvatarPicker.qml new file mode 100644 index 00000000000..0702431e715 --- /dev/null +++ b/interface/resources/qml/overte/staging/tutorial/AvatarPicker.qml @@ -0,0 +1,6 @@ +import "../avatar_picker" + +AvatarPicker { + editable: false + availableTags: ["Human", "Furry", "Anime", "Robot", "Other"] +} diff --git a/interface/resources/qml/overte/staging/tutorial/ControlsGuide.qml b/interface/resources/qml/overte/staging/tutorial/ControlsGuide.qml new file mode 100644 index 00000000000..02d16d4fd5d --- /dev/null +++ b/interface/resources/qml/overte/staging/tutorial/ControlsGuide.qml @@ -0,0 +1,72 @@ +import QtQuick +import QtQuick.Layouts + +import "../" as Overte + +Rectangle { + id: root + implicitWidth: 720 + implicitHeight: 480 + color: Overte.Theme.paletteActive.base + + Overte.TabBar { + id: tabBar + anchors.top: root.top + anchors.left: root.left + anchors.right: root.right + + Overte.TabButton { width: implicitWidth; text: qsTr("Keyboard") } + Overte.TabButton { width: implicitWidth; text: qsTr("Oculus Touch") } + Overte.TabButton { width: implicitWidth; text: qsTr("Mixed Reality") } + Overte.TabButton { width: implicitWidth; text: qsTr("Index") } + Overte.TabButton { width: implicitWidth; text: qsTr("Vive") } + } + + StackLayout { + anchors.top: tabBar.bottom + anchors.left: root.left + anchors.right: root.right + anchors.bottom: root.bottom + currentIndex: tabBar.currentIndex + + // Keyboard + Image { + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/controls_dark.png" : "./assets/controls_light.png" + } + + // Oculus Touch + Image { + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/controls_dark.png" : "./assets/controls_light.png" + } + + // Mixed Reality + Image { + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/controls_dark.png" : "./assets/controls_light.png" + } + + // Index + Image { + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/controls_dark.png" : "./assets/controls_light.png" + } + + // Vive + Image { + Layout.fillWidth: true + Layout.fillHeight: true + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/controls_dark.png" : "./assets/controls_light.png" + } + } +} diff --git a/interface/resources/qml/overte/staging/tutorial/Welcome.qml b/interface/resources/qml/overte/staging/tutorial/Welcome.qml new file mode 100644 index 00000000000..610cd8e14b0 --- /dev/null +++ b/interface/resources/qml/overte/staging/tutorial/Welcome.qml @@ -0,0 +1,46 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import "../" as Overte + +Rectangle { + id: root + implicitWidth: 480 + implicitHeight: 360 + color: Overte.Theme.paletteActive.base + + ScrollView { + anchors.fill: parent + + ScrollBar.vertical: Overte.ScrollBar { + policy: ScrollBar.AsNeeded + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + } + + contentWidth: width - ScrollBar.vertical.width + + Column { + spacing: 16 + padding: 8 + + Image { + width: root.width + height: sourceSize.height + fillMode: Image.PreserveAspectFit + source: Overte.Theme.darkMode ? "./assets/logo_dark.png" : "./assets/logo_light.png" + } + + Overte.Label { + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: root.width / 8 + anchors.rightMargin: root.width / 8 + text: qsTr("Welcome to Overte!\nThis is an offline tutorial world.\n\nTODO: More intro text") + wrapMode: Text.Wrap + } + } + } +} diff --git a/interface/resources/qml/overte/staging/tutorial/assets/controls_dark.png b/interface/resources/qml/overte/staging/tutorial/assets/controls_dark.png new file mode 100644 index 00000000000..3914ae96af6 Binary files /dev/null and b/interface/resources/qml/overte/staging/tutorial/assets/controls_dark.png differ diff --git a/interface/resources/qml/overte/staging/tutorial/assets/controls_light.png b/interface/resources/qml/overte/staging/tutorial/assets/controls_light.png new file mode 100644 index 00000000000..52abbe450d8 Binary files /dev/null and b/interface/resources/qml/overte/staging/tutorial/assets/controls_light.png differ diff --git a/interface/resources/qml/overte/staging/tutorial/assets/logo_dark.png b/interface/resources/qml/overte/staging/tutorial/assets/logo_dark.png new file mode 100644 index 00000000000..bf3380a55d3 Binary files /dev/null and b/interface/resources/qml/overte/staging/tutorial/assets/logo_dark.png differ diff --git a/interface/resources/qml/overte/staging/tutorial/assets/logo_light.png b/interface/resources/qml/overte/staging/tutorial/assets/logo_light.png new file mode 100644 index 00000000000..35285a0a0e3 Binary files /dev/null and b/interface/resources/qml/overte/staging/tutorial/assets/logo_light.png differ diff --git a/interface/resources/qml/overte/staging/tutorial/qmldir b/interface/resources/qml/overte/staging/tutorial/qmldir new file mode 100644 index 00000000000..ed867fa3f36 --- /dev/null +++ b/interface/resources/qml/overte/staging/tutorial/qmldir @@ -0,0 +1,4 @@ +module Tutorial +Welcome 1.0 Welcome.qml +ControlsGuide 1.0 ControlsGuide.qml +AvatarPicker 1.0 AvatarPicker.qml diff --git a/interface/resources/qml/windows/Decoration.qml b/interface/resources/qml/windows/Decoration.qml index 1ba7ad125d6..1d2d6320ec8 100644 --- a/interface/resources/qml/windows/Decoration.qml +++ b/interface/resources/qml/windows/Decoration.qml @@ -9,22 +9,24 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 import "." import stylesUit 1.0 +// TODO: look into whether we should outright replace the Hifi desktop system +import "../overte" as Overte + Rectangle { HifiConstants { id: hifi } signal inflateDecorations(); signal deflateDecorations(); - property int frameMargin: 9 + property int frameMargin: 4 property int frameMarginLeft: frameMargin property int frameMarginRight: frameMargin - property int frameMarginTop: 2 * frameMargin + iconSize - property int frameMarginBottom: iconSize + 11 + property int frameMarginTop: (2 * frameMargin) + iconSize + property int frameMarginBottom: (2 * frameMargin) + (window.resizable || DebugQML ? 18 : 0) anchors { topMargin: -frameMarginTop @@ -33,12 +35,18 @@ Rectangle { bottomMargin: -frameMarginBottom } anchors.fill: parent - color: hifi.colors.baseGrayHighlight40 - border { - width: hifi.dimensions.borderWidth - color: hifi.colors.faintGray50 + color: Overte.Theme.paletteActive.base + border.width: Overte.Theme.borderWidth + border.color: { + if (Overte.Theme.highContrast) { + return Overte.Theme.paletteActive.text; + } else if (Overte.Theme.darkMode) { + return Qt.lighter(Overte.Theme.paletteActive.base); + } else { + return Qt.darker(Overte.Theme.paletteActive.base); + } } - radius: hifi.dimensions.borderRadius + radius: Overte.Theme.borderRadius // Enable dragging of the window, // detect mouseover of the window (including decoration) @@ -90,4 +98,3 @@ Rectangle { } } } - diff --git a/interface/resources/qml/windows/DefaultFrameDecoration.qml b/interface/resources/qml/windows/DefaultFrameDecoration.qml index fb0dd55985c..67a2033e494 100644 --- a/interface/resources/qml/windows/DefaultFrameDecoration.qml +++ b/interface/resources/qml/windows/DefaultFrameDecoration.qml @@ -8,52 +8,74 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import QtQuick +import QtQuick.Layouts import "." import stylesUit 1.0 +// TODO: look into whether we should outright replace the Hifi desktop system +import "../overte" as Overte + Decoration { HifiConstants { id: hifi } // Dialog frame id: root - property int iconSize: hifi.dimensions.frameIconSize - frameMargin: 9 + property int iconSize: 24 + frameMargin: 4 frameMarginLeft: frameMargin frameMarginRight: frameMargin - frameMarginTop: 2 * frameMargin + iconSize - frameMarginBottom: iconSize + 11 + frameMarginTop: (2 * frameMargin) + iconSize + frameMarginBottom: (2 * frameMargin) + (window.resizable || DebugQML ? 18 : 0) onInflateDecorations: { if (!HMD.active) { return; } - root.frameMargin = 18 - titleText.size = hifi.fontSizes.overlayTitle * 2 - root.iconSize = hifi.dimensions.frameIconSize * 2 + root.frameMargin = 18; + root.iconSize = 32; } onDeflateDecorations: { - root.frameMargin = 9 - titleText.size = hifi.fontSizes.overlayTitle - root.iconSize = hifi.dimensions.frameIconSize + root.frameMargin = 4; + root.iconSize = 24; } + Rectangle { + anchors.fill: controlsRow + color: Overte.Theme.paletteActive.activeWindowTitleBg + topLeftRadius: Overte.Theme.borderRadius + topRightRadius: Overte.Theme.borderRadius + } - Row { + RowLayout { id: controlsRow anchors { - right: parent.right; - top: parent.top; - topMargin: root.frameMargin + 1 // Move down a little to visually align with the title - rightMargin: root.frameMarginRight; + top: parent.top + left: parent.left + right: parent.right + margins: Overte.Theme.borderWidth + } + spacing: 2 + height: root.frameMarginTop - root.frameMargin + + Overte.Label { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: 4 + + // Title + id: titleText + text: window ? window.title : "" + verticalAlignment: Text.AlignVCenter + color: Overte.Theme.paletteActive.activeWindowTitleFg } - spacing: root.iconSize / 4 HiFiGlyphs { + Layout.alignment: Qt.AlignCenter + // "Pin" button visible: window.pinnable text: window.pinned ? hifi.glyphs.pinInverted : hifi.glyphs.pin @@ -68,49 +90,28 @@ Decoration { } } - HiFiGlyphs { - // "Close" button + Overte.RoundButton { + Layout.alignment: Qt.AlignCenter + Layout.rightMargin: 4 + visible: window ? window.closable : false - text: closeClickArea.containsPress ? hifi.glyphs.closeInverted : hifi.glyphs.close - color: closeClickArea.containsMouse ? hifi.colors.redHighlight : hifi.colors.white - size: root.iconSize - MouseArea { - id: closeClickArea - anchors.fill: parent - hoverEnabled: true - onClicked: { - window.shown = false; - window.windowClosed(); - } - } - } - } + icon.source: "../overte/icons/close.svg" + icon.width: root.iconSize == 24 ? 12 : 24 + icon.height: root.iconSize == 24 ? 12 : 24 + icon.color: Overte.Theme.paletteActive.buttonText + backgroundColor: ( + hovered ? + Overte.Theme.paletteActive.buttonDestructive : + Overte.Theme.paletteActive.button + ) - RalewayRegular { - // Title - id: titleText - anchors { - left: parent.left - leftMargin: root.frameMarginLeft + hifi.dimensions.contentMargin.x - right: controlsRow.left - rightMargin: root.iconSize - top: parent.top - topMargin: root.frameMargin - } - text: window ? window.title : "" - color: hifi.colors.white - size: hifi.fontSizes.overlayTitle - } + implicitWidth: root.iconSize + implicitHeight: root.iconSize - DropShadow { - source: titleText - anchors.fill: titleText - horizontalOffset: 2 - verticalOffset: 2 - samples: 2 - color: hifi.colors.baseGrayShadow60 - visible: (desktop.gradientsSupported && window && window.focus) - cached: true + onClicked: { + window.shown = false; + window.windowClosed(); + } + } } } - diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index cfff40bbf62..58c31540166 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -9,11 +9,14 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 import "../js/Utils.js" as Utils +// TODO: look into whether we should outright replace the Hifi desktop system +import "../overte" as Overte + Item { id: frame objectName: "Frame" @@ -21,7 +24,6 @@ Item { default property var decoration property string qmlFile: "N/A" - property bool gradientsSupported: desktop.gradientsSupported readonly property int frameMarginLeft: frame.decoration ? frame.decoration.frameMarginLeft : 0 readonly property int frameMarginRight: frame.decoration ? frame.decoration.frameMarginRight : 0 @@ -33,21 +35,12 @@ Item { anchors.fill: parent children: [ - focusShadow, decoration, sizeOutline, debugZ, sizeDrag ] - Text { - id: debugZ - visible: (typeof DebugQML !== 'undefined') ? DebugQML : false - color: "red" - text: (window ? "Z: " + window.z : "") + " " + qmlFile - y: window ? window.height + 4 : 0 - } - function deltaSize(dx, dy) { var newSize = Qt.vector2d(window.width + dx, window.height + dy); newSize = Utils.clampVector(newSize, window.minSize, window.maxSize); @@ -55,41 +48,32 @@ Item { window.height = newSize.y } - RadialGradient { - id: focusShadow - width: 1.66 * window.width - height: 1.66 * window.height - x: (window.width - width) / 2 - y: window.height / 2 - 0.375 * height - visible: gradientsSupported && window && window.focus && window.content.visible - gradient: Gradient { - // GradientStop position 0.5 is at full circumference of circle that fits inside the square. - GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity - GradientStop { position: 0.333; color: "#1f000000" } // black, 12% opacity - GradientStop { position: 0.5; color: "#00000000" } // black, 0% opacity - GradientStop { position: 1.0; color: "#00000000" } - } - cached: true - } - Rectangle { id: sizeOutline x: -frameMarginLeft y: -frameMarginTop width: window ? window.width + frameMarginLeft + frameMarginRight + 2 : 0 height: window ? window.height + frameMarginTop + frameMarginBottom + 2 : 0 - color: hifi.colors.baseGrayHighlight15 - border.width: 3 - border.color: hifi.colors.white50 - radius: hifi.dimensions.borderRadius + color: Overte.Theme.paletteActive.base + border.width: Overte.Theme.borderWidth + border.color: { + if (Overte.Theme.highContrast) { + return Overte.Theme.paletteActive.text; + } else if (Overte.Theme.darkMode) { + return Qt.lighter(Overte.Theme.paletteActive.base); + } else { + return Qt.darker(Overte.Theme.paletteActive.base); + } + } + radius: Overte.Theme.borderRadius visible: window ? !window.content.visible : false } MouseArea { // Resize handle id: sizeDrag - width: hifi.dimensions.frameIconSize - height: hifi.dimensions.frameIconSize + width: 18 + height: 18 enabled: window ? window.resizable : false hoverEnabled: true x: window ? window.width + frameMarginRight - hifi.dimensions.frameIconSize : 0 @@ -119,15 +103,30 @@ Item { frame.deltaSize(delta.x, delta.y) } } + + // TODO: use an SVG icon instead of HifiGlyphs HiFiGlyphs { + x: -9 + y: -9 visible: sizeDrag.enabled - x: -11 // Move a little to visually align - y: window.modality == Qt.ApplicationModal ? -6 : -4 text: hifi.glyphs.resizeHandle - size: hifi.dimensions.frameIconSize + 10 - color: sizeDrag.containsMouse || sizeDrag.pressed - ? hifi.colors.white - : (window.colorScheme == hifi.colorSchemes.dark ? hifi.colors.white50 : hifi.colors.lightGrayText80) + size: 32 + color: { + if (Overte.Theme.highContrast) { + return Overte.Theme.paletteActive.buttonText; + } else { + return Qt.darker(Overte.Theme.paletteActive.base, Overte.Theme.borderDarker); + } + } } } + + Text { + id: debugZ + visible: (typeof DebugQML !== 'undefined') ? DebugQML : false + color: "red" + text: (window ? "Z: " + window.z : "") + " " + qmlFile + y: window ? window.height + 4 : 0 + font.pixelSize: 12 + } } diff --git a/interface/resources/qml/windows/ScrollingWindow.qml b/interface/resources/qml/windows/ScrollingWindow.qml index 0c91b58e315..51a62c5d075 100644 --- a/interface/resources/qml/windows/ScrollingWindow.qml +++ b/interface/resources/qml/windows/ScrollingWindow.qml @@ -11,12 +11,14 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." as Windows import stylesUit 1.0 import controlsUit 1.0 as HifiControlsUit +import "../overte" as Overte + // FIXME how do I set the initial position of a window without // overriding places where the a individual client of the window // might be setting the position with a Settings{} element? @@ -55,25 +57,10 @@ Windows.Window { id: contentBackground anchors.fill: parent //anchors.rightMargin: parent.isScrolling ? verticalScrollWidth + 1 : 0 - color: hifi.colors.baseGray + color: Overte.Theme.paletteActive.base visible: !window.hideBackground && modality != Qt.ApplicationModal } - LinearGradient { - visible: !window.hideBackground && gradientsSupported && modality != Qt.ApplicationModal - anchors.top: contentBackground.bottom - anchors.left: contentBackground.left - width: contentBackground.width - 1 - height: 4 - start: Qt.point(0, 0) - end: Qt.point(0, 4) - gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.darkGray } - GradientStop { position: 1.0; color: hifi.colors.darkGray0 } - } - cached: true - } - Flickable { id: scrollView contentItem.children: [ content ] @@ -176,6 +163,7 @@ Windows.Window { children: [ footer ] } + // TODO: remove the old 2D hifi keyboard HifiControlsUit.Keyboard { id: keyboard enabled: !keyboardOverride diff --git a/interface/resources/qml/windows/ToolFrame.qml b/interface/resources/qml/windows/ToolFrame.qml index bb2bada498e..8ea5bd669ba 100644 --- a/interface/resources/qml/windows/ToolFrame.qml +++ b/interface/resources/qml/windows/ToolFrame.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." import stylesUit 1.0 diff --git a/interface/resources/qml/windows/ToolFrameDecoration.qml b/interface/resources/qml/windows/ToolFrameDecoration.qml index 4f149037b38..2e7044123e9 100644 --- a/interface/resources/qml/windows/ToolFrameDecoration.qml +++ b/interface/resources/qml/windows/ToolFrameDecoration.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." import stylesUit 1.0 diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 77cb35ceba4..64b26f28ab7 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import "." import stylesUit 1.0 @@ -67,7 +67,9 @@ Fadable { property bool destroyOnCloseButton: true // Should hiding the window destroy it or just hide it? property bool destroyOnHidden: false - property bool pinnable: true + // TODO: Remove the pinnable property entirely + // Nobody knows what the pin is supposed to do, disable it by default + property bool pinnable: false property bool pinned: false property bool resizable: false property bool gradientsSupported: desktop.gradientsSupported @@ -127,7 +129,7 @@ Fadable { propagateComposedEvents: true acceptedButtons: Qt.AllButtons enabled: window.visible - onPressed: { + onPressed: mouse => { window.raise(); mouse.accepted = false; } @@ -142,7 +144,7 @@ Fadable { propagateComposedEvents: true acceptedButtons: Qt.AllButtons enabled: window.visible - onPressed: { + onPressed: mouse => { frame.forceActiveFocus(); mouse.accepted = false; } @@ -291,7 +293,7 @@ Fadable { window.height - frame.decoration.anchors.topMargin - frame.decoration.anchors.bottomMargin) } - Keys.onPressed: { + Keys.onPressed: event => { switch(event.key) { case Qt.Key_Control: case Qt.Key_Shift: diff --git a/interface/resources/serverless/Scripts/Wizard.qml b/interface/resources/serverless/Scripts/Wizard.qml index f258de9247b..2799bcc5df1 100644 --- a/interface/resources/serverless/Scripts/Wizard.qml +++ b/interface/resources/serverless/Scripts/Wizard.qml @@ -49,7 +49,7 @@ Rectangle { loader.sourceComponent = step5; break; default: - loader.setSource(undefined); + loader.setSource(""); } } diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp index e5007d706e8..f242273479a 100644 --- a/interface/src/AndroidHelper.cpp +++ b/interface/src/AndroidHelper.cpp @@ -23,7 +23,7 @@ #define qApp (static_cast(QCoreApplication::instance())) AndroidHelper::AndroidHelper() { - qRegisterMetaType("QAudio::Mode"); + qRegisterMetaType("QAudioDevice::Mode"); } AndroidHelper::~AndroidHelper() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5c878abde76..7216b8fb2ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -14,7 +14,6 @@ #include "Application.h" -#include #include #include #include @@ -216,7 +215,9 @@ Application::Application( ) : QApplication(argc, argv), #ifdef USE_GL - _window(new MainWindow(desktop())), + // QT6TODO: is this correct? + _window(new MainWindow()), + //_window(new MainWindow(desktop())), #else _vkWindow(new VKWindow()), _vkWindowWrapper(QWidget::createWindowContainer(_vkWindow)), @@ -235,6 +236,15 @@ Application::Application( _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), _previousPreferredDisplayMode("previousPreferredDisplayMode", 0), // UI + _virtualPointingDevice(std::make_shared( + "OffscreenUiPointingDevice", + 0, + QInputDevice::DeviceType::AllDevices, + QPointingDevice::PointerType::AllPointerTypes, + QInputDevice::Capability::All, + 4, // maxPoints + 2 // buttonCount + )), _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), _desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT), _desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR), @@ -415,7 +425,7 @@ QString Application::getUserAgent() { if (QThread::currentThread() != thread()) { QString userAgent; - BLOCKING_INVOKE_METHOD(this, "getUserAgent", Q_RETURN_ARG(QString, userAgent)); + BLOCKING_INVOKE_METHOD(this, "getUserAgent", Q_GENERIC_RETURN_ARG(QString, userAgent)); return userAgent; } @@ -611,7 +621,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptManagerPoint scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get().data()); #if !defined(DISABLE_QML) - scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); + // QT6TODO: Stats instance is not created? + //scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); #endif scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Snapshot", DependencyManager::get().data()); @@ -1004,7 +1015,7 @@ std::map Application::prepareServerlessDomainContents(QUrl dom void Application::loadServerlessDomain(QUrl domainURL) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_ARG(QUrl, domainURL)); + QMetaObject::invokeMethod(this, "loadServerlessDomain", Q_GENERIC_ARG(QUrl, domainURL)); return; } @@ -1036,7 +1047,7 @@ void Application::loadServerlessDomain(QUrl domainURL) { void Application::loadErrorDomain(QUrl domainURL) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadErrorDomain", Q_ARG(QUrl, domainURL)); + QMetaObject::invokeMethod(this, "loadErrorDomain", Q_GENERIC_ARG(QUrl, domainURL)); return; } diff --git a/interface/src/Application.h b/interface/src/Application.h index f38f6dff04f..3fdd259924e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -94,6 +94,8 @@ class Application : public QApplication, ); ~Application(); + bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted); + /** * @brief Initialize everything * @@ -178,6 +180,8 @@ class Application : public QApplication, const ApplicationOverlay& getApplicationOverlay() const { return *_applicationOverlay; } CompositorHelper& getApplicationCompositor() const; + std::shared_ptr getVirtualPointingDevice() const; + virtual PickRay computePickRay(float x, float y) const override; static void setupQmlSurface(QQmlContext* surfaceContext, bool setAdditionalContextProperties); @@ -326,7 +330,8 @@ class Application : public QApplication, int getMaxOctreePacketsPerSecond() const { return _maxOctreePPS; } bool isMissingSequenceNumbers() { return _isMissingSequenceNumbers; } - NodeToOctreeSceneStats* getOcteeSceneStats() { return _octreeProcessor->getOctreeSceneStats(); } + // This function returns a value only when octree processor is available. + std::optional getOcteeSceneStats(); // Assets @@ -790,6 +795,8 @@ private slots: bool _cursorNeedsChanging { false }; bool _useSystemCursor { false }; + std::shared_ptr _virtualPointingDevice; + DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface; QPointer _logDialog; @@ -854,7 +861,13 @@ private slots: // Events - QHash _keysPressed; + class KeyEventRecord { + public: + KeyEventRecord(const int key, const QString &text) : key(key), text(text) {} + int key; + QString text; + }; + QHash _keysPressed; TouchEvent _lastTouchEvent; quint64 _lastAcceptedKeyPress { 0 }; diff --git a/interface/src/ApplicationEventHandler.h b/interface/src/ApplicationEventHandler.h index d7e5bf171c7..7a252d3b171 100644 --- a/interface/src/ApplicationEventHandler.h +++ b/interface/src/ApplicationEventHandler.h @@ -24,10 +24,12 @@ #include "Application.h" #ifdef Q_OS_WIN -static const UINT UWM_IDENTIFY_INSTANCES = - RegisterWindowMessage("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qgetenv("USERNAME")); -static const UINT UWM_SHOW_APPLICATION = - RegisterWindowMessage("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}_" + qgetenv("USERNAME")); +#include + +static const UINT UWM_IDENTIFY_INSTANCES = RegisterWindowMessage( + qUtf16Printable("UWM_IDENTIFY_INSTANCES_{8AB82783-B74A-4258-955B-8188C22AA0D6}_" + qEnvironmentVariable("USERNAME"))); +static const UINT UWM_SHOW_APPLICATION = RegisterWindowMessage( + qUtf16Printable("UWM_SHOW_APPLICATION_{71123FD6-3DA8-4DC1-9C27-8A12A6250CBA}_" + qEnvironmentVariable("USERNAME"))); class MyNativeEventFilter : public QAbstractNativeEventFilter { public: @@ -36,7 +38,7 @@ class MyNativeEventFilter : public QAbstractNativeEventFilter { return staticInstance; } - bool nativeEventFilter(const QByteArray &eventType, void* msg, long* result) Q_DECL_OVERRIDE { + bool nativeEventFilter(const QByteArray& eventType, void* msg, qintptr* result) Q_DECL_OVERRIDE { if (eventType == "windows_generic_MSG") { MSG* message = (MSG*)msg; diff --git a/interface/src/Application_Assets.cpp b/interface/src/Application_Assets.cpp index 96404063b67..4ac698786e0 100644 --- a/interface/src/Application_Assets.cpp +++ b/interface/src/Application_Assets.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -171,7 +172,7 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip) { QString mapping; QString filename = filenameFromPath(path); if (isZip) { - QString assetName = zipFile.section("/", -1).remove(QRegExp("[.]zip(.*)$")); + QString assetName = zipFile.section("/", -1).remove(QRegularExpression("[.]zip(.*)$")); QString assetFolder = path.section("model_repo/", -1); mapping = "/" + assetName + "/" + assetFolder; } else { diff --git a/interface/src/Application_Entities.cpp b/interface/src/Application_Entities.cpp index fec3dd5d99a..848906cbc43 100644 --- a/interface/src/Application_Entities.cpp +++ b/interface/src/Application_Entities.cpp @@ -36,6 +36,15 @@ void Application::setMaxOctreePacketsPerSecond(int maxOctreePPS) { } } +std::optional Application::getOcteeSceneStats() { + // On start this function is sometimes called before _octreeProcessor is available. + if (_octreeProcessor) { + return _octreeProcessor->getOctreeSceneStats(); + } else { + return {}; + } +} + QVector Application::pasteEntities(const QString& entityHostType, float x, float y, float z) { return _entityClipboard->sendEntities(_entityEditSender.get(), getEntities()->getTree(), entityHostType, x, y, z); } @@ -231,9 +240,11 @@ void Application::clearDomainOctreeDetails(bool clearAll) { setIsInterstitialMode(true); auto octreeServerSceneStats = getOcteeSceneStats(); - octreeServerSceneStats->withWriteLock([&] { - octreeServerSceneStats->clear(); - }); + if (octreeServerSceneStats) { + octreeServerSceneStats.value()->withWriteLock([&] { + octreeServerSceneStats.value()->clear(); + }); + } // reset the model renderer clearAll ? getEntities()->clear() : getEntities()->clearDomainAndNonOwnedEntities(); @@ -331,16 +342,18 @@ int Application::sendNackPackets() { QSet missingSequenceNumbers; auto octreeServerSceneStats = getOcteeSceneStats(); - octreeServerSceneStats->withReadLock([&] { - // retrieve octree scene stats of this node - if (octreeServerSceneStats->find(nodeUUID) == octreeServerSceneStats->end()) { - return; - } - // get sequence number stats of node, prune its missing set, and make a copy of the missing set - SequenceNumberStats& sequenceNumberStats = (*octreeServerSceneStats)[nodeUUID].getIncomingOctreeSequenceNumberStats(); - sequenceNumberStats.pruneMissingSet(); - missingSequenceNumbers = sequenceNumberStats.getMissingSet(); - }); + if (octreeServerSceneStats) { + octreeServerSceneStats.value()->withReadLock([&] { + // retrieve octree scene stats of this node + if (octreeServerSceneStats.value()->find(nodeUUID) == octreeServerSceneStats.value()->end()) { + return; + } + // get sequence number stats of node, prune its missing set, and make a copy of the missing set + SequenceNumberStats& sequenceNumberStats = (*octreeServerSceneStats.value())[nodeUUID].getIncomingOctreeSequenceNumberStats(); + sequenceNumberStats.pruneMissingSet(); + missingSequenceNumbers = sequenceNumberStats.getMissingSet(); + }); + } _isMissingSequenceNumbers = (missingSequenceNumbers.size() != 0); diff --git a/interface/src/Application_Events.cpp b/interface/src/Application_Events.cpp index cd3a9327e48..d29c92c9338 100644 --- a/interface/src/Application_Events.cpp +++ b/interface/src/Application_Events.cpp @@ -55,6 +55,10 @@ class LambdaEvent : public QEvent { void call() const { _fun(); } }; +std::shared_ptr Application::getVirtualPointingDevice() const { + return _virtualPointingDevice; +} + bool Application::notify(QObject* object, QEvent* event) { if (thread() == QThread::currentThread()) { PROFILE_RANGE_IF_LONGER(app, "notify", 2) @@ -211,7 +215,8 @@ bool Application::eventFilter(QObject* object, QEvent* event) { QMouseEvent* newEvent = new QMouseEvent( QEvent::MouseButtonPress, mouseEvent->localPos(), mouseEvent->windowPos(), mouseEvent->screenPos(), Qt::RightButton, Qt::MouseButtons(Qt::RightButton), - mouseEvent->modifiers()); + mouseEvent->modifiers(), + getVirtualPointingDevice().get()); QApplication::postEvent(object, newEvent); return true; } @@ -336,7 +341,7 @@ void Application::windowMinimizedChanged(bool minimized) { void Application::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - _keysPressed.insert(event->key(), *event); + _keysPressed.insert(event->key(), KeyEventRecord(event->key(), event->text())); } _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts @@ -607,10 +612,10 @@ void Application::synthesizeKeyReleasEvents() { // synthesize events for keys currently pressed, since we may not get their release events // Because our key event handlers may manipulate _keysPressed, lets swap the keys pressed into a local copy, // clearing the existing list. - QHash keysPressed; + QHash keysPressed; std::swap(keysPressed, _keysPressed); - for (auto& ev : keysPressed) { - QKeyEvent synthesizedEvent { QKeyEvent::KeyRelease, ev.key(), Qt::NoModifier, ev.text() }; + for (auto& eventRecord : keysPressed) { + QKeyEvent synthesizedEvent { QKeyEvent::KeyRelease, eventRecord.key, Qt::NoModifier, eventRecord.text }; keyReleaseEvent(&synthesizedEvent); } } @@ -652,11 +657,13 @@ void Application::mouseMoveEvent(QMouseEvent* event) { QMouseEvent mappedEvent(event->type(), transformedPos, - event->screenPos(), button, - buttons, event->modifiers()); + event->globalPosition(), button, + buttons, event->modifiers(), + getVirtualPointingDevice().get()); if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_ENTITY_ID) { + // QT6TODO: compositor.getReticleOverDesktop() does not work currently. getEntities()->mouseMoveEvent(&mappedEvent); } @@ -687,7 +694,12 @@ void Application::mousePressEvent(QMouseEvent* event) { QPointF transformedPos; #endif - QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), event->buttons(), event->modifiers()); + QMouseEvent mappedEvent(event->type(), + transformedPos, + event->globalPosition(), event->button(), + event->buttons(), event->modifiers(), + getVirtualPointingDevice().get()); + QUuid result = getEntities()->mousePressEvent(&mappedEvent); setKeyboardFocusEntity(getEntities()->wantsKeyboardFocus(result) ? result : UNKNOWN_ENTITY_ID); @@ -726,8 +738,9 @@ void Application::mouseDoublePressEvent(QMouseEvent* event) { #endif QMouseEvent mappedEvent(event->type(), transformedPos, - event->screenPos(), event->button(), - event->buttons(), event->modifiers()); + event->globalPosition(), event->button(), + event->buttons(), event->modifiers(), + getVirtualPointingDevice().get()); getEntities()->mouseDoublePressEvent(&mappedEvent); // if one of our scripts have asked to capture this event, then stop processing it @@ -748,8 +761,9 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { #endif QMouseEvent mappedEvent(event->type(), transformedPos, - event->screenPos(), event->button(), - event->buttons(), event->modifiers()); + event->globalPosition(), event->button(), + event->buttons(), event->modifiers(), + getVirtualPointingDevice().get()); getEntities()->mouseReleaseEvent(&mappedEvent); diff --git a/interface/src/Application_Graphics.cpp b/interface/src/Application_Graphics.cpp index a7e7c7e217d..401c0d50dfd 100644 --- a/interface/src/Application_Graphics.cpp +++ b/interface/src/Application_Graphics.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -57,6 +58,8 @@ #include "Menu.h" #include "webbrowser/WebBrowserSuggestionsEngine.h" +#include + #if defined(Q_OS_ANDROID) #include "AndroidHelper.h" #endif @@ -81,6 +84,7 @@ void Application::initializeGL() { } #ifdef USE_GL + _primaryWidget->windowHandle()->setSurfaceType(QSurface::OpenGLSurface); _primaryWidget->windowHandle()->setFormat(getDefaultOpenGLSurfaceFormat()); #else //_primaryWidget->windowHandle()->setFormat(getDefaultOpenGLSurfaceFormat()); // VKTODO @@ -163,6 +167,7 @@ void Application::initializeGL() { { OffscreenGLCanvas* qmlShareContext = new OffscreenGLCanvas(); qmlShareContext->setObjectName("QmlShareContext"); + qmlShareContext->getContext()->setFormat(getDefaultOpenGLSurfaceFormat()); qmlShareContext->create(globalShareContext); if (!qmlShareContext->makeCurrent()) { qCWarning(interfaceapp, "Unable to make QML shared context current"); @@ -222,7 +227,7 @@ static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, in } auto parent = menu->getMenu(MenuOption::OutputMenu); auto action = menu->addActionToQMenuAndActionHash(parent, - name, QKeySequence(Qt::CTRL + (Qt::Key_0 + index)), qApp, + name, QKeySequence(Qt::CTRL | static_cast(static_cast(Qt::Key_0) + index)), qApp, SLOT(updateDisplayMode()), QAction::NoRole, Menu::UNSPECIFIED_POSITION, groupingMenu); @@ -243,12 +248,12 @@ void Application::initializeUi() { auto newValidator = [=](const QUrl& url) -> bool { QString allowlistPrefix = "[ALLOWLIST ENTITY SCRIPTS]"; QList safeURLS = { "" }; - safeURLS += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts); + safeURLS += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegularExpression("\\s*,\\s*"), Qt::SkipEmptyParts); // PULL SAFEURLS FROM INTERFACE.JSON Settings QVariant raw = Setting::Handle("private/settingsSafeURLS").get(); - QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegExp("\\s*[,\r\n]+\\s*"), Qt::SkipEmptyParts); + QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegularExpression("\\s*[,\r\n]+\\s*"), Qt::SkipEmptyParts); safeURLS += settingsSafeURLS; // END PULL SAFEURLS FROM INTERFACE.JSON Settings diff --git a/interface/src/Application_Setup.cpp b/interface/src/Application_Setup.cpp index ee8fa932c95..f85ddb42a9e 100644 --- a/interface/src/Application_Setup.cpp +++ b/interface/src/Application_Setup.cpp @@ -250,7 +250,7 @@ static const int WATCHDOG_TIMER_TIMEOUT = 100; static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt"; #endif -bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted) { +bool Application::setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted) { const int listenPort = parser.isSet("listenPort") ? parser.value("listenPort").toInt() : INVALID_PORT; bool suppressPrompt = parser.isSet("suppress-settings-reset"); @@ -329,6 +329,8 @@ bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted DependencyManager::set(); DependencyManager::set(); DependencyManager::set(NodeType::Agent, listenPort); + // Octree processor requires NodeList. + _octreeProcessor = std::make_shared(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); // ModelFormatRegistry must be defined before ModelCache. See the ModelCache constructor. @@ -414,7 +416,14 @@ bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted DependencyManager::set(); - DependencyManager::set(nullptr, qApp->getOcteeSceneStats()); + { + auto octreeSceneStats = qApp->getOcteeSceneStats(); + if (!octreeSceneStats) { + qCritical() << "setupEssentials: Octree stats provider not available yet. This should never happen"; + std::abort(); + } + DependencyManager::set(nullptr, octreeSceneStats.value()); + } DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -459,7 +468,6 @@ void Application::initialize(const QCommandLineParser &parser) { _entitySimulation = std::make_shared(); _physicsEngine = std::make_shared(Vectors::ZERO); _entityClipboard = std::make_shared(); - _octreeProcessor = std::make_shared(); _entityEditSender = std::make_shared(); _graphicsEngine = std::make_shared(); _applicationOverlay = std::make_shared(); @@ -658,6 +666,14 @@ void Application::initialize(const QCommandLineParser &parser) { QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-SemiBold.ttf"); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-Regular.ttf"); QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/FiraSans-Medium.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Roboto-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Roboto-Bold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Roboto-Italic.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Roboto-BoldItalic.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/RobotoMono-Regular.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/RobotoMono-Bold.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/RobotoMono-Italic.ttf"); + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/RobotoMono-BoldItalic.ttf"); _window->setWindowTitle("Overte"); Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us @@ -762,7 +778,8 @@ void Application::initialize(const QCommandLineParser &parser) { << NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer); // setDefaultFormat has no effect after the platform window has been created, so call it here. - QSurfaceFormat::setDefaultFormat(getDefaultOpenGLSurfaceFormat()); + // QT6TODO: I was getting a warning when it was here, so I moved it to the beginning. + //QSurfaceFormat::setDefaultFormat(getDefaultOpenGLSurfaceFormat()); #ifdef USE_GL _primaryWidget = new GLCanvas(); @@ -876,14 +893,17 @@ void Application::initialize(const QCommandLineParser &parser) { { "gl_renderer", glContextData.renderer.c_str() }, { "ideal_thread_count", QThread::idealThreadCount() } }; +#ifdef Q_OS_MAC auto macVersion = QSysInfo::macVersion(); if (macVersion != QSysInfo::MV_None) { properties["os_osx_version"] = QSysInfo::macVersion(); } +#elifdef Q_OS_WIN auto windowsVersion = QSysInfo::windowsVersion(); if (windowsVersion != QSysInfo::WV_None) { properties["os_win_version"] = QSysInfo::windowsVersion(); } +#endif ProcessorInfo procInfo; if (getProcessorInfo(procInfo)) { @@ -1194,10 +1214,12 @@ void Application::initialize(const QCommandLineParser &parser) { properties["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount; properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount; - NodeToOctreeSceneStats* octreeServerSceneStats = getOcteeSceneStats(); + auto octreeServerSceneStats = getOcteeSceneStats(); unsigned long totalServerOctreeElements = 0; - for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { - totalServerOctreeElements += i->second.getTotalElements(); + if (octreeServerSceneStats) { + for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats.value()->begin(); i != octreeServerSceneStats.value()->end(); i++) { + totalServerOctreeElements += i->second.getTotalElements(); + } } properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount(); @@ -2007,11 +2029,11 @@ void Application::setupSignalsAndOperators() { auto reticlePos = getApplicationCompositor().getReticlePosition(); QPoint localPos(reticlePos.x, reticlePos.y); // both hmd and desktop already handle this in our coordinates. if (state) { - QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QMouseEvent mousePress(QEvent::MouseButtonPress, localPos, localPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier, getVirtualPointingDevice().get()); sendEvent(_primaryWidget, &mousePress); _reticleClickPressed = true; } else { - QMouseEvent mouseRelease(QEvent::MouseButtonRelease, localPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); + QMouseEvent mouseRelease(QEvent::MouseButtonRelease, localPos, localPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier, getVirtualPointingDevice().get()); sendEvent(_primaryWidget, &mouseRelease); _reticleClickPressed = false; } diff --git a/interface/src/Application_UI.cpp b/interface/src/Application_UI.cpp index 53e8600b717..534acc599be 100644 --- a/interface/src/Application_UI.cpp +++ b/interface/src/Application_UI.cpp @@ -84,6 +84,7 @@ #include #include #include +#include #include "AboutUtil.h" #include "ArchiveDownloadInterface.h" @@ -229,7 +230,10 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona surfaceContext->setContextProperty("offscreenFlags", flags); surfaceContext->setContextProperty("AddressManager", DependencyManager::get().data()); + // TODO: Replace Settings (conflicts with QtCore.Settings) with SettingsInterface surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); + surfaceContext->setContextProperty("SettingsInterface", new QMLSettingsScriptingInterface(surfaceContext)); + surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); surfaceContext->setContextProperty("Performance", new PerformanceScriptingInterface()); @@ -258,8 +262,16 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona surfaceContext->setContextProperty("Workload", qApp->getGameWorkload()._engine->getConfiguration().get()); surfaceContext->setContextProperty("Controller", DependencyManager::get().data()); surfaceContext->setContextProperty("Pointers", DependencyManager::get().data()); + + // QT6TODO: replace all of the instances of "Window" in QML with WindowScriptingInterface surfaceContext->setContextProperty("Window", DependencyManager::get().data()); + + // There's a lot of stuff in our QML called "Window", + // so this needs to be WindowScriptingInterface + surfaceContext->setContextProperty("WindowScriptingInterface", DependencyManager::get().data()); + surfaceContext->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface()); + surfaceContext->setContextProperty("PickScriptingInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("About", AboutUtil::getInstance()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); // Deprecated. surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); @@ -580,7 +592,7 @@ void Application::showAssetServerWidget(QString filePath) { if (!DependencyManager::get()->getThisNodeCanWriteAssets() || getLoginDialogPoppedUp()) { return; } - static const QUrl url { "hifi/AssetServer.qml" }; + static const QUrl url { "overte/compat/CompatAssetDialog.qml" }; auto startUpload = [=, this](QQmlContext* context, QObject* newObject){ if (!filePath.isEmpty()) { @@ -596,7 +608,7 @@ void Application::showAssetServerWidget(QString filePath) { if (!hmd->getShouldShowTablet() && !isHMDMode()) { getOffscreenUI()->show(url, "AssetServer", startUpload); } else { - static const QUrl url("qrc:///qml/hifi/dialogs/TabletAssetServer.qml"); + static const QUrl url("qrc:///qml/overte/dialogs/AssetDialog.qml"); if (!tablet->isPathLoaded(url)) { tablet->pushOntoStack(url); } @@ -901,6 +913,9 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("Assets", DependencyManager::get().data()); surfaceContext->setContextProperty("Keyboard", DependencyManager::get().data()); + // TODO: replace instances of Keyboard with KeyboardScriptingInterface + surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get().data()); + surfaceContext->setContextProperty("AvatarList", DependencyManager::get().data()); surfaceContext->setContextProperty("Users", DependencyManager::get().data()); @@ -912,10 +927,21 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { #endif surfaceContext->setContextProperty("Overlays", &_overlays); + + // QT6TODO: replace all of the instances of "Window" in QML with WindowScriptingInterface surfaceContext->setContextProperty("Window", DependencyManager::get().data()); + + // There's a lot of stuff in our QML called "Window", + // so this needs to be WindowScriptingInterface + surfaceContext->setContextProperty("WindowScriptingInterface", DependencyManager::get().data()); + surfaceContext->setContextProperty("Desktop", DependencyManager::get().data()); surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); + + // TODO: Replace Settings (conflicts with QtCore.Settings) with SettingsInterface surfaceContext->setContextProperty("Settings", new QMLSettingsScriptingInterface(surfaceContext)); + surfaceContext->setContextProperty("SettingsInterface", new QMLSettingsScriptingInterface(surfaceContext)); + surfaceContext->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); surfaceContext->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get().data()); @@ -941,6 +967,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("Render", RenderScriptingInterface::getInstance()); surfaceContext->setContextProperty("PlatformInfo", PlatformInfoScriptingInterface::getInstance()); surfaceContext->setContextProperty("Workload", _gameWorkload._engine->getConfiguration().get()); + surfaceContext->setContextProperty("PickScriptingInterface", DependencyManager::get().data()); surfaceContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface()); surfaceContext->setContextProperty("Snapshot", DependencyManager::get().data()); @@ -981,7 +1008,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { } // Download the FST file, to attempt to determine its model type - QVariantHash fstMapping = FSTReader::downloadMapping(url); + hifi::VariantMultiHash fstMapping = FSTReader::downloadMapping(url); FSTReader::ModelType modelType = FSTReader::predictModelType(fstMapping); @@ -1462,7 +1489,7 @@ void Application::addAssetToWorldError(QString modelName, QString errorText) { void Application::setMenuBarVisible(bool visible) { if (QThread::currentThread() != qApp->thread()) { - QMetaObject::invokeMethod(this, "setMenuBarVisible", Q_ARG(bool, visible)); + QMetaObject::invokeMethod(this, "setMenuBarVisible", Q_GENERIC_ARG(bool, visible)); return; } diff --git a/interface/src/ArchiveDownloadInterface.cpp b/interface/src/ArchiveDownloadInterface.cpp index d82fd0bec2e..ea187ab051e 100644 --- a/interface/src/ArchiveDownloadInterface.cpp +++ b/interface/src/ArchiveDownloadInterface.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 8410aadebe7..14dad5201f6 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -139,7 +139,7 @@ void AvatarBookmarks::addBookmark(const QString& bookmarkName) { void AvatarBookmarks::addBookmarkInternal(const QString& bookmarkName) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "addBookmark", Q_ARG(QString, bookmarkName)); + BLOCKING_INVOKE_METHOD(this, "addBookmark", Q_GENERIC_ARG(QString, bookmarkName)); return; } QVariantMap bookmark = getAvatarDataToBookmark(); @@ -156,7 +156,7 @@ void AvatarBookmarks::saveBookmark(const QString& bookmarkName) { void AvatarBookmarks::saveBookmarkInternal(const QString& bookmarkName) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "saveBookmark", Q_ARG(QString, bookmarkName)); + BLOCKING_INVOKE_METHOD(this, "saveBookmark", Q_GENERIC_ARG(QString, bookmarkName)); return; } if (contains(bookmarkName)) { @@ -173,7 +173,7 @@ void AvatarBookmarks::removeBookmark(const QString& bookmarkName) { void AvatarBookmarks::removeBookmarkInternal(const QString& bookmarkName) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "removeBookmark", Q_ARG(QString, bookmarkName)); + BLOCKING_INVOKE_METHOD(this, "removeBookmark", Q_GENERIC_ARG(QString, bookmarkName)); return; } @@ -229,7 +229,7 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { void AvatarBookmarks::loadBookmarkInternal(const QString& bookmarkName) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "loadBookmark", Q_ARG(QString, bookmarkName)); + BLOCKING_INVOKE_METHOD(this, "loadBookmark", Q_GENERIC_ARG(QString, bookmarkName)); return; } @@ -276,7 +276,7 @@ void AvatarBookmarks::loadBookmarkInternal(const QString& bookmarkName) { void AvatarBookmarks::readFromFile() { // migrate old avatarbookmarks.json, used to be in 'local' folder on windows - QString oldConfigPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + AVATARBOOKMARKS_FILENAME; + QString oldConfigPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + AVATARBOOKMARKS_FILENAME; QFile oldConfig(oldConfigPath); // I imagine that in a year from now, this code for migrating (as well as the two lines above) @@ -306,7 +306,7 @@ QVariantMap AvatarBookmarks::getBookmarkInternal(const QString &bookmarkName) { if (QThread::currentThread() != thread()) { QVariantMap result; - BLOCKING_INVOKE_METHOD(this, "getBookmark", Q_RETURN_ARG(QVariantMap, result), Q_ARG(QString, bookmarkName)); + BLOCKING_INVOKE_METHOD(this, "getBookmark", Q_GENERIC_RETURN_ARG(QVariantMap, result), Q_GENERIC_ARG(QString, bookmarkName)); return result; } @@ -368,3 +368,50 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities); return bookmark; } + +void AvatarBookmarks::setBookmarkData(const QString& bookmarkName, const QVariantMap& data) { + if (!ScriptPermissions::isCurrentScriptAllowed(ScriptPermissions::Permission::SCRIPT_PERMISSION_GET_AVATAR_URL)) { + return; + } + + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD( + this, + "setBookmarkData", + Q_GENERIC_ARG(QString, bookmarkName), + Q_GENERIC_ARG(QVariantMap, data) + ); + return; + } + + auto sanitizedData = data; + + if (!sanitizedData.contains(ENTRY_VERSION)) { + sanitizedData.insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION); + } + + if (!sanitizedData.contains(ENTRY_AVATAR_URL)) { + qCritical() << "setBookmarkData called without \"avatarUrl\" field!"; + return; + } + + if (!sanitizedData.contains(ENTRY_AVATAR_ICON)) { + sanitizedData.insert(ENTRY_AVATAR_ICON, ""); + } + + if (!sanitizedData.contains(ENTRY_AVATAR_SCALE)) { + sanitizedData.insert(ENTRY_AVATAR_SCALE, 1.0); + } + + if (!sanitizedData.contains(ENTRY_AVATAR_ENTITIES)) { + sanitizedData.insert(ENTRY_AVATAR_ENTITIES, QVariantList()); + } + + auto alreadyExists = contains(bookmarkName); + + insert(bookmarkName, sanitizedData); + + if (!alreadyExists) { + emit bookmarkAdded(bookmarkName); + } +} diff --git a/interface/src/AvatarBookmarks.h b/interface/src/AvatarBookmarks.h index 40d862b83ed..8eccc545fcb 100644 --- a/interface/src/AvatarBookmarks.h +++ b/interface/src/AvatarBookmarks.h @@ -105,6 +105,22 @@ public slots: */ QVariantMap getBookmarks(); + /*@jsdoc + * Directly sets the data object of a bookmark. + * @function AvatarBookmarks.setBookmarkData + * @param {string} - The name of the bookmark. If no bookmark with the specified name exists, it will be created. Otherwise, it will edit the existing one. + * @param {object} - The bookmark data. See the example below for valid keys and their defaults. + * @example + * AvatarBookmarks.setBookmarkData("Woody", { + * version: 3, + * avatarScale: 1.0, + * avatarEntities: [], + * avatarIcon: "", + * avatarUrl: "qrc:///meshes/defaultAvatar_full.fst", + * }); + */ + void setBookmarkData(const QString& bookmarkName, const QVariantMap& data); + signals: /*@jsdoc * Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities to those in the bookmark. diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 624d5430a26..5c64f3f81a2 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -145,7 +145,7 @@ void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply* requestReply // give that session ID to the account manager auto accountManager = DependencyManager::get(); - accountManager->setSessionID(sessionID); + accountManager->setSessionID(QUuid(sessionID)); } } diff --git a/interface/src/LocationBookmarks.cpp b/interface/src/LocationBookmarks.cpp index 8a10e636ae3..3ac51996330 100644 --- a/interface/src/LocationBookmarks.cpp +++ b/interface/src/LocationBookmarks.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -25,7 +26,7 @@ const QString LocationBookmarks::HOME_BOOKMARK = "Home"; LocationBookmarks::LocationBookmarks() { - _bookmarksFilename = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + LOCATIONBOOKMARKS_FILENAME; + _bookmarksFilename = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + LOCATIONBOOKMARKS_FILENAME; readFromFile(); } @@ -104,7 +105,7 @@ void LocationBookmarks::addBookmark() { disconnect(dlg, &ModalDialogListener::response, this, nullptr); auto bookmarkName = response.toString(); - bookmarkName = bookmarkName.trimmed().replace(QRegExp("(\r\n|[\r\n\t\v ])+"), " "); + bookmarkName = bookmarkName.trimmed().replace(QRegularExpression("(\r\n|[\r\n\t\v ])+"), " "); if (bookmarkName.length() == 0) { return; } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b7982f57f70..ee655fbb3ad 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -19,6 +19,7 @@ // QT6TODO: The Key Enums should be replaced by QKeyCombination in Qt6 #include "Menu.h" +#include #include #include #include @@ -97,6 +98,8 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } + // Qt6 TODO: This crashes when the domain changes, maybe a thread safety thing? +#if 0 auto domainLogin = addActionToQMenuAndActionHash(fileMenu, "Domain: Log In"); domainLogin->setVisible(false); connect(domainLogin, &QAction::triggered, [] { @@ -107,6 +110,7 @@ Menu::Menu() { connect(domainAccountManager.data(), &DomainAccountManager::hasLogInChanged, [domainLogin](bool hasLogIn) { domainLogin->setVisible(hasLogIn); }); +#endif // File > Quit addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, static_cast(Qt::CTRL) | static_cast(Qt::Key_Q), qApp, SLOT(quit()), QAction::QuitRole); @@ -149,8 +153,8 @@ Menu::Menu() { auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, static_cast(Qt::CTRL) | static_cast(Qt::Key_J)); connect(action, &QAction::triggered, [] { if (!qApp->getLoginDialogPoppedUp()) { - static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml"); - static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml"); + static const QUrl widgetUrl("overte/compat/RunningScripts_Window.qml"); + static const QUrl tabletUrl("overte/dialogs/RunningScriptsDialog.qml"); static const QString name("RunningScripts"); qApp->showDialog(widgetUrl, tabletUrl, name); } @@ -255,8 +259,11 @@ Menu::Menu() { // Settings menu ---------------------------------- MenuWrapper* settingsMenu = addMenu("Settings"); + // Legacy settings, some stuff isn't accessible from the new one yet + MenuWrapper *legacySettingsMenu = settingsMenu->addMenu("Legacy"); + // Settings > General... - action = addActionToQMenuAndActionHash(settingsMenu, MenuOption::Preferences, static_cast(Qt::CTRL) | static_cast(Qt::Key_G), nullptr, nullptr); + action = addActionToQMenuAndActionHash(legacySettingsMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_G, nullptr, nullptr); connect(action, &QAction::triggered, [] { if (!qApp->getLoginDialogPoppedUp()) { qApp->showDialog(QString("hifi/dialogs/GeneralPreferencesDialog.qml"), @@ -265,7 +272,7 @@ Menu::Menu() { }); // Settings > Controls... - action = addActionToQMenuAndActionHash(settingsMenu, "Controls..."); + action = addActionToQMenuAndActionHash(legacySettingsMenu, "Controls..."); connect(action, &QAction::triggered, [] { auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); auto hmd = DependencyManager::get(); @@ -277,7 +284,7 @@ Menu::Menu() { }); // Settings > Audio... - action = addActionToQMenuAndActionHash(settingsMenu, "Audio..."); + action = addActionToQMenuAndActionHash(legacySettingsMenu, "Audio..."); connect(action, &QAction::triggered, [] { static const QUrl tabletUrl("hifi/audio/Audio.qml"); auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index e6f7c508408..56e1199badb 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -23,6 +23,7 @@ #include "ModelSelector.h" #include "ModelPropertiesDialog.h" #include "InterfaceLogging.h" +#include "shared/QtHelpers.h" static const int MAX_TEXTURE_SIZE = 8192; @@ -109,7 +110,7 @@ bool ModelPackager::loadModel() { qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath(); QByteArray fbxContents = fbx.readAll(); - _hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), _fbxInfo.filePath()); + _hfmModel = FBXSerializer().read(fbxContents, hifi::VariantMultiHash(), _fbxInfo.filePath()); // make sure we have some basic mappings populateBasicMapping(_mapping, _fbxInfo.filePath(), *_hfmModel); @@ -233,7 +234,7 @@ bool ModelPackager::zipModel() { return true; } -void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const hfm::Model& hfmModel) { +void ModelPackager::populateBasicMapping(hifi::VariantMultiHash& mapping, QString filename, const hfm::Model& hfmModel) { // mixamo files - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will // be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file @@ -349,7 +350,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); blendshapes.insert("Sneer", QVariantList() << "Squint_Left" << 0.5); blendshapes.insert("Sneer", QVariantList() << "Squint_Right" << 0.5); - mapping.insert(BLENDSHAPE_FIELD, blendshapes); + mapping.insert(BLENDSHAPE_FIELD, qMultiHashToQVariant(blendshapes)); } } diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index 9a2a49562a6..245a5632d90 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -34,7 +34,7 @@ class ModelPackager : public QObject { bool editProperties(); bool zipModel(); - void populateBasicMapping(QVariantHash& mapping, QString filename, const hfm::Model& hfmModel); + void populateBasicMapping(hifi::VariantMultiHash& mapping, QString filename, const hfm::Model& hfmModel); void listTextures(); bool copyTextures(const QString& oldDir, const QDir& newDir); diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index d67341990db..33c39fcb3c6 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -25,8 +25,10 @@ #include #include +#include "shared/QtHelpers.h" -ModelPropertiesDialog::ModelPropertiesDialog(const QVariantHash& originalMapping, + +ModelPropertiesDialog::ModelPropertiesDialog(const hifi::VariantMultiHash& originalMapping, const QString& basePath, const HFMModel& hfmModel) : _originalMapping(originalMapping), _basePath(basePath), @@ -70,8 +72,8 @@ _hfmModel(hfmModel) reset(); } -QVariantHash ModelPropertiesDialog::getMapping() const { - QVariantHash mapping = _originalMapping; +hifi::VariantMultiHash ModelPropertiesDialog::getMapping() const { + hifi::VariantMultiHash mapping = _originalMapping; mapping.insert(TYPE_FIELD, FSTReader::getNameFromType(FSTReader::HEAD_AND_BODY_MODEL)); mapping.insert(NAME_FIELD, _name->text()); mapping.insert(TEXDIR_FIELD, _textureDirectory->text()); @@ -85,7 +87,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { } mapping.insert(JOINT_INDEX_FIELD, jointIndices); - QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); + hifi::VariantMultiHash joints = qVariantToQMultiHash(mapping.value(JOINT_FIELD)); insertJointMapping(joints, "jointEyeLeft", _leftEyeJoint->currentText()); insertJointMapping(joints, "jointEyeRight", _rightEyeJoint->currentText()); insertJointMapping(joints, "jointNeck", _neckJoint->currentText()); @@ -97,7 +99,7 @@ QVariantHash ModelPropertiesDialog::getMapping() const { insertJointMapping(joints, "jointLeftHand", _leftHandJoint->currentText()); insertJointMapping(joints, "jointRightHand", _rightHandJoint->currentText()); - mapping.insert(JOINT_FIELD, joints); + mapping.insert(JOINT_FIELD, qMultiHashToQVariant(joints)); return mapping; } @@ -177,7 +179,7 @@ QDoubleSpinBox* ModelPropertiesDialog::createTranslationBox() const { return box; } -void ModelPropertiesDialog::insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const { +void ModelPropertiesDialog::insertJointMapping(hifi::VariantMultiHash& joints, const QString& joint, const QString& name) const { if (_hfmModel.jointIndices.contains(name)) { joints.insert(joint, name); } else { diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 8cf9bd52483..cb6aadaaa28 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -29,10 +29,10 @@ class ModelPropertiesDialog : public QDialog { Q_OBJECT public: - ModelPropertiesDialog(const QVariantHash& originalMapping, + ModelPropertiesDialog(const hifi::VariantMultiHash& originalMapping, const QString& basePath, const HFMModel& hfmModel); - QVariantHash getMapping() const; + hifi::VariantMultiHash getMapping() const; private slots: void reset(); @@ -43,9 +43,9 @@ private slots: private: QComboBox* createJointBox(bool withNone = true) const; QDoubleSpinBox* createTranslationBox() const; - void insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const; + void insertJointMapping(hifi::VariantMultiHash& joints, const QString& joint, const QString& name) const; - QVariantHash _originalMapping; + hifi::VariantMultiHash _originalMapping; QString _basePath; HFMModel _hfmModel; QLineEdit* _name = nullptr; diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index 6da9327caca..e855546f071 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -17,6 +17,7 @@ #include #include #include +#include ModelSelector::ModelSelector() { QFormLayout* form = new QFormLayout(this); @@ -53,7 +54,7 @@ void ModelSelector::browse() { "Model files (*.fst *.fbx)"); QFileInfo fileInfo(filename); - if (fileInfo.isFile() && fileInfo.completeSuffix().contains(QRegExp("fst|fbx|FST|FBX"))) { + if (fileInfo.isFile() && fileInfo.completeSuffix().contains(QRegularExpression("fst|fbx|FST|FBX"))) { _modelFile = fileInfo; _browseButton->setText(fileInfo.fileName()); lastModelBrowseLocation.set(fileInfo.path()); diff --git a/interface/src/ScriptHighlighting.cpp b/interface/src/ScriptHighlighting.cpp index 1d31f2823b8..a9c0e7500b6 100644 --- a/interface/src/ScriptHighlighting.cpp +++ b/interface/src/ScriptHighlighting.cpp @@ -15,14 +15,14 @@ ScriptHighlighting::ScriptHighlighting(QTextDocument* parent) : QSyntaxHighlighter(parent) { - _keywordRegex = QRegExp("\\b(break|case|catch|continue|debugger|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|this|throw|try|typeof|var|void|while|with)\\b"); - _quotedTextRegex = QRegExp("(\"[^\"]*(\"){0,1}|\'[^\']*(\'){0,1})"); - _multiLineCommentBegin = QRegExp("/\\*"); - _multiLineCommentEnd = QRegExp("\\*/"); - _numberRegex = QRegExp("[0-9]+(\\.[0-9]+){0,1}"); - _singleLineComment = QRegExp("//[^\n]*"); - _truefalseRegex = QRegExp("\\b(true|false)\\b"); - _alphacharRegex = QRegExp("[A-Za-z]"); + _keywordRegex = QRegularExpression("\\b(break|case|catch|continue|debugger|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|this|throw|try|typeof|var|void|while|with)\\b"); + _quotedTextRegex = QRegularExpression("(\"[^\"]*(\"){0,1}|\'[^\']*(\'){0,1})"); + _multiLineCommentBegin = QRegularExpression("/\\*"); + _multiLineCommentEnd = QRegularExpression("\\*/"); + _numberRegex = QRegularExpression("[0-9]+(\\.[0-9]+){0,1}"); + _singleLineComment = QRegularExpression("//[^\n]*"); + _truefalseRegex = QRegularExpression("\\b(true|false)\\b"); + _alphacharRegex = QRegularExpression("[A-Za-z]"); } void ScriptHighlighting::highlightBlock(const QString& text) { @@ -34,11 +34,12 @@ void ScriptHighlighting::highlightBlock(const QString& text) { } void ScriptHighlighting::highlightKeywords(const QString& text) { - int index = _keywordRegex.indexIn(text); - while (index >= 0) { - int length = _keywordRegex.matchedLength(); - setFormat(index, length, Qt::blue); - index = _keywordRegex.indexIn(text, index + length); + auto keywordMatch = _keywordRegex.match(text); + while (keywordMatch.hasMatch()) { + qsizetype index = keywordMatch.capturedStart(); + qsizetype length = keywordMatch.capturedLength(); + setFormat(static_cast(index), static_cast(length), Qt::blue); + keywordMatch = _keywordRegex.match(text, index + length); } } @@ -46,11 +47,12 @@ void ScriptHighlighting::formatComments(const QString& text) { setCurrentBlockState(BlockStateClean); - int start = (previousBlockState() != BlockStateInMultiComment) ? text.indexOf(_multiLineCommentBegin) : 0; + qsizetype start = (previousBlockState() != BlockStateInMultiComment) ? text.indexOf(_multiLineCommentBegin) : 0; while (start > -1) { - int end = text.indexOf(_multiLineCommentEnd, start); - int length = (end == -1 ? text.length() : (end + _multiLineCommentEnd.matchedLength())) - start; + auto multiLineCommentEndMatch = _multiLineCommentEnd.match(text, start); + qsizetype end = multiLineCommentEndMatch.capturedEnd(); + qsizetype length = (end == qsizetype(-1) ? text.length() : (end + multiLineCommentEndMatch.capturedLength())) - start; setFormat(start, length, Qt::lightGray); start = text.indexOf(_multiLineCommentBegin, start + length); if (end == -1) { @@ -58,53 +60,63 @@ void ScriptHighlighting::formatComments(const QString& text) { } } - int index = _singleLineComment.indexIn(text); + auto singleLineCommentMatch = _singleLineComment.match(text); + qsizetype index = singleLineCommentMatch.capturedStart(); while (index >= 0) { - int length = _singleLineComment.matchedLength(); - int quoted_index = _quotedTextRegex.indexIn(text); + qsizetype length = singleLineCommentMatch.capturedLength(); + auto quotedTextRegexMatch = _quotedTextRegex.match(text); + qsizetype quoted_index = quotedTextRegexMatch.capturedStart(); bool valid = true; while (quoted_index >= 0 && valid) { - int quoted_length = _quotedTextRegex.matchedLength(); + qsizetype quoted_length = quotedTextRegexMatch.capturedLength(); if (quoted_index <= index && index <= (quoted_index + quoted_length)) { valid = false; } - quoted_index = _quotedTextRegex.indexIn(text, quoted_index + quoted_length); + quotedTextRegexMatch = _quotedTextRegex.match(text, quoted_index + quoted_length); + quoted_index = quotedTextRegexMatch.capturedStart(); } if (valid) { setFormat(index, length, Qt::lightGray); } - index = _singleLineComment.indexIn(text, index + length); + singleLineCommentMatch = _singleLineComment.match(text, index + length); + index = singleLineCommentMatch.capturedStart(); } } void ScriptHighlighting::formatQuotedText(const QString& text){ - int index = _quotedTextRegex.indexIn(text); + auto quotedTextRegexMatch = _quotedTextRegex.match(text); + qsizetype index = quotedTextRegexMatch.capturedStart();; while (index >= 0) { - int length = _quotedTextRegex.matchedLength(); + qsizetype length = quotedTextRegexMatch.capturedLength(); setFormat(index, length, Qt::red); - index = _quotedTextRegex.indexIn(text, index + length); + quotedTextRegexMatch = _quotedTextRegex.match(text, index + length); + index = quotedTextRegexMatch.capturedStart(); } } void ScriptHighlighting::formatNumbers(const QString& text){ - int index = _numberRegex.indexIn(text); + auto numberRegexMatch = _numberRegex.match(text); + qsizetype index = numberRegexMatch.capturedStart(); while (index >= 0) { - int length = _numberRegex.matchedLength(); - if (index == 0 || _alphacharRegex.indexIn(text, index - 1) != (index - 1)) { + qsizetype length = numberRegexMatch.capturedLength(); + if (index == 0 || text.indexOf(_alphacharRegex, index - 1) != (index - 1)) { setFormat(index, length, Qt::green); } - index = _numberRegex.indexIn(text, index + length); + numberRegexMatch = _numberRegex.match(text, index + length); + index = numberRegexMatch.capturedStart(); } } void ScriptHighlighting::formatTrueFalse(const QString& text){ - int index = _truefalseRegex.indexIn(text); + auto trueFalseRegexMatch = _truefalseRegex.match(text); + qsizetype index = trueFalseRegexMatch.capturedStart(); while (index >= 0) { - int length = _truefalseRegex.matchedLength(); + qsizetype length = trueFalseRegexMatch.capturedLength(); QFont* font = new QFont(this->document()->defaultFont()); font->setBold(true); setFormat(index, length, *font); - index = _truefalseRegex.indexIn(text, index + length); + trueFalseRegexMatch = _truefalseRegex.match(text, index + length); + index = trueFalseRegexMatch.capturedStart(); } } diff --git a/interface/src/ScriptHighlighting.h b/interface/src/ScriptHighlighting.h index 8952b1bcbd2..cfab657f3d0 100644 --- a/interface/src/ScriptHighlighting.h +++ b/interface/src/ScriptHighlighting.h @@ -13,6 +13,7 @@ #define hifi_ScriptHighlighting_h #include +#include class ScriptHighlighting : public QSyntaxHighlighter { Q_OBJECT @@ -34,14 +35,14 @@ class ScriptHighlighting : public QSyntaxHighlighter { void formatTrueFalse(const QString& text); private: - QRegExp _alphacharRegex; - QRegExp _keywordRegex; - QRegExp _quotedTextRegex; - QRegExp _multiLineCommentBegin; - QRegExp _multiLineCommentEnd; - QRegExp _numberRegex; - QRegExp _singleLineComment; - QRegExp _truefalseRegex; + QRegularExpression _alphacharRegex; + QRegularExpression _keywordRegex; + QRegularExpression _quotedTextRegex; + QRegularExpression _multiLineCommentBegin; + QRegularExpression _multiLineCommentEnd; + QRegularExpression _numberRegex; + QRegularExpression _singleLineComment; + QRegularExpression _truefalseRegex; }; #endif // hifi_ScriptHighlighting_h diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 463034527ac..f7eac000181 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -21,8 +21,8 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second Q_OBJECT Q_PROPERTY(QUuid attachedEntityId MEMBER attachedEntityId NOTIFY dirty) // entity whose properties define camera position and orientation Q_PROPERTY(QUuid portalEntranceEntityId MEMBER portalEntranceEntityId NOTIFY dirty) // entity whose properties define a portal's entrance position and orientation - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) // of viewpoint to render from - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) // of viewpoint to render from + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> position READ getPosition WRITE setPosition) // of viewpoint to render from + Q_PROPERTY(glm::qua orientation READ getOrientation WRITE setOrientation) // of viewpoint to render from Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees. Q_PROPERTY(float nearClipPlaneDistance MEMBER nearClipPlaneDistance NOTIFY dirty) // Secondary camera's near clip plane distance. In meters. Q_PROPERTY(float farClipPlaneDistance MEMBER farClipPlaneDistance NOTIFY dirty) // Secondary camera's far clip plane distance. In meters. @@ -31,8 +31,8 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second public: QUuid attachedEntityId; QUuid portalEntranceEntityId; - glm::vec3 position; - glm::quat orientation; + glm::vec<3,float,glm::packed_highp> position; + glm::qua orientation; float vFoV { DEFAULT_FIELD_OF_VIEW_DEGREES }; float nearClipPlaneDistance { DEFAULT_NEAR_CLIP }; float farClipPlaneDistance { DEFAULT_FAR_CLIP }; @@ -45,10 +45,10 @@ class SecondaryCameraJobConfig : public render::Task::Config { // Exposes second signals: void dirty(); public slots: - glm::vec3 getPosition() { return position; } - void setPosition(glm::vec3 pos); - glm::quat getOrientation() { return orientation; } - void setOrientation(glm::quat orient); + glm::vec<3,float,glm::packed_highp> getPosition() { return position; } + void setPosition(glm::vec<3,float,glm::packed_highp> pos); + glm::qua getOrientation() { return orientation; } + void setOrientation(glm::qua orient); void enableSecondaryCameraRenderConfigs(bool enabled); void resetSizeSpectatorCamera(int width, int height); }; diff --git a/interface/src/WindowsSystemInfo.h b/interface/src/WindowsSystemInfo.h index 7c8a1d3e270..3a83ae2764e 100644 --- a/interface/src/WindowsSystemInfo.h +++ b/interface/src/WindowsSystemInfo.h @@ -185,7 +185,7 @@ void initCpuUsage() { memcpy(&lastUserCPU, &fuser, sizeof(FILETIME)); PdhOpenQuery(NULL, NULL, &cpuQuery); - PdhAddCounter(cpuQuery, "\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal); + PdhAddCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal); PdhCollectQueryData(cpuQuery); } diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 36b1020990a..c7d206b1eb2 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -378,7 +378,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { } ok = true; - holderID = EntityDynamicInterface::extractStringArgument("hold", arguments, "holderID", ok, false); + holderID = QUuid(EntityDynamicInterface::extractStringArgument("hold", arguments, "holderID", ok, false)); if (!ok) { auto myAvatar = DependencyManager::get()->getMyAvatar(); holderID = myAvatar->getSessionUUID(); diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp index a46652c7d9b..4af52489a11 100644 --- a/interface/src/avatar/AvatarDoctor.cpp +++ b/interface/src/avatar/AvatarDoctor.cpp @@ -90,8 +90,8 @@ void AvatarDoctor::startDiagnosing() { return; } _model = resource; - const auto model = resource.data(); - const auto avatarModel = resource.data()->getHFMModel(); + const auto model = resource.get(); + const auto avatarModel = resource.get()->getHFMModel(); if (!avatarModel.originalURL.toLower().endsWith(".fbx")) { addError("Unsupported avatar model format.", "unsupported-format"); emit complete(getErrors()); @@ -230,7 +230,7 @@ void AvatarDoctor::startDiagnosing() { auto mapping = resource->getMapping(); - if (mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].type() == QVariant::Hash) { + if (mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].typeId() == QMetaType::QVariantHash) { const auto& jointNameMappings = mapping[JOINT_NAME_MAPPING_FIELD].toHash(); QStringList jointValues; for (const auto& jointVariant: jointNameMappings.values()) { @@ -277,7 +277,7 @@ void AvatarDoctor::startDiagnosing() { if (materialMappingResource->isLoaded()) { materialMappingHandled(); } else { - connect(materialMappingResource.data(), &NetworkTexture::finished, this, + connect(materialMappingResource.get(), &NetworkTexture::finished, this, [materialMappingHandled](bool success) mutable { materialMappingHandled(); @@ -297,7 +297,7 @@ void AvatarDoctor::startDiagnosing() { if (resource->isLoaded()) { resourceLoaded(!resource->isFailed()); } else { - connect(resource.data(), &GeometryResource::finished, this, resourceLoaded); + connect(resource.get(), &GeometryResource::finished, this, resourceLoaded); } } else { addError("Model file cannot be opened", "missing-file"); @@ -306,8 +306,8 @@ void AvatarDoctor::startDiagnosing() { } void AvatarDoctor::diagnoseTextures() { - const auto model = _model.data(); - const auto avatarModel = _model.data()->getHFMModel(); + const auto model = _model.get(); + const auto avatarModel = _model.get()->getHFMModel(); QVector externalTextures{}; QVector textureNames{}; int texturesFound = 0; @@ -344,7 +344,7 @@ void AvatarDoctor::diagnoseTextures() { } for (const auto& materialMapping : model->getMaterialMapping()) { - for (const auto& networkMaterial : materialMapping.second.data()->parsedMaterials.networkMaterials) { + for (const auto& networkMaterial : materialMapping.second.get()->parsedMaterials.networkMaterials) { texturesFound += (int)networkMaterial.second->getTextureMaps().size(); } } @@ -405,7 +405,7 @@ void AvatarDoctor::diagnoseTextures() { if (textureResource->isLoaded()) { textureLoaded(!textureResource->isFailed()); } else { - connect(textureResource.data(), &NetworkTexture::finished, this, textureLoaded); + connect(textureResource.get(), &NetworkTexture::finished, this, textureLoaded); } } else { _missingTextureCount++; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6a4b7955f0d..e4dbabcf349 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -768,11 +768,11 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic RayToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", - Q_RETURN_ARG(RayToAvatarIntersectionResult, result), - Q_ARG(const PickRay&, ray), - Q_ARG(const QVector&, avatarsToInclude), - Q_ARG(const QVector&, avatarsToDiscard), - Q_ARG(bool, pickAgainstMesh)); + Q_GENERIC_RETURN_ARG(RayToAvatarIntersectionResult, result), + Q_GENERIC_ARG(const PickRay&, ray), + Q_GENERIC_ARG(const QVector&, avatarsToInclude), + Q_GENERIC_ARG(const QVector&, avatarsToDiscard), + Q_GENERIC_ARG(bool, pickAgainstMesh)); return result; } @@ -897,10 +897,10 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector ParabolaToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(const_cast(this), "findParabolaIntersectionVector", - Q_RETURN_ARG(ParabolaToAvatarIntersectionResult, result), - Q_ARG(const PickParabola&, pick), - Q_ARG(const QVector&, avatarsToInclude), - Q_ARG(const QVector&, avatarsToDiscard)); + Q_GENERIC_RETURN_ARG(ParabolaToAvatarIntersectionResult, result), + Q_GENERIC_ARG(const PickParabola&, pick), + Q_GENERIC_ARG(const QVector&, avatarsToInclude), + Q_GENERIC_ARG(const QVector&, avatarsToDiscard)); return result; } diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp index cf41c0a0407..6a73ea59a25 100644 --- a/interface/src/avatar/AvatarProject.cpp +++ b/interface/src/avatar/AvatarProject.cpp @@ -110,7 +110,7 @@ AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder, try { const QByteArray fbxContents = fbx.readAll(); - hfmModel = FBXSerializer().read(fbxContents, QVariantHash(), fbxInfo.filePath()); + hfmModel = FBXSerializer().read(fbxContents, hifi::VariantMultiHash(), fbxInfo.filePath()); } catch (const QString& error) { Q_UNUSED(error) status = AvatarProjectStatus::ERROR_CREATE_READ_MODEL; diff --git a/interface/src/avatar/DetailedMotionState.cpp b/interface/src/avatar/DetailedMotionState.cpp index a22d533bc95..4ea1d40b525 100644 --- a/interface/src/avatar/DetailedMotionState.cpp +++ b/interface/src/avatar/DetailedMotionState.cpp @@ -133,7 +133,7 @@ const QUuid DetailedMotionState::getObjectID() const { } QString DetailedMotionState::getName() const { - return _avatar->getName() + "_" + _jointIndex; + return _avatar->getName() + "_" + QString::number(_jointIndex); } // virtual diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6e1a115d632..b943c880a78 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1245,7 +1245,7 @@ void MyAvatar::restoreHandAnimation(bool isLeft) { QStringList MyAvatar::getAnimationRoles() { if (QThread::currentThread() != thread()) { QStringList result; - BLOCKING_INVOKE_METHOD(this, "getAnimationRoles", Q_RETURN_ARG(QStringList, result)); + BLOCKING_INVOKE_METHOD(this, "getAnimationRoles", Q_GENERIC_RETURN_ARG(QStringList, result)); return result; } return _skeletonModel->getRig().getAnimationRoles(); @@ -2312,7 +2312,7 @@ const float SCRIPT_PRIORITY = 1.0f + 1.0f; const float RECORDER_PRIORITY = 1.0f + 1.0f; void MyAvatar::setJointRotations(const QVector& jointRotations) { - int numStates = glm::min(_skeletonModel->getJointStateCount(), jointRotations.size()); + int numStates = glm::min(static_cast(_skeletonModel->getJointStateCount()), jointRotations.size()); for (int i = 0; i < numStates; ++i) { // HACK: ATM only Recorder calls setJointRotations() so we hardcode its priority here _skeletonModel->setJointRotation(i, true, jointRotations[i], RECORDER_PRIORITY); @@ -2623,8 +2623,8 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "useFullAvatarURL", - Q_ARG(const QUrl&, fullAvatarURL), - Q_ARG(const QString&, modelName)); + Q_GENERIC_ARG(const QUrl&, fullAvatarURL), + Q_GENERIC_ARG(const QString&, modelName)); return; } @@ -4087,7 +4087,7 @@ bool MyAvatar::safeLanding(const glm::vec3& position) { if (QThread::currentThread() != thread()) { bool result; - BLOCKING_INVOKE_METHOD(this, "safeLanding", Q_RETURN_ARG(bool, result), Q_ARG(const glm::vec3&, position)); + BLOCKING_INVOKE_METHOD(this, "safeLanding", Q_GENERIC_RETURN_ARG(bool, result), Q_GENERIC_ARG(const glm::vec3&, position)); return result; } glm::vec3 better; @@ -6159,7 +6159,7 @@ QVariantMap MyAvatar::getFlowData() { QVariantMap result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "getFlowData", - Q_RETURN_ARG(QVariantMap, result)); + Q_GENERIC_RETURN_ARG(QVariantMap, result)); return result; } if (_skeletonModel->isLoaded()) { @@ -6227,7 +6227,7 @@ QVariantList MyAvatar::getCollidingFlowJoints() { QVariantList result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "getCollidingFlowJoints", - Q_RETURN_ARG(QVariantList, result)); + Q_GENERIC_RETURN_ARG(QVariantList, result)); return result; } @@ -6546,7 +6546,7 @@ void MyAvatar::updateHeadLookAt(float deltaTime) { void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "setHeadLookAt", - Q_ARG(const glm::vec3&, lookAtTarget)); + Q_GENERIC_ARG(const glm::vec3&, lookAtTarget)); return; } _headLookAtActive = true; @@ -6558,7 +6558,7 @@ void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) { void MyAvatar::setEyesLookAt(const glm::vec3& lookAtTarget) { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "setEyesLookAt", - Q_ARG(const glm::vec3&, lookAtTarget)); + Q_GENERIC_ARG(const glm::vec3&, lookAtTarget)); return; } _eyesLookAtTarget.set(lookAtTarget); @@ -6655,8 +6655,8 @@ bool MyAvatar::getHMDCrouchRecenterEnabled() const { bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "setPointAt", Q_RETURN_ARG(bool, result), - Q_ARG(const glm::vec3&, pointAtTarget)); + BLOCKING_INVOKE_METHOD(this, "setPointAt", Q_GENERIC_RETURN_ARG(bool, result), + Q_GENERIC_ARG(const glm::vec3&, pointAtTarget)); return result; } if (_skeletonModel->isLoaded() && _pointAtActive) { @@ -6686,3 +6686,37 @@ float MyAvatar::getCameraSensitivity() const { void MyAvatar::setCameraSensitivity(float cameraSensitivity) { qApp->getCamera().setSensitivity(cameraSensitivity); } + +MyAvatar::TabletInputMode MyAvatar::getTabletInputMode() { + auto prefersStylus = qApp->getPreferStylusOverLaser(); + auto prefersFinger = qApp->getPreferAvatarFingerOverStylus(); + + if (prefersFinger) { + return TabletInputMode::AvatarFingers; + } else if (prefersStylus) { + return TabletInputMode::Styluses; + } else { + return TabletInputMode::Lasers; + } +} + +void MyAvatar::setTabletInputMode(MyAvatar::TabletInputMode mode) { + switch (mode) { + case TabletInputMode::Lasers: + qApp->setPreferStylusOverLaser(false); + qApp->setPreferAvatarFingerOverStylus(false); + break; + + case TabletInputMode::Styluses: + qApp->setPreferStylusOverLaser(true); + qApp->setPreferAvatarFingerOverStylus(false); + break; + + case TabletInputMode::AvatarFingers: + qApp->setPreferStylusOverLaser(true); + qApp->setPreferAvatarFingerOverStylus(true); + break; + } + + emit tabletInputModeChanged(mode); +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 84308094720..8933b33d3f5 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -326,9 +326,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition) QVector3D getQmlPosition() { auto p = getWorldPosition(); return QVector3D(p.x, p.y, p.z); } - Q_PROPERTY(glm::vec3 feetPosition READ getWorldFeetPosition WRITE goToFeetLocation) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> feetPosition READ getWorldFeetPosition WRITE goToFeetLocation) Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) - Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale) Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame) Q_PROPERTY(QString motorMode READ getScriptedMotorMode WRITE setScriptedMotorMode) @@ -337,18 +337,18 @@ class MyAvatar : public Avatar { Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead) Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) - Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) - Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) + Q_PROPERTY(glm::qua customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) Q_PROPERTY(float rotationRecenterFilterLength READ getRotationRecenterFilterLength WRITE setRotationRecenterFilterLength) Q_PROPERTY(float rotationThreshold READ getRotationThreshold WRITE setRotationThreshold) Q_PROPERTY(bool enableStepResetRotation READ getEnableStepResetRotation WRITE setEnableStepResetRotation) Q_PROPERTY(bool enableDrawAverageFacing READ getEnableDrawAverageFacing WRITE setEnableDrawAverageFacing) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) - Q_PROPERTY(glm::vec3 leftHandPosition READ getLeftHandPosition) - Q_PROPERTY(glm::vec3 rightHandPosition READ getRightHandPosition) - Q_PROPERTY(glm::vec3 leftHandTipPosition READ getLeftHandTipPosition) - Q_PROPERTY(glm::vec3 rightHandTipPosition READ getRightHandTipPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> leftHandPosition READ getLeftHandPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> rightHandPosition READ getRightHandPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> leftHandTipPosition READ getLeftHandTipPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> rightHandTipPosition READ getRightHandTipPosition) Q_PROPERTY(controller::Pose leftHandPose READ getLeftHandPose) Q_PROPERTY(controller::Pose rightHandPose READ getRightHandPose) @@ -387,6 +387,8 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool allowTeleporting READ getAllowTeleporting) Q_PROPERTY(float cameraBoomLength MEMBER _boomLength) + Q_PROPERTY(MyAvatar::TabletInputMode tabletInputMode READ getTabletInputMode WRITE setTabletInputMode NOTIFY tabletInputModeChanged) + const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; const QString DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE = "head"; @@ -537,6 +539,13 @@ class MyAvatar : public Avatar { static const std::array allowAvatarStandingPreferenceStrings; static const std::array allowAvatarLeaningPreferenceStrings; + enum class TabletInputMode : uint { + Lasers, + Styluses, + AvatarFingers, + }; + Q_ENUM(TabletInputMode); + explicit MyAvatar(QThread* thread); virtual ~MyAvatar(); @@ -578,9 +587,9 @@ class MyAvatar : public Avatar { virtual void postUpdate(float deltaTime, const render::ScenePointer& scene) override; void preDisplaySide(const RenderArgs* renderArgs); - const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; } - const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; } - const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; } + const glm::mat<4,4,float,glm::packed_highp>& getHMDSensorMatrix() const { return _hmdSensorMatrix; } + const glm::vec<3,float,glm::packed_highp>& getHMDSensorPosition() const { return _hmdSensorPosition; } + const glm::qua& getHMDSensorOrientation() const { return _hmdSensorOrientation; } /*@jsdoc * Gets the avatar orientation. Suitable for use in QML. @@ -597,18 +606,18 @@ class MyAvatar : public Avatar { Q_INVOKABLE QVariant getOrientationVar() const; // A method intended to be overriden by MyAvatar for polling orientation for network transmission. - glm::quat getOrientationOutbound() const override; + glm::qua getOrientationOutbound() const override; // Pass a recent sample of the HMD to the avatar. // This can also update the avatar's position to follow the HMD // as it moves through the world. - void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix); + void updateFromHMDSensorMatrix(const glm::mat<4,4,float,glm::packed_highp>& hmdSensorMatrix); // compute the hip to hand average azimuth. - glm::vec2 computeHandAzimuth() const; + glm::vec<2,float,glm::packed_highp> computeHandAzimuth() const; // read the location of a hand controller and save the transform - void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache& matrixCache); + void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache>& matrixCache); // best called at end of main loop, just before rendering. // update sensor to world matrix from current body position and hmd sensor. @@ -627,7 +636,7 @@ class MyAvatar : public Avatar { * var defaultEyePosition = MyAvatar.getDefaultEyePosition(); * print(JSON.stringify(defaultEyePosition)); */ - Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getDefaultEyePosition() const; float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } @@ -994,6 +1003,9 @@ class MyAvatar : public Avatar { bool getAllowTeleporting() { return _allowTeleportingSetting.get(); } void setAllowTeleporting(bool allowTeleporting) { _allowTeleportingSetting.set(allowTeleporting); } + MyAvatar::TabletInputMode getTabletInputMode(); + void setTabletInputMode(MyAvatar::TabletInputMode mode); + bool getShowPlayArea() const { return _showPlayArea.get(); } void setShowPlayArea(bool showPlayArea) { _showPlayArea.set(showPlayArea); } @@ -1097,7 +1109,7 @@ class MyAvatar : public Avatar { * @example Report the current position of your avatar's head. * print(JSON.stringify(MyAvatar.getHeadPosition())); */ - Q_INVOKABLE glm::vec3 getHeadPosition() const { return getHead()->getPosition(); } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getHeadPosition() const { return getHead()->getPosition(); } /*@jsdoc * Gets the yaw of the avatar's head relative to its body. @@ -1137,7 +1149,7 @@ class MyAvatar : public Avatar { * var eyePosition = MyAvatar.getEyePosition(); * print(JSON.stringify(eyePosition)); */ - Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getEyePosition() const { return getHead()->getEyePosition(); } /*@jsdoc * Gets the position of the avatar your avatar is currently looking at. @@ -1148,7 +1160,7 @@ class MyAvatar : public Avatar { */ // FIXME: If not looking at an avatar, the most recently looked-at position is returned. This should be fixed to return // undefined or {NaN, NaN, NaN} or similar. - Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getTargetAvatarPosition() const { return _targetAvatarPosition; } /*@jsdoc * Gets information on the avatar your avatar is currently looking at. @@ -1169,7 +1181,7 @@ class MyAvatar : public Avatar { * @example Report the position of your left hand relative to your avatar. * print(JSON.stringify(MyAvatar.getLeftHandPosition())); */ - Q_INVOKABLE glm::vec3 getLeftHandPosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getLeftHandPosition() const; /*@jsdoc * Gets the position of the avatar's right hand, relative to the avatar, as positioned by a hand controller (e.g., Oculus @@ -1182,7 +1194,7 @@ class MyAvatar : public Avatar { * @example Report the position of your right hand relative to your avatar. * print(JSON.stringify(MyAvatar.getLeftHandPosition())); */ - Q_INVOKABLE glm::vec3 getRightHandPosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getRightHandPosition() const; /*@jsdoc * Gets the position 0.3m in front of the left hand's position in the direction along the palm, in avatar coordinates, as @@ -1191,7 +1203,7 @@ class MyAvatar : public Avatar { * @returns {Vec3} The position 0.3m in front of the left hand's position in the direction along the palm, in avatar * coordinates. If the hand isn't being positioned by a controller, {@link Vec3(0)|Vec3.ZERO} is returned. */ - Q_INVOKABLE glm::vec3 getLeftHandTipPosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getLeftHandTipPosition() const; /*@jsdoc * Gets the position 0.3m in front of the right hand's position in the direction along the palm, in avatar coordinates, as @@ -1200,7 +1212,7 @@ class MyAvatar : public Avatar { * @returns {Vec3} The position 0.3m in front of the right hand's position in the direction along the palm, in avatar * coordinates. If the hand isn't being positioned by a controller, {@link Vec3(0)|Vec3.ZERO} is returned. */ - Q_INVOKABLE glm::vec3 getRightHandTipPosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getRightHandTipPosition() const; /*@jsdoc @@ -1259,15 +1271,15 @@ class MyAvatar : public Avatar { void snapOtherAvatarLookAtTargetsToMe(const AvatarHash& hash); void clearLookAtTargetAvatar(); - virtual void setJointRotations(const QVector& jointRotations) override; - virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) override; - virtual void setJointRotation(int index, const glm::quat& rotation) override; - virtual void setJointTranslation(int index, const glm::vec3& translation) override; + virtual void setJointRotations(const QVector>& jointRotations) override; + virtual void setJointData(int index, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& translation) override; + virtual void setJointRotation(int index, const glm::qua& rotation) override; + virtual void setJointTranslation(int index, const glm::vec<3,float,glm::packed_highp>& translation) override; virtual void clearJointData(int index) override; - virtual void setJointData(const QString& name, const glm::quat& rotation, const glm::vec3& translation) override; - virtual void setJointRotation(const QString& name, const glm::quat& rotation) override; - virtual void setJointTranslation(const QString& name, const glm::vec3& translation) override; + virtual void setJointData(const QString& name, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& translation) override; + virtual void setJointRotation(const QString& name, const glm::qua& rotation) override; + virtual void setJointTranslation(const QString& name, const glm::vec<3,float,glm::packed_highp>& translation) override; virtual void clearJointData(const QString& name) override; virtual void clearJointsData() override; @@ -1280,7 +1292,7 @@ class MyAvatar : public Avatar { * @param {Quat} orientation - The orientation of the joint in world coordinates. * @returns {boolean} true if the joint was pinned, false if it wasn't. */ - Q_INVOKABLE bool pinJoint(int index, const glm::vec3& position, const glm::quat& orientation); + Q_INVOKABLE bool pinJoint(int index, const glm::vec<3,float,glm::packed_highp>& position, const glm::qua& orientation); bool isJointPinned(int index); @@ -1333,7 +1345,7 @@ class MyAvatar : public Avatar { void updateMotors(); void prepareForPhysicsSimulation(); - void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. + void nextAttitude(glm::vec<3,float,glm::packed_highp> position, glm::qua orientation); // Can be safely called at any time. void harvestResultsFromPhysicsSimulation(float deltaTime); const QString& getCollisionSoundURL() { return _collisionSoundURL; } @@ -1367,10 +1379,10 @@ class MyAvatar : public Avatar { AudioListenerMode getAudioListenerMode() { return _audioListenerMode; } void setAudioListenerMode(AudioListenerMode audioListenerMode); - glm::vec3 getCustomListenPosition() { return _customListenPosition; } - void setCustomListenPosition(glm::vec3 customListenPosition) { _customListenPosition = customListenPosition; } - glm::quat getCustomListenOrientation() { return _customListenOrientation; } - void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; } + glm::vec<3,float,glm::packed_highp> getCustomListenPosition() { return _customListenPosition; } + void setCustomListenPosition(glm::vec<3,float,glm::packed_highp> customListenPosition) { _customListenPosition = customListenPosition; } + glm::qua getCustomListenOrientation() { return _customListenOrientation; } + void setCustomListenOrientation(glm::qua customListenOrientation) { _customListenOrientation = customListenOrientation; } virtual void rebuildCollisionShape() override; @@ -1382,8 +1394,8 @@ class MyAvatar : public Avatar { void setHeadControllerFacingMovingAverage(glm::vec2 currentHeadControllerFacing) { _headControllerFacingMovingAverage = currentHeadControllerFacing; } float getCurrentStandingHeight() const { return _currentStandingHeight; } void setCurrentStandingHeight(float newMode) { _currentStandingHeight = newMode; } - const glm::quat getAverageHeadRotation() const { return _averageHeadRotation; } - void setAverageHeadRotation(glm::quat rotation) { _averageHeadRotation = rotation; } + const glm::qua getAverageHeadRotation() const { return _averageHeadRotation; } + void setAverageHeadRotation(glm::qua rotation) { _averageHeadRotation = rotation; } bool getResetMode() const { return _resetMode; } void setResetMode(bool hasBeenReset) { _resetMode = hasBeenReset; } @@ -1575,7 +1587,7 @@ class MyAvatar : public Avatar { * var headRotation = MyAvatar.getAbsoluteJointRotationInObjectFrame(headIndex); * print("Head rotation: " + JSON.stringify(Quat.safeEulerAngles(headRotation))); // Degrees */ - virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; + virtual glm::qua getAbsoluteJointRotationInObjectFrame(int index) const override; /*@jsdoc * Gets the translation of a joint relative to the avatar. @@ -1588,19 +1600,19 @@ class MyAvatar : public Avatar { * var headTranslation = MyAvatar.getAbsoluteJointTranslationInObjectFrame(headIndex); * print("Head translation: " + JSON.stringify(headTranslation)); */ - virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; + virtual glm::vec<3,float,glm::packed_highp> getAbsoluteJointTranslationInObjectFrame(int index) const override; // all calibration matrices are in absolute sensor space. - glm::mat4 getCenterEyeCalibrationMat() const; - glm::mat4 getHeadCalibrationMat() const; - glm::mat4 getSpine2CalibrationMat() const; - glm::mat4 getHipsCalibrationMat() const; - glm::mat4 getLeftFootCalibrationMat() const; - glm::mat4 getRightFootCalibrationMat() const; - glm::mat4 getRightArmCalibrationMat() const; - glm::mat4 getLeftArmCalibrationMat() const; - glm::mat4 getLeftHandCalibrationMat() const; - glm::mat4 getRightHandCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getCenterEyeCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getHeadCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getSpine2CalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getHipsCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getLeftFootCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getRightFootCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getRightArmCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getLeftArmCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getLeftHandCalibrationMat() const; + glm::mat<4,4,float,glm::packed_highp> getRightHandCalibrationMat() const; void addHoldAction(AvatarActionHold* holdAction); // thread-safe void removeHoldAction(AvatarActionHold* holdAction); // thread-safe @@ -1609,16 +1621,16 @@ class MyAvatar : public Avatar { // derive avatar body position and orientation from the current HMD Sensor location. // results are in sensor frame (-z forward) - glm::mat4 deriveBodyFromHMDSensor(const bool forceFollowYPos = false) const; + glm::mat<4,4,float,glm::packed_highp> deriveBodyFromHMDSensor(const bool forceFollowYPos = false) const; - glm::mat4 getSpine2RotationRigSpace() const; + glm::mat<4,4,float,glm::packed_highp> getSpine2RotationRigSpace() const; - glm::vec3 computeCounterBalance(); + glm::vec<3,float,glm::packed_highp> computeCounterBalance(); // derive avatar body position and orientation from using the current HMD Sensor location in relation to the previous // location of the base of support of the avatar. // results are in sensor frame (-z foward) - glm::mat4 deriveBodyUsingCgModel(); + glm::mat<4,4,float,glm::packed_highp> deriveBodyUsingCgModel(); /*@jsdoc * Tests whether a vector is pointing in the general direction of the avatar's "up" direction (i.e., dot product of vectors @@ -1628,7 +1640,7 @@ class MyAvatar : public Avatar { * @returns {boolean} true if the direction vector is pointing generally in the direction of the avatar's "up" * direction. */ - Q_INVOKABLE bool isUp(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up. + Q_INVOKABLE bool isUp(const glm::vec<3,float,glm::packed_highp>& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up. /*@jsdoc * Tests whether a vector is pointing in the general direction of the avatar's "down" direction (i.e., dot product of @@ -1638,14 +1650,14 @@ class MyAvatar : public Avatar { * @returns {boolean} true if the direction vector is pointing generally in the direction of the avatar's * "down" direction. */ - Q_INVOKABLE bool isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; }; + Q_INVOKABLE bool isDown(const glm::vec<3,float,glm::packed_highp>& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; }; void setUserHeight(float value); float getUserHeight() const; float getUserEyeHeight() const; virtual SpatialParentTree* getParentTree() const override; - virtual glm::vec3 scaleForChildren() const override { return glm::vec3(getSensorToWorldScale()); } + virtual glm::vec<3,float,glm::packed_highp> scaleForChildren() const override { return glm::vec3(getSensorToWorldScale()); } const QUuid& getSelfID() const { return AVATAR_SELF_ID; } @@ -1676,9 +1688,9 @@ class MyAvatar : public Avatar { bool isReadyForPhysics() const; float computeStandingHeightMode(const controller::Pose& head); - glm::quat computeAverageHeadRotation(const controller::Pose& head); + glm::qua computeAverageHeadRotation(const controller::Pose& head); - glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } + glm::vec<3,float,glm::packed_highp> getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } void prepareAvatarEntityDataForReload(); /*@jsdoc @@ -1688,14 +1700,14 @@ class MyAvatar : public Avatar { * @function MyAvatar.setHeadLookAt * @param {Vec3} lookAtTarget - The target point in world coordinates. */ - Q_INVOKABLE void setHeadLookAt(const glm::vec3& lookAtTarget); + Q_INVOKABLE void setHeadLookAt(const glm::vec<3,float,glm::packed_highp>& lookAtTarget); /*@jsdoc * Gets the current target point of the head's look direction in world coordinates. * @function MyAvatar.getHeadLookAt * @returns {Vec3} The head's look-at target in world coordinates. */ - Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getHeadLookAt() { return _lookAtCameraTarget; } /*@jsdoc * Returns control of the avatar's head to the engine, and releases control from API calls. @@ -1710,14 +1722,14 @@ class MyAvatar : public Avatar { * @function MyAvatar.setEyesLookAt * @param {Vec3} lookAtTarget - The target point in world coordinates. */ - Q_INVOKABLE void setEyesLookAt(const glm::vec3& lookAtTarget); + Q_INVOKABLE void setEyesLookAt(const glm::vec<3,float,glm::packed_highp>& lookAtTarget); /*@jsdoc * Gets the current target point of the eyes look direction in world coordinates. * @function MyAvatar.getEyesLookAt * @returns {Vec3} The eyes' look-at target in world coordinates. */ - Q_INVOKABLE glm::vec3 getEyesLookAt() { return _eyesLookAtTarget.get(); } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getEyesLookAt() { return _eyesLookAtTarget.get(); } /*@jsdoc * Returns control of the avatar's eyes to the engine, and releases control from API calls. @@ -1733,9 +1745,9 @@ class MyAvatar : public Avatar { * @param {Vec3} pointAtTarget - The target to point at, in world coordinates. * @returns {boolean} true if the target point was set, false if it wasn't. */ - Q_INVOKABLE bool setPointAt(const glm::vec3& pointAtTarget); + Q_INVOKABLE bool setPointAt(const glm::vec<3,float,glm::packed_highp>& pointAtTarget); - glm::quat getLookAtRotation() { return _lookAtYaw * _lookAtPitch; } + glm::qua getLookAtRotation() { return _lookAtYaw * _lookAtPitch; } /*@jsdoc * Creates a new grab that grabs an entity. @@ -1765,7 +1777,7 @@ class MyAvatar : public Avatar { * }, 10000); */ Q_INVOKABLE const QUuid grab(const QUuid& targetID, int parentJointIndex, - glm::vec3 positionalOffset, glm::quat rotationalOffset); + glm::vec<3,float,glm::packed_highp> positionalOffset, glm::qua rotationalOffset); /*@jsdoc * Releases (deletes) a grab to stop grabbing an entity. @@ -1845,7 +1857,7 @@ class MyAvatar : public Avatar { * @param {Vec3} position - The position where the avatar should sit. * @param {Quat} rotation - The initial orientation of the seated avatar. */ - Q_INVOKABLE void beginSit(const glm::vec3& position, const glm::quat& rotation); + Q_INVOKABLE void beginSit(const glm::vec<3,float,glm::packed_highp>& position, const glm::qua& rotation); /*@jsdoc * Ends a sitting action for the avatar. @@ -1853,7 +1865,7 @@ class MyAvatar : public Avatar { * @param {Vec3} position - The position of the avatar when standing up. * @param {Quat} rotation - The orientation of the avatar when standing up. */ - Q_INVOKABLE void endSit(const glm::vec3& position, const glm::quat& rotation); + Q_INVOKABLE void endSit(const glm::vec<3,float,glm::packed_highp>& position, const glm::qua& rotation); /*@jsdoc * Gets whether the avatar is in a seated pose. The seated pose is set by calling {@link MyAvatar.beginSit}. @@ -1878,8 +1890,8 @@ class MyAvatar : public Avatar { void debugDrawPose(controller::Action action, const char* channelName, float size); bool getIsJointOverridden(int jointIndex) const; - glm::vec3 getLookAtPivotPoint(); - glm::vec3 getCameraEyesPosition(float deltaTime); + glm::vec<3,float,glm::packed_highp> getLookAtPivotPoint(); + glm::vec<3,float,glm::packed_highp> getCameraEyesPosition(float deltaTime); bool isJumping(); bool getHMDCrouchRecenterEnabled() const; bool isAllowedToLean() const; @@ -1956,8 +1968,8 @@ public slots: * @param {boolean} [shouldFaceLocation=false] - Set to true to position the avatar a short distance away from * the new position and orientate the avatar to face the position. */ - void goToFeetLocation(const glm::vec3& newPosition, bool hasOrientation = false, - const glm::quat& newOrientation = glm::quat(), bool shouldFaceLocation = false); + void goToFeetLocation(const glm::vec<3,float,glm::packed_highp>& newPosition, bool hasOrientation = false, + const glm::qua& newOrientation = glm::qua(), bool shouldFaceLocation = false); /*@jsdoc * Moves the avatar to a new position and/or orientation in the domain. @@ -1969,8 +1981,8 @@ public slots: * the new position and orientate the avatar to face the position. * @param {boolean} [withSafeLanding=true] - Set to false to disable safe landing when teleporting. */ - void goToLocation(const glm::vec3& newPosition, - bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(), + void goToLocation(const glm::vec<3,float,glm::packed_highp>& newPosition, + bool hasOrientation = false, const glm::qua& newOrientation = glm::qua(), bool shouldFaceLocation = false, bool withSafeLanding = true); /*@jsdoc * Moves the avatar to a new position and (optional) orientation in the domain, with safe landing. @@ -1984,7 +1996,7 @@ public slots: * @function MyAvatar.goToLocationAndEnableCollisions * @param {Vec3} position - The new position for the avatar, in world coordinates. */ - void goToLocationAndEnableCollisions(const glm::vec3& newPosition); + void goToLocationAndEnableCollisions(const glm::vec<3,float,glm::packed_highp>& newPosition); /*@jsdoc * @function MyAvatar.safeLanding @@ -1992,7 +2004,7 @@ public slots: * @returns {boolean} true if the avatar was moved, false if it wasn't. * @deprecated This function is deprecated and will be removed. */ - bool safeLanding(const glm::vec3& position); + bool safeLanding(const glm::vec<3,float,glm::packed_highp>& position); /*@jsdoc @@ -2017,7 +2029,7 @@ public slots: * properties instead. */ // Set/Get update the thrust that will move the avatar around - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + void addThrust(glm::vec<3,float,glm::packed_highp> newThrust) { _thrust += newThrust; }; /*@jsdoc * Gets the thrust currently being applied to your avatar. @@ -2026,7 +2038,7 @@ public slots: * @deprecated This function is deprecated and will be removed. Use {@link MyAvatar|MyAvatar.motorVelocity} and related * properties instead. */ - glm::vec3 getThrust() { return _thrust; }; + glm::vec<3,float,glm::packed_highp> getThrust() { return _thrust; }; /*@jsdoc * Sets the thrust to be applied to your avatar for a short while. @@ -2035,7 +2047,7 @@ public slots: * @deprecated This function is deprecated and will be removed. Use {@link MyAvatar|MyAvatar.motorVelocity} and related * properties instead. */ - void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } + void setThrust(glm::vec<3,float,glm::packed_highp> newThrust) { _thrust = newThrust; } /*@jsdoc @@ -2211,7 +2223,7 @@ public slots: * @function MyAvatar.getPositionForAudio * @returns {Vec3} Your listening position. */ - glm::vec3 getPositionForAudio(); + glm::vec<3,float,glm::packed_highp> getPositionForAudio(); /*@jsdoc * Gets the orientation of your listening position for spatialized audio. The orientation depends on the value of the @@ -2219,7 +2231,7 @@ public slots: * @function MyAvatar.getOrientationForAudio * @returns {Quat} The orientation of your listening position. */ - glm::quat getOrientationForAudio(); + glm::qua getOrientationForAudio(); /*@jsdoc * @function MyAvatar.setModelScale @@ -2465,6 +2477,14 @@ public slots: */ void disableHandTouchForIDChanged(const QUuid& entityID, bool disable); + /*@jsdoc + * Triggered when {@link MyAvatar.tabletInputMode} is changed. + * @function MyAvatar.tabletInputModeChanged + * @param {MyAvatar.TabletInputMode} + * @returns {Signal} + */ + void tabletInputModeChanged(MyAvatar::TabletInputMode mode); + private slots: void leaveDomain(); void updateCollisionCapsuleCache(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 2edcf7f09eb..49099bff2cd 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -82,6 +82,8 @@ int main(int argc, const char* argv[]) { qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray"); } + QSurfaceFormat::setDefaultFormat(getDefaultOpenGLSurfaceFormat()); + // Setup QCoreApplication settings, install log message handler setupHifiApplication(BuildInfo::INTERFACE_NAME); @@ -742,15 +744,15 @@ int main(int argc, const char* argv[]) { if (parser.isSet(checkMinSpecOption)) { QString appPath; { - char filename[MAX_PATH]; + wchar_t filename[MAX_PATH]; GetModuleFileName(NULL, filename, MAX_PATH); - QFileInfo appInfo(filename); + QFileInfo appInfo(QString::fromWCharArray(filename)); appPath = appInfo.absolutePath(); } QString openvrDllPath = appPath + "/plugins/openvr.dll"; HMODULE openvrDll; CHECKMINSPECPROC checkMinSpecPtr; - if ((openvrDll = LoadLibrary(openvrDllPath.toLocal8Bit().data())) && + if ((openvrDll = LoadLibrary(qUtf16Printable(openvrDllPath.toLocal8Bit().data()))) && (checkMinSpecPtr = (CHECKMINSPECPROC)GetProcAddress(openvrDll, "CheckMinSpec"))) { if (!checkMinSpecPtr()) { return -1; @@ -841,8 +843,11 @@ int main(int argc, const char* argv[]) { } QTranslator translator; - translator.load("i18n/interface_en"); - app.installTranslator(&translator); + if (translator.load("i18n/interface_en")) { + app.installTranslator(&translator); + } else { + qWarning() << " Failed to load QTranslator i18n/interface_en"; + } qCDebug(interfaceapp, "Created QT Application."); if (parser.isSet("abortAfterInit")) { return 99; diff --git a/interface/src/networking/CloseEventSender.h b/interface/src/networking/CloseEventSender.h index b74412c41c0..4be84c1f792 100644 --- a/interface/src/networking/CloseEventSender.h +++ b/interface/src/networking/CloseEventSender.h @@ -16,6 +16,7 @@ #include #include +#include #include diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index b0f21e2574c..9cb68512dd7 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -26,6 +26,7 @@ OctreePacketProcessor::OctreePacketProcessor(): { setObjectName("Octree Packet Processor"); + Q_ASSERT(DependencyManager::get()); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); const PacketReceiver::PacketTypeList octreePackets = { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::EntityQueryInitialResultsComplete }; diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index f652639d20e..e71a5274d82 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -134,7 +134,7 @@ bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) { return _mathPick.loaded; } -void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, std::shared_ptr resource) { ShapeType type = shapeInfo.getType(); glm::vec3 dimensions = pick.transform.getScale(); QString modelURL = (resource ? resource->getURL().toString() : ""); @@ -147,7 +147,7 @@ void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, } } -void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, std::shared_ptr resource) { // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo // TODO: Move to some shared code area (in entities-renderer? model-networking?) // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo @@ -305,7 +305,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha points.reserve(sizeToReserve); // copy points - const glm::vec3* vertexItr = vertices.cbegin(); + auto vertexItr = vertices.cbegin(); while (vertexItr != vertices.cend()) { glm::vec3 point = *vertexItr; points.push_back(point); @@ -322,7 +322,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha triangleIndices.reserve((int)triangleIndicesCount); for (const HFMMeshPart& meshPart : mesh.parts) { - const int* indexItr = meshPart.triangleIndices.cbegin(); + auto indexItr = meshPart.triangleIndices.cbegin(); while (indexItr != meshPart.triangleIndices.cend()) { triangleIndices.push_back(*indexItr); ++indexItr; diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 8825ea65d11..31a1a3fd688 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -65,14 +65,14 @@ class CollisionPick : public Pick { bool isLoaded() const; // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. bool getShapeInfoReady(const CollisionRegion& pick); - void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); - void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, std::shared_ptr resource); + void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, std::shared_ptr resource); void filterIntersections(std::vector& intersections) const; bool _scaleWithParent; PhysicsEnginePointer _physicsEngine; - QSharedPointer _cachedResource; + std::shared_ptr _cachedResource; // Options for what information to get from collision results bool _includeNormals; diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 508745ca32d..94a24295922 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -49,7 +49,7 @@ unsigned int PointerScriptingInterface::createPointerInternal(const PickQuery::P // Interaction with managers should always happen on the main thread if (QThread::currentThread() != qApp->thread()) { unsigned int result; - BLOCKING_INVOKE_METHOD(this, "createPointerInternal", Q_RETURN_ARG(unsigned int, result), Q_ARG(PickQuery::PickType, type), Q_ARG(PointerProperties, properties)); + BLOCKING_INVOKE_METHOD(this, "createPointerInternal", Q_GENERIC_RETURN_ARG(unsigned int, result), Q_GENERIC_ARG(PickQuery::PickType, type), Q_GENERIC_ARG(PointerProperties, properties)); return result; } diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index b45bd46dcff..38d686bb91e 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -421,7 +421,7 @@ class PointerScriptingInterface : public QObject, public Dependency { * @param {Mat4} [offset] - The offset of the target point from the center of the target item. If not specified, the * pointer locks on to the center of the target item. */ - Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); } + Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isAvatar, const glm::mat<4,4,float,glm::packed_highp>& offsetMat = glm::mat4()) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isAvatar, offsetMat); } /*@jsdoc * Sets the delay of a Ray pointer. diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 13954cf2972..8acb47a1333 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -167,13 +167,12 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createGetAllMappingsRequest(); - connect(request, &GetAllMappingsRequest::finished, this, [callback](GetAllMappingsRequest* request) mutable { + connect(request, &GetAllMappingsRequest::finished, this, [callback, this](GetAllMappingsRequest* request) mutable { auto mappings = request->getMappings(); - OVERTE_IGNORE_DEPRECATED_BEGIN - // Still using QScriptEngine - auto map = callback.engine()->newObject(); - OVERTE_IGNORE_WARNING_END + // QT6TODO: is this correct? + auto engine = qjsEngine(this); + auto map = engine->newObject(); for (auto& kv : mappings ) { map.setProperty(kv.first, kv.second.hash); diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h index bc624b0dd08..921b393ad49 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -78,7 +78,9 @@ class AssetMappingsScriptingInterface : public QObject, public Dependency { Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue startedCallback = QJSValue(), QJSValue completedCallback = QJSValue(), bool dropEvent = false); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback = QJSValue()); - Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } + Q_INVOKABLE void deleteMapping(QString path, QJSValue callback = QJSValue()) { + deleteMappings(QStringList(path), callback); + } Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue()); Q_INVOKABLE void setBakingEnabled(QStringList paths, bool enabled, QJSValue callback = QJSValue()); diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index f90a7d84a8b..9255b4b1bc1 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -33,8 +33,8 @@ static Setting::Handle hmdOutputDeviceSetting { QStringList { OVERTE_AU Q_DECLARE_METATYPE(HifiAudioDeviceInfo); -Setting::Handle& getSetting(bool contextIsHMD, QAudio::Mode mode) { - if (mode == QAudio::AudioInput) { +Setting::Handle& getSetting(bool contextIsHMD, QAudioDevice::Mode mode) { + if (mode == QAudioDevice::Mode::Input) { return contextIsHMD ? hmdInputDeviceSetting : desktopInputDeviceSetting; } else { // if (mode == QAudio::AudioOutput) return contextIsHMD ? hmdOutputDeviceSetting : desktopOutputDeviceSetting; @@ -59,7 +59,7 @@ QHash AudioDeviceList::_roles { { TypeRole, "type"} }; -static QString getTargetDevice(bool hmd, QAudio::Mode mode) { +static QString getTargetDevice(bool hmd, QAudioDevice::Mode mode) { QString deviceName; auto& setting = getSetting(hmd, mode); if (setting.isSet()) { @@ -70,11 +70,11 @@ static QString getTargetDevice(bool hmd, QAudio::Mode mode) { return deviceName; } -static void checkHmdDefaultsChange(QAudio::Mode mode) { +static void checkHmdDefaultsChange(QAudioDevice::Mode mode) { QString name; foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getAllDisplayPlugins()) { if (displayPlugin && displayPlugin->isHmd()) { - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { name = displayPlugin->getPreferredAudioInDevice(); } else { name = displayPlugin->getPreferredAudioOutDevice(); @@ -86,16 +86,16 @@ static void checkHmdDefaultsChange(QAudio::Mode mode) { if (!name.isEmpty()) { auto client = DependencyManager::get().data(); QMetaObject::invokeMethod(client, "setHmdAudioName", - Q_ARG(QAudio::Mode, mode), + Q_ARG(QAudioDevice::Mode, mode), Q_ARG(const QString&, name)); } } Qt::ItemFlags AudioDeviceList::_flags { Qt::ItemIsSelectable | Qt::ItemIsEnabled }; -AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) { - if (mode == QAudio::AudioInput) { - auto& setting1 = getSetting(true, QAudio::AudioInput); +AudioDeviceList::AudioDeviceList(QAudioDevice::Mode mode) : _mode(mode) { + if (mode == QAudioDevice::Mode::Input) { + auto& setting1 = getSetting(true, QAudioDevice::Mode::Input); if (setting1.isSet()) { qDebug() << "Device name in settings for HMD, Input" << setting1.get(); _backupSelectedHMDDeviceName = setting1.get(); @@ -104,8 +104,8 @@ AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) { } } - if (mode == QAudio::AudioOutput) { - auto& setting2 = getSetting(true, QAudio::AudioOutput); + if (mode == QAudioDevice::Mode::Output) { + auto& setting2 = getSetting(true, QAudioDevice::Mode::Output); if (setting2.isSet()) { qDebug() << "Device name in settings for HMD, Output" << setting2.get(); _backupSelectedHMDDeviceName = setting2.get(); @@ -114,8 +114,8 @@ AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) { } } - if (mode == QAudio::AudioInput) { - auto& setting3 = getSetting(false, QAudio::AudioInput); + if (mode == QAudioDevice::Mode::Input) { + auto& setting3 = getSetting(false, QAudioDevice::Mode::Input); if (setting3.isSet()) { qDebug() << "Device name in settings for Desktop, Input" << setting3.get(); _backupSelectedDesktopDeviceName = setting3.get(); @@ -124,8 +124,8 @@ AudioDeviceList::AudioDeviceList(QAudio::Mode mode) : _mode(mode) { } } - if (mode == QAudio::AudioOutput) { - auto& setting4 = getSetting(false, QAudio::AudioOutput); + if (mode == QAudioDevice::Mode::Output) { + auto& setting4 = getSetting(false, QAudioDevice::Mode::Output); if (setting4.isSet()) { qDebug() << "Device name in settings for Desktop, Output" << setting4.get(); _backupSelectedDesktopDeviceName = setting4.get(); @@ -188,13 +188,13 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { // FIXME can't use blocking connections here, so we can't determine whether the switch succeeded or not // We need to have the AudioClient emit signals on switch success / failure QMetaObject::invokeMethod(client, "switchAudioDevice", - Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName), Q_ARG(bool, contextIsHMD)); + Q_ARG(QAudioDevice::Mode, _mode), Q_ARG(QString, deviceName), Q_ARG(bool, contextIsHMD)); #if 0 bool switchResult = false; QMetaObject::invokeMethod(client, "switchAudioDevice", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, switchResult), - Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName)); + Q_ARG(QAudioDevice::Mode, _mode), Q_ARG(QString, deviceName)); // try to set to the default device for this mode if (!switchResult) { @@ -206,11 +206,11 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice(); } if (!deviceName.isNull()) { - QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName)); + QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudioDevice::Mode, _mode), Q_ARG(QString, deviceName)); } } else { // use the system default - QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, _mode)); + QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudioDevice::Mode, _mode)); } } #endif @@ -280,7 +280,7 @@ std::shared_ptr getSimilarDevice(const QString& deviceNa } -void AudioDeviceList::onDevicesChanged(QAudio::Mode mode, const QList& devices) { +void AudioDeviceList::onDevicesChanged(QAudioDevice::Mode mode, const QList& devices) { beginResetModel(); QList> newDevices; @@ -311,19 +311,7 @@ void AudioDeviceList::onDevicesChanged(QAudio::Mode mode, const QList& peakValueList) { - assert(_mode == QAudio::AudioInput); + assert(_mode == QAudioDevice::Mode::Input); if (peakValueList.length() != rowCount()) { qWarning() << "AudioDeviceList" << __FUNCTION__ << "length mismatch"; @@ -434,8 +422,8 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { connect(client, &AudioClient::devicesChanged, this, &AudioDevices::onDevicesChanged, Qt::QueuedConnection); connect(client, &AudioClient::peakValueListChanged, &_inputs, &AudioInputDeviceList::onPeakValueListChanged, Qt::QueuedConnection); - checkHmdDefaultsChange(QAudio::AudioInput); - checkHmdDefaultsChange(QAudio::AudioOutput); + checkHmdDefaultsChange(QAudioDevice::Mode::Input); + checkHmdDefaultsChange(QAudioDevice::Mode::Output); } AudioDevices::~AudioDevices() {} @@ -445,7 +433,7 @@ void AudioDevices::onContextChanged(const QString& context) { _outputs.resetDevice(_contextIsHMD); } -void AudioDevices::onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo& device, +void AudioDevices::onDeviceSelected(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device, const HifiAudioDeviceInfo& previousDevice, bool isHMD) { QString deviceName = device.deviceName(); @@ -463,7 +451,7 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo const QString MODE = "audio_mode"; const QString INPUT = "INPUT"; - const QString OUTPUT = "OUTPUT"; data[MODE] = mode == QAudio::AudioInput ? INPUT : OUTPUT; + const QString OUTPUT = "OUTPUT"; data[MODE] = mode == QAudioDevice::Mode::Input ? INPUT : OUTPUT; const QString CONTEXT = "display_mode"; data[CONTEXT] = _contextIsHMD ? Audio::HMD : Audio::DESKTOP; @@ -482,10 +470,10 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo } } -void AudioDevices::onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device) { - if (mode == QAudio::AudioInput) { +void AudioDevices::onDeviceChanged(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device) { + if (mode == QAudioDevice::Mode::Input) { if (_requestedInputDevice == device) { - onDeviceSelected(QAudio::AudioInput, device, + onDeviceSelected(QAudioDevice::Mode::Input, device, _contextIsHMD ? _inputs._selectedHMDDevice : _inputs._selectedDesktopDevice, _contextIsHMD); _requestedInputDevice = HifiAudioDeviceInfo(); @@ -493,7 +481,7 @@ void AudioDevices::onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& _inputs.onDeviceChanged(device, _contextIsHMD); } else { // if (mode == QAudio::AudioOutput) if (_requestedOutputDevice == device) { - onDeviceSelected(QAudio::AudioOutput, device, + onDeviceSelected(QAudioDevice::Mode::Output, device, _contextIsHMD ? _outputs._selectedHMDDevice : _outputs._selectedDesktopDevice, _contextIsHMD); _requestedOutputDevice = HifiAudioDeviceInfo(); @@ -502,21 +490,21 @@ void AudioDevices::onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& } } -void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices) { +void AudioDevices::onDevicesChanged(QAudioDevice::Mode mode, const QList& devices) { static std::once_flag once; std::call_once(once, [&] { //readout settings - _inputs._hmdSavedDeviceName = getTargetDevice(true, QAudio::AudioInput); - _inputs._desktopSavedDeviceName = getTargetDevice(false, QAudio::AudioInput); + _inputs._hmdSavedDeviceName = getTargetDevice(true, QAudioDevice::Mode::Input); + _inputs._desktopSavedDeviceName = getTargetDevice(false, QAudioDevice::Mode::Input); - _outputs._hmdSavedDeviceName = getTargetDevice(true, QAudio::AudioOutput); - _outputs._desktopSavedDeviceName = getTargetDevice(false, QAudio::AudioOutput); + _outputs._hmdSavedDeviceName = getTargetDevice(true, QAudioDevice::Mode::Output); + _outputs._desktopSavedDeviceName = getTargetDevice(false, QAudioDevice::Mode::Output); onContextChanged(QString()); }); //set devices for both contexts - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { _inputs.onDevicesChanged(mode, devices); static std::once_flag onceAfterInputDevicesChanged; @@ -540,11 +528,11 @@ void AudioDevices::chooseInputDevice(const HifiAudioDeviceInfo& device, bool isH auto client = DependencyManager::get().data(); _requestedInputDevice = device; QMetaObject::invokeMethod(client, "switchAudioDevice", - Q_ARG(QAudio::Mode, QAudio::AudioInput), + Q_ARG(QAudioDevice::Mode, QAudioDevice::Mode::Input), Q_ARG(const HifiAudioDeviceInfo&, device)); } else { //context is different. just save device in settings - onDeviceSelected(QAudio::AudioInput, device, + onDeviceSelected(QAudioDevice::Mode::Input, device, isHMD ? _inputs._selectedHMDDevice : _inputs._selectedDesktopDevice, isHMD); _inputs.onDeviceChanged(device, isHMD); @@ -557,11 +545,11 @@ void AudioDevices::chooseOutputDevice(const HifiAudioDeviceInfo& device, bool is auto client = DependencyManager::get().data(); _requestedOutputDevice = device; QMetaObject::invokeMethod(client, "switchAudioDevice", - Q_ARG(QAudio::Mode, QAudio::AudioOutput), + Q_ARG(QAudioDevice::Mode, QAudioDevice::Mode::Output), Q_ARG(const HifiAudioDeviceInfo&, device)); } else { //context is different. just save device in settings - onDeviceSelected(QAudio::AudioOutput, device, + onDeviceSelected(QAudioDevice::Mode::Output, device, isHMD ? _outputs._selectedHMDDevice : _outputs._selectedDesktopDevice, isHMD); _outputs.onDeviceChanged(device, isHMD); diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index 24d7580d0d6..8e61cb7c7b2 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -17,9 +17,9 @@ #include #include -#include +#include -#include +#include <../../audio-client/src/HifiAudioDeviceInfo.h> namespace scripting { @@ -36,7 +36,7 @@ class AudioDeviceList : public QAbstractListModel { Q_OBJECT public: - AudioDeviceList(QAudio::Mode mode = QAudio::AudioOutput); + AudioDeviceList(QAudioDevice::Mode mode = QAudioDevice::Mode::Output); virtual ~AudioDeviceList(); virtual std::shared_ptr newDevice(const AudioDevice& device) @@ -58,14 +58,14 @@ class AudioDeviceList : public QAbstractListModel { protected slots: void onDeviceChanged(const HifiAudioDeviceInfo& device, bool isHMD); - void onDevicesChanged(QAudio::Mode mode, const QList& devices); + void onDevicesChanged(QAudioDevice::Mode mode, const QList& devices); protected: friend class AudioDevices; static QHash _roles; static Qt::ItemFlags _flags; - const QAudio::Mode _mode; + const QAudioDevice::Mode _mode; HifiAudioDeviceInfo _selectedDesktopDevice; HifiAudioDeviceInfo _selectedHMDDevice; QString _backupSelectedDesktopDeviceName; @@ -87,7 +87,7 @@ class AudioInputDeviceList : public AudioDeviceList { Q_PROPERTY(bool peakValuesEnabled READ peakValuesEnabled WRITE setPeakValuesEnabled NOTIFY peakValuesEnabledChanged) public: - AudioInputDeviceList() : AudioDeviceList(QAudio::AudioInput) {} + AudioInputDeviceList() : AudioDeviceList(QAudioDevice::Input) {} virtual ~AudioInputDeviceList() = default; virtual std::shared_ptr newDevice(const AudioDevice& device) override @@ -131,10 +131,10 @@ private slots: void chooseOutputDevice(const HifiAudioDeviceInfo& device, bool isHMD); void onContextChanged(const QString& context); - void onDeviceSelected(QAudio::Mode mode, const HifiAudioDeviceInfo& device, + void onDeviceSelected(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device, const HifiAudioDeviceInfo& previousDevice, bool isHMD); - void onDeviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device); - void onDevicesChanged(QAudio::Mode mode, const QList& devices); + void onDeviceChanged(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device); + void onDevicesChanged(QAudioDevice::Mode mode, const QList& devices); private: friend class Audio; @@ -143,7 +143,7 @@ private slots: AudioDeviceList* getOutputList() { return &_outputs; } AudioInputDeviceList _inputs; - AudioDeviceList _outputs { QAudio::AudioOutput }; + AudioDeviceList _outputs { QAudioDevice::Mode::Output }; HifiAudioDeviceInfo _requestedOutputDevice; HifiAudioDeviceInfo _requestedInputDevice; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index af7ac8165b9..0ff9e670883 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -28,21 +28,21 @@ float ClipboardScriptingInterface::getClipboardContentsLargestDimension() { bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector& entityIDs) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "exportEntities", - Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename), - Q_ARG(const QVector&, entityIDs)); + Q_GENERIC_RETURN_ARG(bool, retVal), + Q_GENERIC_ARG(const QString&, filename), + Q_GENERIC_ARG(const QVector&, entityIDs)); return retVal; } bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float scale) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "exportEntities", - Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename), - Q_ARG(float, x), - Q_ARG(float, y), - Q_ARG(float, z), - Q_ARG(float, scale)); + Q_GENERIC_RETURN_ARG(bool, retVal), + Q_GENERIC_ARG(const QString&, filename), + Q_GENERIC_ARG(float, x), + Q_GENERIC_ARG(float, y), + Q_GENERIC_ARG(float, z), + Q_GENERIC_ARG(float, scale)); return retVal; } @@ -53,20 +53,20 @@ bool ClipboardScriptingInterface::importEntities( ) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "importEntities", - Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename), - Q_ARG(const bool, isObservable), - Q_ARG(const qint64, callerId)); + Q_GENERIC_RETURN_ARG(bool, retVal), + Q_GENERIC_ARG(const QString&, filename), + Q_GENERIC_ARG(const bool, isObservable), + Q_GENERIC_ARG(const qint64, callerId)); return retVal; } QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position, const QString& entityHostType) { QVector retVal; BLOCKING_INVOKE_METHOD(qApp, "pasteEntities", - Q_RETURN_ARG(QVector, retVal), - Q_ARG(const QString&, entityHostType), - Q_ARG(float, position.x), - Q_ARG(float, position.y), - Q_ARG(float, position.z)); + Q_GENERIC_RETURN_ARG(QVector, retVal), + Q_GENERIC_ARG(const QString&, entityHostType), + Q_GENERIC_ARG(float, position.x), + Q_GENERIC_ARG(float, position.y), + Q_GENERIC_ARG(float, position.z)); return retVal; } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 41f50e34686..f7fc5cf2408 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -44,7 +44,7 @@ class ClipboardScriptingInterface : public QObject { * } * } */ - Q_INVOKABLE glm::vec3 getContentsDimensions(); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getContentsDimensions(); /*@jsdoc * Gets the largest dimension of the extents of the entities held in the clipboard. @@ -121,7 +121,7 @@ class ClipboardScriptingInterface : public QObject { * @returns {Uuid[]} The IDs of the new entities that were created as a result of the paste operation. If entities couldn't * be created then an empty array is returned. */ - Q_INVOKABLE QVector pasteEntities(glm::vec3 position, const QString& entityHostType = "domain"); + Q_INVOKABLE QVector pasteEntities(glm::vec<3,float,glm::packed_highp> position, const QString& entityHostType = "domain"); }; #endif // hifi_ClipboardScriptingInterface_h diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 4128976fdc5..ef6bddf1c67 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -345,7 +345,7 @@ public slots: * @function Controller.getViewportDimensions * @returns {Vec2} The dimensions of the Interface window interior if in desktop mode or HUD surface if in HMD mode. */ - virtual glm::vec2 getViewportDimensions() const; + virtual glm::vec<2,float,glm::packed_highp> getViewportDimensions() const; /*@jsdoc * Gets the recommended area to position UI on the HUD surface if in HMD mode or Interface's window interior if in desktop @@ -484,6 +484,8 @@ public slots: using InputKey = controller::InputController::Key; }; +Q_DECLARE_METATYPE(ControllerScriptingInterface); + const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip const int NUMBER_OF_JOYSTICKS_PER_PALM = 1; const int NUMBER_OF_TRIGGERS_PER_PALM = 1; diff --git a/interface/src/scripting/DesktopScriptingInterface.cpp b/interface/src/scripting/DesktopScriptingInterface.cpp index f7ac8f43c91..1dbe4e9a76e 100644 --- a/interface/src/scripting/DesktopScriptingInterface.cpp +++ b/interface/src/scripting/DesktopScriptingInterface.cpp @@ -116,12 +116,22 @@ void DesktopScriptingInterface::show(const QString& path, const QString& title) InteractiveWindowPointer DesktopScriptingInterface::createWindow(const QString& sourceUrl, const QVariantMap& properties) { if (QThread::currentThread() != thread()) { + qDebug() << "DesktopScriptingInterface::createWindow" << sourceUrl; InteractiveWindowPointer interactiveWindow = nullptr; - BLOCKING_INVOKE_METHOD(this, "createWindowOnThread", + // QT6TODO + /*BLOCKING_INVOKE_METHOD(this, "createWindowOnThread", + Q_GENERIC_RETURN_ARG(InteractiveWindowPointer, interactiveWindow), + Q_GENERIC_ARG(QString, sourceUrl), + Q_GENERIC_ARG(QVariantMap, properties), + Q_GENERIC_ARG(QThread*, QThread::currentThread()));*/ + QMetaObject::invokeMethod(this, &DesktopScriptingInterface::createWindowOnThread/*"createWindowOnThread"*/, + Qt::BlockingQueuedConnection, Q_RETURN_ARG(InteractiveWindowPointer, interactiveWindow), - Q_ARG(QString, sourceUrl), - Q_ARG(QVariantMap, properties), - Q_ARG(QThread*, QThread::currentThread())); + sourceUrl, + properties, + QThread::currentThread() + ); + return interactiveWindow; } @@ -141,6 +151,8 @@ InteractiveWindowPointer DesktopScriptingInterface::createWindowOnThread(const Q // The offscreen surface already validates against non-local QML sources, but we also need to ensure that // if we create top level QML, like dock widgets or other types of QQuickView containing desktop windows // that the source URL is permitted + // QT6TODO: crashes for some reason, temporarily disabled + qDebug() << "DesktopScriptingInterface::createWindowOnThread " << sourceUrl; const auto& urlValidator = OffscreenQmlSurface::getUrlValidator(); if (!urlValidator(sourceUrl)) { return nullptr; diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 81516ae441b..5e8e597ed4c 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -90,8 +90,8 @@ class ScriptEngine; */ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency { Q_OBJECT - Q_PROPERTY(glm::vec3 position READ getPosition) - Q_PROPERTY(glm::quat orientation READ getOrientation) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> position READ getPosition) + Q_PROPERTY(glm::qua orientation READ getOrientation) Q_PROPERTY(bool showTablet READ getShouldShowTablet) Q_PROPERTY(bool tabletContextualMode READ getTabletContextualMode) Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID) @@ -103,7 +103,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen Q_PROPERTY(int miniTabletHand READ getCurrentMiniTabletHand WRITE setCurrentMiniTabletHand) Q_PROPERTY(bool miniTabletEnabled READ getMiniTabletEnabled WRITE setMiniTabletEnabled) Q_PROPERTY(QVariant playArea READ getPlayAreaRect); - Q_PROPERTY(QVector sensorPositions READ getSensorPositions); + Q_PROPERTY(QVector> sensorPositions READ getSensorPositions); Q_PROPERTY(float visionSqueezeRatioX READ getVisionSqueezeRatioX WRITE setVisionSqueezeRatioX); Q_PROPERTY(float visionSqueezeRatioY READ getVisionSqueezeRatioY WRITE setVisionSqueezeRatioY); @@ -142,9 +142,9 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * Overlays.deleteOverlay(square); * }); */ - Q_INVOKABLE glm::vec3 calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> calculateRayUICollisionPoint(const glm::vec<3,float,glm::packed_highp>& position, const glm::vec<3,float,glm::packed_highp>& direction) const; - glm::vec3 calculateParabolaUICollisionPoint(const glm::vec3& position, const glm::vec3& velocity, const glm::vec3& acceleration, float& parabolicDistance) const; + glm::vec<3,float,glm::packed_highp> calculateParabolaUICollisionPoint(const glm::vec<3,float,glm::packed_highp>& position, const glm::vec<3,float,glm::packed_highp>& velocity, const glm::vec<3,float,glm::packed_highp>& acceleration, float& parabolicDistance) const; /*@jsdoc * Gets the 2D HUD overlay coordinates of a 3D point on the HUD overlay. @@ -170,7 +170,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * Overlays.deleteOverlay(square); * }); */ - Q_INVOKABLE glm::vec2 overlayFromWorldPoint(const glm::vec3& position) const; + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> overlayFromWorldPoint(const glm::vec<3,float,glm::packed_highp>& position) const; /*@jsdoc * Gets the 3D world coordinates of a 2D point on the HUD overlay. @@ -179,7 +179,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * @param {Vec2} coordinates - The point on the HUD overlay in HUD coordinates. * @returns {Vec3} The point on the HUD overlay in world coordinates. */ - Q_INVOKABLE glm::vec3 worldPointFromOverlay(const glm::vec2& overlay) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldPointFromOverlay(const glm::vec<2,float,glm::packed_highp>& overlay) const; /*@jsdoc * Gets the 2D point on the HUD overlay represented by given spherical coordinates. @@ -190,7 +190,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * @param {Vec2} sphericalPos - The point on the HUD overlay in spherical coordinates. * @returns {Vec2} The point on the HUD overlay in HUD coordinates. */ - Q_INVOKABLE glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> sphericalToOverlay(const glm::vec<2,float,glm::packed_highp> & sphericalPos) const; /*@jsdoc * Gets the spherical coordinates of a 2D point on the HUD overlay. @@ -201,7 +201,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen * @param {Vec2} overlayPos - The point on the HUD overlay in HUD coordinates. * @returns {Vec2} The point on the HUD overlay in spherical coordinates. */ - Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> overlayToSpherical(const glm::vec<2,float,glm::packed_highp> & overlayPos) const; /*@jsdoc * Recenters the HMD HUD to the current HMD position and orientation. @@ -488,9 +488,9 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen bool getAwayStateWhenFocusLostInVREnabled(); QVariant getPlayAreaRect(); - QVector getSensorPositions(); + QVector> getSensorPositions(); - glm::vec3 getPosition() const; + glm::vec<3,float,glm::packed_highp> getPosition() const; private: bool _showTablet { false }; @@ -506,7 +506,7 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen bool _miniTabletEnabled { true }; // Get the orientation of the HMD - glm::quat getOrientation() const; + glm::qua getOrientation() const; bool getHUDLookAtPosition3D(glm::vec3& result) const; glm::mat4 getWorldHMDMatrix() const; diff --git a/interface/src/scripting/KeyboardScriptingInterface.cpp b/interface/src/scripting/KeyboardScriptingInterface.cpp index b031f2d749a..45c7df0d65b 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.cpp +++ b/interface/src/scripting/KeyboardScriptingInterface.cpp @@ -64,6 +64,10 @@ bool KeyboardScriptingInterface::getPreferMalletsOverLasers() const { return DependencyManager::get()->getPreferMalletsOverLasers(); } +void KeyboardScriptingInterface::setPreferMalletsOverLasers(bool mallets) { + return DependencyManager::get()->setPreferMalletsOverLasers(mallets); +} + bool KeyboardScriptingInterface::containsID(const QUuid& id) const { return DependencyManager::get()->containsID(id); } diff --git a/interface/src/scripting/KeyboardScriptingInterface.h b/interface/src/scripting/KeyboardScriptingInterface.h index 196c55ffa4a..b261409c302 100644 --- a/interface/src/scripting/KeyboardScriptingInterface.h +++ b/interface/src/scripting/KeyboardScriptingInterface.h @@ -42,7 +42,7 @@ class KeyboardScriptingInterface : public QObject, public Dependency { Q_PROPERTY(bool raised READ isRaised WRITE setRaised) Q_PROPERTY(bool password READ isPassword WRITE setPassword) Q_PROPERTY(bool use3DKeyboard READ getUse3DKeyboard CONSTANT); - Q_PROPERTY(bool preferMalletsOverLasers READ getPreferMalletsOverLasers CONSTANT) + Q_PROPERTY(bool preferMalletsOverLasers READ getPreferMalletsOverLasers WRITE setPreferMalletsOverLasers) public: KeyboardScriptingInterface() = default; @@ -104,6 +104,7 @@ class KeyboardScriptingInterface : public QObject, public Dependency { private: bool getPreferMalletsOverLasers() const; + void setPreferMalletsOverLasers(bool mallets); bool isRaised() const; void setRaised(bool raised); diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 9829ab8343f..4fe93987f32 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -68,8 +68,8 @@ bool MenuScriptingInterface::menuExists(const QString& menu) { bool result { false }; BLOCKING_INVOKE_METHOD(menuInstance, "menuExists", - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menu)); + Q_GENERIC_RETURN_ARG(bool, result), + Q_GENERIC_ARG(const QString&, menu)); return result; } @@ -131,8 +131,8 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& return; } QMetaObject::invokeMethod(menuInstance, "removeMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); + Q_GENERIC_ARG(const QString&, menu), + Q_GENERIC_ARG(const QString&, menuitem)); }; bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) { @@ -148,9 +148,9 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& bool result { false }; BLOCKING_INVOKE_METHOD(menuInstance, "menuItemExists", - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); + Q_GENERIC_RETURN_ARG(bool, result), + Q_GENERIC_ARG(const QString&, menu), + Q_GENERIC_ARG(const QString&, menuitem)); return result; } @@ -168,8 +168,8 @@ bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { bool result { false }; BLOCKING_INVOKE_METHOD(menuInstance, "isOptionChecked", - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menuOption)); + Q_GENERIC_RETURN_ARG(bool, result), + Q_GENERIC_ARG(const QString&, menuOption)); return result; } @@ -180,8 +180,8 @@ void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool } QMetaObject::invokeMethod(menuInstance, "setIsOptionChecked", - Q_ARG(const QString&, menuOption), - Q_ARG(bool, isChecked)); + Q_GENERIC_ARG(const QString&, menuOption), + Q_GENERIC_ARG(bool, isChecked)); } bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) { @@ -197,8 +197,8 @@ bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) { bool result { false }; BLOCKING_INVOKE_METHOD(menuInstance, "isMenuEnabled", - Q_RETURN_ARG(bool, result), - Q_ARG(const QString&, menuOption)); + Q_GENERIC_RETURN_ARG(bool, result), + Q_GENERIC_ARG(const QString&, menuOption)); return result; } @@ -210,8 +210,8 @@ void MenuScriptingInterface::setMenuEnabled(const QString& menuOption, bool isCh } QMetaObject::invokeMethod(menuInstance, "setMenuEnabled", - Q_ARG(const QString&, menuOption), - Q_ARG(bool, isChecked)); + Q_GENERIC_ARG(const QString&, menuOption), + Q_GENERIC_ARG(bool, isChecked)); } void MenuScriptingInterface::triggerOption(const QString& menuOption) { @@ -220,7 +220,7 @@ void MenuScriptingInterface::triggerOption(const QString& menuOption) { return; } - QMetaObject::invokeMethod(menuInstance, "triggerOption", Q_ARG(const QString&, menuOption)); + QMetaObject::invokeMethod(menuInstance, "triggerOption", Q_GENERIC_ARG(const QString&, menuOption)); } void MenuScriptingInterface::setVisible(bool visible) { diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp index 00cdf009eb6..1f82c0956ee 100644 --- a/interface/src/scripting/SettingsScriptingInterface.cpp +++ b/interface/src/scripting/SettingsScriptingInterface.cpp @@ -56,7 +56,7 @@ void SettingsScriptingInterface::setValue(const QString& setting, const QVariant } // Make a deep-copy of the string. // Dangling pointers can occur with QStrings that are implicitly shared from a ScriptEngine. - QString deepCopy = QString::fromUtf16(setting.utf16()); + QString deepCopy = QString(setting.utf16()); Setting::Handle(deepCopy).set(value); emit valueChanged(setting, value); } diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index bc3f59e9174..10d9bc3cd0c 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -66,7 +66,7 @@ void TestScriptingInterface::waitIdle() { bool TestScriptingInterface::loadTestScene(QString scene) { if (QThread::currentThread() != thread()) { bool result; - BLOCKING_INVOKE_METHOD(this, "loadTestScene", Q_RETURN_ARG(bool, result), Q_ARG(QString, scene)); + BLOCKING_INVOKE_METHOD(this, "loadTestScene", Q_GENERIC_RETURN_ARG(bool, result), Q_GENERIC_ARG(QString, scene)); return result; } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 81d88451e3d..b8f362eb12a 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -517,11 +517,11 @@ int WindowScriptingInterface::openMessageBox(QString title, QString text, int bu if (QThread::currentThread() != thread()) { int result; BLOCKING_INVOKE_METHOD(this, "openMessageBox", - Q_RETURN_ARG(int, result), - Q_ARG(QString, title), - Q_ARG(QString, text), - Q_ARG(int, buttons), - Q_ARG(int, defaultButton)); + Q_GENERIC_RETURN_ARG(int, result), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QString, text), + Q_GENERIC_ARG(int, buttons), + Q_GENERIC_ARG(int, defaultButton)); return result; } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index af7f25ea9ed..2819538def1 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -400,7 +400,7 @@ public slots: * ".jpeg", ".png", or ".webp" — or if not provided then in the format chosen in general settings, * Default is PNG. Animated images are saved in GIF format.

*/ - void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString()); + void takeSecondaryCamera360Snapshot(const glm::vec<3,float,glm::packed_highp>& cameraPosition, const bool& cubemapOutputFormat = false, const bool& notify = true, const QString& filename = QString()); /*@jsdoc * Emits a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that @@ -483,7 +483,7 @@ public slots: * @function Window.getDeviceSize * @returns {Vec2} The width and height of the Interface window or HMD rendering surface, in pixels. */ - glm::vec2 getDeviceSize() const; + glm::vec<2,float,glm::packed_highp> getDeviceSize() const; /*@jsdoc * Gets the last domain connection error when a connection is refused. diff --git a/interface/src/ui/BaseLogDialog.cpp b/interface/src/ui/BaseLogDialog.cpp index c018e6508cf..7b2b912c520 100644 --- a/interface/src/ui/BaseLogDialog.cpp +++ b/interface/src/ui/BaseLogDialog.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -180,14 +181,16 @@ Highlighter::Highlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) { } void Highlighter::highlightBlock(const QString& text) { - QRegExp expression(BOLD_PATTERN); + QRegularExpression expression(BOLD_PATTERN); - int index = text.indexOf(expression, 0); + auto expressionMatch = expression.match(text); + qsizetype index = expressionMatch.capturedStart(); while (index >= 0) { - int length = expression.matchedLength(); + qsizetype length = expressionMatch.capturedLength(); setFormat(index, length, boldFormat); - index = text.indexOf(expression, index + length); + expressionMatch = expression.match(text, index + length); + index = expressionMatch.capturedStart(); } if (keyword.isNull() || keyword.isEmpty()) { diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 46ca7bbe039..6827192c5eb 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -163,7 +163,12 @@ void DialogsManager::showUpdateDialog() { void DialogsManager::octreeStatsDetails() { if (!_octreeStatsDialog) { - _octreeStatsDialog = new OctreeStatsDialog(qApp->getWindow(), qApp->getOcteeSceneStats()); + auto octreeSceneStats = qApp->getOcteeSceneStats(); + if (!octreeSceneStats) { + qCritical() << "DialogsManager::octreeStatsDetails(): Octree scene stats object not available yet. This should never happen."; + std::abort(); + } + _octreeStatsDialog = new OctreeStatsDialog(qApp->getWindow(), octreeSceneStats.value()); if (_hmdToolsDialog) { _hmdToolsDialog->watchWindow(_octreeStatsDialog->windowHandle()); diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index 702a24fd1a9..bb1b5afb488 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -11,7 +11,6 @@ #include "HMDToolsDialog.h" -#include #include #include #include diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp index 2761b1c9f07..8cad284ffe2 100644 --- a/interface/src/ui/InteractiveWindow.cpp +++ b/interface/src/ui/InteractiveWindow.cpp @@ -34,7 +34,7 @@ #include "MainWindow.h" #ifdef Q_OS_WIN -#include +#include #endif STATIC_SCRIPT_TYPES_INITIALIZER(+[](ScriptManager* manager){ @@ -421,7 +421,7 @@ void InteractiveWindow::close() { if (_dockWidget) { auto window = qApp->getWindow(); if (QThread::currentThread() != window->thread()) { - BLOCKING_INVOKE_METHOD(window, "removeDockWidget", Q_ARG(QDockWidget*, _dockWidget.get())); + BLOCKING_INVOKE_METHOD(window, "removeDockWidget", Q_GENERIC_ARG(QDockWidget*, _dockWidget.get())); } else { window->removeDockWidget(_dockWidget.get()); } diff --git a/interface/src/ui/InteractiveWindow.h b/interface/src/ui/InteractiveWindow.h index 3d69185ecfc..1c98c4d0cde 100644 --- a/interface/src/ui/InteractiveWindow.h +++ b/interface/src/ui/InteractiveWindow.h @@ -186,10 +186,10 @@ class InteractiveWindow : public QObject { Q_OBJECT Q_PROPERTY(QString title READ getTitle WRITE setTitle) - Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> position READ getPosition WRITE setPosition) Q_PROPERTY(RelativePositionAnchor relativePositionAnchor READ getRelativePositionAnchor WRITE setRelativePositionAnchor) - Q_PROPERTY(glm::vec2 relativePosition READ getRelativePosition WRITE setRelativePosition) - Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> relativePosition READ getRelativePosition WRITE setRelativePosition) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> size READ getSize WRITE setSize) Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode) @@ -202,8 +202,8 @@ class InteractiveWindow : public QObject { Q_INVOKABLE QString getTitle() const; Q_INVOKABLE void setTitle(const QString& title); - Q_INVOKABLE glm::vec2 getPosition() const; - Q_INVOKABLE void setPosition(const glm::vec2& position); + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> getPosition() const; + Q_INVOKABLE void setPosition(const glm::vec<2,float,glm::packed_highp>& position); RelativePositionAnchor _relativePositionAnchor{ RelativePositionAnchor::NO_ANCHOR }; Q_INVOKABLE RelativePositionAnchor getRelativePositionAnchor() const; @@ -212,16 +212,16 @@ class InteractiveWindow : public QObject { // This "relative position" is relative to the "relative position anchor" and excludes the window frame. // This position will ALWAYS include the geometry of a docked widget, if one is present. glm::vec2 _relativePosition{ 0.0f, 0.0f }; - Q_INVOKABLE glm::vec2 getRelativePosition() const; - Q_INVOKABLE void setRelativePosition(const glm::vec2& position); + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> getRelativePosition() const; + Q_INVOKABLE void setRelativePosition(const glm::vec<2,float,glm::packed_highp>& position); Q_INVOKABLE void setPositionUsingRelativePositionAndAnchor(const QRect& mainWindowGeometry); bool _isFullScreenWindow{ false }; Q_INVOKABLE void repositionAndResizeFullScreenWindow(); - Q_INVOKABLE glm::vec2 getSize() const; - Q_INVOKABLE void setSize(const glm::vec2& size); + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> getSize() const; + Q_INVOKABLE void setSize(const glm::vec<2,float,glm::packed_highp>& size); Q_INVOKABLE void setVisible(bool visible); Q_INVOKABLE bool isVisible() const; @@ -263,7 +263,7 @@ public slots: * // QML file, "InteractiveWindow.qml". * * import QtQuick 2.5 - * import QtQuick.Controls 1.4 + * import QtQuick.Controls 2.3 * * Rectangle { * diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 0a7b125a481..4280d972810 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -64,7 +64,7 @@ void _writeLines(const QString& filename, const QList& lines) { file.open(QFile::WriteOnly); auto root = QJsonObject(); root["version"] = 1.0; - root["last-modified"] = QDateTime::currentDateTime().toTimeSpec(Qt::OffsetFromUTC).toString(Qt::ISODate); + root["last-modified"] = QDateTime::currentDateTime().toOffsetFromUtc(Qt::OffsetFromUTC).toString(Qt::ISODate); root[JSON_KEY] = QJsonArray::fromStringList(lines); auto json = QJsonDocument(root).toJson(); QTextStream(&file) << json; @@ -129,7 +129,7 @@ JSConsole::JSConsole(QWidget* parent, const ScriptManagerPointer& scriptManager) QWidget(parent), _ui(new Ui::Console), _currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND), - _savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME), + _savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + HISTORY_FILENAME), _commandHistory(_readLines(_savedHistoryFilename)), _completer(new QCompleter(this)), _monospaceFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)), @@ -512,9 +512,9 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) { const int MODULE_INDEX = 3; const int PROPERTY_INDEX = 4; // TODO: disallow invalid characters on left of property - QRegExp regExp("((([A-Za-z0-9_\\.]+)\\.)|(?!\\.))([a-zA-Z0-9_]*)$"); - regExp.indexIn(leftOfCursor); - auto rexExpCapturedTexts = regExp.capturedTexts(); + QRegularExpression regExp("((([A-Za-z0-9_\\.]+)\\.)|(?!\\.))([a-zA-Z0-9_]*)$"); + auto regExpMatch = regExp.match(leftOfCursor); + auto rexExpCapturedTexts = regExpMatch.capturedTexts(); auto memberOf = rexExpCapturedTexts[MODULE_INDEX]; completionPrefix = rexExpCapturedTexts[PROPERTY_INDEX]; bool switchedModule = false; @@ -591,7 +591,8 @@ void JSConsole::scrollToBottom() { void JSConsole::appendMessage(const QString& gutter, const QString& message, const QColor& fgColor, const QColor& bgColor) { QWidget* logLine = new QWidget(_ui->logArea); QHBoxLayout* layout = new QHBoxLayout(logLine); - layout->setMargin(0); + // QT6TODO: + //layout->setMargin(0); layout->setSpacing(4); QLabel* gutterLabel = new QLabel(logLine); diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 65a0d2ea37b..c6379cf8ed7 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -61,7 +61,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _debugPrintBox->setCheckState(Qt::Checked); } _debugPrintBox->show(); - connect(_debugPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleDebugPrintBox); + connect(_debugPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleDebugPrintBox); _leftPad += DEBUG_CHECKBOX_WIDTH + BUTTON_MARGIN; _infoPrintBox = new QCheckBox("INFO", this); @@ -70,7 +70,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _infoPrintBox->setCheckState(Qt::Checked); } _infoPrintBox->show(); - connect(_infoPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleInfoPrintBox); + connect(_infoPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleInfoPrintBox); _leftPad += INFO_CHECKBOX_WIDTH + BUTTON_MARGIN; _criticalPrintBox = new QCheckBox("CRITICAL", this); @@ -79,7 +79,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _criticalPrintBox->setCheckState(Qt::Checked); } _criticalPrintBox->show(); - connect(_criticalPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleCriticalPrintBox); + connect(_criticalPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleCriticalPrintBox); _leftPad += CRITICAL_CHECKBOX_WIDTH + BUTTON_MARGIN; _warningPrintBox = new QCheckBox("WARNING", this); @@ -88,7 +88,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _warningPrintBox->setCheckState(Qt::Checked); } _warningPrintBox->show(); - connect(_warningPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleWarningPrintBox); + connect(_warningPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleWarningPrintBox); _leftPad += WARNING_CHECKBOX_WIDTH + BUTTON_MARGIN; _suppressPrintBox = new QCheckBox("SUPPRESS", this); @@ -97,7 +97,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _suppressPrintBox->setCheckState(Qt::Checked); } _suppressPrintBox->show(); - connect(_suppressPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleSuppressPrintBox); + connect(_suppressPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleSuppressPrintBox); _leftPad += SUPPRESS_CHECKBOX_WIDTH + BUTTON_MARGIN; _fatalPrintBox = new QCheckBox("FATAL", this); @@ -106,7 +106,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _fatalPrintBox->setCheckState(Qt::Checked); } _fatalPrintBox->show(); - connect(_fatalPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleFatalPrintBox); + connect(_fatalPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleFatalPrintBox); _leftPad += FATAL_CHECKBOX_WIDTH + BUTTON_MARGIN; _unknownPrintBox = new QCheckBox("UNKNOWN", this); @@ -115,7 +115,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _unknownPrintBox->setCheckState(Qt::Checked); } _unknownPrintBox->show(); - connect(_unknownPrintBox, &QCheckBox::stateChanged, this, &LogDialog::handleUnknownPrintBox); + connect(_unknownPrintBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleUnknownPrintBox); _leftPad = MARGIN_LEFT; _filterDropdown = new QComboBox(this); @@ -156,7 +156,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog #ifdef Q_OS_WIN connect(_keepOnTopBox, &QCheckBox::stateChanged, qApp, &Application::recreateLogWindow); #else - connect(_keepOnTopBox, &QCheckBox::stateChanged, this, &LogDialog::handleKeepWindowOnTop); + connect(_keepOnTopBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleKeepWindowOnTop); #endif _keepOnTopBox->show(); @@ -165,14 +165,14 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _extraDebuggingBox->setCheckState(Qt::Checked); } _extraDebuggingBox->show(); - connect(_extraDebuggingBox, &QCheckBox::stateChanged, this, &LogDialog::handleExtraDebuggingCheckbox); + connect(_extraDebuggingBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleExtraDebuggingCheckbox); _showSourceDebuggingBox = new QCheckBox("Show script sources", this); if (_logger->showSourceDebugging()) { _showSourceDebuggingBox->setCheckState(Qt::Checked); } _showSourceDebuggingBox->show(); - connect(_showSourceDebuggingBox, &QCheckBox::stateChanged, this, &LogDialog::handleShowSourceDebuggingCheckbox); + connect(_showSourceDebuggingBox, &QCheckBox::checkStateChanged, this, &LogDialog::handleShowSourceDebuggingCheckbox); _allLogsButton = new QPushButton("All Messages", this); // set object name for css styling diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index cd706d0bcb5..aa9a64b32ec 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index f68f5c8d927..24ec20f2caa 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -188,35 +188,37 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { unsigned long totalInternal = 0; unsigned long totalLeaves = 0; - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - for (NodeToOctreeSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) { - //const QUuid& uuid = i->first; - OctreeSceneStats& stats = i->second; - serverCount++; - - // calculate server node totals - totalNodes += stats.getTotalElements(); - totalInternal += stats.getTotalInternal(); - totalLeaves += stats.getTotalLeaves(); - - // Sending mode - if (serverCount > 1) { - sendingMode << ","; - } - if (stats.isMoving()) { - sendingMode << "M"; - movingServerCount++; - } else { - sendingMode << "S"; - } - if (stats.isFullScene()) { - sendingMode << "F"; - } else { - sendingMode << "p"; + auto sceneStats = qApp->getOcteeSceneStats(); + if (sceneStats) { + sceneStats.value()->withReadLock([&] { + for (NodeToOctreeSceneStatsIterator i = sceneStats.value()->begin(); i != sceneStats.value()->end(); i++) { + //const QUuid& uuid = i->first; + OctreeSceneStats& stats = i->second; + serverCount++; + + // calculate server node totals + totalNodes += stats.getTotalElements(); + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + + // Sending mode + if (serverCount > 1) { + sendingMode << ","; + } + if (stats.isMoving()) { + sendingMode << "M"; + movingServerCount++; + } else { + sendingMode << "S"; + } + if (stats.isFullScene()) { + sendingMode << "F"; + } else { + sendingMode << "p"; + } } - } - }); + }); + } sendingMode << " - " << serverCount << " servers"; if (movingServerCount > 0) { sendingMode << " "; @@ -388,114 +390,116 @@ void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { // now lookup stats details for this server... if (_extraServerDetails != LESS) { - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); - - switch (_extraServerDetails) { - case MOST: { - extraDetails << "
"; - - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; - float lastFullPackets = stats.getLastFullTotalPackets(); - float lastFullPPS = lastFullPackets; - if (lastFullSendInSeconds > 0) { - lastFullPPS = lastFullPackets / lastFullSendInSeconds; - } - - QString lastFullEncodeString = locale.toString(lastFullEncode); - QString lastFullSendString = locale.toString(lastFullSend); - QString lastFullPacketsString = locale.toString(lastFullPackets); - QString lastFullBytesString = locale.toString((uint)stats.getLastFullTotalBytes()); - QString lastFullPPSString = locale.toString(lastFullPPS); - - extraDetails << "
" << "Last Full Scene... " << - "Encode: " << qPrintable(lastFullEncodeString) << " ms " << - "Send: " << qPrintable(lastFullSendString) << " ms " << - "Packets: " << qPrintable(lastFullPacketsString) << " " << - "Bytes: " << qPrintable(lastFullBytesString) << " " << - "Rate: " << qPrintable(lastFullPPSString) << " PPS"; - - for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { - OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); - OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - extraDetails << "
" << itemInfo.caption << " " << stats.getItemValue(item); - } - } // fall through... since MOST has all of MORE - /* fall-thru */ - case MORE: { - QString totalString = locale.toString((uint)stats.getTotalElements()); - QString internalString = locale.toString((uint)stats.getTotalInternal()); - QString leavesString = locale.toString((uint)stats.getTotalLeaves()); - - serverDetails << "
" << "Node UUID: " << qPrintable(nodeUUID.toString()) << " "; - - serverDetails << "
" << "Elements: " << - qPrintable(totalString) << " total " << - qPrintable(internalString) << " internal " << - qPrintable(leavesString) << " leaves "; - - QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets()); - QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); - QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); - const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - QString incomingOutOfOrderString = locale.toString((uint)seqStats.getOutOfOrder()); - QString incomingLateString = locale.toString((uint)seqStats.getLate()); - QString incomingUnreasonableString = locale.toString((uint)seqStats.getUnreasonable()); - QString incomingEarlyString = locale.toString((uint)seqStats.getEarly()); - QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost()); - QString incomingRecovered = locale.toString((uint)seqStats.getRecovered()); - - qint64 clockSkewInUsecs = node->getClockSkewUsec(); - QString formattedClockSkewString = formatUsecTime(clockSkewInUsecs); - qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; - QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); - QString incomingPingTimeString = locale.toString(node->getPingMs()); - QString incomingClockSkewString = locale.toString(clockSkewInMS); - - serverDetails << "
" << "Incoming Packets: " << qPrintable(incomingPacketsString) << - "/ Lost: " << qPrintable(incomingLikelyLostString) << - "/ Recovered: " << qPrintable(incomingRecovered); - - serverDetails << "
" << " Out of Order: " << qPrintable(incomingOutOfOrderString) << - "/ Early: " << qPrintable(incomingEarlyString) << - "/ Late: " << qPrintable(incomingLateString) << - "/ Unreasonable: " << qPrintable(incomingUnreasonableString); - - serverDetails << "
" << - " Average Flight Time: " << qPrintable(incomingFlightTimeString) << " msecs"; - - serverDetails << "
" << - " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; - - serverDetails << "
" << - " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << - " [" << qPrintable(formattedClockSkewString) << "]"; - - - serverDetails << "
" << "Incoming" << - " Bytes: " << qPrintable(incomingBytesString) << - " Wasted Bytes: " << qPrintable(incomingWastedBytesString); - - serverDetails << extraDetails.str(); - if (_extraServerDetails == MORE) { - linkDetails << " [most...]"; - linkDetails << " [less...]"; - } else { - linkDetails << " [less...]"; - linkDetails << " [least...]"; - } - - } break; - case LESS: { - // nothing - } break; + auto sceneStats = qApp->getOcteeSceneStats(); + if (sceneStats) { + sceneStats.value()->withReadLock([&] { + if (sceneStats.value()->find(nodeUUID) != sceneStats.value()->end()) { + OctreeSceneStats& stats = sceneStats.value()->at(nodeUUID); + + switch (_extraServerDetails) { + case MOST: { + extraDetails << "
"; + + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; + } + + QString lastFullEncodeString = locale.toString(lastFullEncode); + QString lastFullSendString = locale.toString(lastFullSend); + QString lastFullPacketsString = locale.toString(lastFullPackets); + QString lastFullBytesString = locale.toString((uint)stats.getLastFullTotalBytes()); + QString lastFullPPSString = locale.toString(lastFullPPS); + + extraDetails << "
" << "Last Full Scene... " << + "Encode: " << qPrintable(lastFullEncodeString) << " ms " << + "Send: " << qPrintable(lastFullSendString) << " ms " << + "Packets: " << qPrintable(lastFullPacketsString) << " " << + "Bytes: " << qPrintable(lastFullBytesString) << " " << + "Rate: " << qPrintable(lastFullPPSString) << " PPS"; + + for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { + OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); + OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + extraDetails << "
" << itemInfo.caption << " " << stats.getItemValue(item); + } + } // fall through... since MOST has all of MORE + /* fall-thru */ + case MORE: { + QString totalString = locale.toString((uint)stats.getTotalElements()); + QString internalString = locale.toString((uint)stats.getTotalInternal()); + QString leavesString = locale.toString((uint)stats.getTotalLeaves()); + + serverDetails << "
" << "Node UUID: " << qPrintable(nodeUUID.toString()) << " "; + + serverDetails << "
" << "Elements: " << + qPrintable(totalString) << " total " << + qPrintable(internalString) << " internal " << + qPrintable(leavesString) << " leaves "; + + QString incomingPacketsString = locale.toString((uint)stats.getIncomingPackets()); + QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); + QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); + const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); + QString incomingOutOfOrderString = locale.toString((uint)seqStats.getOutOfOrder()); + QString incomingLateString = locale.toString((uint)seqStats.getLate()); + QString incomingUnreasonableString = locale.toString((uint)seqStats.getUnreasonable()); + QString incomingEarlyString = locale.toString((uint)seqStats.getEarly()); + QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost()); + QString incomingRecovered = locale.toString((uint)seqStats.getRecovered()); + + qint64 clockSkewInUsecs = node->getClockSkewUsec(); + QString formattedClockSkewString = formatUsecTime(clockSkewInUsecs); + qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; + QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); + QString incomingPingTimeString = locale.toString(node->getPingMs()); + QString incomingClockSkewString = locale.toString(clockSkewInMS); + + serverDetails << "
" << "Incoming Packets: " << qPrintable(incomingPacketsString) << + "/ Lost: " << qPrintable(incomingLikelyLostString) << + "/ Recovered: " << qPrintable(incomingRecovered); + + serverDetails << "
" << " Out of Order: " << qPrintable(incomingOutOfOrderString) << + "/ Early: " << qPrintable(incomingEarlyString) << + "/ Late: " << qPrintable(incomingLateString) << + "/ Unreasonable: " << qPrintable(incomingUnreasonableString); + + serverDetails << "
" << + " Average Flight Time: " << qPrintable(incomingFlightTimeString) << " msecs"; + + serverDetails << "
" << + " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; + + serverDetails << "
" << + " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << + " [" << qPrintable(formattedClockSkewString) << "]"; + + + serverDetails << "
" << "Incoming" << + " Bytes: " << qPrintable(incomingBytesString) << + " Wasted Bytes: " << qPrintable(incomingWastedBytesString); + + serverDetails << extraDetails.str(); + if (_extraServerDetails == MORE) { + linkDetails << " [most...]"; + linkDetails << " [less...]"; + } else { + linkDetails << " [less...]"; + linkDetails << " [least...]"; + } + + } break; + case LESS: { + // nothing + } break; + } } - } - }); + }); + } } else { linkDetails << " [more...]"; linkDetails << " [most...]"; diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index 133af1f7fe0..f4cbda8d1b1 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -115,35 +115,37 @@ void OctreeStatsProvider::updateOctreeStatsData() { unsigned long totalLeaves = 0; m_sendingMode.clear(); - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - for (NodeToOctreeSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) { - //const QUuid& uuid = i->first; - OctreeSceneStats& stats = i->second; - serverCount++; - - // calculate server node totals - totalNodes += stats.getTotalElements(); - totalInternal += stats.getTotalInternal(); - totalLeaves += stats.getTotalLeaves(); - - // Sending mode - if (serverCount > 1) { - m_sendingMode += ","; - } - if (stats.isMoving()) { - m_sendingMode += "M"; - movingServerCount++; - } else { - m_sendingMode += "S"; - } - if (stats.isFullScene()) { - m_sendingMode += "F"; - } else { - m_sendingMode += "p"; + auto sceneStats = qApp->getOcteeSceneStats(); + if (sceneStats) { + sceneStats.value()->withReadLock([&] { + for (NodeToOctreeSceneStatsIterator i = sceneStats.value()->begin(); i != sceneStats.value()->end(); i++) { + //const QUuid& uuid = i->first; + OctreeSceneStats& stats = i->second; + serverCount++; + + // calculate server node totals + totalNodes += stats.getTotalElements(); + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + + // Sending mode + if (serverCount > 1) { + m_sendingMode += ","; + } + if (stats.isMoving()) { + m_sendingMode += "M"; + movingServerCount++; + } else { + m_sendingMode += "S"; + } + if (stats.isFullScene()) { + m_sendingMode += "F"; + } else { + m_sendingMode += "p"; + } } - } - }); + }); + } m_sendingMode += QString(" - %1 servers").arg(serverCount); if (movingServerCount > 0) { m_sendingMode += " "; @@ -262,72 +264,74 @@ void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { QUuid nodeUUID = node->getUUID(); // now lookup stats details for this server... - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); - - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; - float lastFullPackets = stats.getLastFullTotalPackets(); - float lastFullPPS = lastFullPackets; - if (lastFullSendInSeconds > 0) { - lastFullPPS = lastFullPackets / lastFullSendInSeconds; - } - - mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") - .arg(lastFullEncode) - .arg(lastFullSend) - .arg(lastFullPackets) - .arg(stats.getLastFullTotalBytes()) - .arg(lastFullPPS); - - for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { - OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); - OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - mostDetails += QString("
%1 %2") - .arg(itemInfo.caption).arg(stats.getItemValue(item)); + auto sceneStats = qApp->getOcteeSceneStats(); + if (sceneStats) { + sceneStats.value()->withReadLock([&] { + if (sceneStats.value()->find(nodeUUID) != sceneStats.value()->end()) { + OctreeSceneStats& stats = sceneStats.value()->at(nodeUUID); + + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; + } + + mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") + .arg(lastFullEncode) + .arg(lastFullSend) + .arg(lastFullPackets) + .arg(stats.getLastFullTotalBytes()) + .arg(lastFullPPS); + + for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { + OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); + OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + mostDetails += QString("
%1 %2") + .arg(itemInfo.caption).arg(stats.getItemValue(item)); + } + + moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; + + moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") + .arg(stats.getTotalElements()) + .arg(stats.getTotalInternal()) + .arg(stats.getTotalLeaves()); + + const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); + qint64 clockSkewInUsecs = node->getClockSkewUsec(); + qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; + + moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") + .arg(stats.getIncomingPackets()) + .arg(seqStats.getLost()) + .arg(seqStats.getRecovered()); + + moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") + .arg(seqStats.getOutOfOrder()) + .arg(seqStats.getEarly()) + .arg(seqStats.getLate()) + .arg(seqStats.getUnreasonable()); + + moreDetails += QString("
Average Flight Time: %1 msecs") + .arg(stats.getIncomingFlightTimeAverage()); + + moreDetails += QString("
Average Ping Time: %1 msecs") + .arg(node->getPingMs()); + + moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") + .arg(clockSkewInMS) + .arg(formatUsecTime(clockSkewInUsecs)); + + + moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") + .arg(stats.getIncomingBytes()) + .arg(stats.getIncomingWastedBytes()); } - - moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; - - moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") - .arg(stats.getTotalElements()) - .arg(stats.getTotalInternal()) - .arg(stats.getTotalLeaves()); - - const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - qint64 clockSkewInUsecs = node->getClockSkewUsec(); - qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; - - moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") - .arg(stats.getIncomingPackets()) - .arg(seqStats.getLost()) - .arg(seqStats.getRecovered()); - - moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") - .arg(seqStats.getOutOfOrder()) - .arg(seqStats.getEarly()) - .arg(seqStats.getLate()) - .arg(seqStats.getUnreasonable()); - - moreDetails += QString("
Average Flight Time: %1 msecs") - .arg(stats.getIncomingFlightTimeAverage()); - - moreDetails += QString("
Average Ping Time: %1 msecs") - .arg(node->getPingMs()); - - moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") - .arg(clockSkewInMS) - .arg(formatUsecTime(clockSkewInUsecs)); - - - moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") - .arg(stats.getIncomingBytes()) - .arg(stats.getIncomingWastedBytes()); - } - }); + }); + } m_servers.append(lesserDetails); m_servers.append(moreDetails); m_servers.append(mostDetails); diff --git a/interface/src/ui/ResourceImageItem.cpp b/interface/src/ui/ResourceImageItem.cpp index 46ffffe62dd..8b60234df34 100644 --- a/interface/src/ui/ResourceImageItem.cpp +++ b/interface/src/ui/ResourceImageItem.cpp @@ -162,5 +162,6 @@ void ResourceImageItemRenderer::render() { _fboMutex.unlock(); } glFlush(); - _window->resetOpenGLState(); + // QT6TODO: check if this can be omitted + //_window->resetOpenGLState(); } diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 2884574767c..fbd45932a46 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -219,9 +220,9 @@ void Snapshot::takeNextSnapshot() { // Process six QImages if (_cubemapOutputFormat) { - QtConcurrent::run([this]() { convertToCubemap(); }); + QThreadPool::globalInstance()->start([this]() { convertToCubemap(); }); } else { - QtConcurrent::run([this]() { convertToEquirectangular(); }); + QThreadPool::globalInstance()->start([this]() { convertToEquirectangular(); }); } } } @@ -361,7 +362,7 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot, QString username = DependencyManager::get()->getAccountInfo().getUsername(); // normalize username, replace all non alphanumeric with '-' - username.replace(QRegExp("[^A-Za-z0-9_]"), "-"); + username.replace(QRegularExpression("[^A-Za-z0-9_]"), "-"); QDateTime now = QDateTime::currentDateTime(); diff --git a/interface/src/ui/SnapshotAnimated.cpp b/interface/src/ui/SnapshotAnimated.cpp index 6d4c36afa1f..0709d0f99ef 100644 --- a/interface/src/ui/SnapshotAnimated.cpp +++ b/interface/src/ui/SnapshotAnimated.cpp @@ -94,7 +94,7 @@ void SnapshotAnimated::captureFrames() { emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath); // Kick off the thread that'll pack the frames into the GIF - QtConcurrent::run(processFrames); + QThreadPool::globalInstance()->start(processFrames); // Stop the snapshot QTimer. This action by itself DOES NOT GUARANTEE // that the slot will not be called again in the future. // See: http://lists.qt-project.org/pipermail/qt-interest-old/2009-October/013926.html diff --git a/interface/src/ui/StandAloneJSConsole.cpp b/interface/src/ui/StandAloneJSConsole.cpp index e6c3748d208..0bc3d653223 100644 --- a/interface/src/ui/StandAloneJSConsole.cpp +++ b/interface/src/ui/StandAloneJSConsole.cpp @@ -26,7 +26,8 @@ void StandAloneJSConsole::toggleConsole() { dialog->setLayout(layout); dialog->resize(QSize(CONSOLE_WIDTH, CONSOLE_HEIGHT)); - layout->setMargin(0); + // QT6TODO: + //layout->setMargin(0); layout->setSpacing(0); layout->addWidget(new JSConsole(dialog)); dialog->setWindowOpacity(CONSOLE_WINDOW_OPACITY); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 8306274884a..822724c6e0f 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -339,35 +339,39 @@ void Stats::updateStats(bool force) { unsigned long totalLeaves = 0; std::stringstream sendingModeStream(""); sendingModeStream << "["; - NodeToOctreeSceneStats* octreeServerSceneStats = qApp->getOcteeSceneStats(); - for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats->begin(); i != octreeServerSceneStats->end(); i++) { - //const QUuid& uuid = i->first; - OctreeSceneStats& stats = i->second; - serverCount++; - if (_expanded) { - if (serverCount > 1) { - sendingModeStream << ","; - } - if (stats.isMoving()) { - sendingModeStream << "M"; - movingServerCount++; - } else { - sendingModeStream << "S"; - } - if (stats.isFullScene()) { - sendingModeStream << "F"; - } - else { - sendingModeStream << "p"; - } - } + auto octreeServerSceneStats = qApp->getOcteeSceneStats(); + if (octreeServerSceneStats) { + octreeServerSceneStats.value()->withReadLock([&] { + for (NodeToOctreeSceneStatsIterator i = octreeServerSceneStats.value()->begin(); i != octreeServerSceneStats.value()->end(); i++) { + //const QUuid& uuid = i->first; + OctreeSceneStats& stats = i->second; + serverCount++; + if (_expanded) { + if (serverCount > 1) { + sendingModeStream << ","; + } + if (stats.isMoving()) { + sendingModeStream << "M"; + movingServerCount++; + } else { + sendingModeStream << "S"; + } + if (stats.isFullScene()) { + sendingModeStream << "F"; + } + else { + sendingModeStream << "p"; + } + } - // calculate server node totals - totalNodes += stats.getTotalElements(); - if (_expanded) { - totalInternal += stats.getTotalInternal(); - totalLeaves += stats.getTotalLeaves(); - } + // calculate server node totals + totalNodes += stats.getTotalElements(); + if (_expanded) { + totalInternal += stats.getTotalInternal(); + totalLeaves += stats.getTotalLeaves(); + } + } + }); } if (_expanded || force) { if (serverCount == 0) { @@ -505,7 +509,7 @@ void Stats::updateStats(bool force) { } int linesDisplayed = 0; - QMapIterator j(sortedRecords); + QMultiMapIterator j(sortedRecords); j.toBack(); QString perfLines; while (j.hasPrevious()) { diff --git a/interface/src/ui/UpdateDialog.cpp b/interface/src/ui/UpdateDialog.cpp index 7ff2132ab99..68c7d844de3 100644 --- a/interface/src/ui/UpdateDialog.cpp +++ b/interface/src/ui/UpdateDialog.cpp @@ -11,7 +11,10 @@ #include "UpdateDialog.h" +#include + #include +#include #include "DependencyManager.h" @@ -38,7 +41,7 @@ UpdateDialog::UpdateDialog(QQuickItem* parent) : // grab the release notes for this later version QString releaseNotes = it.value()["releaseNotes"]; releaseNotes.remove("
"); - releaseNotes.remove(QRegExp("^\n+")); + releaseNotes.remove(QRegularExpression("^\n+")); _releaseNotes += "\n" + it.key().versionString + "\n" + releaseNotes + "\n"; } else { break; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e204b140f5c..19da0e8991d 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -201,7 +201,7 @@ QUuid Overlays::addOverlay(const QString& type, const QVariant& properties) { if (QThread::currentThread() != thread()) { QUuid result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QString&, type), Q_ARG(const QVariant&, properties)); + BLOCKING_INVOKE_METHOD(this, "addOverlay", Q_GENERIC_RETURN_ARG(QUuid, result), Q_GENERIC_ARG(const QString&, type), Q_GENERIC_ARG(const QVariant&, properties)); return result; } @@ -250,7 +250,7 @@ QUuid Overlays::cloneOverlay(const QUuid& id) { if (QThread::currentThread() != thread()) { QUuid result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_RETURN_ARG(QUuid, result), Q_ARG(const QUuid&, id)); + BLOCKING_INVOKE_METHOD(this, "cloneOverlay", Q_GENERIC_RETURN_ARG(QUuid, result), Q_GENERIC_ARG(const QUuid&, id)); return result; } return add2DOverlay(Overlay::Pointer(overlay->createClone(), [](Overlay* ptr) { ptr->deleteLater(); })); @@ -347,7 +347,7 @@ QString Overlays::getOverlayType(const QUuid& id) { if (QThread::currentThread() != thread()) { QString result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(const QUuid&, id)); + BLOCKING_INVOKE_METHOD(this, "getOverlayType", Q_GENERIC_RETURN_ARG(QString, result), Q_GENERIC_ARG(const QUuid&, id)); return result; } return overlay->getType(); @@ -362,7 +362,7 @@ QObject* Overlays::getOverlayObject(const QUuid& id) { if (QThread::currentThread() != thread()) { QObject* result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(const QUuid&, id)); + BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_GENERIC_RETURN_ARG(QObject*, result), Q_GENERIC_ARG(const QUuid&, id)); return result; } return qobject_cast(&(*overlay)); @@ -378,7 +378,8 @@ QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) { if (QThread::currentThread() != thread()) { QUuid result; - BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_RETURN_ARG(QUuid, result), Q_ARG(const glm::vec2&, point)); + BLOCKING_INVOKE_METHOD(this, "getOverlayAtPoint", Q_GENERIC_RETURN_ARG(QUuid, result), + QArgument& >("const glm::vec<2,float,glm::packed_highp>&", point)); return result; } @@ -520,7 +521,7 @@ QSizeF Overlays::textSize(const QUuid& id, const QString& text) { if (QThread::currentThread() != thread()) { QSizeF result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(const QUuid&, id), Q_ARG(QString, text)); + BLOCKING_INVOKE_METHOD(this, "textSize", Q_GENERIC_RETURN_ARG(QSizeF, result), Q_GENERIC_ARG(const QUuid&, id), Q_GENERIC_ARG(QString, text)); return result; } if (auto textOverlay = std::dynamic_pointer_cast(overlay)) { @@ -569,7 +570,7 @@ float Overlays::width() { if (QThread::currentThread() != thread()) { float result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "width", Q_RETURN_ARG(float, result)); + BLOCKING_INVOKE_METHOD(this, "width", Q_GENERIC_RETURN_ARG(float, result)); return result; } @@ -581,7 +582,7 @@ float Overlays::height() { if (QThread::currentThread() != thread()) { float result; PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "height", Q_RETURN_ARG(float, result)); + BLOCKING_INVOKE_METHOD(this, "height", Q_GENERIC_RETURN_ARG(float, result)); return result; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 9b12a4f6ccd..aabdeaeba94 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -306,7 +306,7 @@ public slots: * print("Clicked: " + overlay); * }); */ - QUuid getOverlayAtPoint(const glm::vec2& point); + QUuid getOverlayAtPoint(const glm::vec<2,float,glm::packed_highp>& point); /*@jsdoc * Finds the closest 3D overlay (or local entity) intersected by a {@link PickRay}. @@ -371,7 +371,7 @@ public slots: * var overlaysFound = Overlays.findOverlays(MyAvatar.position, 5.0); * print("Overlays found: " + JSON.stringify(overlaysFound)); */ - QVector findOverlays(const glm::vec3& center, float radius); + QVector findOverlays(const glm::vec<3,float,glm::packed_highp>& center, float radius); /*@jsdoc * Checks whether an overlay's (or entity's) assets have been loaded. For example, for an diff --git a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp index 4e7b135cdff..5163874a5cc 100644 --- a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp @@ -67,7 +67,7 @@ void WebBrowserSuggestionsEngine::suggestionsFinished(QNetworkReply *reply) { QJsonDocument json = QJsonDocument::fromJson(response, &err); const QVariant res = json.toVariant(); - if (err.error != QJsonParseError::NoError || res.type() != QVariant::List) { + if (err.error != QJsonParseError::NoError || res.typeId() != QMetaType::QVariantList) { return; } diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 87fb3ca20cc..cc52060c02b 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -12,6 +12,7 @@ #define hifi_AnimExpression #include +#include #include #include #include diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 066ccec056b..8a655fbe97f 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -1083,11 +1083,10 @@ bool processBlendDirectionalNode(AnimNode::Pointer node, const QJsonObject& json AnimNodeLoader::AnimNodeLoader(const QUrl& url) : _url(url) { - _resource = QSharedPointer::create(url); - _resource->setSelf(_resource); + _resource = std::make_shared(url); _resource->setLoadPriorityOperator(this, []() { return ANIM_GRAPH_LOAD_PRIORITY; }); - connect(_resource.data(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone); - connect(_resource.data(), &Resource::failed, this, &AnimNodeLoader::onRequestError); + connect(_resource.get(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone); + connect(_resource.get(), &Resource::failed, this, &AnimNodeLoader::onRequestError); _resource->ensureLoading(); } diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h index ac27402cf71..d293133f2fd 100644 --- a/libraries/animation/src/AnimNodeLoader.h +++ b/libraries/animation/src/AnimNodeLoader.h @@ -42,7 +42,7 @@ protected slots: protected: QUrl _url; - QSharedPointer _resource; + std::shared_ptr _resource; private: Q_DISABLE_COPY(AnimNodeLoader) diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index f7112cff73d..6d25b1400e4 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -33,15 +33,19 @@ AnimationCache::AnimationCache(QObject* parent) : } AnimationPointer AnimationCache::getAnimation(const QUrl& url) { - return getResource(url).staticCast(); + auto animation = std::dynamic_pointer_cast(getResource(url)); + Q_ASSERT(animation); + return animation; } -QSharedPointer AnimationCache::createResource(const QUrl& url) { - return QSharedPointer(new Animation(url), &Resource::deleter); +std::shared_ptr AnimationCache::createResource(const QUrl& url) { + return std::shared_ptr(new Animation(url), Resource::sharedPtrDeleter); } -QSharedPointer AnimationCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new Animation(*resource.staticCast()), &Resource::deleter); +std::shared_ptr AnimationCache::createResourceCopy(const std::shared_ptr& resource) { + auto animation = std::dynamic_pointer_cast(resource); + Q_ASSERT(animation); + return std::shared_ptr(new Animation(*animation), Resource::sharedPtrDeleter); } AnimationReader::AnimationReader(const QUrl& url, const QByteArray& data) : @@ -73,7 +77,7 @@ void AnimationReader::run() { // Parse the FBX directly from the QNetworkReply HFMModel::Pointer hfmModel; if (_url.path().toLower().endsWith(".fbx")) { - hfmModel = FBXSerializer().read(_data, QVariantHash(), _url.path()); + hfmModel = FBXSerializer().read(_data, hifi::VariantMultiHash(), _url.path()); } else { QString errorStr("usupported format"); emit onError(299, errorStr); @@ -97,7 +101,7 @@ QStringList Animation::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; BLOCKING_INVOKE_METHOD(const_cast(this), "getJointNames", - Q_RETURN_ARG(QStringList, result)); + Q_GENERIC_RETURN_ARG(QStringList, result)); return result; } QStringList names; @@ -113,7 +117,7 @@ QVector Animation::getFrames() const { if (QThread::currentThread() != thread()) { QVector result; BLOCKING_INVOKE_METHOD(const_cast(this), "getFrames", - Q_RETURN_ARG(QVector, result)); + Q_GENERIC_RETURN_ARG(QVector, result)); return result; } if (_hfmModel) { diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index f879a7eea62..bf048b84a75 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -23,7 +23,7 @@ class Animation; -using AnimationPointer = QSharedPointer; +using AnimationPointer = std::shared_ptr; class AnimationCache : public ResourceCache, public Dependency { Q_OBJECT @@ -35,8 +35,8 @@ class AnimationCache : public ResourceCache, public Dependency { Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; private: explicit AnimationCache(QObject* parent = NULL); @@ -54,6 +54,7 @@ class Animation : public Resource { Animation(const Animation& other) : Resource(other), _hfmModel(other._hfmModel) {} Animation(const QUrl& url) : Resource(url) {} + virtual ~Animation() {} QString getType() const override { return "Animation"; } diff --git a/libraries/animation/src/AnimationObject.h b/libraries/animation/src/AnimationObject.h index d381cdc872a..0bddf69bb15 100644 --- a/libraries/animation/src/AnimationObject.h +++ b/libraries/animation/src/AnimationObject.h @@ -76,7 +76,7 @@ class AnimationObject : public QObject, protected Scriptable { /// Scriptable wrapper for animation frames. class AnimationFrameObject : public QObject, protected Scriptable { Q_OBJECT - Q_PROPERTY(QVector rotations READ getRotations) + Q_PROPERTY(QVector> rotations READ getRotations) public: @@ -85,7 +85,7 @@ class AnimationFrameObject : public QObject, protected Scriptable { * @function AnimationFrameObject.getRotations * @returns {Quat[]} The joint rotations in the animation frame. */ - Q_INVOKABLE QVector getRotations() const; + Q_INVOKABLE QVector> getRotations() const; }; void registerAnimationTypes(ScriptEngine* engine); diff --git a/libraries/animation/src/Flow.cpp b/libraries/animation/src/Flow.cpp index 56194ea0119..eecae48d181 100644 --- a/libraries/animation/src/Flow.cpp +++ b/libraries/animation/src/Flow.cpp @@ -12,6 +12,8 @@ #include "Rig.h" #include "AnimSkeleton.h" +#include + const std::map PRESET_FLOW_DATA = { { "hair", FlowPhysicsSettings() }, { "skirt", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) }, { "breast", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) } }; diff --git a/libraries/animation/src/Flow.h b/libraries/animation/src/Flow.h index 6235b977578..50f5adb3130 100644 --- a/libraries/animation/src/Flow.h +++ b/libraries/animation/src/Flow.h @@ -18,6 +18,9 @@ #include #include #include + +#include + #include "AnimPose.h" class Rig; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a6b8b282ed4..593e6f1341f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -38,6 +38,8 @@ #include #endif +#include +#include #include #include #include @@ -57,6 +59,7 @@ #include "AudioClientLogging.h" #include "AudioLogging.h" #include "AudioHelpers.h" +#include "../../../interface/src/scripting/AudioDevices.h" #if defined(Q_OS_ANDROID) #include @@ -85,11 +88,11 @@ using Lock = std::unique_lock; Mutex _deviceMutex; Mutex _recordMutex; -QString defaultAudioDeviceName(QAudio::Mode mode); +QString defaultAudioDeviceName(QAudioDevice::Mode mode); -void AudioClient::setHmdAudioName(QAudio::Mode mode, const QString& name) { +void AudioClient::setHmdAudioName(QAudioDevice::Mode mode, const QString& name) { QWriteLocker lock(&_hmdNameLock); - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Input) { _hmdInputName = name; } else { _hmdOutputName = name; @@ -97,20 +100,27 @@ void AudioClient::setHmdAudioName(QAudio::Mode mode, const QString& name) { } // thread-safe -QList getAvailableDevices(QAudio::Mode mode, const QString& hmdName) { +QList getAvailableDevices(QAudioDevice::Mode mode, const QString& hmdName) { //get hmd device name prior to locking device mutex. in case of shutdown, this thread will be locked and audio client - //cannot properly shut down. + //cannot properly shut down. QString defDeviceName = defaultAudioDeviceName(mode); // NOTE: availableDevices() clobbers the Qt internal device list + QList devices; Lock lock(_deviceMutex); - auto devices = QAudioDeviceInfo::availableDevices(mode); + if (mode == QAudioDevice::Input) { + devices = QMediaDevices::audioInputs(); + } else if (mode == QAudioDevice::Output) { + devices = QMediaDevices::audioOutputs(); + } else if (mode == QAudioDevice::Null) { + Q_ASSERT(false); + } HifiAudioDeviceInfo defaultDesktopDevice; QList newDevices; for (auto& device : devices) { newDevices.push_back(HifiAudioDeviceInfo(device, false, mode)); - if (device.deviceName() == defDeviceName.trimmed()) { + if (device.description() == defDeviceName.trimmed()) { defaultDesktopDevice = HifiAudioDeviceInfo(device, true, mode, HifiAudioDeviceInfo::both); } } @@ -118,7 +128,7 @@ QList getAvailableDevices(QAudio::Mode mode, const QString& if (defaultDesktopDevice.getDevice().isNull()) { if (devices.size() > 0) { qCDebug(audioclient) << __FUNCTION__ << "Default device not found in list:" << defDeviceName - << "Setting Default to: " << devices.first().deviceName(); + << "Setting Default to: " << devices.first().description(); newDevices.push_front(HifiAudioDeviceInfo(devices.first(), true, mode, HifiAudioDeviceInfo::both)); } else { //current audio list is empty for some reason. @@ -131,7 +141,7 @@ QList getAvailableDevices(QAudio::Mode mode, const QString& if (!hmdName.isNull()) { HifiAudioDeviceInfo hmdDevice; foreach(auto device, newDevices) { - if (device.getDevice().deviceName() == hmdName) { + if (device.getDevice().description() == hmdName) { hmdDevice = HifiAudioDeviceInfo(device.getDevice(), true, mode, HifiAudioDeviceInfo::hmd); break; } @@ -161,8 +171,8 @@ void AudioClient::checkDevices() { hmdOutputName = _hmdOutputName; } - auto inputDevices = getAvailableDevices(QAudio::AudioInput, hmdInputName); - auto outputDevices = getAvailableDevices(QAudio::AudioOutput, hmdOutputName); + auto inputDevices = getAvailableDevices(QAudioDevice::Mode::Input, hmdInputName); + auto outputDevices = getAvailableDevices(QAudioDevice::Mode::Output, hmdOutputName); static const QMetaMethod devicesChangedSig= QMetaMethod::fromSignal(&AudioClient::devicesChanged); //only emit once the scripting interface has connected to the signal @@ -170,30 +180,30 @@ void AudioClient::checkDevices() { Lock lock(_deviceMutex); if (inputDevices != _inputDevices) { _inputDevices.swap(inputDevices); - emit devicesChanged(QAudio::AudioInput, _inputDevices); + emit devicesChanged(QAudioDevice::Mode::Input, _inputDevices); } if (outputDevices != _outputDevices) { _outputDevices.swap(outputDevices); - emit devicesChanged(QAudio::AudioOutput, _outputDevices); + emit devicesChanged(QAudioDevice::Mode::Output, _outputDevices); } } } -HifiAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudio::Mode mode) const { +HifiAudioDeviceInfo AudioClient::getActiveAudioDevice(QAudioDevice::Mode mode) const { Lock lock(_deviceMutex); - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { return _inputDeviceInfo; } else { return _outputDeviceInfo; } } -QList AudioClient::getAudioDevices(QAudio::Mode mode) const { +QList AudioClient::getAudioDevices(QAudioDevice::Mode mode) const { Lock lock(_deviceMutex); - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { return _inputDevices; } else { return _outputDevices; @@ -323,10 +333,8 @@ AudioClient::AudioClient() { // Set up the desired audio format, since scripting API expects it to be set and audio scripting API // is initialized before audio thread starts. _desiredInputFormat.setSampleRate(AudioConstants::SAMPLE_RATE); - _desiredInputFormat.setSampleSize(16); - _desiredInputFormat.setCodec("audio/pcm"); - _desiredInputFormat.setSampleType(QAudioFormat::SignedInt); - _desiredInputFormat.setByteOrder(QAudioFormat::LittleEndian); + _desiredInputFormat.setSampleFormat(QAudioFormat::Int16); + _desiredInputFormat.setChannelCount(1); _desiredOutputFormat = _desiredInputFormat; @@ -352,15 +360,15 @@ AudioClient::AudioClient() { connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat); // initialize wasapi; if getAvailableDevices is called from the CheckDevicesThread before this, it will crash - defaultAudioDeviceName(QAudio::AudioInput); - defaultAudioDeviceName(QAudio::AudioOutput); + defaultAudioDeviceName(QAudioDevice::Mode::Input); + defaultAudioDeviceName(QAudioDevice::Mode::Output); checkDevices(); // start a thread to detect any device changes _checkDevicesTimer = new QTimer(this); const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000; connect(_checkDevicesTimer, &QTimer::timeout, this, [=, this] { - QtConcurrent::run(QThreadPool::globalInstance(), [=, this] { + QThreadPool::globalInstance()->start([=, this] { checkDevices(); // On some systems (Ubuntu) checking all the audio devices can take more than 2 seconds. To // avoid consuming all of the thread pool, don't start the check interval until the previous @@ -374,7 +382,7 @@ AudioClient::AudioClient() { // start a thread to detect peak value changes _checkPeakValuesTimer = new QTimer(this); connect(_checkPeakValuesTimer, &QTimer::timeout, this, [this] { - QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkPeakValues(); }); + QThreadPool::globalInstance()->start([this] { checkPeakValues(); }); }); const unsigned long PEAK_VALUES_CHECK_INTERVAL_MSECS = 50; _checkPeakValuesTimer->start(PEAK_VALUES_CHECK_INTERVAL_MSECS); @@ -414,7 +422,6 @@ AudioClient::AudioClient() { } AudioClient::~AudioClient() { - stop(); if (_codec && _encoder) { @@ -461,7 +468,7 @@ void AudioClient::setAudioPaused(bool pause) { } } -HifiAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName, const QString& hmdName, bool isHmd=false) { +HifiAudioDeviceInfo getNamedAudioDeviceForMode(QAudioDevice::Mode mode, const QString& deviceName, const QString& hmdName, bool isHmd=false) { HifiAudioDeviceInfo result; foreach (HifiAudioDeviceInfo audioDevice, getAvailableDevices(mode,hmdName)) { if (audioDevice.deviceName().trimmed() == deviceName.trimmed()) { @@ -484,7 +491,7 @@ QString getWinDeviceName(IMMDevice* pEndpoint) { HRESULT hr = pPropertyStore->GetValue(PKEY_Device_FriendlyName, &pv); pPropertyStore->Release(); pPropertyStore = nullptr; - deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); + deviceName = QString::fromWCharArray(pv.pwszVal); if (!IsWindows8OrGreater()) { // Windows 7 provides only the 31 first characters of the device name. const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; @@ -518,10 +525,10 @@ QString AudioClient::getWinDeviceName(wchar_t* guid) { #endif -HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode, const QString& hmdName) { +HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudioDevice::Mode mode, const QString& hmdName) { QString deviceName = defaultAudioDeviceName(mode); -#if defined (Q_OS_ANDROID) - if (mode == QAudio::AudioInput) { +#if defined(Q_OS_ANDROID) + if (mode == QAudioDevice::Mode::Input) { Setting::Handle enableAEC(SETTING_AEC_KEY, DEFAULT_AEC_ENABLED); bool aecEnabled = enableAEC.get(); auto audioClient = DependencyManager::get(); @@ -537,12 +544,12 @@ HifiAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode, const QString& return getNamedAudioDeviceForMode(mode, deviceName, hmdName); } -QString defaultAudioDeviceName(QAudio::Mode mode) { +QString defaultAudioDeviceName(QAudioDevice::Mode mode) { QString deviceName; #ifdef __APPLE__ QAudioDeviceInfo device; - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { device = QAudioDeviceInfo::defaultInputDevice(); } else { device = QAudioDeviceInfo::defaultOutputDevice(); @@ -561,7 +568,7 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { kAudioObjectPropertyElementMaster }; - if (mode == QAudio::AudioOutput) { + if (mode == QAudioDevice::Mode::Output) { propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; } @@ -588,8 +595,8 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { #endif #ifdef _WIN32 //Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that. - if (!IsWindowsVistaOrGreater()) { // lower then vista - if (mode == QAudio::AudioInput) { + if (!IsWindowsVistaOrGreater()) { // lower then vista + if (mode == QAudioDevice::Mode::Input) { WAVEINCAPS wic; // first use WAVE_MAPPER to get the default devices manufacturer ID waveInGetDevCaps(WAVE_MAPPER, &wic, sizeof(wic)); @@ -598,7 +605,7 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { #if !defined(NDEBUG) qCDebug(audioclient) << "input device:" << wic.szPname; #endif - deviceName = wic.szPname; + deviceName = QString::fromWCharArray(wic.szPname); } else { WAVEOUTCAPS woc; // first use WAVE_MAPPER to get the default devices manufacturer ID @@ -608,7 +615,7 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { #if !defined(NDEBUG) qCDebug(audioclient) << "output device:" << woc.szPname; #endif - deviceName = woc.szPname; + deviceName = QString::fromWCharArray(woc.szPname); } } else { HRESULT hr = S_OK; @@ -616,7 +623,8 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { IMMDeviceEnumerator* pMMDeviceEnumerator = NULL; CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator); IMMDevice* pEndpoint; - hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudio::AudioOutput ? eRender : eCapture, eMultimedia, &pEndpoint); + hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(mode == QAudioDevice::Mode::Output ? eRender : eCapture, eMultimedia, + &pEndpoint); if (hr == E_NOTFOUND) { printf("Audio Error: device not found\n"); deviceName = QString("NONE"); @@ -630,32 +638,32 @@ QString defaultAudioDeviceName(QAudio::Mode mode) { CoUninitialize(); } -#if !defined(NDEBUG) - qCDebug(audioclient) << "defaultAudioDeviceForMode mode: " << (mode == QAudio::AudioOutput ? "Output" : "Input") - << " [" << deviceName << "] [" << "]"; +#if !defined(NDEBUG) + qCDebug(audioclient) << "defaultAudioDeviceForMode mode: " << (mode == QAudioDevice::Mode::Output ? "Output" : "Input") + << " [" << deviceName << "] [" << "]"; #endif #endif #ifdef Q_OS_LINUX - if ( mode == QAudio::AudioInput ) { - deviceName = QAudioDeviceInfo::defaultInputDevice().deviceName(); + if (mode == QAudioDevice::Mode::Input) { + deviceName = QMediaDevices::defaultAudioInput().description(); } else { - deviceName = QAudioDeviceInfo::defaultOutputDevice().deviceName(); + deviceName = QMediaDevices::defaultAudioOutput().description(); } #endif - return deviceName; + return deviceName; } -bool AudioClient::getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName) { +bool AudioClient::getNamedAudioDeviceForModeExists(QAudioDevice::Mode mode, const QString& deviceName) { QReadLocker readLock(&_hmdNameLock); - QString hmdName = mode == QAudio::AudioInput ? _hmdInputName : _hmdOutputName; + QString hmdName = mode == QAudioDevice::Mode::Input ? _hmdInputName : _hmdOutputName; return (getNamedAudioDeviceForMode(mode, deviceName, hmdName).deviceName() == deviceName); } // attempt to use the native sample rate and channel count -bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioFormat& audioFormat) { +bool nativeFormatForAudioDevice(const QAudioDevice& audioDevice, QAudioFormat& audioFormat) { audioFormat = audioDevice.preferredFormat(); @@ -666,10 +674,7 @@ bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioForma return false; } - audioFormat.setCodec("audio/pcm"); - audioFormat.setSampleSize(16); - audioFormat.setSampleType(QAudioFormat::SignedInt); - audioFormat.setByteOrder(QAudioFormat::LittleEndian); + audioFormat.setSampleFormat(QAudioFormat::Int16); if (!audioDevice.isFormatSupported(audioFormat)) { qCWarning(audioclient) << "The native format is" << audioFormat << "but isFormatSupported() failed."; @@ -688,7 +693,7 @@ bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, QAudioForma return true; } -bool adjustedFormatForAudioDevice(const QAudioDeviceInfo& audioDevice, +bool adjustedFormatForAudioDevice(const QAudioDevice& audioDevice, const QAudioFormat& desiredAudioFormat, QAudioFormat& adjustedAudioFormat) { @@ -804,10 +809,8 @@ void AudioClient::start() { // set up the desired audio format _desiredInputFormat.setSampleRate(AudioConstants::SAMPLE_RATE); - _desiredInputFormat.setSampleSize(16); - _desiredInputFormat.setCodec("audio/pcm"); - _desiredInputFormat.setSampleType(QAudioFormat::SignedInt); - _desiredInputFormat.setByteOrder(QAudioFormat::LittleEndian); + _desiredInputFormat.setSampleFormat(QAudioFormat::Int16); + _desiredInputFormat.setChannelCount(1); _desiredOutputFormat = _desiredInputFormat; @@ -823,8 +826,8 @@ void AudioClient::start() { // Input was originally set to HifiAudioDeviceInfo(), but that was causing trouble. //Original comment: initialize input to the dummy device to prevent starves - switchInputToAudioDevice(defaultAudioDeviceForMode(QAudio::AudioInput, QString())); - switchOutputToAudioDevice(defaultAudioDeviceForMode(QAudio::AudioOutput, QString())); + switchInputToAudioDevice(defaultAudioDeviceForMode(QAudioDevice::Mode::Input, QString())); + switchOutputToAudioDevice(defaultAudioDeviceForMode(QAudioDevice::Mode::Output, QString())); #if defined(Q_OS_ANDROID) connect(&_checkInputTimer, &QTimer::timeout, this, &AudioClient::checkInputTimeout); @@ -1030,25 +1033,25 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { } -bool AudioClient::switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo) { +bool AudioClient::switchAudioDevice(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& deviceInfo) { auto device = deviceInfo; if (deviceInfo.getDevice().isNull()) { qCDebug(audioclient) << __FUNCTION__ << " switching to null device :" - << deviceInfo.deviceName() << " : " << deviceInfo.getDevice().deviceName(); + << deviceInfo.deviceName() << " : " << deviceInfo.getDevice().description(); } - if (mode == QAudio::AudioInput) { + if (mode == QAudioDevice::Mode::Input) { return switchInputToAudioDevice(device); } else { return switchOutputToAudioDevice(device); } } -bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QString& deviceName, bool isHmd) { +bool AudioClient::switchAudioDevice(QAudioDevice::Mode mode, const QString& deviceName, bool isHmd) { QString hmdName; { QReadLocker readLock(&_hmdNameLock); - hmdName = mode == QAudio::AudioInput ? _hmdInputName : _hmdOutputName; + hmdName = mode == QAudioDevice::Mode::Input ? _hmdInputName : _hmdOutputName; } return switchAudioDevice(mode, getNamedAudioDeviceForMode(mode, deviceName, hmdName, isHmd)); } @@ -1815,7 +1818,9 @@ void AudioClient::setAcousticEchoCancellation(bool enable, bool emitSignal) { bool AudioClient::setIsStereoInput(bool isStereoInput) { bool stereoInputChanged = false; - if (isStereoInput != _isStereoInput && _inputDeviceInfo.getDevice().supportedChannelCounts().contains(2)) { + if (isStereoInput != _isStereoInput + && (_inputDeviceInfo.getDevice().minimumChannelCount() <= 2 + && _inputDeviceInfo.getDevice().maximumChannelCount() >= 2)) { _isStereoInput = isStereoInput; stereoInputChanged = true; @@ -1880,8 +1885,8 @@ void AudioClient::outputFormatChanged() { bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDeviceInfo, bool isShutdownRequest) { Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread"); - qCDebug(audioclient) << __FUNCTION__ << "_inputDeviceInfo: [" << _inputDeviceInfo.deviceName() << ":" << _inputDeviceInfo.getDevice().deviceName() - << "-- inputDeviceInfo:" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().deviceName() << "]"; + qCDebug(audioclient) << __FUNCTION__ << "_inputDeviceInfo: [" << _inputDeviceInfo.deviceName() << ":" << _inputDeviceInfo.getDevice().description() + << "-- inputDeviceInfo:" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().description() << "]"; bool supportedFormat = false; // NOTE: device start() uses the Qt internal device list @@ -1903,7 +1908,7 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice _audioInput = NULL; _numInputCallbackBytes = 0; - _inputDeviceInfo.setDevice(QAudioDeviceInfo()); + _inputDeviceInfo.setDevice(QAudioDevice()); } if (_dummyAudioInput) { @@ -1934,11 +1939,11 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice } if (!inputDeviceInfo.getDevice().isNull()) { - qCDebug(audioclient) << "The audio input device" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().deviceName() << "is available."; + qCDebug(audioclient) << "The audio input device" << inputDeviceInfo.deviceName() << ":" << inputDeviceInfo.getDevice().description() << "is available."; //do not update UI that we're changing devices if default or same device _inputDeviceInfo = inputDeviceInfo; - emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo); + emit deviceChanged(QAudioDevice::Mode::Input, _inputDeviceInfo); if (adjustedFormatForAudioDevice(_inputDeviceInfo.getDevice(), _desiredInputFormat, _inputFormat)) { qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat; @@ -1949,8 +1954,8 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice && _inputFormat.sampleRate() != _desiredInputFormat.sampleRate()) { qCDebug(audioclient) << "Attemping to create a resampler for input format to network format."; - assert(_inputFormat.sampleSize() == 16); - assert(_desiredInputFormat.sampleSize() == 16); + assert(_inputFormat.sampleFormat() == QAudioFormat::Int16); + assert(_desiredInputFormat.sampleFormat() == QAudioFormat::Int16); int channelCount = (_inputFormat.channelCount() == 2 && _desiredInputFormat.channelCount() == 2) ? 2 : 1; _inputToNetworkResampler = new AudioSRC(_inputFormat.sampleRate(), _desiredInputFormat.sampleRate(), channelCount); @@ -1965,7 +1970,7 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice // if the user wants stereo but this device can't provide then bail if (!_isStereoInput || _inputFormat.channelCount() == 2) { - _audioInput = new QAudioInput(_inputDeviceInfo.getDevice(), _inputFormat, this); + _audioInput = new QAudioSource(_inputDeviceInfo.getDevice(), _inputFormat, this); _numInputCallbackBytes = calculateNumberOfInputCallbackBytes(_inputFormat); _audioInput->setBufferSize(_numInputCallbackBytes); // different audio input devices may have different volumes @@ -2000,8 +2005,8 @@ bool AudioClient::switchInputToAudioDevice(const HifiAudioDeviceInfo inputDevice // This enables clients without a mic to still receive an audio stream from the mixer. if (!_audioInput) { qCDebug(audioclient) << "Audio input device is not available, using dummy input."; - _inputDeviceInfo.setDevice(QAudioDeviceInfo()); - emit deviceChanged(QAudio::AudioInput, _inputDeviceInfo); + _inputDeviceInfo.setDevice(QAudioDevice()); + emit deviceChanged(QAudioDevice::Mode::Input, _inputDeviceInfo); _inputFormat = _desiredInputFormat; qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat; @@ -2116,8 +2121,8 @@ void AudioClient::noteAwakening() { bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDeviceInfo, bool isShutdownRequest) { Q_ASSERT_X(QThread::currentThread() == thread(), Q_FUNC_INFO, "Function invoked on wrong thread"); - qCDebug(audioclient) << __FUNCTION__ << "_outputdeviceInfo: [" << _outputDeviceInfo.deviceName() << ":" << _outputDeviceInfo.getDevice().deviceName() - << "-- outputDeviceInfo:" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().deviceName() << "]"; + qCDebug(audioclient) << __FUNCTION__ << "_outputdeviceInfo: [" << _outputDeviceInfo.deviceName() << ":" << _outputDeviceInfo.getDevice().description() + << "-- outputDeviceInfo:" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().description() << "]"; bool supportedFormat = false; // NOTE: device start() uses the Qt internal device list @@ -2156,7 +2161,7 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi delete[] _localOutputMixBuffer; _localOutputMixBuffer = NULL; - _outputDeviceInfo.setDevice(QAudioDeviceInfo()); + _outputDeviceInfo.setDevice(QAudioDevice()); } // cleanup any resamplers @@ -2181,11 +2186,11 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi } if (!outputDeviceInfo.getDevice().isNull()) { - qCDebug(audioclient) << "The audio output device" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().deviceName() << "is available."; + qCDebug(audioclient) << "The audio output device" << outputDeviceInfo.deviceName() << ":" << outputDeviceInfo.getDevice().description() << "is available."; //do not update UI that we're changing devices if default or same device _outputDeviceInfo = outputDeviceInfo; - emit deviceChanged(QAudio::AudioOutput, _outputDeviceInfo); + emit deviceChanged(QAudioDevice::Mode::Output, _outputDeviceInfo); if (adjustedFormatForAudioDevice(_outputDeviceInfo.getDevice(), _desiredOutputFormat, _outputFormat)) { qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat; @@ -2196,8 +2201,8 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi && _desiredOutputFormat.sampleRate() != _outputFormat.sampleRate()) { qCDebug(audioclient) << "Attemping to create a resampler for network format to output format."; - assert(_desiredOutputFormat.sampleSize() == 16); - assert(_outputFormat.sampleSize() == 16); + assert(_desiredOutputFormat.sampleFormat() == QAudioFormat::Int16); + assert(_outputFormat.sampleFormat() == QAudioFormat::Int16); _networkToOutputResampler = new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT); _localToOutputResampler = new AudioSRC(_desiredOutputFormat.sampleRate(), _outputFormat.sampleRate(), OUTPUT_CHANNEL_COUNT); @@ -2209,7 +2214,7 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi outputFormatChanged(); // setup our general output device for audio-mixer audio - _audioOutput = new QAudioOutput(_outputDeviceInfo.getDevice(), _outputFormat, this); + _audioOutput = new QAudioSink(_outputDeviceInfo.getDevice(), _outputFormat, this); int deviceChannelCount = _outputFormat.channelCount(); int frameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) / _desiredOutputFormat.sampleRate(); @@ -2222,8 +2227,10 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi _audioOutput->setBufferSize(requestedSize * 8); #endif - connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify); + // QT6TODO: I have no idea what to do about this, QAudioSins has no notify signal in Qt6 + //connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify); + // QT6TODO: we could set the buffer size before starting the IO device and sink // start the output device _audioOutputIODevice.start(); _audioOutput->start(&_audioOutputIODevice); @@ -2231,7 +2238,7 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi // initialize mix buffers // restrict device callback to _outputPeriod samples - _outputPeriod = _audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE; + _outputPeriod = _audioOutput->bufferSize() / AudioConstants::SAMPLE_SIZE / _audioOutput->format().channelCount(); // device callback may exceed reported period, so double it to avoid stutter _outputPeriod *= 2; @@ -2267,7 +2274,7 @@ bool AudioClient::switchOutputToAudioDevice(const HifiAudioDeviceInfo outputDevi localAudioLock.unlock(); // setup a loopback audio output device - _loopbackAudioOutput = new QAudioOutput(outputDeviceInfo.getDevice(), _outputFormat, this); + _loopbackAudioOutput = new QAudioSink(outputDeviceInfo.getDevice(), _outputFormat, this); _timeSinceLastReceived.start(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 06316efee26..48166fb886b 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -164,19 +166,19 @@ class AudioClient : public AbstractAudioInterface, public Dependency { void setIsPlayingBackRecording(bool isPlayingBackRecording) { _isPlayingBackRecording = isPlayingBackRecording; } - Q_INVOKABLE void setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 scale); + Q_INVOKABLE void setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec<3,float,glm::packed_highp> scale); bool outputLocalInjector(const AudioInjectorPointer& injector) override; - HifiAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const; - QList getAudioDevices(QAudio::Mode mode) const; + HifiAudioDeviceInfo getActiveAudioDevice(QAudioDevice::Mode mode) const; + QList getAudioDevices(QAudioDevice::Mode mode) const; void enablePeakValues(bool enable) { _enablePeakValues = enable; } bool peakValuesAvailable() const; static const float CALLBACK_ACCELERATOR_RATIO; - bool getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName); + bool getNamedAudioDeviceForModeExists(QAudioDevice::Mode mode, const QString& deviceName); void setRecording(bool isRecording) { _isRecording = isRecording; }; bool getRecording() { return _isRecording; }; @@ -254,9 +256,9 @@ public slots: bool shouldLoopbackInjectors() override { return _shouldEchoToServer; } // calling with a null QAudioDevice will use the system default - bool switchAudioDevice(QAudio::Mode mode, const HifiAudioDeviceInfo& deviceInfo = HifiAudioDeviceInfo()); - bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName, bool isHmd); - void setHmdAudioName(QAudio::Mode mode, const QString& name); + bool switchAudioDevice(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& deviceInfo = HifiAudioDeviceInfo()); + bool switchAudioDevice(QAudioDevice::Mode mode, const QString& deviceName, bool isHmd); + void setHmdAudioName(QAudioDevice::Mode mode, const QString& name); // Qt opensles plugin is not able to detect when the headset is plugged in void setHeadsetPluggedIn(bool pluggedIn); @@ -293,8 +295,8 @@ public slots: void changeDevice(const HifiAudioDeviceInfo& outputDeviceInfo); - void deviceChanged(QAudio::Mode mode, const HifiAudioDeviceInfo& device); - void devicesChanged(QAudio::Mode mode, const QList& devices); + void deviceChanged(QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device); + void devicesChanged(QAudioDevice::Mode mode, const QList& devices); void peakValueListChanged(const QList peakValueList); void receivedFirstPacket(); @@ -372,19 +374,19 @@ public slots: Gate _gate{ this }; Mutex _injectorsMutex; - QAudioInput* _audioInput{ nullptr }; + QAudioSource* _audioInput{ nullptr }; QTimer* _dummyAudioInput{ nullptr }; QAudioFormat _desiredInputFormat; QAudioFormat _inputFormat; QIODevice* _inputDevice{ nullptr }; int _numInputCallbackBytes{ 0 }; - QAudioOutput* _audioOutput{ nullptr }; + QAudioSink* _audioOutput{ nullptr }; std::atomic _audioOutputInitialized { false }; QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; int _outputFrameSize{ 0 }; int _numOutputCallbackBytes{ 0 }; - QAudioOutput* _loopbackAudioOutput{ nullptr }; + QAudioSink* _loopbackAudioOutput{ nullptr }; QIODevice* _loopbackOutputDevice{ nullptr }; AudioRingBuffer _inputRingBuffer{ 0 }; LocalInjectorsStream _localInjectorsStream{ 0 , 1 }; diff --git a/libraries/audio-client/src/AudioFileWav.cpp b/libraries/audio-client/src/AudioFileWav.cpp index 613628883c1..57188bd62da 100644 --- a/libraries/audio-client/src/AudioFileWav.cpp +++ b/libraries/audio-client/src/AudioFileWav.cpp @@ -60,9 +60,9 @@ void AudioFileWav::addHeader(const QAudioFormat& audioFormat) { stream << quint16(1); stream << quint16(audioFormat.channelCount()); stream << quint32(audioFormat.sampleRate()); - stream << quint32(audioFormat.sampleRate() * audioFormat.channelCount() * audioFormat.sampleSize() / 8); // bytes per second - stream << quint16(audioFormat.channelCount() * audioFormat.sampleSize() / 8); // block align - stream << quint16(audioFormat.sampleSize()); // bits Per Sample + stream << quint32(audioFormat.sampleRate() * audioFormat.channelCount() * audioFormat.bytesPerSample()); // bytes per second + stream << quint16(audioFormat.channelCount() * audioFormat.bytesPerSample()); // block align + stream << quint16(audioFormat.bytesPerSample() * 8); // bits Per Sample // Init data chunck stream.writeRawData("data", 4); stream << quint32(0); diff --git a/libraries/audio-client/src/HifiAudioDeviceInfo.cpp b/libraries/audio-client/src/HifiAudioDeviceInfo.cpp index ed3d94f2b81..c3545fde84d 100644 --- a/libraries/audio-client/src/HifiAudioDeviceInfo.cpp +++ b/libraries/audio-client/src/HifiAudioDeviceInfo.cpp @@ -14,7 +14,7 @@ const QString HifiAudioDeviceInfo::DEFAULT_DEVICE_NAME = HIFI_AUDIO_DEVICE_INFO_DEFAULT_DEVICE_NAME; -void HifiAudioDeviceInfo::setDevice(QAudioDeviceInfo devInfo) { +void HifiAudioDeviceInfo::setDevice(QAudioDevice devInfo) { _audioDeviceInfo = devInfo; } @@ -23,7 +23,7 @@ HifiAudioDeviceInfo& HifiAudioDeviceInfo::operator=(const HifiAudioDeviceInfo& o _mode = other.getMode(); _isDefault = other.isDefault(); _deviceType = other.getDeviceType(); - _debugName = other.getDevice().deviceName(); + _debugName = other.getDevice().description(); return *this; } diff --git a/libraries/audio-client/src/HifiAudioDeviceInfo.h b/libraries/audio-client/src/HifiAudioDeviceInfo.h index dee7d20b23a..6560be2c547 100644 --- a/libraries/audio-client/src/HifiAudioDeviceInfo.h +++ b/libraries/audio-client/src/HifiAudioDeviceInfo.h @@ -15,8 +15,9 @@ #include -#include +//#include #include +#include #include #define HIFI_AUDIO_DEVICE_INFO_DEFAULT_DEVICE_NAME "default " @@ -37,20 +38,20 @@ class HifiAudioDeviceInfo : public QObject { _mode = deviceInfo.getMode(); _isDefault = deviceInfo.isDefault(); _deviceType = deviceInfo.getDeviceType(); - _debugName = deviceInfo.getDevice().deviceName(); + _debugName = deviceInfo.getDevice().description(); } - HifiAudioDeviceInfo(QAudioDeviceInfo deviceInfo, bool isDefault, QAudio::Mode mode, DeviceType devType=both) : + HifiAudioDeviceInfo(QAudioDevice deviceInfo, bool isDefault, QAudioDevice::Mode mode, DeviceType devType=both) : _audioDeviceInfo(deviceInfo), _isDefault(isDefault), _mode(mode), _deviceType(devType), - _debugName(deviceInfo.deviceName()) { + _debugName(deviceInfo.description()) { } - void setMode(QAudio::Mode mode) { _mode = mode; } + void setMode(QAudioDevice::Mode mode) { _mode = mode; } void setIsDefault() { _isDefault = true; } - void setDevice(QAudioDeviceInfo devInfo); + void setDevice(QAudioDevice devInfo); QString deviceName() const { #if defined(Q_OS_ANDROID) return _audioDeviceInfo.deviceName(); @@ -58,21 +59,21 @@ class HifiAudioDeviceInfo : public QObject { if (_isDefault) { return DEFAULT_DEVICE_NAME; } else { - return _audioDeviceInfo.deviceName(); + return _audioDeviceInfo.description(); } } - QAudioDeviceInfo getDevice() const { return _audioDeviceInfo; } + QAudioDevice getDevice() const { return _audioDeviceInfo; } bool isDefault() const { return _isDefault; } - QAudio::Mode getMode() const { return _mode; } + QAudioDevice::Mode getMode() const { return _mode; } DeviceType getDeviceType() const { return _deviceType; } HifiAudioDeviceInfo& operator=(const HifiAudioDeviceInfo& other); bool operator==(const HifiAudioDeviceInfo& rhs) const; bool operator!=(const HifiAudioDeviceInfo& rhs) const; private: - QAudioDeviceInfo _audioDeviceInfo; + QAudioDevice _audioDeviceInfo; bool _isDefault { false }; - QAudio::Mode _mode { QAudio::AudioInput }; + QAudioDevice::Mode _mode { QAudioDevice::Input }; DeviceType _deviceType{ both }; QString _debugName; diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 1f43e5f45a0..ea1fc8b89ce 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -196,7 +196,7 @@ class AudioScriptingInterface : public QObject, public Dependency { * sound.ready.connect(onSoundReady); * } */ - Q_INVOKABLE ScriptAudioInjector* playSound(SharedSoundPointer sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); + Q_INVOKABLE ScriptAudioInjector* playSound(std::shared_ptr sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); /*@jsdoc * Starts playing the content of an audio file locally (isn't sent to the audio mixer). This is the same as calling @@ -207,7 +207,7 @@ class AudioScriptingInterface : public QObject, public Dependency { * {@link SoundObject} for supported formats. * @returns {AudioInjector} The audio injector that plays the audio file. */ - Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound); + Q_INVOKABLE ScriptAudioInjector* playSystemSound(std::shared_ptr sound); /*@jsdoc * Sets whether the audio input should be used in stereo. If the audio input doesn't support stereo then setting a value diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index b42609d5769..9d00d292388 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -122,8 +122,8 @@ public slots: protected: // disallow copying of InboundAudioStream objects - InboundAudioStream(const InboundAudioStream&); - InboundAudioStream& operator= (const InboundAudioStream&); + InboundAudioStream(const InboundAudioStream&) = delete; + InboundAudioStream& operator= (const InboundAudioStream&) = delete; /// parses the info between the seq num and the audio data in the network packet and calculates /// how many audio samples this packet contains (used when filling in samples for dropped packets). diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index d1312edb956..a94dec10729 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -56,7 +56,7 @@ int MixedProcessedAudioStream::lostAudioData(int numPackets) { emit processSamples(decodedBuffer, outputBuffer); _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size()); - qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable()); + qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", (int)outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable()); } return 0; } @@ -81,7 +81,7 @@ int MixedProcessedAudioStream::parseAudioData(const QByteArray& packetAfterStrea emit processSamples(decodedBuffer, outputBuffer); _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size()); - qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable()); + qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", (int)outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable()); return packetAfterStreamProperties.size(); } diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index dcb67014984..83481f9bd41 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -74,13 +74,18 @@ AudioData::AudioData(uint32_t numSamples, uint32_t numChannels, const AudioSampl {} void Sound::downloadFinished(const QByteArray& data) { - if (!_self) { + auto sharedSoundPointer = weak_from_this().lock(); + + if (!sharedSoundPointer) { +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + Q_ASSERT(!_wasDeleted); +#endif soundProcessError(301, "Sound object has gone out of scope"); return; } // this is a QRunnable, will delete itself after it has finished running - auto soundProcessor = new SoundProcessor(_self, data); + auto soundProcessor = new SoundProcessor(sharedSoundPointer, data); connect(soundProcessor, &SoundProcessor::onSuccess, this, &Sound::soundProcessSuccess); connect(soundProcessor, &SoundProcessor::onError, this, &Sound::soundProcessError); QThreadPool::globalInstance()->start(soundProcessor); @@ -102,14 +107,14 @@ void Sound::soundProcessError(int error, QString str) { } -SoundProcessor::SoundProcessor(QWeakPointer sound, QByteArray data) : +SoundProcessor::SoundProcessor(std::weak_ptr sound, QByteArray data) : _sound(sound), _data(data) { } void SoundProcessor::run() { - auto sound = qSharedPointerCast(_sound.lock()); + auto sound = std::dynamic_pointer_cast(_sound.lock()); if (!sound) { emit onError(301, "Sound object has gone out of scope"); return; @@ -440,7 +445,7 @@ bool soundSharedPointerFromScriptValue(const ScriptValue& object, SharedSoundPoi SoundScriptingInterface::SoundScriptingInterface(const SharedSoundPointer& sound) : _sound(sound) { // During shutdown we can sometimes get an empty sound pointer back if (_sound) { - QObject::connect(_sound.data(), &Sound::ready, this, &SoundScriptingInterface::ready); + QObject::connect(_sound.get(), &Sound::ready, this, &SoundScriptingInterface::ready); } } diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 878343e722b..124c20a750b 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -67,6 +67,7 @@ class Sound : public Resource { public: Sound(const QUrl& url, bool isStereo = false, bool isAmbisonic = false); Sound(const Sound& other) : Resource(other), _audioData(other._audioData), _numChannels(other._numChannels) {} + virtual ~Sound() {} bool isReady() const { return (bool)_audioData; } @@ -103,7 +104,7 @@ class SoundProcessor : public QObject, public QRunnable { uint32_t sampleRate { 0 }; }; - SoundProcessor(QWeakPointer sound, QByteArray data); + SoundProcessor(std::weak_ptr sound, QByteArray data); virtual void run() override; @@ -119,11 +120,11 @@ class SoundProcessor : public QObject, public QRunnable { void onError(int error, QString str); private: - const QWeakPointer _sound; + const std::weak_ptr _sound; const QByteArray _data; }; -typedef QSharedPointer SharedSoundPointer; +typedef std::shared_ptr SharedSoundPointer; /*@jsdoc * An audio resource, created by {@link SoundCache.getSound}, to be played back using {@link Audio.playSound}. diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 55a32e72375..a4876733dec 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -30,15 +30,19 @@ SoundCache::SoundCache(QObject* parent) : } SharedSoundPointer SoundCache::getSound(const QUrl& url) { - return getResource(url).staticCast(); + auto sound = std::dynamic_pointer_cast(getResource(url)); + Q_ASSERT(sound); + return sound; } -QSharedPointer SoundCache::createResource(const QUrl& url) { - auto resource = QSharedPointer(new Sound(url), &Resource::deleter); +std::shared_ptr SoundCache::createResource(const QUrl& url) { + auto resource = std::shared_ptr(new Sound(url), Resource::sharedPtrDeleter); resource->setLoadPriorityOperator(this, []() { return SOUNDS_LOADING_PRIORITY; }); return resource; } -QSharedPointer SoundCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new Sound(*resource.staticCast()), &Resource::deleter); +std::shared_ptr SoundCache::createResourceCopy(const std::shared_ptr& resource) { + auto sound = std::dynamic_pointer_cast(resource); + Q_ASSERT(sound); + return std::shared_ptr(new Sound(*sound), Resource::sharedPtrDeleter); } \ No newline at end of file diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index 973edc40487..f704d9c0921 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -26,8 +26,8 @@ class SoundCache : public ResourceCache, public Dependency { Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; private: SoundCache(QObject* parent = NULL); diff --git a/libraries/audio/src/SoundCacheScriptingInterface.h b/libraries/audio/src/SoundCacheScriptingInterface.h index 41ad7b69387..628f8bcb578 100644 --- a/libraries/audio/src/SoundCacheScriptingInterface.h +++ b/libraries/audio/src/SoundCacheScriptingInterface.h @@ -60,7 +60,7 @@ class SoundCacheScriptingInterface : public ScriptableResourceCache, public Depe * formats. * @returns {SoundObject} The sound ready for playback. */ - Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); + Q_INVOKABLE std::shared_ptr getSound(const QUrl& url); }; #endif // hifi_SoundCacheScriptingInterface_h diff --git a/libraries/audio/src/flump3dec.cpp b/libraries/audio/src/flump3dec.cpp index 7349cda7e42..79fec0992a9 100644 --- a/libraries/audio/src/flump3dec.cpp +++ b/libraries/audio/src/flump3dec.cpp @@ -101,7 +101,7 @@ * As Fluendo can not assure that any of the activities you undertake do not * infringe any patents or other industrial or intellectual property rights, * Fluendo hereby disclaims any liability for any patent infringement that may be - * claimed to you or to any other person from any legitimate right’s owner, as + * claimed to you or to any other person from any legitimate right's owner, as * stated in MIT license. So it is your responsibility to get information and to * acquire the necessary patent licenses to undertake your activities legally. */ diff --git a/libraries/audio/src/flump3dec.h b/libraries/audio/src/flump3dec.h index 688831da17d..e7c19cea4b3 100644 --- a/libraries/audio/src/flump3dec.h +++ b/libraries/audio/src/flump3dec.h @@ -101,7 +101,7 @@ * As Fluendo can not assure that any of the activities you undertake do not * infringe any patents or other industrial or intellectual property rights, * Fluendo hereby disclaims any liability for any patent infringement that may be - * claimed to you or to any other person from any legitimate right’s owner, as + * claimed to you or to any other person from any legitimate right's owner, as * stated in MIT license. So it is your responsibility to get information and to * acquire the necessary patent licenses to undertake your activities legally. */ diff --git a/libraries/auto-updater/src/AutoUpdater.h b/libraries/auto-updater/src/AutoUpdater.h index c788ac31d10..34350f8943e 100644 --- a/libraries/auto-updater/src/AutoUpdater.h +++ b/libraries/auto-updater/src/AutoUpdater.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 7c1cfcd4403..298b75fe631 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -136,7 +136,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. */ - Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: static void setShowAvatars(bool render); @@ -194,9 +194,9 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM }; virtual void indicateLoadingStatus(LoadingStatus loadingStatus) { _loadingStatus = loadingStatus; } - virtual QVector getJointRotations() const override; + virtual QVector> getJointRotations() const override; using AvatarData::getJointRotation; - virtual glm::quat getJointRotation(int index) const override; + virtual glm::qua getJointRotation(int index) const override; virtual QVector getJointTranslations() const override; using AvatarData::getJointTranslation; virtual glm::vec3 getJointTranslation(int index) const override; @@ -213,7 +213,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} index - The joint index. * @returns {Quat} The default rotation of the joint if the joint index is valid, otherwise {@link Quat(0)|Quat.IDENTITY}. */ - Q_INVOKABLE virtual glm::quat getDefaultJointRotation(int index) const; + Q_INVOKABLE virtual glm::qua getDefaultJointRotation(int index) const; /*@jsdoc * Gets the default translation of a joint (in the current avatar) relative to its parent, in model coordinates. @@ -225,7 +225,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @returns {Vec3} The default translation of the joint (in model coordinates) if the joint index is valid, otherwise * {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE virtual glm::vec3 getDefaultJointTranslation(int index) const; + Q_INVOKABLE virtual glm::vec<3,float,glm::packed_highp> getDefaultJointTranslation(int index) const; /*@jsdoc * Gets the default joint rotations in avatar coordinates. @@ -239,7 +239,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * var defaultHeadRotation = MyAvatar.getAbsoluteDefaultJointRotationInObjectFrame(headIndex); * print("Default head rotation: " + JSON.stringify(Quat.safeEulerAngles(defaultHeadRotation))); // Degrees */ - Q_INVOKABLE virtual glm::quat getAbsoluteDefaultJointRotationInObjectFrame(int index) const; + Q_INVOKABLE virtual glm::qua getAbsoluteDefaultJointRotationInObjectFrame(int index) const; /*@jsdoc * Gets the default joint translations in avatar coordinates. @@ -253,11 +253,11 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * var defaultHeadTranslation = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(headIndex); * print("Default head translation: " + JSON.stringify(defaultHeadTranslation)); */ - Q_INVOKABLE virtual glm::vec3 getAbsoluteDefaultJointTranslationInObjectFrame(int index) const; + Q_INVOKABLE virtual glm::vec<3,float,glm::packed_highp> getAbsoluteDefaultJointTranslationInObjectFrame(int index) const; virtual glm::vec3 getAbsoluteJointScaleInObjectFrame(int index) const override; - virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; + virtual glm::qua getAbsoluteJointRotationInObjectFrame(int index) const override; virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; /*@jsdoc @@ -268,7 +268,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {Quat} rotation - The rotation of the joint relative to the avatar. Not used. * @returns {boolean} false. */ - virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } + virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::qua& rotation) override { return false; } /*@jsdoc * Sets the translation of a joint relative to the avatar. @@ -291,7 +291,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Vec3} The position in the joint's coordinate system, or avatar coordinate system if no joint is specified. */ - Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToJointPoint(const glm::vec<3,float,glm::packed_highp>& position, const int jointIndex = -1) const; /*@jsdoc * Transforms a direction in world coordinates to a direction in a joint's coordinates, or avatar coordinates if no joint @@ -301,7 +301,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Vec3} The direction in the joint's coordinate system, or avatar coordinate system if no joint is specified. */ - Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToJointDirection(const glm::vec<3,float,glm::packed_highp>& direction, const int jointIndex = -1) const; /*@jsdoc * Transforms a rotation in world coordinates to a rotation in a joint's coordinates, or avatar coordinates if no joint is @@ -311,7 +311,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Quat} The rotation in the joint's coordinate system, or avatar coordinate system if no joint is specified. */ - Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const; + Q_INVOKABLE glm::qua worldToJointRotation(const glm::qua& rotation, const int jointIndex = -1) const; /*@jsdoc * Transforms a position in a joint's coordinates, or avatar coordinates if no joint is specified, to a position in world @@ -321,7 +321,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Vec3} The position in world coordinates. */ - Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> jointToWorldPoint(const glm::vec<3,float,glm::packed_highp>& position, const int jointIndex = -1) const; /*@jsdoc * Transforms a direction in a joint's coordinates, or avatar coordinates if no joint is specified, to a direction in world @@ -331,7 +331,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Vec3} The direction in world coordinates. */ - Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> jointToWorldDirection(const glm::vec<3,float,glm::packed_highp>& direction, const int jointIndex = -1) const; /*@jsdoc * Transforms a rotation in a joint's coordinates, or avatar coordinates if no joint is specified, to a rotation in world @@ -341,7 +341,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} [jointIndex=-1] - The index of the joint. * @returns {Quat} The rotation in world coordinates. */ - Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; + Q_INVOKABLE glm::qua jointToWorldRotation(const glm::qua& rotation, const int jointIndex = -1) const; Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; @@ -364,7 +364,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * MyAvatar.setSkeletonOffset(Vec3.ZERO); * }, 5000); */ - Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset); + Q_INVOKABLE void setSkeletonOffset(const glm::vec<3,float,glm::packed_highp>& offset); /*@jsdoc * Gets the offset applied to the current avatar. The offset adjusts the position that the avatar is rendered. For example, @@ -374,7 +374,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @example Report your avatar's current skeleton offset. * print(JSON.stringify(MyAvatar.getSkeletonOffset())); */ - Q_INVOKABLE glm::vec3 getSkeletonOffset() { return _skeletonOffset; } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getSkeletonOffset() { return _skeletonOffset; } virtual glm::vec3 getSkeletonPosition() const; @@ -384,7 +384,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @param {number} index - The index of the joint. * @returns {Vec3} The position of the joint in world coordinates. */ - Q_INVOKABLE glm::vec3 getJointPosition(int index) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getJointPosition(int index) const; /*@jsdoc * Gets the position of a joint in the current avatar. @@ -394,7 +394,7 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @example Report the position of your avatar's hips. * print(JSON.stringify(MyAvatar.getJointPosition("Hips"))); */ - Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getJointPosition(const QString& name) const; /*@jsdoc * Gets the position of the current avatar's neck in world coordinates. @@ -403,21 +403,21 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @example Report the position of your avatar's neck. * print(JSON.stringify(MyAvatar.getNeckPosition())); */ - Q_INVOKABLE glm::vec3 getNeckPosition() const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getNeckPosition() const; /*@jsdoc * Gets the current acceleration of the avatar. * @function MyAvatar.getAcceleration * @returns {Vec3} The current acceleration of the avatar. */ - Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getAcceleration() const { return _acceleration; } /// Scales a world space position vector relative to the avatar position and scale /// \param vector position to be scaled. Will store the result void scaleVectorRelativeToPosition(glm::vec3& positionToScale) const; void slamPosition(const glm::vec3& position); - virtual void updateAttitude(const glm::quat& orientation) override; + virtual void updateAttitude(const glm::qua& orientation) override; // Call this when updating Avatar position with a delta. This will allow us to // _accurately_ measure position changes and compute the resulting velocity @@ -436,10 +436,10 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM * @function MyAvatar.getWorldFeetPosition * @returns {Vec3} The position of the avatar's feet in world coordinates. */ - Q_INVOKABLE glm::vec3 getWorldFeetPosition(); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getWorldFeetPosition(); void setPositionViaScript(const glm::vec3& position) override; - void setOrientationViaScript(const glm::quat& orientation) override; + void setOrientationViaScript(const glm::qua& orientation) override; /*@jsdoc * Gets the ID of the entity or avatar that the avatar is parented to. @@ -486,9 +486,9 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM // NOT thread safe, must be called on main thread. glm::vec3 getUncachedLeftPalmPosition() const; - glm::quat getUncachedLeftPalmRotation() const; + glm::qua getUncachedLeftPalmRotation() const; glm::vec3 getUncachedRightPalmPosition() const; - glm::quat getUncachedRightPalmRotation() const; + glm::qua getUncachedRightPalmRotation() const; uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; } void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; } @@ -583,7 +583,7 @@ public slots: * @example Report the position of your avatar's left palm. * print(JSON.stringify(MyAvatar.getLeftPalmPosition())); */ - glm::vec3 getLeftPalmPosition() const; + glm::vec<3,float,glm::packed_highp> getLeftPalmPosition() const; /*@jsdoc * Gets the rotation of the left palm in world coordinates. @@ -592,7 +592,7 @@ public slots: * @example Report the rotation of your avatar's left palm. * print(JSON.stringify(MyAvatar.getLeftPalmRotation())); */ - glm::quat getLeftPalmRotation() const; + glm::qua getLeftPalmRotation() const; /*@jsdoc * Gets the position of the right palm in world coordinates. @@ -601,7 +601,7 @@ public slots: * @example Report the position of your avatar's right palm. * print(JSON.stringify(MyAvatar.getRightPalmPosition())); */ - glm::vec3 getRightPalmPosition() const; + glm::vec<3,float,glm::packed_highp> getRightPalmPosition() const; /*@jsdoc * Get the rotation of the right palm in world coordinates. @@ -610,7 +610,7 @@ public slots: * @example Report the rotation of your avatar's right palm. * print(JSON.stringify(MyAvatar.getRightPalmRotation())); */ - glm::quat getRightPalmRotation() const; + glm::qua getRightPalmRotation() const; /*@jsdoc * @function MyAvatar.setModelURLFinished diff --git a/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h b/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h index 906d3d438d3..bfcf37943ed 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h @@ -76,7 +76,7 @@ class ScriptAvatar : public ScriptAvatarData { Q_OBJECT - Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> skeletonOffset READ getSkeletonOffset) public: ScriptAvatar(AvatarSharedPointer avatarData); @@ -92,7 +92,7 @@ public slots: * @returns {Quat} The default rotation of the joint if avatar data are available and the joint index is valid, otherwise * {@link Quat(0)|Quat.IDENTITY}. */ - glm::quat getDefaultJointRotation(int index) const; + glm::qua getDefaultJointRotation(int index) const; /*@jsdoc * Gets the default translation of a joint in the avatar relative to its parent, in model coordinates. @@ -104,7 +104,7 @@ public slots: * @returns {Vec3} The default translation of the joint (in model coordinates) if avatar data are available and the joint * index is valid, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - glm::vec3 getDefaultJointTranslation(int index) const; + glm::vec<3,float,glm::packed_highp> getDefaultJointTranslation(int index) const; /*@jsdoc @@ -112,7 +112,7 @@ public slots: * @function ScriptAvatar.getSkeletonOffset * @returns {Vec3} The skeleton offset if avatar data are available, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - glm::vec3 getSkeletonOffset() const; + glm::vec<3,float,glm::packed_highp> getSkeletonOffset() const; /*@jsdoc @@ -122,7 +122,7 @@ public slots: * @returns {Vec3} The position of the joint in world coordinates, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't * available. */ - glm::vec3 getJointPosition(int index) const; + glm::vec<3,float,glm::packed_highp> getJointPosition(int index) const; /*@jsdoc * Gets the position of a joint in the current avatar. @@ -131,7 +131,7 @@ public slots: * @returns {Vec3} The position of the joint in world coordinates, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't * available. */ - glm::vec3 getJointPosition(const QString& name) const; + glm::vec<3,float,glm::packed_highp> getJointPosition(const QString& name) const; /*@jsdoc * Gets the position of the current avatar's neck in world coordinates. @@ -139,7 +139,7 @@ public slots: * @returns {Vec3} The position of the neck in world coordinates, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't * available. */ - glm::vec3 getNeckPosition() const; + glm::vec<3,float,glm::packed_highp> getNeckPosition() const; /*@jsdoc @@ -147,7 +147,7 @@ public slots: * @function ScriptAvatar.getAcceleration * @returns {Vec3} The current acceleration of the avatar, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't available.. */ - glm::vec3 getAcceleration() const; + glm::vec<3,float,glm::packed_highp> getAcceleration() const; /*@jsdoc @@ -191,7 +191,7 @@ public slots: * @returns {Vec3} The position of the left palm in world coordinates, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't * available. */ - glm::vec3 getLeftPalmPosition() const; + glm::vec<3,float,glm::packed_highp> getLeftPalmPosition() const; /*@jsdoc * Gets the rotation of the left palm in world coordinates. @@ -199,7 +199,7 @@ public slots: * @returns {Quat} The rotation of the left palm in world coordinates, or {@link Quat(0)|Quat.IDENTITY} if the avatar data * aren't available. */ - glm::quat getLeftPalmRotation() const; + glm::qua getLeftPalmRotation() const; /*@jsdoc * Gets the position of the right palm in world coordinates. @@ -207,7 +207,7 @@ public slots: * @returns {Vec3} The position of the right palm in world coordinates, or {@link Vec3(0)|Vec3.ZERO} if avatar data aren't * available. */ - glm::vec3 getRightPalmPosition() const; + glm::vec<3,float,glm::packed_highp> getRightPalmPosition() const; /*@jsdoc * Gets the rotation of the right palm in world coordinates. @@ -215,7 +215,7 @@ public slots: * @returns {Quat} The rotation of the right palm in world coordinates, or {@link Quat(0)|Quat.IDENTITY} if the avatar data * aren't available. */ - glm::quat getRightPalmRotation() const; + glm::qua getRightPalmRotation() const; private: std::shared_ptr lockAvatar() const; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b5c9e2eb0aa..be285c7ccc7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1899,7 +1900,7 @@ QVector AvatarData::getJointRotations() const { if (QThread::currentThread() != thread()) { QVector result; BLOCKING_INVOKE_METHOD(const_cast(this), "getJointRotations", - Q_RETURN_ARG(QVector, result)); + Q_GENERIC_RETURN_ARG(QVector, result)); return result; } QReadLocker readLock(&_jointDataLock); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a31291e1fce..c835b87b2a2 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -551,22 +551,22 @@ class AvatarData : public QObject, public SpatiallyNestable { * this property to false to fully control the mouth facial blend shapes via the * {@link Avatar.setBlendshape} method. */ - Q_PROPERTY(glm::vec3 position READ getWorldPosition WRITE setPositionViaScript) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> position READ getWorldPosition WRITE setPositionViaScript) Q_PROPERTY(float scale READ getDomainLimitedScale WRITE setTargetScale) Q_PROPERTY(float density READ getDensity) - Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll) - Q_PROPERTY(glm::quat orientation READ getWorldOrientation WRITE setOrientationViaScript) - Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation) + Q_PROPERTY(glm::qua orientation READ getWorldOrientation WRITE setOrientationViaScript) + Q_PROPERTY(glm::qua headOrientation READ getHeadOrientation WRITE setHeadOrientation) Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch) Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw) Q_PROPERTY(float headRoll READ getHeadRoll WRITE setHeadRoll) - Q_PROPERTY(glm::vec3 velocity READ getWorldVelocity WRITE setWorldVelocity) - Q_PROPERTY(glm::vec3 angularVelocity READ getWorldAngularVelocity WRITE setWorldAngularVelocity) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> velocity READ getWorldVelocity WRITE setWorldVelocity) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> angularVelocity READ getWorldAngularVelocity WRITE setWorldAngularVelocity) Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness) Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness) @@ -582,9 +582,9 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(QUuid sessionUUID READ getSessionUUID NOTIFY sessionUUIDChanged) - Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix) - Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix) - Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> sensorToWorldMatrix READ getSensorToWorldMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> controllerLeftHandMatrix READ getControllerLeftHandMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> controllerRightHandMatrix READ getControllerRightHandMatrix) Q_PROPERTY(float sensorToWorldScale READ getSensorToWorldScale) @@ -612,7 +612,7 @@ class AvatarData : public QObject, public SpatiallyNestable { const QUuid getSessionUUID() const { return getID(); } - glm::vec3 getHandPosition() const; + glm::vec<3,float,glm::packed_highp> getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); typedef enum { @@ -805,7 +805,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation); + Q_INVOKABLE virtual void setJointData(int index, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& translation); /*@jsdoc * Sets a specific joint's rotation relative to its parent. @@ -818,7 +818,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @param {number} index - The index of the joint. * @param {Quat} rotation - The rotation of the joint relative to its parent. */ - Q_INVOKABLE virtual void setJointRotation(int index, const glm::quat& rotation); + Q_INVOKABLE virtual void setJointRotation(int index, const glm::qua& rotation); /*@jsdoc * Sets a specific joint's translation relative to its parent, in model coordinates. @@ -832,7 +832,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @param {number} index - The index of the joint. * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates. */ - Q_INVOKABLE virtual void setJointTranslation(int index, const glm::vec3& translation); + Q_INVOKABLE virtual void setJointTranslation(int index, const glm::vec<3,float,glm::packed_highp>& translation); /*@jsdoc * Clears joint translations and rotations set by script for a specific joint. This restores all motion from the default @@ -858,7 +858,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @param {number} index - The index of the joint. * @returns {Quat} The rotation of the joint relative to its parent. */ - Q_INVOKABLE virtual glm::quat getJointRotation(int index) const; + Q_INVOKABLE virtual glm::qua getJointRotation(int index) const; /*@jsdoc * Gets the translation of a joint relative to its parent, in model coordinates. @@ -869,7 +869,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @param {number} index - The index of the joint. * @returns {Vec3} The translation of the joint relative to its parent, in model coordinates. */ - Q_INVOKABLE virtual glm::vec3 getJointTranslation(int index) const; + Q_INVOKABLE virtual glm::vec<3,float,glm::packed_highp> getJointTranslation(int index) const; /*@jsdoc * Sets a specific joint's rotation and position relative to its parent, in model coordinates. @@ -884,7 +884,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @param {Quat} rotation - The rotation of the joint relative to its parent. * @param {Vec3} translation - The translation of the joint relative to its parent, in model coordinates. */ - Q_INVOKABLE virtual void setJointData(const QString& name, const glm::quat& rotation, const glm::vec3& translation); + Q_INVOKABLE virtual void setJointData(const QString& name, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& translation); /*@jsdoc * Sets a specific joint's rotation relative to its parent. @@ -917,7 +917,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual void setJointRotation(const QString& name, const glm::quat& rotation); + Q_INVOKABLE virtual void setJointRotation(const QString& name, const glm::qua& rotation); /*@jsdoc * Sets a specific joint's translation relative to its parent, in model coordinates. @@ -943,7 +943,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual void setJointTranslation(const QString& name, const glm::vec3& translation); + Q_INVOKABLE virtual void setJointTranslation(const QString& name, const glm::vec<3,float,glm::packed_highp>& translation); /*@jsdoc * Clears joint translations and rotations set by script for a specific joint. This restores all motion from the default @@ -983,7 +983,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual glm::quat getJointRotation(const QString& name) const; + Q_INVOKABLE virtual glm::qua getJointRotation(const QString& name) const; /*@jsdoc * Gets the translation of a joint relative to its parent, in model coordinates. @@ -998,7 +998,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual glm::vec3 getJointTranslation(const QString& name) const; + Q_INVOKABLE virtual glm::vec<3,float,glm::packed_highp> getJointTranslation(const QString& name) const; /*@jsdoc * Gets the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint. @@ -1010,7 +1010,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace all "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual QVector getJointRotations() const; + Q_INVOKABLE virtual QVector> getJointRotations() const; /*@jsdoc * Gets the translations of all joints in the current avatar. Each joint's translation is relative to its parent joint, in @@ -1021,7 +1021,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * same order as the array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the * Avatar API. */ - Q_INVOKABLE virtual QVector getJointTranslations() const; + Q_INVOKABLE virtual QVector> getJointTranslations() const; /*@jsdoc * Sets the rotations of all joints in the current avatar. Each joint's rotation is relative to its parent joint. @@ -1059,7 +1059,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". */ - Q_INVOKABLE virtual void setJointRotations(const QVector& jointRotations); + Q_INVOKABLE virtual void setJointRotations(const QVector>& jointRotations); /*@jsdoc * Sets the translations of all joints in the current avatar. Each joint's translation is relative to its parent joint, in @@ -1075,7 +1075,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * the same order as the array returned by {@link MyAvatar.getJointNames}, or {@link Avatar.getJointNames} if using the * Avatar API. */ - Q_INVOKABLE virtual void setJointTranslations(const QVector& jointTranslations); + Q_INVOKABLE virtual void setJointTranslations(const QVector>& jointTranslations); /*@jsdoc * Clears all joint translations and rotations that have been set by script. This restores all motion from the default @@ -1293,7 +1293,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ // thread safe - Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const; + Q_INVOKABLE glm::mat<4,4,float,glm::packed_highp> getSensorToWorldMatrix() const; /*@jsdoc * Gets the scale that transforms dimensions in the user's real world to the avatar's size in the virtual world. @@ -1318,7 +1318,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". */ // thread safe - Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const; + Q_INVOKABLE glm::mat<4,4,float,glm::packed_highp> getControllerLeftHandMatrix() const; /*@jsdoc * Gets the rotation and translation of the right hand controller relative to the avatar. @@ -1326,7 +1326,7 @@ class AvatarData : public QObject, public SpatiallyNestable { * @returns {Mat4} The rotation and translation of the right hand controller relative to the avatar. */ // thread safe - Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const; + Q_INVOKABLE glm::mat<4,4,float,glm::packed_highp> getControllerRightHandMatrix() const; /*@jsdoc @@ -1496,7 +1496,7 @@ public slots: * @param {number} index - The index of the joint. Not used. * @returns {Quat} Quat.IDENTITY. */ - virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; + virtual glm::qua getAbsoluteJointRotationInObjectFrame(int index) const override; /*@jsdoc * Gets the translation of a joint relative to the avatar. @@ -1505,7 +1505,7 @@ public slots: * @param {number} index - The index of the joint. Not used. * @returns {Vec3} Vec3.ZERO. */ - virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; + virtual glm::vec<3,float,glm::packed_highp> getAbsoluteJointTranslationInObjectFrame(int index) const override; /*@jsdoc * Sets the rotation of a joint relative to the avatar. @@ -1515,7 +1515,7 @@ public slots: * @param {Quat} rotation - The rotation of the joint relative to the avatar. Not used. * @returns {boolean} false. */ - virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } + virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::qua& rotation) override { return false; } /*@jsdoc * Sets the translation of a joint relative to the avatar. @@ -1525,7 +1525,7 @@ public slots: * @param {Vec3} translation - The translation of the joint relative to the avatar. Not used. * @returns {boolean} false. */ - virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } + virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec<3,float,glm::packed_highp>& translation) override { return false; } /*@jsdoc * Gets the target scale of the avatar without any restrictions on permissible values imposed by the domain. In contrast, the diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index dcb0604e504..99d546bc10d 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -105,7 +105,7 @@ class AvatarHashMap : public QObject, public Dependency { * var avatars = AvatarList.getAvatarsInRange(Vec3.ZERO, RANGE); * print("Avatars near the origin: " + JSON.stringify(avatars)); */ - Q_INVOKABLE QVector getAvatarsInRange(const glm::vec3& position, float rangeMeters) const; + Q_INVOKABLE QVector getAvatarsInRange(const glm::vec<3,float,glm::packed_highp>& position, float rangeMeters) const; /*@jsdoc * Gets information about an avatar. @@ -179,7 +179,7 @@ public slots: * @returns {boolean} true if there's an avatar within the specified distance of the point, false * if not. */ - bool isAvatarInRange(const glm::vec3 & position, const float range); + bool isAvatarInRange(const glm::vec<3,float,glm::packed_highp> & position, const float range); protected slots: diff --git a/libraries/avatars/src/ScriptAvatarData.h b/libraries/avatars/src/ScriptAvatarData.h index 960423a1eec..205e6d43f9f 100644 --- a/libraries/avatars/src/ScriptAvatarData.h +++ b/libraries/avatars/src/ScriptAvatarData.h @@ -23,22 +23,22 @@ class ScriptAvatarData : public QObject { // // PHYSICAL PROPERTIES: POSITION AND ORIENTATION // - Q_PROPERTY(glm::vec3 position READ getPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> position READ getPosition) Q_PROPERTY(float scale READ getTargetScale) - Q_PROPERTY(glm::vec3 handPosition READ getHandPosition) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> handPosition READ getHandPosition) Q_PROPERTY(float bodyPitch READ getBodyPitch) Q_PROPERTY(float bodyYaw READ getBodyYaw) Q_PROPERTY(float bodyRoll READ getBodyRoll) - Q_PROPERTY(glm::quat orientation READ getOrientation) - Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation) + Q_PROPERTY(glm::qua orientation READ getOrientation) + Q_PROPERTY(glm::qua headOrientation READ getHeadOrientation) Q_PROPERTY(float headPitch READ getHeadPitch) Q_PROPERTY(float headYaw READ getHeadYaw) Q_PROPERTY(float headRoll READ getHeadRoll) // // PHYSICAL PROPERTIES: VELOCITY // - Q_PROPERTY(glm::vec3 velocity READ getVelocity) - Q_PROPERTY(glm::vec3 angularVelocity READ getAngularVelocity) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> velocity READ getVelocity) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> angularVelocity READ getAngularVelocity) // // IDENTIFIER PROPERTIES @@ -64,9 +64,9 @@ class ScriptAvatarData : public QObject { // // MATRIX PROPERTIES // - Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix) - Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix) - Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> sensorToWorldMatrix READ getSensorToWorldMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> controllerLeftHandMatrix READ getControllerLeftHandMatrix) + Q_PROPERTY(glm::mat<4,4,float,glm::packed_highp> controllerRightHandMatrix READ getControllerRightHandMatrix) Q_PROPERTY(bool hasPriority READ getHasPriority) @@ -82,8 +82,8 @@ class ScriptAvatarData : public QObject { float getBodyPitch() const; float getBodyYaw() const; float getBodyRoll() const; - glm::quat getOrientation() const; - glm::quat getHeadOrientation() const; + glm::qua getOrientation() const; + glm::qua getHeadOrientation() const; float getHeadPitch() const; float getHeadYaw() const; float getHeadRoll() const; @@ -123,7 +123,7 @@ class ScriptAvatarData : public QObject { * @returns {Quat} The rotation of the joint relative to its parent, or {@link Quat(0)|Quat.IDENTITY} if the avatar data * aren't available. */ - Q_INVOKABLE glm::quat getJointRotation(int index) const; + Q_INVOKABLE glm::qua getJointRotation(int index) const; /*@jsdoc * Gets the translation of a joint relative to its parent, in model coordinates. @@ -135,7 +135,7 @@ class ScriptAvatarData : public QObject { * @returns {Vec3} The translation of the joint relative to its parent, in model coordinates, or {@link Vec3(0)|Vec3.ZERO} * if the avatar data aren't available. */ - Q_INVOKABLE glm::vec3 getJointTranslation(int index) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getJointTranslation(int index) const; /*@jsdoc * Gets the rotation of a joint relative to its parent. For information on the joint hierarchy used, see @@ -145,7 +145,7 @@ class ScriptAvatarData : public QObject { * @returns {Quat} The rotation of the joint relative to its parent, or {@link Quat(0)|Quat.IDENTITY} if the avatar data * aren't available. */ - Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; + Q_INVOKABLE glm::qua getJointRotation(const QString& name) const; /*@jsdoc * Gets the translation of a joint relative to its parent, in model coordinates. @@ -157,7 +157,7 @@ class ScriptAvatarData : public QObject { * @returns {Vec3} The translation of the joint relative to its parent, in model coordinates, or {@link Vec3(0)|Vec3.ZERO} * if the avatar data aren't available. */ - Q_INVOKABLE glm::vec3 getJointTranslation(const QString& name) const; + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getJointTranslation(const QString& name) const; /*@jsdoc * Gets the rotations of all joints in the avatar. Each joint's rotation is relative to its parent joint. @@ -165,7 +165,7 @@ class ScriptAvatarData : public QObject { * @returns {Quat[]} The rotations of all joints relative to each's parent, or [] if the avatar data aren't * available. The values are in the same order as the array returned by {@link ScriptAvatar.getJointNames}. */ - Q_INVOKABLE QVector getJointRotations() const; + Q_INVOKABLE QVector> getJointRotations() const; /*@jsdoc * Gets the translations of all joints in the avatar. Each joint's translation is relative to its parent joint, in @@ -176,7 +176,7 @@ class ScriptAvatarData : public QObject { * the avatar data aren't available. The values are in the same order as the array returned by * {@link ScriptAvatar.getJointNames}. */ - Q_INVOKABLE QVector getJointTranslations() const; + Q_INVOKABLE QVector> getJointTranslations() const; /*@jsdoc * Checks that the data for a joint are valid. @@ -216,9 +216,9 @@ class ScriptAvatarData : public QObject { // // MATRIX PROPERTIES // - glm::mat4 getSensorToWorldMatrix() const; - glm::mat4 getControllerLeftHandMatrix() const; - glm::mat4 getControllerRightHandMatrix() const; + glm::mat<4,4,float,glm::packed_highp> getSensorToWorldMatrix() const; + glm::mat<4,4,float,glm::packed_highp> getControllerLeftHandMatrix() const; + glm::mat<4,4,float,glm::packed_highp> getControllerRightHandMatrix() const; bool getHasPriority() const; @@ -262,7 +262,7 @@ public slots: * @returns {Quat} The rotation of the joint relative to the avatar, or {@link Quat(0)|Quat.IDENTITY} if the avatar data * aren't available. */ - glm::quat getAbsoluteJointRotationInObjectFrame(int index) const; + glm::qua getAbsoluteJointRotationInObjectFrame(int index) const; /*@jsdoc * Gets the translation of a joint relative to the avatar. @@ -271,7 +271,7 @@ public slots: * @returns {Vec3} The translation of the joint relative to the avatar, or {@link Vec3(0)|Vec3.ZERO} if the avatar data * aren't available. */ - glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const; + glm::vec<3,float,glm::packed_highp> getAbsoluteJointTranslationInObjectFrame(int index) const; protected: std::weak_ptr _avatarData; diff --git a/libraries/baking/src/JSBaker.cpp b/libraries/baking/src/JSBaker.cpp index e4fdd742561..26786a6a2b6 100644 --- a/libraries/baking/src/JSBaker.cpp +++ b/libraries/baking/src/JSBaker.cpp @@ -274,7 +274,7 @@ bool JSBaker::canOmitNewLine(QChar previousCharacter, QChar nextCharacter) { //Check if character is alphabet, number or one of the following: '_', '$', '\\' or a non-ASCII character bool JSBaker::isAlphanum(QChar c) { return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') - || c == '_' || c == '$' || c == '\\' || c > ASCII_CHARACTERS_UPPER_LIMIT); + || c == '_' || c == '$' || c == '\\' || c > QChar(ASCII_CHARACTERS_UPPER_LIMIT)); } bool JSBaker::isNonAscii(QChar c) { diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp index 631a10fd11f..669163c6b5a 100644 --- a/libraries/baking/src/MaterialBaker.cpp +++ b/libraries/baking/src/MaterialBaker.cpp @@ -54,7 +54,7 @@ void MaterialBaker::bake() { if (_materialResource->isLoaded()) { processMaterial(); } else { - connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded); + connect(_materialResource.get(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded); } } } @@ -71,7 +71,7 @@ void MaterialBaker::loadMaterial() { if (!_isURL) { qCDebug(material_baking) << "Loading local material" << _materialData; - _materialResource = QSharedPointer::create(); + _materialResource = std::make_shared(); // TODO: add baseURL to allow these to reference relative files next to them _materialResource->parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(_materialData.toUtf8()), QUrl()); } else { @@ -83,7 +83,7 @@ void MaterialBaker::loadMaterial() { if (_materialResource->isLoaded()) { emit originalMaterialLoaded(); } else { - connect(_materialResource.data(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded); + connect(_materialResource.get(), &Resource::finished, this, &MaterialBaker::originalMaterialLoaded); } } else { handleError("Error loading " + _materialData); @@ -139,7 +139,7 @@ void MaterialBaker::processMaterial() { if (QImageReader::supportedImageFormats().contains(extension.toLatin1())) { TextureKey textureKey(textureURL, type); if (!_textureBakers.contains(textureKey)) { - auto baseTextureFileName = _textureFileNamer.createBaseTextureFileName(textureURL.fileName(), type); + auto baseTextureFileName = _textureFileNamer.createBaseTextureFileName(QFileInfo(textureURL.fileName()), type); QSharedPointer textureBaker { new TextureBaker(textureURL, type, _textureOutputDir, baseTextureFileName, content), diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 11b52ba69c8..8d8f4c93029 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -70,7 +70,7 @@ void ModelBaker::setMappingURL(const QUrl& mappingURL) { _mappingURL = mappingURL; } -void ModelBaker::setMapping(const hifi::VariantHash& mapping) { +void ModelBaker::setMapping(const hifi::VariantMultiHash& mapping) { _mapping = mapping; } @@ -227,7 +227,7 @@ void ModelBaker::bakeSourceCopy() { handleError("Could not recognize file type of model file " + _originalOutputModelPath); return; } - hifi::VariantHash serializerMapping = _mapping; + hifi::VariantMultiHash serializerMapping = _mapping; serializerMapping["combineParts"] = true; // set true so that OBJSerializer reads material info from material library serializerMapping["deduplicateIndices"] = true; // Draco compression also deduplicates, but we might as well shave it off to save on some earlier processing (currently FBXSerializer only) hfm::Model::Pointer loadedModel = serializer->read(modelData, serializerMapping, _modelURL); @@ -380,7 +380,7 @@ void ModelBaker::outputUnbakedFST() { outputFSTFilename += FST_EXTENSION; QString outputFSTURL = _originalOutputDir + "/" + outputFSTFilename; - hifi::VariantHash outputMapping; + hifi::VariantMultiHash outputMapping; outputMapping[FST_VERSION_FIELD] = FST_VERSION; outputMapping[FILENAME_FIELD] = _modelURL.fileName(); outputMapping[COMMENT_FIELD] = "This FST file was generated by Oven for use during rebaking. It is not part of the original model. This file's existence is subject to change."; diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index 4280f8af70b..af33bdf0bf7 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -45,7 +45,7 @@ class ModelBaker : public Baker { void setOutputURLSuffix(const QUrl& urlSuffix); void setMappingURL(const QUrl& mappingURL); - void setMapping(const hifi::VariantHash& mapping); + void setMapping(const hifi::VariantMultiHash& mapping); void initializeOutputDirs(); @@ -74,7 +74,7 @@ public slots: QUrl _modelURL; QUrl _outputURLSuffix; QUrl _mappingURL; - hifi::VariantHash _mapping; + hifi::VariantMultiHash _mapping; QString _bakedOutputDir; QString _originalOutputDir; QString _originalOutputModelPath; diff --git a/libraries/baking/src/TextureBaker.cpp b/libraries/baking/src/TextureBaker.cpp index 02423d41486..0ae21a88ee5 100644 --- a/libraries/baking/src/TextureBaker.cpp +++ b/libraries/baking/src/TextureBaker.cpp @@ -136,7 +136,7 @@ void TextureBaker::processTexture() { // so we add that to the processed texture before handling it off to be serialized QCryptographicHash hasher(QCryptographicHash::Md5); hasher.addData(_originalTexture); - hasher.addData((const char*)&_textureType, sizeof(_textureType)); + hasher.addData(QByteArrayView((const char*)&_textureType, sizeof(_textureType))); auto hashData = hasher.result(); std::string hash = hashData.toHex().toStdString(); diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h index f2a5ca1296e..31030013ca8 100644 --- a/libraries/controllers/src/controllers/Input.h +++ b/libraries/controllers/src/controllers/Input.h @@ -95,4 +95,6 @@ struct Input { } +Q_DECLARE_METATYPE(controller::Input) + #endif diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index 7187dfa3f83..33fb50cfaad 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -51,6 +51,6 @@ namespace controller { }; } -//Q_DECLARE_METATYPE(controller::Pose); +Q_DECLARE_METATYPE(controller::Pose); #endif diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 8db3df5011c..4ae598aebb0 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -52,10 +52,10 @@ namespace controller { public slots: virtual bool isActive() const = 0; - virtual glm::vec3 getAbsTranslation() const = 0; - virtual glm::quat getAbsRotation() const = 0; - virtual glm::vec3 getLocTranslation() const = 0; - virtual glm::quat getLocRotation() const = 0; + virtual glm::vec<3,float,glm::packed_highp> getAbsTranslation() const = 0; + virtual glm::qua getAbsRotation() const = 0; + virtual glm::vec<3,float,glm::packed_highp> getLocTranslation() const = 0; + virtual glm::qua getLocRotation() const = 0; signals: //void spatialEvent(const SpatialEvent& event); @@ -205,7 +205,7 @@ namespace controller { * var RIGHT_HAND = 1; * Controller.triggerHapticPulse(HAPTIC_STRENGTH, HAPTIC_DURATION, RIGHT_HAND); */ - Q_INVOKABLE bool triggerHapticPulse(float strength, float duration, uint16_t index = 2) const; + Q_INVOKABLE bool triggerHapticPulse(float strength, float duration, ushort index = 2) const; /*@jsdoc * Triggers a 250ms haptic pulse on connected and enabled devices that have the capability. @@ -216,7 +216,7 @@ namespace controller { * index = 1 is the right hand, and index = 2 is both hands. For other devices, * such as haptic vests, index will have a different meaning, defined by the input device. */ - Q_INVOKABLE bool triggerShortHapticPulse(float strength, uint16_t index = 2) const; + Q_INVOKABLE bool triggerShortHapticPulse(float strength, ushort index = 2) const; /*@jsdoc * Triggers a haptic pulse on a particular device if connected and enabled and it has the capability. @@ -236,7 +236,7 @@ namespace controller { * Controller.triggerHapticPulseOnDevice(deviceID, HAPTIC_STRENGTH, HAPTIC_DURATION, RIGHT_HAND); */ Q_INVOKABLE bool triggerHapticPulseOnDevice(unsigned int device, float strength, float duration, - uint16_t index = 2) const; + ushort index = 2) const; /*@jsdoc * Triggers a 250ms haptic pulse on a particular device if connected and enabled and it has the capability. @@ -248,7 +248,7 @@ namespace controller { * index = 1 is the right hand, and index = 2 is both hands. For other devices, * such as haptic vests, index will have a different meaning, defined by the input device. */ - Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, uint16_t index = 2) const; + Q_INVOKABLE bool triggerShortHapticPulseOnDevice(unsigned int device, float strength, ushort index = 2) const; /*@jsdoc * Creates a new controller mapping. Routes can then be added to the mapping using {@link MappingObject} methods and diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index c20b040a850..1c6b2b99c55 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -232,9 +232,7 @@ namespace controller { } Q_DECLARE_METATYPE(controller::Input::NamedPair) -Q_DECLARE_METATYPE(controller::Pose) Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(controller::Input) Q_DECLARE_METATYPE(controller::Action) Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(controller::Hand) diff --git a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h index da3e3ec26be..ef5757c95d7 100644 --- a/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h +++ b/libraries/controllers/src/controllers/impl/RouteBuilderProxy.h @@ -376,7 +376,7 @@ class RouteBuilderProxy : public QObject { * @returns {RouteObject} The RouteObject with the pre-translation applied. */ // No JSDoc example because filter not currently used. - Q_INVOKABLE QObject* translate(glm::vec3 translate); + Q_INVOKABLE QObject* translate(glm::vec<3,float,glm::packed_highp> translate); /*@jsdoc * Filters {@link Pose} route values to have a pre-transform applied. @@ -385,7 +385,7 @@ class RouteBuilderProxy : public QObject { * @returns {RouteObject} The RouteObject with the pre-transform applied. */ // No JSDoc example because filter not currently used. - Q_INVOKABLE QObject* transform(glm::mat4 transform); + Q_INVOKABLE QObject* transform(glm::mat<4,4,float,glm::packed_highp> transform); /*@jsdoc * Filters {@link Pose} route values to have a post-transform applied. @@ -394,7 +394,7 @@ class RouteBuilderProxy : public QObject { * @returns {RouteObject} The RouteObject with the post-transform applied. */ // No JSDoc example because filter not currently used. - Q_INVOKABLE QObject* postTransform(glm::mat4 transform); + Q_INVOKABLE QObject* postTransform(glm::mat<4,4,float,glm::packed_highp> transform); /*@jsdoc * Filters {@link Pose} route values to have a pre-rotation applied. @@ -403,7 +403,7 @@ class RouteBuilderProxy : public QObject { * @returns {RouteObject} The RouteObject with the pre-rotation applied. */ // No JSDoc example because filter not currently used. - Q_INVOKABLE QObject* rotate(glm::quat rotation); + Q_INVOKABLE QObject* rotate(glm::qua rotation); /*@jsdoc * Filters {@link Pose} route values to be smoothed by a low velocity filter. The filter's rotation and translation diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index a080a094a23..dc6dc860d68 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index ed16b5875c8..e9a9a1c0cf3 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -175,7 +175,7 @@ QPointF CompositorHelper::getMouseEventPosition(QMouseEvent* event) { QMutexLocker locker(&_reticleLock); return QPointF(_reticlePositionInHMD.x, _reticlePositionInHMD.y); } - return event->localPos(); + return event->position(); } static bool isWindowActive() { diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index a952b802383..fcfef875a44 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -215,7 +215,7 @@ class ReticleInterface : public QObject { Q_PROPERTY(bool visible READ getVisible WRITE setVisible) Q_PROPERTY(float depth READ getDepth WRITE setDepth) Q_PROPERTY(float scale READ getScale WRITE setScale) - Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> maximumPosition READ getMaximumPosition) Q_PROPERTY(bool mouseCaptured READ isMouseCaptured) Q_PROPERTY(bool allowMouseCapture READ getAllowMouseCapture WRITE setAllowMouseCapture) Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay) @@ -258,6 +258,7 @@ class ReticleInterface : public QObject { * @returns {boolean} true if the mouse cursor is pointing at UI in the Interface window in desktop mode or on * the HUD surface in HMD mode, false if it isn't. */ + // QT6TODO: Reticle.isPointingAtSystemOverlay does not work currently Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); } /*@jsdoc @@ -332,7 +333,7 @@ class ReticleInterface : public QObject { * @function Reticle.getMaximumPosition * @returns {Vec2} The maximum reticle coordinates on the display device in desktop mode or the HUD surface in HMD mode. */ - Q_INVOKABLE glm::vec2 getMaximumPosition() { return _compositor->getReticleMaximumPosition(); } + Q_INVOKABLE glm::vec<2,float,glm::packed_highp> getMaximumPosition() { return _compositor->getReticleMaximumPosition(); } private: CompositorHelper* _compositor; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index f184027570f..4b1cc3c1677 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index 3ff3441f5cf..aaa7dd4be23 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -9,9 +9,8 @@ #include "StereoDisplayPlugin.h" #include -#include +#include #include -#include #include #include diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index c89c46bd822..0fe4bf3460e 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "HTTPConnection.h" #include "EmbeddedWebserverLogging.h" diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 6e36c360c63..b299f1ba596 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -228,7 +228,7 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() { // Clear the pointer before lambda is run on another thread. _persistentEntitiesScriptManager.reset(); if (scriptManager) { - QtConcurrent::run([manager = scriptManager] { + QThreadPool::globalInstance()->start([manager = scriptManager] { manager->unloadAllEntityScripts(true); manager->stop(); manager->waitTillDoneRunning(); @@ -262,7 +262,7 @@ void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() { // Release the pointer as soon as possible. _nonPersistentEntitiesScriptManager.reset(); if (scriptManager) { - QtConcurrent::run([manager = scriptManager] { + QThreadPool::globalInstance()->start([manager = scriptManager] { manager->unloadAllEntityScripts(true); manager->stop(); manager->waitTillDoneRunning(); @@ -932,7 +932,7 @@ QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); auto entityScriptingInterface = DependencyManager::get(); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + PickRay ray = _viewState->computePickRay(event->position().x(), event->position().y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); EntityItemPointer entity; if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) { @@ -966,7 +966,7 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("EntityTreeRenderer::mouseDoublePressEvent"); auto entityScriptingInterface = DependencyManager::get(); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + PickRay ray = _viewState->computePickRay(event->position().x(), event->position().y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); EntityItemPointer entity; if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) { @@ -998,7 +998,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); auto entityScriptingInterface = DependencyManager::get(); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + PickRay ray = _viewState->computePickRay(event->position().x(), event->position().y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); EntityItemPointer entity; if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) { @@ -1043,7 +1043,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); auto entityScriptingInterface = DependencyManager::get(); - PickRay ray = _viewState->computePickRay(event->x(), event->y()); + PickRay ray = _viewState->computePickRay(event->position().x(), event->position().y()); RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); EntityItemPointer entity; if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) { diff --git a/libraries/entities-renderer/src/ModelScriptingInterface.h b/libraries/entities-renderer/src/ModelScriptingInterface.h index cf276e130e3..328ad5351e5 100644 --- a/libraries/entities-renderer/src/ModelScriptingInterface.h +++ b/libraries/entities-renderer/src/ModelScriptingInterface.h @@ -72,7 +72,7 @@ class ModelScriptingInterface : public QObject { * @param {MeshProxy} mesh - The mesh to apply the transform to. * @returns {MeshProxy|boolean} The transformed mesh, if valid. false if an error. */ - Q_INVOKABLE ScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy); + Q_INVOKABLE ScriptValue transformMesh(glm::mat<4,4,float,glm::packed_highp> transform, MeshProxy* meshProxy); /*@jsdoc * Creates a new mesh. @@ -82,8 +82,8 @@ class ModelScriptingInterface : public QObject { * @param {MeshFace[]} faces - The faces in the mesh. * @returns {MeshProxy} A new mesh. */ - Q_INVOKABLE ScriptValue newMesh(const QVector& vertices, - const QVector& normals, + Q_INVOKABLE ScriptValue newMesh(const QVector>& vertices, + const QVector>& normals, const QVector& faces); /*@jsdoc diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 1d2b771d4ed..38998d3fe73 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -171,7 +171,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo if (_networkMaterial->isLoaded()) { onMaterialRequestFinished(!_networkMaterial->isFailed()); } else { - connect(_networkMaterial.data(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) { + connect(_networkMaterial.get(), &Resource::finished, this, [this, onMaterialRequestFinished](bool success) { onMaterialRequestFinished(success); }); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 82e11f72a00..a5acebd315e 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -465,7 +465,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + offset) - registrationOffset; } } - shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL() + model->getSnapModelToRegistrationPoint()); + // QT6TODO: I have no idea what implicit conversion from bool to QString did in Qt5 + shapeInfo.setParams(type, 0.5f * extents, getCompoundShapeURL() + QString::number(model->getSnapModelToRegistrationPoint())); adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint()); } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { updateModelBounds(); @@ -698,7 +699,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { } } - shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL() + model->getSnapModelToRegistrationPoint()); + shapeInfo.setParams(type, 0.5f * extents.size(), getModelURL() + QString::number(model->getSnapModelToRegistrationPoint())); adjustShapeInfoByRegistration(shapeInfo, model->getSnapModelToRegistrationPoint()); } else { EntityItem::computeShapeInfo(shapeInfo); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 35b9364fb79..ce02f68985a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1018,7 +1018,7 @@ void RenderablePolyVoxEntityItem::uncompressVolumeData() { voxelData = _voxelData; }); - QtConcurrent::run([=, this] { + QThreadPool::globalInstance()->start([=, this] { QDataStream reader(voxelData); quint16 voxelXSize, voxelYSize, voxelZSize; reader >> voxelXSize; @@ -1064,7 +1064,7 @@ void RenderablePolyVoxEntityItem::setVoxelsFromData(QByteArray uncompressedData, low += 1; } loop3(ivec3(0), ivec3(voxelXSize, voxelYSize, voxelZSize), [&](const ivec3& v) { - int uncompressedIndex = (v.z * (voxelYSize) * (voxelXSize)) + (v.y * (voxelZSize)) + v.x; + int uncompressedIndex = (v.z * (voxelYSize) * (voxelXSize)) + (v.y * (voxelXSize)) + v.x; result |= setVoxelInternal(v, uncompressedData[uncompressedIndex]); }); @@ -1094,7 +1094,7 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() { qDebug() << "Compressing voxel and sending data packet"; #endif - QtConcurrent::run([voxelXSize, voxelYSize, voxelZSize, entity] { + QThreadPool::globalInstance()->start([voxelXSize, voxelYSize, voxelZSize, entity] { auto polyVoxEntity = std::static_pointer_cast(entity); QByteArray uncompressedData = polyVoxEntity->volDataToArray(voxelXSize, voxelYSize, voxelZSize); @@ -1310,7 +1310,7 @@ void RenderablePolyVoxEntityItem::recomputeMesh() { auto entity = std::static_pointer_cast(getThisPointer()); - QtConcurrent::run([entity, voxelSurfaceStyle] { + QThreadPool::globalInstance()->start([entity, voxelSurfaceStyle] { graphics::MeshPointer mesh(std::make_shared()); // A mesh object to hold the result of surface extraction @@ -1409,7 +1409,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { mesh = _mesh; }); - QtConcurrent::run([entity, voxelSurfaceStyle, voxelVolumeSize, mesh] { + QThreadPool::globalInstance()->start([entity, voxelSurfaceStyle, voxelVolumeSize, mesh] { auto polyVoxEntity = std::static_pointer_cast(entity); QVector> pointCollection; AABox box; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 7d28a6399ad..04533a8b91f 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -372,6 +372,11 @@ void entities::TextPayload::render(RenderArgs* args) { if (textColor.a <= 0.0f) { return; } + // QT6TODO: temporary workaround, since I don't know this part of code and how fade works + bool fadingWorkaroundCheck = (!forward && ShapeKey(args->_itemShapeKey).isFaded()) && !args->_shapePipeline; + if (fadingWorkaroundCheck) { + return; + } bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 69b59e947b4..c69c334c015 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -33,6 +33,7 @@ #include "EntitiesRendererLogging.h" #include #include +#include using namespace render; using namespace render::entities; @@ -53,13 +54,13 @@ const float METERS_TO_INCHES = 39.3701f; // If a web-view hasn't been rendered for 30 seconds, de-allocate the framebuffer static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND; -static uint8_t YOUTUBE_MAX_FPS = 30; - // Don't allow more than 20 concurrent web views static std::atomic _currentWebCount(0); static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20; -static QTouchDevice _touchDevice; +// QT6TODO: Use one shared virtual pointing device, where do we put it though? +static std::shared_ptr _touchDevice; +static std::shared_ptr _mouseDevice; static uint8_t CUSTOM_PIPELINE_NUMBER; // transparent, forward, shadow, fade @@ -139,10 +140,24 @@ WebEntityRenderer::WebEntityRenderer(const EntityItemPointer& entity) : Parent(e static std::once_flag once; std::call_once(once, [&]{ CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(webPipelineFactory); - _touchDevice.setCapabilities(QTouchDevice::Position); - _touchDevice.setType(QTouchDevice::TouchScreen); - _touchDevice.setName("WebEntityRendererTouchDevice"); - _touchDevice.setMaximumTouchPoints(4); + _touchDevice = std::make_shared( + "WebEntityTouchDevice", + 1002, + QInputDevice::DeviceType::TouchScreen, // QT6TODO: test if touchscreen or stylus works better. + QPointingDevice::PointerType::AllPointerTypes, + QInputDevice::Capability::All, + 1, //maxPoints + 2 // buttonCount + ); + _mouseDevice = std::make_shared( + "WebEntityMouseDevice", + 1003, + QInputDevice::DeviceType::Mouse, + QPointingDevice::PointerType::Cursor, + QInputDevice::Capability::All, + 1, //maxPoints + 2 // buttonCount + ); }); _geometryId = DependencyManager::get()->allocateID(); @@ -266,7 +281,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene if (_webSurface) { if (_webSurface->getRootItem()) { - if (_contentType == ContentType::HtmlContent && _sourceURL != newSourceURL) { + if (_sourceURL != newSourceURL) { if (localSafeContext) { ::hifi::scripting::setLocalAccessSafeThread(true); } @@ -275,11 +290,9 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene _webSurface->getRootItem()->setProperty(USE_BACKGROUND_PROPERTY, _useBackground); _webSurface->getRootItem()->setProperty(USER_AGENT_PROPERTY, _userAgent); _webSurface->getSurfaceContext()->setContextProperty(GLOBAL_POSITION_PROPERTY, vec3toVariant(_contextPosition)); - _webSurface->setMaxFps((QUrl(newSourceURL).host().endsWith("youtube.com", Qt::CaseInsensitive)) ? YOUTUBE_MAX_FPS : _maxFPS); + _webSurface->setMaxFps(_maxFPS); ::hifi::scripting::setLocalAccessSafeThread(false); _sourceURL = newSourceURL; - } else if (_contentType != ContentType::HtmlContent) { - _sourceURL = newSourceURL; } { @@ -293,13 +306,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene { auto maxFPS = entity->getMaxFPS(); if (_maxFPS != maxFPS) { - // We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS. - // FIXME this doesn't handle redirects or shortened URLs, consider using a signaling method from the web entity - if (QUrl(_sourceURL).host().endsWith("youtube.com", Qt::CaseInsensitive)) { - _webSurface->setMaxFps(YOUTUBE_MAX_FPS); - } else { - _webSurface->setMaxFps(maxFPS); - } + _webSurface->setMaxFps(maxFPS); _maxFPS = maxFPS; } } @@ -473,7 +480,7 @@ void WebEntityRenderer::hoverEnterEntity(const PointerEvent& event) { if (_webSurface) { PointerEvent webEvent = event; webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); - _webSurface->hoverBeginEvent(webEvent, _touchDevice); + _webSurface->hoverBeginEvent(webEvent, *_touchDevice); } }); } @@ -493,7 +500,7 @@ void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { if (_webSurface) { PointerEvent webEvent = event; webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); - _webSurface->hoverEndEvent(webEvent, _touchDevice); + _webSurface->hoverEndEvent(webEvent, *_touchDevice); } }); } @@ -515,7 +522,7 @@ void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { void WebEntityRenderer::handlePointerEventAsTouch(const PointerEvent& event) { PointerEvent webEvent = event; webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); - _webSurface->handlePointerEvent(webEvent, _touchDevice); + _webSurface->handlePointerEvent(webEvent, *_touchDevice); } void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) { @@ -552,10 +559,17 @@ void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) { if (type == QEvent::Wheel) { const auto& scroll = event.getScroll() * POINTEREVENT_SCROLL_SENSITIVITY; - QWheelEvent wheelEvent(windowPoint, windowPoint, QPoint(), QPoint(scroll.x, scroll.y), buttons, event.getKeyboardModifiers(), Qt::ScrollPhase::NoScrollPhase, false); + QWheelEvent wheelEvent(windowPoint, windowPoint, QPoint(), QPoint(scroll.x, scroll.y), buttons, event.getKeyboardModifiers(), Qt::ScrollPhase::NoScrollPhase, false, Qt::MouseEventSynthesizedByApplication, _mouseDevice.get()); + wheelEvent.setTimestamp((ulong)QDateTime::currentMSecsSinceEpoch()); + QMutableEventPoint::setTimestamp(wheelEvent.point(0), wheelEvent.timestamp()); QCoreApplication::sendEvent(_webSurface->getWindow(), &wheelEvent); } else { - QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); + QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers(), _mouseDevice.get()); + //QMouseEvent mouseEvent(type, QPointF(), QPointF(), QPointF(), button, buttons, event.getKeyboardModifiers(), _mouseDevice.get()); + mouseEvent.setTimestamp((ulong)QDateTime::currentMSecsSinceEpoch()); + QMutableEventPoint::setTimestamp(mouseEvent.point(0), mouseEvent.timestamp()); + //QMutableEventPoint::setPosition(mouseEvent.point(0), windowPoint); + //QMutableEventPoint::setScenePosition(mouseEvent.point(0), windowPoint); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 61578acfdac..ad1dc017a34 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -536,7 +536,7 @@ void ZoneEntityRenderer::setAmbientURL(const QString& ambientUrl) { if (_ambientTextureURL.isEmpty()) { _pendingAmbientTexture = false; - _ambientTexture.clear(); + _ambientTexture.reset(); _ambientLight->setAmbientMap(nullptr); _ambientLight->setAmbientSpherePreset(gpu::SphericalHarmonics::BREEZEWAY); @@ -575,7 +575,7 @@ void ZoneEntityRenderer::setSkyboxURL(const QString& skyboxUrl) { if (_skyboxTextureURL.isEmpty()) { _pendingSkyboxTexture = false; - _skyboxTexture.clear(); + _skyboxTexture.reset(); editSkybox()->setCubemap(nullptr); } else { diff --git a/libraries/entities/src/EntityDynamicInterface.cpp b/libraries/entities/src/EntityDynamicInterface.cpp index c44c21d32ef..223e02c6388 100644 --- a/libraries/entities/src/EntityDynamicInterface.cpp +++ b/libraries/entities/src/EntityDynamicInterface.cpp @@ -217,7 +217,7 @@ glm::vec3 EntityDynamicInterface::extractVec3Argument(QString objectName, QVaria } QVariant resultV = arguments[argumentName]; - if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) { + if (resultV.typeId() != QMetaType::QVariantMap) { qCDebug(entities) << objectName << "argument" << argumentName << "must be a map"; ok = false; return glm::vec3(0.0f); @@ -266,7 +266,7 @@ glm::quat EntityDynamicInterface::extractQuatArgument(QString objectName, QVaria } QVariant resultV = arguments[argumentName]; - if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) { + if (resultV.typeId() != QMetaType::QVariantMap) { qCDebug(entities) << objectName << "argument" << argumentName << "must be a map, not" << resultV.typeName(); ok = false; return glm::quat(); diff --git a/libraries/entities/src/EntityItem.cpp.in b/libraries/entities/src/EntityItem.cpp.in index 93503843a2e..73b50f3beb0 100644 --- a/libraries/entities/src/EntityItem.cpp.in +++ b/libraries/entities/src/EntityItem.cpp.in @@ -1834,7 +1834,7 @@ QString EntityItem::actionsToDebugString() { const QUuid id = i.key(); EntityDynamicPointer action = _objectActions[id]; EntityDynamicType actionType = action->getType(); - result += QString("") + actionType + ":" + action->getID().toString() + " "; + result += QString("%1: %2 ").arg(actionType).arg(action->getID().toString()); i++; } return result; diff --git a/libraries/entities/src/EntityItemProperties.cpp.in b/libraries/entities/src/EntityItemProperties.cpp.in index 4af4207dfb0..84eb235f344 100644 --- a/libraries/entities/src/EntityItemProperties.cpp.in +++ b/libraries/entities/src/EntityItemProperties.cpp.in @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -469,7 +470,7 @@ QString EntityItemProperties::getCollisionMaskAsString() const { } void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { - QVector groups = maskString.splitRef(','); + auto groups = QStringRef(&maskString).split(','); uint16_t mask = 0x0000; for (auto groupName : groups) { mask |= getCollisionGroupAsBitMask(groupName); @@ -996,7 +997,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy int finalizedSize = packetData->getFinalizedSize(); if (finalizedSize <= buffer.size()) { - buffer.replace(0, finalizedSize, finalizedData, finalizedSize); + // QByteArray::replace allows both qsizetype and char* here, so force it to int + buffer.replace(static_cast(0), finalizedSize, finalizedData, finalizedSize); buffer.resize(finalizedSize); } else { qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer."; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 8b7447cd607..afc5c15d87f 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "Sampler.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -287,6 +288,7 @@ typedef QVector qVectorFloat; typedef QVector qVectorQUuid; typedef QVector qVectorQString; typedef QSet qSetQString; +inline QDebug &operator<<(QDebug& debug, const qSetQString& stringSet) { for (const auto &item: stringSet) { debug << item; } return debug; } inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 458b39db2eb..a7a2b8b63af 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -366,7 +366,7 @@ public slots: /// Deliberately not adding jsdoc, only used internally. // FIXME: Deprecate and remove from the API. Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, - bool collisionless, bool grabbable, const glm::vec3& position, const glm::vec3& gravity); + bool collisionless, bool grabbable, const glm::vec<3,float,glm::packed_highp>& position, const glm::vec<3,float,glm::packed_highp>& gravity); /*@jsdoc * Creates a clone of an entity. The clone has the same properties as the original except that: it has a modified @@ -732,7 +732,7 @@ public slots: * print("Closest entity: " + entityID); */ /// this function will not find any models in script engine contexts which don't have access to models - Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const; + Q_INVOKABLE QUuid findClosestEntity(const glm::vec<3,float,glm::packed_highp>& center, float radius) const; /*@jsdoc * Finds all domain and avatar entities that intersect a sphere. @@ -748,7 +748,7 @@ public slots: * print("Number of entities within 10m: " + entityIDs.length); */ /// this function will not find any models in script engine contexts which don't have access to models - Q_INVOKABLE QVector findEntities(const glm::vec3& center, float radius) const; + Q_INVOKABLE QVector findEntities(const glm::vec<3,float,glm::packed_highp>& center, float radius) const; /*@jsdoc * Finds all domain and avatar entities whose axis-aligned boxes intersect a search axis-aligned box. @@ -761,7 +761,7 @@ public slots: * could be found. */ /// this function will not find any models in script engine contexts which don't have access to models - Q_INVOKABLE QVector findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const; + Q_INVOKABLE QVector findEntitiesInBox(const glm::vec<3,float,glm::packed_highp>& corner, const glm::vec<3,float,glm::packed_highp>& dimensions) const; /*@jsdoc * Finds all domain and avatar entities whose axis-aligned boxes intersect a search frustum. @@ -795,7 +795,7 @@ public slots: * print("Number of Model entities within 10m: " + entityIDs.length); */ /// this function will not find any entities in script engine contexts which don't have access to entities - Q_INVOKABLE QVector findEntitiesByType(const QString entityType, const glm::vec3& center, float radius) const; + Q_INVOKABLE QVector findEntitiesByType(const QString entityType, const glm::vec<3,float,glm::packed_highp>& center, float radius) const; /*@jsdoc * Finds all domain and avatar entities with a particular name that intersect a sphere. @@ -813,7 +813,7 @@ public slots: * var entityIDs = Entities.findEntitiesByName("Light-Target", MyAvatar.position, 10, false); * print("Number of entities with the name Light-Target: " + entityIDs.length); */ - Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, + Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec<3,float,glm::packed_highp>& center, float radius, bool caseSensitiveSearch = false) const; /*@jsdoc @@ -832,7 +832,7 @@ public slots: * var entityIDs = Entities.findEntitiesByTags(["Light-Target"], MyAvatar.position, 10, false); * print("Number of entities with the tag Light-Target: " + entityIDs.length); */ - Q_INVOKABLE QVector findEntitiesByTags(const QVector entityTags, const glm::vec3& center, float radius, + Q_INVOKABLE QVector findEntitiesByTags(const QVector entityTags, const glm::vec<3,float,glm::packed_highp>& center, float radius, bool caseSensitiveSearch = false) const; /*@jsdoc @@ -1017,7 +1017,7 @@ public slots: * Entities.setVoxelSphere(polyVox, position, 0.9, 255); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setVoxelSphere(const QUuid& entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setVoxelSphere(const QUuid& entityID, const glm::vec<3,float,glm::packed_highp>& center, float radius, int value); /*@jsdoc * Sets the values of all voxels in a capsule-shaped portion of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. @@ -1041,7 +1041,7 @@ public slots: * Entities.setVoxelCapsule(polyVox, startPosition, endPosition, 0.5, 255); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setVoxelCapsule(const QUuid& entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value); + Q_INVOKABLE bool setVoxelCapsule(const QUuid& entityID, const glm::vec<3,float,glm::packed_highp>& start, const glm::vec<3,float,glm::packed_highp>& end, float radius, int value); /*@jsdoc * Sets the value of a particular voxel in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. @@ -1063,7 +1063,7 @@ public slots: * Entities.setVoxel(entity, { x: 0, y: 0, z: 0 }, 0); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setVoxel(const QUuid& entityID, const glm::vec3& position, int value); + Q_INVOKABLE bool setVoxel(const QUuid& entityID, const glm::vec<3,float,glm::packed_highp>& position, int value); /*@jsdoc * Sets the values of all voxels in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. @@ -1106,7 +1106,7 @@ public slots: * Entities.setVoxelsInCuboid(polyVox, cuboidPosition, cuboidSize, 0); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setVoxelsInCuboid(const QUuid& entityID, const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value); + Q_INVOKABLE bool setVoxelsInCuboid(const QUuid& entityID, const glm::vec<3,float,glm::packed_highp>& lowPosition, const glm::vec<3,float,glm::packed_highp>& cuboidSize, int value); /*@jsdoc * Converts voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity to world coordinates. Voxel @@ -1141,7 +1141,7 @@ public slots: * }); */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec<3,float,glm::packed_highp> voxelCoords); /*@jsdoc * Converts world coordinates to voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. Voxel @@ -1155,7 +1155,7 @@ public slots: * fractional and outside the entity's bounding box. */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec<3,float,glm::packed_highp> worldCoords); /*@jsdoc * Converts voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity to local coordinates. Local @@ -1179,7 +1179,7 @@ public slots: * print("Voxel dimensions: " + JSON.stringify(voxelDimensions)); */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec<3,float,glm::packed_highp> voxelCoords); /*@jsdoc * Converts local coordinates to voxel coordinates in a {@link Entities.EntityProperties-PolyVox|PolyVox} entity. Local @@ -1194,7 +1194,7 @@ public slots: * fractional and outside the entity's bounding box. */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> localCoordsToVoxelCoords(const QUuid& entityID, glm::vec<3,float,glm::packed_highp> localCoords); /*@jsdoc * Sets all the points in a {@link Entities.EntityProperties-Line|Line} entity. @@ -1230,7 +1230,7 @@ public slots: * ]); * }, 2000); */ - Q_INVOKABLE bool setAllPoints(const QUuid& entityID, const QVector& points); + Q_INVOKABLE bool setAllPoints(const QUuid& entityID, const QVector>& points); /*@jsdoc * Appends a point to a {@link Entities.EntityProperties-Line|Line} entity. @@ -1262,7 +1262,7 @@ public slots: * Entities.appendPoint(entity, { x: 1, y: 1, z: 0 }); * }, 50); // Wait for the entity to be created. */ - Q_INVOKABLE bool appendPoint(const QUuid& entityID, const glm::vec3& point); + Q_INVOKABLE bool appendPoint(const QUuid& entityID, const glm::vec<3,float,glm::packed_highp>& point); /*@jsdoc * Restart a {@link Entities.EntityProperties-Sound|Sound} entity, locally only. It must also be localOnly. @@ -1369,7 +1369,7 @@ public slots: * {@link Vec3(0)|Vec3.ZERO}. */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex); /*@jsdoc * Gets the index of the parent joint of a joint in a {@link Entities.EntityProperties-Model|Model} entity. @@ -1408,7 +1408,7 @@ public slots: * }, 2000); */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::qua getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex); /*@jsdoc * Sets the translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's @@ -1422,7 +1422,7 @@ public slots: * false. */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec3 translation); + Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec<3,float,glm::packed_highp> translation); /*@jsdoc * Sets the rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity relative to the entity's position @@ -1453,7 +1453,7 @@ public slots: * }, 2000); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::quat rotation); + Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::qua rotation); /*@jsdoc @@ -1465,7 +1465,7 @@ public slots: * entity, the entity is loaded, and the joint index is valid; otherwise {@link Vec3(0)|Vec3.ZERO}. */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::vec3 getLocalJointTranslation(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> getLocalJointTranslation(const QUuid& entityID, int jointIndex); /*@jsdoc * Gets the local rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity. @@ -1491,7 +1491,7 @@ public slots: * }, 2000); */ // FIXME move to a renderable entity interface - Q_INVOKABLE glm::quat getLocalJointRotation(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::qua getLocalJointRotation(const QUuid& entityID, int jointIndex); /*@jsdoc * Sets the local translation of a joint in a {@link Entities.EntityProperties-Model|Model} entity. @@ -1504,7 +1504,7 @@ public slots: * false. */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation); + Q_INVOKABLE bool setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec<3,float,glm::packed_highp> translation); /*@jsdoc * Sets the local rotation of a joint in a {@link Entities.EntityProperties-Model|Model} entity. @@ -1533,7 +1533,7 @@ public slots: * }, 2000); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation); + Q_INVOKABLE bool setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::qua rotation); /*@jsdoc @@ -1546,7 +1546,7 @@ public slots: * translations; otherwise false. */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setLocalJointTranslations(const QUuid& entityID, const QVector& translations); + Q_INVOKABLE bool setLocalJointTranslations(const QUuid& entityID, const QVector>& translations); /*@jsdoc * Sets the local rotations of joints in a {@link Entities.EntityProperties-Model|Model} entity. @@ -1588,7 +1588,7 @@ public slots: * }, 2000); */ // FIXME move to a renderable entity interface - Q_INVOKABLE bool setLocalJointRotations(const QUuid& entityID, const QVector& rotations); + Q_INVOKABLE bool setLocalJointRotations(const QUuid& entityID, const QVector>& rotations); /*@jsdoc * Sets the local rotations and translations of joints in a {@link Entities.EntityProperties-Model|Model} entity. This is @@ -1604,8 +1604,8 @@ public slots: */ // FIXME move to a renderable entity interface Q_INVOKABLE bool setLocalJointsData(const QUuid& entityID, - const QVector& rotations, - const QVector& translations); + const QVector>& rotations, + const QVector>& translations); /*@jsdoc @@ -1943,8 +1943,8 @@ public slots: * @param {number} radius - The radius of the capsule. * @returns {boolean} true if the AA box and capsule intersect, otherwise false. */ - Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, - const glm::vec3& start, const glm::vec3& end, float radius); + Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec<3,float,glm::packed_highp>& low, const glm::vec<3,float,glm::packed_highp>& dimensions, + const glm::vec<3,float,glm::packed_highp>& start, const glm::vec<3,float,glm::packed_highp>& end, float radius); /*@jsdoc * Gets the meshes in a {@link Entities.EntityProperties-Model|Model} or {@link Entities.EntityProperties-PolyVox|PolyVox} @@ -1994,7 +1994,7 @@ public slots: * print("Rotation: " + JSON.stringify(Mat4.extractRotation(transform))); // Same as orientation. * print("Scale: " + JSON.stringify(Mat4.extractScale(transform))); // { x: 1, y: 1, z: 1 } */ - Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID); + Q_INVOKABLE glm::mat<4,4,float,glm::packed_highp> getEntityTransform(const QUuid& entityID); /*@jsdoc * Gets the object to parent transform, excluding scale, of an entity. @@ -2029,7 +2029,7 @@ public slots: * print("Translation: " + JSON.stringify(Mat4.extractTranslation(transform))); // childTranslation * print("Rotation: " + JSON.stringify(Quat.safeEulerAngles(Mat4.extractRotation(transform)))); // childRotation * print("Scale: " + JSON.stringify(Mat4.extractScale(transform))); // { x: 1, y: 1, z: 1 } */ - Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID); + Q_INVOKABLE glm::mat<4,4,float,glm::packed_highp> getEntityLocalTransform(const QUuid& entityID); /*@jsdoc @@ -2066,7 +2066,7 @@ public slots: * localPosition = Entities.getEntityProperties(childEntity, "localPosition").localPosition; * print("Local position: " + JSON.stringify(localPosition)); // The same. */ - Q_INVOKABLE glm::vec3 worldToLocalPosition(glm::vec3 worldPosition, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToLocalPosition(glm::vec<3,float,glm::packed_highp> worldPosition, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a rotation or orientation in world coordinates to rotation in an avatar, entity, or joint's local coordinates. @@ -2078,7 +2078,7 @@ public slots: * @param {boolean} [scalesWithParent=false] - Not used in the calculation. * @returns {Quat} The rotation converted to local coordinates if successful, otherwise {@link Quat(0)|Quat.IDENTITY}. */ - Q_INVOKABLE glm::quat worldToLocalRotation(glm::quat worldRotation, const QUuid& parentID, + Q_INVOKABLE glm::qua worldToLocalRotation(glm::qua worldRotation, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a velocity in world coordinates to a velocity in an avatar, entity, or joint's local coordinates. @@ -2091,7 +2091,7 @@ public slots: * false for the local velocity to be at world scale. * @returns {Vec3} The velocity converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 worldToLocalVelocity(glm::vec3 worldVelocity, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToLocalVelocity(glm::vec<3,float,glm::packed_highp> worldVelocity, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a Euler angular velocity in world coordinates to an angular velocity in an avatar, entity, or joint's local @@ -2105,7 +2105,7 @@ public slots: * @param {boolean} [scalesWithParent=false] - Not used in the calculation. * @returns {Vec3} The angular velocity converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 worldToLocalAngularVelocity(glm::vec3 worldAngularVelocity, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToLocalAngularVelocity(glm::vec<3,float,glm::packed_highp> worldAngularVelocity, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts dimensions in world coordinates to dimensions in an avatar or entity's local coordinates. @@ -2117,7 +2117,7 @@ public slots: * false for the local dimensions to be at world scale. * @returns {Vec3} The dimensions converted to local coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 worldToLocalDimensions(glm::vec3 worldDimensions, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> worldToLocalDimensions(glm::vec<3,float,glm::packed_highp> worldDimensions, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a position in an avatar, entity, or joint's local coordinate to a position in world coordinates. @@ -2130,7 +2130,7 @@ public slots: * false if the local dimensions are at world scale. * @returns {Vec3} The position converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 localToWorldPosition(glm::vec3 localPosition, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> localToWorldPosition(glm::vec<3,float,glm::packed_highp> localPosition, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a rotation or orientation in an avatar, entity, or joint's local coordinate to a rotation in world coordinates. @@ -2142,7 +2142,7 @@ public slots: * @param {boolean} [scalesWithParent= false] - Not used in the calculation. * @returns {Quat} The rotation converted to local coordinates if successful, otherwise {@link Quat(0)|Quat.IDENTITY}. */ - Q_INVOKABLE glm::quat localToWorldRotation(glm::quat localRotation, const QUuid& parentID, + Q_INVOKABLE glm::qua localToWorldRotation(glm::qua localRotation, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a velocity in an avatar, entity, or joint's local coordinate to a velocity in world coordinates. @@ -2155,7 +2155,7 @@ public slots: * false if the local velocity is at world scale. * @returns {Vec3} The velocity converted to world coordinates it successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 localToWorldVelocity(glm::vec3 localVelocity, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> localToWorldVelocity(glm::vec<3,float,glm::packed_highp> localVelocity, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts a Euler angular velocity in an avatar, entity, or joint's local coordinate to an angular velocity in world @@ -2169,7 +2169,7 @@ public slots: * @param {boolean} [scalesWithParent= false] - Not used in the calculation. * @returns {Vec3} The angular velocity converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 localToWorldAngularVelocity(glm::vec3 localAngularVelocity, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> localToWorldAngularVelocity(glm::vec<3,float,glm::packed_highp> localAngularVelocity, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); /*@jsdoc * Converts dimensions in an avatar or entity's local coordinates to dimensions in world coordinates. @@ -2181,7 +2181,7 @@ public slots: * scale, false if the local dimensions are at world scale. * @returns {Vec3} The dimensions converted to world coordinates if successful, otherwise {@link Vec3(0)|Vec3.ZERO}. */ - Q_INVOKABLE glm::vec3 localToWorldDimensions(glm::vec3 localDimensions, const QUuid& parentID, + Q_INVOKABLE glm::vec<3,float,glm::packed_highp> localToWorldDimensions(glm::vec<3,float,glm::packed_highp> localDimensions, const QUuid& parentID, int parentJointIndex = -1, bool scalesWithParent = false); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 58a79a81265..c21941cee81 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -440,7 +440,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti properties.setParentJointIndexChanged(false); if (wantTerseEditLogging()) { - qCDebug(entities) << (senderNode ? senderNode->getUUID() : "null") << "physical edits suppressed"; + qCDebug(entities) << (senderNode ? senderNode->getUUID().toString() : "null") << "physical edits suppressed"; } } } @@ -615,7 +615,7 @@ void EntityTree::unhookChildAvatar(const EntityItemID entityID) { EntityItemPointer entity = findEntityByEntityItemID(entityID); entity->forEachDescendant([&](SpatiallyNestablePointer child) { if (child->getNestableType() == NestableType::Avatar) { - child->setParentID(nullptr); + child->setParentID(QUuid()); } }); } @@ -764,7 +764,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) } else { theEntity->forEachDescendant([&](SpatiallyNestablePointer child) { if (child->getNestableType() == NestableType::Avatar) { - child->setParentID(nullptr); + child->setParentID(QUuid()); } }); @@ -2400,7 +2400,7 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen QJsonValue replaceEntityIDsInJSONHelper(const QJsonValue& jsonValue, std::function getMapped) { if (jsonValue.isString()) { QString stringValue = jsonValue.toString(); - QUuid oldID = stringValue; + QUuid oldID(stringValue); if (!oldID.isNull()) { return QJsonValue(getMapped(oldID).toString()); } @@ -2525,11 +2525,11 @@ bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void } } - QUuid oldID = uuidString; + QUuid oldID(uuidString); if (!oldID.isNull()) { uuidString = getMapped(oldID).toString(); } - QUuid oldMaterialName = materialName; + QUuid oldMaterialName(materialName); if (!oldMaterialName.isNull()) { materialName = getMapped(oldMaterialName).toString(); } @@ -2543,7 +2543,7 @@ bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void QString imageURL = properties.getImageURL(); if (imageURL.startsWith("{")) { - QUuid oldID = imageURL; + QUuid oldID(imageURL); if (!oldID.isNull()) { properties.setImageURL(getMapped(oldID).toString()); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 99028adfb7a..a88e74a609b 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -40,7 +40,7 @@ class NewlyCreatedEntityHook { class SendEntitiesOperationArgs { public: - glm::vec3 root; + glm::vec<3,float,glm::packed_highp> root; QString entityHostType; EntityTree* ourTree; EntityTreePointer otherTree; diff --git a/libraries/entities/src/SoundEntityItem.cpp.in b/libraries/entities/src/SoundEntityItem.cpp.in index a308747bffe..841a2517e6e 100644 --- a/libraries/entities/src/SoundEntityItem.cpp.in +++ b/libraries/entities/src/SoundEntityItem.cpp.in @@ -119,7 +119,7 @@ void SoundEntityItem::update(const quint64& now) { if (_sound->isLoaded()) { updateSound(true); } else { - connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + connect(_sound.get(), &Resource::finished, this, [&] { updateSound(true); }); } } } @@ -163,7 +163,7 @@ void SoundEntityItem::setSoundURL(const QString& value) { if (_sound->isLoaded()) { updateSound(true); } else { - connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + connect(_sound.get(), &Resource::finished, this, [&] { updateSound(true); }); } } } @@ -334,7 +334,7 @@ void SoundEntityItem::setLocalOnly(bool value) { if (_sound->isLoaded()) { updateSound(true); } else { - connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + connect(_sound.get(), &Resource::finished, this, [&] { updateSound(true); }); } } } diff --git a/libraries/gl/CMakeLists.txt b/libraries/gl/CMakeLists.txt index 069420aaac8..eaad11c60b4 100644 --- a/libraries/gl/CMakeLists.txt +++ b/libraries/gl/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME gl) -setup_hifi_library(Gui Widgets) +setup_hifi_library(Gui Widgets OpenGL) link_hifi_libraries(shared) set(OpenGL_GL_PREFERENCE "GLVND") diff --git a/libraries/gl/src/gl/ContextQt.cpp b/libraries/gl/src/gl/ContextQt.cpp index a27ba30a2b5..795f4920bbb 100644 --- a/libraries/gl/src/gl/ContextQt.cpp +++ b/libraries/gl/src/gl/ContextQt.cpp @@ -6,7 +6,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Note, `gl::Context is split into two files because a single file cannot include both the GLAD headers +// Note, `gl::Context is split into two files because a single file cannot include both the GLAD headers // and the QOpenGLContext definition headers #include "Context.h" @@ -16,11 +16,7 @@ #include #include "QOpenGLContextWrapper.h" -#ifdef Q_OS_WIN -#include -#endif - -#include +#include #include "GLHelpers.h" diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 50d98d3fbf5..a6fe2c0a4ba 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include "Context.h" @@ -113,7 +113,7 @@ GLAPI PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; GLAPI PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; static bool setupPixelFormatSimple(HDC hdc) { - // FIXME build the PFD based on the + // FIXME build the PFD based on the static const PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor @@ -128,7 +128,7 @@ static bool setupPixelFormatSimple(HDC hdc) { 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored - 24, // 24 Bit Z-Buffer (Depth Buffer) + 24, // 24 Bit Z-Buffer (Depth Buffer) 8, // 8 Bit Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer @@ -188,9 +188,9 @@ uint16_t gl::getAvailableVersion() { major = 4; minor = 1; #elif defined(Q_OS_WIN) - // + // HINSTANCE hInstance = GetModuleHandle(nullptr); - const auto windowClassName = "OpenGLVersionCheck"; + const wchar_t windowClassName[] = L"OpenGLVersionCheck"; WNDCLASS wc = { }; wc.lpfnWndProc = DefWindowProc; wc.hInstance = hInstance; @@ -199,7 +199,7 @@ uint16_t gl::getAvailableVersion() { using Handle = std::shared_ptr; HWND rawHwnd = CreateWindowEx( - WS_EX_APPWINDOW, // extended style + WS_EX_APPWINDOW, // extended style windowClassName, // class name windowClassName, // title WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CS_OWNDC | WS_POPUP, // style @@ -242,7 +242,7 @@ uint16_t gl::getAvailableVersion() { return; } - // The only two versions we care about on Windows + // The only two versions we care about on Windows // are 4.5 and 4.1 if (GLAD_GL_VERSION_4_5) { major = 4; @@ -321,7 +321,7 @@ namespace gl { GLenum error = glGetError(); if (!error) { return false; - } + } switch (error) { case GL_INVALID_ENUM: qCWarning(glLogging) << "GLBackend" << name << ": An unacceptable value is specified for an enumerated argument.The offending command is ignored and has no other side effect than to set the error flag."; @@ -352,8 +352,8 @@ namespace gl { bool checkGLErrorDebug(const char* name) { - // Disabling error checking macro on Android debug builds for now, - // as it throws off performance testing, which must be done on + // Disabling error checking macro on Android debug builds for now, + // as it throws off performance testing, which must be done on // Debug builds #if defined(DEBUG) && !defined(Q_OS_ANDROID) return checkGLError(name); diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index 078737443c8..010e6c361af 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -63,7 +63,9 @@ void GLWidget::createContext(QOpenGLContext* shareContext) { _context = new gl::Context(); _context->setWindow(windowHandle()); _context->create(shareContext); - _context->makeCurrent(); + bool isCurrent = _context->makeCurrent(); + Q_ASSERT(isCurrent); + Q_UNUSED(isCurrent); _context->clear(); _context->doneCurrent(); } @@ -135,7 +137,7 @@ bool GLWidget::event(QEvent* event) { return QWidget::event(event); } -bool GLWidget::nativeEvent(const QByteArray &eventType, void *message, long *result) { +bool GLWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) { #ifdef Q_OS_WIN32 MSG* win32message = static_cast(message); switch (win32message->message) { diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index 0d8b23cd0af..1f907f60a7c 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -38,7 +38,7 @@ class GLWidget : public QWidget { virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const override; protected: - virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; + virtual bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override; virtual bool event(QEvent* event) override; gl::Context* _context { nullptr }; diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index c5b8baa6d44..4d05dbf9271 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include @@ -75,6 +75,10 @@ bool OffscreenGLCanvas::makeCurrent() { bool result = _context->makeCurrent(_offscreenSurface); if (result) { std::call_once(_reportOnce, [] { + // initialise glad before ContextInfo::init uses it, + // otherwise we crash on debug builds because glad + // has its own debug wrappers that need to be set up + gl::initModuleGl(); LOG_GL_CONTEXT_INFO(glLogging, gl::ContextInfo().init()); }); } diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 842c7abd089..e7b4473b2dc 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -13,26 +13,21 @@ #include -#ifdef Q_OS_WIN -#include -#endif - QOpenGLContextWrapper::Pointer QOpenGLContextWrapper::currentContextWrapper() { return std::make_shared(QOpenGLContext::currentContext()); } - QOpenGLContextWrapper::NativeContextPointer QOpenGLContextWrapper::getNativeContext() const { QOpenGLContextWrapper::NativeContextPointer result; - auto nativeHandle = _context->nativeHandle(); + // QT6TODO: + /*auto nativeHandle = _context->nativeHandle(); if (nativeHandle.canConvert()) { result = std::make_shared(); *result = nativeHandle.value(); - } + }*/ return result; } - uint32_t QOpenGLContextWrapper::currentContextVersion() { QOpenGLContext* context = QOpenGLContext::currentContext(); if (!context) { diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 3cf7b2a8142..1b87d38f819 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -77,7 +77,7 @@ class Buffer : public Resource { Buffer(uint32_t usage, Size size, const Byte* bytes, Size pageSize = PageManager::DEFAULT_PAGE_SIZE); Buffer(const Buffer& buf); // deep copy of the sysmem buffer Buffer& operator=(const Buffer& buf); // deep copy of the sysmem buffer - ~Buffer(); + virtual ~Buffer(); // The size in bytes of data stored in the buffer Size getSize() const override; diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index c731c404c91..955538ffdab 100644 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -230,6 +230,9 @@ Texture::Texture(TextureUsageType usageType) : } Texture::~Texture() { + Q_ASSERT(!wasDeleted); + wasDeleted = true; + _textureCPUCount.decrement(); if (_usageType == TextureUsageType::EXTERNAL) { Texture::ExternalUpdates externalUpdates; @@ -900,10 +903,16 @@ const gpu::TexturePointer TextureSource::getGPUTexture() const { _locked = false; return gpuTexture; } + if (_gpuTexture) { + Q_ASSERT(!_gpuTexture->wasDeleted); + } return _gpuTexture; } void TextureSource::resetTexture(const gpu::TexturePointer& texture) { + if (texture) { + Q_ASSERT(!texture->wasDeleted); + } _gpuTexture = texture; _gpuTextureOperator = nullptr; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index c22781da8cb..74a82c25d5b 100644 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -140,6 +140,7 @@ class Texture : public Resource { static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); public: + std::atomic wasDeleted{false}; static const uint32_t CUBE_FACE_COUNT { 6 }; static uint32_t getTextureCPUCount(); static Size getTextureCPUMemSize(); @@ -329,8 +330,11 @@ class Texture : public Resource { // After the texture has been created, it should be defined bool isDefined() const { return _defined; } - Texture(TextureUsageType usageType); - ~Texture(); + explicit Texture(TextureUsageType usageType); + // Textures can be only created through `create...` functions + Texture() = delete; + Texture(const Texture &texture) = delete; + virtual ~Texture(); Stamp getStamp() const { return _stamp; } Stamp getDataStamp() const { return _storage->getStamp(); } @@ -605,8 +609,10 @@ class TextureView { TextureView(Texture* newTexture, const Element& element) : _texture(newTexture), _subresource(0), - _element(element) - {}; + _element(element) { + // TODO: this can cause double delete when it's used with a pointer that is already assigned to another shared_ptr. + Q_ASSERT(false); + }; TextureView(const TexturePointer& texture, uint16 subresource, const Element& element) : _texture(texture), _subresource(subresource), @@ -659,7 +665,7 @@ class TextureSource { protected: gpu::TexturePointer _gpuTexture; std::function _gpuTextureOperator { nullptr }; - mutable bool _locked { false }; + mutable std::atomic _locked { false }; QUrl _imageUrl; int _type { 0 }; }; diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index 24486dcd614..b839b1f1606 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -265,7 +265,7 @@ scriptable::ScriptableMeshPointer GraphicsScriptingInterface::newMesh(const QVar if (texCoords0.size()) { mesh->addAttribute(gpu::Stream::TEXCOORD0, buffer_helpers::newFromVector(gpu::Buffer::VertexBuffer, texCoords0, gpu::Format::VEC2F_UV)); } - QVector parts = {{ 0, indices.size(), 0, topology }}; + QVector parts = {graphics::Mesh::Part(0, indices.size(), 0, topology)}; mesh->setPartBuffer(buffer_helpers::newFromVector(gpu::Buffer::IndirectBuffer, parts, gpu::Element::PART_DRAWCALL)); return scriptable::make_scriptowned(mesh, nullptr); } diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h index 2412a17d1ac..6e452c91589 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h @@ -154,6 +154,7 @@ namespace scriptable { ScriptValue scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material); }; -Q_DECLARE_METATYPE(NestableType) +// QT6TODO +//Q_DECLARE_METATYPE(NestableType) #endif // hifi_GraphicsScriptingInterface_h diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp index 632303ebc7b..1e00f424ba8 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.cpp @@ -27,7 +27,7 @@ QVariant toVariant(const glm::mat4& mat4) { floats.resize(16); memcpy(floats.data(), &mat4, sizeof(glm::mat4)); QVariant v; - v.setValue>(floats); + v.setValue>(std::move(floats)); return v; }; diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h index 922e7b79738..fe96341cd50 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h @@ -133,7 +133,7 @@ namespace scriptable { * origin it is considered to be "nearby". * @returns {number[]} The indices of nearby vertices. */ - QVector findNearbyVertexIndices(const glm::vec3& origin, float epsilon = 1e-6) const; + QVector findNearbyVertexIndices(const glm::vec<3,float,glm::packed_highp>& origin, float epsilon = 1e-6) const; /*@jsdoc * Adds an attribute for all vertices. diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h index cb06b397107..3ff28c3d222 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h @@ -112,7 +112,7 @@ namespace scriptable { * origin it is considered to be "nearby". * @returns {number[]} The indices of nearby vertices. */ - QVector findNearbyPartVertexIndices(const glm::vec3& origin, float epsilon = 1e-6) const; + QVector findNearbyPartVertexIndices(const glm::vec<3,float,glm::packed_highp>& origin, float epsilon = 1e-6) const; /*@jsdoc * Gets the value of an attribute for all vertices in the whole mesh (i.e., parent and mesh parts). @@ -174,7 +174,7 @@ namespace scriptable { * @param {Vec3} translation - The translation to apply, in model coordinates. * @returns {Graphics.MeshExtents} The rseulting mesh extents, in model coordinates. */ - QVariantMap translate(const glm::vec3& translation); + QVariantMap translate(const glm::vec<3,float,glm::packed_highp>& translation); /*@jsdoc * Scales the mesh part. @@ -183,7 +183,7 @@ namespace scriptable { * @param {Vec3} [origin] - The origin to scale about. If not specified, the center of the mesh part is used. * @returns {Graphics.MeshExtents} The resulting mesh extents, in model coordinates. */ - QVariantMap scale(const glm::vec3& scale, const glm::vec3& origin = glm::vec3(NAN)); + QVariantMap scale(const glm::vec<3,float,glm::packed_highp>& scale, const glm::vec<3,float,glm::packed_highp>& origin = glm::vec<3,float,glm::packed_highp>(NAN)); /*@jsdoc * Rotates the mesh part, using Euler angles. @@ -193,7 +193,7 @@ namespace scriptable { *

Warning: Currently doesn't work as expected.

* @returns {Graphics.MeshExtents} The resulting mesh extents, in model coordinates. */ - QVariantMap rotateDegrees(const glm::vec3& eulerAngles, const glm::vec3& origin = glm::vec3(NAN)); + QVariantMap rotateDegrees(const glm::vec<3,float,glm::packed_highp>& eulerAngles, const glm::vec<3,float,glm::packed_highp>& origin = glm::vec<3,float,glm::packed_highp>(NAN)); /*@jsdoc * Rotates the mesh part, using a quaternion. @@ -203,7 +203,7 @@ namespace scriptable { *

Warning: Currently doesn't work as expected.

* @returns {Graphics.MeshExtents} The resulting mesh extents, in model coordinates. */ - QVariantMap rotate(const glm::quat& rotation, const glm::vec3& origin = glm::vec3(NAN)); + QVariantMap rotate(const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& origin = glm::vec<3,float,glm::packed_highp>(NAN)); /*@jsdoc * Scales, rotates, and translates the mesh. @@ -211,7 +211,7 @@ namespace scriptable { * @param {Mat4} transform - The scale, rotate, and translate transform to apply. * @returns {Graphics.MeshExtents} The resulting mesh extents, in model coordinates. */ - QVariantMap transform(const glm::mat4& transform); + QVariantMap transform(const glm::mat<4,4,float,glm::packed_highp>& transform); // @borrows jsdoc from GraphicsMesh. glm::uint32 addAttribute(const QString& attributeName, const QVariant& defaultValue = QVariant()); @@ -339,5 +339,6 @@ namespace scriptable { }; } -Q_DECLARE_METATYPE(scriptable::ScriptableMeshPartPointer) -Q_DECLARE_METATYPE(QVector) +// QT6TODO: +//Q_DECLARE_METATYPE(scriptable::ScriptableMeshPartPointer) +//Q_DECLARE_METATYPE(QVector) diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp index 9f96f776ef7..1a3de45c5fd 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -179,7 +179,8 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint parametricRimFresnelPower = material->getParametricRimFresnelPower(); parametricRimLift = material->getParametricRimLift(); rimLightingMix = material->getRimLightingMix(); - outlineWidthMode = material->getOutlineWidthMode(); + // QT6TODO: something is wrong there, isn't outlineWidthMode supposed to be a string like "worldCoordinates" or "screenCoordinates" + outlineWidthMode = QString::number(material->getOutlineWidthMode()); outlineWidth = material->getOutlineWidth(); outline = material->getOutline(); uvAnimationScrollXSpeed = material->getUVAnimationScrollXSpeed(); diff --git a/libraries/graphics/src/graphics/BufferViewHelpers.h b/libraries/graphics/src/graphics/BufferViewHelpers.h index 1a130672558..74738cff260 100644 --- a/libraries/graphics/src/graphics/BufferViewHelpers.h +++ b/libraries/graphics/src/graphics/BufferViewHelpers.h @@ -47,7 +47,7 @@ namespace buffer_helpers { template const T glmVecFromVariant(const QVariant& v) { - auto isMap = v.type() == (QVariant::Type)QMetaType::QVariantMap; + auto isMap = v.typeId() == QMetaType::QVariantMap; static const auto len = T().length(); const auto& components = isMap ? XYZW : ZERO123; T result; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 6f5b60a703d..6d9113625e1 100644 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -246,22 +246,25 @@ bool Material::resetOpacityMap() const { _key.setOpacityMaskMap(false); _key.setTranslucentMap(false); - const auto& textureMap = getTextureMap(MaterialKey::ALBEDO_MAP); - if (textureMap && - textureMap->useAlphaChannel() && - textureMap->isDefined() && - textureMap->getTextureView().isValid()) { - - auto usage = textureMap->getTextureView()._texture->getUsage(); - if (usage.isAlpha()) { - if (usage.isAlphaMask()) { - // Texture has alpha, but it is just a mask - _key.setOpacityMaskMap(true); - _key.setTranslucentMap(false); - } else { - // Texture has alpha, it is a true translucency channel - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(true); + const auto textureMap = getTextureMap(MaterialKey::ALBEDO_MAP); + if (textureMap) { + auto textureView = textureMap->getTextureView(); + if (textureView && + textureMap->useAlphaChannel() && + textureMap->isDefined() && + textureView.isValid()) { + + auto usage = textureView._texture->getUsage(); + if (usage.isAlpha()) { + if (usage.isAlphaMask()) { + // Texture has alpha, but it is just a mask + _key.setOpacityMaskMap(true); + _key.setTranslucentMap(false); + } else { + // Texture has alpha, it is a true translucency channel + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(true); + } } } } diff --git a/libraries/hfm/src/hfm/HFMSerializer.h b/libraries/hfm/src/hfm/HFMSerializer.h index d0be588d602..c99d021977e 100644 --- a/libraries/hfm/src/hfm/HFMSerializer.h +++ b/libraries/hfm/src/hfm/HFMSerializer.h @@ -37,7 +37,7 @@ class Serializer { virtual MediaType getMediaType() const = 0; virtual std::unique_ptr getFactory() const = 0; - virtual Model::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) = 0; + virtual Model::Pointer read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url = hifi::URL()) = 0; }; }; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index b6513340a30..e2f29f79d4d 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -204,7 +204,7 @@ glm::vec2 evalAverageTouchPoints(const QList& points) { glm::vec2 averagePoint(0.0f); if (points.count() > 0) { for (auto& point : points) { - averagePoint += glm::vec2(point.pos().x(), point.pos().y()); + averagePoint += glm::vec2(point.position().x(), point.position().y()); } averagePoint /= (float)(points.count()); } @@ -244,8 +244,8 @@ void KeyboardMouseDevice::touchGestureEvent(const QGestureEvent* event) { void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { if (_enableTouch) { - _isTouching = event->touchPointStates().testFlag(Qt::TouchPointPressed); - _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _isTouching = event->touchPointStates().testFlag(QEventPoint::State::Pressed); + _lastTouch = evalAverageTouchPoints(event->points()); _lastTouchTime = _clock.now(); } } @@ -253,14 +253,14 @@ void KeyboardMouseDevice::touchBeginEvent(const QTouchEvent* event) { void KeyboardMouseDevice::touchEndEvent(const QTouchEvent* event) { if (_enableTouch) { _isTouching = false; - _lastTouch = evalAverageTouchPoints(event->touchPoints()); + _lastTouch = evalAverageTouchPoints(event->points()); _lastTouchTime = _clock.now(); } } void KeyboardMouseDevice::touchUpdateEvent(const QTouchEvent* event) { if (_enableTouch) { - auto currentPos = evalAverageTouchPoints(event->touchPoints()); + auto currentPos = evalAverageTouchPoints(event->points()); _lastTouchTime = _clock.now(); if (!_isTouching) { diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.cpp index 807d7f0ef92..29ca9520fbc 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.cpp @@ -24,8 +24,8 @@ const char* TouchscreenDevice::NAME = "Touchscreen"; bool TouchscreenDevice::isSupported() const { - for (auto touchDevice : QTouchDevice::devices()) { - if (touchDevice->type() == QTouchDevice::TouchScreen) { + for (auto touchDevice : QInputDevice::devices()) { + if (touchDevice->type() == QInputDevice::DeviceType::TouchScreen) { return true; } } @@ -73,15 +73,17 @@ void TouchscreenDevice::InputDevice::focusOutEvent() { } void TouchscreenDevice::touchBeginEvent(const QTouchEvent* event) { - const QTouchEvent::TouchPoint& point = event->touchPoints().at(0); - _firstTouchVec = glm::vec2(point.pos().x(), point.pos().y()); + const QTouchEvent::TouchPoint& point = event->points().at(0); + _firstTouchVec = glm::vec2(point.position().x(), point.position().y()); KeyboardMouseDevice::enableTouch(false); - QScreen* eventScreen = event->window()->screen(); + // QT6TODO: I'm not sure how to do this part yet + /*QScreen* eventScreen = event->window()->screen(); + QScreen* eventScreen = event->tagret()window()->screen(); if (_screenDPI != eventScreen->physicalDotsPerInch()) { _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); _screenDPI = eventScreen->physicalDotsPerInch(); - } + }*/ } void TouchscreenDevice::touchEndEvent(const QTouchEvent* event) { @@ -90,14 +92,15 @@ void TouchscreenDevice::touchEndEvent(const QTouchEvent* event) { } void TouchscreenDevice::touchUpdateEvent(const QTouchEvent* event) { - const QTouchEvent::TouchPoint& point = event->touchPoints().at(0); - _currentTouchVec = glm::vec2(point.pos().x(), point.pos().y()); - _touchPointCount = event->touchPoints().count(); + const QTouchEvent::TouchPoint& point = event->points().at(0); + _currentTouchVec = glm::vec2(point.position().x(), point.position().y()); + _touchPointCount = static_cast(event->points().count()); } void TouchscreenDevice::touchGestureEvent(const QGestureEvent* event) { if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { - QPinchGesture* pinch = static_cast(gesture); + QPinchGesture* pinch = dynamic_cast(gesture); + Q_ASSERT(pinch); _pinchScale = pinch->totalScaleFactor(); } } diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h index c0cca200d75..eb024247707 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenDevice.h @@ -14,7 +14,6 @@ #include #include "InputPlugin.h" -#include class QTouchEvent; class QGestureEvent; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp index 6ba2d0eeea0..12069042458 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -27,8 +27,8 @@ const char* TouchscreenVirtualPadDevice::NAME = "TouchscreenVirtualPad"; bool TouchscreenVirtualPadDevice::isSupported() const { - for (auto touchDevice : QTouchDevice::devices()) { - if (touchDevice->type() == QTouchDevice::TouchScreen) { + for (const auto &touchDevice : QInputDevice::devices()) { + if (touchDevice->type() == QInputDevice::DeviceType::TouchScreen) { return true; } } @@ -211,14 +211,15 @@ void TouchscreenVirtualPadDevice::InputDevice::focusOutEvent() { void TouchscreenVirtualPadDevice::debugPoints(const QTouchEvent* event, QString who) { // convert the touch points into an average - const QList& tPoints = event->touchPoints(); + const QList& tPoints = event->points(); QVector points; int touchPoints = tPoints.count(); for (int i = 0; i < touchPoints; ++i) { - glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + glm::vec2 thisPoint(tPoints[i].position().x(), tPoints[i].position().y()); points << thisPoint; } - QScreen* eventScreen = event->window()->screen(); + // QT6TODO: I have no idea how to do this part yet + /*QScreen* eventScreen = event->window()->screen(); int midScreenX = eventScreen->availableSize().width()/2; int lefties = 0; int righties = 0; @@ -230,7 +231,7 @@ void TouchscreenVirtualPadDevice::debugPoints(const QTouchEvent* event, QString } else { righties++; } - } + }*/ } void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { @@ -287,9 +288,9 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { viewTouchEnd(); return; } - _touchPointCount = event->touchPoints().count(); + _touchPointCount = static_cast(event->points().count()); - const QList& tPoints = event->touchPoints(); + const QList& tPoints = event->points(); bool moveTouchFound = false; bool viewTouchFound = false; @@ -303,8 +304,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { std::map unusedTouchesInEvent; for (int i = 0; i < _touchPointCount; ++i) { - thisPoint.x = tPoints[i].pos().x(); - thisPoint.y = tPoints[i].pos().y(); + thisPoint.x = tPoints[i].position().x(); + thisPoint.y = tPoints[i].position().y(); thisPointId = tPoints[i].id(); if (!moveTouchFound && _moveHasValidTouch && _moveCurrentTouchId == thisPointId) { @@ -357,8 +358,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { if (idxMoveStartingPointCandidate != -1) { _moveCurrentTouchId = tPoints[idxMoveStartingPointCandidate].id(); _unusedTouches.erase(_moveCurrentTouchId); - thisPoint.x = tPoints[idxMoveStartingPointCandidate].pos().x(); - thisPoint.y = tPoints[idxMoveStartingPointCandidate].pos().y(); + thisPoint.x = tPoints[idxMoveStartingPointCandidate].position().x(); + thisPoint.y = tPoints[idxMoveStartingPointCandidate].position().y(); moveTouchBegin(thisPoint); } else { moveTouchEnd(); @@ -368,8 +369,8 @@ void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { if (idxViewStartingPointCandidate != -1) { _viewCurrentTouchId = tPoints[idxViewStartingPointCandidate].id(); _unusedTouches.erase(_viewCurrentTouchId); - thisPoint.x = tPoints[idxViewStartingPointCandidate].pos().x(); - thisPoint.y = tPoints[idxViewStartingPointCandidate].pos().y(); + thisPoint.x = tPoints[idxViewStartingPointCandidate].position().x(); + thisPoint.y = tPoints[idxViewStartingPointCandidate].position().y(); viewTouchBegin(thisPoint); } else { viewTouchEnd(); @@ -592,8 +593,8 @@ void TouchscreenVirtualPadDevice::TouchscreenButtonsManager::processBeginOrEnd( if (button._candidatePointIdx != -1) { button.currentTouchId = tPoints[button._candidatePointIdx].id(); globalUnusedTouches.erase(button.currentTouchId); - thisPoint.x = tPoints[button._candidatePointIdx].pos().x(); - thisPoint.y = tPoints[button._candidatePointIdx].pos().y(); + thisPoint.x = tPoints[button._candidatePointIdx].position().x(); + thisPoint.y = tPoints[button._candidatePointIdx].position().y(); button.touchBegin(thisPoint); } else { if (button.hasValidTouch) { diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h index 1fa46f8a247..29c09af0372 100644 --- a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -14,7 +14,6 @@ #include #include "InputPlugin.h" -#include #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) #include #else diff --git a/libraries/material-networking/src/material-networking/ShaderCache.cpp b/libraries/material-networking/src/material-networking/ShaderCache.cpp index 0b87b74ae3c..24ceb14af34 100644 --- a/libraries/material-networking/src/material-networking/ShaderCache.cpp +++ b/libraries/material-networking/src/material-networking/ShaderCache.cpp @@ -21,13 +21,17 @@ ShaderCache& ShaderCache::instance() { } NetworkShaderPointer ShaderCache::getShader(const QUrl& url) { - return ResourceCache::getResource(url).staticCast(); + auto shader = std::dynamic_pointer_cast(ResourceCache::getResource(url)); + Q_ASSERT(shader); + return shader; } -QSharedPointer ShaderCache::createResource(const QUrl& url) { - return QSharedPointer(new NetworkShader(url), &Resource::deleter); +std::shared_ptr ShaderCache::createResource(const QUrl& url) { + return std::shared_ptr(new NetworkShader(url), Resource::sharedPtrDeleter); } -QSharedPointer ShaderCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkShader(*resource.staticCast()), &Resource::deleter); +std::shared_ptr ShaderCache::createResourceCopy(const std::shared_ptr& resource) { + auto shader = std::dynamic_pointer_cast(resource); + Q_ASSERT(shader); + return std::shared_ptr(new NetworkShader(*shader), Resource::sharedPtrDeleter); } diff --git a/libraries/material-networking/src/material-networking/ShaderCache.h b/libraries/material-networking/src/material-networking/ShaderCache.h index 5129a7d8b40..a4bbaa2d31e 100644 --- a/libraries/material-networking/src/material-networking/ShaderCache.h +++ b/libraries/material-networking/src/material-networking/ShaderCache.h @@ -16,6 +16,7 @@ class NetworkShader : public Resource { public: NetworkShader(const QUrl& url); NetworkShader(const NetworkShader& other) : Resource(other), _source(other._source) {} + virtual ~NetworkShader() {} QString getType() const override { return "NetworkShader"; } @@ -24,7 +25,7 @@ class NetworkShader : public Resource { QString _source; }; -using NetworkShaderPointer = QSharedPointer; +using NetworkShaderPointer = std::shared_ptr; class ShaderCache : public ResourceCache { public: @@ -33,8 +34,8 @@ class ShaderCache : public ResourceCache { NetworkShaderPointer getShader(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; }; #endif diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index e2d48225431..719f67db1b0 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -281,7 +281,10 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUs modifiedUrl.setQuery(query.toString()); } TextureExtra extra = { type, content, maxNumPixels, sourceChannel }; - return ResourceCache::getResource(modifiedUrl, QUrl(), &extra, std::hash()(extra)).staticCast(); + + auto texture = std::dynamic_pointer_cast(ResourceCache::getResource(modifiedUrl, QUrl(), &extra, std::hash()(extra))); + Q_ASSERT(texture); + return texture; } std::pair TextureCache::getTextureByHash(const std::string& hash) { @@ -377,15 +380,17 @@ gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::Te return gpu::TexturePointer(loader(std::move(image), path.toStdString(), shouldCompress, target, false)); } -QSharedPointer TextureCache::createResource(const QUrl& url) { - return QSharedPointer(new NetworkTexture(url), &Resource::deleter); +std::shared_ptr TextureCache::createResource(const QUrl& url) { + return std::shared_ptr(new NetworkTexture(url), Resource::sharedPtrDeleter); } -QSharedPointer TextureCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkTexture(*resource.staticCast()), &Resource::deleter); +std::shared_ptr TextureCache::createResourceCopy(const std::shared_ptr& resource) { + auto texture = std::dynamic_pointer_cast(resource); + Q_ASSERT(texture); + return std::shared_ptr(new NetworkTexture(*texture), Resource::sharedPtrDeleter); } -int networkTexturePointerMetaTypeId = qRegisterMetaType>(); +int networkTexturePointerMetaTypeId = qRegisterMetaType>(); NetworkTexture::NetworkTexture(const QUrl& url, bool resourceTexture) : Resource(url), @@ -479,6 +484,8 @@ void NetworkTexture::setExtra(void* extra) { void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight) { + auto self = weak_from_this().lock(); + // Passing ownership _textureSource->resetTexture(texture); @@ -487,19 +494,42 @@ void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth, _width = texture->getWidth(); _height = texture->getHeight(); setSize(texture->getStoredSize()); - finishedLoading(true); + if (!_isScheduledForDeletion) { + finishedLoading(true); + } } else { _width = _height = 0; - finishedLoading(false); + if (!_isScheduledForDeletion) { + finishedLoading(false); + } + } + + if (_isScheduledForDeletion) { + return; + } + + if (!self) { + // We need to make sure that texture was just added to unused pool and wasn't deleted yet. +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + Q_ASSERT(!_wasDeleted); +#endif + return; + //TODO: what to do when texture pointer has expired? } - emit networkTextureCreated(qWeakPointerCast (_self)); + auto thisTexture = std::dynamic_pointer_cast(self); + Q_ASSERT(thisTexture); + emit networkTextureCreated(thisTexture); } void NetworkTexture::setImageOperator(std::function textureOperator) { _textureSource->resetTextureOperator(textureOperator); - finishedLoading((bool)textureOperator); - emit networkTextureCreated(qWeakPointerCast (_self)); + if (!_isScheduledForDeletion) { + finishedLoading((bool)textureOperator); + auto thisTexture = std::dynamic_pointer_cast(shared_from_this()); + Q_ASSERT(thisTexture); + emit networkTextureCreated(thisTexture); + } } gpu::TexturePointer NetworkTexture::getFallbackTexture() const { @@ -508,7 +538,7 @@ gpu::TexturePointer NetworkTexture::getFallbackTexture() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& resource, const QUrl& url, + ImageReader(const std::weak_ptr& resource, const QUrl& url, const QByteArray& data, size_t extraHash, int maxNumPixels, image::ColorChannel sourceChannel); void run() override final; @@ -517,7 +547,7 @@ class ImageReader : public QRunnable { private: static void listSupportedImageFormats(); - QWeakPointer _resource; + std::weak_ptr _resource; QUrl _url; QByteArray _content; size_t _extraHash; @@ -537,26 +567,34 @@ NetworkTexture::~NetworkTexture() { _ktxMipRequest->deleteLater(); _ktxMipRequest = nullptr; } - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); } } const uint16_t NetworkTexture::NULL_MIP_LEVEL = std::numeric_limits::max(); void NetworkTexture::makeRequest() { + // Prevent the texture from being scheduled from deletion while the request is being made + auto selfLocked = weak_from_this().lock(); + if (!selfLocked) { + qWarning() << "NetworkTexture::makeRequest: resource pointer has expired."; + Q_ASSERT(false); + return; + } + if (_currentlyLoadingResourceType != ResourceType::KTX) { Resource::makeRequest(); return; } if (isLocalUrl(_activeUrl)) { - auto self = _self; - QtConcurrent::run(QThreadPool::globalInstance(), [self] { + std::weak_ptr self = weak_from_this(); + QThreadPool::globalInstance()->start([self] { auto resource = self.lock(); if (!resource) { return; } - NetworkTexture* networkTexture = static_cast(resource.data()); + NetworkTexture* networkTexture = static_cast(resource.get()); networkTexture->makeLocalRequest(); }); return; @@ -612,7 +650,7 @@ void NetworkTexture::makeRequest() { } void NetworkTexture::handleLocalRequestCompleted() { - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); } void NetworkTexture::makeLocalRequest() { @@ -669,7 +707,9 @@ void NetworkTexture::makeLocalRequest() { if (!textureAndSize.first) { qCDebug(networking).noquote() << "Failed load local KTX from" << path; - QMetaObject::invokeMethod(this, "setImage", + auto self = weak_from_this().lock(); + Q_ASSERT(self); + QMetaObject::invokeMethod(self.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -678,7 +718,9 @@ void NetworkTexture::makeLocalRequest() { _ktxResourceState = PENDING_MIP_REQUEST; _lowestKnownPopulatedMip = textureAndSize.first->minAvailableMipLevel(); - QMetaObject::invokeMethod(this, "setImage", + auto self = weak_from_this().lock(); + Q_ASSERT(self); + QMetaObject::invokeMethod(self.get(), "setImage", Q_ARG(gpu::TexturePointer, textureAndSize.first), Q_ARG(int, textureAndSize.second.x), Q_ARG(int, textureAndSize.second.y)); @@ -700,7 +742,7 @@ bool NetworkTexture::handleFailedRequest(ResourceRequest::Result result) { } void NetworkTexture::startRequestForNextMipLevel() { - auto self = _self.lock(); + auto self = shared_from_this(); if (!self) { return; } @@ -783,7 +825,7 @@ void NetworkTexture::ktxInitialDataRequestFinished() { setSize(_bytesTotal); - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); auto result = _ktxHeaderRequest->getResult(); if (result == ResourceRequest::Success) { @@ -832,7 +874,7 @@ void NetworkTexture::ktxMipRequestFinished() { return; } - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); auto result = _ktxMipRequest->getResult(); if (result == ResourceRequest::Success) { @@ -843,13 +885,13 @@ void NetworkTexture::ktxMipRequestFinished() { _ktxResourceState = WAITING_FOR_MIP_REQUEST; - auto self = _self; + auto self = weak_from_this(); auto url = _url; auto data = _ktxMipRequest->getData(); auto mipLevel = _ktxMipLevelRangeInFlight.first; auto texture = _textureSource->getGPUTexture(); DependencyManager::get()->incrementStat("PendingProcessing"); - QtConcurrent::run(QThreadPool::globalInstance(), [self, data, mipLevel, url, texture] { + QThreadPool::globalInstance()->start([self, data, mipLevel, url, texture] { PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", url.toString() } }); DependencyManager::get()->decrementStat("PendingProcessing"); CounterStat counter("Processing"); @@ -877,12 +919,12 @@ void NetworkTexture::ktxMipRequestFinished() { return; } - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, texture), Q_ARG(int, texture->getWidth()), Q_ARG(int, texture->getHeight())); - QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel"); + QMetaObject::invokeMethod(resource.get(), "startRequestForNextMipLevel"); }); } else { qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState; @@ -914,10 +956,10 @@ void NetworkTexture::handleFinishedInitialLoad() { _ktxResourceState = WAITING_FOR_MIP_REQUEST; - auto self = _self; + auto self = weak_from_this(); auto url = _url; DependencyManager::get()->incrementStat("PendingProcessing"); - QtConcurrent::run(QThreadPool::globalInstance(), [self, ktxHeaderData, ktxHighMipData, url] { + QThreadPool::globalInstance()->start([self, ktxHeaderData, ktxHighMipData, url] { PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", url.toString() } }); DependencyManager::get()->decrementStat("PendingProcessing"); CounterStat counter("Processing"); @@ -938,7 +980,7 @@ void NetworkTexture::handleFinishedInitialLoad() { auto header = reinterpret_cast(ktxHeaderData.data()); if (!ktx::checkIdentifier(header->identifier)) { - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -947,7 +989,7 @@ void NetworkTexture::handleFinishedInitialLoad() { auto kvSize = header->bytesOfKeyValueData; if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -958,14 +1000,14 @@ void NetworkTexture::handleFinishedInitialLoad() { auto imageDescriptors = header->generateImageDescriptors(); if (imageDescriptors.size() == 0) { - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); return; } auto originalKtxDescriptor = new ktx::KTXDescriptor(*header, keyValues, imageDescriptors); - QMetaObject::invokeMethod(resource.data(), "setOriginalDescriptor", + QMetaObject::invokeMethod(resource.get(), "setOriginalDescriptor", Q_ARG(ktx::KTXDescriptor*, originalKtxDescriptor)); // Create bare ktx in memory @@ -976,7 +1018,7 @@ void NetworkTexture::handleFinishedInitialLoad() { std::string hash; if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { qWarning("Invalid source hash key found, bailing"); - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -1009,7 +1051,7 @@ void NetworkTexture::handleFinishedInitialLoad() { auto memKtx = ktx::KTX::createBare(*header, keyValues); if (!memKtx) { qWarning() << " Ktx could not be created, bailing"; - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -1023,7 +1065,7 @@ void NetworkTexture::handleFinishedInitialLoad() { auto& ktxCache = textureCache->_ktxCache; if (!memKtx || !(file = ktxCache->writeFile(data, KTXCache::Metadata(filename, length)))) { qCWarning(materialnetworking) << url << " failed to write cache file"; - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -1058,12 +1100,12 @@ void NetworkTexture::handleFinishedInitialLoad() { textureAndSize = textureCache->cacheTextureByHash(filename, textureAndSize); } - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, textureAndSize.first), Q_ARG(int, textureAndSize.second.x), Q_ARG(int, textureAndSize.second.y)); - QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel"); + QMetaObject::invokeMethod(resource.get(), "startRequestForNextMipLevel"); }); } @@ -1073,7 +1115,7 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } else if (_currentlyLoadingResourceType == ResourceType::ORIGINAL) { loadTextureContent(data); } else { - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); Resource::handleFailedRequest(ResourceRequest::Error); } } @@ -1104,8 +1146,11 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) { _currentlyLoadingResourceType = ResourceType::KTX; _activeUrl = _activeUrl.resolved(url); auto textureCache = DependencyManager::get(); - auto self = _self.lock(); + auto self = weak_from_this().lock(); if (!self) { +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + Q_ASSERT(!_wasDeleted); +#endif return; } QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection); @@ -1120,7 +1165,7 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) { _activeUrl = _activeUrl.resolved(meta.uncompressed); auto textureCache = DependencyManager::get(); - auto self = _self.lock(); + auto self = shared_from_this(); if (!self) { return; } @@ -1134,7 +1179,7 @@ void NetworkTexture::loadMetaContent(const QByteArray& content) { _activeUrl = _activeUrl.resolved(meta.original); auto textureCache = DependencyManager::get(); - auto self = _self.lock(); + auto self = shared_from_this(); if (!self) { return; } @@ -1152,7 +1197,7 @@ void NetworkTexture::loadTextureContent(const QByteArray& content) { return; } - QThreadPool::globalInstance()->start(new ImageReader(_self, _url, content, _extraHash, _maxNumPixels, _sourceChannel)); + QThreadPool::globalInstance()->start(new ImageReader(weak_from_this(), _url, content, _extraHash, _maxNumPixels, _sourceChannel)); } void NetworkTexture::refresh() { @@ -1170,14 +1215,14 @@ void NetworkTexture::refresh() { _ktxMipRequest->deleteLater(); _ktxMipRequest = nullptr; } - TextureCache::requestCompleted(_self); + TextureCache::requestCompleted(weak_from_this()); } _ktxResourceState = PENDING_INITIAL_LOAD; Resource::refresh(); } -ImageReader::ImageReader(const QWeakPointer& resource, const QUrl& url, const QByteArray& data, size_t extraHash, int maxNumPixels, image::ColorChannel sourceChannel) : +ImageReader::ImageReader(const std::weak_ptr& resource, const QUrl& url, const QByteArray& data, size_t extraHash, int maxNumPixels, image::ColorChannel sourceChannel) : _resource(resource), _url(url), _content(data), @@ -1236,7 +1281,8 @@ void ImageReader::read() { if (!resource) { return; } - auto networkTexture = resource.staticCast(); + auto networkTexture = std::dynamic_pointer_cast(resource); + Q_ASSERT(networkTexture); // Hash the source image and extraHash for KTX caching std::string hash; @@ -1269,7 +1315,7 @@ void ImageReader::read() { // If we found the texture either because it's in use or via KTX deserialization, // set the image and return immediately. if (textureAndSize.first) { - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, textureAndSize.first), Q_ARG(int, textureAndSize.second.x), Q_ARG(int, textureAndSize.second.y)); @@ -1294,7 +1340,7 @@ void ImageReader::read() { textureAndSize = image::processImage(std::move(buffer), _url.toString().toStdString(), _sourceChannel, _maxNumPixels, networkTexture->getTextureType(), shouldCompress, target); if (!textureAndSize.first) { - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, textureAndSize.first), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -1326,7 +1372,7 @@ void ImageReader::read() { textureAndSize = textureCache->cacheTextureByHash(hash, textureAndSize); } - QMetaObject::invokeMethod(resource.data(), "setImage", + QMetaObject::invokeMethod(resource.get(), "setImage", Q_ARG(gpu::TexturePointer, textureAndSize.first), Q_ARG(int, textureAndSize.second.x), Q_ARG(int, textureAndSize.second.y)); @@ -1402,8 +1448,8 @@ NetworkTexturePointer TextureCache::getTextureByUUID(const QString& uuid) { if (!quuid.isNull()) { // We mark this as a resource texture because it's just a reference to another texture. The source // texture will be marked properly - NetworkTexturePointer toReturn = NetworkTexturePointer::create(uuid, true); - toReturn->setImageOperator(Texture::getTextureForUUIDOperator(uuid)); + NetworkTexturePointer toReturn = std::make_shared(uuid, true); + toReturn->setImageOperator(Texture::getTextureForUUIDOperator(QUuid(uuid))); return toReturn; } return NetworkTexturePointer(); diff --git a/libraries/material-networking/src/material-networking/TextureCache.h b/libraries/material-networking/src/material-networking/TextureCache.h index d2279fbc89d..4df41117da7 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.h +++ b/libraries/material-networking/src/material-networking/TextureCache.h @@ -74,7 +74,7 @@ class NetworkTexture : public Resource, public Texture { void setExtra(void* extra) override; signals: - void networkTextureCreated(const QWeakPointer& self); + void networkTextureCreated(const std::weak_ptr& self); public slots: void ktxInitialDataRequestFinished(); @@ -152,9 +152,9 @@ public slots: friend class TextureCache; }; -using NetworkTexturePointer = QSharedPointer; +using NetworkTexturePointer = std::shared_ptr; -Q_DECLARE_METATYPE(QWeakPointer) +Q_DECLARE_METATYPE(std::weak_ptr) /// Stores cached textures, including render-to-texture targets. @@ -214,8 +214,8 @@ class TextureCache : public ResourceCache, public Dependency { // Overload ResourceCache::prefetch to allow specifying texture type for loads Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, image::ColorChannel sourceChannel = image::ColorChannel::NONE); - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; private: friend class ImageReader; diff --git a/libraries/midi/src/Midi.cpp b/libraries/midi/src/Midi.cpp index 05940324014..80fd22f668a 100644 --- a/libraries/midi/src/Midi.cpp +++ b/libraries/midi/src/Midi.cpp @@ -198,15 +198,14 @@ void Midi::MidiSetup() { MIDIINCAPS incaps; for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { if (MMSYSERR_NOERROR == midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS))) { - bool found = false; for (int j = 0; j < midiInExclude.size(); j++) { - if (midiInExclude[j].toStdString().compare(incaps.szPname) == 0) { + if (midiInExclude[j].toStdWString().compare(incaps.szPname) == 0) { found = true; break; } } - if (!found) { // EXCLUDE AN INPUT BY NAME + if (!found) { // EXCLUDE AN INPUT BY NAME HMIDIIN tmphin; if (MMSYSERR_NOERROR == midiInOpen(&tmphin, i, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION)) { if (MMSYSERR_NOERROR == midiInStart(tmphin)) { @@ -220,15 +219,14 @@ void Midi::MidiSetup() { MIDIOUTCAPS outcaps; for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { if (MMSYSERR_NOERROR == midiOutGetDevCaps(i, &outcaps, sizeof(MIDIOUTCAPS))) { - bool found = false; for (int j = 0; j < midiOutExclude.size(); j++) { - if (midiOutExclude[j].toStdString().compare(outcaps.szPname) == 0) { + if (midiOutExclude[j].toStdWString().compare(outcaps.szPname) == 0) { found = true; break; } } - if (!found) { // EXCLUDE AN OUTPUT BY NAME + if (!found) { // EXCLUDE AN OUTPUT BY NAME HMIDIOUT tmphout; if (MMSYSERR_NOERROR == midiOutOpen(&tmphout, i, (DWORD_PTR)MidiOutProc, NULL, CALLBACK_FUNCTION)) { midihout.push_back(tmphout); @@ -395,13 +393,13 @@ QStringList Midi::listMidiDevices(bool output) { MIDIOUTCAPS outcaps; for (unsigned int i = 0; i < midiOutGetNumDevs(); i++) { midiOutGetDevCaps(i, &outcaps, sizeof(MIDIINCAPS)); - rv.append(outcaps.szPname); + rv.append(QString::fromWCharArray(outcaps.szPname)); } } else { MIDIINCAPS incaps; for (unsigned int i = 0; i < midiInGetNumDevs(); i++) { midiInGetDevCaps(i, &incaps, sizeof(MIDIINCAPS)); - rv.append(incaps.szPname); + rv.append(QString::fromWCharArray(incaps.szPname)); } } #endif diff --git a/libraries/midi/src/Midi.h b/libraries/midi/src/Midi.h index ee1ba6e8b36..2ec1ca50887 100644 --- a/libraries/midi/src/Midi.h +++ b/libraries/midi/src/Midi.h @@ -15,6 +15,7 @@ #define hifi_Midi_h #include +#include #include #include diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index 9fd3f520799..39d9ffd6e29 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -126,7 +126,7 @@ namespace baker { class BakerEngineBuilder { public: - using Input = VaryingSet3; + using Input = VaryingSet3; using Output = VaryingSet5, std::vector, std::vector>>; using JobModel = Task::ModelIO; void build(JobModel& model, const Varying& input, Varying& output) { @@ -193,7 +193,7 @@ namespace baker { } }; - Baker::Baker(const hfm::Model::Pointer& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& materialMappingBaseURL) : + Baker::Baker(const hfm::Model::Pointer& hfmModel, const hifi::VariantMultiHash& mapping, const hifi::URL& materialMappingBaseURL) : _engine(std::make_shared(BakerEngineBuilder::JobModel::create("Baker"), std::make_shared())) { _engine->feedInput(0, hfmModel); _engine->feedInput(1, mapping); diff --git a/libraries/model-baker/src/model-baker/Baker.h b/libraries/model-baker/src/model-baker/Baker.h index 9780484fa48..3bc9f7197b6 100644 --- a/libraries/model-baker/src/model-baker/Baker.h +++ b/libraries/model-baker/src/model-baker/Baker.h @@ -23,7 +23,7 @@ namespace baker { class Baker { public: - Baker(const hfm::Model::Pointer& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& materialMappingBaseURL); + Baker(const hfm::Model::Pointer& hfmModel, const hifi::VariantMultiHash& mapping, const hifi::URL& materialMappingBaseURL); std::shared_ptr getConfiguration(); diff --git a/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp b/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp index 48466ebe07a..1949b62906c 100644 --- a/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp +++ b/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp @@ -12,6 +12,7 @@ void ParseFlowDataTask::run(const baker::BakeContextPointer& context, const Inpu FlowData flowData; static const QString FLOW_PHYSICS_FIELD = "flowPhysicsData"; static const QString FLOW_COLLISIONS_FIELD = "flowCollisionsData"; + // QT6TODO: currently crashes on Qt6 for (auto mappingIter = mapping.cbegin(); mappingIter != mapping.cend(); mappingIter++) { if (mappingIter.key() == FLOW_PHYSICS_FIELD || mappingIter.key() == FLOW_COLLISIONS_FIELD) { QByteArray data = mappingIter.value().toByteArray(); diff --git a/libraries/model-baker/src/model-baker/ParseFlowDataTask.h b/libraries/model-baker/src/model-baker/ParseFlowDataTask.h index deabb63f79c..29e5224cd2d 100644 --- a/libraries/model-baker/src/model-baker/ParseFlowDataTask.h +++ b/libraries/model-baker/src/model-baker/ParseFlowDataTask.h @@ -18,7 +18,7 @@ class ParseFlowDataTask { public: - using Input = hifi::VariantHash; + using Input = hifi::VariantMultiHash; using Output = FlowData; using JobModel = baker::Job::ModelIO; diff --git a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp index c4c4f7f74b2..a6bbef97a99 100644 --- a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.cpp @@ -71,6 +71,9 @@ void ParseMaterialMappingTask::run(const baker::BakeContextPointer& context, con const auto& url = input.get1(); MaterialMapping materialMapping; + // QT6TODO: even listing keys causes crash + qDebug() << "ParseMaterialMappingTask::run " << mapping.keys(); + auto mappingIter = mapping.find("materialMap"); if (mappingIter != mapping.end()) { QByteArray materialMapValue = mappingIter.value().toByteArray(); diff --git a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h index 3e967a7d3f0..0e453c53c95 100644 --- a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h @@ -22,11 +22,11 @@ class ParseMaterialMappingTask { public: - using Input = baker::VaryingSet2; + using Input = baker::VaryingSet2; using Output = MaterialMapping; using JobModel = baker::Job::ModelIO; void run(const baker::BakeContextPointer& context, const Input& input, Output& output); }; -#endif // hifi_ParseMaterialMappingTask_h \ No newline at end of file +#endif // hifi_ParseMaterialMappingTask_h diff --git a/libraries/model-baker/src/model-baker/PrepareJointsTask.cpp b/libraries/model-baker/src/model-baker/PrepareJointsTask.cpp index 662d5f36dc6..9685d4369e2 100644 --- a/libraries/model-baker/src/model-baker/PrepareJointsTask.cpp +++ b/libraries/model-baker/src/model-baker/PrepareJointsTask.cpp @@ -13,10 +13,10 @@ #include "ModelBakerLogging.h" -QMap getJointNameMapping(const hifi::VariantHash& mapping) { +QMap getJointNameMapping(const hifi::VariantMultiHash& mapping) { static const QString JOINT_NAME_MAPPING_FIELD = "jointMap"; QMap hfmToHifiJointNameMap; - if (!mapping.isEmpty() && mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].type() == QVariant::Hash) { + if (!mapping.isEmpty() && mapping.contains(JOINT_NAME_MAPPING_FIELD) && mapping[JOINT_NAME_MAPPING_FIELD].typeId() == QMetaType::QVariantHash) { auto jointNames = mapping[JOINT_NAME_MAPPING_FIELD].toHash(); for (auto itr = jointNames.begin(); itr != jointNames.end(); itr++) { hfmToHifiJointNameMap.insert(itr.key(), itr.value().toString()); @@ -26,11 +26,13 @@ QMap getJointNameMapping(const hifi::VariantHash& mapping) { return hfmToHifiJointNameMap; } -QMap getJointRotationOffsets(const hifi::VariantHash& mapping) { +QMap getJointRotationOffsets(const hifi::VariantMultiHash& mapping) { QMap jointRotationOffsets; static const QString JOINT_ROTATION_OFFSET_FIELD = "jointRotationOffset"; static const QString JOINT_ROTATION_OFFSET2_FIELD = "jointRotationOffset2"; - if (!mapping.isEmpty() && ((mapping.contains(JOINT_ROTATION_OFFSET_FIELD) && mapping[JOINT_ROTATION_OFFSET_FIELD].type() == QVariant::Hash) || (mapping.contains(JOINT_ROTATION_OFFSET2_FIELD) && mapping[JOINT_ROTATION_OFFSET2_FIELD].type() == QVariant::Hash))) { + if (!mapping.isEmpty() && ((mapping.contains(JOINT_ROTATION_OFFSET_FIELD) && mapping[JOINT_ROTATION_OFFSET_FIELD].typeId() == QMetaType::QVariantHash) + || (mapping.contains(JOINT_ROTATION_OFFSET2_FIELD) && mapping[JOINT_ROTATION_OFFSET2_FIELD].typeId() == QMetaType::QVariantHash))) { + QHash offsets; if (mapping.contains(JOINT_ROTATION_OFFSET_FIELD)) { offsets = mapping[JOINT_ROTATION_OFFSET_FIELD].toHash(); @@ -72,7 +74,7 @@ void PrepareJointsTask::run(const baker::BakeContextPointer& context, const Inpu auto& jointRotationOffsets = output.edit1(); static const QString JOINT_ROTATION_OFFSET2_FIELD = "jointRotationOffset2"; - QVariantHash fstHashMap = mapping; + hifi::VariantMultiHash fstHashMap = mapping; bool newJointRot = fstHashMap.contains(JOINT_ROTATION_OFFSET2_FIELD); // Get joint renames diff --git a/libraries/model-baker/src/model-baker/PrepareJointsTask.h b/libraries/model-baker/src/model-baker/PrepareJointsTask.h index 802dbb38260..76960b8f92d 100644 --- a/libraries/model-baker/src/model-baker/PrepareJointsTask.h +++ b/libraries/model-baker/src/model-baker/PrepareJointsTask.h @@ -29,7 +29,7 @@ class PrepareJointsConfig : public baker::JobConfig { class PrepareJointsTask { public: using Config = PrepareJointsConfig; - using Input = baker::VaryingSet2, hifi::VariantHash /*mapping*/>; + using Input = baker::VaryingSet2, hifi::VariantMultiHash /*mapping*/>; using Output = baker::VaryingSet3, QMap /*jointRotationOffsets*/, QHash /*jointIndices*/>; using JobModel = baker::Job::ModelIO; @@ -40,4 +40,4 @@ class PrepareJointsTask { bool _passthrough { false }; }; -#endif // hifi_PrepareJointsTask_h \ No newline at end of file +#endif // hifi_PrepareJointsTask_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 264c6b98019..f4ac0c4e7f7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -29,6 +29,8 @@ #include #include +#include "shared/QtHelpers.h" + Q_LOGGING_CATEGORY(trace_resource_parse_geometry, "trace.resource.parse.geometry") class GeometryExtra { @@ -67,6 +69,15 @@ namespace std { } }; + template <> + struct hash { + size_t operator()(const hifi::VariantMultiHash& a) const { + QVariantHasher hasher; + // QT6TODO: check with profiler if this is not causing performance problems + return hasher.hash(qMultiHashToQVariant(a)); + } + }; + template <> struct hash { size_t operator()(const QUrl& a) const { @@ -87,7 +98,7 @@ namespace std { class GeometryReader : public QRunnable { public: - GeometryReader(const ModelLoader& modelLoader, QWeakPointer& resource, const QUrl& url, const GeometryMappingPair& mapping, + GeometryReader(const ModelLoader& modelLoader, std::weak_ptr resource, const QUrl& url, const GeometryMappingPair& mapping, const QByteArray& data, bool combineParts, const QString& webMediaType) : _modelLoader(modelLoader), _resource(resource), _url(url), _mapping(mapping), _data(data), _combineParts(combineParts), _webMediaType(webMediaType) { @@ -98,8 +109,9 @@ class GeometryReader : public QRunnable { private: ModelLoader _modelLoader; - QWeakPointer _resource; + std::weak_ptr _resource; QUrl _url; + // QT6TODO: I'm not sure if _mapping should be QHash or QMultiHash GeometryMappingPair _mapping; QByteArray _data; bool _combineParts; @@ -119,7 +131,8 @@ void GeometryReader::run() { QThread::currentThread()->setPriority(originalPriority); }); - if (!_resource.toStrongRef().data()) { + if (!_resource.lock()) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; return; } @@ -129,7 +142,7 @@ void GeometryReader::run() { } // Ensure the resource has not been deleted - auto resource = _resource.toStrongRef(); + auto resource = _resource.lock(); if (!resource) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; return; @@ -140,9 +153,9 @@ void GeometryReader::run() { } HFMModel::Pointer hfmModel; - QMultiHash serializerMapping = _mapping.second; - serializerMapping.replace("combineParts",_combineParts); - serializerMapping.replace("deduplicateIndices", true); + hifi::VariantMultiHash serializerMapping = _mapping.second; + serializerMapping["combineParts"] = _combineParts; + serializerMapping["deduplicateIndices"] = true; if (_url.path().toLower().endsWith(".gz")) { QByteArray uncompressedData; @@ -181,19 +194,19 @@ void GeometryReader::run() { auto processedHFMModel = modelBaker.getHFMModel(); auto materialMapping = modelBaker.getMaterialMapping(); - QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", + QMetaObject::invokeMethod(resource.get(), "setGeometryDefinition", Q_ARG(HFMModel::Pointer, processedHFMModel), Q_ARG(MaterialMapping, materialMapping)); } catch (const std::exception&) { - auto resource = _resource.toStrongRef(); + auto resource = _resource.lock(); if (resource) { - QMetaObject::invokeMethod(resource.data(), "finishedLoading", + QMetaObject::invokeMethod(resource.get(), "finishedLoading", Q_ARG(bool, false)); } } catch (QString& e) { qCWarning(modelnetworking) << "Exception while loading model --" << e; - auto resource = _resource.toStrongRef(); + auto resource = _resource.lock(); if (resource) { - QMetaObject::invokeMethod(resource.data(), "finishedLoading", + QMetaObject::invokeMethod(resource.get(), "finishedLoading", Q_ARG(bool, false)); } } @@ -269,7 +282,8 @@ void GeometryResource::downloadFinished(const QByteArray& data) { GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false }; // Get the raw GeometryResource - _geometryResource = modelCache->getResource(url, QUrl(), &extra, std::hash()(extra)).staticCast(); + _geometryResource = std::dynamic_pointer_cast(modelCache->getResource(url, QUrl(), &extra, std::hash()(extra))); + Q_ASSERT(_geometryResource); // Avoid caching nested resources - their references will be held by the parent _geometryResource->_isCacheable = false; @@ -280,7 +294,7 @@ void GeometryResource::downloadFinished(const QByteArray& data) { disconnect(_connection); } - _connection = connect(_geometryResource.data(), &Resource::finished, this, &GeometryResource::onGeometryMappingLoaded); + _connection = connect(_geometryResource.get(), &Resource::finished, this, &GeometryResource::onGeometryMappingLoaded); } } } else { @@ -288,7 +302,7 @@ void GeometryResource::downloadFinished(const QByteArray& data) { _url = _effectiveBaseURL; _textureBaseURL = _effectiveBaseURL; } - QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, _self, _effectiveBaseURL, _mappingPair, data, _combineParts, _request->getWebMediaType())); + QThreadPool::globalInstance()->start(new GeometryReader(_modelLoader, weak_from_this(), _effectiveBaseURL, _mappingPair, data, _combineParts, _request->getWebMediaType())); } } @@ -389,18 +403,20 @@ ModelCache::ModelCache() { modelFormatRegistry->addFormat(GLTFSerializer()); } -QSharedPointer ModelCache::createResource(const QUrl& url) { - return QSharedPointer(new GeometryResource(url, _modelLoader), &GeometryResource::deleter); +std::shared_ptr ModelCache::createResource(const QUrl& url) { + return std::shared_ptr(new GeometryResource(url, _modelLoader), GeometryResource::sharedPtrDeleter); } -QSharedPointer ModelCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new GeometryResource(*resource.staticCast()), &GeometryResource::deleter); +std::shared_ptr ModelCache::createResourceCopy(const std::shared_ptr& resource) { + auto geometryResource = std::dynamic_pointer_cast(resource); + Q_ASSERT(geometryResource); + return std::shared_ptr(new GeometryResource(*geometryResource), GeometryResource::sharedPtrDeleter); } GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const GeometryMappingPair& mapping, const QUrl& textureBaseUrl) { bool combineParts = true; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; - GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); + GeometryResource::Pointer resource = std::dynamic_pointer_cast(getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra))); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { resource->setTextures(); @@ -414,7 +430,7 @@ GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& u const QUrl& textureBaseUrl) { bool combineParts = false; GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts }; - GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra)).staticCast(); + GeometryResource::Pointer resource = std::dynamic_pointer_cast(getResource(url, QUrl(), &geometryExtra, std::hash()(geometryExtra))); if (resource) { if (resource->isLoaded() && resource->shouldSetTextures()) { resource->setTextures(); @@ -533,16 +549,16 @@ const std::shared_ptr Geometry::getShapeMaterial(int partID) co } void GeometryResourceWatcher::startWatching() { - connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); - connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); + connect(_resource.get(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); + connect(_resource.get(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); if (_resource->isLoaded()) { resourceFinished(!_resource->getURL().isEmpty()); } } void GeometryResourceWatcher::stopWatching() { - disconnect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); - disconnect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); + disconnect(_resource.get(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished); + disconnect(_resource.get(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed); } void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 79021087095..9969ceba449 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -26,7 +26,7 @@ class MeshPart; -using GeometryMappingPair = std::pair; +using GeometryMappingPair = std::pair; Q_DECLARE_METATYPE(GeometryMappingPair) class Geometry { @@ -59,7 +59,7 @@ class Geometry { virtual bool areTexturesLoaded() const; const QUrl& getAnimGraphOverrideUrl() const { return _animGraphOverrideUrl; } bool shouldWaitForWearables() const { return _waitForWearables; } - const QVariantHash& getMapping() const { return _mapping; } + const hifi::VariantMultiHash& getMapping() const { return _mapping; } protected: // Shared across all geometries, constant throughout lifetime @@ -72,21 +72,22 @@ class Geometry { NetworkMaterials _materials; QUrl _animGraphOverrideUrl; - QVariantHash _mapping; // parsed contents of FST file. + hifi::VariantMultiHash _mapping; // parsed contents of FST file. bool _waitForWearables { false }; private: - mutable bool _areTexturesLoaded { false }; + mutable std::atomic _areTexturesLoaded { false }; }; /// A geometry loaded from the network. class GeometryResource : public Resource, public Geometry { Q_OBJECT public: - using Pointer = QSharedPointer; + using Pointer = std::shared_ptr; GeometryResource(const QUrl& url, const ModelLoader& modelLoader) : Resource(url), _modelLoader(modelLoader) {} GeometryResource(const GeometryResource& other); + virtual ~GeometryResource() {} QString getType() const override { return "Geometry"; } @@ -175,8 +176,8 @@ class ModelCache : public ResourceCache, public Dependency { protected: friend class GeometryResource; - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; private: ModelCache(); diff --git a/libraries/model-networking/src/model-networking/ModelLoader.cpp b/libraries/model-networking/src/model-networking/ModelLoader.cpp index 65314633c96..63282ac7a10 100644 --- a/libraries/model-networking/src/model-networking/ModelLoader.cpp +++ b/libraries/model-networking/src/model-networking/ModelLoader.cpp @@ -15,7 +15,7 @@ #include -hfm::Model::Pointer ModelLoader::load(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const { +hfm::Model::Pointer ModelLoader::load(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url, const std::string& webMediaType) const { auto serializer = DependencyManager::get()->getSerializerForMediaType(data, url, webMediaType); if (!serializer) { return hfm::Model::Pointer(); diff --git a/libraries/model-networking/src/model-networking/ModelLoader.h b/libraries/model-networking/src/model-networking/ModelLoader.h index 5fbab4fb650..095fa5c22d8 100644 --- a/libraries/model-networking/src/model-networking/ModelLoader.h +++ b/libraries/model-networking/src/model-networking/ModelLoader.h @@ -20,7 +20,7 @@ class ModelLoader { // Given the currently stored list of supported file formats, determine how to load a model from the given parameters. // If successful, return an owned reference to the newly loaded model. // If failed, return an empty reference. - hfm::Model::Pointer load(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const; + hfm::Model::Pointer load(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url, const std::string& webMediaType) const; }; #endif // hifi_ModelLoader_h diff --git a/libraries/model-serializers/src/FBXSerializer.cpp b/libraries/model-serializers/src/FBXSerializer.cpp index 58eed40bdb4..8115b8c541b 100644 --- a/libraries/model-serializers/src/FBXSerializer.cpp +++ b/libraries/model-serializers/src/FBXSerializer.cpp @@ -23,6 +23,8 @@ #include +#include "shared/QtHelpers.h" + // TOOL: Uncomment the following line to enable the filtering of all the unknown fields of a node so we can break point easily while loading a model with problems... //#define DEBUG_FBXSERIALIZER @@ -34,7 +36,7 @@ glm::vec3 parseVec3(const QString& string) { return glm::vec3(); } glm::vec3 value; - for (int i = 0; i < 3; i++) { + for (qsizetype i = 0; i < 3; i++) { // duplicate last value if there aren't three elements value[i] = elements.at(min(i, elements.size() - 1)).trimmed().toFloat(); } @@ -103,10 +105,10 @@ QString getModelName(const QVariantList& properties) { QString name; if (properties.size() == 3) { name = properties.at(1).toString(); - name = processID(name.left(name.indexOf(QChar('\0')))); } else { - name = processID(properties.at(0).toString()); + name = properties.at(0).toString(); } + name = processID(name.left(name.indexOf(QChar('\0')))); return name; } @@ -114,10 +116,10 @@ QString getMaterialName(const QVariantList& properties) { QString name; if (properties.size() == 1 || properties.at(1).toString().isEmpty()) { name = properties.at(0).toString(); - name = processID(name.left(name.indexOf(QChar('\0')))); } else { - name = processID(properties.at(1).toString()); + name = properties.at(1).toString(); } + name = processID(name.left(name.indexOf(QChar('\0')))); return name; } @@ -260,7 +262,7 @@ typedef QPair WeightedIndex; void addBlendshapes(const ExtractedBlendshape& extracted, const QList& indices, ExtractedMesh& extractedMesh) { foreach (const WeightedIndex& index, indices) { - extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1)); + extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), static_cast(index.first + 1))); extractedMesh.blendshapeIndexMaps.resize(extractedMesh.mesh.blendshapes.size()); HFMBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first]; QHash& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first]; @@ -394,7 +396,7 @@ hifi::ByteArray fileOnUrl(const hifi::ByteArray& filepath, const QString& url) { return filepath.mid(filepath.lastIndexOf('/') + 1); } -HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const QString& url) { +HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantMultiHash& mapping, const QString& url) { const FBXNode& node = _rootNode; bool deduplicateIndices = mapping["deduplicateIndices"].toBool(); @@ -419,7 +421,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const std::map lights; - hifi::VariantMultiHash blendshapeMappings = mapping.value("bs").toHash(); + hifi::VariantMultiHash blendshapeMappings = qVariantToQMultiHash(mapping.value("bs")); QMultiHash blendshapeIndices; for (int i = 0;; i++) { @@ -490,7 +492,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const foreach (const FBXNode& subsubobject, subobject.children) { static const QVariant APPLICATION_NAME = QVariant(hifi::ByteArray("Original|ApplicationName")); if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 && - subsubobject.properties.at(0) == APPLICATION_NAME) { + subsubobject.properties.at(0).toByteArray() == APPLICATION_NAME) { hfmModel.applicationName = subsubobject.properties.at(4).toString(); } } @@ -510,7 +512,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const static const QVariant UNIT_SCALE_FACTOR = hifi::ByteArray("UnitScaleFactor"); static const QVariant AMBIENT_COLOR = hifi::ByteArray("AmbientColor"); static const QVariant UP_AXIS = hifi::ByteArray("UpAxis"); - const auto& subpropName = subobject.properties.at(0); + const auto& subpropName = subobject.properties.at(0).toByteArray(); if (subpropName == UNIT_SCALE_FACTOR) { unitScaleFactor = subobject.properties.at(index).toFloat(); } else if (subpropName == AMBIENT_COLOR) { @@ -533,7 +535,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } else if (child.name == "Objects") { foreach (const FBXNode& object, child.children) { if (object.name == "Geometry") { - if (object.properties.at(2) == "Mesh") { + if (object.properties.at(2).toByteArray() == "Mesh") { meshes.insert(getID(object.properties), extractMesh(object, meshIndex, deduplicateIndices)); } else { // object.properties.at(2) == "Shape" ExtractedBlendshape extracted = { getID(object.properties), extractBlendshape(object) }; @@ -567,7 +569,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const glm::vec3 rotationMin, rotationMax; - bool isLimbNode = object.properties.size() >= 3 && object.properties.at(2) == "LimbNode"; + bool isLimbNode = object.properties.size() >= 3 && object.properties.at(2).toByteArray() == "LimbNode"; FBXModel fbxModel = { name, -1, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), glm::quat(), glm::mat4(), glm::vec3(), glm::vec3(), false, glm::vec3(), glm::quat(), glm::vec3(1.0f), isLimbNode }; @@ -610,7 +612,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const static const QVariant PRE_ROTATION = hifi::ByteArray("PreRotation"); static const QVariant POST_ROTATION = hifi::ByteArray("PostRotation"); foreach(const FBXNode& property, subobject.children) { - const auto& childProperty = property.properties.at(0); + const auto& childProperty = property.properties.at(0).toByteArray(); if (property.name == propertyName) { if (childProperty == LCL_TRANSLATION) { translation = getVec3(property.properties, index); @@ -791,18 +793,18 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const static const QVariant SCALING = hifi::ByteArray("Scaling"); if (property.name == propertyName) { QString v = property.properties.at(0).toString(); - if (property.properties.at(0) == UV_SET) { + if (property.properties.at(0).toByteArray() == UV_SET) { std::string uvName = property.properties.at(index).toString().toStdString(); tex.assign(tex.UVSet, property.properties.at(index).toString()); - } else if (property.properties.at(0) == CURRENT_TEXTURE_BLEND_MODE) { + } else if (property.properties.at(0).toByteArray() == CURRENT_TEXTURE_BLEND_MODE) { tex.assign(tex.currentTextureBlendMode, property.properties.at(index).value()); - } else if (property.properties.at(0) == USE_MATERIAL) { + } else if (property.properties.at(0).toByteArray() == USE_MATERIAL) { tex.assign(tex.useMaterial, property.properties.at(index).value()); - } else if (property.properties.at(0) == TRANSLATION) { + } else if (property.properties.at(0).toByteArray() == TRANSLATION) { tex.assign(tex.translation, tex.translation + getVec3(property.properties, index)); - } else if (property.properties.at(0) == ROTATION) { + } else if (property.properties.at(0).toByteArray() == ROTATION) { tex.assign(tex.rotation, getVec3(property.properties, index)); - } else if (property.properties.at(0) == SCALING) { + } else if (property.properties.at(0).toByteArray() == SCALING) { auto newScaling = getVec3(property.properties, index); if (newScaling.x == 0.0f) { newScaling.x = 1.0f; @@ -917,41 +919,41 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const foreach(const FBXNode& property, subobject.children) { if (property.name == propertyName) { - if (property.properties.at(0) == DIFFUSE_COLOR) { + if (property.properties.at(0).toByteArray() == DIFFUSE_COLOR) { material.diffuseColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == DIFFUSE_FACTOR) { + } else if (property.properties.at(0).toByteArray() == DIFFUSE_FACTOR) { material.diffuseFactor = property.properties.at(index).value(); - } else if (property.properties.at(0) == DIFFUSE) { + } else if (property.properties.at(0).toByteArray() == DIFFUSE) { // NOTE: this is uneeded but keep it for now for debug // material.diffuseColor = getVec3(property.properties, index); // material.diffuseFactor = 1.0; - } else if (property.properties.at(0) == SPECULAR_COLOR) { + } else if (property.properties.at(0).toByteArray() == SPECULAR_COLOR) { material.specularColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == SPECULAR_FACTOR) { + } else if (property.properties.at(0).toByteArray() == SPECULAR_FACTOR) { material.specularFactor = property.properties.at(index).value(); - } else if (property.properties.at(0) == SPECULAR) { + } else if (property.properties.at(0).toByteArray() == SPECULAR) { // NOTE: this is uneeded but keep it for now for debug // material.specularColor = getVec3(property.properties, index); // material.specularFactor = 1.0; - } else if (property.properties.at(0) == EMISSIVE_COLOR) { + } else if (property.properties.at(0).toByteArray() == EMISSIVE_COLOR) { material.emissiveColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == EMISSIVE_FACTOR) { + } else if (property.properties.at(0).toByteArray() == EMISSIVE_FACTOR) { material.emissiveFactor = property.properties.at(index).value(); - } else if (property.properties.at(0) == EMISSIVE) { + } else if (property.properties.at(0).toByteArray() == EMISSIVE) { // NOTE: this is uneeded but keep it for now for debug // material.emissiveColor = getVec3(property.properties, index); // material.emissiveFactor = 1.0; - } else if (property.properties.at(0) == AMBIENT_FACTOR) { + } else if (property.properties.at(0).toByteArray() == AMBIENT_FACTOR) { material.ambientFactor = property.properties.at(index).value(); // Detected just for Blender AO vs lightmap - } else if (property.properties.at(0) == SHININESS) { + } else if (property.properties.at(0).toByteArray() == SHININESS) { material.shininess = property.properties.at(index).value(); - } else if (property.properties.at(0) == OPACITY) { + } else if (property.properties.at(0).toByteArray() == OPACITY) { material.opacity = property.properties.at(index).value(); - } else if (property.properties.at(0) == REFLECTION_FACTOR) { + } else if (property.properties.at(0).toByteArray() == REFLECTION_FACTOR) { // Blender 2.79 and below set REFLECTION_FACTOR, but there is no way to actually change that value in their UI, // so we are falling back to non-PBS material. if (isBlenderVersionLower280 == true) { @@ -963,51 +965,51 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } // Sting Ray Material Properties!!!! - else if (property.properties.at(0) == MAYA_USE_NORMAL_MAP) { + else if (property.properties.at(0).toByteArray() == MAYA_USE_NORMAL_MAP) { material.isPBSMaterial = true; material.useNormalMap = (bool)property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_BASE_COLOR) { + } else if (property.properties.at(0).toByteArray() == MAYA_BASE_COLOR) { material.isPBSMaterial = true; material.diffuseColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == MAYA_USE_COLOR_MAP) { + } else if (property.properties.at(0).toByteArray() == MAYA_USE_COLOR_MAP) { material.isPBSMaterial = true; material.useAlbedoMap = (bool) property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_ROUGHNESS) { + } else if (property.properties.at(0).toByteArray() == MAYA_ROUGHNESS) { material.isPBSMaterial = true; material.roughness = property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_USE_ROUGHNESS_MAP) { + } else if (property.properties.at(0).toByteArray() == MAYA_USE_ROUGHNESS_MAP) { material.isPBSMaterial = true; material.useRoughnessMap = (bool)property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_METALLIC) { + } else if (property.properties.at(0).toByteArray() == MAYA_METALLIC) { material.isPBSMaterial = true; material.metallic = property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_USE_METALLIC_MAP) { + } else if (property.properties.at(0).toByteArray() == MAYA_USE_METALLIC_MAP) { material.isPBSMaterial = true; material.useMetallicMap = (bool)property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_EMISSIVE) { + } else if (property.properties.at(0).toByteArray() == MAYA_EMISSIVE) { material.isPBSMaterial = true; material.emissiveColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == MAYA_EMISSIVE_INTENSITY) { + } else if (property.properties.at(0).toByteArray() == MAYA_EMISSIVE_INTENSITY) { material.isPBSMaterial = true; material.emissiveIntensity = property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_USE_EMISSIVE_MAP) { + } else if (property.properties.at(0).toByteArray() == MAYA_USE_EMISSIVE_MAP) { material.isPBSMaterial = true; material.useEmissiveMap = (bool)property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_USE_AO_MAP) { + } else if (property.properties.at(0).toByteArray() == MAYA_USE_AO_MAP) { material.isPBSMaterial = true; material.useOcclusionMap = (bool)property.properties.at(index).value(); - } else if (property.properties.at(0) == MAYA_UV_SCALE) { + } else if (property.properties.at(0).toByteArray() == MAYA_UV_SCALE) { if (property.properties.size() == MAYA_UV_SCALE_PROPERTY_LENGTH) { // properties: { "Maya|uv_scale", "Vector2D", "Vector2", nothing, double, double } glm::vec3 scale = glm::vec3(property.properties.at(4).value(), property.properties.at(5).value(), 1.0); @@ -1022,7 +1024,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } materialParam.scaling *= scale; } - } else if (property.properties.at(0) == MAYA_UV_OFFSET) { + } else if (property.properties.at(0).toByteArray() == MAYA_UV_OFFSET) { if (property.properties.size() == MAYA_UV_OFFSET_PROPERTY_LENGTH) { // properties: { "Maya|uv_offset", "Vector2D", "Vector2", nothing, double, double } glm::vec3 translation = glm::vec3(property.properties.at(4).value(), property.properties.at(5).value(), 1.0); @@ -1076,7 +1078,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } } else if (object.name == "Deformer") { - if (object.properties.last() == "Cluster") { + if (object.properties.last().toByteArray() == "Cluster") { Cluster cluster; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "Indexes") { @@ -1096,7 +1098,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const clusters.insert(getID(object.properties), cluster); } - } else if (object.properties.last() == "BlendShapeChannel") { + } else if (object.properties.last().toByteArray() == "BlendShapeChannel") { hifi::ByteArray name = object.properties.at(1).toByteArray(); name = name.left(name.indexOf('\0')); @@ -1138,7 +1140,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const static const QVariant OP = hifi::ByteArray("OP"); foreach (const FBXNode& connection, child.children) { if (connection.name == "C" || connection.name == "Connect") { - if (connection.properties.at(0) == OO) { + if (connection.properties.at(0).toByteArray() == OO) { QString childID = getID(connection.properties, 1); QString parentID = getID(connection.properties, 2); ooChildToParent.insert(childID, parentID); @@ -1152,7 +1154,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const _lightmapOffset = glm::clamp((*lightIt).second.color.x, 0.f, 1.f); } } - } else if (connection.properties.at(0) == OP) { + } else if (connection.properties.at(0).toByteArray() == OP) { int counter = 0; hifi::ByteArray type = connection.properties.at(3).toByteArray().toLower(); if (type.contains("DiffuseFactor")) { @@ -1394,7 +1396,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const } // NOTE: shapeVertices are in joint-frame - hfmModel.shapeVertices.resize(std::max(1, hfmModel.joints.size()) ); + hfmModel.shapeVertices.resize(std::max(qsizetype(1), hfmModel.joints.size()) ); hfmModel.bindExtents.reset(); hfmModel.meshExtents.reset(); @@ -1700,7 +1702,7 @@ std::unique_ptr FBXSerializer::getFactory() const { return std::make_unique>(); } -HFMModel::Pointer FBXSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) { +HFMModel::Pointer FBXSerializer::read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url) { QBuffer buffer(const_cast(&data)); buffer.open(QIODevice::ReadOnly); diff --git a/libraries/model-serializers/src/FBXSerializer.h b/libraries/model-serializers/src/FBXSerializer.h index e528885754c..f6fe0e42313 100644 --- a/libraries/model-serializers/src/FBXSerializer.h +++ b/libraries/model-serializers/src/FBXSerializer.h @@ -112,12 +112,12 @@ class FBXSerializer : public HFMSerializer { HFMModel* _hfmModel; /// Reads HFMModel from the supplied model and mapping data. /// \exception QString if an error occurs in parsing - HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override; + HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url = hifi::URL()) override; FBXNode _rootNode; static FBXNode parseFBX(QIODevice* device); - HFMModel* extractHFMModel(const hifi::VariantHash& mapping, const QString& url); + HFMModel* extractHFMModel(const hifi::VariantMultiHash& mapping, const QString& url); static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate); QHash meshes; diff --git a/libraries/model-serializers/src/FBXSerializer_Mesh.cpp b/libraries/model-serializers/src/FBXSerializer_Mesh.cpp index 90942c877ae..f2c1894dd1e 100644 --- a/libraries/model-serializers/src/FBXSerializer_Mesh.cpp +++ b/libraries/model-serializers/src/FBXSerializer_Mesh.cpp @@ -220,10 +220,10 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me } else if (subdata.name == "NormalsIndex") { data.normalIndices = getIntVector(subdata); - } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0) == BY_VERTICE) { + } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0).toByteArray() == BY_VERTICE) { data.normalsByVertex = true; - } else if (subdata.name == "ReferenceInformationType" && subdata.properties.at(0) == INDEX_TO_DIRECT) { + } else if (subdata.name == "ReferenceInformationType" && subdata.properties.at(0).toByteArray() == INDEX_TO_DIRECT) { indexToDirect = true; } } @@ -240,10 +240,10 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me } else if (subdata.name == "ColorsIndex" || subdata.name == "ColorIndex") { data.colorIndices = getIntVector(subdata); - } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0) == BY_VERTICE) { + } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0).toByteArray() == BY_VERTICE) { data.colorsByVertex = true; - } else if (subdata.name == "ReferenceInformationType" && subdata.properties.at(0) == INDEX_TO_DIRECT) { + } else if (subdata.name == "ReferenceInformationType" && subdata.properties.at(0).toByteArray() == INDEX_TO_DIRECT) { indexToDirect = true; } } @@ -334,7 +334,7 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me if (subdata.name == "Materials") { materials = getIntVector(subdata); } else if (subdata.name == "MappingInformationType") { - if (subdata.properties.at(0) == BY_POLYGON) { + if (subdata.properties.at(0).toByteArray() == BY_POLYGON) { isMaterialPerPolygon = true; } } else { diff --git a/libraries/model-serializers/src/FBXToJSON.h b/libraries/model-serializers/src/FBXToJSON.h index f36235abca8..6d9117d0326 100644 --- a/libraries/model-serializers/src/FBXToJSON.h +++ b/libraries/model-serializers/src/FBXToJSON.h @@ -15,9 +15,11 @@ #include #include +#include + // Forward declarations. class FBXNode; -template class QVector; +//template class QVector; class FBXToJSON : public std::ostringstream { public: diff --git a/libraries/model-serializers/src/FBXWriter.cpp b/libraries/model-serializers/src/FBXWriter.cpp index efc94461aa0..05708ec9391 100644 --- a/libraries/model-serializers/src/FBXWriter.cpp +++ b/libraries/model-serializers/src/FBXWriter.cpp @@ -12,6 +12,7 @@ #include "FBXWriter.h" #include +#include #ifdef USE_FBX_2016_FORMAT using FBXEndOffset = int64_t; @@ -131,7 +132,7 @@ void FBXWriter::encodeFBXProperty(QDataStream& out, const QVariant& prop) { out << prop.value(); break; - case QVariant::Type::Bool: + case QMetaType::Bool: out.device()->write("C", 1); out << prop.toBool(); break; diff --git a/libraries/model-serializers/src/FST.cpp b/libraries/model-serializers/src/FST.cpp index 8d03933717b..080df2ce500 100644 --- a/libraries/model-serializers/src/FST.cpp +++ b/libraries/model-serializers/src/FST.cpp @@ -15,6 +15,8 @@ #include #include +#include "shared/QtHelpers.h" + constexpr float DEFAULT_SCALE { 1.0f }; FST::FST(QString fstPath, QMultiHash data) : _fstPath(std::move(fstPath)) { @@ -40,7 +42,7 @@ FST::FST(QString fstPath, QMultiHash data) : _fstPath(std::mo } FST* FST::createFSTFromModel(const QString& fstPath, const QString& modelFilePath, const hfm::Model& hfmModel) { - QVariantHash mapping; + hifi::VariantMultiHash mapping; // mixamo files - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will // be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file @@ -136,7 +138,7 @@ FST* FST::createFSTFromModel(const QString& fstPath, const QString& modelFilePat blendshapes.insert("Sneer", QVariantList() << "NoseScrunch_Right" << 0.75); blendshapes.insert("Sneer", QVariantList() << "Squint_Left" << 0.5); blendshapes.insert("Sneer", QVariantList() << "Squint_Right" << 0.5); - mapping.insert(BLENDSHAPE_FIELD, blendshapes); + mapping.insert(BLENDSHAPE_FIELD, qMultiHashToQVariant(blendshapes)); } return new FST(fstPath, mapping); } diff --git a/libraries/model-serializers/src/FST.h b/libraries/model-serializers/src/FST.h index e1273987a26..aed46a49cfe 100644 --- a/libraries/model-serializers/src/FST.h +++ b/libraries/model-serializers/src/FST.h @@ -57,7 +57,7 @@ class FST : public QObject { QStringList _scriptPaths{}; - QVariantHash _other{}; + hifi::VariantMultiHash _other{}; }; #endif // hifi_FST_h diff --git a/libraries/model-serializers/src/FSTReader.cpp b/libraries/model-serializers/src/FSTReader.cpp index 9c1ff5a431d..058c25b63a0 100644 --- a/libraries/model-serializers/src/FSTReader.cpp +++ b/libraries/model-serializers/src/FSTReader.cpp @@ -21,6 +21,8 @@ #include #include +#include "shared/QtHelpers.h" + const QStringList SINGLE_VALUE_PROPERTIES { NAME_FIELD, FILENAME_FIELD, TEXDIR_FIELD, SCRIPT_FIELD, WAIT_FOR_WEARABLES_FIELD, COMMENT_FIELD }; @@ -73,7 +75,7 @@ hifi::VariantMultiHash FSTReader::parseMapping(QIODevice* device) { return properties; } -static void removeBlendshape(QVariantHash& bs, const QString& key) { +static void removeBlendshape(hifi::VariantMultiHash& bs, const QString& key) { if (bs.contains(key)) { bs.remove(key); } @@ -96,8 +98,9 @@ static void splitBlendshapes(hifi::VariantMultiHash& bs, const QString& key, con } // convert legacy blendshapes to arkit blendshapes +// QT6TODO: I'm not sure if qVariantToQMultiHash will work correctly. static void fixUpLegacyBlendshapes(hifi::VariantMultiHash & properties) { - hifi::VariantMultiHash bs = properties.value("bs").toHash(); + hifi::VariantMultiHash bs = qVariantToQMultiHash(properties.value("bs")); // These blendshapes have no ARKit equivalent, so we remove them. removeBlendshape(bs, "JawChew"); @@ -112,7 +115,8 @@ static void fixUpLegacyBlendshapes(hifi::VariantMultiHash & properties) { splitBlendshapes(bs, "Sneer", "NoseSneer_L", "NoseSneer_R"); // re-insert new mutated bs hash into mapping properties. - properties.insert("bs", bs); + // QT6TODO: add VariantMultiHash to QVariant conversion + properties.insert("bs", qMultiHashToQVariant(bs)); } hifi::VariantMultiHash FSTReader::readMapping(const QByteArray& data) { @@ -123,7 +127,7 @@ hifi::VariantMultiHash FSTReader::readMapping(const QByteArray& data) { return mapping; } -void FSTReader::writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) { +void FSTReader::writeVariant(QBuffer& buffer, const hifi::VariantMultiHash::const_iterator& it) { QByteArray key = it.key().toUtf8() + " = "; QVariantHash hashValue = it.value().toHash(); if (hashValue.isEmpty()) { @@ -202,7 +206,7 @@ FSTReader::ModelType FSTReader::predictModelType(const hifi::VariantMultiHash& m QVariantHash joints; - if (mapping.contains("joint") && mapping.value("joint").type() == QVariant::Hash) { + if (mapping.contains("joint") && mapping.value("joint").typeId() == QMetaType::QVariantHash) { joints = mapping.value("joint").toHash(); } diff --git a/libraries/model-serializers/src/FSTReader.h b/libraries/model-serializers/src/FSTReader.h index 5557df67c69..4becf1c9275 100644 --- a/libraries/model-serializers/src/FSTReader.h +++ b/libraries/model-serializers/src/FSTReader.h @@ -55,14 +55,14 @@ class FSTReader { /// Predicts the type of model by examining the mapping static ModelType predictModelType(const hifi::VariantMultiHash& mapping); - static QVector getScripts(const QUrl& fstUrl, const hifi::VariantMultiHash& mapping = QVariantHash()); + static QVector getScripts(const QUrl& fstUrl, const hifi::VariantMultiHash& mapping = hifi::VariantMultiHash()); static QString getNameFromType(ModelType modelType); static FSTReader::ModelType getTypeFromName(const QString& name); static hifi::VariantMultiHash downloadMapping(const QString& url); private: - static void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it); + static void writeVariant(QBuffer& buffer, const hifi::VariantMultiHash::const_iterator& it); static hifi::VariantMultiHash parseMapping(QIODevice* device); static QHash _typesToNames; diff --git a/libraries/model-serializers/src/GLTFSerializer.cpp b/libraries/model-serializers/src/GLTFSerializer.cpp index 9e8e5aa68af..393f0317cdf 100644 --- a/libraries/model-serializers/src/GLTFSerializer.cpp +++ b/libraries/model-serializers/src/GLTFSerializer.cpp @@ -44,6 +44,7 @@ #include #include "FBXSerializer.h" +#include "shared/QtHelpers.h" float atof_locale_independent(char* str) { //TODO: Once we have C++17 we can use std::from_chars @@ -188,7 +189,7 @@ bool findAttribute(const QString &name, const cgltf_attribute *attributes, size_ return false; } -bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url) { +bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantMultiHash& mapping, const hifi::URL& url) { hfmModel.originalURL = url.toString(); int numNodes = (int)_data->nodes_count; @@ -999,7 +1000,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build list of blendshapes from FST and model. typedef QPair WeightedIndex; - hifi::VariantMultiHash blendshapeMappings = mapping.value("bs").toHash(); + hifi::VariantMultiHash blendshapeMappings = qVariantToQMultiHash(mapping.value("bs")); QMultiHash blendshapeIndices; for (int i = 0;; ++i) { auto blendshapeName = QString(BLENDSHAPE_NAMES[i]); @@ -1198,7 +1199,7 @@ std::unique_ptr GLTFSerializer::getFactory() const { return std::make_unique>(); } -HFMModel::Pointer GLTFSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) { +HFMModel::Pointer GLTFSerializer::read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url) { _url = url; diff --git a/libraries/model-serializers/src/GLTFSerializer.h b/libraries/model-serializers/src/GLTFSerializer.h index 0786eac98b3..790ef1b0d00 100644 --- a/libraries/model-serializers/src/GLTFSerializer.h +++ b/libraries/model-serializers/src/GLTFSerializer.h @@ -32,7 +32,7 @@ class GLTFSerializer : public QObject, public HFMSerializer { MediaType getMediaType() const override; std::unique_ptr getFactory() const override; - HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override; + HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url = hifi::URL()) override; ~GLTFSerializer(); private: cgltf_data* _data {nullptr}; @@ -43,7 +43,7 @@ class GLTFSerializer : public QObject, public HFMSerializer { bool getSkinInverseBindMatrices(std::vector>& inverseBindMatrixValues); bool generateTargetData(cgltf_accessor *accessor, float weight, QVector& returnVector); - bool buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url); + bool buildGeometry(HFMModel& hfmModel, const hifi::VariantMultiHash& mapping, const hifi::URL& url); bool readBinary(const QString& url, cgltf_buffer &buffer); diff --git a/libraries/model-serializers/src/OBJSerializer.cpp b/libraries/model-serializers/src/OBJSerializer.cpp index 8529c72a338..1b4b11061b0 100644 --- a/libraries/model-serializers/src/OBJSerializer.cpp +++ b/libraries/model-serializers/src/OBJSerializer.cpp @@ -493,7 +493,7 @@ QNetworkReply* request(hifi::URL& url, bool isTest) { } -bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantHash& mapping, HFMModel& hfmModel, +bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantMultiHash& mapping, HFMModel& hfmModel, float& scaleGuess, bool combineParts) { FaceGroup faces; HFMMesh& mesh = hfmModel.meshes[0]; @@ -666,7 +666,7 @@ std::unique_ptr OBJSerializer::getFactory() const { return std::make_unique>(); } -HFMModel::Pointer OBJSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) { +HFMModel::Pointer OBJSerializer::read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); QBuffer buffer { const_cast(&data) }; buffer.open(QIODevice::ReadOnly); diff --git a/libraries/model-serializers/src/OBJSerializer.h b/libraries/model-serializers/src/OBJSerializer.h index 20633e90e4c..b3ce01a2027 100644 --- a/libraries/model-serializers/src/OBJSerializer.h +++ b/libraries/model-serializers/src/OBJSerializer.h @@ -103,13 +103,13 @@ class OBJSerializer: public QObject, public HFMSerializer { // QObject so we can QString currentMaterialName; QHash materials; - HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override; + HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantMultiHash& mapping, const hifi::URL& url = hifi::URL()) override; private: hifi::URL _url; QHash librariesSeen; - bool parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantHash& mapping, HFMModel& hfmModel, + bool parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantMultiHash& mapping, HFMModel& hfmModel, float& scaleGuess, bool combineParts); void parseMaterialLibrary(QIODevice* device); void parseTextureLine(const hifi::ByteArray& textureLine, hifi::ByteArray& filename, OBJMaterialTextureOptions& textureOptions); diff --git a/libraries/model-serializers/src/OBJWriter.cpp b/libraries/model-serializers/src/OBJWriter.cpp index dec35c7aac6..5a7c4cee806 100644 --- a/libraries/model-serializers/src/OBJWriter.cpp +++ b/libraries/model-serializers/src/OBJWriter.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include #include #include @@ -110,7 +112,7 @@ bool writeOBJToTextStream(QTextStream& out, QList meshes) { graphics::Index partCount = (graphics::Index)mesh->getNumParts(); QString name = (!mesh->displayName.size() ? QString("mesh-%1-part").arg(nth) : QString::fromStdString(mesh->displayName)) - .replace(QRegExp("[^-_a-zA-Z0-9]"), "_"); + .replace(QRegularExpression("[^-_a-zA-Z0-9]"), "_"); for (int partIndex = 0; partIndex < partCount; partIndex++) { const graphics::Mesh::Part& part = partBuffer.get(partIndex); diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 9454853418a..81f6200ff25 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -83,10 +83,8 @@ AccountManager::AccountManager(bool accountSettingsEnabled, UserAgentGetter user _accountSettingsEnabled(accountSettingsEnabled) { qRegisterMetaType("OAuthAccessToken"); - qRegisterMetaTypeStreamOperators("OAuthAccessToken"); qRegisterMetaType("DataServerAccountInfo"); - qRegisterMetaTypeStreamOperators("DataServerAccountInfo"); qRegisterMetaType("QNetworkAccessManager::Operation"); qRegisterMetaType("JSONCallbackParameters"); @@ -347,7 +345,7 @@ void AccountManager::sendRequest(const QString& path, // double check if the finished network reply had a session ID in the header and make // sure that our session ID matches that value if so if (networkReply->hasRawHeader(METAVERSE_SESSION_ID_HEADER)) { - _sessionID = networkReply->rawHeader(METAVERSE_SESSION_ID_HEADER); + _sessionID = QUuid::fromBytes(networkReply->rawHeader(METAVERSE_SESSION_ID_HEADER)); } }); @@ -626,7 +624,7 @@ void AccountManager::requestAccessTokenWithSteam(QByteArray authSessionTicket) { QNetworkReply* requestReply = networkAccessManager.post(request, postData); connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished); - connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError))); + connect(requestReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError))); } void AccountManager::requestAccessTokenWithOculus(const QString& nonce, const QString &oculusID) { @@ -649,7 +647,7 @@ void AccountManager::requestAccessTokenWithOculus(const QString& nonce, const QS QNetworkReply* requestReply = networkAccessManager.post(request, postData); connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished); - connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError))); + connect(requestReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError))); } void AccountManager::refreshAccessToken() { @@ -679,7 +677,7 @@ void AccountManager::refreshAccessToken() { QNetworkReply* requestReply = networkAccessManager.post(request, postData); connect(requestReply, &QNetworkReply::finished, this, &AccountManager::refreshAccessTokenFinished); - connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(refreshAccessTokenError(QNetworkReply::NetworkError))); + connect(requestReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(refreshAccessTokenError(QNetworkReply::NetworkError))); } else { qCWarning(networking) << "Cannot refresh access token without refresh token." << "Access token will need to be manually refreshed."; @@ -807,7 +805,7 @@ void AccountManager::requestProfile() { QNetworkReply* profileReply = networkAccessManager.get(profileRequest); connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished); - connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError))); + connect(profileReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError))); } void AccountManager::requestProfileFinished() { @@ -857,7 +855,7 @@ void AccountManager::requestAccountSettings() { QNetworkReply* lockerReply = networkAccessManager.get(lockerRequest); connect(lockerReply, &QNetworkReply::finished, this, &AccountManager::requestAccountSettingsFinished); - connect(lockerReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccountSettingsError(QNetworkReply::NetworkError))); + connect(lockerReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestAccountSettingsError(QNetworkReply::NetworkError))); _settings.startedLoading(); } @@ -935,7 +933,7 @@ void AccountManager::postAccountSettings() { QNetworkReply* lockerReply = networkAccessManager.put(lockerRequest, postData); connect(lockerReply, &QNetworkReply::finished, this, &AccountManager::postAccountSettingsFinished); - connect(lockerReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(postAccountSettingsError(QNetworkReply::NetworkError))); + connect(lockerReply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(postAccountSettingsError(QNetworkReply::NetworkError))); } void AccountManager::postAccountSettingsFinished() { diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index e8ca40c17dd..78eb3a37595 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -33,6 +33,7 @@ #include "NetworkingConstants.h" #include "UserActivityLogger.h" #include "udt/PacketHeaders.h" +#include const QString REDIRECT_HIFI_ADDRESS = NetworkingConstants::REDIRECT_HIFI_ADDRESS; const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; @@ -284,7 +285,7 @@ bool AddressManager::handleUrl(const QUrl& lookupUrlIn, LookupTrigger trigger, c if (lookupUrl.host().isEmpty()) { // this was in the form hifi:/somewhere or hifi:somewhere. Fix it by making it hifi://somewhere - static const QRegExp HIFI_SCHEME_REGEX = QRegExp(URL_SCHEME_OVERTE + ":\\/{0,2}", Qt::CaseInsensitive); + static const QRegularExpression HIFI_SCHEME_REGEX = QRegularExpression(URL_SCHEME_OVERTE + ":\\/{0,2}", QRegularExpression::CaseInsensitiveOption); lookupUrl = QUrl(lookupUrl.toString().replace(HIFI_SCHEME_REGEX, URL_SCHEME_OVERTE + "://")); } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index a78f9d7d73b..044790b175f 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -435,7 +435,7 @@ public slots: * * location.locationChangeRequired.connect(onLocationChangeRequired); */ - void locationChangeRequired(const glm::vec3& newPosition, + void locationChangeRequired(const glm::vec<3,float,glm::packed_highp>& newPosition, bool hasOrientationChange, const glm::quat& newOrientation, bool shouldFaceLocation); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 5f87c31b865..36dbbaab9fb 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -68,7 +68,7 @@ void AssetClient::initCaching() { #ifdef Q_OS_ANDROID QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); #else - QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); #endif _cacheDir = !cachePath.isEmpty() ? cachePath : "interfaceCache"; } @@ -222,7 +222,7 @@ namespace { if (!dt.isValid()) { qDebug() << __FUNCTION__ << "unrecognized date format:" << dateString; } - dt.setTimeSpec(Qt::UTC); + dt.setTimeZone(QTimeZone::utc()); return dt; } QDateTime getHttpDateValue(const QVariantMap& headers, const QString& keyName, const QDateTime& defaultValue) { diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 5419424f46b..f5e34584bd2 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -12,6 +12,7 @@ #include "AssetResourceRequest.h" #include +#include #include #include diff --git a/libraries/networking/src/AssetUtils.cpp b/libraries/networking/src/AssetUtils.cpp index b0eb19bb735..7b64e2201e1 100644 --- a/libraries/networking/src/AssetUtils.cpp +++ b/libraries/networking/src/AssetUtils.cpp @@ -17,6 +17,7 @@ #include #include // for baseName #include +#include #include "NetworkAccessManager.h" #include "NetworkLogging.h" diff --git a/libraries/networking/src/BaseAssetScriptingInterface.cpp b/libraries/networking/src/BaseAssetScriptingInterface.cpp index 6dcc862c414..d5861316431 100644 --- a/libraries/networking/src/BaseAssetScriptingInterface.cpp +++ b/libraries/networking/src/BaseAssetScriptingInterface.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -262,7 +263,7 @@ Promise BaseAssetScriptingInterface::downloadBytes(QString hash) { { "data", data }, }; } else { - error = request->getError(); + error = QMetaEnum::fromType().valueToKey(request->getError()); result = { { "error", request->getError() } }; } // forward thread-safe copies back to our thread diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp index 5bb530d332b..3bd6785e3e1 100644 --- a/libraries/networking/src/FingerprintUtils.cpp +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -110,11 +110,11 @@ QString FingerprintUtils::getMachineFingerprintString() { bool success = false; // try and open the key that contains the machine GUID - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &cryptoKey) == ERROR_SUCCESS) { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &cryptoKey) == ERROR_SUCCESS) { DWORD type; DWORD guidSize; - const char* MACHINE_GUID_KEY = "MachineGuid"; + const wchar_t MACHINE_GUID_KEY[] = L"MachineGuid"; // try and retrieve the size of the GUID value if (RegQueryValueEx(cryptoKey, MACHINE_GUID_KEY, NULL, &type, NULL, &guidSize) == ERROR_SUCCESS) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d182e7ea94a..87c3c1fe912 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -237,6 +237,12 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { return *_dtlsSocket; } +PacketReceiver& LimitedNodeList::getPacketReceiver() { + Q_ASSERT(_packetReceiver); + return *_packetReceiver; +} + + #if defined(WEBRTC_DATA_CHANNELS) const WebRTCSocket* LimitedNodeList::getWebRTCSocket() { return _nodeSocket.getWebRTCSocket(); @@ -281,7 +287,7 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { if (!hasBeenOutput) { sourcedVersionDebugSuppressMap.insert(sourceID, headerType); - senderString = uuidStringWithoutCurlyBraces(sourceID.toString()); + senderString = uuidStringWithoutCurlyBraces(sourceID); } } } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index cdb742a3c37..92822ae67d3 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -143,7 +143,7 @@ class LimitedNodeList : public QObject, public Dependency { #endif - PacketReceiver& getPacketReceiver() { return *_packetReceiver; } + PacketReceiver& getPacketReceiver(); virtual bool isDomainServer() const { return true; } virtual QUuid getDomainUUID() const { assert(false); return QUuid(); } diff --git a/libraries/networking/src/NodePermissions.cpp b/libraries/networking/src/NodePermissions.cpp index 8a23c7dbd31..f29cbc60cc8 100644 --- a/libraries/networking/src/NodePermissions.cpp +++ b/libraries/networking/src/NodePermissions.cpp @@ -32,10 +32,10 @@ size_t std::hash::operator()(const NodePermissionsKey& key) } -NodePermissionsKey NodePermissions::standardNameLocalhost = NodePermissionsKey("localhost", 0); -NodePermissionsKey NodePermissions::standardNameLoggedIn = NodePermissionsKey("logged-in", 0); -NodePermissionsKey NodePermissions::standardNameAnonymous = NodePermissionsKey("anonymous", 0); -NodePermissionsKey NodePermissions::standardNameFriends = NodePermissionsKey("friends", 0); +NodePermissionsKey NodePermissions::standardNameLocalhost = NodePermissionsKey("localhost", QUuid()); +NodePermissionsKey NodePermissions::standardNameLoggedIn = NodePermissionsKey("logged-in", QUuid()); +NodePermissionsKey NodePermissions::standardNameAnonymous = NodePermissionsKey("anonymous", QUuid()); +NodePermissionsKey NodePermissions::standardNameFriends = NodePermissionsKey("friends", QUuid()); QStringList NodePermissions::standardNames = QList() << NodePermissions::standardNameLocalhost.first diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 782c40609de..c8dbaf41ca4 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -30,7 +30,7 @@ #include "NetworkLogging.h" #include "NodeList.h" -bool ResourceCacheSharedItems::appendRequest(QWeakPointer resource, float priority) { +bool ResourceCacheSharedItems::appendRequest(std::weak_ptr resource, float priority) { Lock lock(_mutex); if ((uint32_t)_loadingRequests.size() < _requestLimit) { _loadingRequests.append({ resource, priority }); @@ -51,11 +51,11 @@ uint32_t ResourceCacheSharedItems::getRequestLimit() const { return _requestLimit; } -QList> ResourceCacheSharedItems::getPendingRequests() const { - QList> result; +QList> ResourceCacheSharedItems::getPendingRequests() const { + QList> result; Lock lock(_mutex); - foreach (QWeakPointer resource, _pendingRequests) { + foreach (std::weak_ptr resource, _pendingRequests) { auto locked = resource.lock(); if (locked) { result.append(locked); @@ -70,8 +70,8 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const { return _pendingRequests.size(); } -QList, float>> ResourceCacheSharedItems::getLoadingRequests() const { - QList, float>> result; +QList, float>> ResourceCacheSharedItems::getLoadingRequests() const { + QList, float>> result; Lock lock(_mutex); foreach(auto resourcePair, _loadingRequests) { @@ -89,16 +89,16 @@ uint32_t ResourceCacheSharedItems::getLoadingRequestsCount() const { return _loadingRequests.size(); } -void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { +void ResourceCacheSharedItems::removeRequest(std::weak_ptr resource) { Lock lock(_mutex); // resource can only be removed if it still has a ref-count, as // QWeakPointer has no operator== implementation for two weak ptrs, so // manually loop in case resource has been freed. for (int i = 0; i < _loadingRequests.size();) { - auto request = _loadingRequests.at(i).first; + auto request = _loadingRequests.at(i).first.lock(); // Clear our resource and any freed resources - if (!request || request.toStrongRef().data() == resource.toStrongRef().data()) { + if (!request || request.get() == resource.lock().get()) { _loadingRequests.removeAt(i); continue; } @@ -106,11 +106,11 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { } } -std::pair, float> ResourceCacheSharedItems::getHighestPendingRequest() { +std::pair, float> ResourceCacheSharedItems::getHighestPendingRequest() { // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; - QSharedPointer highestResource; + std::shared_ptr highestResource; Lock lock(_mutex); bool currentHighestIsFile = false; @@ -162,7 +162,7 @@ void ScriptableResourceCache::updateTotalSize(const qint64& deltaSize) { _resourceCache->updateTotalSize(deltaSize); } -ScriptableResource* ScriptableResourceCache::prefetch(const QUrl& url, void* extra, size_t extraHash) { +ScriptableResource* ScriptableResourceCache::prefetch(const QUrl& url, void* extra, ulong extraHash) { return _resourceCache->prefetch(url, extra, extraHash); } @@ -215,14 +215,14 @@ void ScriptableResource::disconnectHelper() { } } -ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra, size_t extraHash) { +ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra, ulong extraHash) { ScriptableResource* result = nullptr; - if (QThread::currentThread() != thread()) { + if (QThread::currentThread() != this->thread()) { // Must be called in thread to ensure getResource returns a valid pointer BLOCKING_INVOKE_METHOD(this, "prefetch", - Q_RETURN_ARG(ScriptableResource*, result), - Q_ARG(QUrl, url), Q_ARG(void*, extra), Q_ARG(size_t, extraHash)); + Q_GENERIC_RETURN_ARG(ScriptableResource*, result), + Q_GENERIC_ARG(QUrl, url), Q_GENERIC_ARG(void*, extra), Q_GENERIC_ARG(ulong, extraHash)); return result; } @@ -237,16 +237,16 @@ ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra, size_t result->finished(!resource->_failedToLoad); } else { result->_progressConnection = connect( - resource.data(), &Resource::onProgress, + resource.get(), &Resource::onProgress, result, &ScriptableResource::progressChanged); result->_loadingConnection = connect( - resource.data(), &Resource::loading, + resource.get(), &Resource::loading, result, &ScriptableResource::loadingChanged); result->_loadedConnection = connect( - resource.data(), &Resource::loaded, + resource.get(), &Resource::loaded, result, &ScriptableResource::loadedChanged); result->_finishedConnection = connect( - resource.data(), &Resource::finished, + resource.get(), &Resource::finished, result, &ScriptableResource::finished); } @@ -302,7 +302,7 @@ void ResourceCache::refreshAll() { clearUnusedResources(); resetUnusedResourceCounter(); - QHash>> allResources; + QHash>> allResources; { QReadLocker locker(&_resourcesLock); allResources = _resources; @@ -325,7 +325,7 @@ QVariantList ResourceCache::getResourceList() { if (QThread::currentThread() != thread()) { // NOTE: invokeMethod does not allow a const QObject* BLOCKING_INVOKE_METHOD(this, "getResourceList", - Q_RETURN_ARG(QVariantList, list)); + Q_GENERIC_RETURN_ARG(QVariantList, list)); } else { QList resources; { @@ -351,8 +351,8 @@ void ResourceCache::setRequestLimit(uint32_t limit) { } } -QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& fallback, void* extra, size_t extraHash) { - QSharedPointer resource; +std::shared_ptr ResourceCache::getResource(const QUrl& url, const QUrl& fallback, void* extra, size_t extraHash) { + std::shared_ptr resource; { QWriteLocker locker(&_resourcesLock); auto& resourcesWithExtraHash = _resources[url]; @@ -367,10 +367,9 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& resource = createResourceCopy(oldResource); resource->setExtra(extra); resource->setExtraHash(extraHash); - resource->setSelf(resource); resource->setCache(this); resource->moveToThread(qApp->thread()); - connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); + connect(resource.get(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); resourcesWithExtraHash.insert(extraHash, resource); resource->ensureLoading(); } @@ -388,10 +387,9 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& resource = createResource(url); resource->setExtra(extra); resource->setExtraHash(extraHash); - resource->setSelf(resource); resource->setCache(this); resource->moveToThread(qApp->thread()); - connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); + connect(resource.get(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); { QWriteLocker locker(&_resourcesLock); _resources[url].insert(extraHash, resource); @@ -410,7 +408,7 @@ void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { resetUnusedResourceCounter(); } -void ResourceCache::addUnusedResource(const QSharedPointer& resource) { +void ResourceCache::addUnusedResource(const std::shared_ptr& resource) { // If it doesn't fit or its size is unknown, remove it from the cache. if (resource->getBytes() == 0 || resource->getBytes() > _unusedResourcesMaxSize) { resource->setCache(nullptr); @@ -431,7 +429,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resetUnusedResourceCounter(); } -void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { +void ResourceCache::removeUnusedResource(const std::shared_ptr& resource) { QWriteLocker locker(&_unusedResourcesLock); if (_unusedResources.contains(resource->getLRUKey())) { _unusedResources.remove(resource->getLRUKey()); @@ -447,7 +445,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { while (!_unusedResources.empty() && _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { // unload the oldest resource - QMap >::iterator it = _unusedResources.begin(); + QMap >::iterator it = _unusedResources.begin(); it.value()->setCache(nullptr); auto size = it.value()->getBytes(); @@ -466,7 +464,7 @@ void ResourceCache::clearUnusedResources() { // list on destruction, so keep clearing until there are no references left QWriteLocker locker(&_unusedResourcesLock); while (!_unusedResources.isEmpty()) { - foreach (const QSharedPointer& resource, _unusedResources) { + foreach (const std::shared_ptr& resource, _unusedResources) { resource->setCache(nullptr); } _unusedResources.clear(); @@ -519,7 +517,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) { emit dirty(); } -QList, float>> ResourceCache::getLoadingRequests() { +QList, float>> ResourceCache::getLoadingRequests() { return DependencyManager::get()->getLoadingRequests(); } @@ -531,8 +529,8 @@ uint32_t ResourceCache::getLoadingRequestCount() { return DependencyManager::get()->getLoadingRequestsCount(); } -bool ResourceCache::attemptRequest(QSharedPointer resource, float priority) { - Q_ASSERT(!resource.isNull()); +bool ResourceCache::attemptRequest(std::shared_ptr resource, float priority) { + Q_ASSERT(resource); auto sharedItems = DependencyManager::get(); if (sharedItems->appendRequest(resource, priority)) { @@ -542,7 +540,7 @@ bool ResourceCache::attemptRequest(QSharedPointer resource, float prio return false; } -void ResourceCache::requestCompleted(QWeakPointer resource) { +void ResourceCache::requestCompleted(std::weak_ptr resource) { auto sharedItems = DependencyManager::get(); sharedItems->removeRequest(resource); @@ -563,6 +561,7 @@ static int requestID = 0; Resource::Resource(const Resource& other) : QObject(), + std::enable_shared_from_this(), _url(other._url), _effectiveBaseURL(other._effectiveBaseURL), _activeUrl(other._activeUrl), @@ -577,6 +576,7 @@ Resource::Resource(const Resource& other) : _bytes(other._bytes), _requestID(++requestID), _extraHash(other._extraHash) { + // TODO: should we add an assert here to make sure this gets deleted on correct thread? if (!other._loaded) { _startedLoading = false; } @@ -591,11 +591,15 @@ Resource::Resource(const QUrl& url) : } Resource::~Resource() { +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + _wasDeleted = true; +#endif + Q_ASSERT(QThread::currentThread() == thread()); if (_request) { _request->disconnect(this); _request->deleteLater(); _request = nullptr; - ResourceCache::requestCompleted(_self); + ResourceCache::requestCompleted(weak_from_this()); } } @@ -637,13 +641,15 @@ void Resource::refresh() { _request->disconnect(this); _request->deleteLater(); _request = nullptr; - ResourceCache::requestCompleted(_self); + ResourceCache::requestCompleted(weak_from_this()); } _activeUrl = _url; init(); ensureLoading(); - emit onRefresh(); + if (!_isScheduledForDeletion) { + emit onRefresh(); + } } void Resource::allReferencesCleared() { @@ -654,8 +660,7 @@ void Resource::allReferencesCleared() { if (_cache && isCacheable()) { // create and reinsert new shared pointer - QSharedPointer self(this, &Resource::deleter); - setSelf(self); + std::shared_ptr self(this, Resource::sharedPtrDeleter); reinsert(); // add to the unused list @@ -667,6 +672,14 @@ void Resource::allReferencesCleared() { _cache->resetTotalResourceCounter(); } + if (_request) { + _request->disconnect(this); + _request->deleteLater(); + _request = nullptr; + ResourceCache::requestCompleted(weak_from_this()); + } + _isScheduledForDeletion = true; + disconnect(); deleteLater(); } } @@ -718,8 +731,11 @@ void Resource::attemptRequest() { << "- retrying asset load - attempt" << _attempts << " of " << MAX_ATTEMPTS; } - auto self = _self.lock(); + auto self = weak_from_this().lock(); if (self) { +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + Q_ASSERT(!_wasDeleted); +#endif ResourceCache::attemptRequest(self); } } @@ -731,7 +747,9 @@ void Resource::finishedLoading(bool success) { } else { _failedToLoad = true; } - emit finished(success); + if (!_isScheduledForDeletion) { + emit finished(success); + } } void Resource::setSize(const qint64& bytes) { @@ -741,7 +759,7 @@ void Resource::setSize(const qint64& bytes) { void Resource::reinsert() { QWriteLocker locker(&_cache->_resourcesLock); - _cache->_resources[_url].insert(_extraHash, _self); + _cache->_resources[_url].insert(_extraHash, weak_from_this()); } @@ -758,7 +776,7 @@ void Resource::makeRequest() { this, _activeUrl, true, -1, "Resource::makeRequest"); if (!_request) { - ResourceCache::requestCompleted(_self); + ResourceCache::requestCompleted(weak_from_this()); finishedLoading(false); PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID)); return; @@ -785,6 +803,15 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota } void Resource::handleReplyFinished() { + // Make sure we keep the Resource alive here + auto self = weak_from_this().lock(); + if (!self) { + // Make sure the resource wasn't deleted yet, and it's just scheduled for deletion or pointer has expired. +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + Q_ASSERT(!_wasDeleted); +#endif + } + if (!_request || _request != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. qWarning(networking) << "Received signal Resource::handleReplyFinished from ResourceRequest that is not the current" @@ -793,7 +820,10 @@ void Resource::handleReplyFinished() { { "from_cache", false }, { "size_mb", _bytesTotal / 1000000.0 } }); - ResourceCache::requestCompleted(_self); + // TODO: should we still emit requestCompleted if resource's shared_ptr has expired? + if (self) { + ResourceCache::requestCompleted(weak_from_this()); + } return; } @@ -802,9 +832,7 @@ void Resource::handleReplyFinished() { { "size_mb", _bytesTotal / 1000000.0 } }); - // Make sure we keep the Resource alive here - auto self = _self.lock(); - ResourceCache::requestCompleted(_self); + ResourceCache::requestCompleted(weak_from_this()); auto result = _request->getResult(); if (result == ResourceRequest::Success) { @@ -823,10 +851,16 @@ void Resource::handleReplyFinished() { } setSize(_bytesTotal); - emit loaded(data); - downloadFinished(data); + // TODO: should we emit these after pointer has expired or delete_later() was called? + if (self) { + emit loaded(data); + downloadFinished(data); + } } else { - handleFailedRequest(result); + // TODO: should we emit these after pointer has expired or delete_later() was called? + if (self) { + handleFailedRequest(result); + } } _request->disconnect(this); @@ -867,7 +901,9 @@ bool Resource::handleFailedRequest(ResourceRequest::Result result) { qCDebug(networking) << "Error loading:" << metaEnum.valueToKey(result) << "resource:" << _url.toString(); auto error = (result == ResourceRequest::Timeout) ? QNetworkReply::TimeoutError : QNetworkReply::UnknownNetworkError; - emit failed(error); + if (!_isScheduledForDeletion) { + emit failed(error); + } willRetry = false; finishedLoading(false); break; @@ -876,6 +912,6 @@ bool Resource::handleFailedRequest(ResourceRequest::Result result) { return willRetry; } -uint qHash(const QPointer& value, uint seed) { +size_t qHash(const QPointer& value, size_t seed) { return qHash(value.data(), seed); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index d2687f0964d..031cdef815c 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include @@ -67,14 +65,14 @@ class ResourceCacheSharedItems : public Dependency { using Lock = std::unique_lock; public: - bool appendRequest(QWeakPointer newRequest, float priority); - void removeRequest(QWeakPointer doneRequest); + bool appendRequest(std::weak_ptr newRequest, float priority); + void removeRequest(std::weak_ptr doneRequest); void setRequestLimit(uint32_t limit); uint32_t getRequestLimit() const; - QList> getPendingRequests() const; - std::pair, float> getHighestPendingRequest(); + QList> getPendingRequests() const; + std::pair, float> getHighestPendingRequest(); uint32_t getPendingRequestsCount() const; - QList, float>> getLoadingRequests() const; + QList, float>> getLoadingRequests() const; uint32_t getLoadingRequestsCount() const; void clear(); @@ -82,8 +80,8 @@ class ResourceCacheSharedItems : public Dependency { ResourceCacheSharedItems() = default; mutable Mutex _mutex; - QList> _pendingRequests; - QList, float>> _loadingRequests; + QList> _pendingRequests; + QList, float>> _loadingRequests; const uint32_t DEFAULT_REQUEST_LIMIT = 10; uint32_t _requestLimit { DEFAULT_REQUEST_LIMIT }; }; @@ -142,7 +140,7 @@ class ScriptableResource : public QObject { const QUrl& getURL() const { return _url; } int getState() const { return (int)_state; } - const QSharedPointer& getResource() const { return _resource; } + const std::shared_ptr& getResource() const { return _resource; } bool isInScript() const; void setInScript(bool isInScript); @@ -180,7 +178,7 @@ private slots: friend class ResourceCache; // Holds a ref to the resource to keep it in scope - QSharedPointer _resource; + std::shared_ptr _resource; QMetaObject::Connection _progressConnection; QMetaObject::Connection _loadingConnection; @@ -217,7 +215,7 @@ class ResourceCache : public QObject { void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } - static QList, float>> getLoadingRequests(); + static QList, float>> getLoadingRequests(); static uint32_t getPendingRequestCount(); static uint32_t getLoadingRequestCount(); @@ -238,7 +236,7 @@ protected slots: // Prefetches a resource to be held by the ScriptEngine. // Left as a protected member so subclasses can overload prefetch // and delegate to it (see TextureCache::prefetch(const QUrl&, int). - ScriptableResource* prefetch(const QUrl& url, void* extra, size_t extraHash); + ScriptableResource* prefetch(const QUrl& url, void* extra, ulong extraHash); // FIXME: The return type is not recognized by JavaScript. /// Loads a resource from the specified URL and returns it. @@ -246,8 +244,8 @@ protected slots: /// returns an empty smart pointer and loads its asynchronously. /// \param fallback a fallback URL to load if the desired one is unavailable // FIXME: std::numeric_limits::max() could be a valid extraHash - QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl()) { return getResource(url, fallback, nullptr, std::numeric_limits::max()); } - QSharedPointer getResource(const QUrl& url, const QUrl& fallback, void* extra, size_t extraHash); + std::shared_ptr getResource(const QUrl& url, const QUrl& fallback = QUrl()) { return getResource(url, fallback, nullptr, std::numeric_limits::max()); } + std::shared_ptr getResource(const QUrl& url, const QUrl& fallback, void* extra, size_t extraHash); private slots: void clearATPAssets(); @@ -261,16 +259,16 @@ private slots: Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr, std::numeric_limits::max()); } /// Creates a new resource. - virtual QSharedPointer createResource(const QUrl& url) = 0; - virtual QSharedPointer createResourceCopy(const QSharedPointer& resource) = 0; + virtual std::shared_ptr createResource(const QUrl& url) = 0; + virtual std::shared_ptr createResourceCopy(const std::shared_ptr& resource) = 0; - void addUnusedResource(const QSharedPointer& resource); - void removeUnusedResource(const QSharedPointer& resource); + void addUnusedResource(const std::shared_ptr& resource); + void removeUnusedResource(const std::shared_ptr& resource); /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue - static bool attemptRequest(QSharedPointer resource, float priority = NAN); - static void requestCompleted(QWeakPointer resource); + static bool attemptRequest(std::shared_ptr resource, float priority = NAN); + static void requestCompleted(std::weak_ptr resource); static bool attemptHighestPriorityRequest(); private: @@ -285,7 +283,7 @@ private slots: void resetResourceCounters(); // Resources - QHash>> _resources; + QHash>> _resources; QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; int _lastLRUKey = 0; @@ -293,7 +291,7 @@ private slots: std::atomic _totalResourcesSize { 0 }; // Cached resources - QMap> _unusedResources; + QMap> _unusedResources; QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; @@ -383,7 +381,7 @@ class ScriptableResourceCache : public QObject { Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr, std::numeric_limits::max()); } // FIXME: This function variation shouldn't be in the API. - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, void* extra, size_t extraHash); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, void* extra, ulong extraHash); signals: @@ -407,7 +405,7 @@ class ScriptableResourceCache : public QObject { }; /// Base class for resources. -class Resource : public QObject { +class Resource : public QObject, public std::enable_shared_from_this { Q_OBJECT public: @@ -451,10 +449,9 @@ class Resource : public QObject { /// Refreshes the resource. virtual void refresh(); - void setSelf(const QWeakPointer& self) { _self = self; } - void setCache(ResourceCache* cache) { _cache = cache; } + static void sharedPtrDeleter(Resource *object) { object->deleter(); }; virtual void deleter() { allReferencesCleared(); } const QUrl& getURL() const { return _url; } @@ -519,6 +516,13 @@ protected slots: /// Return true if the resource will be retried virtual bool handleFailedRequest(ResourceRequest::Result result); + // Safeguard for debugging. +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + std::atomic _wasDeleted{ false }; +#endif + + std::atomic_bool _isScheduledForDeletion{ false }; + QUrl _url; QUrl _effectiveBaseURL { _url }; QUrl _activeUrl; @@ -533,7 +537,6 @@ protected slots: bool _loaded = false; QHash, std::function> _loadPriorityOperators; - QWeakPointer _self; QPointer _cache; qint64 _bytesReceived { 0 }; diff --git a/libraries/networking/src/SocketType.h b/libraries/networking/src/SocketType.h index 33da7c4ea03..30432eb2381 100644 --- a/libraries/networking/src/SocketType.h +++ b/libraries/networking/src/SocketType.h @@ -13,6 +13,7 @@ #ifndef overte_SocketType_h #define overte_SocketType_h +#include /// @addtogroup Networking /// @{ diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index 8e4e6b8fb57..4b78cc5fa29 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -12,6 +12,8 @@ #include "UserActivityLoggerScriptingInterface.h" #include "UserActivityLogger.h" +#include + void UserActivityLoggerScriptingInterface::enabledEdit() { doLogAction("enabled_edit"); } diff --git a/libraries/networking/src/udt/NetworkSocket.cpp b/libraries/networking/src/udt/NetworkSocket.cpp index 298455e33ce..c846c648b22 100644 --- a/libraries/networking/src/udt/NetworkSocket.cpp +++ b/libraries/networking/src/udt/NetworkSocket.cpp @@ -8,6 +8,8 @@ #include "NetworkSocket.h" +#include + #include "../NetworkLogging.h" @@ -23,7 +25,7 @@ NetworkSocket::NetworkSocket(QObject* parent) : connect(&_udpSocket, &QUdpSocket::readyRead, this, &NetworkSocket::readyRead); connect(&_udpSocket, &QAbstractSocket::stateChanged, this, &NetworkSocket::onUDPStateChanged); // Use old SIGNAL/SLOT mechanism for Android builds. - connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), + connect(&_udpSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(onUDPSocketError(QAbstractSocket::SocketError))); #if defined(WEBRTC_DATA_CHANNELS) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 2221c4bf2b0..d200be9e594 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -16,6 +16,7 @@ #include #include +#include #include diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 16b46d8c165..a43f72775f3 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -807,7 +807,13 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); result.resize(length); - memcpy(result.data(), dataBytes, length * sizeof(float)); + // It does a lot of zero-length writes to nullptr for some reason. + if (length != 0) { + // These were null sometimes, so it's best to check in debug builds. + Q_ASSERT(result.data()); + Q_ASSERT(dataBytes); + memcpy(result.data(), dataBytes, length * sizeof(float)); + } return sizeof(uint16_t) + length * sizeof(float); } @@ -834,7 +840,13 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto memcpy(&length, dataBytes, sizeof(uint16_t)); dataBytes += sizeof(length); result.resize(length); - memcpy(result.data(), dataBytes, length * sizeof(QUuid)); + // It does a lot of zero-length writes to nullptr for some reason. + if (length != 0) { + // These were null sometimes, so it's best to check in debug builds. + Q_ASSERT(result.data()); + Q_ASSERT(dataBytes); + memcpy(result.data(), dataBytes, length * sizeof(QUuid)); + } return sizeof(uint16_t) + length * sizeof(QUuid); } diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index e2b27f4b268..3ede2c41e1c 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -68,7 +68,7 @@ namespace gpu { } class NetworkTexture; -using NetworkTexturePointer = QSharedPointer; +using NetworkTexturePointer = std::shared_ptr; typedef struct __GLsync *GLsync; // Stereo display functionality diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index c206d67b66c..89e639e853c 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -24,7 +24,7 @@ QStringList InputConfiguration::inputPlugins() { if (QThread::currentThread() != thread()) { QStringList result; BLOCKING_INVOKE_METHOD(this, "inputPlugins", - Q_RETURN_ARG(QStringList, result)); + Q_GENERIC_RETURN_ARG(QStringList, result)); return result; } @@ -46,7 +46,7 @@ QStringList InputConfiguration::activeInputPlugins() { if (QThread::currentThread() != thread()) { QStringList result; BLOCKING_INVOKE_METHOD(this, "activeInputPlugins", - Q_RETURN_ARG(QStringList, result)); + Q_GENERIC_RETURN_ARG(QStringList, result)); return result; } @@ -69,8 +69,8 @@ QString InputConfiguration::configurationLayout(QString pluginName) { if (QThread::currentThread() != thread()) { QString result; BLOCKING_INVOKE_METHOD(this, "configurationLayout", - Q_RETURN_ARG(QString, result), - Q_ARG(QString, pluginName)); + Q_GENERIC_RETURN_ARG(QString, result), + Q_GENERIC_ARG(QString, pluginName)); return result; } @@ -86,8 +86,8 @@ QString InputConfiguration::configurationLayout(QString pluginName) { void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "setConfigurationSettings", - Q_ARG(QJsonObject, configurationSettings), - Q_ARG(QString, pluginName)); + Q_GENERIC_ARG(QJsonObject, configurationSettings), + Q_GENERIC_ARG(QString, pluginName)); return; } @@ -102,8 +102,8 @@ QJsonObject InputConfiguration::configurationSettings(QString pluginName) { if (QThread::currentThread() != thread()) { QJsonObject result; BLOCKING_INVOKE_METHOD(this, "configurationSettings", - Q_RETURN_ARG(QJsonObject, result), - Q_ARG(QString, pluginName)); + Q_GENERIC_RETURN_ARG(QJsonObject, result), + Q_GENERIC_ARG(QString, pluginName)); return result; } @@ -133,7 +133,7 @@ bool InputConfiguration::uncalibratePlugin(QString pluginName) { if (QThread::currentThread() != thread()) { bool result; BLOCKING_INVOKE_METHOD(this, "uncalibratePlugin", - Q_ARG(bool, result)); + Q_GENERIC_ARG(bool, result)); return result; } diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp index 0925efa0561..b5d98c36d4d 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp @@ -804,15 +804,19 @@ std::pair> NetworkMaterialResource } NetworkMaterialResourcePointer MaterialCache::getMaterial(const QUrl& url) { - return ResourceCache::getResource(url).staticCast(); + auto networkMaterialResource = std::dynamic_pointer_cast(getResource(url)); + Q_ASSERT(networkMaterialResource); + return networkMaterialResource; } -QSharedPointer MaterialCache::createResource(const QUrl& url) { - return QSharedPointer(new NetworkMaterialResource(url), &Resource::deleter); +std::shared_ptr MaterialCache::createResource(const QUrl& url) { + return std::shared_ptr(new NetworkMaterialResource(url), Resource::sharedPtrDeleter); } -QSharedPointer MaterialCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkMaterialResource(*resource.staticCast()), &Resource::deleter); +std::shared_ptr MaterialCache::createResourceCopy(const std::shared_ptr& resource) { + auto networkMaterialResource = std::dynamic_pointer_cast(resource); + Q_ASSERT(networkMaterialResource); + return std::shared_ptr(new NetworkMaterialResource(*networkMaterialResource), Resource::sharedPtrDeleter); } NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : @@ -1130,13 +1134,17 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { bool NetworkMaterial::isMissingTexture() { for (auto& networkTexture : _textures) { - auto& texture = networkTexture.second.texture; + auto texture = networkTexture.second.texture; if (!texture) { continue; } // Failed texture downloads need to be considered as 'loaded' // or the object will never fade in - bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined()); + auto gpuTexture = texture->getGPUTexture(); + if (gpuTexture) { + Q_ASSERT(!gpuTexture->wasDeleted); + } + bool finished = texture->isFailed() || (texture->isLoaded() && gpuTexture && gpuTexture->isDefined()); if (!finished) { return true; } diff --git a/libraries/procedural/src/procedural/ProceduralMaterialCache.h b/libraries/procedural/src/procedural/ProceduralMaterialCache.h index 90d2a6964dc..f9e1c6f4cdb 100644 --- a/libraries/procedural/src/procedural/ProceduralMaterialCache.h +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.h @@ -51,6 +51,7 @@ class NetworkMaterial : public graphics::Material { } }; using Textures = std::unordered_map; + // TODO: investigate if this could pass reference instead Textures getTextures() { return _textures; } protected: @@ -202,6 +203,7 @@ class NetworkMaterialResource : public Resource { public: NetworkMaterialResource() : Resource() {} NetworkMaterialResource(const QUrl& url); + virtual ~NetworkMaterialResource() {} QString getType() const override { return "NetworkMaterial"; } @@ -227,7 +229,7 @@ class NetworkMaterialResource : public Resource { static std::pair> parseJSONMaterial(const QJsonValue& materialJSONValue, const QUrl& baseUrl = QUrl()); }; -using NetworkMaterialResourcePointer = QSharedPointer; +using NetworkMaterialResourcePointer = std::shared_ptr; using MaterialMapping = std::vector>; Q_DECLARE_METATYPE(MaterialMapping) @@ -239,8 +241,8 @@ class MaterialCache : public ResourceCache, public Dependency { NetworkMaterialResourcePointer getMaterial(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; }; #endif diff --git a/libraries/procedural/src/procedural/ReferenceMaterial.h b/libraries/procedural/src/procedural/ReferenceMaterial.h index ce58e811c02..04bece16fd9 100644 --- a/libraries/procedural/src/procedural/ReferenceMaterial.h +++ b/libraries/procedural/src/procedural/ReferenceMaterial.h @@ -77,7 +77,7 @@ class ReferenceMaterial : public graphics::ProceduralMaterial { private: static std::function _unboundMaterialForUUIDOperator; std::function _materialForUUIDOperator; - mutable bool _locked { false }; + mutable std::atomic _locked { false }; graphics::MaterialPointer getMaterial() const; std::shared_ptr getNetworkMaterial() const; diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index aabe6f36ba5..a3a6ed5788f 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -10,6 +10,11 @@ #include #include +#ifdef Q_OS_WIN +#include +#endif //Q_OS_WIN +#include + #include #include #include @@ -35,6 +40,9 @@ using namespace hifi::qml; using namespace hifi::qml::impl; +// QT6TODO: Use one shared virtual pointing device, where do we put it though? +static std::shared_ptr _touchDevice; + QmlUrlValidator OffscreenSurface::validator = [](const QUrl& url) -> bool { if (url.isRelative()) { return true; @@ -92,12 +100,24 @@ void OffscreenSurface::setSharedContext(QOpenGLContext* sharedContext) { std::function OffscreenSurface::getDiscardLambda() { return [](uint32_t texture, void* fence) { - SharedObject::getTextureCache().releaseTexture({ texture, static_cast(fence) }); + SharedObject::getTextureCache().releaseTexture(TextureCache::Value(texture, static_cast(fence))); }; } OffscreenSurface::OffscreenSurface() : _sharedObject(new impl::SharedObject()) { + static std::once_flag once; + std::call_once(once, [&] { + _touchDevice = std::make_shared( + "OffscreenSurfacePointingDevice", + 1, + QInputDevice::DeviceType::AllDevices, + QPointingDevice::PointerType::AllPointerTypes, + QInputDevice::Capability::All, + 4, //maxPoints + 2 // buttonCount + ); + }); } OffscreenSurface::~OffscreenSurface() { @@ -178,7 +198,7 @@ bool OffscreenSurface::eventFilter(QObject* originalDestination, QEvent* event) QWheelEvent mappedEvent(transformedPos, wheelEvent->globalPosition(), wheelEvent->pixelDelta(), wheelEvent->angleDelta(), wheelEvent->buttons(), wheelEvent->modifiers(), wheelEvent->phase(), - wheelEvent->inverted(), wheelEvent->source()); + wheelEvent->inverted(), wheelEvent->source(), _touchDevice.get()); mappedEvent.ignore(); if (QCoreApplication::sendEvent(_sharedObject->getWindow(), &mappedEvent)) { @@ -186,19 +206,22 @@ bool OffscreenSurface::eventFilter(QObject* originalDestination, QEvent* event) } break; } - case QEvent::MouseMove: { + // QT6TODO: this may be not necessary, mouse move events were doubled with it and without it nothing seems to break. + /*case QEvent::MouseMove: { QMouseEvent* mouseEvent = static_cast(event); - QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos()); - QMouseEvent mappedEvent(mouseEvent->type(), transformedPos, mouseEvent->screenPos(), mouseEvent->button(), - mouseEvent->buttons(), mouseEvent->modifiers()); + QPointF transformedPos = mapToVirtualScreen(mouseEvent->position()); + QMouseEvent mappedEvent(mouseEvent->type(), transformedPos, mouseEvent->globalPosition(), mouseEvent->button(), + mouseEvent->buttons(), mouseEvent->modifiers(), + _touchDevice.get()); mappedEvent.ignore(); if (QCoreApplication::sendEvent(_sharedObject->getWindow(), &mappedEvent)) { return mappedEvent.isAccepted(); } break; - } + }*/ #if defined(Q_OS_ANDROID) + // QT6TODO: Cases above needed to be deleted for Qt6 due to doubled events, so maybe these are not needed too? case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: { @@ -223,7 +246,7 @@ bool OffscreenSurface::eventFilter(QObject* originalDestination, QEvent* event) Q_UNREACHABLE(); } // Same case as OffscreenUi.cpp::eventFilter: touch events are always being accepted so we now use mouse events and consider one touch, touchPoints()[0]. - QMouseEvent fakeMouseEvent(fakeMouseEventType, originalEvent->touchPoints()[0].pos(), fakeMouseButton, fakeMouseButtons, Qt::NoModifier); + QMouseEvent fakeMouseEvent(fakeMouseEventType, originalEvent->touchPoints()[0].pos(), fakeMouseButton, fakeMouseButtons, Qt::NoModifier, _touchDevice.get()); fakeMouseEvent.ignore(); if (QCoreApplication::sendEvent(_sharedObject->getWindow(), &fakeMouseEvent)) { /*qInfo() << __FUNCTION__ << "sent fake touch event:" << fakeMouseEvent.type() diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.cpp b/libraries/qml/src/qml/impl/RenderEventHandler.cpp index c2e69d5a9b2..03d46148643 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.cpp +++ b/libraries/qml/src/qml/impl/RenderEventHandler.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include "Profiling.h" @@ -60,7 +61,11 @@ RenderEventHandler::RenderEventHandler(SharedObject* shared, QThread* targetThre moveToThread(targetThread); } +// I'm not sure if several contexts can be initalized with the same shared context concurrently, so better safe than sorry. +static std::mutex renderControlInitMutex; + void RenderEventHandler::onInitalize() { + std::lock_guard lock(renderControlInitMutex); if (_shared->isQuit()) { return; } @@ -129,6 +134,10 @@ void RenderEventHandler::qmlRender(bool sceneGraphSync) { PROFILE_RANGE(render_qml_gl, __FUNCTION__); gl::globalLock(); + + _shared->_renderControl->polishItems(); + _shared->_renderControl->beginFrame(); + if (!_shared->preRender(sceneGraphSync)) { gl::globalRelease(); return; @@ -146,17 +155,10 @@ void RenderEventHandler::qmlRender(bool sceneGraphSync) { glClear(GL_COLOR_BUFFER_BIT); } else { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - _shared->setRenderTarget(_fbo, _currentSize); - - // workaround for https://highfidelity.atlassian.net/browse/BUGZ-1119 - { - // Serialize QML rendering because of a crash caused by Qt bug - // https://bugreports.qt.io/browse/QTBUG-77469 - static std::mutex qmlRenderMutex; - std::unique_lock qmlRenderLock{ qmlRenderMutex }; - _shared->_renderControl->render(); - } + _shared->setRenderTarget(texture, _currentSize); + _shared->_renderControl->render(); } + _shared->_renderControl->endFrame(); _shared->_lastRenderTime = usecTimestampNow(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, texture); @@ -166,7 +168,7 @@ void RenderEventHandler::qmlRender(bool sceneGraphSync) { // Fence will be used in another thread / context, so a flush is required glFlush(); _shared->updateTextureAndFence({ texture, fence }); - _shared->_quickWindow->resetOpenGLState(); + QQuickOpenGLUtils::resetOpenGLState(); } gl::globalRelease(); } diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index 555389c4c3a..202e47f3759 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include @@ -68,11 +70,15 @@ SharedObject::SharedObject() { // NOTE: Must be created on the main thread so that OffscreenQmlSurface can send it events // NOTE: Must be created on the rendering thread or it will refuse to render, // so we wait until after its ctor to move object/context to this thread. - QQuickWindow::setDefaultAlphaBuffer(true); + // QT6TODO: QRhi fails to initialize with setDefaultAlphaBuffer + //QQuickWindow::setDefaultAlphaBuffer(true); _quickWindow = new QQuickWindow(_renderControl); + _quickWindow->setSurfaceType(QQuickWindow::OpenGLSurface); _quickWindow->setFormat(getDefaultOpenGLSurfaceFormat()); _quickWindow->setColor(Qt::transparent); - _quickWindow->setClearBeforeRendering(true); + // QT6TODO: setClearBeforeRendering was removed, what to do about this? + // https://doc.qt.io/qt-6/quick-changes-qt6.html + //_quickWindow->setClearBeforeRendering(true); #endif @@ -113,6 +119,10 @@ SharedObject::~SharedObject() { #ifndef DISABLE_QML if (_quickWindow) { +#ifdef ENABLE_SHARED_OBJECT_EVENT_DEBUG + // Remove event filter that was installed if event debugging is enabled. + _quickWindow->removeEventFilter(&_eventDebugFilter); +#endif _quickWindow->destroy(); delete _quickWindow; _quickWindow = nullptr; @@ -290,9 +300,15 @@ void SharedObject::initializeRenderControl(QOpenGLContext* context) { qFatal("QML rendering context has no share context"); } + Q_ASSERT(context->isValid()); + #ifndef DISABLE_QML if (!nsightActive()) { - _renderControl->initialize(context); + _quickWindow->setFormat(context->format()); + _quickWindow->setGraphicsDevice(QQuickGraphicsDevice::fromOpenGLContext(context)); + bool result = _renderControl->initialize(); + Q_ASSERT(result); + Q_UNUSED(result); } #endif } @@ -308,9 +324,9 @@ void SharedObject::releaseTextureAndFence() { #endif } -void SharedObject::setRenderTarget(uint32_t fbo, const QSize& size) { +void SharedObject::setRenderTarget(uint32_t texture, const QSize& size) { #ifndef DISABLE_QML - _quickWindow->setRenderTarget(fbo, size); + _quickWindow->setRenderTarget(QQuickRenderTarget::fromOpenGLTexture(texture, size)); #endif } @@ -439,6 +455,11 @@ void SharedObject::wake() { void SharedObject::onInitialize() { #ifndef DISABLE_QML +#ifdef ENABLE_SHARED_OBJECT_EVENT_DEBUG + // Install event filter if event debugging is enabled. + _quickWindow->installEventFilter(&_eventDebugFilter); +#endif + // Associate root item with the window. _rootItem->setParentItem(_quickWindow->contentItem()); _renderControl->prepareThread(_renderThread); @@ -535,3 +556,20 @@ void SharedObject::resume() { bool SharedObject::isPaused() const { return _paused; } + +#ifdef ENABLE_SHARED_OBJECT_EVENT_DEBUG +bool SharedObjectEventDebug::eventFilter(QObject *object, QEvent *event) { + QMouseEvent *mouseEvent = dynamic_cast(event); + if (mouseEvent) { + if (mouseEvent->device()->name() == "WebEntityMouseDevice") { + qDebug() << "SharedObjectEventDebug QMouseEevent: " << mouseEvent << mouseEvent->buttons(); + } + //qDebug() << "SharedObjectEventDebug QMouseEevent: " << mouseEvent << mouseEvent->buttons(); + } + QTouchEvent *touchEvent = dynamic_cast(event); + if (touchEvent) { + qDebug() << "SharedObjectEventDebug QTouchEvent: " << touchEvent; + } + return false; +}; +#endif diff --git a/libraries/qml/src/qml/impl/SharedObject.h b/libraries/qml/src/qml/impl/SharedObject.h index 4f287471e82..90178e5eb22 100644 --- a/libraries/qml/src/qml/impl/SharedObject.h +++ b/libraries/qml/src/qml/impl/SharedObject.h @@ -32,6 +32,27 @@ namespace impl { class RenderControl; class RenderEventHandler; +// Uncomment to show events received by the shared object. +//#define ENABLE_SHARED_OBJECT_EVENT_DEBUG + +/** + * @brief A class used for debugging input events being sent to shared object. + * + **/ + +#ifdef ENABLE_SHARED_OBJECT_EVENT_DEBUG +class SharedObjectEventDebug : public QObject { + Q_OBJECT +public: + bool eventFilter(QObject *object, QEvent *event); +}; +#endif + +/** + * @brief A class containing virtual Qt window for webentiies and in-game overlay. + * + **/ + class SharedObject : public QObject { Q_OBJECT @@ -73,7 +94,9 @@ class SharedObject : public QObject { // Called by the render event handler, from the render thread void initializeRenderControl(QOpenGLContext* context); void releaseTextureAndFence(); - void setRenderTarget(uint32_t fbo, const QSize& size); + + // NOTE: On Qt5 this took an FBO handle, on Qt6 it takes a texture handle + void setRenderTarget(uint32_t texture, const QSize& size); QQmlEngine* acquireEngine(OffscreenSurface* surface); void releaseEngine(QQmlEngine* engine); @@ -98,6 +121,10 @@ class SharedObject : public QObject { mutable QMutex _mutex; QWaitCondition _cond; +#ifdef ENABLE_SHARED_OBJECT_EVENT_DEBUG + SharedObjectEventDebug _eventDebugFilter; +#endif + #ifndef DISABLE_QML QWindow* _proxyWindow { nullptr }; RenderControl* _renderControl { nullptr }; diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index 285b5b7acff..933eb018e97 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -47,18 +47,23 @@ NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { if (QThread::currentThread() != thread()) { NetworkClipLoaderPointer result; BLOCKING_INVOKE_METHOD(this, "getClipLoader", - Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url)); + Q_GENERIC_RETURN_ARG(NetworkClipLoaderPointer, result), Q_GENERIC_ARG(const QUrl&, url)); return result; } - return getResource(url).staticCast(); + auto clipLoader = std::dynamic_pointer_cast(getResource(url)); + Q_ASSERT(clipLoader); + + return clipLoader; } -QSharedPointer ClipCache::createResource(const QUrl& url) { +std::shared_ptr ClipCache::createResource(const QUrl& url) { qCDebug(recordingLog) << "Loading recording at" << url; - return QSharedPointer(new NetworkClipLoader(url), &Resource::deleter); + return std::shared_ptr(new NetworkClipLoader(url), Resource::sharedPtrDeleter); } -QSharedPointer ClipCache::createResourceCopy(const QSharedPointer& resource) { - return QSharedPointer(new NetworkClipLoader(*resource.staticCast()), &Resource::deleter); +std::shared_ptr ClipCache::createResourceCopy(const std::shared_ptr& resource) { + auto clipLoader = std::dynamic_pointer_cast(resource); + Q_ASSERT(clipLoader); + return std::shared_ptr(new NetworkClipLoader(*clipLoader), Resource::sharedPtrDeleter); } \ No newline at end of file diff --git a/libraries/recording/src/recording/ClipCache.h b/libraries/recording/src/recording/ClipCache.h index e909af7e70a..1d780be8da8 100644 --- a/libraries/recording/src/recording/ClipCache.h +++ b/libraries/recording/src/recording/ClipCache.h @@ -36,6 +36,7 @@ class NetworkClipLoader : public Resource { public: NetworkClipLoader(const QUrl& url); NetworkClipLoader(const NetworkClipLoader& other) : Resource(other), _clip(other._clip) {} + virtual ~NetworkClipLoader() {} virtual void downloadFinished(const QByteArray& data) override; ClipPointer getClip() { return _clip; } @@ -48,7 +49,7 @@ class NetworkClipLoader : public Resource { const NetworkClip::Pointer _clip; }; -using NetworkClipLoaderPointer = QSharedPointer; +using NetworkClipLoaderPointer = std::shared_ptr; class ClipCache : public ResourceCache, public Dependency { Q_OBJECT @@ -58,8 +59,8 @@ public slots: NetworkClipLoaderPointer getClipLoader(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url) override; - QSharedPointer createResourceCopy(const QSharedPointer& resource) override; + virtual std::shared_ptr createResource(const QUrl& url) override; + std::shared_ptr createResourceCopy(const std::shared_ptr& resource) override; private: ClipCache(QObject* parent = nullptr); diff --git a/libraries/recording/src/recording/RecordingScriptingInterface.cpp b/libraries/recording/src/recording/RecordingScriptingInterface.cpp index a50453bb697..68f6f55e28e 100644 --- a/libraries/recording/src/recording/RecordingScriptingInterface.cpp +++ b/libraries/recording/src/recording/RecordingScriptingInterface.cpp @@ -90,7 +90,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, const Script // hold a strong pointer to the loading clip so that it has a chance to load _clipLoaders.insert(clipLoader); - auto weakClipLoader = clipLoader.toWeakRef(); + std::weak_ptr weakClipLoader = clipLoader; auto manager = callback.engine()->manager(); if (!manager) { @@ -99,10 +99,11 @@ void RecordingScriptingInterface::loadRecording(const QString& url, const Script } // when clip loaded, call the callback with the URL and success boolean - connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, manager, + connect(clipLoader.get(), &recording::NetworkClipLoader::clipLoaded, manager, [this, weakClipLoader, url, callback]() mutable { - if (auto clipLoader = weakClipLoader.toStrongRef()) { + if (auto clipLoader = weakClipLoader.lock()) { + Q_ASSERT(clipLoader); qCDebug(scriptengine) << "Loaded recording from" << url; playClip(clipLoader, url, callback); @@ -113,7 +114,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, const Script }); // when clip load fails, call the callback with the URL and failure boolean - connect(clipLoader.data(), &recording::NetworkClipLoader::failed, manager, + connect(clipLoader.get(), &recording::NetworkClipLoader::failed, manager, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable { qCDebug(scriptengine) << "Failed to load recording from\"" << url << '"'; @@ -123,7 +124,8 @@ void RecordingScriptingInterface::loadRecording(const QString& url, const Script callback.call(ScriptValue(), args); } - if (auto clipLoader = weakClipLoader.toStrongRef()) { + if (auto clipLoader = weakClipLoader.lock()) { + Q_ASSERT(clipLoader); // drop out strong pointer to this clip so it is cleaned up _clipLoaders.remove(clipLoader); } @@ -151,7 +153,7 @@ void RecordingScriptingInterface::setPlayerAudioOffset(float audioOffset) { void RecordingScriptingInterface::setPlayerTime(float time) { if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "setPlayerTime", Q_ARG(float, time)); + BLOCKING_INVOKE_METHOD(this, "setPlayerTime", Q_GENERIC_ARG(float, time)); return; } diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 971d09fbb65..8ece39525ed 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -5,7 +5,7 @@ set(TARGET_NAME render-utils) generate_render_pipelines() # pull in the resources.qrc file -qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") +qt6_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Gui Network Qml Quick) target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils/src") target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/libraries/render-utils/src") diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 9debb203ec8..b555c45fa74 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -248,7 +248,7 @@ class DebugAmbientOcclusionConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) - Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) public: DebugAmbientOcclusionConfig() : render::Job::Config(false) {} diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index b99e96a31cb..d414bc83a27 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -146,7 +146,7 @@ class AntialiasingConfig : public render::Job::Config { Q_PROPERTY(bool fxaaOnOff READ debugFXAA WRITE setDebugFXAA NOTIFY dirty) Q_PROPERTY(float debugShowVelocityThreshold MEMBER debugShowVelocityThreshold NOTIFY dirty) Q_PROPERTY(bool showCursorPixel MEMBER showCursorPixel NOTIFY dirty) - Q_PROPERTY(glm::vec2 debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> debugCursorTexcoord MEMBER debugCursorTexcoord NOTIFY dirty) Q_PROPERTY(float debugOrbZoom MEMBER debugOrbZoom NOTIFY dirty) Q_PROPERTY(bool showClosestFragment MEMBER showClosestFragment NOTIFY dirty) diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h index 70a33b27eba..517218c8cd9 100644 --- a/libraries/render-utils/src/HazeStage.h +++ b/libraries/render-utils/src/HazeStage.h @@ -28,10 +28,10 @@ class HazeStageSetup : public render::StageSetup { class FetchHazeConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(glm::vec3 hazeColor MEMBER hazeColor WRITE setHazeColor NOTIFY dirty); + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> hazeColor MEMBER hazeColor WRITE setHazeColor NOTIFY dirty); Q_PROPERTY(float hazeGlareAngle MEMBER hazeGlareAngle WRITE setHazeGlareAngle NOTIFY dirty); - Q_PROPERTY(glm::vec3 hazeGlareColor MEMBER hazeGlareColor WRITE setHazeGlareColor NOTIFY dirty); + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> hazeGlareColor MEMBER hazeGlareColor WRITE setHazeGlareColor NOTIFY dirty); Q_PROPERTY(float hazeBaseReference MEMBER hazeBaseReference WRITE setHazeBaseReference NOTIFY dirty); Q_PROPERTY(bool isHazeActive MEMBER isHazeActive WRITE setHazeActive NOTIFY dirty); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9784ba13460..63345dd73bf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1399,7 +1399,7 @@ QStringList Model::getJointNames() const { if (QThread::currentThread() != thread()) { QStringList result; BLOCKING_INVOKE_METHOD(const_cast(this), "getJointNames", - Q_RETURN_ARG(QStringList, result)); + Q_GENERIC_RETURN_ARG(QStringList, result)); return result; } return isLoaded() ? getHFMModel().getJointNames() : QStringList(); @@ -1783,7 +1783,7 @@ void Model::applyMaterialMapping() { if (networkMaterialResource->isLoaded()) { materialLoaded(); } else { - connect(networkMaterialResource.data(), &Resource::finished, materialLoaded); + connect(networkMaterialResource.get(), &Resource::finished, materialLoaded); } } } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index cf934f6023b..e72d9cbd8fd 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -164,10 +164,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial if (itr != textureMaps.end()) { if (itr->second->isDefined()) { material->resetOpacityMap(); - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialAlbedo, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::ALBEDO_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -188,10 +190,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialMetallic, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialMetallic, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::METALLIC_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -210,10 +214,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialRoughness, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialRoughness, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::ROUGHNESS_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -232,10 +238,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialNormal, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::NORMAL_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -254,10 +262,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialOcclusion, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialOcclusion, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::OCCLUSION_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -276,10 +286,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialScattering, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialScattering, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::SCATTERING_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -299,10 +311,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::EMISSIVE_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -324,10 +338,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::LIGHT_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::LIGHT_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -345,10 +361,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::SPLAT_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - multiMaterial.setSplatMap(itr->second->getTextureView()._texture); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + multiMaterial.setSplatMap(textureView._texture); multiMaterial.addSamplerFunc([=]() { material->applySampler(graphics::MaterialKey::SPLAT_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -430,10 +448,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial if (itr != textureMaps.end()) { if (itr->second->isDefined()) { material->resetOpacityMap(); - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialAlbedo, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::ALBEDO_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -454,10 +474,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialNormal, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::NORMAL_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -477,10 +499,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialEmissiveLightmap, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler(graphics::MaterialKey::EMISSIVE_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -501,10 +525,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find(graphics::MaterialKey::SPLAT_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - multiMaterial.setSplatMap(itr->second->getTextureView()._texture); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + multiMaterial.setSplatMap(textureView._texture); multiMaterial.addSamplerFunc([=]() { material->applySampler(graphics::MaterialKey::SPLAT_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -576,10 +602,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find((graphics::Material::MapChannel) NetworkMToonMaterial::SHADE_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialShade, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialShade, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler((graphics::Material::MapChannel) NetworkMToonMaterial::SHADE_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -598,10 +626,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find((graphics::Material::MapChannel) NetworkMToonMaterial::SHADING_SHIFT_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialShadingShift, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialShadingShift, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler((graphics::Material::MapChannel) NetworkMToonMaterial::SHADING_SHIFT_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -620,10 +650,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find((graphics::Material::MapChannel) NetworkMToonMaterial::MATCAP_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialMatcap, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialMatcap, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler((graphics::Material::MapChannel) NetworkMToonMaterial::MATCAP_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -642,10 +674,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find((graphics::Material::MapChannel) NetworkMToonMaterial::RIM_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialRim, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialRim, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler((graphics::Material::MapChannel) NetworkMToonMaterial::RIM_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { @@ -664,10 +698,12 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial auto itr = textureMaps.find((graphics::Material::MapChannel) NetworkMToonMaterial::UV_ANIMATION_MASK_MAP); if (itr != textureMaps.end()) { if (itr->second->isDefined()) { - drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialUVAnimationMask, itr->second->getTextureView()); + auto textureView = itr->second->getTextureView(); + Q_ASSERT(textureView); + drawMaterialTextures[layerIndex]->setTexture(gr::Texture::MaterialUVAnimationMask, textureView); multiMaterial.addSamplerFunc([=] () { material->applySampler((graphics::Material::MapChannel) NetworkMToonMaterial::UV_ANIMATION_MASK_MAP); }); - if (itr->second->getTextureView().isReference()) { - multiMaterial.addReferenceTexture(itr->second->getTextureView().getTextureOperator()); + if (textureView.isReference()) { + multiMaterial.addReferenceTexture(textureView.getTextureOperator()); } wasSet = true; } else { diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 992de467ec7..514816a0d5a 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -59,7 +59,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto currentKeyLight = setupOutput.getN(4); // Fetch and cull the items from the scene - static const auto shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); + static const ItemFilter shadowCasterReceiverFilter = ItemFilter::Builder::visibleWorldItems().withOpaque().withoutLayered().withTagBits(tagBits, tagMask); const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterReceiverFilter, queryResolution).asVarying(); const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index f0c4ecd0ae4..bc8fab7abbc 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -106,6 +106,13 @@ int readHelper(void* dst, int length, void* data) { if (_readOffset.localData() + length > _readMax.localData()) { return -1; } + // Sometimes artery_font::decode issues zero-length reads to nullptr, which causes issues with memory sanitizers. + if (length == 0) { + return 0; + } + // These were null sometimes, so it's best to check in debug builds. + Q_ASSERT(dst); + Q_ASSERT(data); memcpy(dst, (char *)data + _readOffset.localData(), length); _readOffset.setLocalData(_readOffset.localData() + length); return length; @@ -147,7 +154,7 @@ void Font::read(QIODevice& in) { auto& g = arteryFont.variants[0].glyphs[i]; Glyph glyph; - glyph.c = g.codepoint; + glyph.c = QChar(g.codepoint); glyph.texOffset = glm::vec2(g.imageBounds.l, g.imageBounds.b); glyph.texSize = glm::vec2(g.imageBounds.r, g.imageBounds.t) - glyph.texOffset; glyph.offset = glm::vec2(g.planeBounds.l, g.planeBounds.b); diff --git a/libraries/script-engine/src/CanvasCommand.h b/libraries/script-engine/src/CanvasCommand.h index 838af044f22..b6022577af4 100644 --- a/libraries/script-engine/src/CanvasCommand.h +++ b/libraries/script-engine/src/CanvasCommand.h @@ -417,7 +417,8 @@ struct CanvasCommand { static CanvasCommand fillRect(const QRectF& rect) { CanvasCommand cmd; cmd.kind = FillRect; - return CanvasCommand { .kind = FillRect, ._rect = rect }; + cmd._rect = rect; + return cmd; } static CanvasCommand fillEllipse(const QRectF& rect) { diff --git a/libraries/script-engine/src/Mat4.h b/libraries/script-engine/src/Mat4.h index 8c56f513ab8..73cbc11458e 100644 --- a/libraries/script-engine/src/Mat4.h +++ b/libraries/script-engine/src/Mat4.h @@ -53,7 +53,7 @@ public slots: * @param {Mat4} m2 - The second matrix. * @returns {Mat4} m1 multiplied with m2. */ - glm::mat4 multiply(const glm::mat4& m1, const glm::mat4& m2) const; + glm::mat<4,4,float,glm::packed_highp> multiply(const glm::mat<4,4,float,glm::packed_highp>& m1, const glm::mat<4,4,float,glm::packed_highp>& m2) const; /*@jsdoc @@ -72,7 +72,7 @@ public slots: * // (0.739199, 0.280330, 0.612372, 0.000000), * // (10.000000, 11.000000, 12.000000, 1.000000)) */ - glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const; + glm::mat<4,4,float,glm::packed_highp> createFromRotAndTrans(const glm::qua& rot, const glm::vec<3,float,glm::packed_highp>& trans) const; /*@jsdoc * Creates a matrix that represents a scale, rotation, and translation. @@ -92,7 +92,7 @@ public slots: * // (1.478398, 0.560660, 1.224745, 0.000000), * // (10.000000, 11.000000, 12.000000, 1.000000)) */ - glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const; + glm::mat<4,4,float,glm::packed_highp> createFromScaleRotAndTrans(const glm::vec<3,float,glm::packed_highp>& scale, const glm::qua& rot, const glm::vec<3,float,glm::packed_highp>& trans) const; /*@jsdoc * Creates a matrix from columns of values. @@ -114,7 +114,7 @@ public slots: * // (1.478398, 0.560660, 1.224745, 0.000000), * // (10.000000, 11.000000, 12.000000, 1.000000)) */ - glm::mat4 createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const; + glm::mat<4,4,float,glm::packed_highp> createFromColumns(const glm::vec<4,float,glm::packed_highp>& col0, const glm::vec<4,float,glm::packed_highp>& col1, const glm::vec<4,float,glm::packed_highp>& col2, const glm::vec<4,float,glm::packed_highp>& col3) const; /*@jsdoc * Creates a matrix from an array of values. @@ -135,7 +135,7 @@ public slots: * // (1.478398, 0.560660, 1.224745, 0.000000), * // (10.000000, 11.000000, 12.000000, 1.000000)) */ - glm::mat4 createFromArray(const QVector& floats) const; + glm::mat<4,4,float,glm::packed_highp> createFromArray(const QVector& floats) const; /*@jsdoc @@ -153,7 +153,7 @@ public slots: * print("Translation: " + JSON.stringify(trans)); * // Translation: {"x":10,"y":11,"z":12} */ - glm::vec3 extractTranslation(const glm::mat4& m) const; + glm::vec<3,float,glm::packed_highp> extractTranslation(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc * Extracts the rotation from a matrix. @@ -170,7 +170,7 @@ public slots: * print("Rotation: " + JSON.stringify(Quat.safeEulerAngles(rot))); * // Rotation: {"x":29.999998092651367,"y":45.00000762939453,"z":60.000003814697266} */ - glm::quat extractRotation(const glm::mat4& m) const; + glm::qua extractRotation(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc * Extracts the scale from a matrix. @@ -187,7 +187,7 @@ public slots: * print("Scale: " + JSON.stringify(scale)); * // Scale: {"x":1.9999998807907104,"y":1.9999998807907104,"z":1.9999998807907104} */ - glm::vec3 extractScale(const glm::mat4& m) const; + glm::vec<3,float,glm::packed_highp> extractScale(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc @@ -207,7 +207,7 @@ public slots: * print("Transformed point: " + JSON.stringify(transformedPoint)); * // Transformed point: { "x": 2.8284270763397217, "y": 12, "z": -2.384185791015625e-7 } */ - glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& point) const; + glm::vec<3,float,glm::packed_highp> transformPoint(const glm::mat<4,4,float,glm::packed_highp>& m, const glm::vec<3,float,glm::packed_highp>& point) const; /*@jsdoc * Transforms a vector into a new coordinate system: the vector is scaled and rotated. @@ -226,7 +226,7 @@ public slots: * print("Transformed vector: " + JSON.stringify(transformedVector)); * // Transformed vector: { "x": 2.8284270763397217, "y": 2, "z": -2.384185791015625e-7 } */ - glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& vector) const; + glm::vec<3,float,glm::packed_highp> transformVector(const glm::mat<4,4,float,glm::packed_highp>& m, const glm::vec<3,float,glm::packed_highp>& vector) const; /*@jsdoc @@ -247,7 +247,7 @@ public slots: * // (0.000000, 0.000000, 1.000000, 0.000000), * // (0.000000, 0.000000, 0.000001, 1.000000)) */ - glm::mat4 inverse(const glm::mat4& m) const; + glm::mat<4,4,float,glm::packed_highp> inverse(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc @@ -259,7 +259,7 @@ public slots: * @returns {Vec3} The negative z-axis rotated by orientation. */ // redundant, calls getForward which better describes the returned vector as a direction - glm::vec3 getFront(const glm::mat4& m) const { return getForward(m); } + glm::vec<3,float,glm::packed_highp> getFront(const glm::mat<4,4,float,glm::packed_highp>& m) const { return getForward(m); } /*@jsdoc * Gets the "forward" direction that the camera would face if its orientation was set to the rotation contained in a @@ -275,7 +275,7 @@ public slots: * print("Forward: " + JSON.stringify(forward)); * // Forward: {"x":0,"y":0,"z":-1} */ - glm::vec3 getForward(const glm::mat4& m) const; + glm::vec<3,float,glm::packed_highp> getForward(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc * Gets the "right" direction that the camera would have if its orientation was set to the rotation contained in a matrix. @@ -284,7 +284,7 @@ public slots: * @param {Mat4} m - The matrix. * @returns {Vec3} The x-axis rotated by the rotation in the matrix. */ - glm::vec3 getRight(const glm::mat4& m) const; + glm::vec<3,float,glm::packed_highp> getRight(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc * Gets the "up" direction that the camera would have if its orientation was set to the rotation contained in a matrix. The @@ -293,7 +293,7 @@ public slots: * @param {Mat4} m - The matrix. * @returns {Vec3} The y-axis rotated by the rotation in the matrix. */ - glm::vec3 getUp(const glm::mat4& m) const; + glm::vec<3,float,glm::packed_highp> getUp(const glm::mat<4,4,float,glm::packed_highp>& m) const; /*@jsdoc @@ -321,7 +321,7 @@ public slots: * // "r0c2": 1.4783978462219238, "r1c2": 0.5606603026390076, "r2c2": 1.2247447967529297, "r3c2": 0, * // "r0c3": 10, "r1c3": 11, "r2c3": 12, "r3c3": 1} */ - void print(const QString& label, const glm::mat4& m, bool transpose = false) const; + void print(const QString& label, const glm::mat<4,4,float,glm::packed_highp>& m, bool transpose = false) const; }; #endif // hifi_Mat4_h diff --git a/libraries/script-engine/src/MouseEvent.cpp b/libraries/script-engine/src/MouseEvent.cpp index 20f525e61b6..c3569a37a76 100644 --- a/libraries/script-engine/src/MouseEvent.cpp +++ b/libraries/script-engine/src/MouseEvent.cpp @@ -32,8 +32,8 @@ MouseEvent::MouseEvent() : MouseEvent::MouseEvent(const QMouseEvent& event) : - x(event.x()), - y(event.y()), + x(static_cast(event.position().x())), + y(static_cast(event.position().y())), isLeftButton(event.buttons().testFlag(Qt::LeftButton)), isRightButton(event.buttons().testFlag(Qt::RightButton)), isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)), diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 75caf0e8af7..bfe7329e28c 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -21,6 +21,8 @@ #include +#include + #include #include @@ -60,7 +62,7 @@ /// Provides the Quat scripting interface class Quat : public QObject, protected Scriptable { Q_OBJECT - Q_PROPERTY(glm::quat IDENTITY READ IDENTITY CONSTANT) + Q_PROPERTY(glm::qua IDENTITY READ IDENTITY CONSTANT) public slots: @@ -77,7 +79,7 @@ public slots: * var handOrientation = Quat.multiply(MyAvatar.orientation, handPose.rotation); * } */ - glm::quat multiply(const glm::quat& q1, const glm::quat& q2); + glm::qua multiply(const glm::qua& q1, const glm::qua& q2); /*@jsdoc * Normalizes a quaternion. @@ -93,7 +95,7 @@ public slots: * // Use currentRotatation for something. * } */ - glm::quat normalize(const glm::quat& q); + glm::qua normalize(const glm::qua& q); /*@jsdoc * Calculates the conjugate of a quaternion. For a unit quaternion, its conjugate is the same as its @@ -109,7 +111,7 @@ public slots: * var identity = Quat.multiply(conjugate, quaternion); * Quat.print("identity", identity, true); // dvec3(0.000000, 0.000000, 0.000000) */ - glm::quat conjugate(const glm::quat& q); + glm::qua conjugate(const glm::qua& q); /*@jsdoc * Calculates a camera orientation given an eye position, point of interest, and "up" direction. The camera's negative @@ -125,7 +127,7 @@ public slots: * Camera.mode = "independent"; * Camera.orientation = Quat.lookAt(Camera.position, Vec3.ZERO, Vec3.UNIT_NEG_Y); */ - glm::quat lookAt(const glm::vec3& eye, const glm::vec3& center, const glm::vec3& up); + glm::qua lookAt(const glm::vec<3,float,glm::packed_highp>& eye, const glm::vec<3,float,glm::packed_highp>& center, const glm::vec<3,float,glm::packed_highp>& up); /*@jsdoc * Calculates a camera orientation given an eye position and point of interest. The camera's negative z-axis is the forward @@ -141,7 +143,7 @@ public slots: * Camera.mode = "independent"; * Camera.orientation = Quat.lookAtSimple(Camera.position, Vec3.ZERO); */ - glm::quat lookAtSimple(const glm::vec3& eye, const glm::vec3& center); + glm::qua lookAtSimple(const glm::vec<3,float,glm::packed_highp>& eye, const glm::vec<3,float,glm::packed_highp>& center); /*@jsdoc * Calculates the shortest rotation from a first vector onto a second. @@ -158,7 +160,7 @@ public slots: * Entities.editEntity(entityID, properties); * entityVelocity = newVelocity; */ - glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); + glm::qua rotationBetween(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2); /*@jsdoc * Generates a quaternion from a {@link Vec3} of Euler angles in degrees. @@ -172,7 +174,7 @@ public slots: * eulerAngles.z = 0; * var newOrientation = Quat.fromVec3Degrees(eulerAngles); */ - glm::quat fromVec3Degrees(const glm::vec3& vec3); + glm::qua fromVec3Degrees(const glm::vec<3,float,glm::packed_highp>& vec3); /*@jsdoc * Generates a quaternion from a {@link Vec3} of Euler angles in radians. @@ -183,7 +185,7 @@ public slots: * @example Create a rotation of 180 degrees about the y axis. * var rotation = Quat.fromVec3Radians({ x: 0, y: Math.PI, z: 0 }); */ - glm::quat fromVec3Radians(const glm::vec3& vec3); + glm::qua fromVec3Radians(const glm::vec<3,float,glm::packed_highp>& vec3); /*@jsdoc * Generates a quaternion from pitch, yaw, and roll values in degrees. @@ -195,7 +197,7 @@ public slots: * @example Create a rotation of 180 degrees about the y axis. * var rotation = Quat.fromPitchYawRollDegrees(0, 180, 0 ); */ - glm::quat fromPitchYawRollDegrees(float pitch, float yaw, float roll); + glm::qua fromPitchYawRollDegrees(float pitch, float yaw, float roll); /*@jsdoc * Generates a quaternion from pitch, yaw, and roll values in radians. @@ -207,7 +209,7 @@ public slots: * @example Create a rotation of 180 degrees about the y axis. * var rotation = Quat.fromPitchYawRollRadians(0, Math.PI, 0); */ - glm::quat fromPitchYawRollRadians(float pitch, float yaw, float roll); + glm::qua fromPitchYawRollRadians(float pitch, float yaw, float roll); /*@jsdoc * Calculates the inverse of a quaternion. For a unit quaternion, its inverse is the same as its @@ -223,7 +225,7 @@ public slots: * var identity = Quat.multiply(inverse, quaternion); * Quat.print("identity", identity, true); // dvec3(0.000000, 0.000000, 0.000000) */ - glm::quat inverse(const glm::quat& q); + glm::qua inverse(const glm::qua& q); /*@jsdoc * Gets the "front" direction that the camera would face if its orientation was set to the quaternion value. @@ -233,7 +235,7 @@ public slots: * @param {Quat} orientation - A quaternion representing an orientation. * @returns {Vec3} The negative z-axis rotated by orientation. */ - glm::vec3 getFront(const glm::quat& orientation) { return getForward(orientation); } + glm::vec<3,float,glm::packed_highp> getFront(const glm::qua& orientation) { return getForward(orientation); } /*@jsdoc * Gets the "forward" direction that the camera would face if its orientation was set to the quaternion value. @@ -246,7 +248,7 @@ public slots: * var forward = Quat.getForward(Quat.IDENTITY); * print(JSON.stringify(forward)); // {"x":0,"y":0,"z":-1} */ - glm::vec3 getForward(const glm::quat& orientation); + glm::vec<3,float,glm::packed_highp> getForward(const glm::qua& orientation); /*@jsdoc * Gets the "right" direction that the camera would have if its orientation was set to the quaternion value. @@ -255,7 +257,7 @@ public slots: * @param {Quat} orientation - A quaternion representing an orientation. * @returns {Vec3} The x-axis rotated by orientation. */ - glm::vec3 getRight(const glm::quat& orientation); + glm::vec<3,float,glm::packed_highp> getRight(const glm::qua& orientation); /*@jsdoc * Gets the "up" direction that the camera would have if its orientation was set to the quaternion value. @@ -264,7 +266,7 @@ public slots: * @param {Quat} orientation - A quaternion representing an orientation. * @returns {Vec3} The y-axis rotated by orientation. */ - glm::vec3 getUp(const glm::quat& orientation); + glm::vec<3,float,glm::packed_highp> getUp(const glm::qua& orientation); /*@jsdoc * Calculates the Euler angles for the quaternion, in degrees. (The "safe" in the name signifies that the angle results @@ -277,7 +279,7 @@ public slots: * var eulerAngles = Quat.safeEulerAngles(Camera.orientation); * print("Camera yaw: " + eulerAngles.y); */ - glm::vec3 safeEulerAngles(const glm::quat& orientation); + glm::vec<3,float,glm::packed_highp> safeEulerAngles(const glm::qua& orientation); /*@jsdoc * Generates a quaternion given an angle to rotate through and an axis to rotate about. @@ -290,7 +292,7 @@ public slots: * @example Calculate a rotation of 90 degrees about the direction your camera is looking. * var rotation = Quat.angleAxis(90, Quat.getForward(Camera.orientation)); */ - glm::quat angleAxis(float angle, const glm::vec3& v); + glm::qua angleAxis(float angle, const glm::vec<3,float,glm::packed_highp>& v); /*@jsdoc * Gets the rotation axis for a quaternion. @@ -304,7 +306,7 @@ public slots: * print("Forward: " + JSON.stringify(forward)); * print("Axis: " + JSON.stringify(axis)); // Same value as forward. */ - glm::vec3 axis(const glm::quat& orientation); + glm::vec<3,float,glm::packed_highp> axis(const glm::qua& orientation); /*@jsdoc * Gets the rotation angle for a quaternion. @@ -318,7 +320,7 @@ public slots: * var angle = Quat.angle(rotation); * print("Angle: " + angle * 180 / Math.PI); // 90 degrees. */ - float angle(const glm::quat& orientation); + float angle(const glm::qua& orientation); // spherical linear interpolation // alpha: 0.0 to 1.0? @@ -340,7 +342,7 @@ public slots: * } * var newRotation = Quat.mix(startRotation, endRotation, mixFactor); */ - glm::quat mix(const glm::quat& q1, const glm::quat& q2, float alpha); + glm::qua mix(const glm::qua& q1, const glm::qua& q2, float alpha); /*@jsdoc * Computes a spherical linear interpolation between two rotations, for rotations that are not very similar. @@ -353,7 +355,7 @@ public slots: * q1's value; 1.0 returns q2s's value. * @returns {Quat} A spherical linear interpolation between rotations q1 and q2. */ - glm::quat slerp(const glm::quat& q1, const glm::quat& q2, float alpha); + glm::qua slerp(const glm::qua& q1, const glm::qua& q2, float alpha); /*@jsdoc * Computes a spherical quadrangle interpolation between two rotations along a path oriented toward two other rotations. @@ -368,7 +370,7 @@ public slots: * @returns {Quat} A spherical quadrangle interpolation between rotations q1 and q2 using control * points s1 and s2. */ - glm::quat squad(const glm::quat& q1, const glm::quat& q2, const glm::quat& s1, const glm::quat& s2, float h); + glm::qua squad(const glm::qua& q1, const glm::qua& q2, const glm::qua& s1, const glm::qua& s2, float h); /*@jsdoc * Calculates the dot product of two quaternions. The closer the quaternions are to each other the more non-zero the value @@ -389,7 +391,7 @@ public slots: * var equal = Math.abs(1 - Math.abs(dot)) < 0.000001; * print(equal); // true */ - float dot(const glm::quat& q1, const glm::quat& q2); + float dot(const glm::qua& q1, const glm::qua& q2); /*@jsdoc * Prints to the program log a text label followed by a quaternion's pitch, yaw, and roll Euler angles. @@ -407,7 +409,7 @@ public slots: * // Quaternion: {"x":0,"y":45.000003814697266,"z":0} * print("Quaternion: " + JSON.stringify(Quat.safeEulerAngles(quaternion))); */ - void print(const QString& label, const glm::quat& q, bool asDegrees = false); + void print(const QString& label, const glm::qua& q, bool asDegrees = false); /*@jsdoc * Tests whether two quaternions are equal. @@ -429,7 +431,7 @@ public slots: * var equal = Math.abs(1 - Math.abs(dot)) < 0.000001; * print(equal); // true */ - bool equal(const glm::quat& q1, const glm::quat& q2); + bool equal(const glm::qua& q1, const glm::qua& q2); /*@jsdoc * Cancels out the roll and pitch component of a quaternion so that its completely horizontal with a yaw pointing in the @@ -449,7 +451,7 @@ public slots: * Quat.print("", lookAt, true); // dvec3(0.000000, 22.245996, 0.000000) * */ - glm::quat cancelOutRollAndPitch(const glm::quat& q); + glm::qua cancelOutRollAndPitch(const glm::qua& q); /*@jsdoc * Cancels out the roll component of a quaternion so that its horizontal axis is level. @@ -467,10 +469,10 @@ public slots: * var lookAt = Quat.lookAtSimple(Vec3.ZERO, front); * Quat.print("", lookAt, true); // dvec3(-1.033004, 22.245996, -0.000000) */ - glm::quat cancelOutRoll(const glm::quat& q); + glm::qua cancelOutRoll(const glm::qua& q); private: - const glm::quat& IDENTITY() const { return Quaternions::IDENTITY; } + const glm::qua& IDENTITY() const { return Quaternions::IDENTITY; } }; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 26a0f130a1e..cede6fb3782 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -17,6 +17,8 @@ #ifndef hifi_SceneScriptingInterface_h #define hifi_SceneScriptingInterface_h +#include + #include /*@jsdoc diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index b9e9c83ad1c..eee6f3474a6 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/script-engine/src/ScriptCache.h b/libraries/script-engine/src/ScriptCache.h index 2fb9f91046d..f480a317ae4 100644 --- a/libraries/script-engine/src/ScriptCache.h +++ b/libraries/script-engine/src/ScriptCache.h @@ -18,6 +18,8 @@ #define hifi_ScriptCache_h #include +#include + #include using contentAvailableCallback = std::function; diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index ed446269834..2e3e26b5b61 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -466,7 +466,7 @@ QStringList ScriptEngines::getRunningScripts() { } void ScriptEngines::stopAllScripts(bool restart) { - QtConcurrent::run([this, restart] { + QThreadPool::globalInstance()->start([this, restart] { QHash scriptManagersHashCopy; { @@ -557,13 +557,13 @@ ScriptManagerPointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool bool activateMainWindow, bool reload, bool quitWhenFinished) { if (thread() != QThread::currentThread()) { ScriptManagerPointer result { nullptr }; - BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptManagerPointer, result), - Q_ARG(QUrl, scriptFilename), - Q_ARG(bool, isUserLoaded), - Q_ARG(bool, loadScriptFromEditor), - Q_ARG(bool, activateMainWindow), - Q_ARG(bool, reload), - Q_ARG(bool, quitWhenFinished)); + BLOCKING_INVOKE_METHOD(this, "loadScript", Q_GENERIC_RETURN_ARG(ScriptManagerPointer, result), + Q_GENERIC_ARG(QUrl, scriptFilename), + Q_GENERIC_ARG(bool, isUserLoaded), + Q_GENERIC_ARG(bool, loadScriptFromEditor), + Q_GENERIC_ARG(bool, activateMainWindow), + Q_GENERIC_ARG(bool, reload), + Q_GENERIC_ARG(bool, quitWhenFinished)); return result; } QUrl scriptUrl; diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 97f798b804d..3da02d7d600 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -409,7 +409,7 @@ protected slots: ScriptManager::Context _context; QReadWriteLock _scriptManagersHashLock; - QMultiHash _scriptManagersHash; + QHash _scriptManagersHash; QSet _allKnownScriptManagers; QMutex _allScriptsMutex; ScriptsModel _scriptsModel; diff --git a/libraries/script-engine/src/ScriptException.h b/libraries/script-engine/src/ScriptException.h index f533d7a4f0e..77eb21d225a 100644 --- a/libraries/script-engine/src/ScriptException.h +++ b/libraries/script-engine/src/ScriptException.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "ScriptValue.h" @@ -146,20 +147,16 @@ class ScriptRuntimeException : public ScriptException { * * @return std::shared_ptr */ - virtual std::shared_ptr clone() const override { - return std::make_shared(*this); - } + virtual std::shared_ptr clone() const override { return std::make_shared(*this); } }; inline QDebug operator<<(QDebug debug, const ScriptException& e) { - debug << "Exception:" - << e.errorMessage - << (e.additionalInfo.isEmpty() ? QString("") : "[" + e.additionalInfo + "]") - << " at line " << e.errorLine << ", column " << e.errorColumn; + debug << "Exception:" << e.errorMessage << (e.additionalInfo.isEmpty() ? QString("") : "[" + e.additionalInfo + "]") + << " at line " << e.errorLine << ", column " << e.errorColumn; if (e.backtrace.length()) { debug << "Backtrace:"; - debug << e.backtrace; + debug << e.backtrace.join("\n"); } return debug; diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index 65b333e5cee..ec383191dc5 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -675,7 +676,7 @@ static ScriptValue scriptableResourceToScriptValue(ScriptEngine* engine, auto manager = engine->manager(); if (data && manager && !resource->isInScript()) { resource->setInScript(true); - QObject::connect(data.data(), &Resource::updateSize, manager, &ScriptManager::updateMemoryCost); + QObject::connect(data.get(), &Resource::updateSize, manager, &ScriptManager::updateMemoryCost); } auto object = engine->newQObject(const_cast(resource), ScriptEngine::ScriptOwnership); @@ -1612,7 +1613,7 @@ ScriptValue ScriptManager::instantiateModule(const ScriptValue& module, const QS // scoped vars for consistency with Node.js closure.setProperty("require", module.property("require")); closure.setProperty("__filename", modulePath, READONLY_HIDDEN_PROP_FLAGS); - closure.setProperty("__dirname", QString(modulePath).replace(QRegExp("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); + closure.setProperty("__dirname", QString(modulePath).replace(QRegularExpression("/[^/]*$"), ""), READONLY_HIDDEN_PROP_FLAGS); //_engine->scriptValueDebugDetails(module); result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath )); } @@ -2016,7 +2017,7 @@ QVariant ScriptManager::cloneEntityScriptDetails(const EntityItemID& entityID, c } QFuture ScriptManager::getLocalEntityScriptDetails(const EntityItemID& entityID, const QString& scriptURL) { - return QtConcurrent::run(this, &ScriptManager::cloneEntityScriptDetails, entityID, scriptURL); + return QtConcurrent::run(&ScriptManager::cloneEntityScriptDetails, this, entityID, scriptURL); } bool ScriptManager::getEntityScriptDetails(const EntityItemID& entityID, const QString& scriptURL, EntityScriptDetails &details) const { @@ -2337,7 +2338,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c bool passList = false; // assume unsafe QString allowlistPrefix = "[ALLOWLIST ENTITY SCRIPTS]"; QList safeURLPrefixes = { "file:///", "atp:", "cache:" }; - safeURLPrefixes += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegExp("\\s*,\\s*"), Qt::SkipEmptyParts); + safeURLPrefixes += qEnvironmentVariable("EXTRA_ALLOWLIST").trimmed().split(QRegularExpression("\\s*,\\s*"), Qt::SkipEmptyParts); // Entity Script Allowlist toggle check. Setting::Handle allowlistEnabled {"private/allowlistEnabled", false }; @@ -2348,7 +2349,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c // Pull SAFEURLS from the Interface.JSON settings. QVariant raw = Setting::Handle("private/settingsSafeURLS").get(); - QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegExp("\\s*[,\r\n]+\\s*"), Qt::SkipEmptyParts); + QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegularExpression("\\s*[,\r\n]+\\s*"), Qt::SkipEmptyParts); safeURLPrefixes += settingsSafeURLS; // END Pull SAFEURLS from the Interface.JSON settings. diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h index 77d02656216..5f70c5c673c 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h @@ -338,7 +338,8 @@ class ScriptManagerScriptingInterface : public QObject { Q_INVOKABLE void clearInterval(QTimer* timer) { _manager->clearInterval(timer); } // Overloaded version is needed in case the timer has expired - Q_INVOKABLE void clearInterval(QVariantMap timer) { ; } + // QT6TODO: This errors out on Qt6. It seems to work without it, but I'm not sure if there isn't more of underlying bugs. + //Q_INVOKABLE void clearInterval(QVariantMap timer) { ; } /*@jsdoc * Stops a timeout timer set by {@link Script.setTimeout|setTimeout}. @@ -356,7 +357,8 @@ class ScriptManagerScriptingInterface : public QObject { Q_INVOKABLE void clearTimeout(QTimer* timer) { _manager->clearTimeout(timer); } // Overloaded version is needed in case the timer has expired - Q_INVOKABLE void clearTimeout(QVariantMap timer) { ; } + // QT6TODO: This errors out on Qt6. It seems to work without it, but I'm not sure if there isn't more of underlying bugs. + //Q_INVOKABLE void clearTimeout(QVariantMap timer) { ; } /*@jsdoc * Prints a message to the program log and emits {@link Script.printedMessage}. diff --git a/libraries/script-engine/src/ScriptMessage.cpp b/libraries/script-engine/src/ScriptMessage.cpp index 0b3ea1abc86..3650e02ad18 100644 --- a/libraries/script-engine/src/ScriptMessage.cpp +++ b/libraries/script-engine/src/ScriptMessage.cpp @@ -40,7 +40,7 @@ bool ScriptMessage::fromJson(const QJsonObject &object) { } _messageContent = object["message"].toString(); _lineNumber = object["lineNumber"].toInt(); - _fileName = object["fileName"].toInt(); + _fileName = object["fileName"].toString(); _entityID = QUuid::fromString(object["entityID"].toString()); _scriptType = static_cast(object["type"].toInt()); _severity = static_cast(object["severity"].toInt()); diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 450e8797c50..f227b9d1d32 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -794,7 +794,7 @@ bool qColorFromScriptValue(const ScriptValue& object, QColor& color) { color.setRgb(object.toUInt32()); return true; } else if (object.isString()) { - color.setNamedColor(object.toString()); + color = QColor::fromString(object.toString()); return true; } else if (object.isArray()) { auto length = object.property("length").toInt32(); @@ -1097,7 +1097,8 @@ QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& arra newVector.reserve(length); for (int i = 0; i < length; i++) { QString uuidAsString = array.property(i).toString(); - EntityItemID fromString(uuidAsString); + QUuid uuid(uuidAsString); + EntityItemID fromString(uuid); newVector << fromString; } return newVector; diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index 026f819d35a..20fc3eaa247 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -53,8 +53,8 @@ void registerMetaTypes(ScriptEngine* engine); * @property {number} r2c3 - Row 2, column 3 value. * @property {number} r3c3 - Row 3, column 3 value. */ -ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat4& mat4); -bool mat4FromScriptValue(const ScriptValue& object, glm::mat4& mat4); +ScriptValue mat4toScriptValue(ScriptEngine* engine, const glm::mat<4,4,float,glm::packed_highp>& mat4); +bool mat4FromScriptValue(const ScriptValue& object, glm::mat<4,4,float,glm::packed_highp>& mat4); /*@jsdoc * A 2-dimensional vector. @@ -148,9 +148,9 @@ bool u8vec3FromScriptValue(const ScriptValue& object, glm::u8vec3& vec3); * @property {number} z - Z-coordinate of the vector. * @property {number} w - W-coordinate of the vector. */ -ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec4& vec4); -ScriptValue vec4ColorToScriptValue(ScriptEngine* engine, const glm::vec4& vec4); -bool vec4FromScriptValue(const ScriptValue& object, glm::vec4& vec4); +ScriptValue vec4toScriptValue(ScriptEngine* engine, const glm::vec<4,float,glm::packed_highp>& vec4); +ScriptValue vec4ColorToScriptValue(ScriptEngine* engine, const glm::vec<4,float,glm::packed_highp>& vec4); +bool vec4FromScriptValue(const ScriptValue& object, glm::vec<4,float,glm::packed_highp>& vec4); // Quaternions ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat); diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 18adf103529..b1ef09377a7 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/libraries/script-engine/src/ScriptsModelFilter.cpp b/libraries/script-engine/src/ScriptsModelFilter.cpp index 1879e547c09..31ea329f68a 100644 --- a/libraries/script-engine/src/ScriptsModelFilter.cpp +++ b/libraries/script-engine/src/ScriptsModelFilter.cpp @@ -26,7 +26,7 @@ bool ScriptsModelFilter::lessThan(const QModelIndex& left, const QModelIndex& ri } bool ScriptsModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { - if (!filterRegExp().isEmpty()) { + if (!filterRegularExpression().pattern().isEmpty()) { ScriptsModel* scriptsModel = static_cast(sourceModel()); TreeNodeBase* node = scriptsModel->getFolderNodes( static_cast(scriptsModel->getTreeNodeFromIndex(sourceParent))).at(sourceRow); diff --git a/libraries/script-engine/src/TouchEvent.cpp b/libraries/script-engine/src/TouchEvent.cpp index f6b61a49f29..f21f2a6a86a 100644 --- a/libraries/script-engine/src/TouchEvent.cpp +++ b/libraries/script-engine/src/TouchEvent.cpp @@ -73,17 +73,17 @@ float angleBetweenPoints(const glm::vec2& a, const glm::vec2& b ) { void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { // convert the touch points into an average - const QList& tPoints = event.touchPoints(); + const QList& tPoints = event.points(); float touchAvgX = 0.0f; float touchAvgY = 0.0f; touchPoints = tPoints.count(); if (touchPoints > 1) { for (int i = 0; i < touchPoints; ++i) { - touchAvgX += (float)tPoints[i].pos().x(); - touchAvgY += (float)tPoints[i].pos().y(); + touchAvgX += (float)tPoints[i].position().x(); + touchAvgY += (float)tPoints[i].position().y(); // add it to our points vector - glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + glm::vec2 thisPoint(tPoints[i].position().x(), tPoints[i].position().y()); points << thisPoint; } touchAvgX /= (float)(touchPoints); @@ -91,8 +91,8 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { } else { // I'm not sure this should ever happen, why would Qt send us a touch event for only one point? // maybe this happens in the case of a multi-touch where all but the last finger is released? - touchAvgX = tPoints[0].pos().x(); - touchAvgY = tPoints[0].pos().y(); + touchAvgX = tPoints[0].position().x(); + touchAvgY = tPoints[0].position().y(); } x = touchAvgX; y = touchAvgY; @@ -102,7 +102,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { float maxRadius = 0.0f; glm::vec2 center(x,y); for (int i = 0; i < touchPoints; ++i) { - glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + glm::vec2 touchPoint(tPoints[i].position().x(), tPoints[i].position().y()); float thisRadius = glm::distance(center,touchPoint); if (thisRadius > maxRadius) { maxRadius = thisRadius; @@ -121,10 +121,10 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) { } angle = totalAngle/(float)touchPoints; - isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed); - isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved); - isStationary = event.touchPointStates().testFlag(Qt::TouchPointStationary); - isReleased = event.touchPointStates().testFlag(Qt::TouchPointReleased); + isPressed = event.touchPointStates().testFlag(QEventPoint::State::Pressed); + isMoved = event.touchPointStates().testFlag(QEventPoint::State::Updated); + isStationary = event.touchPointStates().testFlag(QEventPoint::State::Stationary); + isReleased = event.touchPointStates().testFlag(QEventPoint::State::Released); // keyboard modifiers isShifted = event.modifiers().testFlag(Qt::ShiftModifier); diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 026441f5fef..0ac79bda58b 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -18,6 +18,8 @@ #ifndef hifi_UsersScriptingInterface_h #define hifi_UsersScriptingInterface_h +#include + #include #include #include diff --git a/libraries/script-engine/src/VariantMapToScriptValue.cpp b/libraries/script-engine/src/VariantMapToScriptValue.cpp index b40f9fd735c..c27736b0984 100644 --- a/libraries/script-engine/src/VariantMapToScriptValue.cpp +++ b/libraries/script-engine/src/VariantMapToScriptValue.cpp @@ -18,26 +18,26 @@ #include "SharedLogging.h" ScriptValue variantToScriptValue(QVariant& qValue, ScriptEngine& scriptEngine) { - switch(qValue.type()) { - case QVariant::Bool: + switch(qValue.typeId()) { + case QMetaType::Bool: return scriptEngine.newValue(qValue.toBool()); break; - case QVariant::Int: + case QMetaType::Int: return scriptEngine.newValue(qValue.toInt()); break; - case QVariant::Double: + case QMetaType::Double: return scriptEngine.newValue(qValue.toDouble()); break; - case QVariant::String: - case QVariant::Url: + case QMetaType::QString: + case QMetaType::QUrl: return scriptEngine.newValue(qValue.toString()); break; - case QVariant::Map: { + case QMetaType::QVariantMap: { QVariantMap childMap = qValue.toMap(); return variantMapToScriptValue(childMap, scriptEngine); break; } - case QVariant::List: { + case QMetaType::QVariantList: { QVariantList childList = qValue.toList(); return variantListToScriptValue(childList, scriptEngine); break; diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index e63a7cd7ca7..df0eb79c7a8 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -113,7 +113,7 @@ public slots: * var reflected = Vec3.reflect(v, normal); * print(JSON.stringify(reflected)); // {"x":1,"y":-2,"z":3} */ - glm::vec3 reflect(const glm::vec3& v1, const glm::vec3& v2) { return glm::reflect(v1, v2); } + glm::vec<3,float,glm::packed_highp> reflect(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return glm::reflect(v1, v2); } /*@jsdoc * Calculates the cross product of two vectors. @@ -127,7 +127,7 @@ public slots: * var crossProduct = Vec3.cross(v1, v2); * print(JSON.stringify(crossProduct)); // {"x":0,"y":0,"z":1} */ - glm::vec3 cross(const glm::vec3& v1, const glm::vec3& v2) { return glm::cross(v1, v2); } + glm::vec<3,float,glm::packed_highp> cross(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return glm::cross(v1, v2); } /*@jsdoc * Calculates the dot product of two vectors. @@ -141,7 +141,7 @@ public slots: * var dotProduct = Vec3.dot(v1, v2); * print(dotProduct); // 0 */ - float dot(const glm::vec3& v1, const glm::vec3& v2) { return glm::dot(v1, v2); } + float dot(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return glm::dot(v1, v2); } /*@jsdoc * Multiplies a vector by a scale factor. @@ -150,7 +150,7 @@ public slots: * @param {number} scale - The scale factor. * @returns {Vec3} The vector with each ordinate value multiplied by the scale. */ - glm::vec3 multiply(const glm::vec3& v1, float f) { return v1 * f; } + glm::vec<3,float,glm::packed_highp> multiply(const glm::vec<3,float,glm::packed_highp>& v1, float f) { return v1 * f; } /*@jsdoc * Multiplies a vector by a scale factor. @@ -159,7 +159,7 @@ public slots: * @param {Vec3} v - The vector. * @returns {Vec3} The vector with each ordinate value multiplied by the scale. */ - glm::vec3 multiply(float f, const glm::vec3& v1) { return v1 * f; } + glm::vec<3,float,glm::packed_highp> multiply(float f, const glm::vec<3,float,glm::packed_highp>& v1) { return v1 * f; } /*@jsdoc * Multiplies two vectors. @@ -174,7 +174,7 @@ public slots: * var multiplied = Vec3.multiplyVbyV(v1, v2); * print(JSON.stringify(multiplied)); // {"x":1,"y":4,"z":9} */ - glm::vec3 multiplyVbyV(const glm::vec3& v1, const glm::vec3& v2) { return v1 * v2; } + glm::vec<3,float,glm::packed_highp> multiplyVbyV(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return v1 * v2; } /*@jsdoc * Rotates a vector. @@ -188,7 +188,7 @@ public slots: * var result = Vec3.multiplyQbyV(q, v); * print(JSON.stringify(result)); // {"x":0,"y":1.000,"z":1.19e-7} */ - glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v) { return q * v; } + glm::vec<3,float,glm::packed_highp> multiplyQbyV(const glm::qua& q, const glm::vec<3,float,glm::packed_highp>& v) { return q * v; } /*@jsdoc * Calculates the sum of two vectors. @@ -197,7 +197,7 @@ public slots: * @param {Vec3} v2 - The second vector. * @returns {Vec3} The sum of the two vectors. */ - glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; } + glm::vec<3,float,glm::packed_highp> sum(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return v1 + v2; } /*@jsdoc * Calculates one vector subtracted from another. @@ -206,7 +206,7 @@ public slots: * @param {Vec3} v2 - The second vector. * @returns {Vec3} The second vector subtracted from the first. */ - glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2) { return v1 - v2; } + glm::vec<3,float,glm::packed_highp> subtract(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return v1 - v2; } /*@jsdoc * Calculates the length of a vector @@ -214,7 +214,7 @@ public slots: * @param {Vec3} v - The vector. * @returns {number} The length of the vector. */ - float length(const glm::vec3& v) { return glm::length(v); } + float length(const glm::vec<3,float,glm::packed_highp>& v) { return glm::length(v); } /*@jsdoc * Calculates the distance between two points. @@ -232,7 +232,7 @@ public slots: * distance = Vec3.distance(p1, p2); * print(distance); // 10 */ - float distance(const glm::vec3& v1, const glm::vec3& v2) { return glm::distance(v1, v2); } + float distance(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return glm::distance(v1, v2); } /*@jsdoc * Calculates the angle of rotation from one vector onto another, with the sign depending on a reference vector. @@ -254,7 +254,7 @@ public slots: * print(Vec3.orientedAngle(v1, v2, { x: 1, y: 2, z: -1 })); // -45 * print(Vec3.orientedAngle(v1, v2, { x: 1, y: -2, z: -1 })); // 45 */ - float orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3); + float orientedAngle(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2, const glm::vec<3,float,glm::packed_highp>& v3); /*@jsdoc * Normalizes a vector so that its length is 1. @@ -267,7 +267,7 @@ public slots: * print(JSON.stringify(normalized)); // {"x":0.7071,"y":0.7071,"z":0} * print(Vec3.length(normalized)); // 1 */ - glm::vec3 normalize(const glm::vec3& v) { return glm::normalize(v); }; + glm::vec<3,float,glm::packed_highp> normalize(const glm::vec<3,float,glm::packed_highp>& v) { return glm::normalize(v); }; /*@jsdoc * Calculates a linear interpolation between two vectors. @@ -282,7 +282,7 @@ public slots: * var interpolated = Vec3.mix(v1, v2, 0.75); // 1/4 of v1 and 3/4 of v2. * print(JSON.stringify(interpolated)); // {"x":2.5,"y":7.5","z":0} */ - glm::vec3 mix(const glm::vec3& v1, const glm::vec3& v2, float m) { return glm::mix(v1, v2, m); } + glm::vec<3,float,glm::packed_highp> mix(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2, float m) { return glm::mix(v1, v2, m); } /*@jsdoc * Prints the vector to the program log, as a text label followed by the vector value. @@ -294,7 +294,7 @@ public slots: * Vec3.print("Vector: ", v); // dvec3(1.000000, 2.000000, 3.000000) * print("Vector: " + JSON.stringify(v)); // {"x":1,"y":2,"z":3} */ - void print(const QString& label, const glm::vec3& v); + void print(const QString& label, const glm::vec<3,float,glm::packed_highp>& v); /*@jsdoc * Tests whether two vectors are equal. @@ -315,7 +315,7 @@ public slots: * equal = Vec3.equal(v1, v2); * print(equal); // false */ - bool equal(const glm::vec3& v1, const glm::vec3& v2) { return v1 == v2; } + bool equal(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2) { return v1 == v2; } /*@jsdoc * Tests whether two vectors are equal within a tolerance. @@ -336,7 +336,7 @@ public slots: * equal = Vec3.withinEpsilon(v1, v2, 0.001); * print(equal); // true */ - bool withinEpsilon(const glm::vec3& v1, const glm::vec3& v2, float epsilon); + bool withinEpsilon(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2, float epsilon); /*@jsdoc * Calculates polar coordinates (elevation, azimuth, radius) that transform the unit z-axis vector onto a point. @@ -352,7 +352,7 @@ public slots: * print("Radius: " + polar.z); // 7.5 */ // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation - glm::vec3 toPolar(const glm::vec3& v); + glm::vec<3,float,glm::packed_highp> toPolar(const glm::vec<3,float,glm::packed_highp>& v); /*@jsdoc * Calculates the coordinates of a point from polar coordinate transformation of the unit z-axis vector. @@ -366,7 +366,7 @@ public slots: * print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5} */ // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation - glm::vec3 fromPolar(const glm::vec3& polar); + glm::vec<3,float,glm::packed_highp> fromPolar(const glm::vec<3,float,glm::packed_highp>& polar); /*@jsdoc * Calculates the unit vector corresponding to polar coordinates elevation and azimuth transformation of the unit z-axis @@ -384,7 +384,7 @@ public slots: * print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5} */ // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation - glm::vec3 fromPolar(float elevation, float azimuth); + glm::vec<3,float,glm::packed_highp> fromPolar(float elevation, float azimuth); /*@jsdoc * Calculates the angle between two vectors. @@ -398,28 +398,28 @@ public slots: * var angle = Vec3.getAngle(v1, v2); * print(angle * 180 / Math.PI); // 90 */ - float getAngle(const glm::vec3& v1, const glm::vec3& v2); + float getAngle(const glm::vec<3,float,glm::packed_highp>& v1, const glm::vec<3,float,glm::packed_highp>& v2); private: - const glm::vec3& UNIT_X() { return Vectors::UNIT_X; } - const glm::vec3& UNIT_Y() { return Vectors::UNIT_Y; } - const glm::vec3& UNIT_Z() { return Vectors::UNIT_Z; } - const glm::vec3& UNIT_NEG_X() { return Vectors::UNIT_NEG_X; } - const glm::vec3& UNIT_NEG_Y() { return Vectors::UNIT_NEG_Y; } - const glm::vec3& UNIT_NEG_Z() { return Vectors::UNIT_NEG_Z; } - const glm::vec3& UNIT_XY() { return Vectors::UNIT_XY; } - const glm::vec3& UNIT_XZ() { return Vectors::UNIT_XZ; } - const glm::vec3& UNIT_YZ() { return Vectors::UNIT_YZ; } - const glm::vec3& UNIT_XYZ() { return Vectors::UNIT_XYZ; } - const glm::vec3& FLOAT_MAX() { return Vectors::MAX; } - const glm::vec3& FLOAT_MIN() { return Vectors::MIN; } - const glm::vec3& ZERO() { return Vectors::ZERO; } - const glm::vec3& ONE() { return Vectors::ONE; } - const glm::vec3& TWO() { return Vectors::TWO; } - const glm::vec3& HALF() { return Vectors::HALF; } - const glm::vec3& RIGHT() { return Vectors::RIGHT; } - const glm::vec3& UP() { return Vectors::UP; } - const glm::vec3& FRONT() { return Vectors::FRONT; } + const glm::vec<3,float,glm::packed_highp>& UNIT_X() { return Vectors::UNIT_X; } + const glm::vec<3,float,glm::packed_highp>& UNIT_Y() { return Vectors::UNIT_Y; } + const glm::vec<3,float,glm::packed_highp>& UNIT_Z() { return Vectors::UNIT_Z; } + const glm::vec<3,float,glm::packed_highp>& UNIT_NEG_X() { return Vectors::UNIT_NEG_X; } + const glm::vec<3,float,glm::packed_highp>& UNIT_NEG_Y() { return Vectors::UNIT_NEG_Y; } + const glm::vec<3,float,glm::packed_highp>& UNIT_NEG_Z() { return Vectors::UNIT_NEG_Z; } + const glm::vec<3,float,glm::packed_highp>& UNIT_XY() { return Vectors::UNIT_XY; } + const glm::vec<3,float,glm::packed_highp>& UNIT_XZ() { return Vectors::UNIT_XZ; } + const glm::vec<3,float,glm::packed_highp>& UNIT_YZ() { return Vectors::UNIT_YZ; } + const glm::vec<3,float,glm::packed_highp>& UNIT_XYZ() { return Vectors::UNIT_XYZ; } + const glm::vec<3,float,glm::packed_highp>& FLOAT_MAX() { return Vectors::MAX; } + const glm::vec<3,float,glm::packed_highp>& FLOAT_MIN() { return Vectors::MIN; } + const glm::vec<3,float,glm::packed_highp>& ZERO() { return Vectors::ZERO; } + const glm::vec<3,float,glm::packed_highp>& ONE() { return Vectors::ONE; } + const glm::vec<3,float,glm::packed_highp>& TWO() { return Vectors::TWO; } + const glm::vec<3,float,glm::packed_highp>& HALF() { return Vectors::HALF; } + const glm::vec<3,float,glm::packed_highp>& RIGHT() { return Vectors::RIGHT; } + const glm::vec<3,float,glm::packed_highp>& UP() { return Vectors::UP; } + const glm::vec<3,float,glm::packed_highp>& FRONT() { return Vectors::FRONT; } public: virtual ~Vec3(); diff --git a/libraries/script-engine/src/WebSocketClass.cpp b/libraries/script-engine/src/WebSocketClass.cpp index dada3029510..5e135d9d358 100644 --- a/libraries/script-engine/src/WebSocketClass.cpp +++ b/libraries/script-engine/src/WebSocketClass.cpp @@ -51,7 +51,7 @@ void WebSocketClass::initialize() { connect(_webSocket, &QWebSocket::textMessageReceived, this, &WebSocketClass::handleOnMessage); connect(_webSocket, &QWebSocket::binaryMessageReceived, this, &WebSocketClass::handleOnBinaryMessage); connect(_webSocket, &QWebSocket::connected, this, &WebSocketClass::handleOnOpen); - connect(_webSocket, static_cast(&QWebSocket::error), this, + connect(_webSocket, static_cast(&QWebSocket::errorOccurred), this, &WebSocketClass::handleOnError); _binaryType = QStringLiteral("arraybuffer"); } diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 2f99281e89d..95244eefe42 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -256,14 +256,14 @@ void XMLHttpRequestClass::abortRequest() { void XMLHttpRequestClass::connectToReply(QNetworkReply* reply) { connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(requestDownloadProgress(qint64, qint64))); connect(reply, SIGNAL(metaDataChanged()), this, SLOT(requestMetaDataChanged())); } void XMLHttpRequestClass::disconnectFromReply(QNetworkReply* reply) { disconnect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); - disconnect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); + disconnect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); disconnect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(requestDownloadProgress(qint64, qint64))); disconnect(reply, SIGNAL(metaDataChanged()), this, SLOT(requestMetaDataChanged())); } diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp index ca19abd9572..2edc7d01c59 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp @@ -798,9 +798,9 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(ScriptValue, result), - Q_ARG(const QString&, sourceCode), - Q_ARG(const QString&, fileName)); + Q_GENERIC_RETURN_ARG(ScriptValue, result), + Q_GENERIC_ARG(const QString&, sourceCode), + Q_GENERIC_ARG(const QString&, fileName)); return result; }*/ // Compile and check syntax @@ -1039,8 +1039,8 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro "sourceCode:" << sourceCode << " fileName:" << fileName; #endif BLOCKING_INVOKE_METHOD(this, "evaluate", - Q_RETURN_ARG(ScriptValue, result), - Q_ARG(const ScriptProgramPointer&, program)); + Q_GENERIC_RETURN_ARG(ScriptValue, result), + Q_GENERIC_ARG(const ScriptProgramPointer&, program)); return result; } _evaluatingCounter++; @@ -1422,9 +1422,9 @@ ScriptValue ScriptEngineV8::create(int type, const void* ptr) { Q_ASSERT(_v8Isolate->IsCurrent()); v8::HandleScope handleScope(_v8Isolate); v8::Context::Scope contextScope(getContext()); - QVariant variant(type, ptr); + QVariant variant(QMetaType(type), ptr); V8ScriptValue scriptValue = castVariantToValue(variant); - return ScriptValue(new ScriptValueV8Wrapper(this, std::move(scriptValue))); + return {new ScriptValueV8Wrapper(this, std::move(scriptValue))}; } QVariant ScriptEngineV8::convert(const ScriptValue& value, int typeId) { @@ -1433,21 +1433,21 @@ QVariant ScriptEngineV8::convert(const ScriptValue& value, int typeId) { v8::Context::Scope contextScope(getContext()); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value); if (unwrapped == nullptr) { - return QVariant(); + return {}; } QVariant var; if (!castValueToVariant(unwrapped->toV8Value(), var, typeId)) { - return QVariant(); + return {}; } int destType = var.userType(); if (destType != typeId) { - var.convert(typeId); // if conversion fails then var is set to QVariant() + var.convert(QMetaType(typeId)); // if conversion fails then var is set to QVariant() } return var; - return QVariant(); + return {}; } void ScriptEngineV8::compileTest() { diff --git a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp index 9dfce6f6e9c..ff0ee990859 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp @@ -300,7 +300,7 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de if (obj) { for (const QMetaObject* metaObject = obj->metaObject(); metaObject; metaObject = metaObject->superClass()) { QByteArray typeName = QByteArray(metaObject->className()) + "*"; - int typeId = QMetaType::type(typeName.constData()); + int typeId = QMetaType::fromName(typeName).id(); if (typeId != QMetaType::UnknownType) { destTypeId = typeId; break; @@ -382,7 +382,7 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de } } errorMessage = QString() + "Conversion failure: " + QString(*v8::String::Utf8Value(_v8Isolate, val->ToDetailString(getConstContext()).ToLocalChecked())) - + "to variant. Destination type: " + QMetaType::typeName(destTypeId) +" details: "+ scriptValueDebugDetailsV8(v8Val); + + "to variant. Destination type: " + QMetaType(destTypeId).name() +" details: "+ scriptValueDebugDetailsV8(v8Val); qCDebug(scriptengine_v8) << errorMessage; // V8TODO: this doesn't seem to be necessary anymore but I'm keeping it until all the API is tested @@ -501,12 +501,13 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de } } errorMessage = QString() + "Conversion to variant failed: " + QString(*v8::String::Utf8Value(_v8Isolate, val->ToDetailString(getConstContext()).ToLocalChecked())) - + " Destination type: " + QMetaType::typeName(destTypeId) + " Value details: " + scriptValueDebugDetailsV8(v8Val); + + " Destination type: " + QMetaType(destTypeId).name() + " Value details: " + scriptValueDebugDetailsV8(v8Val); qCDebug(scriptengine_v8) << errorMessage; return false; default: // check to see if this is a pointer to a QObject-derived object - if (QMetaType::typeFlags(destTypeId) & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { + const auto destMetaType = QMetaType(destTypeId); + if (destMetaType.flags() & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { /* Do we really want to permit regular passing of nullptr to native functions? if (!val.isValid() || val.isUndefined() || val.isNull()) { dest = QVariant::fromValue(nullptr); @@ -514,7 +515,7 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de }*/ QObject* obj = ScriptObjectV8Proxy::unwrap(v8Val); if (!obj) return false; - const QMetaObject* destMeta = QMetaType::metaObjectForType(destTypeId); + const QMetaObject* destMeta = destMetaType.metaObject(); Q_ASSERT(destMeta); obj = destMeta->cast(obj); if (!obj) return false; @@ -540,7 +541,7 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de // last chance, just convert it to a variant (impossible on V8) // V8TODO errorMessage = QString() + "Conversion failure: " + QString(*v8::String::Utf8Value(_v8Isolate, val->ToDetailString(getConstContext()).ToLocalChecked())) - + "to variant. Destination type: " + QMetaType::typeName(destTypeId); + + "to variant. Destination type: " + destMetaType.name(); qCDebug(scriptengine_v8) << errorMessage; if(destTypeId == QMetaType::QVariant) { Q_ASSERT(false); @@ -550,7 +551,7 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de } } - return destTypeId == QMetaType::UnknownType || dest.userType() == destTypeId || dest.convert(destTypeId); + return destTypeId == QMetaType::UnknownType || dest.userType() == destTypeId || dest.convert(QMetaType(destTypeId)); } bool ScriptEngineV8::convertJSArrayToVariant(v8::Local array, QVariant &dest) { @@ -562,7 +563,7 @@ bool ScriptEngineV8::convertJSArrayToVariant(v8::Local array, QVarian for (int i = 0; i < length; i++) { v8::Local v8Property; if (!array->Get(context, i).ToLocal(&v8Property)) { - qCDebug(scriptengine_v8) << "ScriptEngineV8::convertJSArrayToVariant could not get property: " + QString(i); + qCDebug(scriptengine_v8) << "ScriptEngineV8::convertJSArrayToVariant could not get property: " + QString::number(i); continue; } QVariant property; @@ -570,7 +571,7 @@ bool ScriptEngineV8::convertJSArrayToVariant(v8::Local array, QVarian if (castValueToVariant(V8ScriptValue(this, v8Property), property, QMetaType::UnknownType)) { properties.append(property); } else { - qCDebug(scriptengine_v8) << "ScriptEngineV8::convertJSArrayToVariant could cast property to variant: " + QString(i); + qCDebug(scriptengine_v8) << "ScriptEngineV8::convertJSArrayToVariant could cast property to variant: " + QString::number(i); ; } } @@ -654,6 +655,9 @@ QString ScriptEngineV8::valueType(const V8ScriptValue& v8Val) { return "undefined"; } +// QT6TODO: where does this belong? +Q_DECLARE_METATYPE(Qt::TimerType); + V8ScriptValue ScriptEngineV8::castVariantToValue(const QVariant& val) { Q_ASSERT(_v8Isolate->IsCurrent()); v8::HandleScope handleScope(_v8Isolate); @@ -731,12 +735,18 @@ V8ScriptValue ScriptEngineV8::castVariantToValue(const QVariant& val) { default: // check to see if this is a pointer to a QObject-derived object // WeakPointerToQObject and SharedPointerToQObject were causing trouble here because some values are handled by custom prototypes instead - if (QMetaType::typeFlags(valTypeId) & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { + if (QMetaType(valTypeId).flags() & (QMetaType::PointerToQObject | QMetaType::TrackingPointerToQObject)) { QObject* obj = val.value(); if (obj == nullptr) return V8ScriptValue(this, v8::Null(_v8Isolate)); //V8TODO: what should be the ownership in this case? return ScriptObjectV8Proxy::newQObject(this, obj); } + + // enums need special treatment, Qt::TimerType fails without this + if (QMetaType(valTypeId).flags() & (QMetaType::IsEnumeration | QMetaType::IsUnsignedEnumeration)) { + return V8ScriptValue(this, v8::Integer::New(_v8Isolate, val.toInt())); + } + // have we set a prototyped variant? { _customTypeProtect.lockForRead(); @@ -748,7 +758,7 @@ V8ScriptValue ScriptEngineV8::castVariantToValue(const QVariant& val) { } // just do a generic variant //V8TODO - qCDebug(scriptengine_v8) << "ScriptEngineV8::castVariantToValue failed for " << QMetaType::typeName(valTypeId); + qCDebug(scriptengine_v8) << "ScriptEngineV8::castVariantToValue failed for " << QMetaType(valTypeId).name(); logBacktrace("ScriptEngineV8::castVariantToValue failed"); //Q_ASSERT(false); return V8ScriptValue(this, v8::Undefined(_v8Isolate)); diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp index d2c73708e7d..9b9892622ee 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp @@ -23,6 +23,7 @@ #include "ScriptContextV8Wrapper.h" #include "ScriptValueV8Wrapper.h" #include "ScriptEngineLoggingV8.h" +#include "shared/QtHelpers.h" Q_DECLARE_METATYPE(ScriptValue) @@ -291,10 +292,10 @@ void ScriptObjectV8Proxy::investigate() { } PropertyDef& propDef = _props.insert(idx, PropertyDef(prop.name(), idx)).value(); - _propNameMap.insert(prop.name(), &propDef); propDef.flags = ScriptValue::Undeletable | ScriptValue::PropertyGetter | ScriptValue::PropertySetter | ScriptValue::QObjectMember; if (prop.isConstant()) propDef.flags |= ScriptValue::ReadOnly; + _propNameMap.insert(prop.name(), propDef); } // discover methods @@ -342,7 +343,7 @@ void ScriptObjectV8Proxy::investigate() { SignalDef& signalDef = _signals.insert(idx, SignalDef(szName, idx)).value(); signalDef.name = szName; signalDef.signal = method; - _signalNameMap.insert(szName, &signalDef); + _signalNameMap.insert(szName, signalDef); methodNames.insert(szName, idx); } else { int originalMethodId = nameLookup.value(); @@ -369,7 +370,7 @@ void ScriptObjectV8Proxy::investigate() { methodDef.name = szName; methodDef.numMaxParams = parameterCount; methodDef.methods.append(method); - _methodNameMap.insert(szName, &methodDef); + _methodNameMap.insert(szName, methodDef); methodNames.insert(szName, idx); } else { int originalMethodId = nameLookup.value(); @@ -433,16 +434,16 @@ ScriptObjectV8Proxy::QueryFlags ScriptObjectV8Proxy::queryProperty(const V8Scrip // check for methods MethodNameMap::const_iterator method = _methodNameMap.find(nameStr); if (method != _methodNameMap.cend()) { - const MethodDef* methodDef = method.value(); - *id = methodDef->_id | METHOD_TYPE; + const MethodDef &methodDef = method.value(); + *id = methodDef._id | METHOD_TYPE; return flags & (HandlesReadAccess | HandlesWriteAccess); } // check for properties PropertyNameMap::const_iterator prop = _propNameMap.find(nameStr); if (prop != _propNameMap.cend()) { - const PropertyDef* propDef = prop.value(); - *id = propDef->_id | PROPERTY_TYPE; + const PropertyDef &propDef = prop.value(); + *id = propDef._id | PROPERTY_TYPE; return flags & (HandlesReadAccess | HandlesWriteAccess); } @@ -1016,6 +1017,20 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo& argume for (int i = 0; i < num_metas; i++) { const QMetaMethod& meta = _metas[i]; + qVarArgLists[i].reserve(_numMaxParams); + + // This check is needed for catching issues caused by a bug in Qt6 that causes metamethod invocations to fail when typedefs are used in header files. +#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) + for (int parameterIndex = 0; parameterIndex < meta.parameterCount(); parameterIndex++) { + if (std::string(meta.parameterTypeName(parameterIndex)) != std::string(meta.parameterMetaType(parameterIndex).name())) { + qCritical() << "ScriptMethodV8Proxy::call: " << fullName() << " parameter " << parameterIndex + << " has a broken type " << meta.parameterTypeName(parameterIndex) + << " Correct type is " << meta.parameterMetaType(parameterIndex).name(); + Q_ASSERT(false); + } + } +#endif + int methodNumArgs = meta.parameterCount(); if (methodNumArgs != numArgs) { continue; @@ -1035,28 +1050,27 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo& argume v8::Local argVal = arguments[arg]; if (methodArgTypeId == scriptValueTypeId) { qScriptArgLists[i].append(ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine, argVal)))); - qGenArgsVectors[i][arg] = Q_ARG(ScriptValue, qScriptArgLists[i].back()); + qGenArgsVectors[i][arg] = Q_GENERIC_ARG(ScriptValue, qScriptArgLists[i].back()); } else if (methodArgTypeId == QMetaType::QVariant) { - QVariant varArgVal; - if (!_engine->castValueToVariant(V8ScriptValue(_engine, argVal), varArgVal, methodArgTypeId)) { + qVarArgLists[i].emplace_back(); + if (!_engine->castValueToVariant(V8ScriptValue(_engine, argVal), qVarArgLists[i].back(), methodArgTypeId)) { conversionFailures++; + qVarArgLists[i].pop_back(); } else { - qVarArgLists[i].append(varArgVal); - qGenArgsVectors[i][arg] = Q_ARG(QVariant, qVarArgLists[i].back()); + qGenArgsVectors[i][arg] = Q_GENERIC_ARG(QVariant, qVarArgLists[i].back()); } } else { - QVariant varArgVal; - if (!_engine->castValueToVariant(V8ScriptValue(_engine, argVal), varArgVal, methodArgTypeId)) { + qVarArgLists[i].emplace_back(); + if (!_engine->castValueToVariant(V8ScriptValue(_engine, argVal), qVarArgLists[i].back(), methodArgTypeId)) { conversionFailures++; } else { - qVarArgLists[i].append(varArgVal); const QVariant& converted = qVarArgLists[i].back(); conversionPenaltyScore += _engine->computeCastPenalty(V8ScriptValue(_engine, argVal), methodArgTypeId); // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant // A const_cast is needed because calling data() would detach the QVariant. qGenArgsVectors[i][arg] = - QGenericArgument(QMetaType::typeName(converted.userType()), const_cast(converted.constData())); + QGenericArgument(QMetaType(converted.userType()).name(), const_cast(converted.constData())); } } } @@ -1108,7 +1122,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo& argume return; } else if (returnTypeId == scriptValueTypeId) { ScriptValue result; - bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0], + bool success = meta.invoke(qobject, Qt::DirectConnection, Q_GENERIC_RETURN_ARG(ScriptValue, result), qGenArgs[0], qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6], qGenArgs[7], qGenArgs[8], qGenArgs[9]); if (!success) { @@ -1121,7 +1135,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo& argume } else { // a lot of type conversion assistance thanks to https://stackoverflow.com/questions/28457819/qt-invoke-method-with-qvariant const char* typeName = meta.typeName(); - QVariant qRetVal(returnTypeId, static_cast(NULL)); + QVariant qRetVal(QMetaType(returnTypeId), static_cast(NULL)); QGenericReturnArgument sRetVal(typeName, const_cast(qRetVal.constData())); bool success = @@ -1259,7 +1273,7 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu for (int arg = 0; arg < numArgs; ++arg) { int methodArgTypeId = _meta.parameterType(arg); Q_ASSERT(methodArgTypeId != QMetaType::UnknownType); - QVariant argValue(methodArgTypeId, arguments[arg + 1]); + QVariant argValue(QMetaType(methodArgTypeId), arguments[arg + 1]); args[arg] = _engine->castVariantToValue(argValue).get(); } for (ConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter) { diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h index 14b8f1900eb..3d7584aae36 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h @@ -69,9 +69,9 @@ class ScriptObjectV8Proxy final { using MethodDefMap = QHash; using SignalDefMap = QHash; using InstanceMap = QHash >; - using PropertyNameMap = QHash; - using MethodNameMap = QHash; - using SignalNameMap = QHash; + using PropertyNameMap = QHash; + using MethodNameMap = QHash; + using SignalNameMap = QHash; static constexpr uint PROPERTY_TYPE = 0x1000; static constexpr uint METHOD_TYPE = 0x2000; diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index 769e2c66044..9658f825104 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -448,7 +448,7 @@ void ScriptValueV8Wrapper::setProperty(quint32 arrayIndex, const ScriptValue& va qCDebug(scriptengine_v8) << "Failed to set property"; } } else { - qCDebug(scriptengine_v8) << "Failed to set property: " + QString(arrayIndex) + " - parent is not an object"; + qCDebug(scriptengine_v8) << "Failed to set property: " + QString::number(arrayIndex) + " - parent is not an object"; } //V8TODO: what about flags? //_value.setProperty(arrayIndex, unwrapped, (V8ScriptValue::PropertyFlags)(int)flags); diff --git a/libraries/shared/src/ApplicationVersion.cpp b/libraries/shared/src/ApplicationVersion.cpp index 5c2d5ad11ce..c6be7532b76 100644 --- a/libraries/shared/src/ApplicationVersion.cpp +++ b/libraries/shared/src/ApplicationVersion.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include ApplicationVersion::ApplicationVersion(const QString& versionString) : diff --git a/libraries/shared/src/DebugDraw.h b/libraries/shared/src/DebugDraw.h index c5ba2905144..88681101135 100644 --- a/libraries/shared/src/DebugDraw.h +++ b/libraries/shared/src/DebugDraw.h @@ -10,6 +10,10 @@ #ifndef hifi_DebugDraw_h #define hifi_DebugDraw_h +#include + +#include "RegisteredMetaTypes.h" + #include #include #include @@ -18,7 +22,6 @@ #include #include -#include #include /*@jsdoc @@ -58,7 +61,7 @@ class DebugDraw : public QObject { * DebugDraw.drawRay(start, end, color); * }); */ - Q_INVOKABLE void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color); + Q_INVOKABLE void drawRay(const glm::vec<3,float,glm::packed_highp>& start, const glm::vec<3,float,glm::packed_highp>& end, const glm::vec<4,float,glm::packed_highp>& color); /*@jsdoc * Draws lines in world space, visible for a single frame. To make the lines visually persist, you need to repeatedly draw @@ -83,8 +86,8 @@ class DebugDraw : public QObject { * DebugDraw.drawRays(lines, color, translation, rotation); * }); */ - Q_INVOKABLE void drawRays(const std::vector>& lines, const glm::vec4& color, - const glm::vec3& translation = glm::vec3(0.0f, 0.0f, 0.0f), const glm::quat& rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f)); + Q_INVOKABLE void drawRays(const std::vector, glm::vec<3,float,glm::packed_highp>>>& lines, const glm::vec<4,float,glm::packed_highp>& color, + const glm::vec<3,float,glm::packed_highp>& translation = glm::vec<3,float,glm::packed_highp>(0.0f, 0.0f, 0.0f), const glm::qua& rotation = glm::qua(1.0f, 0.0f, 0.0f, 0.0f)); /*@jsdoc * Adds or updates a debug marker in world coordinates. This marker is drawn every frame until it is removed using @@ -109,8 +112,8 @@ class DebugDraw : public QObject { * DebugDraw.removeMarker(MARKER_NAME); * }, 5000); */ - Q_INVOKABLE void addMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, - const glm::vec4& color, float size = 1.0f); + Q_INVOKABLE void addMarker(const QString& key, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& position, + const glm::vec<4,float,glm::packed_highp>& color, float size = 1.0f); /*@jsdoc * Removes a debug marker that was added in world coordinates. @@ -142,8 +145,8 @@ class DebugDraw : public QObject { * DebugDraw.removeMyAvatarMarker(MARKER_NAME); * }, 5000); */ - Q_INVOKABLE void addMyAvatarMarker(const QString& key, const glm::quat& rotation, const glm::vec3& position, - const glm::vec4& color, float size = 1.0f); + Q_INVOKABLE void addMyAvatarMarker(const QString& key, const glm::qua& rotation, const glm::vec<3,float,glm::packed_highp>& position, + const glm::vec<4,float,glm::packed_highp>& color, float size = 1.0f); /*@jsdoc * Removes a debug marker that was added in avatar coordinates. @@ -165,8 +168,8 @@ class DebugDraw : public QObject { MarkerMap getMyAvatarMarkerMap() const; void updateMyAvatarPos(const glm::vec3& pos) { _myAvatarPos = pos; } const glm::vec3& getMyAvatarPos() const { return _myAvatarPos; } - void updateMyAvatarRot(const glm::quat& rot) { _myAvatarRot = rot; } - const glm::quat& getMyAvatarRot() const { return _myAvatarRot; } + void updateMyAvatarRot(const glm::qua& rot) { _myAvatarRot = rot; } + const glm::qua& getMyAvatarRot() const { return _myAvatarRot; } Rays getRays() const; void clearRays(); diff --git a/libraries/shared/src/Grab.cpp b/libraries/shared/src/Grab.cpp index 195bc61f66c..118794ff70b 100644 --- a/libraries/shared/src/Grab.cpp +++ b/libraries/shared/src/Grab.cpp @@ -11,6 +11,8 @@ #include "Grab.h" +#include + QByteArray Grab::toByteArray() { QByteArray ba; QDataStream dataStream(&ba, QIODevice::WriteOnly); diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index 71748ffd10e..c9030b69d5b 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -20,19 +20,20 @@ #include #include #include +#include #include "PathUtils.h" #include "SharedLogging.h" QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringList& argumentList) { - QMultiMap mergedMap; + QVariantMap mergedMap; // Add anything in the CL parameter list to the variant map. // Take anything with a dash in it as a key, and the values after it as the value. const QString DASHED_KEY_REGEX_STRING = "(^-{1,2})([\\w-]+)"; - QRegExp dashedKeyRegex(DASHED_KEY_REGEX_STRING); + QRegularExpression dashedKeyRegex(DASHED_KEY_REGEX_STRING); int keyIndex = argumentList.indexOf(dashedKeyRegex); int nextKeyIndex = 0; @@ -43,7 +44,7 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL while (keyIndex != -1) { if (argumentList[keyIndex] != CONFIG_FILE_OPTION) { // we have a key - look forward to see how many values associate to it - QString key = dashedKeyRegex.cap(2); + QString key = dashedKeyRegex.namedCaptureGroups()[2]; nextKeyIndex = argumentList.indexOf(dashedKeyRegex, keyIndex + 1); @@ -115,7 +116,7 @@ void HifiConfigVariantMap::addMissingValuesToExistingMap(QVariantMap& existingMa if (existingMap.contains(key)) { // if this is just a regular value, we're done - we don't ovveride - if (newMap[key].canConvert(QMetaType::QVariantMap) && existingMap[key].canConvert(QMetaType::QVariantMap)) { + if (newMap[key].canConvert(QMetaType(QMetaType::QVariantMap)) && existingMap[key].canConvert(QMetaType(QMetaType::QVariantMap))) { // there's a variant map below and the existing map has one too, so we need to keep recursing addMissingValuesToExistingMap(*static_cast(existingMap[key].data()), newMap[key].toMap()); } @@ -134,7 +135,7 @@ QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool if (dotIndex == -1) { return &variantMap[firstKey]; } - if (!variantMap[firstKey].canConvert(QMetaType::QVariantMap)) { + if (!variantMap[firstKey].canConvert(QMetaType(QMetaType::QVariantMap))) { variantMap[firstKey] = QVariantMap(); } return valueForKeyPath(*static_cast(variantMap[firstKey].data()), keyPath.mid(dotIndex + 1), diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index e64f8e29c35..60c85bd1009 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/libraries/shared/src/PathUtils.cpp b/libraries/shared/src/PathUtils.cpp index be605334068..283fabe3fd2 100644 --- a/libraries/shared/src/PathUtils.cpp +++ b/libraries/shared/src/PathUtils.cpp @@ -192,7 +192,7 @@ bool PathUtils::deleteMyTemporaryDir(QString dirName) { QRegularExpression re { "^" + QRegularExpression::escape(appName) + "\\-(?\\d+)\\-(?\\d+)$" }; auto match = re.match(dirName); - auto pid = match.capturedRef("pid").toLongLong(); + auto pid = match.capturedView("pid").toLongLong(); if (match.hasMatch() && rootTempDir.exists(dirName) && pid == qApp->applicationPid()) { auto absoluteDirPath = QDir(rootTempDir.absoluteFilePath(dirName)); @@ -227,8 +227,7 @@ int PathUtils::removeTemporaryApplicationDirs(QString appName) { auto match = re.match(dirName); if (match.hasMatch()) { - auto pid = match.capturedRef("pid").toLongLong(); - auto timestamp = match.capturedRef("timestamp"); + auto pid = match.capturedView("pid").toLongLong(); if (!processIsRunning(pid)) { qDebug() << " Removing old temporary directory: " << dir.absoluteFilePath(); absoluteDirPath.removeRecursively(); @@ -246,7 +245,7 @@ QString fileNameWithoutExtension(const QString& fileName, const QVector QString fileNameLowered = fileName.toLower(); foreach (const QString possibleExtension, possibleExtensions) { if (fileNameLowered.endsWith(possibleExtension.toLower())) { - return fileName.left(fileName.count() - possibleExtension.count() - 1); + return fileName.left(fileName.size() - possibleExtension.size() - 1); } } return fileName; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index b3b742e1ba3..99b57224bbf 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -20,6 +20,9 @@ #include #include +#include +#include + #include "AACube.h" #include "ShapeInfo.h" #include "SharedUtil.h" @@ -44,6 +47,7 @@ Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(AACube) Q_DECLARE_METATYPE(std::function); Q_DECLARE_METATYPE(std::function); +Q_DECLARE_METATYPE(QTimer*); // Mat4 /*@jsdoc diff --git a/libraries/shared/src/RunningMarker.cpp b/libraries/shared/src/RunningMarker.cpp index cb7b39320c4..09e16a40253 100644 --- a/libraries/shared/src/RunningMarker.cpp +++ b/libraries/shared/src/RunningMarker.cpp @@ -47,5 +47,5 @@ void RunningMarker::deleteRunningMarkerFile() { } QString RunningMarker::getFilePath() const { - return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + _name; + return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + _name; } diff --git a/libraries/shared/src/Sampler.cpp b/libraries/shared/src/Sampler.cpp index f106a218731..4e0a45237aa 100644 --- a/libraries/shared/src/Sampler.cpp +++ b/libraries/shared/src/Sampler.cpp @@ -126,45 +126,45 @@ QDebug& operator<<(QDebug& dbg, const Sampler& s) { QString result = "[ "; result += "borderColor: ("; - result += s.getBorderColor().r; + result += QString::number(s.getBorderColor().r); result += ", "; - result += s.getBorderColor().g; + result += QString::number(s.getBorderColor().g); result += ", "; - result += s.getBorderColor().b; + result += QString::number(s.getBorderColor().b); result += ", "; - result += s.getBorderColor().a; + result += QString::number(s.getBorderColor().a); result += "), "; result += "maxAnistropy: "; - result += s.getMaxAnisotropy(); + result += QString::number(s.getMaxAnisotropy()); result += ", "; result += "filter: "; - result += s.getFilter(); + result += QString::number(s.getFilter()); result += ", "; result += "comparisonFunction: "; - result += (uint8_t)s.getComparisonFunction(); + result += QString::number((uint8_t)s.getComparisonFunction()); result += ", "; result += "wrap: ("; - result += s.getWrapModeU(); + result += QString::number(s.getWrapModeU()); result += ", "; - result += s.getWrapModeV(); + result += QString::number(s.getWrapModeV()); result += ", "; - result += s.getWrapModeW(); + result += QString::number(s.getWrapModeW()); result += "), "; result += "mipOffset: "; - result += s.getMipOffset(); + result += QString::number(s.getMipOffset()); result += ", "; result += "minMip: "; - result += s.getMinMip(); + result += QString::number(s.getMinMip()); result += ", "; result += "maxMip: "; - result += s.getMaxMip(); + result += QString::number(s.getMaxMip()); result += ", "; result += "]"; diff --git a/libraries/shared/src/SettingHelpers.cpp b/libraries/shared/src/SettingHelpers.cpp index b4caa2f7bf4..8882aa630cd 100644 --- a/libraries/shared/src/SettingHelpers.cpp +++ b/libraries/shared/src/SettingHelpers.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "SharedLogging.h" @@ -64,10 +65,10 @@ void loadOldINIFile(QSettings& settings) { if (!iniSettings.allKeys().isEmpty()) { qCDebug(shared) << "No data in json settings file, trying to load old ini settings file."; - for (auto key : iniSettings.allKeys()) { + for (const auto &key : iniSettings.allKeys()) { auto variant = iniSettings.value(key); - if (variant.type() == QVariant::String) { + if (variant.typeId() == QMetaType::QString) { auto string = variant.toString(); if (string == "true") { variant = true; @@ -91,7 +92,7 @@ void loadOldINIFile(QSettings& settings) { } QStringList splitArgs(const QString& string, int idx) { - int length = string.length(); + qsizetype length = string.length(); Q_ASSERT(length > 0); Q_ASSERT(string.at(idx) == QLatin1Char('(')); Q_ASSERT(string.at(length - 1) == QLatin1Char(')')); @@ -120,42 +121,44 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { for (auto it = map.cbegin(); it != map.cend(); ++it) { auto& key = it.key(); auto& variant = it.value(); - auto variantType = variant.type(); + auto variantType = variant.typeId(); // Switch some types so they are readable/modifiable in the json file - if (variantType == QVariant(1.0f).type()) { // float - variantType = QVariant::Double; + if (variantType == QMetaType::Float) { // float + variantType = QMetaType::Double; } - if (variantType == QVariant((quint16)0).type()) { // uint16 - variantType = QVariant::UInt; + if (variantType == QMetaType::UShort) { // uint16 + variantType = QMetaType::UInt; } - if (variantType == QVariant::Url) { // QUrl - variantType = QVariant::String; + if (variantType == QMetaType::QUrl) { // QUrl + variantType = QMetaType::QString; + } + + if (!variant.isValid()) { + object.insert(key, QJsonValue()); + continue; } switch (variantType) { // QML has problems with QVariant::Hash - case QVariant::Hash: { + case QMetaType::QVariantHash: { qCritical() << "Unsupported variant type" << variant.typeName() << ";" << key << variant; Q_ASSERT(false); break; } - case QVariant::Invalid: - object.insert(key, QJsonValue()); - break; - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Int: - case QVariant::UInt: - case QVariant::Bool: - case QVariant::Double: - case QVariant::Map: - case QVariant::List: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::Int: + case QMetaType::UInt: + case QMetaType::Bool: + case QMetaType::Double: + case QMetaType::QVariantMap: + case QMetaType::QVariantList: object.insert(key, QJsonValue::fromVariant(variant)); break; - case QVariant::String: { + case QMetaType::QString: { QString result = variant.toString(); if (result.startsWith(QLatin1Char('@'))) { result.prepend(QLatin1Char('@')); @@ -164,7 +167,7 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { break; } - case QVariant::ByteArray: { + case QMetaType::QByteArray: { QByteArray a = variant.toByteArray(); QString result = QLatin1String("@ByteArray("); int sz = a.size(); @@ -177,7 +180,7 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { object.insert(key, result); break; } - case QVariant::Rect: { + case QMetaType::QRect: { QRect r = qvariant_cast(variant); QString result = QLatin1String("@Rect("); result += QString::number(r.x()); @@ -191,7 +194,7 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { object.insert(key, result); break; } - case QVariant::Size: { + case QMetaType::QSize: { QSize s = qvariant_cast(variant); QString result = QLatin1String("@Size("); result += QString::number(s.width()); @@ -201,7 +204,7 @@ QJsonDocument variantMapToJsonDocument(const QSettings::SettingsMap& map) { object.insert(key, result); break; } - case QVariant::Point: { + case QMetaType::QPoint: { QPoint p = qvariant_cast(variant); QString result = QLatin1String("@Point("); result += QString::number(p.x()); diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 0f2bae11703..6a719a01873 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -298,7 +298,7 @@ uint64_t ShapeInfo::getHash() const { QString url = _url.toString(); if (!url.isEmpty()) { QByteArray baUrl = url.toLocal8Bit(); - uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size()); + uint32_t urlHash = qChecksum(baUrl); hasher.hashUint64((uint64_t)urlHash); } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 55bb1f01763..7003fb7e246 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -190,7 +190,7 @@ void outputBits(unsigned char byte, QDebug* continuedDebug) { qts << qSetPadChar('0'); if (isalnum(byte)) { - qts << " (" << QString(byte) << ") : "; + qts << " (" << QString(QChar(byte)) << ") : "; } else { qts << " (0x" << Qt::hex << qSetFieldWidth(2) << byte << qSetFieldWidth(0) << "): "; } @@ -752,9 +752,9 @@ QString formatSecondsElapsed(float seconds) { } else { result += " day "; } - result += QDateTime::fromTime_t(rest).toUTC().toString("h 'hours' m 'minutes' s 'seconds'"); + result += QDateTime::fromSecsSinceEpoch(rest).toUTC().toString("h 'hours' m 'minutes' s 'seconds'"); } else { - result = QDateTime::fromTime_t(seconds).toUTC().toString("h 'hours' m 'minutes' s 'seconds'"); + result = QDateTime::fromSecsSinceEpoch(seconds).toUTC().toString("h 'hours' m 'minutes' s 'seconds'"); } return result; } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index c40cae5f766..653856bddd1 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "NumericalConstants.h" // When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows @@ -188,8 +189,7 @@ QString formatSecondsElapsed(float seconds); bool similarStrings(const QString& stringA, const QString& stringB); template -uint qHash(const std::shared_ptr& ptr, uint seed = 0) -{ +size_t qHash(const std::shared_ptr& ptr, size_t seed = 0) { return qHash(ptr.get(), seed); } diff --git a/libraries/shared/src/ShutdownEventListener.cpp b/libraries/shared/src/ShutdownEventListener.cpp index 6f043cd43e6..53e90e8aa34 100644 --- a/libraries/shared/src/ShutdownEventListener.cpp +++ b/libraries/shared/src/ShutdownEventListener.cpp @@ -39,7 +39,7 @@ ShutdownEventListener::ShutdownEventListener(QObject* parent) : QObject(parent) } -bool ShutdownEventListener::nativeEventFilter(const QByteArray &eventType, void* msg, long* result) { +bool ShutdownEventListener::nativeEventFilter(const QByteArray &eventType, void* msg, qintptr* result) { #ifdef Q_OS_WIN if (eventType == "windows_generic_MSG") { MSG* message = (MSG*)msg; diff --git a/libraries/shared/src/ShutdownEventListener.h b/libraries/shared/src/ShutdownEventListener.h index 8a9363e2c84..7076aff70e2 100644 --- a/libraries/shared/src/ShutdownEventListener.h +++ b/libraries/shared/src/ShutdownEventListener.h @@ -20,7 +20,7 @@ class ShutdownEventListener : public QObject, public QAbstractNativeEventFilter public: static ShutdownEventListener& getInstance(); - virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override; + virtual bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result) override; private: ShutdownEventListener(QObject* parent = 0); }; diff --git a/libraries/shared/src/ThreadHelpers.h b/libraries/shared/src/ThreadHelpers.h index 42de117e670..db77493872d 100644 --- a/libraries/shared/src/ThreadHelpers.h +++ b/libraries/shared/src/ThreadHelpers.h @@ -11,6 +11,7 @@ #ifndef hifi_ThreadHelpers_h #define hifi_ThreadHelpers_h +#include #include #include diff --git a/libraries/shared/src/Trace.cpp b/libraries/shared/src/Trace.cpp index e9e77b55ae2..0cdf0096043 100644 --- a/libraries/shared/src/Trace.cpp +++ b/libraries/shared/src/Trace.cpp @@ -84,7 +84,7 @@ void TraceEvent::writeJson(QTextStream& out) const { QJsonObject ev { { "name", QJsonValue(name) }, { "cat", category.categoryName() }, - { "ph", QString(type) }, + { "ph", QString(static_cast(type)) }, { "ts", timestamp }, { "pid", processID }, { "tid", threadID } diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h index 54dfea77cf8..7abd45c442c 100644 --- a/libraries/shared/src/shared/Camera.h +++ b/libraries/shared/src/shared/Camera.h @@ -41,8 +41,8 @@ static int cameraModeId = qRegisterMetaType(); class Camera : public QObject { Q_OBJECT - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientation) + Q_PROPERTY(glm::vec<3,float,glm::packed_highp> position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::qua orientation READ getOrientation WRITE setOrientation) Q_PROPERTY(QString mode READ getModeString WRITE setModeString NOTIFY modeUpdated) Q_PROPERTY(QVariantMap frustum READ getViewFrustum CONSTANT) Q_PROPERTY(bool captureMouse READ getCaptureMouse WRITE setCaptureMouse NOTIFY captureMouseChanged) @@ -88,7 +88,7 @@ public slots: * @function Camera.getPosition * @returns {Vec3} The current camera position. */ - glm::vec3 getPosition() const { return _position; } + glm::vec<3,float,glm::packed_highp> getPosition() const { return _position; } /*@jsdoc * Sets the camera position. You can also set the position using the {@link Camera|Camera.position} property. Only works if @@ -96,7 +96,7 @@ public slots: * @function Camera.setPosition * @param {Vec3} position - The position to set the camera at. */ - void setPosition(const glm::vec3& position); + void setPosition(const glm::vec<3,float,glm::packed_highp>& position); /*@jsdoc * Gets the current camera orientation. You can also get the orientation using the {@link Camera|Camera.orientation} @@ -104,7 +104,7 @@ public slots: * @function Camera.getOrientation * @returns {Quat} The current camera orientation. */ - glm::quat getOrientation() const { return _orientation; } + glm::qua getOrientation() const { return _orientation; } /*@jsdoc * Sets the camera orientation. You can also set the orientation using the {@link Camera|Camera.orientation} property. Only @@ -112,7 +112,7 @@ public slots: * @function Camera.setOrientation * @param {Quat} orientation - The orientation to set the camera to. */ - void setOrientation(const glm::quat& orientation); + void setOrientation(const glm::qua& orientation); /*@jsdoc * Gets the current mouse capture state. @@ -202,7 +202,7 @@ public slots: * * Controller.mousePressEvent.connect(onMousePressEvent); */ - void lookAt(const glm::vec3& position); + void lookAt(const glm::vec<3,float,glm::packed_highp>& position); /*@jsdoc * Sets the camera to continue looking at the specified position even while the camera moves. Only works if @@ -210,7 +210,7 @@ public slots: * @function Camera.keepLookingAt * @param {Vec3} position - The position to keep looking at. */ - void keepLookingAt(const glm::vec3& position); + void keepLookingAt(const glm::vec<3,float,glm::packed_highp>& position); /*@jsdoc * Stops the camera from continually looking at the position that was set with {@link Camera.keepLookingAt}. diff --git a/libraries/shared/src/shared/FileLogger.cpp b/libraries/shared/src/shared/FileLogger.cpp index d467aed0f86..f16bdc6ebc8 100644 --- a/libraries/shared/src/shared/FileLogger.cpp +++ b/libraries/shared/src/shared/FileLogger.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "FileUtils.h" #include "NetworkUtils.h" diff --git a/libraries/shared/src/shared/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp index 14ac78bfbd9..5ba37e4d980 100644 --- a/libraries/shared/src/shared/FileUtils.cpp +++ b/libraries/shared/src/shared/FileUtils.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -122,7 +123,7 @@ QString FileUtils::standardPath(QString subfolder) { #ifdef Q_OS_ANDROID QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); #else - QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + QString path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); #endif if (!subfolder.startsWith("/")) { subfolder.prepend("/"); diff --git a/libraries/shared/src/shared/JSONHelpers.cpp b/libraries/shared/src/shared/JSONHelpers.cpp index 298a1ea85d6..d151f4241d2 100644 --- a/libraries/shared/src/shared/JSONHelpers.cpp +++ b/libraries/shared/src/shared/JSONHelpers.cpp @@ -30,7 +30,7 @@ T glmFromJson(const QJsonValue& json) { T result; if (json.isArray()) { QJsonArray array = json.toArray(); - auto length = std::min(array.size(), result.length()); + auto length = std::min(array.size(), static_cast(result.length())); for (auto i = 0; i < length; ++i) { result[i] = (float)array[i].toDouble(); } @@ -136,7 +136,7 @@ void qObjectFromJsonValue(const QJsonValue& j, QObject& o) { qObjectFromJsonValue(it.value(), *child); } } else { - o.setProperty(key.c_str(), it.value()); + o.setProperty(key.c_str(), it.value().toVariant()); } } } diff --git a/libraries/shared/src/shared/PlatformHelper.h b/libraries/shared/src/shared/PlatformHelper.h index 760eb7bd420..5896c2ab4bf 100644 --- a/libraries/shared/src/shared/PlatformHelper.h +++ b/libraries/shared/src/shared/PlatformHelper.h @@ -12,6 +12,7 @@ #include #include +#include #include "../DependencyManager.h" class PlatformHelper : public QObject, public Dependency { diff --git a/libraries/shared/src/shared/QtHelpers.h b/libraries/shared/src/shared/QtHelpers.h index 880d285f815..9c8c0daf67a 100644 --- a/libraries/shared/src/shared/QtHelpers.h +++ b/libraries/shared/src/shared/QtHelpers.h @@ -18,6 +18,11 @@ #include "../Profile.h" +// Macros for these are missing from QT6 +// QT6TODO: replace QGenericArgument and QGenericReturnArgument with modern equivalents +#define Q_GENERIC_ARG(type, data) QArgument(#type, data) +#define Q_GENERIC_RETURN_ARG(type, data) QReturnArgument(#type, data) + #if defined(Q_OS_WIN) // Enable event queue debugging //#define DEBUG_EVENT_QUEUE @@ -113,4 +118,35 @@ blockingInvokeMethod(const char* callingFunction, QObject* context, Func functio #define BLOCKING_INVOKE_METHOD(obj, member, ...) \ ::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__) +inline QMultiHash qVariantToQMultiHash(const QVariant &variant) { + QMultiHash multiHash; + // QT6TODO: check if variant can be converted to a list + + for(QVariant item : variant.toList()) { + // QT6TODO: I'm not sure if this will work correctly + multiHash.insert(item.toList()[0].toString(), item.toList()[1]); + } + return multiHash; +} + +inline QVariant qMultiHashToQVariant(QMultiHash hash) { + QVariantList variant; + // QT6TODO: I'm not sure if this will work correctly + for(QString key : hash.keys()) { + QVariantList list; + list << key; + list << hash.values(key); + variant << QVariant(list); + } + return variant; +} + +inline QMultiHash qHashToQMultiHash(const QHash &hash) { + QMultiHash multiHash; + for(const QString &key : hash.keys()) { + multiHash.insert(key, hash.value(key)); + } + return multiHash; +} + #endif diff --git a/libraries/shared/src/shared/StringHelpers.cpp b/libraries/shared/src/shared/StringHelpers.cpp index 39ac23e510f..fbcded6937d 100644 --- a/libraries/shared/src/shared/StringHelpers.cpp +++ b/libraries/shared/src/shared/StringHelpers.cpp @@ -8,11 +8,12 @@ #include "StringHelpers.h" +#include #include /// Note: this will not preserve line breaks in the original input. QString simpleWordWrap(const QString& input, int maxCharactersPerLine) { - QStringList words = input.split(QRegExp("\\s+")); + QStringList words = input.split(QRegularExpression("\\s+")); QString output; QString currentLine; foreach(const auto& word, words) { diff --git a/libraries/shared/src/shared/platform/WinHelper.cpp b/libraries/shared/src/shared/platform/WinHelper.cpp index 3de82af0872..ca67c049aef 100644 --- a/libraries/shared/src/shared/platform/WinHelper.cpp +++ b/libraries/shared/src/shared/platform/WinHelper.cpp @@ -16,9 +16,7 @@ class WinHelper : public PlatformHelper, public QAbstractNativeEventFilter { public: - WinHelper() { - QAbstractEventDispatcher::instance()->installNativeEventFilter(this); - } + WinHelper() { QAbstractEventDispatcher::instance()->installNativeEventFilter(this); } ~WinHelper() { auto eventDispatcher = QAbstractEventDispatcher::instance(); @@ -27,7 +25,7 @@ class WinHelper : public PlatformHelper, public QAbstractNativeEventFilter { } } - bool nativeEventFilter(const QByteArray& eventType, void* message, long*) override { + bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr*) override { MSG* msg = static_cast(message); if (msg->message == WM_POWERBROADCAST) { switch (msg->wParam) { diff --git a/libraries/task/src/task/Config.h b/libraries/task/src/task/Config.h index 785f94d4285..5313daf3705 100644 --- a/libraries/task/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -50,9 +50,18 @@ template class PersistentConfig : public C { _default = toJsonValue(*this).toObject().toVariantMap(); - _presets.unite(list.toVariantMap()); + auto listMap = list.toVariantMap(); + // QT6TODO: I'm not sure about this. + //_presets.unite(listMap); + for (auto it = listMap.cbegin(); it != listMap.cend(); it++) { + if (_presets.contains(it.key())) { + _presets[it.key()] = it.value(); + } else { + _presets.insert(it.key(), it.value()); + } + } if (C::isEnabled()) { - _presets.insert(DEFAULT, _default); + _presets.insert(DEFAULT, toJsonValue(*this).toObject().toVariantMap()); } _presets.insert(NONE, QVariantMap{{ "enabled", false }}); @@ -69,8 +78,9 @@ template class PersistentConfig : public C { _preset.set(preset); if (_presets.contains(preset)) { // Always start back at default to remain deterministic + // QT6TODO: I'm not sure about maps and multimaps here. Shouldn't there be one entry per key? QVariantMap config = _default; - QVariantMap presetConfig = _presets[preset].toMap(); + QVariantMap presetConfig = _presets.value(preset).toMap(); for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) { config.insert(it.key(), it.value()); } @@ -79,8 +89,8 @@ template class PersistentConfig : public C { } protected: - QMultiMap _default; - QMultiMap _presets; + QVariantMap _default; + QVariantMap _presets; Setting::Handle _preset; }; diff --git a/libraries/task/src/task/Varying.h b/libraries/task/src/task/Varying.h index 686a00446bd..7f9e42c6c9d 100644 --- a/libraries/task/src/task/Varying.h +++ b/libraries/task/src/task/Varying.h @@ -32,7 +32,10 @@ class Varying { template Varying(const T& data, const std::string& name = "noname") : _concept(std::make_shared>(data, name)) {} template bool canCast() const { return !!std::dynamic_pointer_cast>(_concept); } - template const T& get() const { return std::static_pointer_cast>(_concept)->_data; } + template const T& get() const { + Q_ASSERT(std::dynamic_pointer_cast>(_concept)); + return std::static_pointer_cast>(_concept)->_data; + } template T& edit() { return std::static_pointer_cast>(_concept)->_data; } const std::string name() const { return _concept->name(); } diff --git a/libraries/ui-plugins/src/ui-plugins/PluginContainer.cpp b/libraries/ui-plugins/src/ui-plugins/PluginContainer.cpp index 0c71d4fa69a..f277c20eb49 100644 --- a/libraries/ui-plugins/src/ui-plugins/PluginContainer.cpp +++ b/libraries/ui-plugins/src/ui-plugins/PluginContainer.cpp @@ -7,6 +7,7 @@ // #include "PluginContainer.h" +#include #include #include #include diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 4056d5026dc..ab8975e0e84 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,9 +1,9 @@ # Copyright 2013-2018, High Fidelity, Inc. -# Copyright 2020-2023 Overte e.V. +# Copyright 2020-2025 Overte e.V. # SPDX-License-Identifier: Apache-2.0 set(TARGET_NAME ui) -setup_hifi_library(OpenGL Multimedia Network Qml Quick WebChannel WebSockets XmlPatterns ${PLATFORM_QT_COMPONENTS}) +setup_hifi_library(OpenGL Multimedia Network Qml Quick WebChannel WebSockets Xml WebEngineQuick GuiPrivate ${PLATFORM_QT_COMPONENTS}) link_hifi_libraries(shared networking qml gl audio audio-client plugins pointers script-engine) include_hifi_library_headers(controllers) diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h index b0cc64245f4..c6c57949c5a 100644 --- a/libraries/ui/src/DesktopPreviewProvider.h +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -8,6 +8,7 @@ #include #include +#include #include class DesktopPreviewProvider : public QObject, public Dependency { diff --git a/libraries/ui/src/InfoView.cpp b/libraries/ui/src/InfoView.cpp index c14ff6bf64a..e9d73dcef26 100644 --- a/libraries/ui/src/InfoView.cpp +++ b/libraries/ui/src/InfoView.cpp @@ -13,7 +13,7 @@ #include #include -#include +//#include #include const QUrl InfoView::QML{ "InfoView.qml" }; const QString InfoView::NAME{ "InfoView" }; @@ -34,12 +34,14 @@ void InfoView::registerType() { } QString fetchVersion(const QUrl& url) { - QXmlQuery query; - query.bindVariable("file", QVariant(url)); - query.setQuery("string((doc($file)//input[@id='version'])[1]/@value)"); - QString r; - query.evaluateTo(&r); - return r.trimmed(); + // QT6TODO: QXmlQuery is not available in Qt6 + //QXmlQuery query; + //query.bindVariable("file", QVariant(url)); + //query.setQuery("string((doc($file)//input[@id='version'])[1]/@value)"); + //QString r; + //query.evaluateTo(&r); + //return r.trimmed(); + return {}; } void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQuery) { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 72320252f59..e9d84bec17b 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -30,6 +30,8 @@ #include "ui/ToolbarScriptingInterface.h" #include +#include + #include "MainWindow.h" /*@jsdoc @@ -119,14 +121,30 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { return false; } -static QTouchDevice _touchDevice; +static std::shared_ptr _touchDevice; + OffscreenUi::OffscreenUi() { static std::once_flag once; std::call_once(once, [&] { - _touchDevice.setCapabilities(QTouchDevice::Position); - _touchDevice.setType(QTouchDevice::TouchScreen); - _touchDevice.setName("OffscreenUiTouchDevice"); - _touchDevice.setMaximumTouchPoints(4); + // QT6TODO: choose the best parameters for this: + /*_touchDevice = std::make_shared( + "OffscreenUiTouchDevice", + 1, + QInputDevice::DeviceType::AllDevices, + QPointingDevice::PointerType::AllPointerTypes, + QInputDevice::Capability::All, + 4, //maxPoints + 2 // buttonCount + );*/ + _touchDevice = std::make_shared( + "OffscreenUiTouchDevice", + 1, + QInputDevice::DeviceType::Mouse, + QPointingDevice::PointerType::Cursor, + QInputDevice::Capability::None, + 1, //maxPoints + 2 // buttonCount + ); }); auto pointerManager = DependencyManager::get(); @@ -140,15 +158,15 @@ OffscreenUi::OffscreenUi() { } void OffscreenUi::hoverBeginEvent(const PointerEvent& event) { - OffscreenQmlSurface::hoverBeginEvent(event, _touchDevice); + OffscreenQmlSurface::hoverBeginEvent(event, *_touchDevice); } void OffscreenUi::hoverEndEvent(const PointerEvent& event) { - OffscreenQmlSurface::hoverEndEvent(event, _touchDevice); + OffscreenQmlSurface::hoverEndEvent(event, *_touchDevice); } void OffscreenUi::handlePointerEvent(const PointerEvent& event) { - OffscreenQmlSurface::handlePointerEvent(event, _touchDevice); + OffscreenQmlSurface::handlePointerEvent(event, *_touchDevice); } QObject* OffscreenUi::getFlags() { @@ -214,8 +232,8 @@ bool OffscreenUi::isPointOnDesktopWindow(QVariant point) { if (_desktop) { QVariant result; BLOCKING_INVOKE_METHOD(_desktop, "isPointOnWindow", - Q_RETURN_ARG(QVariant, result), - Q_ARG(QVariant, point)); + Q_GENERIC_RETURN_ARG(QVariant, result), + Q_GENERIC_ARG(QVariant, point)); return result.toBool(); } return false; @@ -319,12 +337,12 @@ QMessageBox::StandardButton OffscreenUi::messageBox(Icon icon, const QString& ti if (QThread::currentThread() != thread()) { QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; BLOCKING_INVOKE_METHOD(this, "messageBox", - Q_RETURN_ARG(QMessageBox::StandardButton, result), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QString, text), - Q_ARG(QMessageBox::StandardButtons, buttons), - Q_ARG(QMessageBox::StandardButton, defaultButton)); + Q_GENERIC_RETURN_ARG(QMessageBox::StandardButton, result), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QString, text), + Q_GENERIC_ARG(QMessageBox::StandardButtons, buttons), + Q_GENERIC_ARG(QMessageBox::StandardButton, defaultButton)); return result; } @@ -335,12 +353,12 @@ ModalDialogListener* OffscreenUi::asyncMessageBox(Icon icon, const QString& titl if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "asyncMessageBox", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QString, text), - Q_ARG(QMessageBox::StandardButtons, buttons), - Q_ARG(QMessageBox::StandardButton, defaultButton)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QString, text), + Q_GENERIC_ARG(QMessageBox::StandardButtons, buttons), + Q_GENERIC_ARG(QMessageBox::StandardButton, defaultButton)); return ret; } @@ -473,11 +491,11 @@ QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const Q if (QThread::currentThread() != thread()) { QVariant result; BLOCKING_INVOKE_METHOD(this, "inputDialog", - Q_RETURN_ARG(QVariant, result), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QString, label), - Q_ARG(QVariant, current)); + Q_GENERIC_RETURN_ARG(QVariant, result), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QString, label), + Q_GENERIC_ARG(QVariant, current)); return result; } @@ -488,11 +506,11 @@ ModalDialogListener* OffscreenUi::inputDialogAsync(const Icon icon, const QStrin if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "inputDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QString, label), - Q_ARG(QVariant, current)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QString, label), + Q_GENERIC_ARG(QVariant, current)); return ret; } @@ -506,10 +524,10 @@ QVariant OffscreenUi::customInputDialog(const Icon icon, const QString& title, c if (QThread::currentThread() != thread()) { QVariant result; BLOCKING_INVOKE_METHOD(this, "customInputDialog", - Q_RETURN_ARG(QVariant, result), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QVariantMap, config)); + Q_GENERIC_RETURN_ARG(QVariant, result), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QVariantMap, config)); return result; } @@ -526,10 +544,10 @@ ModalDialogListener* OffscreenUi::customInputDialogAsync(const Icon icon, const if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "customInputDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(Icon, icon), - Q_ARG(QString, title), - Q_ARG(QVariantMap, config)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(Icon, icon), + Q_GENERIC_ARG(QString, title), + Q_GENERIC_ARG(QVariantMap, config)); return ret; } @@ -547,14 +565,14 @@ void OffscreenUi::togglePinned() { } void OffscreenUi::setPinned(bool pinned) { - bool invokeResult = _desktop && QMetaObject::invokeMethod(_desktop, "setPinned", Q_ARG(QVariant, pinned)); + bool invokeResult = _desktop && QMetaObject::invokeMethod(_desktop, "setPinned", Q_GENERIC_ARG(QVariant, pinned)); if (!invokeResult) { qWarning() << "Failed to set window visibility"; } } void OffscreenUi::setConstrainToolbarToCenterX(bool constrained) { - bool invokeResult = _desktop && QMetaObject::invokeMethod(_desktop, "setConstrainToolbarToCenterX", Q_ARG(QVariant, constrained)); + bool invokeResult = _desktop && QMetaObject::invokeMethod(_desktop, "setConstrainToolbarToCenterX", Q_GENERIC_ARG(QVariant, constrained)); if (!invokeResult) { qWarning() << "Failed to set toolbar constraint"; } @@ -814,12 +832,12 @@ QString OffscreenUi::fileOpenDialog(const QString& caption, const QString& dir, if (QThread::currentThread() != thread()) { QString result; BLOCKING_INVOKE_METHOD(this, "fileOpenDialog", - Q_RETURN_ARG(QString, result), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(QString, result), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return result; } @@ -836,12 +854,12 @@ ModalDialogListener* OffscreenUi::fileOpenDialogAsync(const QString& caption, co if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "fileOpenDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return ret; } @@ -858,12 +876,12 @@ QString OffscreenUi::fileSaveDialog(const QString& caption, const QString& dir, if (QThread::currentThread() != thread()) { QString result; BLOCKING_INVOKE_METHOD(this, "fileSaveDialog", - Q_RETURN_ARG(QString, result), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(QString, result), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return result; } @@ -882,12 +900,12 @@ ModalDialogListener* OffscreenUi::fileSaveDialogAsync(const QString& caption, co if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "fileSaveDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return ret; } @@ -906,12 +924,12 @@ QString OffscreenUi::existingDirectoryDialog(const QString& caption, const QStri if (QThread::currentThread() != thread()) { QString result; BLOCKING_INVOKE_METHOD(this, "existingDirectoryDialog", - Q_RETURN_ARG(QString, result), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(QString, result), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return result; } @@ -928,12 +946,12 @@ ModalDialogListener* OffscreenUi::existingDirectoryDialogAsync(const QString& ca if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "existingDirectoryDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return ret; } @@ -1068,12 +1086,12 @@ QString OffscreenUi::assetOpenDialog(const QString& caption, const QString& dir, if (QThread::currentThread() != thread()) { QString result; BLOCKING_INVOKE_METHOD(this, "assetOpenDialog", - Q_RETURN_ARG(QString, result), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(QString, result), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return result; } @@ -1091,12 +1109,12 @@ ModalDialogListener* OffscreenUi::assetOpenDialogAsync(const QString& caption, c if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "assetOpenDialogAsync", - Q_RETURN_ARG(ModalDialogListener*, ret), - Q_ARG(QString, caption), - Q_ARG(QString, dir), - Q_ARG(QString, filter), - Q_ARG(QString*, selectedFilter), - Q_ARG(QFileDialog::Options, options)); + Q_GENERIC_RETURN_ARG(ModalDialogListener*, ret), + Q_GENERIC_ARG(QString, caption), + Q_GENERIC_ARG(QString, dir), + Q_GENERIC_ARG(QString, filter), + Q_GENERIC_ARG(QString*, selectedFilter), + Q_GENERIC_ARG(QFileDialog::Options, options)); return ret; } @@ -1135,13 +1153,25 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { - QMouseEvent* mouseEvent = static_cast(event); - QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos()); + QMouseEvent* mouseEvent = dynamic_cast(event); + Q_ASSERT(mouseEvent); + QPointF transformedPos = mapToVirtualScreen(mouseEvent->position()); // FIXME: touch events are always being accepted. Use mouse events on the OffScreenUi for now, and investigate properly switching to touch events // (using handlePointerEvent) later - QMouseEvent mappedEvent(mouseEvent->type(), transformedPos, mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); + QMouseEvent mappedEvent(mouseEvent->type(), transformedPos, mouseEvent->globalPosition(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers(), _touchDevice.get()); mappedEvent.ignore(); + mappedEvent.setTimestamp(mouseEvent->timestamp()); + QMutableEventPoint::setPosition(mappedEvent.point(0), transformedPos); + QMutableEventPoint::setScenePosition(mappedEvent.point(0), transformedPos); + QMutableEventPoint::setTimestamp(mappedEvent.point(0), mouseEvent->timestamp()); if (QCoreApplication::sendEvent(getWindow(), &mappedEvent)) { + + // QT6TODO: I added this as a fix for Qt6 but is it needed? + // Mouse release events are always accepted for some reason, so a workaround is needed. + //if (event->type() == QEvent::MouseButtonRelease) { + // return false; + //} + return mappedEvent.isAccepted(); } break; diff --git a/libraries/ui/src/QmlFragmentClass.cpp b/libraries/ui/src/QmlFragmentClass.cpp index e3f31557023..3eaca595134 100644 --- a/libraries/ui/src/QmlFragmentClass.cpp +++ b/libraries/ui/src/QmlFragmentClass.cpp @@ -45,7 +45,7 @@ ScriptValue QmlFragmentClass::internal_constructor(ScriptContext* context, Scrip Q_ASSERT(retVal); if (QThread::currentThread() != qApp->thread()) { retVal->moveToThread(qApp->thread()); - BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_ARG(QVariantMap, properties)); + BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_GENERIC_ARG(QVariantMap, properties)); } else { retVal->initQml(properties); } diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 6542bc750f0..1987da14a8a 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -40,7 +40,7 @@ ScriptValue QmlWebWindowClass::internal_constructor(ScriptContext* context, Scri QString QmlWebWindowClass::getURL() { if (QThread::currentThread() != thread()) { QString result; - BLOCKING_INVOKE_METHOD(this, "getURL", Q_RETURN_ARG(QString, result)); + BLOCKING_INVOKE_METHOD(this, "getURL", Q_GENERIC_RETURN_ARG(QString, result)); return result; } diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 74734fdc43c..821cadb1304 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -80,7 +80,7 @@ ScriptValue QmlWindowClass::internal_constructor(ScriptContext* context, ScriptE Q_ASSERT(retVal); if (QThread::currentThread() != qApp->thread()) { retVal->moveToThread(qApp->thread()); - BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_ARG(QVariantMap, properties)); + BLOCKING_INVOKE_METHOD(retVal, "initQml", Q_GENERIC_ARG(QVariantMap, properties)); } else { retVal->initQml(properties); } @@ -200,7 +200,7 @@ void QmlWindowClass::emitWebEvent(const QVariant& webMessage) { const QString RAISE_KEYBOARD = "_RAISE_KEYBOARD"; const QString RAISE_KEYBOARD_NUMERIC = "_RAISE_KEYBOARD_NUMERIC"; const QString LOWER_KEYBOARD = "_LOWER_KEYBOARD"; - QString messageString = webMessage.type() == QVariant::String ? webMessage.toString() : ""; + QString messageString = webMessage.typeId() == QMetaType::QString ? webMessage.toString() : ""; if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) { QQuickItem *quickItem = asQuickItem(); if (quickItem) { @@ -265,7 +265,7 @@ void QmlWindowClass::setVisible(bool visible) { bool QmlWindowClass::isVisible() { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "isVisible", Q_RETURN_ARG(bool, result)); + BLOCKING_INVOKE_METHOD(this, "isVisible", Q_GENERIC_RETURN_ARG(bool, result)); return result; } @@ -286,7 +286,7 @@ bool QmlWindowClass::isVisible() { glm::vec2 QmlWindowClass::getPosition() { if (QThread::currentThread() != thread()) { vec2 result; - BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(glm::vec2, result)); + BLOCKING_INVOKE_METHOD(this, "getPosition", Q_GENERIC_RETURN_ARG(glm::vec2, result)); return result; } @@ -327,7 +327,7 @@ glm::vec2 toGlm(const QSizeF& size) { glm::vec2 QmlWindowClass::getSize() { if (QThread::currentThread() != thread()) { vec2 result; - BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(glm::vec2, result)); + BLOCKING_INVOKE_METHOD(this, "getSize", Q_GENERIC_RETURN_ARG(glm::vec2, result)); return result; } diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index 76a5be0c2d0..ebdf5b31fa9 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -50,8 +50,8 @@ class ScriptEngine; // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWindowClass : public QObject { Q_OBJECT - Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition NOTIFY positionChanged) - Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> position READ getPosition WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(glm::vec<2,float,glm::packed_highp> size READ getSize WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) private: @@ -102,14 +102,14 @@ public slots: * @function OverlayWindow.getPosition * @returns {Vec2} The position of the window, in pixels. */ - glm::vec2 getPosition(); + glm::vec<2,float,glm::packed_highp> getPosition(); /*@jsdoc * Sets the position of the window, from a {@link Vec2}. * @function OverlayWindow.setPosition * @param {Vec2} position - The position of the window, in pixels. */ - void setPosition(const glm::vec2& position); + void setPosition(const glm::vec<2,float,glm::packed_highp>& position); /*@jsdoc * Sets the position of the window, from a pair of numbers. @@ -125,14 +125,14 @@ public slots: * @function OverlayWindow.getSize * @returns {Vec2} The size of the window interior, in pixels. */ - glm::vec2 getSize(); + glm::vec<2,float,glm::packed_highp> getSize(); /*@jsdoc * Sets the size of the window interior, from a {@link Vec2}. * @function OverlayWindow.setSize * @param {Vec2} size - The size of the window interior, in pixels. */ - void setSize(const glm::vec2& size); + void setSize(const glm::vec<2,float,glm::packed_highp>& size); /*@jsdoc * Sets the size of the window interior, from a pair of numbers. @@ -200,7 +200,7 @@ public slots: * // QML file, "OverlayWindow.qml". * * import QtQuick 2.5 - * import QtQuick.Controls 1.4 + * import QtQuick.Controls 2.3 * * Rectangle { * width: parent.width @@ -275,7 +275,7 @@ public slots: * @param {Vec2} position - The position of the window, in pixels. * @returns {Signal} */ - void moved(glm::vec2 position); + void moved(glm::vec<2,float,glm::packed_highp> position); /*@jsdoc * Triggered when the window changes size. diff --git a/libraries/ui/src/Tooltip.cpp b/libraries/ui/src/Tooltip.cpp index bd2c4e6d8f4..d0d87406b6d 100644 --- a/libraries/ui/src/Tooltip.cpp +++ b/libraries/ui/src/Tooltip.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index c29a71245b7..bbbf9f01bb3 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -85,7 +85,10 @@ void MenuUserData::updateQmlItemFromAction() { _qml->setProperty("text", text); _qml->setProperty("shortcut", _action->shortcut().toString()); _qml->setProperty("checked", _action->isChecked()); - _qml->setProperty("visible", _action->isVisible()); + + // Qt6 TODO: Inconsistent segfault inside Qt, possible thread race condition? + // How come it's only on "visible" and not the other properties? + //_qml->setProperty("visible", _action->isVisible()); } void MenuUserData::clear() { @@ -143,6 +146,9 @@ QObject* VrMenu::findMenuObject(const QString& menuOption) { void VrMenu::addMenu(QMenu* menu) { + auto *ui = dynamic_cast(parent()); + Q_ASSERT(ui); + QQmlEngine *engine = ui->getSurfaceContext()->engine(); Q_ASSERT(!MenuUserData::hasData(menu->menuAction())); QObject* parent = menu->parent(); QObject* qmlParent = nullptr; @@ -159,20 +165,29 @@ void VrMenu::addMenu(QMenu* menu) { Q_ASSERT(false); } QVariant returnedValue; - bool invokeResult = QMetaObject::invokeMethod(qmlParent, "addMenu", Qt::DirectConnection, - Q_RETURN_ARG(QVariant, returnedValue), - Q_ARG(QVariant, QVariant::fromValue(menu->title()))); - Q_ASSERT(invokeResult); - Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x - QObject* result = returnedValue.value(); - Q_ASSERT(result); - if (!result) { - qWarning() << "Unable to create QML menu for widget menu: " << menu->title(); + // QT6TODO: move to constructor, we need to load the component only once + QQmlComponent menuComponent(engine); + //menuComponent.loadFromModule("QtQuick.Controls", "Menu"); + menuComponent.loadUrl(PathUtils::qmlUrl("controls/WrappedMenu.qml")); + if (menuComponent.status() == QQmlComponent::Status::Error) { + qDebug() << "QML Menu component error: " << menuComponent.errorString(); return; } + Q_ASSERT(menuComponent.isReady()); + // QT6TODO: what deletes the item later? + QObject *menuObject = menuComponent.create(ui->getSurfaceContext()); + Q_ASSERT(menuObject); + menuObject->setObjectName(menu->title()); + menuObject->setProperty("title", menu->title()); + menuObject->setParent(qmlParent); + qDebug() << "menuObject: " << QString(menuObject->metaObject()->metaType().name()); + bool invokeResult = QMetaObject::invokeMethod(qmlParent, "addMenuWrap", Qt::DirectConnection, + Q_ARG(QVariant, QVariant::fromValue(menuObject))); + Q_ASSERT(invokeResult); + Q_UNUSED(invokeResult); // Bind the QML and Widget together - new MenuUserData(menu->menuAction(), result, qmlParent); + new MenuUserData(menu->menuAction(), menuObject, qmlParent); } void bindActionToQmlAction(QObject* qmlAction, QAction* action, QObject* qmlParent) { @@ -191,6 +206,10 @@ void bindActionToQmlAction(QObject* qmlAction, QAction* action, QObject* qmlPare class QQuickMenuItem1; void VrMenu::addAction(QMenu* menu, QAction* action) { + auto *ui = dynamic_cast(parent()); + Q_ASSERT(ui); + QQmlEngine *engine = ui->getSurfaceContext()->engine(); + Q_ASSERT(!MenuUserData::hasData(action)); Q_ASSERT(MenuUserData::hasData(menu->menuAction())); @@ -200,20 +219,36 @@ void VrMenu::addAction(QMenu* menu, QAction* action) { } QObject* menuQml = findMenuObject(userData->uuid.toString()); Q_ASSERT(menuQml); - QQuickMenuItem1* returnedValue { nullptr }; - bool invokeResult = QMetaObject::invokeMethod(menuQml, "addItem", Qt::DirectConnection, - Q_RETURN_ARG(QQuickMenuItem1*, returnedValue), - Q_ARG(QString, action->text())); + + QQmlComponent menuItemComponent(engine); + menuItemComponent.loadFromModule("QtQuick.Controls", "MenuItem"); + + if (menuItemComponent.status() == QQmlComponent::Status::Error) { + qDebug() << "QML Menu component error: " << menuItemComponent.errorString(); + return; + } + Q_ASSERT(menuItemComponent.isReady()); + // QT6TODO: I think parent deletes item later? Are there extra options for ownership? + QObject *menuItemObject = menuItemComponent.create(ui->getSurfaceContext()); + Q_ASSERT(menuItemObject); + menuItemObject->setObjectName(action->text()); + menuItemObject->setProperty("text", action->text()); + menuItemObject->setParent(menuQml); + + bool invokeResult = QMetaObject::invokeMethod(menuQml, "addItemWrap", Qt::DirectConnection, + Q_ARG(QVariant, QVariant::fromValue(menuItemObject))); Q_ASSERT(invokeResult); - Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x - QObject* result = reinterpret_cast(returnedValue); // returnedValue.value(); - Q_ASSERT(result); + Q_UNUSED(invokeResult); // Bind the QML and Widget together - bindActionToQmlAction(result, action, _rootMenu); + bindActionToQmlAction(menuItemObject, action, _rootMenu); } void VrMenu::addSeparator(QMenu* menu) { + auto *ui = dynamic_cast(parent()); + Q_ASSERT(ui); + QQmlEngine *engine = ui->getSurfaceContext()->engine(); + Q_ASSERT(MenuUserData::hasData(menu->menuAction())); MenuUserData* userData = MenuUserData::forObject(menu->menuAction()); if (!userData) { @@ -222,12 +257,31 @@ void VrMenu::addSeparator(QMenu* menu) { QObject* menuQml = findMenuObject(userData->uuid.toString()); Q_ASSERT(menuQml); - bool invokeResult = QMetaObject::invokeMethod(menuQml, "addSeparator", Qt::DirectConnection); + QQmlComponent menuSeparatorComponent(engine); + menuSeparatorComponent.loadFromModule("QtQuick.Controls", "MenuSeparator"); + + if (menuSeparatorComponent.status() == QQmlComponent::Status::Error) { + qDebug() << "QML Menu component error: " << menuSeparatorComponent.errorString(); + return; + } + Q_ASSERT(menuSeparatorComponent.isReady()); + QObject *menuSeparatorObject = menuSeparatorComponent.create(ui->getSurfaceContext()); + Q_ASSERT(menuSeparatorObject); + menuSeparatorObject->setParent(menuQml); + qDebug() << "VrMenu::addSeparator menuQml " << menuQml->objectName(); + qDebug() << "VrMenu::addSeparator menuQml type " << menuQml->metaObject()->className(); + + bool invokeResult = QMetaObject::invokeMethod(menuQml, "addItemWrap", Qt::DirectConnection, + Q_ARG(QVariant, QVariant::fromValue(menuSeparatorObject))); Q_ASSERT(invokeResult); - Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x + Q_UNUSED(invokeResult); } void VrMenu::insertAction(QAction* before, QAction* action) { + auto *ui = dynamic_cast(parent()); + Q_ASSERT(ui); + QQmlEngine *engine = ui->getSurfaceContext()->engine(); + QObject* beforeQml{ nullptr }; { MenuUserData* beforeUserData = MenuUserData::forObject(before); @@ -238,23 +292,40 @@ void VrMenu::insertAction(QAction* before, QAction* action) { beforeQml = findMenuObject(beforeUserData->uuid.toString()); } QObject* menu = beforeQml->parent(); - QQuickMenuItem1* returnedValue { nullptr }; + Q_ASSERT(menu); + + // QT6TODO: move to constructor, we need to load the component only once + QQmlComponent menuItemComponent(engine); + menuItemComponent.loadFromModule("QtQuick.Controls", "MenuItem"); + //menuComponent.loadUrl(PathUtils::qmlUrl("controls/WrappedMenu.qml")); + if (menuItemComponent.status() == QQmlComponent::Status::Error) { + qDebug() << "QML Menu component error: " << menuItemComponent.errorString(); + return; + } + Q_ASSERT(menuItemComponent.isReady()); + // QT6TODO: what deletes the item later? + QObject *menuItemObject = menuItemComponent.create(ui->getSurfaceContext()); + Q_ASSERT(menuItemObject); + menuItemObject->setObjectName(action->text()); + menuItemObject->setProperty("text", action->text()); + menuItemObject->setParent(menu); + + qDebug() << "menuObject: " << QString(menuItemObject->metaObject()->metaType().name()); + bool invokeResult = QMetaObject::invokeMethod(menu, "addItemWrap", Qt::DirectConnection, + Q_ARG(QVariant, QVariant::fromValue(menuItemObject))); // FIXME this needs to find the index of the beforeQml item and call insertItem(int, object) - bool invokeResult = QMetaObject::invokeMethod(menu, "addItem", Qt::DirectConnection, - Q_RETURN_ARG(QQuickMenuItem1*, returnedValue), - Q_ARG(QString, action->text())); Q_ASSERT(invokeResult); - QObject* result = reinterpret_cast(returnedValue); // returnedValue.value(); - Q_ASSERT(result); - if ( result ) { - bindActionToQmlAction(result, action, _rootMenu); + + if (menuItemObject) { + bindActionToQmlAction(menuItemObject, action, _rootMenu); } else { - qWarning() << "Failed to find addItem() method in object " << menu << ". Not inserting action " << action; + qWarning() << "Failed to find addItemWrap() method in object " << menu << ". Not inserting action " << action; } } class QQuickMenuBase; class QQuickMenu1; +class QQuickMenu; void VrMenu::removeAction(QAction* action) { if (!action) { diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 6e8557e1d24..a112c8d6a62 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -247,8 +247,8 @@ void Menu::removeAction(MenuWrapper* menu, const QString& actionName) { void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { if (thread() != QThread::currentThread()) { BLOCKING_INVOKE_METHOD(this, "setIsOptionChecked", - Q_ARG(const QString&, menuOption), - Q_ARG(bool, isChecked)); + Q_GENERIC_ARG(const QString&, menuOption), + Q_GENERIC_ARG(bool, isChecked)); return; } QAction* menu = _actionHash.value(menuOption); @@ -595,7 +595,7 @@ QAction* MenuWrapper::addAction(const QString& menuName) { } QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) { - QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut); + QAction* action = _realMenu->addAction(menuName, shortcut, receiver, member); auto offscreenUi = DependencyManager::get(); if (offscreenUi) { offscreenUi->addMenuInitializer([=, this](VrMenu* vrMenu) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index bac992492cf..f52a187881a 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -14,7 +14,8 @@ #include #include -#include +// QT6TODO +//#include #include #include #include @@ -27,10 +28,13 @@ #include #include #include -#include -#include +// QT6TODO +//#include +// QT6TODO +//#include #include #include +#include #include #include #include @@ -45,6 +49,7 @@ #include #include +#include #include #include @@ -112,6 +117,7 @@ class AudioHandler : public QObject, QRunnable { private: QString _newTargetDevice; + std::shared_ptr _audioOutput; QSharedPointer _surface; std::vector _players; }; @@ -194,34 +200,39 @@ AudioHandler::AudioHandler(OffscreenQmlSurface* surface, const QString& deviceNa } void AudioHandler::run() { + for (auto player : _players) { - auto mediaState = player->state(); - QMediaService* svc = player->service(); + auto mediaState = player->playbackState(); + /*QMediaService* svc = player->service(); if (nullptr == svc) { continue; - } - QAudioOutputSelectorControl* out = + }*/ + /*QAudioOutputSelectorControl* out = qobject_cast(svc->requestControl(QAudioOutputSelectorControl_iid)); if (nullptr == out) { continue; - } - QString deviceOuput; - auto outputs = out->availableOutputs(); - for (int i = 0; i < outputs.size(); i++) { - QString output = outputs[i]; - QString description = out->outputDescription(output); - if (description == _newTargetDevice) { - deviceOuput = output; + }*/ + //auto audioClient = DependencyManager::get(); + //auto outputs = audioClient->getAudioDevices(QAudioDevice::Output); + auto outputs = QMediaDevices::audioOutputs(); + QAudioDevice selectedDevice; + for (const auto &output: outputs) { + if (output.description() == _newTargetDevice) { + selectedDevice = output; break; } } - out->setActiveOutput(deviceOuput); - svc->releaseControl(out); + auto oldAudioOutput = _audioOutput; + _audioOutput = std::make_shared(); + _audioOutput->setDevice(selectedDevice); + // Q6TODO: we could set volume here in the future. + player->setAudioOutput(_audioOutput.get()); + //svc->releaseControl(out); // if multimedia was paused, it will start playing automatically after changing audio device // this will reset it back to a paused state - if (mediaState == QMediaPlayer::State::PausedState) { + if (mediaState == QMediaPlayer::PlaybackState::PausedState) { player->pause(); - } else if (mediaState == QMediaPlayer::State::StoppedState) { + } else if (mediaState == QMediaPlayer::PlaybackState::StoppedState) { player->stop(); } } @@ -248,7 +259,7 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { fileSelector->setExtraSelectors(FileUtils::getFileSelectors()); static std::once_flag once; - std::call_once(once, [] { + std::call_once(once, [] { qRegisterMetaType(); qRegisterMetaType(); qmlRegisterType("Hifi", 1, 0, "SoundEffect"); @@ -355,8 +366,8 @@ void OffscreenQmlSurface::onRootCreated() { getSurfaceContext()->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow())); // Connect with the audio client and listen for audio device changes - connect(DependencyManager::get().data(), &AudioClient::deviceChanged, this, [this](QAudio::Mode mode, const HifiAudioDeviceInfo& device) { - if (mode == QAudio::Mode::AudioOutput) { + connect(DependencyManager::get().data(), &AudioClient::deviceChanged, this, [this](QAudioDevice::Mode mode, const HifiAudioDeviceInfo& device) { + if (mode == QAudioDevice::Mode::Output) { QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, device.deviceName())); } }); @@ -424,7 +435,7 @@ unsigned int OffscreenQmlSurface::deviceIdByTouchPoint(qreal x, qreal y) { auto mapped = getRootItem()->mapFromGlobal(QPoint(x, y)); for (auto pair : _activeTouchPoints) { - if (mapped.x() == (int)pair.second.touchPoint.pos().x() && mapped.y() == (int)pair.second.touchPoint.pos().y()) { + if (mapped.x() == (int)pair.second.touchPoint.position().x() && mapped.y() == (int)pair.second.touchPoint.position().y()) { return pair.first; } } @@ -449,7 +460,7 @@ PointerEvent::EventType OffscreenQmlSurface::choosePointerEventType(QEvent::Type } } -void OffscreenQmlSurface::hoverBeginEvent(const PointerEvent& event, class QTouchDevice& device) { +void OffscreenQmlSurface::hoverBeginEvent(const PointerEvent& event, class QPointingDevice& device) { #if defined(DISABLE_QML) return; #endif @@ -457,7 +468,7 @@ void OffscreenQmlSurface::hoverBeginEvent(const PointerEvent& event, class QTouc _activeTouchPoints[event.getID()].hovering = true; } -void OffscreenQmlSurface::hoverEndEvent(const PointerEvent& event, class QTouchDevice& device) { +void OffscreenQmlSurface::hoverEndEvent(const PointerEvent& event, class QPointingDevice& device) { #if defined(DISABLE_QML) return; #endif @@ -473,7 +484,7 @@ void OffscreenQmlSurface::hoverEndEvent(const PointerEvent& event, class QTouchD } } -bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QTouchDevice& device, bool release) { +bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QPointingDevice& device, bool release) { #if defined(DISABLE_QML) return false; #endif @@ -485,13 +496,14 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT QPointF windowPoint(event.getPos2D().x, event.getPos2D().y); - Qt::TouchPointState state = Qt::TouchPointStationary; + //Qt::TouchPointState state = Qt::TouchPointStationary; + QEventPoint::State state = QEventPoint::State::Stationary; if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { - state = Qt::TouchPointPressed; + state = QEventPoint::State::Pressed; } else if (event.getType() == PointerEvent::Release && event.getButton() == PointerEvent::PrimaryButton) { - state = Qt::TouchPointReleased; - } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].touchPoint.pos()) { - state = Qt::TouchPointMoved; + state = QEventPoint::State::Released; + } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].touchPoint.position()) { + state = QEventPoint::State::Updated; } // Remove the touch point if: @@ -499,7 +511,7 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT // - this was a release event and we aren't still hovering auto touchPoint = _activeTouchPoints.find(event.getID()); bool removeTouchPoint = - release || (touchPoint != _activeTouchPoints.end() && !touchPoint->second.hovering && state == Qt::TouchPointReleased); + release || (touchPoint != _activeTouchPoints.end() && !touchPoint->second.hovering && state == QEventPoint::State::Released); QEvent::Type touchType = QEvent::TouchUpdate; if (_activeTouchPoints.empty()) { // If the first active touch point is being created, send a begin @@ -510,37 +522,42 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT } { - QTouchEvent::TouchPoint point; - point.setId(event.getID()); - point.setState(state); - point.setPos(windowPoint); - point.setScreenPos(windowPoint); + // Synthetic touch events aren't documented anywhere, + // and I don't think Qt really expects you to create them. + // + // qtbase/tests/auto/widgets/util/qscroller/tst_qscroller.cpp + // tst_QScroller::kineticScroll + QTouchEvent::TouchPoint point(0); + QMutableEventPoint::setState(point, QEventPoint::State::Pressed); + QMutableEventPoint::setPosition(point, windowPoint); + QMutableEventPoint::setScenePosition(point, windowPoint); + QMutableEventPoint::setGlobalPosition(point, windowPoint); + QMutableEventPoint::setId(point, event.getID()); + QMutableEventPoint::setState(point, state); + QMutableEventPoint::setTimestamp(point, (ulong)QDateTime::currentMSecsSinceEpoch()); + QMutableEventPoint::setGlobalLastPosition(point, touchPoint->second.touchPoint.globalPosition()); + QMutableEventPoint::setGlobalPressPosition(point, touchPoint->second.touchPoint.globalPosition()); + _activeTouchPoints[event.getID()].touchPoint = point; - if (state == Qt::TouchPointPressed) { + if (state == QEventPoint::State::Pressed) { _activeTouchPoints[event.getID()].pressed = true; - } else if (state == Qt::TouchPointReleased) { + QMutableEventPoint::setPressure(_activeTouchPoints[event.getID()].touchPoint, 1.0); + } else if (state == QEventPoint::State::Released) { _activeTouchPoints[event.getID()].pressed = false; + QMutableEventPoint::setPressure(_activeTouchPoints[event.getID()].touchPoint, 0); } } - QTouchEvent touchEvent(touchType, &device, event.getKeyboardModifiers()); - { - QList touchPoints; - Qt::TouchPointStates touchPointStates; - for (const auto& entry : _activeTouchPoints) { - touchPointStates |= entry.second.touchPoint.state(); - touchPoints.push_back(entry.second.touchPoint); - } - - touchEvent.setDevice(&device); - touchEvent.setWindow(getWindow()); - touchEvent.setTarget(getRootItem()); - touchEvent.setTouchPoints(touchPoints); - touchEvent.setTouchPointStates(touchPointStates); - touchEvent.setTimestamp((ulong)QDateTime::currentMSecsSinceEpoch()); - touchEvent.ignore(); + QList touchPoints; + for (const auto& entry : _activeTouchPoints) { + touchPoints.push_back(entry.second.touchPoint); } + QTouchEvent touchEvent(touchType, &device, event.getKeyboardModifiers(), touchPoints); + + touchEvent.setTimestamp((ulong)QDateTime::currentMSecsSinceEpoch()); + touchEvent.ignore(); + // Send mouse events to the surface so that HTML dialog elements work with mouse press and hover. // // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will @@ -557,9 +574,10 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT bool eventSent = false; bool eventsAccepted = true; - if (event.getType() == PointerEvent::Move) { + // QT6TODO: I think this is not needed? + /*if (event.getType() == PointerEvent::Move) { QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, - event.getKeyboardModifiers()); + event.getKeyboardModifiers(), &device); // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install // need to investigate into why this crash is happening. //_qmlContext->setContextProperty("lastMousePosition", windowPoint); @@ -568,7 +586,7 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT eventSent = true; eventsAccepted &= mouseEvent.isAccepted(); } - } + }*/ if (touchType == QEvent::TouchBegin) { _touchBeginAccepted = QCoreApplication::sendEvent(getWindow(), &touchEvent); @@ -585,7 +603,7 @@ bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QT if (event.getType() == PointerEvent::Scroll) { auto scroll = event.getScroll() * POINTEREVENT_SCROLL_SENSITIVITY; - QWheelEvent wheelEvent(windowPoint, windowPoint, QPoint(), QPoint(scroll.x, scroll.y), buttons, event.getKeyboardModifiers(), Qt::ScrollPhase::NoScrollPhase, false); + QWheelEvent wheelEvent(windowPoint, windowPoint, QPoint(), QPoint(scroll.x, scroll.y), buttons, event.getKeyboardModifiers(), Qt::ScrollPhase::NoScrollPhase, false, Qt::MouseEventSynthesizedByApplication, &device); if (QCoreApplication::sendEvent(getWindow(), &wheelEvent)) { eventSent = true; eventsAccepted &= wheelEvent.isAccepted(); @@ -606,8 +624,10 @@ void OffscreenQmlSurface::focusDestroyed(QObject* obj) { void OffscreenQmlSurface::onFocusObjectChanged(QObject* object) { clearFocusItem(); - QQuickItem* item = static_cast(object); + QQuickItem* item = qobject_cast(object); if (!item) { + // QT6TODO: investigate when this happens and if it's a problem or not + qDebug() << "OffscreenQmlSurface::onFocusObjectChanged object is not QQuickItem"; setFocusText(false); return; } @@ -720,7 +740,7 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n if (!android || hmd) { // if HMD is being worn, allow keyboard to open. allow it to close, HMD or not. if (!raised || hmd) { - QQuickItem* item = dynamic_cast(object); + QQuickItem* item = qobject_cast(object); if (!item) { return; } @@ -772,7 +792,7 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) { const QString LOWER_KEYBOARD = "_LOWER_KEYBOARD"; const QString RAISE_KEYBOARD_NUMERIC_PASSWORD = "_RAISE_KEYBOARD_NUMERIC_PASSWORD"; const QString RAISE_KEYBOARD_PASSWORD = "_RAISE_KEYBOARD_PASSWORD"; - QString messageString = message.type() == QVariant::String ? message.toString() : ""; + QString messageString = message.typeId() == QMetaType::QString ? message.toString() : ""; if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) { bool numeric = (messageString == RAISE_KEYBOARD_NUMERIC || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD); bool passwordField = (messageString == RAISE_KEYBOARD_PASSWORD || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 07358dcf386..9914b057e14 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -81,9 +81,9 @@ private slots: void onFocusObjectChanged(QObject* newFocus) override; public slots: - void hoverBeginEvent(const PointerEvent& event, class QTouchDevice& device); - void hoverEndEvent(const PointerEvent& event, class QTouchDevice& device); - bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device, bool release = false); + void hoverBeginEvent(const PointerEvent& event, QPointingDevice& device); + void hoverEndEvent(const PointerEvent& event, QPointingDevice& device); + bool handlePointerEvent(const PointerEvent& event, QPointingDevice& device, bool release = false); void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false); void forceHtmlAudioOutputDeviceUpdate(); void forceQmlAudioOutputDeviceUpdate(); diff --git a/libraries/ui/src/ui/QmlWrapper.cpp b/libraries/ui/src/ui/QmlWrapper.cpp index 3879e1bc8f4..2cb65bf2f08 100644 --- a/libraries/ui/src/ui/QmlWrapper.cpp +++ b/libraries/ui/src/ui/QmlWrapper.cpp @@ -38,7 +38,7 @@ void QmlWrapper::writeProperties(QVariant propertyMap) { QVariant QmlWrapper::readProperty(const QString& propertyName) { if (QThread::currentThread() != thread()) { QVariant result; - BLOCKING_INVOKE_METHOD(this, "readProperty", Q_RETURN_ARG(QVariant, result), Q_ARG(QString, propertyName)); + BLOCKING_INVOKE_METHOD(this, "readProperty", Q_GENERIC_RETURN_ARG(QVariant, result), Q_GENERIC_ARG(QString, propertyName)); return result; } @@ -48,7 +48,7 @@ QVariant QmlWrapper::readProperty(const QString& propertyName) { QVariant QmlWrapper::readProperties(const QVariant& propertyList) { if (QThread::currentThread() != thread()) { QVariant result; - BLOCKING_INVOKE_METHOD(this, "readProperties", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, propertyList)); + BLOCKING_INVOKE_METHOD(this, "readProperties", Q_GENERIC_RETURN_ARG(QVariant, result), Q_GENERIC_ARG(QVariant, propertyList)); return result; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 42af68f820f..5cbfa0c8576 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -188,7 +188,7 @@ ToolbarProxy* TabletScriptingInterface::getSystemToolbarProxy() { TabletProxy* TabletScriptingInterface::getTablet(const QString& tabletId) { TabletProxy* tabletProxy = nullptr; if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "getTablet", Q_RETURN_ARG(TabletProxy*, tabletProxy), Q_ARG(QString, tabletId)); + BLOCKING_INVOKE_METHOD(this, "getTablet", Q_GENERIC_RETURN_ARG(TabletProxy*, tabletProxy), Q_GENERIC_ARG(QString, tabletId)); return tabletProxy; } @@ -441,7 +441,7 @@ void TabletProxy::initialScreen(const QVariant& url) { bool TabletProxy::isMessageDialogOpen() { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "isMessageDialogOpen", Q_RETURN_ARG(bool, result)); + BLOCKING_INVOKE_METHOD(this, "isMessageDialogOpen", Q_GENERIC_RETURN_ARG(bool, result)); return result; } @@ -501,7 +501,7 @@ void TabletProxy::onTabletShown() { bool TabletProxy::isPathLoaded(const QVariant& path) { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "isPathLoaded", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); + BLOCKING_INVOKE_METHOD(this, "isPathLoaded", Q_GENERIC_RETURN_ARG(bool, result), Q_GENERIC_ARG(QVariant, path)); return result; } @@ -757,7 +757,7 @@ void TabletProxy::stopQMLSource() { bool TabletProxy::pushOntoStack(const QVariant& path) { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "pushOntoStack", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, path)); + BLOCKING_INVOKE_METHOD(this, "pushOntoStack", Q_GENERIC_RETURN_ARG(bool, result), Q_GENERIC_ARG(QVariant, path)); return result; } @@ -900,7 +900,7 @@ void TabletProxy::loadHTMLSourceOnTopImpl(const QString& url, const QString& inj TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { if (QThread::currentThread() != thread()) { TabletButtonProxy* result = nullptr; - BLOCKING_INVOKE_METHOD(this, "addButton", Q_RETURN_ARG(TabletButtonProxy*, result), Q_ARG(QVariant, properties)); + BLOCKING_INVOKE_METHOD(this, "addButton", Q_GENERIC_RETURN_ARG(TabletButtonProxy*, result), Q_GENERIC_ARG(QVariant, properties)); return result; } @@ -910,7 +910,7 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { bool TabletProxy::onHomeScreen() { if (QThread::currentThread() != thread()) { bool result = false; - BLOCKING_INVOKE_METHOD(this, "onHomeScreen", Q_RETURN_ARG(bool, result)); + BLOCKING_INVOKE_METHOD(this, "onHomeScreen", Q_GENERIC_RETURN_ARG(bool, result)); return result; } @@ -919,7 +919,7 @@ bool TabletProxy::onHomeScreen() { void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "removeButton", Q_ARG(TabletButtonProxy*, tabletButtonProxy)); + QMetaObject::invokeMethod(this, "removeButton", Q_GENERIC_ARG(TabletButtonProxy*, tabletButtonProxy)); return; } @@ -928,34 +928,34 @@ void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) { void TabletProxy::emitScriptEvent(const QVariant& msg) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "emitScriptEvent", Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(this, "emitScriptEvent", Q_GENERIC_ARG(QVariant, msg)); return; } if (!_toolbarMode && _qmlOffscreenSurface) { - QMetaObject::invokeMethod(_qmlOffscreenSurface, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(_qmlOffscreenSurface, "emitScriptEvent", Qt::AutoConnection, Q_GENERIC_ARG(QVariant, msg)); } else if (_toolbarMode && _desktopWindow) { - QMetaObject::invokeMethod(_desktopWindow, "emitScriptEvent", Qt::AutoConnection, Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(_desktopWindow, "emitScriptEvent", Qt::AutoConnection, Q_GENERIC_ARG(QVariant, msg)); } } void TabletProxy::sendToQml(const QVariant& msg) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "sendToQml", Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(this, "sendToQml", Q_GENERIC_ARG(QVariant, msg)); return; } if (!_toolbarMode && _qmlOffscreenSurface) { - QMetaObject::invokeMethod(_qmlOffscreenSurface, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(_qmlOffscreenSurface, "sendToQml", Qt::AutoConnection, Q_GENERIC_ARG(QVariant, msg)); } else if (_toolbarMode && _desktopWindow) { - QMetaObject::invokeMethod(_desktopWindow, "sendToQml", Qt::AutoConnection, Q_ARG(QVariant, msg)); + QMetaObject::invokeMethod(_desktopWindow, "sendToQml", Qt::AutoConnection, Q_GENERIC_ARG(QVariant, msg)); } } OffscreenQmlSurface* TabletProxy::getTabletSurface() { if (QThread::currentThread() != thread()) { OffscreenQmlSurface* result = nullptr; - BLOCKING_INVOKE_METHOD(this, "getTabletSurface", Q_RETURN_ARG(OffscreenQmlSurface*, result)); + BLOCKING_INVOKE_METHOD(this, "getTabletSurface", Q_GENERIC_RETURN_ARG(OffscreenQmlSurface*, result)); return result; } @@ -1091,7 +1091,7 @@ TabletButtonProxy::~TabletButtonProxy() { QVariantMap TabletButtonProxy::getProperties() { if (QThread::currentThread() != thread()) { QVariantMap result; - BLOCKING_INVOKE_METHOD(this, "getProperties", Q_RETURN_ARG(QVariantMap, result)); + BLOCKING_INVOKE_METHOD(this, "getProperties", Q_GENERIC_RETURN_ARG(QVariantMap, result)); return result; } @@ -1100,7 +1100,7 @@ QVariantMap TabletButtonProxy::getProperties() { void TabletButtonProxy::editProperties(const QVariantMap& properties) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "editProperties", Q_ARG(QVariantMap, properties)); + QMetaObject::invokeMethod(this, "editProperties", Q_GENERIC_ARG(QVariantMap, properties)); return; } diff --git a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp index 4934ba4e351..a978bd23c3a 100644 --- a/libraries/ui/src/ui/ToolbarScriptingInterface.cpp +++ b/libraries/ui/src/ui/ToolbarScriptingInterface.cpp @@ -83,7 +83,7 @@ ToolbarProxy::ToolbarProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qml ToolbarButtonProxy* ToolbarProxy::addButton(const QVariant& properties) { if (QThread::currentThread() != thread()) { ToolbarButtonProxy* result = nullptr; - BLOCKING_INVOKE_METHOD(this, "addButton", Q_RETURN_ARG(ToolbarButtonProxy*, result), Q_ARG(QVariant, properties)); + BLOCKING_INVOKE_METHOD(this, "addButton", Q_GENERIC_RETURN_ARG(ToolbarButtonProxy*, result), Q_GENERIC_ARG(QVariant, properties)); return result; } @@ -114,7 +114,7 @@ void ToolbarProxy::removeButton(const QVariant& name) { ToolbarProxy* ToolbarScriptingInterface::getToolbar(const QString& toolbarId) { if (QThread::currentThread() != thread()) { ToolbarProxy* result = nullptr; - BLOCKING_INVOKE_METHOD(this, "getToolbar", Q_RETURN_ARG(ToolbarProxy*, result), Q_ARG(QString, toolbarId)); + BLOCKING_INVOKE_METHOD(this, "getToolbar", Q_GENERIC_RETURN_ARG(ToolbarProxy*, result), Q_GENERIC_ARG(QString, toolbarId)); return result; } diff --git a/libraries/ui/src/ui/types/ContextAwareProfile.cpp b/libraries/ui/src/ui/types/ContextAwareProfile.cpp index 210e1f36b1c..c00f1d2148e 100644 --- a/libraries/ui/src/ui/types/ContextAwareProfile.cpp +++ b/libraries/ui/src/ui/types/ContextAwareProfile.cpp @@ -78,7 +78,7 @@ void ContextAwareProfile::restrictContext(QQmlContext* context, bool restrict) { bool ContextAwareProfile::isRestrictedGetProperty() { if (QThread::currentThread() != thread()) { bool restrictedResult = false; - BLOCKING_INVOKE_METHOD(this, "isRestrictedGetProperty", Q_RETURN_ARG(bool, restrictedResult)); + BLOCKING_INVOKE_METHOD(this, "isRestrictedGetProperty", Q_GENERIC_RETURN_ARG(bool, restrictedResult)); return restrictedResult; } diff --git a/libraries/ui/src/ui/types/ContextAwareProfile.h b/libraries/ui/src/ui/types/ContextAwareProfile.h index 7ea56846992..584b54946e9 100644 --- a/libraries/ui/src/ui/types/ContextAwareProfile.h +++ b/libraries/ui/src/ui/types/ContextAwareProfile.h @@ -17,7 +17,7 @@ #include #if !defined(Q_OS_ANDROID) -#include +#include #include using ContextAwareProfileParent = QQuickWebEngineProfile; diff --git a/libraries/ui/src/ui/types/FileTypeProfile.cpp b/libraries/ui/src/ui/types/FileTypeProfile.cpp index 9fca1be4361..f2ac9aa4f50 100644 --- a/libraries/ui/src/ui/types/FileTypeProfile.cpp +++ b/libraries/ui/src/ui/types/FileTypeProfile.cpp @@ -33,7 +33,7 @@ FileTypeProfile::FileTypeProfile(QQmlContext* parent) : setOffTheRecord(false); auto requestInterceptor = new RequestInterceptor(this); - setRequestInterceptor(requestInterceptor); + setUrlRequestInterceptor(requestInterceptor); std::lock_guard lock(FileTypeProfile_mutex); FileTypeProfile_instances.insert(this); diff --git a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp index 3f2d50e8fa8..7a5c668e59f 100644 --- a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp +++ b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp @@ -30,7 +30,7 @@ HFWebEngineProfile::HFWebEngineProfile(QQmlContext* parent) : Parent(parent) setOffTheRecord(false); // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user - setRequestInterceptor(new RequestInterceptor(this)); + setUrlRequestInterceptor(new RequestInterceptor(this)); std::lock_guard lock(HFWebEngineProfile_mutex); HFWebEngineProfile_instances.insert(this); diff --git a/nix/cmake3/000-nixpkgs-cmake-prefix-path.diff b/nix/cmake3/000-nixpkgs-cmake-prefix-path.diff new file mode 100644 index 00000000000..4ebdcced055 --- /dev/null +++ b/nix/cmake3/000-nixpkgs-cmake-prefix-path.diff @@ -0,0 +1,28 @@ +diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx +index 8840cdcb..c34b7ee9 100644 +--- a/Source/cmFindBase.cxx ++++ b/Source/cmFindBase.cxx +@@ -280,6 +280,11 @@ void cmFindBase::FillCMakeEnvironmentPath() + // Add CMAKE_*_PATH environment variables + std::string var = cmStrCat("CMAKE_", this->CMakePathName, "_PATH"); + paths.AddEnvPrefixPath("CMAKE_PREFIX_PATH"); ++ if (this->CMakePathName != "PROGRAM") { ++ // Like CMAKE_PREFIX_PATH except when searching for programs. Programs need ++ // to be located via PATH ++ paths.AddEnvPrefixPath("NIXPKGS_CMAKE_PREFIX_PATH"); ++ } + paths.AddEnvPath(var); + + if (this->CMakePathName == "PROGRAM") { +diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx +index 9b51b1ad..6acc676c 100644 +--- a/Source/cmFindPackageCommand.cxx ++++ b/Source/cmFindPackageCommand.cxx +@@ -2039,6 +2039,7 @@ void cmFindPackageCommand::FillPrefixesCMakeEnvironment() + + // And now the general CMake environment variables + paths.AddEnvPath("CMAKE_PREFIX_PATH"); ++ paths.AddEnvPath("NIXPKGS_CMAKE_PREFIX_PATH"); + if (this->DebugMode) { + debugBuffer = cmStrCat(debugBuffer, + "CMAKE_PREFIX_PATH env variable " diff --git a/nix/cmake3/001-search-path.diff b/nix/cmake3/001-search-path.diff new file mode 100644 index 00000000000..04ab0847a70 --- /dev/null +++ b/nix/cmake3/001-search-path.diff @@ -0,0 +1,95 @@ +diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake +index b9381c3d7d..5e944640b5 100644 +--- a/Modules/Platform/UnixPaths.cmake ++++ b/Modules/Platform/UnixPaths.cmake +@@ -26,9 +26,6 @@ get_filename_component(_CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" PATH) + # please make sure to keep Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst + # synchronized + list(APPEND CMAKE_SYSTEM_PREFIX_PATH +- # Standard +- /usr/local /usr / +- + # CMake install location + "${_CMAKE_INSTALL_DIR}" + ) +@@ -47,48 +44,49 @@ endif() + + # Non "standard" but common install prefixes + list(APPEND CMAKE_SYSTEM_PREFIX_PATH +- /usr/X11R6 +- /usr/pkg +- /opt + ) + + # List common include file locations not under the common prefixes. ++if(DEFINED ENV{NIX_CC} ++ AND IS_DIRECTORY "$ENV{NIX_CC}" ++ AND EXISTS "$ENV{NIX_CC}/nix-support/orig-libc" ++ AND EXISTS "$ENV{NIX_CC}/nix-support/orig-libc-dev") ++ file(STRINGS "$ENV{NIX_CC}/nix-support/orig-libc" _nix_cmake_libc) ++ file(STRINGS "$ENV{NIX_CC}/nix-support/orig-libc-dev" _nix_cmake_libc_dev) ++else() ++ set(_nix_cmake_libc @libc_lib@) ++ set(_nix_cmake_libc_dev @libc_dev@) ++endif() ++ + list(APPEND CMAKE_SYSTEM_INCLUDE_PATH +- # X11 +- /usr/include/X11 ++ "${_nix_cmake_libc_dev}/include" + ) + + list(APPEND CMAKE_SYSTEM_LIBRARY_PATH +- # X11 +- /usr/lib/X11 ++ "${_nix_cmake_libc}/lib" + ) + + list(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES +- /lib /lib32 /lib64 /usr/lib /usr/lib32 /usr/lib64 ++ "${_nix_cmake_libc}/lib" + ) + +-if(CMAKE_SYSROOT_COMPILE) +- set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}") +-else() +- set(_cmake_sysroot_compile "${CMAKE_SYSROOT}") +-endif() +- + # Default per-language values. These may be later replaced after + # parsing the implicit directory information from compiler output. + set(_CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_INIT + ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES} +- "${_cmake_sysroot_compile}/usr/include" ++ "${_nix_cmake_libc_dev}/include" + ) + set(_CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES_INIT + ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES} +- "${_cmake_sysroot_compile}/usr/include" ++ "${_nix_cmake_libc_dev}/include" + ) + set(_CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES_INIT + ${CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES} +- "${_cmake_sysroot_compile}/usr/include" ++ "${_nix_cmake_libc_dev}/include" + ) + +-unset(_cmake_sysroot_compile) ++unset(_nix_cmake_libc) ++unset(_nix_cmake_libc_dev) + + # Reminder when adding new locations computed from environment variables + # please make sure to keep Help/variable/CMAKE_SYSTEM_PREFIX_PATH.rst +diff --git a/Modules/Platform/WindowsPaths.cmake b/Modules/Platform/WindowsPaths.cmake +index b9e2f17979..ab517cd4a7 100644 +--- a/Modules/Platform/WindowsPaths.cmake ++++ b/Modules/Platform/WindowsPaths.cmake +@@ -70,7 +70,7 @@ endif() + + if(CMAKE_CROSSCOMPILING AND NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") + # MinGW (useful when cross compiling from linux with CMAKE_FIND_ROOT_PATH set) +- list(APPEND CMAKE_SYSTEM_PREFIX_PATH /) ++ # list(APPEND CMAKE_SYSTEM_PREFIX_PATH /) + endif() + + list(APPEND CMAKE_SYSTEM_INCLUDE_PATH diff --git a/nix/cmake3/008-FindCURL-Add-more-target-properties-from-pkg-config.diff b/nix/cmake3/008-FindCURL-Add-more-target-properties-from-pkg-config.diff new file mode 100644 index 00000000000..8dfc354a9c2 --- /dev/null +++ b/nix/cmake3/008-FindCURL-Add-more-target-properties-from-pkg-config.diff @@ -0,0 +1,32 @@ +diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake +index 5ce8a9046b..f7361308b7 100644 +--- a/Modules/FindCURL.cmake ++++ b/Modules/FindCURL.cmake +@@ -239,9 +239,24 @@ if(CURL_FOUND) + IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}") + endif() + +- if(CURL_USE_STATIC_LIBS AND MSVC) +- set_target_properties(CURL::libcurl PROPERTIES +- INTERFACE_LINK_LIBRARIES "normaliz.lib;ws2_32.lib;wldap32.lib") ++ if(PC_CURL_FOUND) ++ if(PC_CURL_LINK_LIBRARIES) ++ set_property(TARGET CURL::libcurl PROPERTY ++ INTERFACE_LINK_LIBRARIES "${PC_CURL_LINK_LIBRARIES}") ++ endif() ++ if(PC_CURL_LDFLAGS_OTHER) ++ set_property(TARGET CURL::libcurl PROPERTY ++ INTERFACE_LINK_OPTIONS "${PC_CURL_LDFLAGS_OTHER}") ++ endif() ++ if(PC_CURL_CFLAGS_OTHER) ++ set_property(TARGET CURL::libcurl PROPERTY ++ INTERFACE_COMPILE_OPTIONS "${PC_CURL_CFLAGS_OTHER}") ++ endif() ++ else() ++ if(CURL_USE_STATIC_LIBS AND MSVC) ++ set_target_properties(CURL::libcurl PROPERTIES ++ INTERFACE_LINK_LIBRARIES "normaliz.lib;ws2_32.lib;wldap32.lib") ++ endif() + endif() + + endif() diff --git a/nix/cmake3/009-cmCTestCurl-Avoid-using-undocumented-type-for-CURLOPT_PROXYTYPE-values.diff b/nix/cmake3/009-cmCTestCurl-Avoid-using-undocumented-type-for-CURLOPT_PROXYTYPE-values.diff new file mode 100644 index 00000000000..feabba28b0d --- /dev/null +++ b/nix/cmake3/009-cmCTestCurl-Avoid-using-undocumented-type-for-CURLOPT_PROXYTYPE-values.diff @@ -0,0 +1,13 @@ +diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h +index 7836f4b9c78a1d103eee515d618856a6712b4480..9113890b5a12cb157b691b66d96e25d0fd4b50ef 100644 +--- a/Source/CTest/cmCTestCurl.h ++++ b/Source/CTest/cmCTestCurl.h +@@ -52,7 +52,7 @@ private: + std::vector HttpHeaders; + std::string HTTPProxyAuth; + std::string HTTPProxy; +- curl_proxytype HTTPProxyType; ++ long HTTPProxyType; + bool UseHttp10 = false; + bool Quiet = false; + int TimeOutSeconds = 0; diff --git a/nix/cmake3/check-pc-files-hook.sh b/nix/cmake3/check-pc-files-hook.sh new file mode 100644 index 00000000000..94d1b7b5355 --- /dev/null +++ b/nix/cmake3/check-pc-files-hook.sh @@ -0,0 +1,18 @@ +cmakePcfileCheckPhase() { + while IFS= read -rd $'\0' file; do + grepout=$(grep --line-number '}//nix/store' "$file" || true) + if [ -n "$grepout" ]; then + { + echo "Broken paths found in a .pc file! $file" + echo "The following lines have issues (specifically '//' in paths)." + echo "$grepout" + echo "It is very likely that paths are being joined improperly." + echo 'ex: "${prefix}/@CMAKE_INSTALL_LIBDIR@" should be "@CMAKE_INSTALL_FULL_LIBDIR@"' + echo "Please see https://github.com/NixOS/nixpkgs/issues/144170 for more details." + exit 1 + } 1>&2 + fi + done < <(find "${!outputDev}" -iname "*.pc" -print0) +} + +postFixupHooks+=(cmakePcfileCheckPhase) diff --git a/nix/cmake3/default.nix b/nix/cmake3/default.nix new file mode 100644 index 00000000000..4fac4e38712 --- /dev/null +++ b/nix/cmake3/default.nix @@ -0,0 +1,232 @@ +{ + lib, + stdenv, + fetchurl, + replaceVars, + buildPackages, + bzip2, + curlMinimal, + expat, + libarchive, + libuv, + ncurses, + openssl, + pkg-config, + ps, + rhash, + sphinx, + texinfo, + xz, + zlib, + isBootstrap ? null, + isMinimalBuild ? ( + if isBootstrap != null then + lib.warn "isBootstrap argument is deprecated and will be removed; use isMinimalBuild instead" isBootstrap + else + false + ), + useOpenSSL ? !isMinimalBuild, + useSharedLibraries ? (!isMinimalBuild && !stdenv.hostPlatform.isCygwin), + uiToolkits ? [ ], # can contain "ncurses" and/or "qt5" + buildDocs ? !(isMinimalBuild || (uiToolkits == [ ])), + libsForQt5, + gitUpdater, +}: + +let + inherit (libsForQt5) qtbase wrapQtAppsHook; + cursesUI = lib.elem "ncurses" uiToolkits; + qt5UI = lib.elem "qt5" uiToolkits; +in +# Accepts only "ncurses" and "qt5" as possible uiToolkits +assert lib.subtractLists [ "ncurses" "qt5" ] uiToolkits == [ ]; +# Minimal, bootstrap cmake does not have toolkits +assert isMinimalBuild -> (uiToolkits == [ ]); +stdenv.mkDerivation (finalAttrs: { + pname = + "cmake" + + lib.optionalString isMinimalBuild "-minimal" + + lib.optionalString cursesUI "-cursesUI" + + lib.optionalString qt5UI "-qt5UI"; + version = "3.31.7"; + + src = fetchurl { + url = "https://cmake.org/files/v${lib.versions.majorMinor finalAttrs.version}/cmake-${finalAttrs.version}.tar.gz"; + hash = "sha256-ptLrHr65kTDf5j71o0DD/bEUMczj18oUhSTBJZJM6mg="; + }; + + patches = [ + # Add NIXPKGS_CMAKE_PREFIX_PATH to cmake which is like CMAKE_PREFIX_PATH + # except it is not searched for programs + ./000-nixpkgs-cmake-prefix-path.diff + # Don't search in non-Nix locations such as /usr, but do search in our libc. + ./001-search-path.diff + ] + # On Darwin, always set CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG. + ++ lib.optional stdenv.hostPlatform.isDarwin ./006-darwin-always-set-runtime-c-flag.diff + # On platforms where ps is not part of stdenv, patch the invocation of ps to use an absolute path. + ++ lib.optional (stdenv.hostPlatform.isDarwin || stdenv.hostPlatform.isFreeBSD) ( + replaceVars ./007-darwin-bsd-ps-abspath.diff { + ps = lib.getExe ps; + } + ) + ++ [ + # Backport of https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9900 + # Needed to correctly link curl in pkgsStatic. + ./008-FindCURL-Add-more-target-properties-from-pkg-config.diff + # Backport of https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11134 + # Fixes build against curl 8.16 and later + ./009-cmCTestCurl-Avoid-using-undocumented-type-for-CURLOPT_PROXYTYPE-values.diff + ]; + + outputs = [ + "out" + ] + ++ lib.optionals buildDocs [ + "man" + "info" + ]; + separateDebugInfo = true; + setOutputFlags = false; + + setupHooks = [ + ./setup-hook.sh + ./check-pc-files-hook.sh + ]; + + depsBuildBuild = [ buildPackages.stdenv.cc ]; + + nativeBuildInputs = + finalAttrs.setupHooks + ++ [ + pkg-config + ] + ++ lib.optionals buildDocs [ texinfo ] + ++ lib.optionals qt5UI [ wrapQtAppsHook ]; + + buildInputs = + lib.optionals useSharedLibraries [ + bzip2 + curlMinimal + expat + libarchive + xz + zlib + libuv + rhash + ] + ++ lib.optional useOpenSSL openssl + ++ lib.optional cursesUI ncurses + ++ lib.optional qt5UI qtbase; + + preConfigure = '' + fixCmakeFiles . + substituteInPlace Modules/Platform/UnixPaths.cmake \ + --subst-var-by libc_bin ${lib.getBin stdenv.cc.libc} \ + --subst-var-by libc_dev ${lib.getDev stdenv.cc.libc} \ + --subst-var-by libc_lib ${lib.getLib stdenv.cc.libc} + # CC_FOR_BUILD and CXX_FOR_BUILD are used to bootstrap cmake + configureFlags="--parallel=''${NIX_BUILD_CORES:-1} CC=$CC_FOR_BUILD CXX=$CXX_FOR_BUILD $configureFlags $cmakeFlags" + ''; + + # The configuration script is not autoconf-based, although being similar; + # triples and other interesting info are passed via CMAKE_* environment + # variables and commandline switches + configurePlatforms = [ ]; + + configureFlags = [ + "CXXFLAGS=-Wno-elaborated-enum-base" + "--docdir=share/doc/${finalAttrs.pname}-${finalAttrs.version}" + ] + ++ ( + if useSharedLibraries then + [ + "--no-system-cppdap" + "--no-system-jsoncpp" + "--system-libs" + ] + else + [ + "--no-system-libs" + ] + ) # FIXME: cleanup + ++ lib.optional qt5UI "--qt-gui" + ++ lib.optionals buildDocs [ + "--sphinx-build=${sphinx}/bin/sphinx-build" + "--sphinx-info" + "--sphinx-man" + ] + # Workaround https://gitlab.kitware.com/cmake/cmake/-/issues/20568 + ++ lib.optionals stdenv.hostPlatform.is32bit [ + "CFLAGS=-D_FILE_OFFSET_BITS=64" + "CXXFLAGS=-D_FILE_OFFSET_BITS=64" + ] + ++ [ + "--" + # We should set the proper `CMAKE_SYSTEM_NAME`. + # http://www.cmake.org/Wiki/CMake_Cross_Compiling + # + # Unfortunately cmake seems to expect absolute paths for ar, ranlib, and + # strip. Otherwise they are taken to be relative to the source root of the + # package being built. + (lib.cmakeFeature "CMAKE_CXX_COMPILER" "${stdenv.cc.targetPrefix}c++") + (lib.cmakeFeature "CMAKE_C_COMPILER" "${stdenv.cc.targetPrefix}cc") + (lib.cmakeFeature "CMAKE_AR" "${lib.getBin stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}ar") + (lib.cmakeFeature "CMAKE_RANLIB" "${lib.getBin stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}ranlib") + (lib.cmakeFeature "CMAKE_STRIP" "${lib.getBin stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}strip") + + (lib.cmakeBool "CMAKE_USE_OPENSSL" useOpenSSL) + (lib.cmakeBool "BUILD_CursesDialog" cursesUI) + ]; + + # `pkgsCross.musl64.cmake.override { stdenv = pkgsCross.musl64.llvmPackages_16.libcxxStdenv; }` + # fails with `The C++ compiler does not support C++11 (e.g. std::unique_ptr).` + # The cause is a compiler warning `warning: argument unused during compilation: '-pie' [-Wunused-command-line-argument]` + # interfering with the feature check. + env.NIX_CFLAGS_COMPILE = "-Wno-unused-command-line-argument"; + + # make install attempts to use the just-built cmake + preInstall = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' + sed -i 's|bin/cmake|${buildPackages.cmakeMinimal}/bin/cmake|g' Makefile + ''; + + # Undo some of `fixCmakeFiles` for Darwin to make sure that checks for libraries in the SDK find them + # (e.g., `find_library(MATH_LIBRARY m)` should find `$SDKROOT/usr/lib/libm.tbd`). + postFixup = lib.optionalString stdenv.hostPlatform.isDarwin '' + substituteInPlace "$out/share/cmake-${lib.versions.majorMinor finalAttrs.version}/Modules/Platform/Darwin.cmake" \ + --replace-fail '/var/empty/include' '/usr/include' \ + --replace-fail '/var/empty/lib' '/usr/lib' + ''; + + dontUseCmakeConfigure = true; + enableParallelBuilding = true; + + doCheck = false; # fails + + passthru.updateScript = gitUpdater { + url = "https://gitlab.kitware.com/cmake/cmake.git"; + rev-prefix = "v"; + ignoredVersions = "-"; # -rc1 and friends + }; + + meta = { + homepage = "https://cmake.org/"; + description = "Cross-platform, open-source build system generator"; + longDescription = '' + CMake is an open-source, cross-platform family of tools designed to build, + test and package software. CMake is used to control the software + compilation process using simple platform and compiler independent + configuration files, and generate native makefiles and workspaces that can + be used in the compiler environment of your choice. + ''; + changelog = "https://cmake.org/cmake/help/v${lib.versions.majorMinor finalAttrs.version}/release/${lib.versions.majorMinor finalAttrs.version}.html"; + license = lib.licenses.bsd3; + maintainers = with lib.maintainers; [ + ttuegel + lnl7 + ]; + platforms = lib.platforms.all; + mainProgram = "cmake"; + broken = (qt5UI && stdenv.hostPlatform.isDarwin); + }; +}) diff --git a/nix/cmake3/setup-hook.sh b/nix/cmake3/setup-hook.sh new file mode 100644 index 00000000000..ea2d3d2a45b --- /dev/null +++ b/nix/cmake3/setup-hook.sh @@ -0,0 +1,188 @@ +addCMakeParams() { + # NIXPKGS_CMAKE_PREFIX_PATH is like CMAKE_PREFIX_PATH except cmake + # will not search it for programs + addToSearchPath NIXPKGS_CMAKE_PREFIX_PATH $1 +} + +fixCmakeFiles() { + # Replace occurences of /usr and /opt by /var/empty. + echo "fixing cmake files..." + find "$1" -type f \( -name "*.cmake" -o -name "*.cmake.in" -o -name CMakeLists.txt \) -print | + while read fn; do + sed -e 's^/usr\([ /]\|$\)^/var/empty\1^g' -e 's^/opt\([ /]\|$\)^/var/empty\1^g' < "$fn" > "$fn.tmp" + mv "$fn.tmp" "$fn" + done +} + +cmakeConfigurePhase() { + runHook preConfigure + + # default to CMake defaults if unset + : ${cmakeBuildDir:=build} + + export CTEST_OUTPUT_ON_FAILURE=1 + if [ -n "${enableParallelChecking-1}" ]; then + export CTEST_PARALLEL_LEVEL=$NIX_BUILD_CORES + fi + + if [ -z "${dontFixCmake-}" ]; then + fixCmakeFiles . + fi + + if [ -z "${dontUseCmakeBuildDir-}" ]; then + mkdir -p "$cmakeBuildDir" + cd "$cmakeBuildDir" + : ${cmakeDir:=..} + else + : ${cmakeDir:=.} + fi + + if [ -z "${dontAddPrefix-}" ]; then + prependToVar cmakeFlags "-DCMAKE_INSTALL_PREFIX=$prefix" + fi + + # We should set the proper `CMAKE_SYSTEM_NAME`. + # http://www.cmake.org/Wiki/CMake_Cross_Compiling + # + # Unfortunately cmake seems to expect absolute paths for ar, ranlib, and + # strip. Otherwise they are taken to be relative to the source root of the + # package being built. + prependToVar cmakeFlags "-DCMAKE_CXX_COMPILER=$CXX" + prependToVar cmakeFlags "-DCMAKE_C_COMPILER=$CC" + prependToVar cmakeFlags "-DCMAKE_AR=$(command -v $AR)" + prependToVar cmakeFlags "-DCMAKE_RANLIB=$(command -v $RANLIB)" + prependToVar cmakeFlags "-DCMAKE_STRIP=$(command -v $STRIP)" + + # on macOS we want to prefer Unix-style headers to Frameworks + # because we usually do not package the framework + prependToVar cmakeFlags "-DCMAKE_FIND_FRAMEWORK=LAST" + + # correctly detect our clang compiler + prependToVar cmakeFlags "-DCMAKE_POLICY_DEFAULT_CMP0025=NEW" + + # This installs shared libraries with a fully-specified install + # name. By default, cmake installs shared libraries with just the + # basename as the install name, which means that, on Darwin, they + # can only be found by an executable at runtime if the shared + # libraries are in a system path or in the same directory as the + # executable. This flag makes the shared library accessible from its + # nix/store directory. + prependToVar cmakeFlags "-DCMAKE_INSTALL_NAME_DIR=${!outputLib}/lib" + + # The docdir flag needs to include PROJECT_NAME as per GNU guidelines, + # try to extract it from CMakeLists.txt. + if [[ -z "$shareDocName" ]]; then + local cmakeLists="${cmakeDir}/CMakeLists.txt" + if [[ -f "$cmakeLists" ]]; then + local shareDocName="$(grep --only-matching --perl-regexp --ignore-case '\bproject\s*\(\s*"?\K([^[:space:]")]+)' < "$cmakeLists" | head -n1)" + fi + # The argument sometimes contains garbage or variable interpolation. + # When that is the case, let’s fall back to the derivation name. + if [[ -z "$shareDocName" ]] || echo "$shareDocName" | grep -q '[^a-zA-Z0-9_+-]'; then + if [[ -n "${pname-}" ]]; then + shareDocName="$pname" + else + shareDocName="$(echo "$name" | sed 's/-[^a-zA-Z].*//')" + fi + fi + fi + + # This ensures correct paths with multiple output derivations + # It requires the project to use variables from GNUInstallDirs module + # https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html + prependToVar cmakeFlags "-DCMAKE_INSTALL_BINDIR=${!outputBin}/bin" + prependToVar cmakeFlags "-DCMAKE_INSTALL_SBINDIR=${!outputBin}/sbin" + prependToVar cmakeFlags "-DCMAKE_INSTALL_INCLUDEDIR=${!outputInclude}/include" + prependToVar cmakeFlags "-DCMAKE_INSTALL_MANDIR=${!outputMan}/share/man" + prependToVar cmakeFlags "-DCMAKE_INSTALL_INFODIR=${!outputInfo}/share/info" + prependToVar cmakeFlags "-DCMAKE_INSTALL_DOCDIR=${!outputDoc}/share/doc/${shareDocName}" + prependToVar cmakeFlags "-DCMAKE_INSTALL_LIBDIR=${!outputLib}/lib" + prependToVar cmakeFlags "-DCMAKE_INSTALL_LIBEXECDIR=${!outputLib}/libexec" + prependToVar cmakeFlags "-DCMAKE_INSTALL_LOCALEDIR=${!outputLib}/share/locale" + + # Don’t build tests when doCheck = false + if [ -z "${doCheck-}" ]; then + prependToVar cmakeFlags "-DBUILD_TESTING=OFF" + fi + + # Always build Release, to ensure optimisation flags + prependToVar cmakeFlags "-DCMAKE_BUILD_TYPE=${cmakeBuildType:-Release}" + + # Disable user package registry to avoid potential side effects + # and unecessary attempts to access non-existent home folder + # https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#disabling-the-package-registry + prependToVar cmakeFlags "-DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON" + prependToVar cmakeFlags "-DCMAKE_FIND_USE_PACKAGE_REGISTRY=OFF" + prependToVar cmakeFlags "-DCMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY=OFF" + + if [ "${buildPhase-}" = ninjaBuildPhase ]; then + prependToVar cmakeFlags "-GNinja" + fi + + local flagsArray=() + concatTo flagsArray cmakeFlags cmakeFlagsArray + + echoCmd 'cmake flags' "${flagsArray[@]}" + + cmake "$cmakeDir" "${flagsArray[@]}" + + if ! [[ -v enableParallelBuilding ]]; then + enableParallelBuilding=1 + echo "cmake: enabled parallel building" + fi + if [[ "$enableParallelBuilding" -ne 0 ]]; then + export CMAKE_BUILD_PARALLEL_LEVEL=$NIX_BUILD_CORES + fi + + if ! [[ -v enableParallelInstalling ]]; then + enableParallelInstalling=1 + echo "cmake: enabled parallel installing" + fi + + runHook postConfigure +} + +if [ -z "${dontUseCmakeConfigure-}" -a -z "${configurePhase-}" ]; then + setOutputFlags= + configurePhase=cmakeConfigurePhase +fi + +addEnvHooks "$targetOffset" addCMakeParams + +makeCmakeFindLibs() { + isystem_seen= + iframework_seen= + for flag in ${NIX_CFLAGS_COMPILE-} ${NIX_LDFLAGS-}; do + if test -n "$isystem_seen" && test -d "$flag"; then + isystem_seen= + addToSearchPath CMAKE_INCLUDE_PATH "${flag}" + elif test -n "$iframework_seen" && test -d "$flag"; then + iframework_seen= + addToSearchPath CMAKE_FRAMEWORK_PATH "${flag}" + else + isystem_seen= + iframework_seen= + case $flag in + -I*) + addToSearchPath CMAKE_INCLUDE_PATH "${flag:2}" + ;; + -L*) + addToSearchPath CMAKE_LIBRARY_PATH "${flag:2}" + ;; + -F*) + addToSearchPath CMAKE_FRAMEWORK_PATH "${flag:2}" + ;; + -isystem) + isystem_seen=1 + ;; + -iframework) + iframework_seen=1 + ;; + esac + fi + done +} + +# not using setupHook, because it could be a setupHook adding additional +# include flags to NIX_CFLAGS_COMPILE +postHooks+=(makeCmakeFindLibs) diff --git a/nix/overte.nix b/nix/overte.nix index efaa42ce787..0f6b029d46f 100644 --- a/nix/overte.nix +++ b/nix/overte.nix @@ -29,7 +29,7 @@ openxr-loader, SDL2, libopus, - libsForQt5, + qt6Packages, libv8, # tools for shader compilation @@ -52,7 +52,7 @@ stdenv.mkDerivation { cmake pkg-config python3 - libsForQt5.wrapQtAppsHook + qt6Packages.wrapQtAppsHook nodejs autoPatchelfHook ]; @@ -60,20 +60,16 @@ stdenv.mkDerivation { # TODO: make dependencies minimal for !buildClient buildInputs = builtins.attrValues { - inherit (libsForQt5) + inherit (qt6Packages) qtbase qtmultimedia qtdeclarative qtwebsockets qtsvg quazip - ; - inherit (libsForQt5.qt5) qtwebchannel qtwebengine - qtxmlpatterns - qtquickcontrols2 - qtgraphicaleffects + qt5compat ; } ++ [ @@ -120,6 +116,7 @@ stdenv.mkDerivation { dontWrapQtApps = true; # TODO: remove set QT_PLUGIN_PATH after qt6 update + # TODO: remote set QT_QPA_PLATOFORM, when wayland works installPhase = '' runHook preInstall @@ -140,6 +137,7 @@ stdenv.mkDerivation { ln -s "$I"/interface $out/bin/overte-client makeWrapper "$I"/interface $out/bin/overte-client \ --set QT_PLUGIN_PATH ''' \ + --set QT_QPA_PLATFORM 'xcb' \ "''${qtWrapperArgs[@]}" '' ) diff --git a/plugins/JSAPIExample/src/JSAPIExample.cpp b/plugins/JSAPIExample/src/JSAPIExample.cpp index 02b59ba412f..49ef023131c 100644 --- a/plugins/JSAPIExample/src/JSAPIExample.cpp +++ b/plugins/JSAPIExample/src/JSAPIExample.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include // for ::settingsFilename() #include // for ::usecTimestampNow() diff --git a/plugins/hifiOsc/src/OscPlugin.cpp b/plugins/hifiOsc/src/OscPlugin.cpp index a261674feb3..3e8ba8c44af 100644 --- a/plugins/hifiOsc/src/OscPlugin.cpp +++ b/plugins/hifiOsc/src/OscPlugin.cpp @@ -85,7 +85,7 @@ enum class FaceCap { // used to mirror left/right shapes from FaceCap. // i.e. right and left shapes are swapped. -FaceCap faceMirrorMap[static_cast(FaceCap::BlendshapeCount)] = { +FaceCap faceMirrorMap[static_cast(FaceCap::BlendshapeCount)] = { FaceCap::BrowsU_C, FaceCap::BrowsD_R, FaceCap::BrowsD_L, @@ -140,7 +140,7 @@ FaceCap faceMirrorMap[static_cast(FaceCap::BlendshapeCount)] = { FaceCap::TongueOut }; -static const char* STRINGS[static_cast(FaceCap::BlendshapeCount)] = { +static const char* STRINGS[static_cast(FaceCap::BlendshapeCount)] = { "BrowsU_C", "BrowsD_L", "BrowsD_R", @@ -195,7 +195,7 @@ static const char* STRINGS[static_cast(FaceCap::BlendshapeCount)] = { "TongueOut" }; -static enum controller::StandardAxisChannel CHANNELS[static_cast(FaceCap::BlendshapeCount)] = { +static enum controller::StandardAxisChannel CHANNELS[static_cast(FaceCap::BlendshapeCount)] = { controller::BROWSU_C, controller::BROWSD_L, controller::BROWSD_R, @@ -582,7 +582,7 @@ controller::Input::NamedVector OscPlugin::InputDevice::getAvailableInputs() cons static controller::Input::NamedVector availableInputs; if (availableInputs.size() == 0) { for (int i = 0; i < static_cast(FaceCap::BlendshapeCount); i++) { - availableInputs.push_back(makePair(CHANNELS[i], QString(STRINGS[i]))); + availableInputs.push_back(makePair(static_cast(CHANNELS[i]), QString(STRINGS[i]))); } } availableInputs.push_back(makePair(controller::HEAD, QString("Head"))); diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index 5f2eedeea33..8b8e67eaa41 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -28,6 +28,10 @@ #include #include "../../interface/src/Menu.h" +#ifdef Q_OS_WIN +#include +#endif + Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") diff --git a/plugins/steamClient/src/SteamAPIPlugin.cpp b/plugins/steamClient/src/SteamAPIPlugin.cpp index b6e5b2ea770..0c2ee74395a 100644 --- a/plugins/steamClient/src/SteamAPIPlugin.cpp +++ b/plugins/steamClient/src/SteamAPIPlugin.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/script-archive/floofChat/FloofChat.qml b/script-archive/floofChat/FloofChat.qml index 8d111222927..a96383880b5 100644 --- a/script-archive/floofChat/FloofChat.qml +++ b/script-archive/floofChat/FloofChat.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 //import Hifi 1.0 as Hifi Rectangle { diff --git a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml index 7470af55dce..f85b380020f 100644 --- a/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml +++ b/scripts/communityScripts/armored-chat/armored_chat_quick_message.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 Item { id: root diff --git a/scripts/communityScripts/chatBubbles/chatBubbles.js b/scripts/communityScripts/chatBubbles/chatBubbles.js index a9a5fb30640..c13e6590b3a 100644 --- a/scripts/communityScripts/chatBubbles/chatBubbles.js +++ b/scripts/communityScripts/chatBubbles/chatBubbles.js @@ -14,7 +14,7 @@ const CHAT_CHANNEL = "chat"; const TYPING_NOTIFICATION_CHANNEL = "Chat-Typing"; -const CONFIG_UPDATE_CHANNEL = "ChatBubbles-Config"; +const CONFIG_UPDATE_CHANNEL = "ChatBubbles-Enabled"; const BUBBLE_MIN_LIFETIME_SECS = 10; const BUBBLE_MAX_LIFETIME_SECS = 60; // failsafe to prevent really long perma-messages @@ -33,9 +33,8 @@ const SELF_BUBBLES = false; const NOTIFY_SOUND = SoundCache.getSound(Script.resolvePath("./assets/notify.wav")); -let settings = { - enabled: true, -}; +// NOTE: we don't call Settings.setValue here because chat.js does that for us +let settings = Settings.getValue("Chat", { chatBubbles: true }); let currentBubbles = {}; let typingIndicators = {}; @@ -312,21 +311,9 @@ function ChatBubbles_HideTypingIndicator(senderID) { } function ChatBubbles_RecvMsg(channel, msg, senderID, localOnly) { - // IPC between ArmoredChat's config window and this script + // IPC between the chat config and this script if (channel === CONFIG_UPDATE_CHANNEL && localOnly) { - let data; - try { - data = JSON.parse(msg); - } catch (e) { - console.error(e); - return; - } - - for (const [key, value] of Object.entries(data)) { - settings[key] = value; - } - - Settings.setValue("ChatBubbles-Config", settings); + settings.chatBubbles = msg === "true"; return; } @@ -345,14 +332,14 @@ function ChatBubbles_RecvMsg(channel, msg, senderID, localOnly) { } if (channel === TYPING_NOTIFICATION_CHANNEL) { - if (data.action === "typing_start") { + if (data.action === "typing_start" && settings.chatBubbles) { // don't spawn a bubble if they're too far away if (Vec3.distance(MyAvatar.position, data.position) > MAX_DISTANCE) { return; } ChatBubbles_ShowTypingIndicator(senderID); } else if (data.action === "typing_stop") { ChatBubbles_HideTypingIndicator(senderID); } - } else if (data.action === "send_chat_message" && settings.enabled) { + } else if (data.action === "send_chat_message" && settings.chatBubbles) { // don't spawn a bubble if they're too far away if (data.channel !== "local") { return; } if (Vec3.distance(MyAvatar.position, data.position) > MAX_DISTANCE) { return; } @@ -405,12 +392,10 @@ Window.domainConnectionRefused.connect((_msg, _code, _info) => ChatBubbles_Delet AvatarList.avatarRemovedEvent.connect(sessionID => ChatBubbles_Delete(sessionID)); AvatarList.avatarSessionChangedEvent.connect((_, oldSessionID) => ChatBubbles_Delete(oldSessionID)); -settings = Settings.getValue("ChatBubbles-Config", settings); Messages.messageReceived.connect(ChatBubbles_RecvMsg); Messages.subscribe(TYPING_NOTIFICATION_CHANNEL); Script.scriptEnding.connect(() => { - Settings.setValue("ChatBubbles-Config", settings); Messages.messageReceived.disconnect(ChatBubbles_RecvMsg); Messages.unsubscribe(TYPING_NOTIFICATION_CHANNEL); ChatBubbles_DeleteAll(); diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 6de377e6e8c..ad672cb4f9e 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -22,34 +22,28 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/menu.js", "system/bubble.js", "system/snapshot.js", - "system/pal.js", // "system/mod.js", // older UX, if you prefer - "system/avatarapp.js", - "system/settings/settings.js", "system/makeUserConnection.js", "system/notifications.js", "system/create/edit.js", "system/dialTone.js", "system/firstPersonHMD.js", "system/tablet-ui/tabletUI.js", - "system/emote.js", - "system/miniTablet.js", "system/audioMuteOverlay.js", "system/inspect.js", "system/keyboardShortcuts/keyboardShortcuts.js", "system/onEscape.js", - "system/places/places.js" //"developer/debugging/scriptMemoryReport.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ + "system/systemApps.js", + "system/chat.js", + "system/places/places.js", "system/controllers/controllerScripts.js", "system/controllers/squeezeHands.js", "communityScripts/notificationCore/notificationCore.js", "simplifiedUI/ui/simplifiedNametag/simplifiedNametag.js", - {"stable": "system/more/app-more.js", "beta": "https://more.overte.org/more/app-more.js"}, - "communityScripts/armored-chat/armored_chat.js", "communityScripts/chatBubbles/chatBubbles.js", "communityScripts/contextMenu.js", - //"system/chat.js" ]; if (Window.interstitialModeEnabled) { diff --git a/scripts/developer/debugging/debugHaze.qml b/scripts/developer/debugging/debugHaze.qml index 5a18f88c79a..039dc23023f 100644 --- a/scripts/developer/debugging/debugHaze.qml +++ b/scripts/developer/debugging/debugHaze.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../utilities/render/configSlider" Item { diff --git a/scripts/developer/debugging/debugWindow.qml b/scripts/developer/debugging/debugWindow.qml index 23708033351..eca330cb99e 100644 --- a/scripts/developer/debugging/debugWindow.qml +++ b/scripts/developer/debugging/debugWindow.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import Hifi 1.0 as Hifi diff --git a/scripts/developer/debugging/surfaceGeometryPass.qml b/scripts/developer/debugging/surfaceGeometryPass.qml index ba1db66d16e..0c17789794b 100644 --- a/scripts/developer/debugging/surfaceGeometryPass.qml +++ b/scripts/developer/debugging/surfaceGeometryPass.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "configSlider" Column { diff --git a/scripts/developer/tests/playaPerformanceTest.qml b/scripts/developer/tests/playaPerformanceTest.qml index 028cfc9e1ab..fd6fec15734 100644 --- a/scripts/developer/tests/playaPerformanceTest.qml +++ b/scripts/developer/tests/playaPerformanceTest.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import Qt.labs.settings 1.0 Rectangle { diff --git a/scripts/developer/tests/textureStress.qml b/scripts/developer/tests/textureStress.qml index 1a8b9944757..eca135a1c46 100644 --- a/scripts/developer/tests/textureStress.qml +++ b/scripts/developer/tests/textureStress.qml @@ -1,5 +1,5 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 Rectangle { id: root diff --git a/scripts/developer/utilities/audio/Jitter.qml b/scripts/developer/utilities/audio/Jitter.qml index 91f197a9191..524b17ba82f 100644 --- a/scripts/developer/utilities/audio/Jitter.qml +++ b/scripts/developer/utilities/audio/Jitter.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 ColumnLayout { diff --git a/scripts/developer/utilities/audio/MovingValue.qml b/scripts/developer/utilities/audio/MovingValue.qml index bbd9c31d6be..b10691867d6 100644 --- a/scripts/developer/utilities/audio/MovingValue.qml +++ b/scripts/developer/utilities/audio/MovingValue.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import "../lib/plotperf" diff --git a/scripts/developer/utilities/audio/Section.qml b/scripts/developer/utilities/audio/Section.qml index 100d05f6b2f..f6bd324646d 100644 --- a/scripts/developer/utilities/audio/Section.qml +++ b/scripts/developer/utilities/audio/Section.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 Rectangle { diff --git a/scripts/developer/utilities/audio/Stats.qml b/scripts/developer/utilities/audio/Stats.qml index e2291e485d6..91a3fc63ae3 100644 --- a/scripts/developer/utilities/audio/Stats.qml +++ b/scripts/developer/utilities/audio/Stats.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/audio/Stream.qml b/scripts/developer/utilities/audio/Stream.qml index e9383b627aa..8cd944d33d6 100644 --- a/scripts/developer/utilities/audio/Stream.qml +++ b/scripts/developer/utilities/audio/Stream.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 ColumnLayout { diff --git a/scripts/developer/utilities/audio/TabletStats.qml b/scripts/developer/utilities/audio/TabletStats.qml index b50acabec48..00213b4666f 100644 --- a/scripts/developer/utilities/audio/TabletStats.qml +++ b/scripts/developer/utilities/audio/TabletStats.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/audio/Value.qml b/scripts/developer/utilities/audio/Value.qml index 70df7695bc4..9ed90b5b331 100644 --- a/scripts/developer/utilities/audio/Value.qml +++ b/scripts/developer/utilities/audio/Value.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 RowLayout { diff --git a/scripts/developer/utilities/cache/stats.qml b/scripts/developer/utilities/cache/stats.qml index d7888eb1aaf..c454ea21ff9 100644 --- a/scripts/developer/utilities/cache/stats.qml +++ b/scripts/developer/utilities/cache/stats.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../lib/plotperf" Item { diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index e4b0267d3f1..02c68b152f8 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml index a935163bd9a..e65d76ea3e1 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/lib/jet/qml/TaskPropView.qml b/scripts/developer/utilities/lib/jet/qml/TaskPropView.qml index 6a658a33e34..1f2a9be23c2 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskPropView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskPropView.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import "../../prop" as Prop diff --git a/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml b/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml index 0b89b5d5be1..3a2966dbe5a 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskTimeFrameView.qml @@ -11,8 +11,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls @@ -181,7 +181,8 @@ Rectangle { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - ctx.font="12px Verdana"; + // QT6TODO + //ctx.font="12px Verdana"; displayBackground(ctx); if (jobsArray.length > 0) { diff --git a/scripts/developer/utilities/lib/plotperf/Color.qml b/scripts/developer/utilities/lib/plotperf/Color.qml index 1ad72fe2e61..c8add4d20d5 100644 --- a/scripts/developer/utilities/lib/plotperf/Color.qml +++ b/scripts/developer/utilities/lib/plotperf/Color.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/lib/plotperf/PlotPerf.qml b/scripts/developer/utilities/lib/plotperf/PlotPerf.qml index f239cc010a5..05103f923d1 100644 --- a/scripts/developer/utilities/lib/plotperf/PlotPerf.qml +++ b/scripts/developer/utilities/lib/plotperf/PlotPerf.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 Item { id: root @@ -264,7 +264,8 @@ Item { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - ctx.font="12px Verdana"; + // QT6TODO + //ctx.font="12px Verdana"; displayBackground(ctx); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 75b927a2c95..0104d4ec8fd 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -10,7 +10,7 @@ // SPDX-License-Identifier: Apache-2.0 // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index bf9089d82c9..1a02a6b770f 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/render/configSlider/RichSlider.qml b/scripts/developer/utilities/render/configSlider/RichSlider.qml index ff16cb32ad5..db6993f2930 100644 --- a/scripts/developer/utilities/render/configSlider/RichSlider.qml +++ b/scripts/developer/utilities/render/configSlider/RichSlider.qml @@ -9,8 +9,8 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 as Original +//import QtQuick.Controls.Styles import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/render/engineList.qml b/scripts/developer/utilities/render/engineList.qml index 55df1bd1875..7aa05f8d36d 100644 --- a/scripts/developer/utilities/render/engineList.qml +++ b/scripts/developer/utilities/render/engineList.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/engineProfiler.qml b/scripts/developer/utilities/render/engineProfiler.qml index 11373187812..ecb3d0c2e49 100644 --- a/scripts/developer/utilities/render/engineProfiler.qml +++ b/scripts/developer/utilities/render/engineProfiler.qml @@ -10,7 +10,7 @@ // SPDX-License-Identifier: Apache-2.0 // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/highlight.qml b/scripts/developer/utilities/render/highlight.qml index d8af2a828ef..3a1f4098fcd 100644 --- a/scripts/developer/utilities/render/highlight.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/highlight/HighlightStyle.qml b/scripts/developer/utilities/render/highlight/HighlightStyle.qml index 475aadfdce0..511094f5975 100644 --- a/scripts/developer/utilities/render/highlight/HighlightStyle.qml +++ b/scripts/developer/utilities/render/highlight/HighlightStyle.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import "../configSlider" import "../../lib/plotperf" diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index 69cf1a6064f..75f007ed2ea 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "configSlider" import "../lib/plotperf" diff --git a/scripts/developer/utilities/render/lod.qml b/scripts/developer/utilities/render/lod.qml index 3d4cafdd38c..5ffeadd37e2 100644 --- a/scripts/developer/utilities/render/lod.qml +++ b/scripts/developer/utilities/render/lod.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/render/luci/Antialiasing.qml b/scripts/developer/utilities/render/luci/Antialiasing.qml index 7c174d53c5b..e3773dcc181 100644 --- a/scripts/developer/utilities/render/luci/Antialiasing.qml +++ b/scripts/developer/utilities/render/luci/Antialiasing.qml @@ -10,7 +10,7 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/luci/Culling.qml b/scripts/developer/utilities/render/luci/Culling.qml index 548b6908b35..b6a0bedfd36 100644 --- a/scripts/developer/utilities/render/luci/Culling.qml +++ b/scripts/developer/utilities/render/luci/Culling.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../../lib/prop" as Prop diff --git a/scripts/developer/utilities/render/rates.qml b/scripts/developer/utilities/render/rates.qml index f4a4ee2c6cb..17e95aa722e 100644 --- a/scripts/developer/utilities/render/rates.qml +++ b/scripts/developer/utilities/render/rates.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../lib/plotperf" Item { diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index 6af0b21d1bf..831aa6d3b29 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/developer/utilities/render/stats.qml b/scripts/developer/utilities/render/stats.qml index 25c108884a0..c776885469e 100644 --- a/scripts/developer/utilities/render/stats.qml +++ b/scripts/developer/utilities/render/stats.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../lib/plotperf" Item { diff --git a/scripts/developer/utilities/render/statsGPU.qml b/scripts/developer/utilities/render/statsGPU.qml index 8d284c11ca8..bba61eb7f21 100644 --- a/scripts/developer/utilities/render/statsGPU.qml +++ b/scripts/developer/utilities/render/statsGPU.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../lib/plotperf" Item { diff --git a/scripts/developer/utilities/render/subsurfaceScattering.qml b/scripts/developer/utilities/render/subsurfaceScattering.qml index ec7367217ef..a4552f529ef 100644 --- a/scripts/developer/utilities/render/subsurfaceScattering.qml +++ b/scripts/developer/utilities/render/subsurfaceScattering.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "configSlider" Column { diff --git a/scripts/developer/utilities/render/surfaceGeometryPass.qml b/scripts/developer/utilities/render/surfaceGeometryPass.qml index ba1db66d16e..0c17789794b 100644 --- a/scripts/developer/utilities/render/surfaceGeometryPass.qml +++ b/scripts/developer/utilities/render/surfaceGeometryPass.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "configSlider" Column { diff --git a/scripts/developer/utilities/render/textureMonitor.qml b/scripts/developer/utilities/render/textureMonitor.qml index b01a390fa80..7e1a594ad93 100644 --- a/scripts/developer/utilities/render/textureMonitor.qml +++ b/scripts/developer/utilities/render/textureMonitor.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import "../lib/plotperf" diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index 440075c9496..ffb233c046c 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -8,10 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/workload/avatars.qml b/scripts/developer/utilities/workload/avatars.qml index 5951e72c315..c4e325d841f 100644 --- a/scripts/developer/utilities/workload/avatars.qml +++ b/scripts/developer/utilities/workload/avatars.qml @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import stylesUit 1.0 import controlsUit 1.0 as HifiControls diff --git a/scripts/developer/utilities/workload/workloadInspector.qml b/scripts/developer/utilities/workload/workloadInspector.qml index 746a572f29b..0c5e007bc2f 100644 --- a/scripts/developer/utilities/workload/workloadInspector.qml +++ b/scripts/developer/utilities/workload/workloadInspector.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // import QtQuick 2.7 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import stylesUit 1.0 diff --git a/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml b/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml index 32a4664e0ac..f1ffeabcfe8 100644 --- a/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml +++ b/scripts/simplifiedUI/simplifiedEmote/ui/qml/SimplifiedEmoteIndicator.qml @@ -11,7 +11,7 @@ import QtQuick 2.10 import QtQuick.Controls 2.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 as HifiStylesUit import TabletScriptingInterface 1.0 import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants diff --git a/scripts/simplifiedUI/ui/simplifiedFTUE/InitialLaunchWindow.qml b/scripts/simplifiedUI/ui/simplifiedFTUE/InitialLaunchWindow.qml index 1938586edb8..5fefde32e7b 100644 --- a/scripts/simplifiedUI/ui/simplifiedFTUE/InitialLaunchWindow.qml +++ b/scripts/simplifiedUI/ui/simplifiedFTUE/InitialLaunchWindow.qml @@ -9,7 +9,7 @@ import QtQuick 2.10 import QtQuick.Controls 2.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Layouts 1.3 import stylesUit 1.0 as HifiStylesUit import TabletScriptingInterface 1.0 diff --git a/scripts/simplifiedUI/ui/simplifiedFTUE/SecondLaunchWindow.qml b/scripts/simplifiedUI/ui/simplifiedFTUE/SecondLaunchWindow.qml index 2a796465aed..0cc89ed9898 100644 --- a/scripts/simplifiedUI/ui/simplifiedFTUE/SecondLaunchWindow.qml +++ b/scripts/simplifiedUI/ui/simplifiedFTUE/SecondLaunchWindow.qml @@ -9,7 +9,7 @@ import QtQuick 2.10 import QtQuick.Controls 2.3 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import QtQuick.Layouts 1.3 import stylesUit 1.0 as HifiStylesUit import TabletScriptingInterface 1.0 diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 2dee944a855..6730c1425fc 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -190,7 +190,7 @@ icon: "icons/tablet-icons/bubble-i.svg", activeIcon: "icons/tablet-icons/bubble-a.svg", text: buttonName, - sortOrder: 4 + sortOrder: 2 }); onBubbleToggled(Users.getIgnoreRadiusEnabled(), true); // pass in true so we don't log this initial one in the UserActivity table diff --git a/scripts/system/chat.js b/scripts/system/chat.js new file mode 100644 index 00000000000..9d606e905ad --- /dev/null +++ b/scripts/system/chat.js @@ -0,0 +1,208 @@ +// +// chat.js +// +// Created by Ada on 2025-10-26 +// Copyright 2025 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// SPDX-License-Identifier: Apache-2.0 +"use strict"; + +const SystemTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + +let settings = Settings.getValue("Chat", { + joinNotifications: true, + broadcastEnabled: false, + chatBubbles: true, + desktopWindow: false, +}); + +function updateSetting(name, value) { + switch (name) { + case "join_notify": + settings.joinNotifications = value; + break; + + case "broadcast": + settings.broadcastEnabled = value; + break; + + case "chat_bubbles": + settings.chatBubbles = value; + Messages.sendLocalMessage("ChatBubbles-Enabled", JSON.stringify(value)); + break; + + case "desktop_window": + settings.desktopWindow = value; + // FIXME: this sometimes leaves an empty ghost window on the overlay? + appWindow.presentationMode = value ? + Desktop.PresentationMode.NATIVE : + Desktop.PresentationMode.VIRTUAL; + break; + } + + Settings.setValue("Chat", settings); +} + +function sendInitialSettings() { + const send = (name, value) => appWindow.sendToQml(JSON.stringify({ + event: "change_setting", + name: name, + value: value, + })); + + send("join_notify", settings.joinNotifications); + send("broadcast", settings.broadcastEnabled); + send("chat_bubbles", settings.chatBubbles); + send("desktop_window", settings.desktopWindow); +} + +function appWindowFromQml(rawMsg) { + const msg = JSON.parse(rawMsg); + + switch (msg.event) { + case "change_setting": + updateSetting(msg.setting, msg.value); + break; + + case "send_message": + Messages.sendMessage("chat", JSON.stringify({ + action: "send_chat_message", + position: MyAvatar.position, + displayName: MyAvatar.sessionDisplayName ? MyAvatar.sessionDisplayName : MyAvatar.displayName, + message: msg.body, + channel: settings.broadcastEnabled ? "domain" : "local", + timestamp: Date.now(), + })); + break; + + case "start_typing": + Messages.sendMessage("Chat-Typing", JSON.stringify({ + action: "typing_start", + position: MyAvatar.position, + })); + break; + + case "end_typing": + Messages.sendMessage("Chat-Typing", JSON.stringify({ + action: "typing_stop" + })); + break; + } +} + +function recreateAppWindow() { + appWindow = Desktop.createWindow( + `${Script.resourcesPath()}qml/overte/chat/Chat.qml`, + { + // TODO: translation support in JS + title: "Chat", + size: { x: 550, y: 400 }, + visible: appButton.buttonData.isActive, + presentationMode: settings.desktopWindow ? + Desktop.PresentationMode.NATIVE : + Desktop.PresentationMode.VIRTUAL, + additionalFlags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES, + } + ); + + // https://github.com/overte-org/overte/issues/824 + appWindow.visible = appButton.buttonData.isActive; + + // FIXME: CLOSE_BUTTON_HIDES doesn't work with desktop windows + appWindow.closed.connect(() => { + appButton.buttonData.isActive = false; + appButton.button.editProperties({ isActive: false }); + appWindow = undefined; + }); + + appWindow.fromQml.connect(appWindowFromQml); + + sendInitialSettings(); +} + +const appButton = { + buttonData: { + isActive: false, + sortOrder: 6, + icon: "icons/tablet-icons/chat-i.svg", + activeIcon: "icons/tablet-icons/chat-a.svg", + + // TODO: translation support in JS + text: "CHAT", + }, + + button: null, + + onClicked() { + this.buttonData.isActive = !this.buttonData.isActive; + this.button.editProperties({ isActive: this.buttonData.isActive }); + + if (!appWindow) { recreateAppWindow(); } + + appWindow.visible = this.buttonData.isActive; + }, +}; + +let appWindow; + +// postpone the window creation until there's a chat event, +// if it's opened too quickly then it can spawn visible +// rather than hidden +//recreateAppWindow(); + +appButton.button = SystemTablet.addButton(appButton.buttonData); +appButton.button.clicked.connect(() => appButton.onClicked()); + +Messages.subscribe("chat"); +Messages.subscribe("Chat-Typing"); + +Messages.messageReceived.connect((channel, rawMsg, senderID, _localOnly) => { + if (channel === "chat") { + if (!appWindow) { recreateAppWindow(); } + + const msg = JSON.parse(rawMsg); + appWindow.sendToQml(JSON.stringify({ + event: "recv_message", + name: msg.displayName, + body: msg.message, + timestamp: msg.timestamp, + })); + } else if (channel === "Chat-Typing") { + if (!appWindow) { recreateAppWindow(); } + + const avatar = AvatarManager.getAvatar(senderID); + const msg = JSON.parse(rawMsg); + appWindow.sendToQml(JSON.stringify({ + event: msg.action === "typing_start" ? "start_typing" : "end_typing", + name: avatar.sessionDisplayName ? avatar.sessionDisplayName : avatar.displayName, + uuid: senderID, + })); + } +}); + +AvatarManager.avatarAddedEvent.connect(uuid => { + if (!appWindow) { recreateAppWindow(); } + + appWindow.sendToQml(JSON.stringify({ + event: "user_joined", + name: AvatarManager.getAvatar(uuid).sessionDisplayName, + timestamp: Date.now(), + })); +}); + +AvatarManager.avatarRemovedEvent.connect(uuid => { + if (!appWindow) { recreateAppWindow(); } + + appWindow.sendToQml(JSON.stringify({ + event: "user_left", + name: AvatarManager.getAvatar(uuid).sessionDisplayName, + timestamp: Date.now(), + })); +}); + +Script.scriptEnding.connect(() => { + SystemTablet.removeButton(appButton.button); +}); diff --git a/scripts/system/controllers/controllerModules/mouseHMD.js b/scripts/system/controllers/controllerModules/mouseHMD.js index 0eccec01a6b..cb8aefb5ab5 100644 --- a/scripts/system/controllers/controllerModules/mouseHMD.js +++ b/scripts/system/controllers/controllerModules/mouseHMD.js @@ -59,6 +59,7 @@ }; this.adjustReticleDepth = function(controllerData) { + // QT6TODO: Reticle.isPointingAtSystemOverlay does not work currently if (Reticle.isPointingAtSystemOverlay(Reticle.position)) { var reticlePositionOnHUD = HMD.worldPointFromOverlay(Reticle.position); Reticle.depth = Vec3.distance(reticlePositionOnHUD, HMD.position); diff --git a/scripts/system/create/entityList/qml/EditEntityList.qml b/scripts/system/create/entityList/qml/EditEntityList.qml index 1d5beb9914f..55be0d8212a 100644 --- a/scripts/system/create/entityList/qml/EditEntityList.qml +++ b/scripts/system/create/entityList/qml/EditEntityList.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 2.2 import QtWebChannel 1.0 import controls 1.0 import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import controlsUit 1.0 as HifiControls import stylesUit 1.0 diff --git a/scripts/system/create/qml/EditTabView.qml b/scripts/system/create/qml/EditTabView.qml index 091ddf0ac77..016b18da340 100644 --- a/scripts/system/create/qml/EditTabView.qml +++ b/scripts/system/create/qml/EditTabView.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 2.2 import QtWebChannel 1.0 import controls 1.0 import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import controlsUit 1.0 as HifiControls import stylesUit 1.0 diff --git a/scripts/system/create/qml/EditToolsTabView.qml b/scripts/system/create/qml/EditToolsTabView.qml index 87295ff543f..12e8a1f14c6 100644 --- a/scripts/system/create/qml/EditToolsTabView.qml +++ b/scripts/system/create/qml/EditToolsTabView.qml @@ -3,7 +3,7 @@ import QtQuick.Controls 2.2 import QtWebChannel 1.0 import controls 1.0 import hifi.toolbars 1.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import controlsUit 1.0 as HifiControls import stylesUit 1.0 diff --git a/scripts/system/create/qml/NewEntityButton.qml b/scripts/system/create/qml/NewEntityButton.qml index a78af7a845e..fd87f9dba0e 100644 --- a/scripts/system/create/qml/NewEntityButton.qml +++ b/scripts/system/create/qml/NewEntityButton.qml @@ -1,5 +1,5 @@ import QtQuick 2.0 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import TabletScriptingInterface 1.0 Item { diff --git a/scripts/system/create/qml/NewMaterialDialog.qml b/scripts/system/create/qml/NewMaterialDialog.qml index 423afe4b186..e3a9d0b1437 100644 --- a/scripts/system/create/qml/NewMaterialDialog.qml +++ b/scripts/system/create/qml/NewMaterialDialog.qml @@ -13,7 +13,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import stylesUit 1.0 import controlsUit 1.0 diff --git a/scripts/system/create/qml/NewModelDialog.qml b/scripts/system/create/qml/NewModelDialog.qml index 5dcbfafa513..0df9b72045c 100644 --- a/scripts/system/create/qml/NewModelDialog.qml +++ b/scripts/system/create/qml/NewModelDialog.qml @@ -12,7 +12,7 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import stylesUit 1.0 import controlsUit 1.0 diff --git a/scripts/system/create/qml/NewParticleDialog.qml b/scripts/system/create/qml/NewParticleDialog.qml index c07843f30ad..08f22403dba 100644 --- a/scripts/system/create/qml/NewParticleDialog.qml +++ b/scripts/system/create/qml/NewParticleDialog.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import stylesUit 1.0 import controlsUit 1.0 diff --git a/scripts/system/create/qml/NewPolyVoxDialog.qml b/scripts/system/create/qml/NewPolyVoxDialog.qml index 38a8d5d77e3..34cf253ad83 100644 --- a/scripts/system/create/qml/NewPolyVoxDialog.qml +++ b/scripts/system/create/qml/NewPolyVoxDialog.qml @@ -13,7 +13,7 @@ // import QtQuick 2.5 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import stylesUit 1.0 import controlsUit 1.0 diff --git a/scripts/system/create/qml/NewSoundDialog.qml b/scripts/system/create/qml/NewSoundDialog.qml index f43a2707acc..13a8ef345bd 100644 --- a/scripts/system/create/qml/NewSoundDialog.qml +++ b/scripts/system/create/qml/NewSoundDialog.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Dialogs as OriginalDialogs import stylesUit 1.0 import controlsUit 1.0 diff --git a/scripts/system/placePortals.js b/scripts/system/placePortals.js new file mode 100644 index 00000000000..adb976080fc --- /dev/null +++ b/scripts/system/placePortals.js @@ -0,0 +1,204 @@ +// +// placePortals.js +// +// Created by Ada on 2025-11-07 +// Copyright 2025 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// SPDX-License-Identifier: Apache-2.0 +"use strict"; + +const PORTAL_LIFETIME_SECS = 20; +const MESSAGE_CHANNEL = "org.overte.PlacePortal"; + +// convenience function because QML can't use the vec3 or quat we normally use +const CREATE_MESSAGE_CHANNEL = "org.overte.PlacePortal.Create"; + +const ROOT_DEFAULT_PROPS = { + type: "Shape", + shape: "Cylinder", + grab: { grabbable: false }, + ignorePickIntersection: true, + dimensions: [1, 2, 1], + alpha: 0, +}; + +const VISUAL_DEFAULT_PROPS = { + type: "ParticleEffect", + // FIXME: why is this oriented weird? + emitDimensions: [0.5, 0.5, 1.5], + textures: Script.resolvePath("./places/icons/portalFX.png"), + emitRate: 100, + lifespan: 3, + maxParticles: 500, + polarStart: 0, + polarFinish: Math.PI, + emitAcceleration: [0, 0, 0], + radiusStart: 1.0, + particleRadius: 0.5, + radiusFinish: 0.3, + alphaStart: 0.1, + alpha: 0.1, + alphaFinish: 0.1, + emitSpeed: -0.1, + speedSpread: 0, + colorStart: [255, 0, 0], + color: [255, 0, 0], + colorFinish: [255, 255, 255], +}; + +const TITLE_DEFAULT_PROPS = { + type: "Text", + grab: { grabbable: false }, + ignorePickIntersection: true, + dimensions: [2, 0.5, 0.1], + localPosition: [0, 1, 0], + billboardMode: "yaw", + backgroundAlpha: 0.0, + lineHeight: 0.1, + unlit: true, + textColor: "white", + textEffect: "outline fill", + textEffectColor: "black", + textEffectThickness: 0.3, + alignment: "center", +}; + +// key is the UUID of the collider, +// value is { +// titleEntity: UUID, +// visualEntity: UUID, +// placeUrl: string, +// onTick: function, +// lifetime: int, +// tickInterval: setInterval, +// } +let portalInfo = new Map(); + +function deleteAllPortals() { + for (const [id, props] of portalInfo) { + Entities.deleteEntity(id); + Entities.deleteEntity(props.titleEntity); + } + + portalInfo.clear(); +} + +function colorHash(x) { + const FNV_PRIME = 0x01000193; + const FNV_OFFSET = 0x811c9dc5; + + let value = FNV_OFFSET; + for (const c of x) { + value ^= c; + value = (value * FNV_PRIME) & 0xffffffff; + } + value /= 0x7fffffff; + + const TAU = 2 * Math.PI; + + const r = 127 * Math.sin((value - (1 / 3)) * TAU) + 128; + const g = 127 * Math.sin((value + 0) * TAU) + 128; + const b = 127 * Math.sin((value + (1 / 3)) * TAU) + 128; + + return [r, g, b]; +} + +function createPortal(placeName, placeUrl, position) { + const color = colorHash(placeName); + + // TODO: translation support + const goingToText = `Going to ${placeName}`; + + const root = Entities.addEntity({ + position: Vec3.sum(position, [0, 1, 0]), + // enterEntity can't be connected to through Entities, is that a bug? + script: `(function(){ + this.enterEntity = _id => { + Window.displayAnnouncement(${JSON.stringify(goingToText)}); + location.handleLookupString(${JSON.stringify(placeUrl)}); + }; +})`, + ...ROOT_DEFAULT_PROPS, + }, "local"); + + const title = Entities.addEntity({ + parentID: root, + text: `${placeName}\n${PORTAL_LIFETIME_SECS}`, + ...TITLE_DEFAULT_PROPS, + }, "local"); + + const visual = Entities.addEntity({ + parentID: root, + ...VISUAL_DEFAULT_PROPS, + colorStart: color, + color: color, + }, "local"); + + let props = { + rootEntity: root, + titleEntity: title, + visualEntity: visual, + placeUrl: placeUrl, + + lifetime: PORTAL_LIFETIME_SECS, + + onTick() { + this.lifetime -= 1; + Entities.editEntity(this.titleEntity, { text: `${placeName}\n${this.lifetime}` }); + + if (this.lifetime <= 0) { + portalInfo.delete(this.rootEntity); + Script.clearInterval(this.tickInterval); + + Entities.deleteEntity(this.titleEntity); + Entities.deleteEntity(this.visualEntity); + Entities.deleteEntity(this.rootEntity); + } + }, + }; + + props.tickInterval = Script.setInterval(() => props.onTick(), 1000); + + portalInfo.set(root, props); +} + +Messages.messageReceived.connect((channel, rawMsg, _senderID, _localOnly) => { + if (channel === MESSAGE_CHANNEL) { + try { + const data = JSON.parse(rawMsg); + + if (data.place_name && data.place_url && data.position) { + createPortal(data.place_name, data.place_url, data.position); + } else { + console.warn(MESSAGE_CHANNEL, "Necessary data missing, can't create portal"); + } + } catch (e) { console.error(e); } + } else if (channel === CREATE_MESSAGE_CHANNEL) { + try { + const data = JSON.parse(rawMsg); + + if (data.place_name && data.place_url) { + createPortal( + data.place_name, + data.place_url, + Vec3.sum( + MyAvatar.feetPosition, + Vec3.multiply( + 1.5 * MyAvatar.sensorToWorldScale, + Quat.getForward(MyAvatar.orientation) + ) + ) + ); + } else { + console.warn(MESSAGE_CHANNEL, "Necessary data missing, can't create portal"); + } + } catch (e) { console.error(e); } + } +}); + +Messages.subscribe(MESSAGE_CHANNEL); +Script.scriptEnding.connect(() => deleteAllPortals()); +Window.domainChanged.connect(_url => deleteAllPortals()); diff --git a/scripts/system/settings/qml/AdvancedOptions.qml b/scripts/system/settings/qml/AdvancedOptions.qml index c1d38a0c9dd..cbd2bff3c81 100644 --- a/scripts/system/settings/qml/AdvancedOptions.qml +++ b/scripts/system/settings/qml/AdvancedOptions.qml @@ -1,6 +1,6 @@ import QtQuick 2.7 import QtQuick.Controls 2.5 -import QtQuick.Controls.Styles 1.4 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 Item { diff --git a/scripts/system/settings/qml/SettingBoolean.qml b/scripts/system/settings/qml/SettingBoolean.qml index 541f1f98555..ad415d67cb7 100644 --- a/scripts/system/settings/qml/SettingBoolean.qml +++ b/scripts/system/settings/qml/SettingBoolean.qml @@ -88,7 +88,7 @@ Item { hoverEnabled: true; propagateComposedEvents: true; - onPressed: { + onPressed: mouse => { mouse.accepted = false } diff --git a/scripts/system/settings/qml/SettingComboBox.qml b/scripts/system/settings/qml/SettingComboBox.qml index fca268be8a1..1a482b131e7 100644 --- a/scripts/system/settings/qml/SettingComboBox.qml +++ b/scripts/system/settings/qml/SettingComboBox.qml @@ -152,7 +152,7 @@ Item { hoverEnabled: true; propagateComposedEvents: true; - onPressed: { + onPressed: mouse => { if (disabled) return; mouse.accepted = false; } @@ -202,4 +202,4 @@ Item { function setOptionIndex(index) { control.currentIndex = index; } -} \ No newline at end of file +} diff --git a/scripts/system/settings/qml/SettingNumber.qml b/scripts/system/settings/qml/SettingNumber.qml index aa00a3f3c47..2a71ba4be9a 100644 --- a/scripts/system/settings/qml/SettingNumber.qml +++ b/scripts/system/settings/qml/SettingNumber.qml @@ -1,6 +1,6 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.5 -import QtQuick.Controls.Styles 1.4 +import QtQuick +import QtQuick.Controls +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 Item { @@ -67,7 +67,7 @@ Item { width: parent.width; clip: true; font.pixelSize: 22 - validator: RegExpValidator { regExp: /[0-9]*/ } + validator: RegularExpressionValidator { regularExpression: /[0-9]*/ } background: Rectangle { color: "#111"; @@ -162,7 +162,7 @@ Item { hoverEnabled: true; propagateComposedEvents: true; - onPressed: { + onPressed: mouse => { mouse.accepted = false } @@ -184,4 +184,4 @@ Item { } } } -} \ No newline at end of file +} diff --git a/scripts/system/settings/qml/SettingSlider.qml b/scripts/system/settings/qml/SettingSlider.qml index 05093724423..b8ca1cb3c3d 100644 --- a/scripts/system/settings/qml/SettingSlider.qml +++ b/scripts/system/settings/qml/SettingSlider.qml @@ -1,6 +1,6 @@ import QtQuick 2.7 import QtQuick.Controls 2.5 -import QtQuick.Controls.Styles 1.4 +//import QtQuick.Controls.Styles import QtQuick.Layouts 1.3 Item { @@ -119,7 +119,7 @@ Item { hoverEnabled: true; propagateComposedEvents: true; - onPressed: { + onPressed: mouse => { mouse.accepted = false } @@ -139,4 +139,4 @@ Item { } } } -} \ No newline at end of file +} diff --git a/scripts/system/settings/qml/pages/GraphicsSettings.qml b/scripts/system/settings/qml/pages/GraphicsSettings.qml index 95f5150813c..da623c2b9ff 100644 --- a/scripts/system/settings/qml/pages/GraphicsSettings.qml +++ b/scripts/system/settings/qml/pages/GraphicsSettings.qml @@ -1,4 +1,4 @@ -import QtQuick 2.15 +import QtQuick import QtQuick.Controls 2.15 import QtQuick.Layouts 1.3 import "../" @@ -74,7 +74,7 @@ Flickable { optionIndex: Performance.getPerformancePreset() - 1; options: ["Low Power", "Low", "Medium", "High", "Custom"]; - onValueChanged: { + function onValueChanged(index) { Performance.setPerformancePreset(index + 1); if (index !== 4) switchToAGraphicsPreset(); } @@ -163,7 +163,7 @@ Flickable { options: ["Economical", "Interactive", "Real-Time", "Custom"]; optionIndex: Performance.getRefreshRateProfile(); - onValueChanged: { + function onValueChanged(index) { Performance.setRefreshRateProfile(index); fpsAdvancedOptions.isEnabled = index == 3; } @@ -181,7 +181,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(0) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(0, value); } } @@ -193,7 +193,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(1) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(1, value); } } @@ -205,7 +205,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(2) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(2, value); } } @@ -217,7 +217,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(3) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(3, value); } } @@ -229,7 +229,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(4) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(4, value); } } @@ -241,7 +241,7 @@ Flickable { suffixText: "fps"; settingValue: Performance.getCustomRefreshRate(5) - onValueChanged: { + function onValueChanged(value) { Performance.setCustomRefreshRate(5, value); } } @@ -255,7 +255,7 @@ Flickable { maxValue: 2; settingValue: Render.viewportResolutionScale.toFixed(1) - onSliderValueChanged: { + function onSliderValueChanged(value) { Render.viewportResolutionScale = value.toFixed(1) } } @@ -265,7 +265,7 @@ Flickable { options: ["Low Detail", "Medium Detail", "High Detail" ]; optionIndex: LODManager.worldDetailQuality; - onValueChanged: { + function onValueChanged(index) { LODManager.worldDetailQuality = index; } @@ -305,7 +305,7 @@ Flickable { settingValue: Render.verticalFieldOfView.toFixed(1); roundDisplay: 0; - onSliderValueChanged: { + function onSliderValueChanged(value) { Render.verticalFieldOfView = value.toFixed(1); } } @@ -327,7 +327,7 @@ Flickable { options: ["None", "TAA", "FXAA"]; disabled: Render.renderMethod; - onValueChanged: { + function onValueChanged(index) { Render.antialiasingMode = index; } diff --git a/scripts/system/systemApps.js b/scripts/system/systemApps.js new file mode 100644 index 00000000000..5ae59e5b199 --- /dev/null +++ b/scripts/system/systemApps.js @@ -0,0 +1,215 @@ +// +// systemApps.js +// +// Created by Ada on 2025-10-26 +// Copyright 2025 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// SPDX-License-Identifier: Apache-2.0 +"use strict"; + +const SystemTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + +function defaultOnClicked() { + this.appButtonData.isActive = !this.appButtonData.isActive; + this.appButton.editProperties({ isActive: this.appButtonData.isActive }); + + if (this.appButtonData.isActive) { + SystemTablet.loadQMLSource(this.qmlSource, false); + } else { + SystemTablet.gotoHomeScreen(); + } +} + +function defaultOnScreenChanged(type, url) { + if (type != "QML" || url != this.qmlSource) { + this.appButtonData.isActive = false; + this.appButton.editProperties({ isActive: this.appButtonData.isActive }); + } +} + +// has absolutely nothing to do with HTTP cookies, +// just here to keep track of what requests are being handled +let waitingRequestCookies = new Set(); + +function defaultFromQml(message) { + const data = JSON.parse(message); + + switch (data.action) { + // QML's XMLHttpRequest doesn't have the authentication header that's + // needed for interacting with the directory server. This passes a + // request through the JS XMLHttpRequest so it can use the account auth. + case "system:auth_request": { + // sometimes requests get sent twice? don't let that happen + if (waitingRequestCookies.has(data.data.cookie)) { + return; + } else { + waitingRequestCookies.add(data.data.cookie); + } + + let xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4 /* DONE */) { + SystemTablet.sendToQml(JSON.stringify({ + action: "system:auth_request", + data: { + status: xhr.status, + statusText: xhr.statusText, + responseText: xhr.responseText, + responseURL: data.data.url, + cookie: data.data.cookie, + }, + })); + + waitingRequestCookies.delete(data.data.cookie); + } + }; + + xhr.open(data.data.method, data.data.url); + + if (data.data.method === "POST") { + xhr.setRequestHeader("Content-Type", "application/json;charset=utf-8"); + } + + xhr.send(data.data.body); + } break; + + case "system:location_go_back": location.goBack(); break; + case "system:location_go_forward": location.goForward(); break; + case "system:location_go_to": { + location.handleLookupString(data.data.path); + + // hide the tablet after travelling + SystemTablet.gotoHomeScreen(); + SystemTablet.tabletShown = false; + } break; + } +} + +const SYSTEM_APPS = { + settings: { + appButtonData: { + sortOrder: 3, + isActive: false, + icon: Script.resolvePath("./settings/img/icon_white.png"), + activeIcon: Script.resolvePath("./settings/img/icon_black.png"), + + // TODO: translation support in JS + text: "SETTINGS", + }, + + qmlSource: "overte/settings/Settings.qml", + appButton: null, + }, + + avatar: { + appButtonData: { + sortOrder: 4, + isActive: false, + icon: "icons/tablet-icons/avatar-i.svg", + activeIcon: "icons/tablet-icons/avatar-a.svg", + + // TODO: translation support in JS + text: "AVATAR", + }, + + qmlSource: "overte/avatar_picker/AvatarPicker.qml", + appButton: null, + }, + + contacts: { + appButtonData: { + sortOrder: 5, + isActive: false, + icon: "icons/tablet-icons/people-i.svg", + activeIcon: "icons/tablet-icons/people-a.svg", + + // TODO: translation support in JS + text: "CONTACTS", + }, + + qmlSource: "overte/contacts/ContactsList.qml", + appButton: null, + }, + + // TODO: to be picked up again in a later PR + /*places: { + appButtonData: { + sortOrder: 6, + isActive: false, + // TODO: put these somewhere more global + icon: Script.resolvePath("./places/icons/appicon_i.png"), + activeIcon: Script.resolvePath("./places/icons/appicon_a.png"), + + // TODO: translation support in JS + text: "PLACES", + }, + + qmlSource: "overte/place_picker/PlacePicker.qml", + appButton: null, + },*/ + + more: { + appButtonData: { + isActive: false, + // TODO: put these somewhere more global + icon: Script.resolvePath("./more/appicon_i.png"), + activeIcon: Script.resolvePath("./more/appicon_a.png"), + + // TODO: translation support in JS + text: "MORE", + }, + + qmlSource: "overte/more_apps/MoreApps.qml", + appButton: null, + }, +}; + +function setupButtons() { + for (let app of Object.values(SYSTEM_APPS)) { + if (!app.onClicked) { app.onClicked = defaultOnClicked; } + if (!app.onScreenChanged) { app.onScreenChanged = defaultOnScreenChanged; } + if (!app.fromQml) { app.fromQml = defaultFromQml; } + + let button = SystemTablet.addButton(app.appButtonData); + button.clicked.connect(() => app.onClicked()); + SystemTablet.screenChanged.connect((type, url) => app.onScreenChanged(type, url)); + SystemTablet.fromQml.connect(message => app.fromQml(message)); + app.appButton = button; + } + + Script.scriptEnding.connect(() => { + for (const app of Object.values(SYSTEM_APPS)) { + if (app.appButton) { + SystemTablet.removeButton(app.appButton); + } + } + }); +} + +function loadInstalledMoreApps() { + const RETRY_DELAY_SECS = 5; + const installedScripts = Settings.getValue("moreApp/installedScripts", []); + + for (const scriptUrl of installedScripts) { + ScriptDiscoveryService.loadScript(scriptUrl, false); + } + + // Check that all of the installed scripts are running. + // If there's some that aren't, then give them one more try. + Script.setTimeout(() => { + const running = ScriptDiscoveryService.getRunning(); + + for (const scriptUrl of installedScripts) { + if (!running.includes(scriptUrl)) { + ScriptDiscoveryService.loadScript(scriptUrl, false); + } + } + }, RETRY_DELAY_SECS * 1000); +} + +loadInstalledMoreApps(); +setupButtons(); diff --git a/tests-manual/controllers/qml/main.qml b/tests-manual/controllers/qml/main.qml index 66060399a67..085e5ccbc9d 100644 --- a/tests-manual/controllers/qml/main.qml +++ b/tests-manual/controllers/qml/main.qml @@ -1,7 +1,7 @@ import QtQuick 2.1 import QtQuick.Controls 1.0 import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs ApplicationWindow { id: window diff --git a/tests-manual/qml/qml/MacQml.qml b/tests-manual/qml/qml/MacQml.qml index 14749bb8264..7df1e23a5f3 100644 --- a/tests-manual/qml/qml/MacQml.qml +++ b/tests-manual/qml/qml/MacQml.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtQuick.Layouts 1.1 -import QtQuick.Dialogs 1.1 +import QtQuick.Dialogs import QtQuick.Controls 1.2 import QtWebEngine 1.5 diff --git a/tests-manual/qml/qml/main.qml b/tests-manual/qml/qml/main.qml index 3b375433939..bd0f9e19fca 100644 --- a/tests-manual/qml/qml/main.qml +++ b/tests-manual/qml/qml/main.qml @@ -50,7 +50,7 @@ import QtQuick 2.2 import QtQuick.Layouts 1.1 -import QtQuick.Dialogs 1.1 +import QtQuick.Dialogs import QtQuick.Controls 1.2 import "qml/UI.js" as UI import "qml" diff --git a/tests-manual/ui/qml/ControlsGalleryWindow.qml b/tests-manual/ui/qml/ControlsGalleryWindow.qml index 32fd62da363..56cd0a35ed7 100644 --- a/tests-manual/ui/qml/ControlsGalleryWindow.qml +++ b/tests-manual/ui/qml/ControlsGalleryWindow.qml @@ -1,6 +1,6 @@ import QtQuick 2.0 import QtQuick.Window 2.3 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 import '../../../scripts/developer/tests' as Tests ApplicationWindow { diff --git a/tests/audio/src/AudioTests.cpp b/tests/audio/src/AudioTests.cpp index 1e097855e8f..f3acc6c96e1 100644 --- a/tests/audio/src/AudioTests.cpp +++ b/tests/audio/src/AudioTests.cpp @@ -38,7 +38,7 @@ void AudioTests::listAudioDevices() { /* // AudioClient::devicesChanged is declared as: - // void devicesChanged(QAudio::Mode mode, const QList& devices); + // void devicesChanged(QAudioDevice::Mode mode, const QList& devices); // // Unfortunately with QSignalSpy we have to use the old SIGNAL() syntax, so it was a bit tricky // to figure out how to get the signal to connect. The snippet below lists signals in the format @@ -59,7 +59,7 @@ void AudioTests::listAudioDevices() { } */ - QSignalSpy spy(ac.get(), SIGNAL(devicesChanged(QAudio::Mode,QList))); + QSignalSpy spy(ac.get(), SIGNAL(devicesChanged(QAudioDevice::Mode,QList))); QVERIFY(spy.isValid()); // This checks that the signal has connected spy.wait(15000); @@ -72,7 +72,7 @@ void AudioTests::listAudioDevices() { // QSignalSpy is a QList, which stores the received signals. We can then examine it to see // what we got. for(auto event : spy) { - QAudio::Mode mode = qvariant_cast(event.at(0)); + QAudioDevice::Mode mode = qvariant_cast(event.at(0)); QList devs = qvariant_cast>(event.at(1)); QVERIFY(devs.count() > 0); diff --git a/tests/model-serializers/src/ModelSerializersTests.cpp b/tests/model-serializers/src/ModelSerializersTests.cpp index 05e3633d7aa..8d537608999 100644 --- a/tests/model-serializers/src/ModelSerializersTests.cpp +++ b/tests/model-serializers/src/ModelSerializersTests.cpp @@ -159,3 +159,63 @@ void ModelSerializersTests::loadGLTF() { QVERIFY(expectWarnings == (model->loadWarningCount>0)); QVERIFY(expectErrors == (model->loadErrorCount>0)); } + +/*void ModelSerializersTests::loadFBX() { + // QTTODO: fix path, but how? + QString filename("/home/ksuprynowicz/overte/overte/interface/resources/serverless/Models/dome.fbx"); + QFile fbx_file(filename); + QVERIFY(fbx_file.open(QIODevice::ReadOnly)); + + QByteArray data = fbx_file.readAll(); + QByteArray uncompressedData; + QUrl url("https://example.com"); + + qInfo() << "URL: " << url; + + if (filename.toLower().endsWith(".gz")) { + url.setPath("/" + filename.chopped(3)); + + if (gunzip(data, uncompressedData)) { + qInfo() << "Uncompressed into" << uncompressedData.length(); + } else { + qCritical() << "Failed to uncompress"; + } + } else { + url.setPath("/" + filename); + uncompressedData = data; + } + + + ModelLoader loader; + QMultiHash serializerMapping; + std::string webMediaType; + + serializerMapping.insert("combineParts", true); + serializerMapping.insert("deduplicateIndices", true); + + qInfo() << "Loading model from" << uncompressedData.length() << "bytes data, url" << url; + + // Check that we can find a serializer for this + auto serializer = DependencyManager::get()->getSerializerForMediaType(uncompressedData, url, webMediaType); + QVERIFY(serializer); + + + + hfm::Model::Pointer model = loader.load(uncompressedData, serializerMapping, url, webMediaType); + QVERIFY(model); + + if (!model) { + // We expected this parse to fail, so nothing more to do here. + return; + } + + QVERIFY(!model->meshes.empty()); + QVERIFY(!model->joints.empty()); + + qInfo() << "Model was loaded with" << model->meshes.count() << "meshes and" << model->joints.count() << "joints. Found" << model->loadWarningCount << "warnings and" << model->loadErrorCount << "errors"; + + // Some models we test are expected to be broken. We're testing that we can load the model without blowing up, + // so loading it with errors is still a successful test. + QVERIFY(model->loadWarningCount == 0); + QVERIFY(model->loadErrorCount == 0); +}*/ diff --git a/tests/model-serializers/src/ModelSerializersTests.h b/tests/model-serializers/src/ModelSerializersTests.h index 45b913a5d7d..89a95919874 100644 --- a/tests/model-serializers/src/ModelSerializersTests.h +++ b/tests/model-serializers/src/ModelSerializersTests.h @@ -21,6 +21,7 @@ private slots: void initTestCase(); void loadGLTF_data(); void loadGLTF(); + //void loadFBX(); }; diff --git a/tests/networking/src/ResourceTests.cpp b/tests/networking/src/ResourceTests.cpp index 18c55d38098..33042743556 100644 --- a/tests/networking/src/ResourceTests.cpp +++ b/tests/networking/src/ResourceTests.cpp @@ -35,7 +35,7 @@ void ResourceTests::initTestCase() { const qint64 MAXIMUM_CACHE_SIZE = 1024 * 1024 * 1024; // 1GB // set up the file cache - //QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + //QString cachePath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); QString cachePath = "./resourceTestCache"; QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkDiskCache* cache = new QNetworkDiskCache(); diff --git a/tests/script-engine/CMakeLists.txt b/tests/script-engine/CMakeLists.txt index 51743129aa4..218bfb1c567 100644 --- a/tests/script-engine/CMakeLists.txt +++ b/tests/script-engine/CMakeLists.txt @@ -5,7 +5,9 @@ macro (setup_testcase_dependencies) # V8TODO: replace most link_hifi_libraries with include_hifi_library_headers # link in the shared libraries - link_hifi_libraries(shared test-utils script-engine networking octree avatars entities model-networking material-networking model-serializers graphics gpu ktx shaders hfm image procedural) + link_hifi_libraries(shared test-utils script-engine networking octree avatars entities model-networking material-networking model-serializers graphics gpu ktx shaders hfm image procedural audio) + include_hifi_library_headers(entities) + include_hifi_library_headers(audio) package_libraries_for_deployment() diff --git a/tests/script-engine/src/ScriptEngineTests.cpp b/tests/script-engine/src/ScriptEngineTests.cpp index 8ad353f8464..c6e13452855 100644 --- a/tests/script-engine/src/ScriptEngineTests.cpp +++ b/tests/script-engine/src/ScriptEngineTests.cpp @@ -326,7 +326,7 @@ void ScriptEngineTests::testQuat() { }); connect(sm.get(), &ScriptManager::unhandledException, [](std::shared_ptr exception){ - QVERIFY(exception->errorMessage.contains("undefined to glm::quat")); + QVERIFY(exception->errorMessage.contains("undefined to glm::qua")); }); diff --git a/tools/animedit/qml/fields/BooleanField.qml b/tools/animedit/qml/fields/BooleanField.qml index 8ba2b938554..5d2956b549f 100644 --- a/tools/animedit/qml/fields/BooleanField.qml +++ b/tools/animedit/qml/fields/BooleanField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { diff --git a/tools/animedit/qml/fields/IdField.qml b/tools/animedit/qml/fields/IdField.qml index b3ee5b6ac98..cc61982bf4a 100644 --- a/tools/animedit/qml/fields/IdField.qml +++ b/tools/animedit/qml/fields/IdField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { id: row diff --git a/tools/animedit/qml/fields/JSONField.qml b/tools/animedit/qml/fields/JSONField.qml index f7b16b82cda..8ba5bb6084f 100644 --- a/tools/animedit/qml/fields/JSONField.qml +++ b/tools/animedit/qml/fields/JSONField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Column { diff --git a/tools/animedit/qml/fields/NumberArrayField.qml b/tools/animedit/qml/fields/NumberArrayField.qml index dd393dc2590..4ac6f776ed6 100644 --- a/tools/animedit/qml/fields/NumberArrayField.qml +++ b/tools/animedit/qml/fields/NumberArrayField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { @@ -43,7 +43,7 @@ Row { // then substitue the second into the \d+ of the first, yeilding this monstrocity. // ^\[\s*(\d+\.?\d*)(\s*,\s*(\d+\.?\d*))*\]$|\[\s*\] - //validator: RegExpValidator { regExp: /^\[\s*(\d+\.?\d*)(\s*,\s*(\d+\.?\d*))*\]$|\[\s*\]/ } + //validator: RegularExpressionValidator { regularExpression: /^\[\s*(\d+\.?\d*)(\s*,\s*(\d+\.?\d*))*\]$|\[\s*\]/ } text: JSON.stringify(value) onEditingFinished: { diff --git a/tools/animedit/qml/fields/NumberField.qml b/tools/animedit/qml/fields/NumberField.qml index 88c952d2056..cfbc0a4ebcf 100644 --- a/tools/animedit/qml/fields/NumberField.qml +++ b/tools/animedit/qml/fields/NumberField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { diff --git a/tools/animedit/qml/fields/StringField.qml b/tools/animedit/qml/fields/StringField.qml index 7ce5cd4c6c0..ae01bc0a094 100644 --- a/tools/animedit/qml/fields/StringField.qml +++ b/tools/animedit/qml/fields/StringField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { diff --git a/tools/animedit/qml/fields/TypeField.qml b/tools/animedit/qml/fields/TypeField.qml index 0a9a7110745..79ee1bd9a56 100644 --- a/tools/animedit/qml/fields/TypeField.qml +++ b/tools/animedit/qml/fields/TypeField.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs Row { id: row diff --git a/tools/animedit/qml/main.qml b/tools/animedit/qml/main.qml index 2d0c277132f..aaa67b05fae 100644 --- a/tools/animedit/qml/main.qml +++ b/tools/animedit/qml/main.qml @@ -1,8 +1,8 @@ import QtQuick 2.12 import QtQuick.Window 2.12 -import QtQuick.Controls 1.6 -import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs import "fields" import "nodes" diff --git a/tools/animedit/qml/nodes/BlendDirectional.qml b/tools/animedit/qml/nodes/BlendDirectional.qml index efdea746628..32be0b97ead 100644 --- a/tools/animedit/qml/nodes/BlendDirectional.qml +++ b/tools/animedit/qml/nodes/BlendDirectional.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/BlendLinear.qml b/tools/animedit/qml/nodes/BlendLinear.qml index 5ed15d9ea78..fa55db879be 100644 --- a/tools/animedit/qml/nodes/BlendLinear.qml +++ b/tools/animedit/qml/nodes/BlendLinear.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/BlendLinearMove.qml b/tools/animedit/qml/nodes/BlendLinearMove.qml index cde0c83fd73..b32edb59ac6 100644 --- a/tools/animedit/qml/nodes/BlendLinearMove.qml +++ b/tools/animedit/qml/nodes/BlendLinearMove.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/ClipData.qml b/tools/animedit/qml/nodes/ClipData.qml index 99490643936..c616dba3283 100644 --- a/tools/animedit/qml/nodes/ClipData.qml +++ b/tools/animedit/qml/nodes/ClipData.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/DefaultPose.qml b/tools/animedit/qml/nodes/DefaultPose.qml index eb16dfb0c0c..315629fa151 100644 --- a/tools/animedit/qml/nodes/DefaultPose.qml +++ b/tools/animedit/qml/nodes/DefaultPose.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/InverseKinematics.qml b/tools/animedit/qml/nodes/InverseKinematics.qml index b401869c32e..75395ea8082 100644 --- a/tools/animedit/qml/nodes/InverseKinematics.qml +++ b/tools/animedit/qml/nodes/InverseKinematics.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/Manipulator.qml b/tools/animedit/qml/nodes/Manipulator.qml index 6a651ae73b7..4e2a3fd912d 100644 --- a/tools/animedit/qml/nodes/Manipulator.qml +++ b/tools/animedit/qml/nodes/Manipulator.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/Overlay.qml b/tools/animedit/qml/nodes/Overlay.qml index 96c974d6e55..cb1f1b6990d 100644 --- a/tools/animedit/qml/nodes/Overlay.qml +++ b/tools/animedit/qml/nodes/Overlay.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/PoleVector.qml b/tools/animedit/qml/nodes/PoleVector.qml index bbf5e96a2fa..050cea6ccb9 100644 --- a/tools/animedit/qml/nodes/PoleVector.qml +++ b/tools/animedit/qml/nodes/PoleVector.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/RandomStateMachine.qml b/tools/animedit/qml/nodes/RandomStateMachine.qml index 357fc4b2bf8..a01b3158ca3 100644 --- a/tools/animedit/qml/nodes/RandomStateMachine.qml +++ b/tools/animedit/qml/nodes/RandomStateMachine.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/SplineIK.qml b/tools/animedit/qml/nodes/SplineIK.qml index df1c8931a3f..ceb9ead9297 100644 --- a/tools/animedit/qml/nodes/SplineIK.qml +++ b/tools/animedit/qml/nodes/SplineIK.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/StateMachine.qml b/tools/animedit/qml/nodes/StateMachine.qml index aec4c30d272..8a3ec4de103 100644 --- a/tools/animedit/qml/nodes/StateMachine.qml +++ b/tools/animedit/qml/nodes/StateMachine.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/animedit/qml/nodes/TwoBoneIK.qml b/tools/animedit/qml/nodes/TwoBoneIK.qml index 6bdae5c1bed..4ea6445861f 100644 --- a/tools/animedit/qml/nodes/TwoBoneIK.qml +++ b/tools/animedit/qml/nodes/TwoBoneIK.qml @@ -2,7 +2,7 @@ import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 1.6 import QtQuick.Layouts 1.3 -import QtQuick.Dialogs 1.0 +import QtQuick.Dialogs import "../fields" Column { diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index 5240ae6ea75..aa46245e6e6 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -11,7 +11,7 @@ #include #include #ifdef Q_OS_LINUX -#include +//#include #endif #ifdef USE_GL #include diff --git a/tools/nitpick/CMakeLists.txt b/tools/nitpick/CMakeLists.txt index 3b4f3917201..0b3179a6889 100644 --- a/tools/nitpick/CMakeLists.txt +++ b/tools/nitpick/CMakeLists.txt @@ -4,13 +4,13 @@ project(${TARGET_NAME}) set(CUSTOM_NITPICK_QRC_PATHS "") find_npm() -find_package(Qt5 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS Widgets) set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc) set(RESOURCES_RCC ${CMAKE_CURRENT_BINARY_DIR}/resources.rcc) generate_qrc(OUTPUT ${RESOURCES_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources CUSTOM_PATHS ${CUSTOM_NITPICK_QRC_PATHS} GLOBS *) -qt5_add_binary_resources(nitpick_resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}" OPTIONS -no-compress) +qt6_add_binary_resources(nitpick_resources "${RESOURCES_QRC}" DESTINATION "${RESOURCES_RCC}" OPTIONS -no-compress) # grab the implementation and header files from src dirs file(GLOB_RECURSE NITPICK_SRCS "src/*.cpp" "src/*.h") @@ -23,7 +23,7 @@ file (GLOB_RECURSE QT_UI_FILES ui/*.ui) source_group("UI Files" FILES ${QT_UI_FILES}) # have qt5 wrap them and generate the appropriate header files -qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") +qt6_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}") setup_memory_debugger() setup_thread_debugger() diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp index 894dfa85f7b..76aee17cde6 100644 --- a/tools/nitpick/src/AWSInterface.cpp +++ b/tools/nitpick/src/AWSInterface.cpp @@ -43,7 +43,7 @@ void AWSInterface::createWebPageFromResults(const QString& testResults, QStringList parts = testResults.split('/'); QString zipFilename = parts[parts.length() - 1]; - QStringList zipFolderNameParts = zipFilename.split(QRegExp("[\\(\\)\\[\\]]"), Qt::SkipEmptyParts); + QStringList zipFolderNameParts = zipFilename.split(QRegularExpression("[\\(\\)\\[\\]]"), Qt::SkipEmptyParts); if (!QRegularExpression("TestResults--\\d{4}(-\\d\\d){2}_\\d\\d(-\\d\\d){2}").match(zipFolderNameParts[0]).hasMatch() || !QRegularExpression("\\w").match(zipFolderNameParts[1]).hasMatch() || // build (local, build number or PR number) diff --git a/tools/nitpick/src/TestCreator.cpp b/tools/nitpick/src/TestCreator.cpp index 0ae3e08353c..7fbcf6913bb 100644 --- a/tools/nitpick/src/TestCreator.cpp +++ b/tools/nitpick/src/TestCreator.cpp @@ -1051,7 +1051,7 @@ void TestCreator::createTestsOutline() { 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('/') }; + qsizetype 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, QDirIterator::Subdirectories); @@ -1231,7 +1231,7 @@ QString TestCreator::getExpectedImagePartialSourceDirectory(const QString& filen // Note that the bottom-most "tests" folder is assumed to be the root // This is required because the tests folder is named hifi_tests - int i { filenameParts.length() - 1 }; + qsizetype i { filenameParts.length() - 1 }; while (i >= 0 && filenameParts[i] != "tests") { --i; } diff --git a/tools/nitpick/src/TestRunnerMobile.cpp b/tools/nitpick/src/TestRunnerMobile.cpp index 53a74da82f5..a9a52b5bfa7 100644 --- a/tools/nitpick/src/TestRunnerMobile.cpp +++ b/tools/nitpick/src/TestRunnerMobile.cpp @@ -13,6 +13,9 @@ #include #include #include +#if defined Q_OS_WIN || defined Q_OS_MAC +#include +#endif #include "Nitpick.h" extern Nitpick* nitpick; @@ -104,15 +107,15 @@ void TestRunnerMobile::connectDevice() { if (line2.contains("unauthorized")) { QMessageBox::critical(0, "Unauthorized device detected", "Please allow USB debugging on device"); } else if (line2.contains(DEVICE)) { - // Make sure only 1 device + // Make sure only 1 device QString line3 = devicesFile.readLine(); if (line3.contains(DEVICE)) { QMessageBox::critical(0, "Too many devices detected", "Tests will run only if a single device is attached"); } else { // Line looks like this: 988a1b47335239434b device product:dream2qlteue model:SM_G955U1 device:dream2qlteue transport_id:2 - QStringList tokens = line2.split(QRegExp("[\r\n\t ]+")); + QStringList tokens = line2.split(QRegularExpression("[\r\n\t ]+")); QString deviceID = tokens[0]; - + // Find the model entry _modelName = "UNKNOWN"; for (int i = 0; i < tokens.size(); ++i) { diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index 0853b41872c..9f770bea985 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -197,7 +197,7 @@ void DomainBaker::addTextureBaker(const QString& property, const QString& url, i // setup a texture baker for this URL, as long as we aren't baking a texture already if (!_textureBakers.contains(key)) { - auto baseTextureFileName = _textureFileNamer.createBaseTextureFileName(textureURL.fileName(), type); + auto baseTextureFileName = _textureFileNamer.createBaseTextureFileName(QFileInfo(textureURL.fileName()), type); // setup a baker for this texture QSharedPointer textureBaker { diff --git a/tools/skeleton-dump/src/SkeletonDumpApp.cpp b/tools/skeleton-dump/src/SkeletonDumpApp.cpp index a736cf60b80..552e42b7d26 100644 --- a/tools/skeleton-dump/src/SkeletonDumpApp.cpp +++ b/tools/skeleton-dump/src/SkeletonDumpApp.cpp @@ -54,7 +54,7 @@ SkeletonDumpApp::SkeletonDumpApp(int argc, char* argv[]) : QCoreApplication(argc return; } QByteArray blob = file.readAll(); - HFMModel::Pointer geometry = FBXSerializer().read(blob, QVariantHash()); + HFMModel::Pointer geometry = FBXSerializer().read(blob, hifi::VariantMultiHash()); std::unique_ptr skeleton(new AnimSkeleton(*geometry)); skeleton->dump(verbose); } diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml index 54839bbd1c0..290a3d1b3a8 100644 --- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml +++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml @@ -14,7 +14,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 +import Qt5Compat.GraphicalEffects import stylesUit 1.0 as HifiStylesUit import controlsUit 1.0 as HifiControlsUit