diff options
125 files changed, 2379 insertions, 880 deletions
@@ -31,7 +31,6 @@ Prerequisites: * ActiveState Active Perl * MinGW with g++ 5.3 or Visual Studio 2017 or later * jom - * Ninja (optional, needed for CMake) * Python 3.5 or later (optional, needed for the python enabled debug helper) * On Mac OS X: latest Xcode * On Linux: g++ 5.3 or later @@ -40,6 +39,7 @@ Prerequisites: "Get LLVM/Clang for the Clang Code Model". The LLVM C++ API provides no compatibility garantee, so if later versions don't compile we don't support that version.) * CMake (for manual builds of LLVM/Clang, and Qt Creator itself) +* Ninja (optional, recommended for building with CMake) * Qbs 1.7.x (optional, sources also contain Qbs itself) The installed toolchains have to match the one Qt was compiled with. diff --git a/dist/changes-4.11.0.md b/dist/changes-4.11.0.md index a85f8e5c3d..3b24537c3e 100644 --- a/dist/changes-4.11.0.md +++ b/dist/changes-4.11.0.md @@ -112,6 +112,10 @@ you can check out from the public Git repository. For example: * Added option to remove directories directly from project tree (QTCREATORBUG-16575) * Added support for Framework paths (QTCREATORBUG-20099) +### Compilation Database + +* Fixed issue with `/imsvc` compiler option (QTCREATORBUG-23146) + ## Debugging ### CDB @@ -131,6 +135,7 @@ you can check out from the public Git repository. For example: * Changed to use separate `clang-tidy` executable * Separated diagnostic configuration settings for code model (`C++` > `Code Model`) and analyzer (`Analyzer` > `Clang Tools`) +* Fixed invocation of `clazy` with latest `clazy` versions ## Qt Widget Designer @@ -174,6 +179,8 @@ you can check out from the public Git repository. For example: * Removed auto-detection of GCC toolchains * Fixed closing of terminal window after application finishes (QTCREATORBUG-15138) +* Fixed execution of `qtc-askpass` (QTCREATORBUG-23120) +* Fixed environment when opening terminal with `zsh` (QTCREATORBUG-21712) ### Android diff --git a/doc/config/qtcreator-project.qdocconf b/doc/config/qtcreator-project.qdocconf index 82daf9faad..b6710edb43 100644 --- a/doc/config/qtcreator-project.qdocconf +++ b/doc/config/qtcreator-project.qdocconf @@ -23,7 +23,8 @@ imagedirs = ../images \ ../../src/plugins/qmldesigner/qmlpreviewplugin/images \ ../../src/plugins/scxmleditor/common/images \ ../../src/plugins/texteditor/images \ - ../../src/plugins/valgrind/images + ../../src/plugins/valgrind/images \ + ../../src/plugins/welcome/images exampledirs = ../examples examples.fileextensions += *.qml *.svg diff --git a/doc/images/qtcreator-clang-tools-options.png b/doc/images/qtcreator-clang-tools-options.png Binary files differindex 6cf866f13f..3fce1e2dff 100644 --- a/doc/images/qtcreator-clang-tools-options.png +++ b/doc/images/qtcreator-clang-tools-options.png diff --git a/doc/images/qtcreator-clang-tools.png b/doc/images/qtcreator-clang-tools.png Binary files differindex 0ae985591c..cd80438a8a 100644 --- a/doc/images/qtcreator-clang-tools.png +++ b/doc/images/qtcreator-clang-tools.png diff --git a/doc/images/qtcreator-cmake-build-settings.png b/doc/images/qtcreator-cmake-build-settings.png Binary files differindex 35b4401820..534ddf6be1 100644 --- a/doc/images/qtcreator-cmake-build-settings.png +++ b/doc/images/qtcreator-cmake-build-settings.png diff --git a/doc/images/qtcreator-cmake-build-steps.png b/doc/images/qtcreator-cmake-build-steps.png Binary files differindex 1679217c51..5809136a85 100644 --- a/doc/images/qtcreator-cmake-build-steps.png +++ b/doc/images/qtcreator-cmake-build-steps.png diff --git a/doc/images/qtcreator-cmake-clean-steps.png b/doc/images/qtcreator-cmake-clean-steps.png Binary files differindex 9ecfbc74f1..88be99d715 100644 --- a/doc/images/qtcreator-cmake-clean-steps.png +++ b/doc/images/qtcreator-cmake-clean-steps.png diff --git a/doc/images/qtcreator-cmakeexecutable.png b/doc/images/qtcreator-cmakeexecutable.png Binary files differindex a0475e0c04..b98085b4e0 100644 --- a/doc/images/qtcreator-cmakeexecutable.png +++ b/doc/images/qtcreator-cmakeexecutable.png diff --git a/doc/images/qtcreator-files-to-analyze.png b/doc/images/qtcreator-files-to-analyze.png Binary files differindex fcdf05c0db..add972f337 100644 --- a/doc/images/qtcreator-files-to-analyze.png +++ b/doc/images/qtcreator-files-to-analyze.png diff --git a/doc/images/qtcreator-kits.png b/doc/images/qtcreator-kits.png Binary files differindex 05e8cc0df3..4dfaa560f3 100644 --- a/doc/images/qtcreator-kits.png +++ b/doc/images/qtcreator-kits.png diff --git a/doc/src/analyze/creator-clang-static-analyzer.qdoc b/doc/src/analyze/creator-clang-static-analyzer.qdoc index c4468ef038..b378553495 100644 --- a/doc/src/analyze/creator-clang-static-analyzer.qdoc +++ b/doc/src/analyze/creator-clang-static-analyzer.qdoc @@ -60,6 +60,11 @@ Clang tools are delivered and installed with \QC, and therefore you do not need to set them up separately. + In addition to running the tools to collect diagnostics, you can select + \inlineimage open.png + to load diagnostics from \l{https://yaml.org/}{YAML} files that you exported + using the \c {-export fixes} option. + \section1 Running Clang Tools To run the Clang tools to analyze an open project: @@ -68,41 +73,25 @@ \li Select \uicontrol Analyze > \uicontrol {Clang-Tidy and Clazy}. - \image qtcreator-files-to-analyze.png "Analyzer Configuration dialog" - - \li In the \uicontrol General group, select \uicontrol {Custom Settings} - to modify the analyzer configuration. - - \li To build the project before running the Clang tools, select the - \uicontrol {Build the project before analysis} check box. The Clang - tools do not require the project to be built before analysis, but - they might display misleading warnings about files missing that are - generated during the build. For big projects, not building the - project might save some time. - - \li In the \uicontrol {Diagnostic configuration} field, select a Clang - configuration in the list of pre-defined configurations (1). For - more information about creating a custom configuration, see - \l {Configuring Clang Tools}. + \image qtcreator-files-to-analyze.png "Files to Analyze dialog" - \li In the \uicontrol {Files to Analyze} group, select the files to - apply the checks to. + \li Select the files to apply the checks to. \li Select \uicontrol Analyze to start the checks. \endlist - If you select \uicontrol Debug in the mode selector to open the - \uicontrol Debug mode and then select \uicontrol {Clang-Tidy and Clazy}, - you must select the \inlineimage qtcreator-analyze-start-button.png - (\uicontrol Start) button to open the \uicontrol {Analyzer Configuration} - dialog. - The found issues are displayed in the \uicontrol {Clang-Tidy and Clazy} view: \image qtcreator-clang-tools.png "Clang-Tidy and Clazy view" + \note If you select \uicontrol Debug in the mode selector to open the + \uicontrol Debug mode and then select \uicontrol {Clang-Tidy and Clazy}, + you must select the \inlineimage qtcreator-analyze-start-button.png + (\uicontrol Start) button to open the \uicontrol {Files to Analyze} + dialog. + Double-click an issue to move to the location where the issue appears in the code editor. diff --git a/doc/src/cmake/creator-projects-cmake-building.qdocinc b/doc/src/cmake/creator-projects-cmake-building.qdocinc index bca11658e4..a31449984c 100644 --- a/doc/src/cmake/creator-projects-cmake-building.qdocinc +++ b/doc/src/cmake/creator-projects-cmake-building.qdocinc @@ -57,6 +57,10 @@ To reset the changes that you made, select \uicontrol Reset. + To reconfigure CMake, select \uicontrol Build > + \uicontrol {Clear CMake Configuration}, and then + select \uicontrol Build > \uicontrol {Rescan Project}. + //! [cmake build configuration] @@ -65,7 +69,7 @@ \section2 CMake Build Steps \QC builds CMake projects by running \c {cmake . --build}, which then runs - run whatever is needed based on how the project was configured: \c make, + whatever is needed based on how the project was configured: \c make, \c mingw32-make, \c nmake, or \c ninja, for example. You can add arguments and targets for the build command in diff --git a/doc/src/cmake/creator-projects-cmake.qdoc b/doc/src/cmake/creator-projects-cmake.qdoc index 585031ded7..a6d0ad6671 100644 --- a/doc/src/cmake/creator-projects-cmake.qdoc +++ b/doc/src/cmake/creator-projects-cmake.qdoc @@ -61,6 +61,10 @@ provide less information to the code model, which will then fail to resolve includes and defines. + For CMake version 3.14, or later, \QC supports the + \l {https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html} + {file-based API}. + To specify paths to CMake executables: \list 1 @@ -99,9 +103,14 @@ \section1 Editing CMake Configuration Files To open a CMakeLists.txt file for editing, right-click it in the - \uicontrol Projects view and select \uicontrol {Open with} > + \uicontrol Projects view and select \uicontrol {Open With} > \uicontrol {CMake Editor}. + You can also use the \c cmo filter in the \l {Searching with the Locator} + {locator} to open the CMakeLists.txt file for the current run configuration + in the editor. This is the same build target as when you select + \uicontrol Build > \uicontrol {Build for Run Configuration}. + The following features are supported: \list diff --git a/doc/src/editors/creator-locator.qdoc b/doc/src/editors/creator-locator.qdoc index e7c048f6d2..cd99ab139b 100644 --- a/doc/src/editors/creator-locator.qdoc +++ b/doc/src/editors/creator-locator.qdoc @@ -150,6 +150,11 @@ \if defined(qtcreator) \li Running external tools (\c x) + \li Using CMake to build the project for the current run configuration + (\c {cm}). For more information, see \l {Setting up CMake}. + \li Opening the CMakeLists.txt file for the current run configuration in + the editor (\c {cmo}). This is the same build target as when you + select \uicontrol Build > \uicontrol {Build for Run Configuration}. \endif \endlist diff --git a/doc/src/projects/creator-only/creator-projects-building.qdoc b/doc/src/projects/creator-only/creator-projects-building.qdoc index c87557dc69..86b8b61748 100644 --- a/doc/src/projects/creator-only/creator-projects-building.qdoc +++ b/doc/src/projects/creator-only/creator-projects-building.qdoc @@ -84,16 +84,18 @@ To quickly check the compile output for changes that you made in one file or subproject, you can use the \uicontrol Build menu commands to build a file or - subproject. + subproject. The available build menu commands depend on the build system + you selected for the project: CMake, qmake, or Qbs. - To build the executable that corresponds to the selected run configuration, - select \uicontrol Build > \uicontrol {Build for Run Configuration}. + Select \uicontrol Build > \uicontrol {Build for Run Configuration} to + build the executable that corresponds to the selected run configuration. + You can also use the \c cm filter in the \l {Searching with the Locator} + {locator}. To remove all build artifacts, select \uicontrol Build > \uicontrol {Clean All} or \uicontrol {Clean Project}. To clean the build directory and then build the project, select \uicontrol Build > \uicontrol {Rebuild All} or - \uicontrol {Rebuild Project}. If you use qmake, rebuilding also runs qmake - to generate new Makefiles between cleaning and building. + \uicontrol {Rebuild Project}. To build and clean projects without dependencies, select the \uicontrol {Build Without Dependencies}, @@ -101,11 +103,22 @@ \uicontrol {Clean Without Dependencies} options in the context menu in the \uicontrol Projects view. - \section1 Additional qmake Commands + To run qmake or CMake to regenerate build system files, select + \uicontrol Build > \uicontrol {Run qmake} or \uicontrol {Run CMake}. - To run qmake to generate new Makefiles, select \uicontrol Build > - \uicontrol qmake. To prevent failures on incremental builds, it might make - sense to always run qmake before building, even though it means that + \section2 Building with CMake + + \QC automatically runs CMake when you make changes to \c {CMakeLists.txt} + files. To disable this feature, select \uicontrol Tools > + \uicontrol Options > \uicontrol Kits > \uicontrol CMake > + \uicontrol {Autorun CMake}. + + For more information, see \l {Setting Up CMake}. + + \section2 Building with qmake + + To prevent failures on incremental builds, it might make sense + to always run qmake before building, even though it means that building will take more time. To enable this option, select \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > \uicontrol qmake > \uicontrol {Run qmake on every build}. diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml index 9ffd3aa85b..dc4c38d100 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -46,7 +46,7 @@ Node { } Connections { - target: designStudioNativeCameraControlHelper + target: _generalHelper onOverlayUpdateNeeded: updateScale() } @@ -81,6 +81,7 @@ Node { MouseArea3D { id: helper + active: false view3D: overlayNode.view3D } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml new file mode 100644 index 0000000000..86c60db721 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +View3D { + id: axisHelperView + + property var editCameraCtrl + property Node selectedNode + + camera: axisHelperCamera + + Node { + OrthographicCamera { + id: axisHelperCamera + rotation: editCameraCtrl.camera.rotation + position: editCameraCtrl.camera.position.minus(editCameraCtrl._lookAtPoint) + .normalized().times(600) + } + + AutoScaleHelper { + id: autoScale + view3D: axisHelperView + position: axisHelperGizmo.scenePosition + } + + Node { + id: axisHelperGizmo + scale: autoScale.getScale(Qt.vector3d(4, 4, 4)) + + AxisHelperArm { + id: armX + rotation: Qt.vector3d(0, 0, -90) + color: Qt.rgba(1, 0, 0, 1) + hoverColor: Qt.lighter(Qt.rgba(1, 0, 0, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(0, 90, 0) + camRotNeg: Qt.vector3d(0, -90, 0) + } + + AxisHelperArm { + id: armY + rotation: Qt.vector3d(0, 0, 0) + color: Qt.rgba(0, 0.6, 0, 1) + hoverColor: Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(-90, 0, 0) + camRotNeg: Qt.vector3d(90, 0, 0) + } + + AxisHelperArm { + id: armZ + rotation: Qt.vector3d(90, 0, 0) + color: Qt.rgba(0, 0, 1, 1) + hoverColor: Qt.lighter(Qt.rgba(0, 0, 1, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(0, 0, 0) + camRotNeg: Qt.vector3d(0, 180, 0) + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton + + property var pickObj: null + + function cancelHover() + { + if (pickObj) { + pickObj.hovering = false; + pickObj = null; + } + } + + function pick(mouse) + { + var result = axisHelperView.pick(mouse.x, mouse.y); + if (result.objectHit) { + if (result.objectHit !== pickObj) { + cancelHover(); + pickObj = result.objectHit; + pickObj.hovering = true; + } + } else { + cancelHover(); + } + } + + onPositionChanged: { + pick(mouse); + } + + onPressed: { + pick(mouse); + if (pickObj) { + axisHelperView.editCameraCtrl.fitObject(axisHelperView.selectedNode, + pickObj.cameraRotation); + } else { + mouse.accepted = false; + } + } + + onExited: cancelHover() + onCanceled: cancelHover() + } +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml index ae17196044..23d2f9bbaf 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml @@ -23,40 +23,48 @@ ** ****************************************************************************/ -#pragma once +import QtQuick 2.0 +import QtQuick3D 1.0 -#include <QtCore/QObject> -#include <QtCore/QTimer> +Node { + id: armRoot + property alias posModel: posModel + property alias negModel: negModel + property View3D view3D + property color hoverColor + property color color + property vector3d camRotPos + property vector3d camRotNeg -namespace QmlDesigner { -namespace Internal { -class CameraControlHelper : public QObject -{ - Q_OBJECT - Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Model { + id: posModel -public: - CameraControlHelper(); + property bool hovering: false + property vector3d cameraRotation: armRoot.camRotPos - bool enabled(); - void setEnabled(bool enabled); + source: "meshes/axishelper.mesh" + materials: DefaultMaterial { + id: posMat + emissiveColor: posModel.hovering ? armRoot.hoverColor : armRoot.color + lighting: DefaultMaterial.NoLighting + } + pickable: true + } - Q_INVOKABLE void requestOverlayUpdate(); - Q_INVOKABLE QString generateUniqueName(const QString &nameRoot); + Model { + id: negModel -public slots: - void handleUpdateTimer(); + property bool hovering: false + property vector3d cameraRotation: armRoot.camRotNeg -signals: - void updateInputs(); - void enabledChanged(bool enabled); - void overlayUpdateNeeded(); - -private: - bool m_enabled = false; - QTimer m_inputUpdateTimer; - QTimer m_overlayUpdateTimer; -}; - -} + source: "#Sphere" + y: -6 + scale: Qt.vector3d(0.025, 0.025, 0.025) + materials: DefaultMaterial { + id: negMat + emissiveColor: negModel.hovering ? armRoot.hoverColor : armRoot.color + lighting: DefaultMaterial.NoLighting + } + pickable: true + } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml index e158128a5f..3b6badbb28 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml @@ -31,21 +31,26 @@ IconGizmo { id: cameraGizmo iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_camera.png" - gizmoModel.geometry: cameraGeometry property alias geometryName: cameraGeometry.name // Name must be unique for each geometry property alias viewPortRect: cameraGeometry.viewPortRect + Model { + id: gizmoModel + geometry: cameraGeometry + visible: cameraGizmo.visible + materials: [ + DefaultMaterial { + id: defaultMaterial + emissiveColor: cameraGizmo.targetNode === cameraGizmo.selectedNode ? "#FF0000" + : "#555555" + lighting: DefaultMaterial.NoLighting + cullingMode: Material.DisableCulling + } + ] + } + CameraGeometry { id: cameraGeometry camera: cameraGizmo.targetNode } - - gizmoModel.materials: [ - DefaultMaterial { - id: defaultMaterial - emissiveColor: cameraGizmo.targetNode === cameraGizmo.selectedNode ? "#FF0000" : "#555555" - lighting: DefaultMaterial.NoLighting - cullingMode: Material.DisableCulling - } - ] } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml index 243744210e..7ccfaa9816 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml @@ -34,7 +34,7 @@ Model { property View3D view3D property alias color: material.emissiveColor property Node targetNode: null - property bool dragging: false + property bool dragging: mouseAreaYZ.dragging || mouseAreaXZ.dragging property bool active: false readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering @@ -61,7 +61,6 @@ Model { _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); var sp = targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); - dragging = true; pressed(mouseArea); } @@ -88,7 +87,6 @@ Model { return; released(mouseArea, calcRelativeDistance(mouseArea, scenePos)); - dragging = false; } MouseArea3D { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml new file mode 100644 index 0000000000..dba7e30f96 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick3D 1.0 + +Item { + id: cameraCtrl + + property Camera camera: null + property View3D view3d: null + + property vector3d _lookAtPoint + property vector3d _pressPoint + property vector3d _prevPoint + property vector3d _startRotation + property vector3d _startPosition + property vector3d _startLookAtPoint + property matrix4x4 _startTransform + property bool _dragging + property int _button + property real _zoomFactor: 1 + property real _defaultCameraLookAtDistance: 0 + property Camera _prevCamera: null + + function fitObject(targetObject, rotation) + { + camera.rotation = rotation; + var newLookAtAndZoom = _generalHelper.fitObjectToCamera( + camera, _defaultCameraLookAtDistance, targetObject, view3d); + _lookAtPoint = newLookAtAndZoom.toVector3d(); + _zoomFactor = newLookAtAndZoom.w; + } + + function zoomRelative(distance) + { + _zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance, + _lookAtPoint, _zoomFactor, true); + } + + Component.onCompleted: { + cameraCtrl._defaultCameraLookAtDistance = cameraCtrl.camera.position.length(); + } + + onCameraChanged: { + if (_prevCamera) { + // Reset zoom on previous camera to ensure it's properties are good to copy to new cam + _generalHelper.zoomCamera(_prevCamera, 0, _defaultCameraLookAtDistance, _lookAtPoint, + 1, false); + + camera.position = _prevCamera.position; + camera.rotation = _prevCamera.rotation; + + // Apply correct zoom to new camera + _generalHelper.zoomCamera(camera, 0, _defaultCameraLookAtDistance, _lookAtPoint, + _zoomFactor, false); + } + _prevCamera = camera; + } + + MouseArea { + id: mouseHandler + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + hoverEnabled: false + anchors.fill: parent + onPositionChanged: { + if (mouse.modifiers === Qt.AltModifier && cameraCtrl._dragging) { + var currentPoint = Qt.vector3d(mouse.x, mouse.y, 0); + if (cameraCtrl._button == Qt.LeftButton) { + _generalHelper.orbitCamera(cameraCtrl.camera, cameraCtrl._startRotation, + cameraCtrl._lookAtPoint, cameraCtrl._pressPoint, + currentPoint); + } else if (cameraCtrl._button == Qt.MiddleButton) { + cameraCtrl._lookAtPoint = _generalHelper.panCamera( + cameraCtrl.camera, cameraCtrl._startTransform, + cameraCtrl._startPosition, cameraCtrl._startLookAtPoint, + cameraCtrl._pressPoint, currentPoint, _zoomFactor); + } else if (cameraCtrl._button == Qt.RightButton) { + cameraCtrl.zoomRelative(currentPoint.y - cameraCtrl._prevPoint.y) + cameraCtrl._prevPoint = currentPoint; + } + } + } + onPressed: { + if (mouse.modifiers === Qt.AltModifier) { + cameraCtrl._dragging = true; + cameraCtrl._startRotation = cameraCtrl.camera.rotation; + cameraCtrl._startPosition = cameraCtrl.camera.position; + cameraCtrl._startLookAtPoint = _lookAtPoint; + cameraCtrl._pressPoint = Qt.vector3d(mouse.x, mouse.y, 0); + cameraCtrl._prevPoint = cameraCtrl._pressPoint; + cameraCtrl._button = mouse.button; + cameraCtrl._startTransform = cameraCtrl.camera.sceneTransform; + } else { + mouse.accepted = false; + } + } + + onReleased: cameraCtrl._dragging = false; + onCanceled: cameraCtrl._dragging = false; + onWheel: { + // Emprically determined divisor for nice zoom + cameraCtrl.zoomRelative(wheel.angleDelta.y / -40); + } + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 9db9d0c8a8..2200048fa5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -26,7 +26,6 @@ import QtQuick 2.12 import QtQuick.Window 2.0 import QtQuick3D 1.0 -import QtQuick3D.Helpers 1.0 import QtQuick.Controls 2.0 import QtGraphicalEffects 1.0 @@ -39,8 +38,8 @@ Window { flags: Qt.WindowStaysOnTopHint | Qt.Window | Qt.WindowTitleHint | Qt.WindowCloseButtonHint property alias scene: editView.importScene - property alias showEditLight: editLightCheckbox.checked - property alias usePerspective: usePerspectiveCheckbox.checked + property alias showEditLight: btnEditViewLight.toggled + property alias usePerspective: btnPerspective.toggled property Node selectedNode: null @@ -56,9 +55,14 @@ Window { selectedNode = object; } - function emitObjectClicked(object) { - selectObject(object); - objectClicked(object); + function handleObjectClicked(object) { + var theObject = object; + if (btnSelectGroup.selected) { + while (theObject && theObject.parent !== scene) + theObject = theObject.parent; + } + selectObject(theObject); + objectClicked(theObject); } function addLightGizmo(obj) @@ -69,7 +73,7 @@ Window { {"view3D": overlayView, "targetNode": obj, "selectedNode": selectedNode}); lightGizmos[lightGizmos.length] = gizmo; - gizmo.clicked.connect(emitObjectClicked); + gizmo.clicked.connect(handleObjectClicked); gizmo.selectedNode = Qt.binding(function() {return selectedNode;}); } } @@ -78,13 +82,13 @@ Window { { var component = Qt.createComponent("CameraGizmo.qml"); if (component.status === Component.Ready) { - var geometryName = designStudioNativeCameraControlHelper.generateUniqueName("CameraGeometry"); + var geometryName = _generalHelper.generateUniqueName("CameraGeometry"); var gizmo = component.createObject( overlayScene, {"view3D": overlayView, "targetNode": obj, "geometryName": geometryName, "viewPortRect": viewPortRect, "selectedNode": selectedNode}); cameraGizmos[cameraGizmos.length] = gizmo; - gizmo.clicked.connect(emitObjectClicked); + gizmo.clicked.connect(handleObjectClicked); gizmo.viewPortRect = Qt.binding(function() {return viewPortRect;}); gizmo.selectedNode = Qt.binding(function() {return selectedNode;}); } @@ -92,10 +96,10 @@ Window { // Work-around the fact that the projection matrix for the camera is not calculated until // the first frame is rendered, so any initial calls to mapFrom3DScene() will fail. - Component.onCompleted: designStudioNativeCameraControlHelper.requestOverlayUpdate(); + Component.onCompleted: _generalHelper.requestOverlayUpdate(); - onWidthChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate(); - onHeightChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate(); + onWidthChanged: _generalHelper.requestOverlayUpdate(); + onHeightChanged: _generalHelper.requestOverlayUpdate(); Node { id: overlayScene @@ -114,6 +118,7 @@ Window { clipNear: editOrthoCamera.clipNear position: editOrthoCamera.position rotation: editOrthoCamera.rotation + scale: editOrthoCamera.scale } MoveGizmo { @@ -123,7 +128,7 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) - globalOrientation: globalControl.checked + globalOrientation: btnLocalGlobal.toggled visible: selectedNode && btnMove.selected view3D: overlayView @@ -138,7 +143,7 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) - globalOrientation: globalControl.checked + globalOrientation: false visible: selectedNode && btnScale.selected view3D: overlayView @@ -153,7 +158,7 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) - globalOrientation: globalControl.checked + globalOrientation: btnLocalGlobal.toggled visible: selectedNode && btnRotate.selected view3D: overlayView @@ -169,16 +174,19 @@ Window { } Rectangle { - id: sceneBg - color: "#FFFFFF" anchors.fill: parent focus: true + gradient: Gradient { + GradientStop { position: 1.0; color: "#222222" } + GradientStop { position: 0.0; color: "#999999" } + } + TapHandler { // check tapping/clicking an object in the scene onTapped: { var pickResult = editView.pick(eventPoint.scenePosition.x, eventPoint.scenePosition.y); - emitObjectClicked(pickResult.objectHit); + handleObjectClicked(pickResult.objectHit); } } @@ -200,6 +208,12 @@ Window { step: 50 } + SelectionBox { + id: selectionBox + view3D: editView + targetNode: viewWindow.selectedNode + } + PointLight { id: editLight visible: showEditLight @@ -209,11 +223,14 @@ Window { linearFade: 0 } + // Initial camera position and rotation should be such that they look at origin. + // Otherwise EditCameraController._lookAtPoint needs to be initialized to correct + // point. PerspectiveCamera { id: editPerspectiveCamera z: -600 - y: 200 - rotation.x: 30 + y: 600 + rotation.x: 45 clipFar: 100000 clipNear: 1 } @@ -221,10 +238,10 @@ Window { OrthographicCamera { id: editOrthoCamera z: -600 - y: 200 - rotation.x: 30 + y: 600 + rotation.x: 45 clipFar: 100000 - clipNear: 1 + clipNear: -10000 } } } @@ -240,14 +257,12 @@ Window { id: gizmoLabel targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo targetView: overlayView - offsetX: 0 - offsetY: 45 visible: targetNode.dragging Rectangle { color: "white" x: -width / 2 - y: -height + y: -height - 8 width: gizmoLabelText.width + 4 height: gizmoLabelText.height + 4 border.width: 1 @@ -273,19 +288,11 @@ Window { } } - WasdController { + EditCameraController { id: cameraControl - controlledObject: editView.camera - acceptedButtons: Qt.RightButton - - onInputsNeedProcessingChanged: designStudioNativeCameraControlHelper.enabled - = cameraControl.inputsNeedProcessing - - // Use separate native timer as QML timers don't work inside Qt Design Studio - Connections { - target: designStudioNativeCameraControlHelper - onUpdateInputs: cameraControl.processInputs() - } + camera: editView.camera + anchors.fill: parent + view3d: editView } } @@ -301,7 +308,8 @@ Window { spacing: 5 padding: 5 - property var group: [btnSelectItem, btnSelectGroup, btnMove, btnRotate, btnScale] + property var groupSelect: [btnSelectGroup, btnSelectItem] + property var groupTransform: [btnMove, btnRotate, btnScale] ToolBarButton { id: btnSelectItem @@ -310,7 +318,7 @@ Window { shortcut: "Q" currentShortcut: selected ? "" : shortcut tool: "item_selection" - buttonsGroup: col.group + buttonsGroup: col.groupSelect } ToolBarButton { @@ -319,7 +327,7 @@ Window { shortcut: "Q" currentShortcut: btnSelectItem.currentShortcut === shortcut ? "" : shortcut tool: "group_selection" - buttonsGroup: col.group + buttonsGroup: col.groupSelect } Rectangle { // separator @@ -331,11 +339,12 @@ Window { ToolBarButton { id: btnMove + selected: true tooltip: qsTr("Move current selection") - shortcut: "M" + shortcut: "W" currentShortcut: shortcut tool: "move" - buttonsGroup: col.group + buttonsGroup: col.groupTransform } ToolBarButton { @@ -344,60 +353,96 @@ Window { shortcut: "E" currentShortcut: shortcut tool: "rotate" - buttonsGroup: col.group + buttonsGroup: col.groupTransform } ToolBarButton { id: btnScale tooltip: qsTr("Scale current selection") - shortcut: "T" + shortcut: "R" currentShortcut: shortcut tool: "scale" - buttonsGroup: col.group + buttonsGroup: col.groupTransform + } + + Rectangle { // separator + width: 25 + height: 1 + color: "#f1f1f1" + anchors.horizontalCenter: parent.horizontalCenter + } + + ToolBarButton { + id: btnFit + tooltip: qsTr("Fit camera to current selection") + shortcut: "F" + currentShortcut: shortcut + tool: "fit" + togglable: false + + onSelectedChanged: { + if (selected) { + var targetNode = viewWindow.selectedNode ? selectionBox.model : null; + cameraControl.fitObject(targetNode, editView.camera.rotation); + } + } } } } - Column { - y: 8 + AxisHelper { anchors.right: parent.right - CheckBox { - id: editLightCheckbox - checked: false - text: qsTr("Use Edit View Light") - onCheckedChanged: cameraControl.forceActiveFocus() + anchors.top: parent.top + width: 100 + height: width + editCameraCtrl: cameraControl + selectedNode : viewWindow.selectedNode ? selectionBox.model : null + } + + Rectangle { // top controls bar + color: "#aa000000" + width: 265 + height: btnPerspective.height + 10 + anchors.top: parent.top + anchors.right: parent.right + anchors.rightMargin: 100 + + ToggleButton { + id: btnPerspective + anchors.top: parent.top + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 5 + tooltip: qsTr("Toggle Perspective / Orthographic Projection") + states: [{iconId: "ortho", text: qsTr("Orthographic")}, {iconId: "persp", text: qsTr("Perspective")}] } - CheckBox { - id: usePerspectiveCheckbox - checked: true - text: qsTr("Use Perspective Projection") - onCheckedChanged: { - // Since WasdController always acts on active camera, we need to update pos/rot - // to the other camera when we change - if (checked) { - editPerspectiveCamera.position = editOrthoCamera.position; - editPerspectiveCamera.rotation = editOrthoCamera.rotation; - } else { - editOrthoCamera.position = editPerspectiveCamera.position; - editOrthoCamera.rotation = editPerspectiveCamera.rotation; - } - designStudioNativeCameraControlHelper.requestOverlayUpdate(); - cameraControl.forceActiveFocus(); - } + ToggleButton { + id: btnLocalGlobal + anchors.top: parent.top + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 100 + tooltip: qsTr("Toggle Global / Local Orientation") + states: [{iconId: "local", text: qsTr("Local")}, {iconId: "global", text: qsTr("Global")}] } - CheckBox { - id: globalControl - checked: true - text: qsTr("Use Global Orientation") - onCheckedChanged: cameraControl.forceActiveFocus() + ToggleButton { + id: btnEditViewLight + anchors.top: parent.top + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 165 + toggleBackground: true + tooltip: qsTr("Toggle Edit Light") + states: [{iconId: "edit_light_off", text: qsTr("Edit Light Off")}, {iconId: "edit_light_on", text: qsTr("Edit Light On")}] } } Text { id: helpText - text: qsTr("Camera: W,A,S,D,R,F,right mouse drag") + color: "white" + text: qsTr("Camera controls: ALT + mouse press and drag. Left: Rotate, Middle: Pan, Right/Wheel: Zoom.") anchors.bottom: parent.bottom } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/HelperGrid.qml index 54af572a7b..2d70c0b95c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/HelperGrid.qml @@ -45,7 +45,7 @@ Node { materials: [ DefaultMaterial { id: mainGridMaterial - emissiveColor: "#e6e6e6" + emissiveColor: "#cccccc" lighting: DefaultMaterial.NoLighting cullingMode: Material.DisableCulling } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml index 8623b87a84..3d4183a9dc 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -25,6 +25,7 @@ import QtQuick 2.0 import QtQuick3D 1.0 +import QtGraphicalEffects 1.12 Node { id: iconGizmo @@ -34,8 +35,8 @@ Node { property Node targetNode: null property Node selectedNode: null - property alias gizmoModel: gizmoModel property alias iconSource: iconImage.source + property alias overlayColor: colorOverlay.color signal positionCommit() signal clicked(Node node) @@ -44,30 +45,25 @@ Node { rotation: targetNode ? targetNode.sceneRotation : Qt.vector3d(0, 0, 0) visible: targetNode ? targetNode.visible : false - Model { - id: gizmoModel - visible: iconGizmo.visible - } Overlay2D { - id: gizmoLabel - targetNode: gizmoModel + id: iconOverlay + targetNode: iconGizmo targetView: view3D - offsetX: 0 - offsetY: 0 visible: iconGizmo.visible && !isBehindCamera parent: view3D Rectangle { + id: iconRect width: iconImage.width height: iconImage.height x: -width / 2 - y: -height + y: -height / 2 color: "transparent" border.color: "#7777ff" - border.width: iconGizmo.selectedNode === iconGizmo.targetNode - || (iconGizmo.highlightOnHover && iconMouseArea.containsMouse) ? 2 : 0 + border.width: iconGizmo.selectedNode !== iconGizmo.targetNode + && iconGizmo.highlightOnHover && iconMouseArea.containsMouse ? 2 : 0 radius: 5 - opacity: iconGizmo.selectedNode === iconGizmo.targetNode ? 0.3 : 1 + opacity: iconGizmo.selectedNode === iconGizmo.targetNode ? 0.2 : 1 Image { id: iconImage fillMode: Image.Pad @@ -81,6 +77,15 @@ Node { ? Qt.LeftButton : Qt.NoButton } } + ColorOverlay { + id: colorOverlay + anchors.fill: parent + cached: true + source: iconImage + color: "transparent" + opacity: 0.6 + } + } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml index 888b2fce5c..6e321f8398 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml @@ -29,14 +29,13 @@ import QtQuick3D 1.0 IconGizmo { id: lightGizmo - iconSource: "qrc:///qtquickplugin/mockfiles/images/light-pick-icon.png" - gizmoModel.source: "#Sphere" - gizmoModel.scale: Qt.vector3d(0.10, 0.10, 0.10) - gizmoModel.materials: [ - DefaultMaterial { - id: defaultMaterial - emissiveColor: "yellow" - lighting: DefaultMaterial.NoLighting - } - ] + iconSource: targetNode + ? targetNode instanceof DirectionalLight + ? "qrc:///qtquickplugin/mockfiles/images/directional_light_gradient.png" + : targetNode instanceof AreaLight + ? "qrc:///qtquickplugin/mockfiles/images/area_light_gradient.png" + : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" + : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" + + overlayColor: targetNode ? targetNode.color : "transparent" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml index 1392c60cb2..f4a85226b7 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml @@ -31,8 +31,7 @@ Item { property Node targetNode property View3D targetView - property real offsetX: 0 - property real offsetY: 0 + property vector3d offset: Qt.vector3d(0, 0, 0) property bool isBehindCamera @@ -49,14 +48,16 @@ Item { } Connections { - target: designStudioNativeCameraControlHelper + target: _generalHelper onOverlayUpdateNeeded: updateOverlay() } function updateOverlay() { var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0); - var scenePosWithOffset = Qt.vector3d(scenePos.x + offsetX, scenePos.y + offsetY, scenePos.z); + var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x, + scenePos.y + offset.y, + scenePos.z + offset.z); var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset) : Qt.vector3d(0, 0, 0); root.x = viewPos.x; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml index 7bb1085e65..bd4fcd388b 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml @@ -34,7 +34,7 @@ Model { property alias color: gizmoMaterial.emissiveColor property alias priority: mouseArea.priority property Node targetNode: null - property bool dragging: false + property bool dragging: mouseArea.dragging property bool active: false readonly property bool hovering: mouseArea.hovering @@ -65,7 +65,6 @@ Model { _pointerPosPressed = mouseArea.mapPositionToScene(scenePos); var sp = targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); - dragging = true; pressed(mouseArea); } @@ -91,7 +90,6 @@ Model { return; released(mouseArea, calcRelativeDistance(mouseArea, scenePos)); - dragging = false; } MouseArea3D { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml index b2f42b39e2..b730e86910 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml @@ -134,8 +134,7 @@ Node { targetNode: rotateGizmo.targetNode color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1)) : Qt.rgba(0.5, 0.5, 0.5, 1) - // Just a smidge smaller than higher priority rings so that it doesn't obscure them - scale: Qt.vector3d(0.994, 0.994, 0.994) + scale: Qt.vector3d(1.1, 1.1, 1.1) priority: 10 view3D: rotateGizmo.view3D active: rotateGizmo.visible diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml index 634eb017c9..3d21f8fd6a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml @@ -33,7 +33,7 @@ Model { property View3D view3D property alias color: material.emissiveColor property Node targetNode: null - property bool dragging: false + property bool dragging: mouseAreaMain.dragging property bool active: false property alias hovering: mouseAreaMain.hovering property alias priority: mouseAreaMain.priority @@ -80,7 +80,6 @@ Model { _targetPosOnScreen = view3D.mapFrom3DScene(targetNode.scenePosition); _targetPosOnScreen.z = 0; _pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0); - dragging = true; _trackBall = angle < 0.1; // Recreate vector so we don't follow the changes in targetNode.rotation @@ -108,7 +107,6 @@ Model { applyLocalRotation(screenPos); rotateCommit(); - dragging = false; currentAngle = 0; currentMousePos = screenPos; } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml new file mode 100644 index 0000000000..995b4badd8 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 +import SelectionBoxGeometry 1.0 + +Node { + id: selectionBox + + property View3D view3D + property Node targetNode: null + property alias model: selectionBoxModel + + SelectionBoxGeometry { + id: selectionBoxGeometry + name: "Selection Box of 3D Edit View" + view3D: selectionBox.view3D + targetNode: selectionBox.targetNode + rootNode: selectionBox + } + + Model { + id: selectionBoxModel + geometry: selectionBoxGeometry + + scale: selectionBox.targetNode ? selectionBox.targetNode.scale : Qt.vector3d(1, 1, 1) + rotation: selectionBox.targetNode ? selectionBox.targetNode.rotation : Qt.vector3d(0, 0, 0) + position: selectionBox.targetNode ? selectionBox.targetNode.position : Qt.vector3d(0, 0, 0) + pivot: selectionBox.targetNode ? selectionBox.targetNode.pivot : Qt.vector3d(0, 0, 0) + orientation: selectionBox.targetNode ? selectionBox.targetNode.orientation : Node.LeftHanded + rotationOrder: selectionBox.targetNode ? selectionBox.targetNode.rotationOrder : Node.YXZ + + visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty + + materials: [ + DefaultMaterial { + emissiveColor: "#fff600" + lighting: DefaultMaterial.NoLighting + cullingMode: Material.DisableCulling + } + ] + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ToggleButton.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ToggleButton.qml new file mode 100644 index 0000000000..a0ebeabbd4 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ToggleButton.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick 2.0 +import QtQuick.Controls 2.0 + +Rectangle { + property bool toggled: false + property string tooltip + property bool toggleBackground: false // show a black background for the toggled state + property var states: [] // array of 2 state-objects, idx 0: untoggled, idx 1: toggled + + id: root + color: toggleBackground && toggled ? "#aa000000" : mouseArea.containsMouse ? "#44000000" : "#00000000" + width: img.width + txt.width + 5 + height: img.height + + Image { + id: img + anchors.verticalCenter: parent.verticalCenter + source: "qrc:///qtquickplugin/mockfiles/images/" + root.states[toggled ? 1 : 0].iconId + ".png" + } + + Text { + id: txt + color: "#b5b5b5" + anchors.verticalCenter: parent.verticalCenter + anchors.left: img.right + text: root.states[toggled ? 1 : 0].text + } + + ToolTip { + text: tooltip + visible: mouseArea.containsMouse + delay: 1000 + } + + MouseArea { + id: mouseArea + cursorShape: "PointingHandCursor" + hoverEnabled: true + anchors.fill: parent + onClicked: root.toggled = !root.toggled + } +} + + diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ToolBarButton.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ToolBarButton.qml index cbc450ed2b..38a8608e47 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/ToolBarButton.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ToolBarButton.qml @@ -34,6 +34,7 @@ Rectangle { property string currentShortcut property string tool property variant buttonsGroup: [] + property bool togglable: true id: root width: img.width + 5 @@ -71,6 +72,11 @@ Rectangle { root.buttonsGroup[i].selected = false; root.selected = true; + + if (!root.togglable) { + // Deselect button after a short while (selection acts as simple click indicator) + _generalHelper.delayedPropertySet(root, 200, "selected", false); + } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient.png Binary files differnew file mode 100644 index 0000000000..bd6404a36c --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient@2x.png Binary files differnew file mode 100644 index 0000000000..463f3ac481 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png Binary files differnew file mode 100644 index 0000000000..f3c013e157 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient@2x.png Binary files differnew file mode 100644 index 0000000000..87d60515f5 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png Binary files differnew file mode 100644 index 0000000000..73e6e92374 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off@2x.png Binary files differnew file mode 100644 index 0000000000..5166264e16 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png Binary files differnew file mode 100644 index 0000000000..7660c28546 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on@2x.png Binary files differnew file mode 100644 index 0000000000..836bd2a0d5 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png Binary files differnew file mode 100644 index 0000000000..056e9ec3c8 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png Binary files differnew file mode 100644 index 0000000000..4b05f83d46 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png Binary files differnew file mode 100644 index 0000000000..b8f98d9f12 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png Binary files differnew file mode 100644 index 0000000000..eac4361253 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png Binary files differnew file mode 100644 index 0000000000..1bd09c680a --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png Binary files differnew file mode 100644 index 0000000000..a2a857fb10 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png Binary files differnew file mode 100644 index 0000000000..0a608f6816 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png Binary files differnew file mode 100644 index 0000000000..a5c931e750 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png Binary files differnew file mode 100644 index 0000000000..35b36203fa --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png Binary files differnew file mode 100644 index 0000000000..443c73e444 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png Binary files differnew file mode 100644 index 0000000000..9a48e76399 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png Binary files differnew file mode 100644 index 0000000000..88a4eab9c6 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png Binary files differnew file mode 100644 index 0000000000..5136b39fc2 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient@2x.png Binary files differnew file mode 100644 index 0000000000..ccbfb1c846 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh Binary files differnew file mode 100644 index 0000000000..3e9e4958e4 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp deleted file mode 100644 index 1091e45911..0000000000 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ -#include "cameracontrolhelper.h" - -#include <QHash> - -namespace QmlDesigner { -namespace Internal { - -CameraControlHelper::CameraControlHelper() - : QObject() -{ - m_inputUpdateTimer.setInterval(16); - QObject::connect(&m_inputUpdateTimer, &QTimer::timeout, - this, &CameraControlHelper::handleUpdateTimer); - - m_overlayUpdateTimer.setInterval(16); - m_overlayUpdateTimer.setSingleShot(true); - QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout, - this, &CameraControlHelper::overlayUpdateNeeded); -} - -bool CameraControlHelper::enabled() -{ - return m_enabled; -} - -void CameraControlHelper::handleUpdateTimer() -{ - emit updateInputs(); -} - -void CameraControlHelper::setEnabled(bool enabled) -{ - if (enabled) - m_inputUpdateTimer.start(); - else - m_inputUpdateTimer.stop(); - m_enabled = enabled; -} - -void CameraControlHelper::requestOverlayUpdate() -{ - if (!m_overlayUpdateTimer.isActive()) - m_overlayUpdateTimer.start(); -} - -QString CameraControlHelper::generateUniqueName(const QString &nameRoot) -{ - static QHash<QString, int> counters; - int count = counters[nameRoot]++; - return QStringLiteral("%1_%2").arg(nameRoot).arg(count); -} - -} -} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri index e8f546e818..7b515e7a60 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri @@ -1,9 +1,11 @@ -HEADERS += $$PWD/cameracontrolhelper.h \ +HEADERS += $$PWD/generalhelper.h \ $$PWD/mousearea3d.h \ $$PWD/camerageometry.h \ - $$PWD/gridgeometry.h + $$PWD/gridgeometry.h \ + $$PWD/selectionboxgeometry.h -SOURCES += $$PWD/cameracontrolhelper.cpp \ +SOURCES += $$PWD/generalhelper.cpp \ $$PWD/mousearea3d.cpp \ $$PWD/camerageometry.cpp \ - $$PWD/gridgeometry.cpp + $$PWD/gridgeometry.cpp \ + $$PWD/selectionboxgeometry.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp new file mode 100644 index 0000000000..850a440a12 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "generalhelper.h" + +#ifdef QUICK3D_MODULE + +#include "selectionboxgeometry.h" + +#include <QtQuick3D/private/qquick3dorthographiccamera_p.h> +#include <QtQuick3D/private/qquick3dperspectivecamera_p.h> +#include <QtQuick3D/private/qquick3dobject_p_p.h> +#include <QtQuick3D/private/qquick3dcamera_p.h> +#include <QtQuick3D/private/qquick3dnode_p.h> +#include <QtQuick3D/private/qquick3dmodel_p.h> +#include <QtQuick3D/private/qquick3dviewport_p.h> +#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h> +#include <QtQuick3DUtils/private/qssgbounds3_p.h> +#include <QtQuick/qquickwindow.h> +#include <QtCore/qmath.h> + +namespace QmlDesigner { +namespace Internal { + +GeneralHelper::GeneralHelper() + : QObject() +{ + m_overlayUpdateTimer.setInterval(16); + m_overlayUpdateTimer.setSingleShot(true); + QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout, + this, &GeneralHelper::overlayUpdateNeeded); +} + +void GeneralHelper::requestOverlayUpdate() +{ + if (!m_overlayUpdateTimer.isActive()) + m_overlayUpdateTimer.start(); +} + +QString GeneralHelper::generateUniqueName(const QString &nameRoot) +{ + static QHash<QString, int> counters; + int count = counters[nameRoot]++; + return QStringLiteral("%1_%2").arg(nameRoot).arg(count); +} + +void GeneralHelper::orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation, + const QVector3D &lookAtPoint, const QVector3D &pressPos, + const QVector3D ¤tPos) +{ + QVector3D dragVector = currentPos - pressPos; + + if (dragVector.length() < 0.001f) + return; + + camera->setRotation(startRotation); + QVector3D newRotation(dragVector.y(), dragVector.x(), 0.f); + newRotation *= 0.5f; // Emprically determined multiplier for nice drag + newRotation += startRotation; + + camera->setRotation(newRotation); + + const QVector3D oldLookVector = camera->position() - lookAtPoint; + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]); + newLookVector.normalize(); + newLookVector *= oldLookVector.length(); + + camera->setPosition(lookAtPoint + newLookVector); +} + +// Pans camera and returns the new look-at point +QVector3D GeneralHelper::panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform, + const QVector3D &startPosition, const QVector3D &startLookAt, + const QVector3D &pressPos, const QVector3D ¤tPos, + float zoomFactor) +{ + QVector3D dragVector = currentPos - pressPos; + + if (dragVector.length() < 0.001f) + return startLookAt; + + const float *dataPtr(startTransform.data()); + const QVector3D xAxis = QVector3D(dataPtr[0], dataPtr[1], dataPtr[2]).normalized(); + const QVector3D yAxis = QVector3D(dataPtr[4], dataPtr[5], dataPtr[6]).normalized(); + const QVector3D xDelta = -1.f * xAxis * dragVector.x(); + const QVector3D yDelta = yAxis * dragVector.y(); + const QVector3D delta = (xDelta + yDelta) * zoomFactor; + + camera->setPosition(startPosition + delta); + return startLookAt + delta; +} + +float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float defaultLookAtDistance, + const QVector3D &lookAt, float zoomFactor, bool relative) +{ + // Emprically determined divisor for nice zoom + float multiplier = 1.f + (distance / 40.f); + float newZoomFactor = relative ? qBound(.0001f, zoomFactor * multiplier, 10000.f) + : zoomFactor; + + if (qobject_cast<QQuick3DOrthographicCamera *>(camera)) { + // Ortho camera we can simply scale + camera->setScale(QVector3D(newZoomFactor, newZoomFactor, newZoomFactor)); + } else if (qobject_cast<QQuick3DPerspectiveCamera *>(camera)) { + // Perspective camera is zoomed by moving camera forward or backward while keeping the + // look-at point the same + const QVector3D lookAtVec = (camera->position() - lookAt).normalized(); + const float newDistance = defaultLookAtDistance * newZoomFactor; + camera->setPosition(lookAt + (lookAtVec * newDistance)); + } + + return newZoomFactor; +} + +// Return value contains new lookAt point (xyz) and zoom factor (w) +QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + QQuick3DNode *targetObject, QQuick3DViewport *viewPort) +{ + if (!camera) + return QVector4D(0.f, 0.f, 0.f, 1.f); + + QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D(); + + // Get object bounds + qreal maxExtent = 200.; + if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) { + auto targetPriv = QQuick3DObjectPrivate::get(targetObject); + if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) { + QWindow *window = static_cast<QWindow *>(viewPort->window()); + if (window) { + auto context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); + if (!context.isNull()) { + QSSGBounds3 bounds; + auto geometry = qobject_cast<SelectionBoxGeometry *>(modelNode->geometry()); + if (geometry) { + bounds = geometry->bounds(); + } else { + auto bufferManager = context->bufferManager(); + bounds = renderModel->getModelBounds(bufferManager); + } + + QVector3D center = bounds.center(); + const QVector3D e = bounds.extents(); + const QVector3D s = targetObject->sceneScale(); + qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z())); + maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z())); + maxExtent *= maxScale; + + // Adjust lookAt to look directly at the center of the object bounds + lookAt = renderModel->globalTransform.map(center); + lookAt.setZ(-lookAt.z()); // Render node transforms have inverted z + } + } + } + } + + // Reset camera position to default zoom + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]); + newLookVector.normalize(); + newLookVector *= defaultLookAtDistance; + + camera->setPosition(lookAt + newLookVector); + + // Emprically determined algorithm for nice zoom + float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f); + + return QVector4D(lookAt, + zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false)); +} + +void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &property, + const QVariant &value) +{ + QTimer::singleShot(delay, [obj, property, value]() { + obj->setProperty(property.toLatin1().constData(), value); + }); +} + +} +} + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h new file mode 100644 index 0000000000..16007e6798 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#ifdef QUICK3D_MODULE + +#include <QtCore/qobject.h> +#include <QtCore/qtimer.h> +#include <QtCore/qhash.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qmatrix4x4.h> + +QT_BEGIN_NAMESPACE +class QQuick3DCamera; +class QQuick3DNode; +class QQuick3DViewport; +QT_END_NAMESPACE + +namespace QmlDesigner { +namespace Internal { + +class GeneralHelper : public QObject +{ + Q_OBJECT + +public: + GeneralHelper(); + + Q_INVOKABLE void requestOverlayUpdate(); + Q_INVOKABLE QString generateUniqueName(const QString &nameRoot); + + Q_INVOKABLE void orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation, + const QVector3D &lookAtPoint, const QVector3D &pressPos, + const QVector3D ¤tPos); + Q_INVOKABLE QVector3D panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform, + const QVector3D &startPosition, const QVector3D &startLookAt, + const QVector3D &pressPos, const QVector3D ¤tPos, + float zoomFactor); + Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance, + float defaultLookAtDistance, const QVector3D &lookAt, + float zoomFactor, bool relative); + Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + QQuick3DNode *targetObject, QQuick3DViewport *viewPort); + Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, + const QVariant& value); + +signals: + void overlayUpdateNeeded(); + +private: + QTimer m_overlayUpdateTimer; +}; + +} +} + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp index 31ed661125..d571b24dcb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -37,7 +37,6 @@ namespace QmlDesigner { namespace Internal { MouseArea3D *MouseArea3D::s_mouseGrab = nullptr; -static const qreal s_mouseDragMultiplier = .02; MouseArea3D::MouseArea3D(QQuick3DNode *parent) : QQuick3DNode(parent) @@ -124,6 +123,13 @@ void MouseArea3D::setGrabsMouse(bool grabsMouse) return; m_grabsMouse = grabsMouse; + + if (!m_grabsMouse && s_mouseGrab == this) { + setDragging(false); + setHovering(false); + s_mouseGrab = nullptr; + } + emit grabsMouseChanged(); } @@ -133,6 +139,13 @@ void MouseArea3D::setActive(bool active) return; m_active = active; + + if (!m_active && s_mouseGrab == this) { + setDragging(false); + setHovering(false); + s_mouseGrab = nullptr; + } + emit activeChanged(); } @@ -340,7 +353,7 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle( dragDir = (screenDragDir - nodePos).normalized(); const QVector3D pressToCurrent = (currentPos - pressPos); float magnitude = QVector3D::dotProduct(pressToCurrent, dragDir); - qreal angle = -s_mouseDragMultiplier * qreal(magnitude); + qreal angle = -mouseDragMultiplier() * qreal(magnitude); return angle; } else { const QVector3D nodeToPress = (pressPos - nodePos).normalized(); @@ -397,7 +410,7 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis); - qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * s_mouseDragMultiplier); + qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * mouseDragMultiplier()); finalAxis.normalize(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h index e227b3f9dd..c824b92969 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h @@ -51,7 +51,7 @@ class MouseArea3D : public QQuick3DNode Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged) Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged) - Q_PROPERTY(int active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QPointF circlePickArea READ circlePickArea WRITE setCirclePickArea NOTIFY circlePickAreaChanged) Q_PROPERTY(qreal minAngle READ minAngle WRITE setMinAngle NOTIFY minAngleChanged) Q_PROPERTY(QQuick3DNode *pickNode READ pickNode WRITE setPickNode NOTIFY pickNodeChanged) @@ -77,6 +77,8 @@ public: qreal minAngle() const; QQuick3DNode *pickNode() const; + static qreal mouseDragMultiplier() { return .02; } + public slots: void setView3D(QQuick3DViewport *view3D); void setGrabsMouse(bool grabsMouse); @@ -157,7 +159,7 @@ private: QVector3D getMousePosInPlane(const QPointF &mousePosInView) const; static MouseArea3D *s_mouseGrab; - bool m_grabsMouse; + bool m_grabsMouse = false; QVector3D m_mousePosInPlane; QPointF m_circlePickArea; qreal m_minAngle = 0.; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp new file mode 100644 index 0000000000..7770061923 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp @@ -0,0 +1,336 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifdef QUICK3D_MODULE + +#include "selectionboxgeometry.h" + +#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h> +#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h> +#include <QtQuick3D/private/qquick3dmodel_p.h> +#include <QtQuick3D/private/qquick3dobject_p_p.h> +#include <QtQuick/qquickwindow.h> +#include <QtCore/qvector.h> + +#include <limits> + +namespace QmlDesigner { +namespace Internal { + +SelectionBoxGeometry::SelectionBoxGeometry() + : QQuick3DGeometry() +{ +} + +SelectionBoxGeometry::~SelectionBoxGeometry() +{ + for (auto &connection : qAsConst(m_connections)) + QObject::disconnect(connection); + m_connections.clear(); +} + +QQuick3DNode *SelectionBoxGeometry::targetNode() const +{ + return m_targetNode; +} + +QQuick3DNode *SelectionBoxGeometry::rootNode() const +{ + return m_rootNode; +} + +QQuick3DViewport *SelectionBoxGeometry::view3D() const +{ + return m_view3D; +} + +bool QmlDesigner::Internal::SelectionBoxGeometry::isEmpty() const +{ + return m_isEmpty; +} + +QSSGBounds3 SelectionBoxGeometry::bounds() const +{ + return m_bounds; +} + +void SelectionBoxGeometry::setTargetNode(QQuick3DNode *targetNode) +{ + if (m_targetNode == targetNode) + return; + + if (m_targetNode) + m_targetNode->disconnect(this); + m_targetNode = targetNode; + + if (auto model = qobject_cast<QQuick3DModel *>(m_targetNode)) { + QObject::connect(model, &QQuick3DModel::sourceChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + QObject::connect(model, &QQuick3DModel::geometryChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + } + + emit targetNodeChanged(); + update(); +} + +void SelectionBoxGeometry::setRootNode(QQuick3DNode *rootNode) +{ + if (m_rootNode == rootNode) + return; + + m_rootNode = rootNode; + + emit rootNodeChanged(); + update(); +} + +void SelectionBoxGeometry::setView3D(QQuick3DViewport *view) +{ + if (m_view3D == view) + return; + + m_view3D = view; + + emit view3DChanged(); + update(); +} + +QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphObject *node) +{ + node = QQuick3DGeometry::updateSpatialNode(node); + QSSGRenderGeometry *geometry = static_cast<QSSGRenderGeometry *>(node); + + geometry->clear(); + for (auto &connection : qAsConst(m_connections)) + QObject::disconnect(connection); + m_connections.clear(); + + QByteArray vertexData; + QByteArray indexData; + + static const float floatMin = std::numeric_limits<float>::lowest(); + static const float floatMax = std::numeric_limits<float>::max(); + + QVector3D minBounds = QVector3D(floatMax, floatMax, floatMax); + QVector3D maxBounds = QVector3D(floatMin, floatMin, floatMin); + + if (m_targetNode) { + auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode); + auto targetPriv = QQuick3DObjectPrivate::get(m_targetNode); + auto rootRN = static_cast<QSSGRenderNode *>(rootPriv->spatialNode); + auto targetRN = static_cast<QSSGRenderNode *>(targetPriv->spatialNode); + if (rootRN && targetRN) { + // Explicitly set local transform of root node to target node parent's global transform + // to avoid having to reparent the selection box. This has to be done directly on render + // nodes. + targetRN->parent->calculateGlobalVariables(); + QMatrix4x4 m = targetRN->parent->globalTransform; + rootRN->localTransform = m; + rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty); + rootRN->calculateGlobalVariables(); + } + getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds, QMatrix4x4()); + } else { + // Fill some dummy data so geometry won't get rejected + appendVertexData(vertexData, indexData, minBounds, maxBounds); + } + + geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0, + QSSGRenderGeometry::Attribute::ComponentType::F32Type); + geometry->addAttribute(QSSGRenderGeometry::Attribute::IndexSemantic, 0, + QSSGRenderGeometry::Attribute::ComponentType::U16Type); + geometry->setStride(12); + geometry->setVertexData(vertexData); + geometry->setIndexData(indexData); + geometry->setPrimitiveType(QSSGRenderGeometry::Lines); + geometry->setBounds(minBounds, maxBounds); + + m_bounds = QSSGBounds3(minBounds, maxBounds); + + bool empty = minBounds.isNull() && maxBounds.isNull(); + if (m_isEmpty != empty) { + m_isEmpty = empty; + // Delay notification until we're done with spatial node updates + QTimer::singleShot(0, this, &SelectionBoxGeometry::isEmptyChanged); + } + + return node; +} + +void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData, + QByteArray &indexData, QVector3D &minBounds, + QVector3D &maxBounds, const QMatrix4x4 &transform) +{ + QMatrix4x4 fullTransform; + auto nodePriv = QQuick3DObjectPrivate::get(node); + auto renderNode = static_cast<QSSGRenderNode *>(nodePriv->spatialNode); + + // All transforms are relative to targetNode transform, so its local transform is ignored + if (node != m_targetNode) { + if (renderNode) { + if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) + renderNode->calculateLocalTransform(); + fullTransform = transform * renderNode->localTransform; + } + + m_connections << QObject::connect(node, &QQuick3DNode::scaleChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + m_connections << QObject::connect(node, &QQuick3DNode::rotationChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + m_connections << QObject::connect(node, &QQuick3DNode::positionChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + m_connections << QObject::connect(node, &QQuick3DNode::pivotChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + m_connections << QObject::connect(node, &QQuick3DNode::orientationChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + m_connections << QObject::connect(node, &QQuick3DNode::rotationOrderChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + } + + QVector<QVector3D> minBoundsVec; + QVector<QVector3D> maxBoundsVec; + + // Check for children + const auto children = node->childItems(); + for (const auto child : children) { + if (auto childNode = qobject_cast<QQuick3DNode *>(child)) { + QVector3D newMinBounds = minBounds; + QVector3D newMaxBounds = maxBounds; + getBounds(childNode, vertexData, indexData, newMinBounds, newMaxBounds, fullTransform); + minBoundsVec << newMinBounds; + maxBoundsVec << newMaxBounds; + } + } + + // Combine all child bounds + for (const auto &newBounds : qAsConst(minBoundsVec)) { + minBounds.setX(qMin(newBounds.x(), minBounds.x())); + minBounds.setY(qMin(newBounds.y(), minBounds.y())); + minBounds.setZ(qMin(newBounds.z(), minBounds.z())); + } + for (const auto &newBounds : qAsConst(maxBoundsVec)) { + maxBounds.setX(qMax(newBounds.x(), maxBounds.x())); + maxBounds.setY(qMax(newBounds.y(), maxBounds.y())); + maxBounds.setZ(qMax(newBounds.z(), maxBounds.z())); + } + + if (auto modelNode = qobject_cast<QQuick3DModel *>(node)) { + if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) { + QWindow *window = static_cast<QWindow *>(m_view3D->window()); + if (window) { + auto context = QSSGRenderContextInterface::getRenderContextInterface( + quintptr(window)); + if (!context.isNull()) { + auto bufferManager = context->bufferManager(); + QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager); + QVector3D center = bounds.center(); + QVector3D extents = bounds.extents(); + QVector3D localMin = center - extents; + QVector3D localMax = center + extents; + + // Transform all corners of the local bounding box to find final extent in + // in parent space + + auto checkCorner = [&minBounds, &maxBounds, &fullTransform] + (const QVector3D &corner) { + QVector3D mappedCorner = fullTransform.map(corner); + minBounds.setX(qMin(mappedCorner.x(), minBounds.x())); + minBounds.setY(qMin(mappedCorner.y(), minBounds.y())); + minBounds.setZ(qMin(mappedCorner.z(), minBounds.z())); + maxBounds.setX(qMax(mappedCorner.x(), maxBounds.x())); + maxBounds.setY(qMax(mappedCorner.y(), maxBounds.y())); + maxBounds.setZ(qMax(mappedCorner.z(), maxBounds.z())); + }; + + checkCorner(localMin); + checkCorner(localMax); + checkCorner(QVector3D(localMin.x(), localMin.y(), localMax.z())); + checkCorner(QVector3D(localMin.x(), localMax.y(), localMin.z())); + checkCorner(QVector3D(localMax.x(), localMin.y(), localMin.z())); + checkCorner(QVector3D(localMin.x(), localMax.y(), localMax.z())); + checkCorner(QVector3D(localMax.x(), localMax.y(), localMin.z())); + checkCorner(QVector3D(localMax.x(), localMin.y(), localMax.z())); + } + } + } + } + + // Target node and immediate children get selection boxes + if (transform.isIdentity()) { + // Adjust bounds to reduce targetNode pixels obscuring the selection box + QVector3D extents = (maxBounds - minBounds) / 1000.f; + QVector3D minAdjBounds = minBounds - extents; + QVector3D maxAdjBounds = maxBounds + extents; + + appendVertexData(vertexData, indexData, minAdjBounds, maxAdjBounds); + } +} + +void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &indexData, + const QVector3D &minBounds, const QVector3D &maxBounds) +{ + int initialVertexSize = vertexData.size(); + int initialIndexSize = indexData.size(); + const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert + quint16 indexAdd = quint16(initialVertexSize / 12); + vertexData.resize(initialVertexSize + vertexSize); + const int indexSize = int(sizeof(quint16)) * 12 * 2; // 12 lines, 2 vert/line + indexData.resize(initialIndexSize + indexSize); + + auto dataPtr = reinterpret_cast<float *>(vertexData.data() + initialVertexSize); + auto indexPtr = reinterpret_cast<quint16 *>(indexData.data() + initialIndexSize); + + *dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z(); + + *indexPtr++ = 0 + indexAdd; *indexPtr++ = 1 + indexAdd; + *indexPtr++ = 1 + indexAdd; *indexPtr++ = 2 + indexAdd; + *indexPtr++ = 2 + indexAdd; *indexPtr++ = 3 + indexAdd; + *indexPtr++ = 3 + indexAdd; *indexPtr++ = 0 + indexAdd; + + *indexPtr++ = 0 + indexAdd; *indexPtr++ = 4 + indexAdd; + *indexPtr++ = 1 + indexAdd; *indexPtr++ = 5 + indexAdd; + *indexPtr++ = 2 + indexAdd; *indexPtr++ = 6 + indexAdd; + *indexPtr++ = 3 + indexAdd; *indexPtr++ = 7 + indexAdd; + + *indexPtr++ = 4 + indexAdd; *indexPtr++ = 5 + indexAdd; + *indexPtr++ = 5 + indexAdd; *indexPtr++ = 6 + indexAdd; + *indexPtr++ = 6 + indexAdd; *indexPtr++ = 7 + indexAdd; + *indexPtr++ = 7 + indexAdd; *indexPtr++ = 4 + indexAdd; +} + +} +} + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h new file mode 100644 index 0000000000..08a28cec06 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#ifdef QUICK3D_MODULE + +#include <QtQuick3D/private/qquick3dnode_p.h> +#include <QtQuick3D/private/qquick3dgeometry_p.h> +#include <QtQuick3D/private/qquick3dviewport_p.h> +#include <QtQuick3DUtils/private/qssgbounds3_p.h> + +namespace QmlDesigner { +namespace Internal { + +class SelectionBoxGeometry : public QQuick3DGeometry +{ + Q_OBJECT + Q_PROPERTY(QQuick3DNode *targetNode READ targetNode WRITE setTargetNode NOTIFY targetNodeChanged) + Q_PROPERTY(QQuick3DNode *rootNode READ rootNode WRITE setRootNode NOTIFY rootNodeChanged) + Q_PROPERTY(QQuick3DViewport *view3D READ view3D WRITE setView3D NOTIFY view3DChanged) + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) + +public: + SelectionBoxGeometry(); + ~SelectionBoxGeometry() override; + + QQuick3DNode *targetNode() const; + QQuick3DNode *rootNode() const; + QQuick3DViewport *view3D() const; + bool isEmpty() const; + + QSSGBounds3 bounds() const; + +public Q_SLOTS: + void setTargetNode(QQuick3DNode *targetNode); + void setRootNode(QQuick3DNode *rootNode); + void setView3D(QQuick3DViewport *view); + +Q_SIGNALS: + void targetNodeChanged(); + void rootNodeChanged(); + void view3DChanged(); + void isEmptyChanged(); + +protected: + QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override; + +private: + void getBounds(QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData, + QVector3D &minBounds, QVector3D &maxBounds, const QMatrix4x4 &transform); + void appendVertexData(QByteArray &vertexData, QByteArray &indexData, + const QVector3D &minBounds, const QVector3D &maxBounds); + + QQuick3DNode *m_targetNode = nullptr; + QQuick3DViewport *m_view3D = nullptr; + QQuick3DNode *m_rootNode = nullptr; + bool m_isEmpty = true; + QVector<QMetaObject::Connection> m_connections; + QSSGBounds3 m_bounds; +}; + +} +} + +QML_DECLARE_TYPE(QmlDesigner::Internal::SelectionBoxGeometry) + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 2cd59af460..95360eaa4f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -62,10 +62,11 @@ #include <drop3dlibraryitemcommand.h> #include "dummycontextobject.h" -#include "../editor3d/cameracontrolhelper.h" +#include "../editor3d/generalhelper.h" #include "../editor3d/mousearea3d.h" #include "../editor3d/camerageometry.h" #include "../editor3d/gridgeometry.h" +#include "../editor3d/selectionboxgeometry.h" #include <designersupportdelegate.h> @@ -104,13 +105,13 @@ bool Qt5InformationNodeInstanceServer::eventFilter(QObject *, QEvent *event) QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) { - auto helper = new QmlDesigner::Internal::CameraControlHelper(); - engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper); - #ifdef QUICK3D_MODULE + auto helper = new QmlDesigner::Internal::GeneralHelper(); + engine->rootContext()->setContextProperty("_generalHelper", helper); qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D"); qmlRegisterType<QmlDesigner::Internal::CameraGeometry>("CameraGeometry", 1, 0, "CameraGeometry"); qmlRegisterType<QmlDesigner::Internal::GridGeometry>("GridGeometry", 1, 0, "GridGeometry"); + qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry"); #endif QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); @@ -136,7 +137,10 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) surfaceFormat.setVersion(4, 1); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); window->setFormat(surfaceFormat); + +#ifdef QUICK3D_MODULE helper->setParent(window); +#endif return window; } @@ -336,12 +340,24 @@ QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( { for (const ServerNodeInstance &instance : instanceList) { if (instance.isSubclassOf("QQuick3DViewport")) { + QObject *rootObj = nullptr; + int viewChildCount = 0; for (const ServerNodeInstance &child : instanceList) { /* Look for scene node */ /* The QQuick3DViewport always creates a root node. * This root node contains the complete scene. */ - if (child.isSubclassOf("QQuick3DNode") && child.parent() == instance) - return child.internalObject()->property("parent").value<QObject *>(); + if (child.isSubclassOf("QQuick3DNode") && child.parent() == instance) { + // Implicit root node is not visible in editor, so there is often another node + // added below it that serves as the actual scene root node. + // If the found root is the only node child of the view, assume that is the case. + ++viewChildCount; + if (!rootObj) + rootObj = child.internalObject(); + } } + if (viewChildCount == 1) + return rootObj; + else if (rootObj) + return rootObj->property("parent").value<QObject *>(); } } return nullptr; @@ -599,10 +615,8 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm if (hasInstanceForId(id)) { ServerNodeInstance instance = instanceForId(id); QObject *object = nullptr; - if (instance.isSubclassOf("QQuick3DModel") || instance.isSubclassOf("QQuick3DCamera") - || instance.isSubclassOf("QQuick3DAbstractLight")) { + if (instance.isSubclassOf("QQuick3DNode")) object = instance.internalObject(); - } QMetaObject::invokeMethod(m_editView3D, "selectObject", Q_ARG(QVariant, objectToVariant(object))); return; // TODO: support multi-selection diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 61b21b7810..db0f0f847f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -56,17 +56,7 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo InstanceContainer::NodeFlags flags) { ObjectNodeInstance::initialize(objectNodeInstance, flags); - -#ifdef QUICK3D_MODULE - if (quick3DNode()) { - QQuick3DObject::Type nodeType = quick3DNode()->type(); - if (nodeType == QQuick3DObject::Camera || nodeType == QQuick3DObject::Light - || nodeType == QQuick3DObject::Model || nodeType == QQuick3DObject::Image - || nodeType == QQuick3DObject::Text) { - setPropertyVariant("pickable", true); // allow 3D objects to receive mouse clicks - } - } -#endif + setPickable(true, true, false); } Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const @@ -83,6 +73,48 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const #endif } +void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildren) +{ +#ifdef QUICK3D_MODULE + auto node = quick3DNode(); + if (node) { + QQuick3DObject::Type nodeType = node->type(); + bool parentHidden = false; + if (checkParent) { + // First check if any parent node is already hidden. Never set pickable on that case. + auto parentNode = node->parentNode(); + while (parentNode && !parentHidden) { + parentHidden = QQuick3DNodePrivate::get(parentNode)->m_isHiddenInEditor; + parentNode = parentNode->parentNode(); + } + + } + if (!parentHidden) { + if (applyToChildren) { + auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * { + if (nodeInstanceServer()->hasInstanceForObject(obj)) { + ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj); + if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject())) + return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data()); + } + return nullptr; + }; + const auto childItems = node->childItems(); + for (auto childItem : childItems) { + if (auto quick3dInstance = getQuick3DInstance(childItem)) { + // Don't override explicit block in children + if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor) + quick3dInstance->setPickable(enable, false, true); + } + } + } + if (nodeType == QQuick3DObject::Model) + setPropertyVariant("pickable", enable); // allow 3D objects to receive mouse clicks + } + } +#endif +} + Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object) { Pointer instance(new Quick3DNodeInstance(object)); @@ -94,8 +126,12 @@ void Quick3DNodeInstance::setHideInEditor(bool b) { #ifdef QUICK3D_MODULE QQuick3DNodePrivate *privateNode = QQuick3DNodePrivate::get(quick3DNode()); - if (privateNode) + if (privateNode) { privateNode->setIsHiddenInEditor(b); + + // Hidden objects should not be pickable + setPickable(!b, true, true); + } #else Q_UNUSED(b) #endif diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 96c44c4d52..27e2488eb3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -53,6 +53,7 @@ protected: private: Qt5NodeInstanceServer *qt5NodeInstanceServer() const; QQuick3DNode *quick3DNode() const; + void setPickable(bool enable, bool checkParent, bool applyToChildren); }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 86003b51b6..c85ba9a2b8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -60,6 +60,7 @@ namespace Internal { class GraphicsObjectNodeInstance; class QmlStateNodeInstance; class QuickItemNodeInstance; + class Quick3DNodeInstance; } class ServerNodeInstance @@ -82,6 +83,7 @@ class ServerNodeInstance friend class QmlDesigner::Internal::ObjectNodeInstance; friend class QmlDesigner::Internal::QmlPropertyChangesNodeInstance; friend class QmlDesigner::Internal::QmlStateNodeInstance; + friend class QmlDesigner::Internal::Quick3DNodeInstance; public: enum ComponentWrap { diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index f818f23fd5..c4a49064b6 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -8,6 +8,7 @@ <file>mockfiles/GenericBackend.qml</file> <file>mockfiles/Dialog.qml</file> <file>mockfiles/EditView3D.qml</file> + <file>mockfiles/EditCameraController.qml</file> <file>mockfiles/Arrow.qml</file> <file>mockfiles/AutoScaleHelper.qml</file> <file>mockfiles/MoveGizmo.qml</file> @@ -23,12 +24,17 @@ <file>mockfiles/ScaleRod.qml</file> <file>mockfiles/ScaleGizmo.qml</file> <file>mockfiles/ToolBarButton.qml</file> + <file>mockfiles/ToggleButton.qml</file> <file>mockfiles/RotateGizmo.qml</file> <file>mockfiles/RotateRing.qml</file> + <file>mockfiles/SelectionBox.qml</file> + <file>mockfiles/AxisHelper.qml</file> + <file>mockfiles/AxisHelperArm.qml</file> <file>mockfiles/meshes/arrow.mesh</file> <file>mockfiles/meshes/scalerod.mesh</file> <file>mockfiles/meshes/ring.mesh</file> <file>mockfiles/meshes/ringselect.mesh</file> + <file>mockfiles/meshes/axishelper.mesh</file> <file>mockfiles/images/editor_camera.png</file> <file>mockfiles/images/editor_camera@2x.png</file> <file>mockfiles/images/light-pick-icon.png</file> @@ -53,5 +59,27 @@ <file>mockfiles/images/scale_active@2x.png</file> <file>mockfiles/images/scale_selected.png</file> <file>mockfiles/images/scale_selected@2x.png</file> + <file>mockfiles/images/directional_light_gradient.png</file> + <file>mockfiles/images/directional_light_gradient@2x.png</file> + <file>mockfiles/images/point_light_gradient.png</file> + <file>mockfiles/images/point_light_gradient@2x.png</file> + <file>mockfiles/images/area_light_gradient.png</file> + <file>mockfiles/images/area_light_gradient@2x.png</file> + <file>mockfiles/images/fit_active.png</file> + <file>mockfiles/images/fit_active@2x.png</file> + <file>mockfiles/images/fit_selected.png</file> + <file>mockfiles/images/fit_selected@2x.png</file> + <file>mockfiles/images/local.png</file> + <file>mockfiles/images/local@2x.png</file> + <file>mockfiles/images/global.png</file> + <file>mockfiles/images/global@2x.png</file> + <file>mockfiles/images/ortho.png</file> + <file>mockfiles/images/ortho@2x.png</file> + <file>mockfiles/images/persp.png</file> + <file>mockfiles/images/persp@2x.png</file> + <file>mockfiles/images/edit_light_off.png</file> + <file>mockfiles/images/edit_light_off@2x.png</file> + <file>mockfiles/images/edit_light_on.png</file> + <file>mockfiles/images/edit_light_on@2x.png</file> </qresource> </RCC> diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml index 6cbc8a77c0..a97923a032 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml @@ -41,7 +41,6 @@ Section { function getBackendValue(name) { - print(fontSection.fontName + "_" + name) return backendValues[fontSection.fontName + "_" + name] } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index f8865e62cf..1c3dc46c15 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -185,7 +185,9 @@ T.ComboBox { StudioTheme.Values.maxComboBoxPopupHeight) padding: StudioTheme.Values.border margins: 0 // If not defined margin will be -1 - closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent + closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent + | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside + | T.Popup.CloseOnReleaseOutsideParent contentItem: ListView { clip: true @@ -242,7 +244,7 @@ T.ComboBox { }, State { name: "edit" - when: myComboBox.edit && myComboBox.editable + when: myComboBox.edit && myComboBox.editable && !comboBoxPopup.opened PropertyChanges { target: myComboBox wheelEnabled: true @@ -250,12 +252,29 @@ T.ComboBox { PropertyChanges { target: comboBoxInput selectByMouse: true + readOnly: false } PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeInteraction border.color: StudioTheme.Values.themeInteraction } + StateChangeScript { + script: comboBoxPopup.close() + } + }, + State { + name: "popup" + when: myComboBox.edit && comboBoxPopup.opened + PropertyChanges { + target: myComboBox + wheelEnabled: true + } + PropertyChanges { + target: comboBoxInput + selectByMouse: false + readOnly: true + } } ] diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml index 01a86847fc..773282958f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml @@ -1,3 +1,5 @@ + + /**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. @@ -22,7 +24,6 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ - import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Templates 2.12 as T @@ -43,10 +44,11 @@ T.Menu { overlap: 1 padding: 0 - closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnEscape + closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent + | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside + | T.Popup.CloseOnReleaseOutsideParent - delegate: MenuItem { - } + delegate: MenuItem {} contentItem: ListView { model: control.contentModel diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml index fe83e82ee6..dd6be8cbc1 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml @@ -33,7 +33,9 @@ T.Popup { property T.Control myControl dim: false - closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent + closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent + | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside + | T.Popup.CloseOnReleaseOutsideParent background: Rectangle { color: StudioTheme.Values.themeControlBackground diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml index 72a713c282..98c592f112 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml @@ -193,6 +193,7 @@ TextInput { PropertyChanges { target: mouseArea cursorShape: Qt.PointingHandCursor + enabled: false } }, State { diff --git a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp index 25d22bb1c1..8556c84b4b 100644 --- a/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp +++ b/src/plugins/clangcodemodel/test/clangbatchfileprocessor.cpp @@ -237,7 +237,7 @@ bool OpenProjectCommand::run() Project *project = openProjectSucceeded.project(); project->configureAsExampleProject(); - return CppTools::Tests::TestCase::waitUntilCppModelManagerIsAwareOf(project, timeOutInMs()); + return CppTools::Tests::TestCase::waitUntilProjectIsFullyOpened(project, timeOutInMs()); } Command::Ptr OpenProjectCommand::parse(BatchFileLineTokenizer &arguments, diff --git a/src/plugins/clangtools/clangtidyclazyrunner.cpp b/src/plugins/clangtools/clangtidyclazyrunner.cpp index bd909384d0..34a149c823 100644 --- a/src/plugins/clangtools/clangtidyclazyrunner.cpp +++ b/src/plugins/clangtools/clangtidyclazyrunner.cpp @@ -66,10 +66,6 @@ static QStringList clazyPluginArguments(const ClangDiagnosticConfig diagnosticCo arguments << XclangArgs({"-add-plugin", "clazy", "-plugin-arg-clazy", - "enable-all-fixits", - "-plugin-arg-clazy", - "no-autowrite-fixits", - "-plugin-arg-clazy", diagnosticConfig.clazyChecks()}); } diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 607b78680c..780a38c4ff 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -33,6 +33,7 @@ #include "clangtoolsdiagnosticmodel.h" #include "clangtoolsdiagnosticview.h" #include "clangtoolslogfilereader.h" +#include "clangtoolsplugin.h" #include "clangtoolsprojectsettings.h" #include "clangtoolssettings.h" #include "clangtoolsutils.h" @@ -399,6 +400,15 @@ ClangTool::ClangTool() ApplyFixIts(diagnosticItems).apply(m_diagnosticModel); }); + // Open Project Settings + action = new QAction(this); + action->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon()); + //action->setToolTip(tr("Open Project Settings")); // TODO: Uncomment in master. + connect(action, &QAction::triggered, []() { + ProjectExplorerPlugin::activateProjectPanel(Constants::PROJECT_PANEL_ID); + }); + m_openProjectSettings = action; + ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); const QString toolTip = tr("Clang-Tidy and Clazy use a customized Clang executable from the " "Clang project to search for diagnostics."); @@ -424,6 +434,7 @@ ClangTool::ClangTool() m_perspective.addToolBarAction(m_startAction); m_perspective.addToolBarAction(m_startOnCurrentFileAction); m_perspective.addToolBarAction(m_stopAction); + m_perspective.addToolBarAction(m_openProjectSettings); m_perspective.addToolBarAction(m_loadExported); m_perspective.addToolBarAction(m_clear); m_perspective.addToolBarAction(m_goBack); diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h index bde31d355d..d994a6b2f9 100644 --- a/src/plugins/clangtools/clangtool.h +++ b/src/plugins/clangtools/clangtool.h @@ -129,6 +129,7 @@ private: Utils::FancyLineEdit *m_filterLineEdit = nullptr; QToolButton *m_applyFixitsButton = nullptr; + QAction *m_openProjectSettings = nullptr; QAction *m_goBack = nullptr; QAction *m_goNext = nullptr; QAction *m_loadExported = nullptr; diff --git a/src/plugins/clangtools/clangtoolsconstants.h b/src/plugins/clangtools/clangtoolsconstants.h index a3da1d78f5..8f09865b1c 100644 --- a/src/plugins/clangtools/clangtoolsconstants.h +++ b/src/plugins/clangtools/clangtoolsconstants.h @@ -28,6 +28,8 @@ namespace ClangTools { namespace Constants { +const char PROJECT_PANEL_ID[] = "ClangTools"; + const char RUN_ON_PROJECT[] = "ClangTools.RunOnProject"; const char RUN_ON_CURRENT_FILE[] = "ClangTools.RunOnCurrentFile"; diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp index 1fe490a6bf..8c4211544b 100644 --- a/src/plugins/clangtools/clangtoolslogfilereader.cpp +++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp @@ -347,7 +347,7 @@ public: int extraOffset = 0) : m_node(node) , m_fileCache(fileCache) - , m_filePath(asString(node["FilePath"])) + , m_filePath(QDir::cleanPath(asString(node["FilePath"]))) , m_fileOffsetKey(fileOffsetKey) , m_extraOffset(extraOffset) {} diff --git a/src/plugins/clangtools/clangtoolsplugin.cpp b/src/plugins/clangtools/clangtoolsplugin.cpp index cdcda4d3c6..b53901e95a 100644 --- a/src/plugins/clangtools/clangtoolsplugin.cpp +++ b/src/plugins/clangtools/clangtoolsplugin.cpp @@ -67,6 +67,13 @@ using namespace ProjectExplorer; namespace ClangTools { namespace Internal { +static ProjectPanelFactory *m_projectPanelFactoryInstance = nullptr; + +ProjectPanelFactory *projectPanelFactory() +{ + return m_projectPanelFactoryInstance; +} + class ClangToolsOptionsPage : public IOptionsPage { public: @@ -123,8 +130,9 @@ bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorSt ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(), Constants::RUN_ON_CURRENT_FILE); - auto panelFactory = new ProjectPanelFactory(); + auto panelFactory = m_projectPanelFactoryInstance = new ProjectPanelFactory; panelFactory->setPriority(100); + panelFactory->setId(Constants::PROJECT_PANEL_ID); panelFactory->setDisplayName(tr("Clang Tools")); panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); }); ProjectPanelFactory::registerFactory(panelFactory); diff --git a/src/plugins/clangtools/clangtoolsplugin.h b/src/plugins/clangtools/clangtoolsplugin.h index 7f24d79f4b..30c28b276b 100644 --- a/src/plugins/clangtools/clangtoolsplugin.h +++ b/src/plugins/clangtools/clangtoolsplugin.h @@ -27,9 +27,13 @@ #include <extensionsystem/iplugin.h> +namespace ProjectExplorer { class ProjectPanelFactory; } + namespace ClangTools { namespace Internal { +ProjectExplorer::ProjectPanelFactory *projectPanelFactory(); + class ClangToolsPlugin : public ExtensionSystem::IPlugin { Q_OBJECT diff --git a/src/plugins/clangtools/clangtoolssettings.h b/src/plugins/clangtools/clangtoolssettings.h index 36da00d293..aaa52011b1 100644 --- a/src/plugins/clangtools/clangtoolssettings.h +++ b/src/plugins/clangtools/clangtoolssettings.h @@ -34,7 +34,7 @@ namespace ClangTools { namespace Internal { -const char diagnosticConfigIdKey[] = "DiagnosticConfigId"; +const char diagnosticConfigIdKey[] = "DiagnosticConfig"; class RunSettings { diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 63dfdac4c6..26e4bffdeb 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -318,7 +318,7 @@ class CMakeGeneratorKitAspectWidget : public KitAspectWidget public: CMakeGeneratorKitAspectWidget(Kit *kit, const ::KitAspect *ki) : KitAspectWidget(kit, ki), - m_label(new QLabel), + m_label(new Utils::ElidingLabel), m_changeButton(new QPushButton) { m_label->setToolTip(ki->description()); @@ -459,7 +459,7 @@ private: } bool m_ignoreChange = false; - QLabel *m_label; + Utils::ElidingLabel *m_label; QPushButton *m_changeButton; CMakeTool *m_currentTool = nullptr; }; diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp index b9ba701aeb..8040e3f811 100644 --- a/src/plugins/cpptools/cpptoolstestcase.cpp +++ b/src/plugins/cpptools/cpptoolstestcase.cpp @@ -226,22 +226,17 @@ QList<CPlusPlus::Document::Ptr> TestCase::waitForFilesInGlobalSnapshot(const QSt return result; } -bool TestCase::waitUntilCppModelManagerIsAwareOf(Project *project, int timeOutInMs) +bool TestCase::waitUntilProjectIsFullyOpened(Project *project, int timeOutInMs) { if (!project) return false; - QElapsedTimer t; - t.start(); - - CppModelManager *modelManager = CppModelManager::instance(); - forever { - if (modelManager->projectInfo(project).isValid()) - return true; - if (t.elapsed() > timeOutInMs) - return false; - QCoreApplication::processEvents(); - } + return QTest::qWaitFor( + [project]() { + return !project->isParsing() + && CppModelManager::instance()->projectInfo(project).isValid(); + }, + timeOutInMs); } bool TestCase::writeFile(const QString &filePath, const QByteArray &contents) @@ -293,7 +288,7 @@ ProjectInfo ProjectOpenerAndCloser::open(const QString &projectFile, bool config if (configureAsExampleProject) project->configureAsExampleProject(); - if (TestCase::waitUntilCppModelManagerIsAwareOf(project)) { + if (TestCase::waitUntilProjectIsFullyOpened(project)) { m_openProjects.append(project); return CppModelManager::instance()->projectInfo(project); } diff --git a/src/plugins/cpptools/cpptoolstestcase.h b/src/plugins/cpptools/cpptoolstestcase.h index 009a5a9c3e..d6e306d255 100644 --- a/src/plugins/cpptools/cpptoolstestcase.h +++ b/src/plugins/cpptools/cpptoolstestcase.h @@ -92,9 +92,8 @@ public: static bool waitForProcessedEditorDocument(const QString &filePath, int timeOutInMs = 5000); enum { defaultTimeOutInMs = 30 * 1000 /*= 30 secs*/ }; - static bool waitUntilCppModelManagerIsAwareOf( - ProjectExplorer::Project *project, - int timeOutInMs = defaultTimeOutInMs); + static bool waitUntilProjectIsFullyOpened(ProjectExplorer::Project *project, + int timeOutInMs = defaultTimeOutInMs); static CPlusPlus::Document::Ptr waitForFileInGlobalSnapshot( const QString &filePath, int timeOutInMs = defaultTimeOutInMs); diff --git a/src/plugins/designer/codemodelhelpers.cpp b/src/plugins/designer/codemodelhelpers.cpp index f57f1081d2..7beed0874a 100644 --- a/src/plugins/designer/codemodelhelpers.cpp +++ b/src/plugins/designer/codemodelhelpers.cpp @@ -40,10 +40,10 @@ using namespace ProjectExplorer; -typedef QMap<QString, QStringList> DependencyMap; -typedef CPlusPlus::Document::Ptr DocumentPtr; -typedef QList<CPlusPlus::Symbol *> SymbolList; -typedef QList<DocumentPtr> DocumentPtrList; +using DependencyMap = QMap<QString, QStringList>; +using DocumentPtr = CPlusPlus::Document::Ptr; +using SymbolList = QList<CPlusPlus::Symbol *>; +using DocumentPtrList = QList<DocumentPtr>; static const char setupUiC[] = "setupUi"; diff --git a/src/plugins/designer/cpp/formclasswizard.cpp b/src/plugins/designer/cpp/formclasswizard.cpp index 88c1b5da4c..9b878cf32c 100644 --- a/src/plugins/designer/cpp/formclasswizard.cpp +++ b/src/plugins/designer/cpp/formclasswizard.cpp @@ -58,14 +58,14 @@ QString FormClassWizard::formSuffix() const Core::BaseFileWizard *FormClassWizard::create(QWidget *parent, const Core::WizardDialogParameters ¶meters) const { - FormClassWizardDialog *wizardDialog = new FormClassWizardDialog(this, parent); + auto wizardDialog = new FormClassWizardDialog(this, parent); wizardDialog->setPath(parameters.defaultPath()); return wizardDialog; } Core::GeneratedFiles FormClassWizard::generateFiles(const QWizard *w, QString *errorMessage) const { - const FormClassWizardDialog *wizardDialog = qobject_cast<const FormClassWizardDialog *>(w); + auto wizardDialog = qobject_cast<const FormClassWizardDialog *>(w); const Designer::FormClassWizardParameters params = wizardDialog->parameters(); if (params.uiTemplate.isEmpty()) { @@ -90,7 +90,8 @@ Core::GeneratedFiles FormClassWizard::generateFiles(const QWizard *w, QString *e uiFile.setContents(params.uiTemplate); uiFile.setAttributes(Core::GeneratedFile::OpenEditorAttribute); - QString source, header; + QString source; + QString header; QtDesignerFormClassCodeGenerator::generateCpp(params, &header, &source); sourceFile.setContents(source); diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index 06be563702..9a912ac68e 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -105,7 +105,7 @@ bool FormEditorPlugin::initialize(const QStringList &arguments, QString *error) // Ensure that loading designer translations is done before FormEditorW is instantiated const QString locale = ICore::userInterfaceLanguage(); if (!locale.isEmpty()) { - QTranslator *qtr = new QTranslator(this); + auto qtr = new QTranslator(this); const QString &creatorTrPath = ICore::resourcePath() + "/translations"; const QString &qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); const QString &trFile = "designer_" + locale; diff --git a/src/plugins/designer/formeditorstack.cpp b/src/plugins/designer/formeditorstack.cpp index f109138cb3..65c89fc359 100644 --- a/src/plugins/designer/formeditorstack.cpp +++ b/src/plugins/designer/formeditorstack.cpp @@ -92,7 +92,7 @@ void FormEditorStack::add(const EditorData &data) // Since we have 1 pixel splitters we enforce no frame // on the content widget - if (QFrame *frame = qobject_cast<QFrame*>(data.widgetHost)) + if (auto frame = qobject_cast<QFrame*>(data.widgetHost)) frame->setFrameStyle(QFrame::NoFrame); } @@ -122,7 +122,7 @@ EditorData FormEditorStack::activeEditor() const if (index >= 0) return m_formEditors.at(index); } - return EditorData(); + return {}; } SharedTools::WidgetHost *FormEditorStack::formWindowEditorForFormWindow(const QDesignerFormWindowInterface *fw) const @@ -173,7 +173,7 @@ void FormEditorStack::formSizeChanged(int w, int h) // Handle main container resize. if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << w << h; - if (const SharedTools::WidgetHost *wh = qobject_cast<const SharedTools::WidgetHost *>(sender())) { + if (auto wh = qobject_cast<const SharedTools::WidgetHost *>(sender())) { wh->formWindow()->setDirty(true); static const QString geometry = "geometry"; m_designerCore->propertyEditor()->setPropertyValue(geometry, QRect(0,0,w,h) ); diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp index 36db2e05ba..d7df1c8e85 100644 --- a/src/plugins/designer/formeditorw.cpp +++ b/src/plugins/designer/formeditorw.cpp @@ -115,7 +115,7 @@ namespace Internal { class DesignerXmlEditorWidget : public TextEditor::TextEditorWidget { public: - DesignerXmlEditorWidget() {} + using TextEditorWidget::TextEditorWidget; void finalizeInitialization() override { @@ -196,7 +196,7 @@ public: QDesignerFormEditorInterface *m_formeditor = nullptr; QtCreatorIntegration *m_integration = nullptr; QDesignerFormWindowManagerInterface *m_fwm = nullptr; - FormEditorW::InitializationStage m_initStage; + FormEditorW::InitializationStage m_initStage = FormEditorW::RegisterPlugins; QWidget *m_designerSubWindows[DesignerSubWindowCount]; @@ -229,8 +229,7 @@ static FormEditorData *d = nullptr; static FormEditorW *m_instance = nullptr; FormEditorData::FormEditorData() : - m_formeditor(QDesignerComponents::createFormEditor(nullptr)), - m_initStage(FormEditorW::RegisterPlugins) + m_formeditor(QDesignerComponents::createFormEditor(nullptr)) { if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO; @@ -409,19 +408,18 @@ void FormEditorData::fullInit() m_modeWidget = new QWidget; m_modeWidget->setObjectName("DesignerModeWidget"); - QVBoxLayout *layout = new QVBoxLayout; + auto layout = new QVBoxLayout(m_modeWidget); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(m_toolBar); // Avoid mode switch to 'Edit' mode when the application started by // 'Run' in 'Design' mode emits output. - MiniSplitter *splitter = new MiniSplitter(Qt::Vertical); + auto splitter = new MiniSplitter(Qt::Vertical); splitter->addWidget(m_editorWidget); QWidget *outputPane = new OutputPanePlaceHolder(Core::Constants::MODE_DESIGN, splitter); outputPane->setObjectName("DesignerOutputPanePlaceHolder"); splitter->addWidget(outputPane); layout->addWidget(splitter); - m_modeWidget->setLayout(layout); Context designerContexts = m_contexts; designerContexts.add(Core::Constants::C_EDITORMANAGER); @@ -648,9 +646,8 @@ void FormEditorData::setupActions() QToolBar *FormEditorData::createEditorToolBar() const { QToolBar *editorToolBar = new QToolBar; - const QList<Id>::const_iterator cend = m_toolActionIds.constEnd(); - for (QList<Id>::const_iterator it = m_toolActionIds.constBegin(); it != cend; ++it) { - Command *cmd = ActionManager::command(*it); + for (const auto &id : m_toolActionIds) { + Command *cmd = ActionManager::command(id); QTC_ASSERT(cmd, continue); QAction *action = cmd->action(); if (!action->icon().isNull()) // Simplify grid has no action yet @@ -735,7 +732,7 @@ QAction *FormEditorData::createEditModeAction(QActionGroup *ag, const QString &iconName, const QString &keySequence) { - QAction *rc = new QAction(actionName, ag); + auto rc = new QAction(actionName, ag); rc->setCheckable(true); if (!iconName.isEmpty()) rc->setIcon(designerIcon(iconName)); @@ -774,7 +771,7 @@ IEditor *FormEditorData::createEditor() QTC_ASSERT(form, return nullptr); QObject::connect(form, &QDesignerFormWindowInterface::toolChanged, [this] (int i) { toolChanged(i); }); - SharedTools::WidgetHost *widgetHost = new SharedTools::WidgetHost( /* parent */ nullptr, form); + auto widgetHost = new SharedTools::WidgetHost( /* parent */ nullptr, form); FormWindowEditor *formWindowEditor = m_xmlEditorFactory->create(form); m_editorWidget->add(widgetHost, formWindowEditor); diff --git a/src/plugins/designer/formtemplatewizardpage.cpp b/src/plugins/designer/formtemplatewizardpage.cpp index 3387ec6395..738a70285d 100644 --- a/src/plugins/designer/formtemplatewizardpage.cpp +++ b/src/plugins/designer/formtemplatewizardpage.cpp @@ -60,8 +60,7 @@ Utils::WizardPage *FormPageFactory::create(ProjectExplorer::JsonWizard *wizard, QTC_ASSERT(canCreate(typeId), return nullptr); - FormTemplateWizardPage *page = new FormTemplateWizardPage; - return page; + return new FormTemplateWizardPage; } bool FormPageFactory::validateData(Core::Id typeId, const QVariant &data, QString *errorMessage) diff --git a/src/plugins/designer/formwindoweditor.cpp b/src/plugins/designer/formwindoweditor.cpp index b75bad127f..27dfb06889 100644 --- a/src/plugins/designer/formwindoweditor.cpp +++ b/src/plugins/designer/formwindoweditor.cpp @@ -44,9 +44,7 @@ FormWindowEditor::FormWindowEditor() addContext(Designer::Constants::C_DESIGNER_XML_EDITOR); } -FormWindowEditor::~FormWindowEditor() -{ -} +FormWindowEditor::~FormWindowEditor() = default; QWidget *FormWindowEditor::toolBar() { diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp index 2a3b77df5d..176cf41741 100644 --- a/src/plugins/designer/formwindowfile.cpp +++ b/src/plugins/designer/formwindowfile.cpp @@ -84,7 +84,7 @@ Core::IDocument::OpenResult FormWindowFile::open(QString *errorString, const QSt Utils::TextFileFormat::ReadResult readResult = read(absfileName, &contents, errorString); if (readResult == Utils::TextFileFormat::ReadEncodingError) return OpenResult::CannotHandle; - else if (readResult != Utils::TextFileFormat::ReadSuccess) + if (readResult != Utils::TextFileFormat::ReadSuccess) return OpenResult::ReadError; form->setFileName(absfileName); diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index 4a760ff65e..3775642529 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -218,18 +218,18 @@ static const Class *findClass(const Namespace *parentNameSpace, const LookupCont static Function *findDeclaration(const Class *cl, const QString &functionName) { const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8())); - const unsigned mCount = cl->memberCount(); + const int mCount = cl->memberCount(); // we are interested only in declarations (can be decl of function or of a field) // we are only interested in declarations of functions const Overview overview; - for (unsigned j = 0; j < mCount; ++j) { // go through all members + for (int j = 0; j < mCount; ++j) { // go through all members if (Declaration *decl = cl->memberAt(j)->asDeclaration()) if (Function *fun = decl->type()->asFunctionType()) { // Format signature QString memberFunction = overview.prettyName(fun->name()); memberFunction += '('; - const uint aCount = fun->argumentCount(); - for (uint i = 0; i < aCount; i++) { // we build argument types string + const int aCount = fun->argumentCount(); + for (int i = 0; i < aCount; i++) { // we build argument types string const Argument *arg = fun->argumentAt(i)->asArgument(); if (i > 0) memberFunction += ','; @@ -350,7 +350,7 @@ static QString addConstRefIfNeeded(const QString &argument) "unsigned", "qint64", "quint64"}); for (int i = 0; i < nonConstRefs.count(); i++) { - const QString nonConstRef = nonConstRefs.at(i); + const QString &nonConstRef = nonConstRefs.at(i); if (argument == nonConstRef || argument.startsWith(nonConstRef + ' ')) return argument; } @@ -411,7 +411,7 @@ static QString addParameterNames(const QString &functionSignature, const QString // included files (going down [maxIncludeDepth] includes) and return a pair // of <Class*, Document>. -typedef QPair<const Class *, Document::Ptr> ClassDocumentPtrPair; +using ClassDocumentPtrPair = QPair<const Class *, Document::Ptr>; static ClassDocumentPtrPair findClassRecursively(const LookupContext &context, const QString &className, @@ -431,7 +431,7 @@ static ClassDocumentPtrPair for (const QString &include : includedFiles) { const Snapshot::const_iterator it = docTable.find(include); if (it != docTable.end()) { - const Document::Ptr includeDoc = it.value(); + const Document::Ptr &includeDoc = it.value(); LookupContext context(includeDoc, docTable); const ClassDocumentPtrPair irc = findClassRecursively(context, className, recursionMaxIncludeDepth, namespaceName); @@ -489,7 +489,7 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName, const QStringList ¶meterNames, QString *errorMessage) { - typedef QMap<int, Document::Ptr> DocumentMap; + using DocumentMap = QMap<int, Document::Ptr>; const Utils::FilePath currentUiFile = FormEditorW::activeEditor()->document()->filePath(); #if 0 diff --git a/src/plugins/designer/resourcehandler.cpp b/src/plugins/designer/resourcehandler.cpp index 392b632a8f..f111e8dbf8 100644 --- a/src/plugins/designer/resourcehandler.cpp +++ b/src/plugins/designer/resourcehandler.cpp @@ -73,10 +73,7 @@ void ResourceHandler::ensureInitialized() qDebug() << "ResourceHandler::ensureInitialized() origPaths=" << m_originalUiQrcPaths; } -ResourceHandler::~ResourceHandler() -{ - -} +ResourceHandler::~ResourceHandler() = default; void ResourceHandler::updateResourcesHelper(bool updateProjectResources) { diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 10147d2ac3..431b91f1e2 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -267,7 +267,7 @@ static McuPackage *createQtForMCUsPackage() McuPackage::tr("Qt for MCUs SDK"), QDir::homePath(), Utils::HostOsInfo::withExecutableSuffix("bin/qmltocpp"), - "QtMCUSdk"); + "QtForMCUsSdk"); result->setEnvironmentVariableName("Qul_DIR"); return result; } diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 06bb9a86e6..c0d1c42afc 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -168,6 +168,9 @@ void McuSupportOptionsPage::apply() QTC_ASSERT(m_options->armGccPackage, return); QTC_ASSERT(m_options->qtForMCUsSdkPackage, return); + if (!widget()->isVisible()) + return; // Only create/overwrite kits when this option page is shown + const McuTarget *mcuTarget = m_widget->currentMcuTarget(); if (!mcuTarget) return; diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp index 68ec688c5f..d6b2dd427a 100644 --- a/src/plugins/mcusupport/mcusupportplugin.cpp +++ b/src/plugins/mcusupport/mcusupportplugin.cpp @@ -45,8 +45,8 @@ class McuSupportPluginPrivate { public: McuSupportDeviceFactory deviceFactory; - EmrunRunConfigurationFactory emrunRunConfigurationFactory; - RunWorkerFactory emrunRunWorkerFactory{ + McuSupportRunConfigurationFactory runConfigurationFactory; + RunWorkerFactory runWorkerFactory{ makeFlashAndRunWorker(), {ProjectExplorer::Constants::NORMAL_RUN_MODE}, {Constants::RUNCONFIGURATION} diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp index 49e2d798db..88dbf8349b 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp @@ -103,7 +103,7 @@ RunWorkerFactory::WorkerCreator makeFlashAndRunWorker() return RunWorkerFactory::make<FlashAndRunWorker>(); } -EmrunRunConfigurationFactory::EmrunRunConfigurationFactory() +McuSupportRunConfigurationFactory::McuSupportRunConfigurationFactory() : FixedRunConfigurationFactory(FlashAndRunConfiguration::tr("Flash and run")) { registerRunConfiguration<FlashAndRunConfiguration>(Constants::RUNCONFIGURATION); diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.h b/src/plugins/mcusupport/mcusupportrunconfiguration.h index b53eea03a4..704c8c9c90 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.h +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.h @@ -31,10 +31,10 @@ namespace McuSupport { namespace Internal { -class EmrunRunConfigurationFactory : public ProjectExplorer::FixedRunConfigurationFactory +class McuSupportRunConfigurationFactory : public ProjectExplorer::FixedRunConfigurationFactory { public: - EmrunRunConfigurationFactory(); + McuSupportRunConfigurationFactory(); }; class FlashAndRunConfiguration : public ProjectExplorer::RunConfiguration diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4d04a7da68..6a186b380c 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3917,6 +3917,12 @@ void ProjectExplorerPlugin::updateActions() dd->updateActions(); } +void ProjectExplorerPlugin::activateProjectPanel(Core::Id panelId) +{ + Core::ModeManager::activateMode(Constants::MODE_SESSION); + dd->m_proWindow->activateProjectPanel(panelId); +} + QList<QPair<QString, QString> > ProjectExplorerPlugin::recentProjects() { return dd->recentProjects(); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index c2dffd4f6f..d7de49c83b 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -172,6 +172,8 @@ public: static void updateActions(); + static void activateProjectPanel(Core::Id panelId); + signals: void finishedInitialization(); diff --git a/src/plugins/projectexplorer/projectpanelfactory.cpp b/src/plugins/projectexplorer/projectpanelfactory.cpp index d734b8d336..c4eaef05b4 100644 --- a/src/plugins/projectexplorer/projectpanelfactory.cpp +++ b/src/plugins/projectexplorer/projectpanelfactory.cpp @@ -80,6 +80,16 @@ void ProjectPanelFactory::destroyFactories() s_factories.clear(); } +Core::Id ProjectPanelFactory::id() const +{ + return m_id; +} + +void ProjectPanelFactory::setId(Core::Id id) +{ + m_id = id; +} + QString ProjectPanelFactory::icon() const { return m_icon; diff --git a/src/plugins/projectexplorer/projectpanelfactory.h b/src/plugins/projectexplorer/projectpanelfactory.h index 27e643b0ed..6d03125398 100644 --- a/src/plugins/projectexplorer/projectpanelfactory.h +++ b/src/plugins/projectexplorer/projectpanelfactory.h @@ -30,6 +30,8 @@ #include "panelswidget.h" #include "projectwindow.h" +#include <coreplugin/id.h> + #include <utils/treemodel.h> #include <functional> @@ -44,6 +46,9 @@ class PROJECTEXPLORER_EXPORT ProjectPanelFactory public: ProjectPanelFactory(); + Core::Id id() const; + void setId(Core::Id id); + // simple properties QString displayName() const; void setDisplayName(const QString &name); @@ -78,6 +83,7 @@ private: friend class ProjectExplorerPlugin; static void destroyFactories(); + Core::Id m_id; int m_priority = 0; QString m_displayName; SupportsFunction m_supportsFunction; diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index 267a8626b9..3314b78dde 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -88,6 +88,8 @@ public: Qt::ItemFlags flags(int column) const override; bool setData(int column, const QVariant &, int role) override; + ProjectPanelFactory *factory() const { return m_factory; } + protected: ProjectPanelFactory *m_factory = nullptr; QPointer<Project> m_project; @@ -285,6 +287,13 @@ public: return activeItem ? activeItem->index() : QModelIndex(); } + TreeItem *itemForProjectPanel(Core::Id panelId) + { + return m_miscItem->findChildAtLevel(1, [panelId](const TreeItem *item){ + return static_cast<const MiscSettingsPanelItem *>(item)->factory()->id() == panelId; + }); + } + private: int m_currentChildIndex = 0; // Start with Build & Run. Project *m_project = nullptr; @@ -509,6 +518,14 @@ public: item->setData(0, QVariant(), ItemActivatedDirectlyRole); } + void activateProjectPanel(Core::Id panelId) + { + if (ProjectItem *projectItem = m_projectsModel.rootItem()->childAt(0)) { + if (TreeItem *item = projectItem->itemForProjectPanel(panelId)) + itemActivated(item->index()); + } + } + void openContextMenu(const QPoint &pos) { QMenu menu; @@ -618,6 +635,11 @@ ProjectWindow::ProjectWindow() setContextMenuPolicy(Qt::CustomContextMenu); } +void ProjectWindow::activateProjectPanel(Core::Id panelId) +{ + d->activateProjectPanel(panelId); +} + ProjectWindow::~ProjectWindow() = default; QSize SelectorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const diff --git a/src/plugins/projectexplorer/projectwindow.h b/src/plugins/projectexplorer/projectwindow.h index 1aeeb882f9..01840951ab 100644 --- a/src/plugins/projectexplorer/projectwindow.h +++ b/src/plugins/projectexplorer/projectwindow.h @@ -31,6 +31,8 @@ #include <memory> +namespace Core { class Id; } + namespace ProjectExplorer { namespace Internal { @@ -60,6 +62,8 @@ public: ProjectWindow(); ~ProjectWindow() override; + void activateProjectPanel(Core::Id panelId); + private: const std::unique_ptr<ProjectWindowPrivate> d; }; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 9d291c7bad..5689455b63 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -524,6 +524,8 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/bindingeditor SOURCES bindingeditor.cpp bindingeditor.h + bindingeditordialog.cpp bindingeditordialog.h + bindingeditorwidget.cpp bindingeditorwidget.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index e56822b2a3..fe3871c6c1 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -26,393 +26,19 @@ #include "bindingeditor.h" #include <qmldesignerplugin.h> - -#include "texteditorview.h" -#include "texteditorwidget.h" -#include <texteditor/texteditor.h> - #include <coreplugin/icore.h> #include <coreplugin/actionmanager/actionmanager.h> -#include <qmldesigner/qmldesignerplugin.h> -#include <qmldesigner/qmldesignerconstants.h> -#include <qmljseditor/qmljseditor.h> -#include <qmljseditor/qmljseditorconstants.h> -#include <qmljstools/qmljstoolsconstants.h> -#include <qmljseditor/qmljscompletionassist.h> -#include <qmljseditor/qmljshighlighter.h> -#include <qmljseditor/qmljshoverhandler.h> -#include <qmljstools/qmljsindenter.h> -#include <qmljseditor/qmljsautocompleter.h> -#include <qmljseditor/qmljseditordocument.h> -#include <qmljseditor/qmljssemantichighlighter.h> -#include <texteditor/textdocument.h> -#include <texteditor/texteditoractionhandler.h> -#include <texteditor/codeassist/assistinterface.h> -#include <texteditor/codeassist/completionassistprovider.h> -#include <texteditor/syntaxhighlighter.h> -#include <projectexplorer/projectexplorerconstants.h> -#include <coreplugin/editormanager/editormanager.h> #include <metainfo.h> #include <qmlmodelnodeproxy.h> -#include <variantproperty.h> -#include <bindingproperty.h> #include <nodeabstractproperty.h> #include <nodelistproperty.h> #include <propertyeditorvalue.h> -#include <QDialogButtonBox> -#include <QPushButton> -#include <QDebug> -#include <QVBoxLayout> -#include <QHBoxLayout> -#include <QComboBox> -#include <QPlainTextEdit> - namespace QmlDesigner { static BindingEditor *s_lastBindingEditor = nullptr; -const char BINDINGEDITOR_CONTEXT_ID[] = "BindingEditor.BindingEditorContext"; - -BindingEditorWidget::BindingEditorWidget() - : m_context(new BindingEditorContext(this)) -{ - Core::ICore::addContextObject(m_context); - - const Core::Context context(BINDINGEDITOR_CONTEXT_ID); - - /* - * We have to register our own active auto completion shortcut, because the original short cut will - * use the cursor position of the original editor in the editor manager. - */ - - m_completionAction = new QAction(tr("Trigger Completion"), this); - Core::Command *command = Core::ActionManager::registerAction( - m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); - command->setDefaultKeySequence(QKeySequence( - Core::useMacShortcuts - ? tr("Meta+Space") - : tr("Ctrl+Space"))); - - connect(m_completionAction, &QAction::triggered, [this]() { - invokeAssist(TextEditor::Completion); - }); -} - -BindingEditorWidget::~BindingEditorWidget() -{ - unregisterAutoCompletion(); - - Core::ICore::removeContextObject(m_context); - delete m_context; -} - -void BindingEditorWidget::unregisterAutoCompletion() -{ - if (m_completionAction) { - Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS); - delete m_completionAction; - m_completionAction = nullptr; - } -} - -bool BindingEditorWidget::event(QEvent *event) -{ - if (event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { - emit returnKeyClicked(); - return true; - } else { - return QmlJSEditor::QmlJSEditorWidget::event(event); - } - } - return QmlJSEditor::QmlJSEditorWidget::event(event); -} - -TextEditor::AssistInterface *BindingEditorWidget::createAssistInterface( - TextEditor::AssistKind assistKind, TextEditor::AssistReason assistReason) const -{ - Q_UNUSED(assistKind) - return new QmlJSEditor::QmlJSCompletionAssistInterface( - document(), position(), QString(), - assistReason, qmljsdocument->semanticInfo()); -} - -class BindingDocument : public QmlJSEditor::QmlJSEditorDocument -{ -public: - BindingDocument() - : QmlJSEditor::QmlJSEditorDocument(BINDINGEDITOR_CONTEXT_ID) - , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this)) {} - ~BindingDocument() { delete m_semanticHighlighter; } - -protected: - void applyFontSettings() - { - TextDocument::applyFontSettings(); - m_semanticHighlighter->updateFontSettings(fontSettings()); - if (!isSemanticInfoOutdated()) - m_semanticHighlighter->rerun(semanticInfo()); - } - - void triggerPendingUpdates() - { - TextDocument::triggerPendingUpdates(); // calls applyFontSettings if necessary - if (!isSemanticInfoOutdated()) - m_semanticHighlighter->rerun(semanticInfo()); - } - -private: - QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr; -}; - -class BindingEditorFactory : public TextEditor::TextEditorFactory -{ -public: - BindingEditorFactory() - { - setId(BINDINGEDITOR_CONTEXT_ID); - setDisplayName(QCoreApplication::translate("OpenWith::Editors", BINDINGEDITOR_CONTEXT_ID)); - - - setDocumentCreator([]() { return new BindingDocument; }); - setEditorWidgetCreator([]() { return new BindingEditorWidget; }); - setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; }); - setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; }); - setCommentDefinition(Utils::CommentDefinition::CppStyle); - setParenthesesMatchingEnabled(true); - setCodeFoldingSupported(true); - - addHoverHandler(new QmlJSEditor::QmlJSHoverHandler); - setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider); - } - - static void decorateEditor(TextEditor::TextEditorWidget *editor) - { - editor->textDocument()->setSyntaxHighlighter(new QmlJSEditor::QmlJSHighlighter); - editor->textDocument()->setIndenter(new QmlJSEditor::Internal::Indenter( - editor->textDocument()->document())); - editor->setAutoCompleter(new QmlJSEditor::AutoCompleter); - } -}; - -BindingEditorDialog::BindingEditorDialog(QWidget *parent) - : QDialog(parent) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - setWindowTitle(tr("Binding Editor")); - setModal(false); - - setupJSEditor(); - setupUIComponents(); - - QObject::connect(m_buttonBox, &QDialogButtonBox::accepted, - this, &BindingEditorDialog::accepted); - QObject::connect(m_buttonBox, &QDialogButtonBox::rejected, - this, &BindingEditorDialog::rejected); - QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked, - this, &BindingEditorDialog::accepted); - - QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged), - this, &BindingEditorDialog::itemIDChanged); - QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged), - this, &BindingEditorDialog::propertyIDChanged); - QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged, - this, &BindingEditorDialog::textChanged); -} - -BindingEditorDialog::~BindingEditorDialog() -{ - delete m_editor; //m_editorWidget is handled by basetexteditor destructor - delete m_buttonBox; - delete m_comboBoxItem; - delete m_comboBoxProperty; - delete m_comboBoxLayout; - delete m_verticalLayout; -} - -void BindingEditorDialog::showWidget(int x, int y) -{ - this->show(); - this->raise(); - move(QPoint(x, y)); - m_editorWidget->setFocus(); -} - -QString BindingEditorDialog::editorValue() const -{ - if (!m_editorWidget) - return {}; - - return m_editorWidget->document()->toPlainText(); -} - -void BindingEditorDialog::setEditorValue(const QString &text) -{ - if (m_editorWidget) - m_editorWidget->document()->setPlainText(text); -} - -void BindingEditorDialog::setAllBindings(QList<BindingEditorDialog::BindingOption> bindings) -{ - m_lock = true; - - m_bindings = bindings; - setupComboBoxes(); - adjustProperties(); - - m_lock = false; -} - -void BindingEditorDialog::adjustProperties() -{ - const QString expression = editorValue(); - QString item; - QString property; - QStringList expressionElements = expression.split("."); - - if (!expressionElements.isEmpty()) { - const int itemIndex = m_bindings.indexOf(expressionElements.at(0)); - - if (itemIndex != -1) { - item = expressionElements.at(0); - expressionElements.removeFirst(); - - if (!expressionElements.isEmpty()) { - const QString sum = expressionElements.join("."); - - if (m_bindings.at(itemIndex).properties.contains(sum)) - property = sum; - } - } - } - - if (item.isEmpty()) { - item = undefinedString; - if (m_comboBoxItem->findText(item) == -1) - m_comboBoxItem->addItem(item); - } - m_comboBoxItem->setCurrentText(item); - - if (property.isEmpty()) { - property = undefinedString; - if (m_comboBoxProperty->findText(property) == -1) - m_comboBoxProperty->addItem(property); - } - m_comboBoxProperty->setCurrentText(property); -} - -void BindingEditorDialog::unregisterAutoCompletion() -{ - if (m_editorWidget) - m_editorWidget->unregisterAutoCompletion(); -} - -void BindingEditorDialog::setupJSEditor() -{ - static BindingEditorFactory f; - m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor()); - m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget()); - - Core::Context context = m_editor->context(); - context.prepend(BINDINGEDITOR_CONTEXT_ID); - m_editorWidget->m_context->setContext(context); - - auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor(); - - m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>( - qmlDesignerEditor->widget())->qmlJsEditorDocument(); - - - m_editorWidget->setLineNumbersVisible(false); - m_editorWidget->setMarksVisible(false); - m_editorWidget->setCodeFoldingSupported(false); - m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - m_editorWidget->setTabChangesFocus(true); -} - -void BindingEditorDialog::setupUIComponents() -{ - m_verticalLayout = new QVBoxLayout(this); - m_comboBoxLayout = new QHBoxLayout; - - m_comboBoxItem = new QComboBox(this); - m_comboBoxProperty = new QComboBox(this); - - m_editorWidget->setParent(this); - m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); - m_editorWidget->show(); - - m_buttonBox = new QDialogButtonBox(this); - m_buttonBox->setOrientation(Qt::Horizontal); - m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - - - m_comboBoxLayout->addWidget(m_comboBoxItem); - m_comboBoxLayout->addWidget(m_comboBoxProperty); - - m_verticalLayout->addLayout(m_comboBoxLayout); - m_verticalLayout->addWidget(m_editorWidget); - m_verticalLayout->addWidget(m_buttonBox); - - this->resize(660, 240); -} - -void BindingEditorDialog::setupComboBoxes() -{ - m_comboBoxItem->clear(); - m_comboBoxProperty->clear(); - - for (auto bind : m_bindings) - m_comboBoxItem->addItem(bind.item); -} - -void BindingEditorDialog::itemIDChanged(int itemID) -{ - const QString previousProperty = m_comboBoxProperty->currentText(); - m_comboBoxProperty->clear(); - - if (m_bindings.size() > itemID && itemID != -1) { - m_comboBoxProperty->addItems(m_bindings.at(itemID).properties); - - if (!m_lock) - if (m_comboBoxProperty->findText(previousProperty) != -1) - m_comboBoxProperty->setCurrentText(previousProperty); - - const int undefinedItem = m_comboBoxItem->findText(undefinedString); - if ((undefinedItem != -1) && (m_comboBoxItem->itemText(itemID) != undefinedString)) - m_comboBoxItem->removeItem(undefinedItem); - } -} - -void BindingEditorDialog::propertyIDChanged(int propertyID) -{ - const int itemID = m_comboBoxItem->currentIndex(); - - if (!m_lock) - if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString)) - setEditorValue(m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID)); - - const int undefinedProperty = m_comboBoxProperty->findText(undefinedString); - if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString)) - m_comboBoxProperty->removeItem(undefinedProperty); -} - -void BindingEditorDialog::textChanged() -{ - if (m_lock) - return; - - m_lock = true; - adjustProperties(); - m_lock = false; -} - - BindingEditor::BindingEditor(QObject *) { } @@ -476,9 +102,16 @@ void BindingEditor::setBackendValue(const QVariant &backendValue) m_backendValue = backendValue; const QObject *backendValueObj = backendValue.value<QObject*>(); const PropertyEditorValue *propertyEditorValue = qobject_cast<const PropertyEditorValue *>(backendValueObj); + const ModelNode node = propertyEditorValue->modelNode(); + + if (node.isValid()) + { + m_backendValueTypeName = node.metaInfo().propertyTypeName(propertyEditorValue->name()); - m_backendValueTypeName = propertyEditorValue->modelNode().metaInfo().propertyTypeName( - propertyEditorValue->name()); + if (m_backendValueTypeName == "alias" || m_backendValueTypeName == "unknown") + if (QmlObjectNode::isValidQmlObjectNode(node)) + m_backendValueTypeName = QmlObjectNode(node).instanceType(propertyEditorValue->name()); + } emit backendValueChanged(); } @@ -528,8 +161,16 @@ void BindingEditor::prepareBindings() for (auto objnode : allNodes) { BindingEditorDialog::BindingOption binding; for (auto propertyName : objnode.metaInfo().propertyNames()) - if (m_backendValueTypeName == objnode.metaInfo().propertyTypeName(propertyName)) + { + TypeName propertyTypeName = objnode.metaInfo().propertyTypeName(propertyName); + + if ((propertyTypeName == "alias" || propertyTypeName == "unknown")) + if (QmlObjectNode::isValidQmlObjectNode(objnode)) + propertyTypeName = QmlObjectNode(objnode).instanceType(propertyName); + + if (m_backendValueTypeName == propertyTypeName) binding.properties.append(QString::fromUtf8(propertyName)); + } if (!binding.properties.isEmpty() && objnode.hasId()) { binding.item = objnode.displayName(); @@ -539,6 +180,16 @@ void BindingEditor::prepareBindings() if (!bindings.isEmpty() && !m_dialog.isNull()) m_dialog->setAllBindings(bindings); + + updateWindowName(); +} + +void BindingEditor::updateWindowName() +{ + if (!m_dialog.isNull() && !m_backendValueTypeName.isEmpty()) + { + m_dialog->setWindowTitle(m_dialog->defaultTitle() + " [" + m_backendValueTypeName + "]"); + } } QVariant BindingEditor::backendValue() const @@ -556,5 +207,4 @@ QVariant BindingEditor::stateModelNode() const return m_stateModelNode; } - -} +} // QmlDesigner namespace diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h index a1deb74108..8f9a77baec 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.h @@ -26,117 +26,16 @@ #ifndef BINDINGEDITOR_H #define BINDINGEDITOR_H -#include "texteditorview.h" -#include <texteditor/texteditor.h> -#include <QtQml> +#include <bindingeditor/bindingeditordialog.h> +#include <qmldesignercorelib_global.h> +#include <modelnode.h> -#include <QWidget> -#include <QDialog> +#include <QtQml> +#include <QObject> #include <QPointer> -#include <qmljseditor/qmljseditor.h> - -#include <memory> - -QT_BEGIN_NAMESPACE -class QTextEdit; -class QDialogButtonBox; -class QVBoxLayout; -class QHBoxLayout; -class QComboBox; -QT_END_NAMESPACE - namespace QmlDesigner { -class BindingEditorContext : public Core::IContext -{ - Q_OBJECT - -public: - BindingEditorContext(QWidget *parent) : Core::IContext(parent) - { - setWidget(parent); - } -}; - -class BindingEditorWidget : public QmlJSEditor::QmlJSEditorWidget -{ - Q_OBJECT - -public: - BindingEditorWidget(); - ~BindingEditorWidget() override; - - void unregisterAutoCompletion(); - - bool event(QEvent *event) override; - - TextEditor::AssistInterface *createAssistInterface(TextEditor::AssistKind assistKind, - TextEditor::AssistReason assistReason) const override; - -signals: - void returnKeyClicked(); - -public: - QmlJSEditor::QmlJSEditorDocument *qmljsdocument = nullptr; - BindingEditorContext *m_context = nullptr; - QAction *m_completionAction = nullptr; -}; - -class BindingEditorDialog : public QDialog -{ - Q_OBJECT - -public: - struct BindingOption - { - BindingOption() {} - BindingOption(const QString &value) { item = value; } - - bool operator==(const QString &value) const { return value == item; } - bool operator==(const BindingOption &value) const { return value.item == item; } - - QString item; - QStringList properties; - }; - -public: - BindingEditorDialog(QWidget *parent = nullptr); - ~BindingEditorDialog() override; - - void showWidget(int x, int y); - - QString editorValue() const; - void setEditorValue(const QString &text); - - void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings); - void adjustProperties(); - - void unregisterAutoCompletion(); - -private: - void setupJSEditor(); - void setupUIComponents(); - void setupComboBoxes(); - -public slots: - void itemIDChanged(int); - void propertyIDChanged(int); - void textChanged(); - -private: - TextEditor::BaseTextEditor *m_editor = nullptr; - BindingEditorWidget *m_editorWidget = nullptr; - QVBoxLayout *m_verticalLayout = nullptr; - QDialogButtonBox *m_buttonBox = nullptr; - QHBoxLayout *m_comboBoxLayout = nullptr; - QComboBox *m_comboBoxItem = nullptr; - QComboBox *m_comboBoxProperty = nullptr; - QList<BindingEditorDialog::BindingOption> m_bindings; - bool m_lock = false; - const QString undefinedString = {"[Undefined]"}; -}; - class BindingEditor : public QObject { Q_OBJECT @@ -163,6 +62,7 @@ public: void setStateModelNode(const QVariant &stateModelNode); Q_INVOKABLE void prepareBindings(); + Q_INVOKABLE void updateWindowName(); signals: void accepted(); diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri index 518905eb2a..88b2897c7b 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.pri @@ -1,3 +1,7 @@ HEADERS += $$PWD/bindingeditor.h +HEADERS += $$PWD/bindingeditordialog.h +HEADERS += $$PWD/bindingeditorwidget.h SOURCES += $$PWD/bindingeditor.cpp +SOURCES += $$PWD/bindingeditordialog.cpp +SOURCES += $$PWD/bindingeditorwidget.cpp diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp new file mode 100644 index 0000000000..51bd771843 --- /dev/null +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "bindingeditordialog.h" + +#include <texteditor/texteditor.h> + +#include <qmldesigner/qmldesignerplugin.h> +#include <qmljseditor/qmljseditor.h> +#include <qmljseditor/qmljseditordocument.h> +#include <texteditor/textdocument.h> + +#include <QDialogButtonBox> +#include <QPushButton> +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QComboBox> +#include <QPlainTextEdit> + +namespace QmlDesigner { + +BindingEditorDialog::BindingEditorDialog(QWidget *parent) + : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(defaultTitle()); + setModal(false); + + setupJSEditor(); + setupUIComponents(); + + QObject::connect(m_buttonBox, &QDialogButtonBox::accepted, + this, &BindingEditorDialog::accepted); + QObject::connect(m_buttonBox, &QDialogButtonBox::rejected, + this, &BindingEditorDialog::rejected); + QObject::connect(m_editorWidget, &BindingEditorWidget::returnKeyClicked, + this, &BindingEditorDialog::accepted); + + QObject::connect(m_comboBoxItem, QOverload<int>::of(&QComboBox::currentIndexChanged), + this, &BindingEditorDialog::itemIDChanged); + QObject::connect(m_comboBoxProperty, QOverload<int>::of(&QComboBox::currentIndexChanged), + this, &BindingEditorDialog::propertyIDChanged); + QObject::connect(m_editorWidget, &QPlainTextEdit::textChanged, + this, &BindingEditorDialog::textChanged); +} + +BindingEditorDialog::~BindingEditorDialog() +{ + delete m_editor; //m_editorWidget is handled by basetexteditor destructor + delete m_buttonBox; + delete m_comboBoxItem; + delete m_comboBoxProperty; + delete m_comboBoxLayout; + delete m_verticalLayout; +} + +void BindingEditorDialog::showWidget(int x, int y) +{ + this->show(); + this->raise(); + move(QPoint(x, y)); + m_editorWidget->setFocus(); +} + +QString BindingEditorDialog::editorValue() const +{ + if (!m_editorWidget) + return {}; + + return m_editorWidget->document()->toPlainText(); +} + +void BindingEditorDialog::setEditorValue(const QString &text) +{ + if (m_editorWidget) + m_editorWidget->document()->setPlainText(text); +} + +void BindingEditorDialog::setAllBindings(QList<BindingEditorDialog::BindingOption> bindings) +{ + m_lock = true; + + m_bindings = bindings; + setupComboBoxes(); + adjustProperties(); + + m_lock = false; +} + +void BindingEditorDialog::adjustProperties() +{ + const QString expression = editorValue(); + QString item; + QString property; + QStringList expressionElements = expression.split("."); + + if (!expressionElements.isEmpty()) { + const int itemIndex = m_bindings.indexOf(expressionElements.at(0)); + + if (itemIndex != -1) { + item = expressionElements.at(0); + expressionElements.removeFirst(); + + if (!expressionElements.isEmpty()) { + const QString sum = expressionElements.join("."); + + if (m_bindings.at(itemIndex).properties.contains(sum)) + property = sum; + } + } + } + + if (item.isEmpty()) { + item = undefinedString; + if (m_comboBoxItem->findText(item) == -1) + m_comboBoxItem->addItem(item); + } + m_comboBoxItem->setCurrentText(item); + + if (property.isEmpty()) { + property = undefinedString; + if (m_comboBoxProperty->findText(property) == -1) + m_comboBoxProperty->addItem(property); + } + m_comboBoxProperty->setCurrentText(property); +} + +void BindingEditorDialog::unregisterAutoCompletion() +{ + if (m_editorWidget) + m_editorWidget->unregisterAutoCompletion(); +} + +QString BindingEditorDialog::defaultTitle() const +{ + return titleString; +} + +void BindingEditorDialog::setupJSEditor() +{ + static BindingEditorFactory f; + m_editor = qobject_cast<TextEditor::BaseTextEditor*>(f.createEditor()); + m_editorWidget = qobject_cast<BindingEditorWidget*>(m_editor->editorWidget()); + + Core::Context context = m_editor->context(); + context.prepend(BINDINGEDITOR_CONTEXT_ID); + m_editorWidget->m_context->setContext(context); + + auto qmlDesignerEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor(); + + m_editorWidget->qmljsdocument = qobject_cast<QmlJSEditor::QmlJSEditorWidget *>( + qmlDesignerEditor->widget())->qmlJsEditorDocument(); + + + m_editorWidget->setLineNumbersVisible(false); + m_editorWidget->setMarksVisible(false); + m_editorWidget->setCodeFoldingSupported(false); + m_editorWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_editorWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_editorWidget->setTabChangesFocus(true); +} + +void BindingEditorDialog::setupUIComponents() +{ + m_verticalLayout = new QVBoxLayout(this); + m_comboBoxLayout = new QHBoxLayout; + + m_comboBoxItem = new QComboBox(this); + m_comboBoxProperty = new QComboBox(this); + + m_editorWidget->setParent(this); + m_editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + m_editorWidget->show(); + + m_buttonBox = new QDialogButtonBox(this); + m_buttonBox->setOrientation(Qt::Horizontal); + m_buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + + + m_comboBoxLayout->addWidget(m_comboBoxItem); + m_comboBoxLayout->addWidget(m_comboBoxProperty); + + m_verticalLayout->addLayout(m_comboBoxLayout); + m_verticalLayout->addWidget(m_editorWidget); + m_verticalLayout->addWidget(m_buttonBox); + + this->resize(660, 240); +} + +void BindingEditorDialog::setupComboBoxes() +{ + m_comboBoxItem->clear(); + m_comboBoxProperty->clear(); + + for (auto bind : m_bindings) + m_comboBoxItem->addItem(bind.item); +} + +void BindingEditorDialog::itemIDChanged(int itemID) +{ + const QString previousProperty = m_comboBoxProperty->currentText(); + m_comboBoxProperty->clear(); + + if (m_bindings.size() > itemID && itemID != -1) { + m_comboBoxProperty->addItems(m_bindings.at(itemID).properties); + + if (!m_lock) + if (m_comboBoxProperty->findText(previousProperty) != -1) + m_comboBoxProperty->setCurrentText(previousProperty); + + const int undefinedItem = m_comboBoxItem->findText(undefinedString); + if ((undefinedItem != -1) && (m_comboBoxItem->itemText(itemID) != undefinedString)) + m_comboBoxItem->removeItem(undefinedItem); + } +} + +void BindingEditorDialog::propertyIDChanged(int propertyID) +{ + const int itemID = m_comboBoxItem->currentIndex(); + + if (!m_lock) + if (!m_comboBoxProperty->currentText().isEmpty() && (m_comboBoxProperty->currentText() != undefinedString)) + setEditorValue(m_comboBoxItem->itemText(itemID) + "." + m_comboBoxProperty->itemText(propertyID)); + + const int undefinedProperty = m_comboBoxProperty->findText(undefinedString); + if ((undefinedProperty != -1) && (m_comboBoxProperty->itemText(propertyID) != undefinedString)) + m_comboBoxProperty->removeItem(undefinedProperty); +} + +void BindingEditorDialog::textChanged() +{ + if (m_lock) + return; + + m_lock = true; + adjustProperties(); + m_lock = false; +} + +} // QmlDesigner namespace diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h new file mode 100644 index 0000000000..6cb0c00361 --- /dev/null +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditordialog.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifndef BINDINGEDITORDIALOG_H +#define BINDINGEDITORDIALOG_H + +#include <bindingeditor/bindingeditorwidget.h> +#include <texteditor/texteditor.h> + +#include <QDialog> + +QT_BEGIN_NAMESPACE +class QDialogButtonBox; +class QVBoxLayout; +class QHBoxLayout; +class QComboBox; +QT_END_NAMESPACE + +namespace QmlDesigner { + +class BindingEditorDialog : public QDialog +{ + Q_OBJECT + +public: + struct BindingOption + { + BindingOption() {} + BindingOption(const QString &value) { item = value; } + + bool operator==(const QString &value) const { return value == item; } + bool operator==(const BindingOption &value) const { return value.item == item; } + + QString item; + QStringList properties; + }; + +public: + BindingEditorDialog(QWidget *parent = nullptr); + ~BindingEditorDialog() override; + + void showWidget(int x, int y); + + QString editorValue() const; + void setEditorValue(const QString &text); + + void setAllBindings(QList<BindingEditorDialog::BindingOption> bindings); + void adjustProperties(); + + void unregisterAutoCompletion(); + + QString defaultTitle() const; + +private: + void setupJSEditor(); + void setupUIComponents(); + void setupComboBoxes(); + +public slots: + void itemIDChanged(int); + void propertyIDChanged(int); + void textChanged(); + +private: + TextEditor::BaseTextEditor *m_editor = nullptr; + BindingEditorWidget *m_editorWidget = nullptr; + QVBoxLayout *m_verticalLayout = nullptr; + QDialogButtonBox *m_buttonBox = nullptr; + QHBoxLayout *m_comboBoxLayout = nullptr; + QComboBox *m_comboBoxItem = nullptr; + QComboBox *m_comboBoxProperty = nullptr; + QList<BindingEditorDialog::BindingOption> m_bindings; + bool m_lock = false; + const QString undefinedString = {"[Undefined]"}; + const QString titleString = {tr("Binding Editor")}; +}; + +} + +#endif //BINDINGEDITORDIALOG_H diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp new file mode 100644 index 0000000000..6a058cb49a --- /dev/null +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "bindingeditorwidget.h" + +#include <coreplugin/icore.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <qmljseditor/qmljseditor.h> +#include <qmljseditor/qmljscompletionassist.h> +#include <qmljseditor/qmljshighlighter.h> +#include <qmljseditor/qmljshoverhandler.h> +#include <qmljseditor/qmljsautocompleter.h> +#include <qmljseditor/qmljseditordocument.h> +#include <qmljseditor/qmljssemantichighlighter.h> +#include <qmljstools/qmljsindenter.h> + +#include <QAction> + +namespace QmlDesigner { + +BindingEditorWidget::BindingEditorWidget() + : m_context(new BindingEditorContext(this)) +{ + Core::ICore::addContextObject(m_context); + + const Core::Context context(BINDINGEDITOR_CONTEXT_ID); + + /* + * We have to register our own active auto completion shortcut, because the original short cut will + * use the cursor position of the original editor in the editor manager. + */ + + m_completionAction = new QAction(tr("Trigger Completion"), this); + Core::Command *command = Core::ActionManager::registerAction( + m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); + command->setDefaultKeySequence(QKeySequence( + Core::useMacShortcuts + ? tr("Meta+Space") + : tr("Ctrl+Space"))); + + connect(m_completionAction, &QAction::triggered, [this]() { + invokeAssist(TextEditor::Completion); + }); +} + +BindingEditorWidget::~BindingEditorWidget() +{ + unregisterAutoCompletion(); + + Core::ICore::removeContextObject(m_context); + delete m_context; +} + +void BindingEditorWidget::unregisterAutoCompletion() +{ + if (m_completionAction) { + Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS); + delete m_completionAction; + m_completionAction = nullptr; + } +} + +bool BindingEditorWidget::event(QEvent *event) +{ + if (event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); + if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + emit returnKeyClicked(); + return true; + } else { + return QmlJSEditor::QmlJSEditorWidget::event(event); + } + } + return QmlJSEditor::QmlJSEditorWidget::event(event); +} + +TextEditor::AssistInterface *BindingEditorWidget::createAssistInterface( + TextEditor::AssistKind assistKind, TextEditor::AssistReason assistReason) const +{ + Q_UNUSED(assistKind) + return new QmlJSEditor::QmlJSCompletionAssistInterface( + document(), position(), QString(), + assistReason, qmljsdocument->semanticInfo()); +} + +BindingDocument::BindingDocument() + : QmlJSEditor::QmlJSEditorDocument(BINDINGEDITOR_CONTEXT_ID) + , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this)) +{ + +} + +BindingDocument::~BindingDocument() +{ + delete m_semanticHighlighter; +} + +void BindingDocument::applyFontSettings() +{ + TextDocument::applyFontSettings(); + m_semanticHighlighter->updateFontSettings(fontSettings()); + if (!isSemanticInfoOutdated()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +void BindingDocument::triggerPendingUpdates() +{ + TextDocument::triggerPendingUpdates(); // calls applyFontSettings if necessary + if (!isSemanticInfoOutdated()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +BindingEditorFactory::BindingEditorFactory() +{ + setId(BINDINGEDITOR_CONTEXT_ID); + setDisplayName(QCoreApplication::translate("OpenWith::Editors", QmlDesigner::BINDINGEDITOR_CONTEXT_ID)); + + setDocumentCreator([]() { return new BindingDocument; }); + setEditorWidgetCreator([]() { return new BindingEditorWidget; }); + setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; }); + setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; }); + setCommentDefinition(Utils::CommentDefinition::CppStyle); + setParenthesesMatchingEnabled(true); + setCodeFoldingSupported(true); + + addHoverHandler(new QmlJSEditor::QmlJSHoverHandler); + setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider); +} + +void BindingEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor) +{ + editor->textDocument()->setSyntaxHighlighter(new QmlJSEditor::QmlJSHighlighter); + editor->textDocument()->setIndenter(new QmlJSEditor::Internal::Indenter( + editor->textDocument()->document())); + editor->setAutoCompleter(new QmlJSEditor::AutoCompleter); +} + +} // QmlDesigner namespace diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h new file mode 100644 index 0000000000..597051d89f --- /dev/null +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifndef BINDINGEDITORWIDGET_H +#define BINDINGEDITORWIDGET_H + +#include <texteditor/texteditor.h> +#include <qmljseditor/qmljseditordocument.h> +#include <qmljseditor/qmljssemantichighlighter.h> +#include <qmljseditor/qmljseditor.h> + +#include <QtQml> +#include <QWidget> +#include <QDialog> + +namespace QmlDesigner { + +const char BINDINGEDITOR_CONTEXT_ID[] = "BindingEditor.BindingEditorContext"; + + +class BindingEditorContext : public Core::IContext +{ + Q_OBJECT + +public: + BindingEditorContext(QWidget *parent) : Core::IContext(parent) + { + setWidget(parent); + } +}; + +class BindingEditorWidget : public QmlJSEditor::QmlJSEditorWidget +{ + Q_OBJECT + +public: + BindingEditorWidget(); + ~BindingEditorWidget() override; + + void unregisterAutoCompletion(); + + bool event(QEvent *event) override; + + TextEditor::AssistInterface *createAssistInterface(TextEditor::AssistKind assistKind, + TextEditor::AssistReason assistReason) const override; + +signals: + void returnKeyClicked(); + +public: + QmlJSEditor::QmlJSEditorDocument *qmljsdocument = nullptr; + BindingEditorContext *m_context = nullptr; + QAction *m_completionAction = nullptr; +}; + +class BindingDocument : public QmlJSEditor::QmlJSEditorDocument +{ +public: + BindingDocument(); + ~BindingDocument(); + +protected: + void applyFontSettings(); + + void triggerPendingUpdates(); + +private: + QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr; +}; + + +class BindingEditorFactory : public TextEditor::TextEditorFactory +{ +public: + BindingEditorFactory(); + + static void decorateEditor(TextEditor::TextEditorWidget *editor); +}; + +} + +#endif //BINDINGEDITORWIDGET_H diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index f225128a01..b0f0c7637f 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -54,6 +54,7 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent) setScene(&m_scene); setAlignment(Qt::AlignLeft | Qt::AlignVCenter); setResizeAnchor(QGraphicsView::NoAnchor); + setRenderHint(QPainter::Antialiasing, true); setTransformationAnchor(QGraphicsView::NoAnchor); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 76af5b8013..67b36c6e72 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -24,6 +24,7 @@ ****************************************************************************/ #pragma once +#include <QSet> #include <QtCore/qobject.h> #include <QtCore/qstringlist.h> #include <QtCore/qhash.h> diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 4ebac8ce31..736d4ed52c 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -630,6 +630,10 @@ Project { files: [ "bindingeditor/bindingeditor.cpp", "bindingeditor/bindingeditor.h", + "bindingeditor/bindingeditordialog.cpp", + "bindingeditor/bindingeditordialog.h", + "bindingeditor/bindingeditorwidget.cpp", + "bindingeditor/bindingeditorwidget.h", "colortool/colortool.cpp", "colortool/colortool.h", "connectioneditor/addnewbackenddialog.h", diff --git a/src/shared/designerintegrationv2/formresizer.cpp b/src/shared/designerintegrationv2/formresizer.cpp index 34de90a477..354c7b4f46 100644 --- a/src/shared/designerintegrationv2/formresizer.cpp +++ b/src/shared/designerintegrationv2/formresizer.cpp @@ -42,14 +42,13 @@ using namespace SharedTools::Internal; FormResizer::FormResizer(QWidget *parent) : QWidget(parent), - m_frame(new QFrame), - m_formWindow(0) + m_frame(new QFrame) { // Make the resize grip of a mainwindow form find us as resizable window. setWindowFlags(windowFlags() | Qt::SubWindow); setBackgroundRole(QPalette::Base); - QVBoxLayout *handleLayout = new QVBoxLayout(this); + auto handleLayout = new QVBoxLayout(this); handleLayout->setContentsMargins(SELECTION_MARGIN, SELECTION_MARGIN, SELECTION_MARGIN, SELECTION_MARGIN); handleLayout->addWidget(m_frame); @@ -166,7 +165,7 @@ QWidget *FormResizer::mainContainer() { if (m_formWindow) return m_formWindow->mainContainer(); - return 0; + return nullptr; } void FormResizer::mainContainerChanged() diff --git a/src/shared/designerintegrationv2/formresizer.h b/src/shared/designerintegrationv2/formresizer.h index aad1a57b0f..a1bdf02161 100644 --- a/src/shared/designerintegrationv2/formresizer.h +++ b/src/shared/designerintegrationv2/formresizer.h @@ -60,7 +60,7 @@ class FormResizer : public QWidget Q_OBJECT public: - FormResizer(QWidget *parent = 0); + FormResizer(QWidget *parent = nullptr); void updateGeometry(); void setState(SelectionHandleState st); @@ -84,7 +84,7 @@ private: QFrame *m_frame; typedef QVector<SizeHandleRect*> Handles; Handles m_handles; - QDesignerFormWindowInterface * m_formWindow; + QDesignerFormWindowInterface *m_formWindow = nullptr; }; } diff --git a/src/shared/designerintegrationv2/widgethost.cpp b/src/shared/designerintegrationv2/widgethost.cpp index ed7f2fb91d..3ce7975c03 100644 --- a/src/shared/designerintegrationv2/widgethost.cpp +++ b/src/shared/designerintegrationv2/widgethost.cpp @@ -41,7 +41,6 @@ using namespace SharedTools; // ---------- WidgetHost WidgetHost::WidgetHost(QWidget *parent, QDesignerFormWindowInterface *formWindow) : QScrollArea(parent), - m_formWindow(0), m_formResizer(new Internal::FormResizer) { setWidget(m_formResizer); @@ -52,8 +51,7 @@ WidgetHost::WidgetHost(QWidget *parent, QDesignerFormWindowInterface *formWindow WidgetHost::~WidgetHost() { - if (m_formWindow) - delete m_formWindow; + delete m_formWindow; } void WidgetHost::setFormWindow(QDesignerFormWindowInterface *fw) @@ -75,7 +73,7 @@ void WidgetHost::setFormWindow(QDesignerFormWindowInterface *fw) QSize WidgetHost::formWindowSize() const { if (!m_formWindow || !m_formWindow->mainContainer()) - return QSize(); + return {}; return m_formWindow->mainContainer()->size(); } diff --git a/src/shared/designerintegrationv2/widgethost.h b/src/shared/designerintegrationv2/widgethost.h index ccf8590e91..1545509493 100644 --- a/src/shared/designerintegrationv2/widgethost.h +++ b/src/shared/designerintegrationv2/widgethost.h @@ -60,7 +60,7 @@ private slots: private: QSize formWindowSize() const; - QDesignerFormWindowInterface *m_formWindow; + QDesignerFormWindowInterface *m_formWindow = nullptr; Internal::FormResizer *m_formResizer; QSize m_oldFakeWidgetSize; }; diff --git a/src/shared/qbs b/src/shared/qbs -Subproject de04ecbbf59b361320a174ee0117c2cfa8c1001 +Subproject 491b293b07e59f69f2c8d9721ac6a098844d590 diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index b62d063e62..e2475a3ae7 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -108,10 +108,11 @@ extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet SOURCES_PREFIX "${SRCDIR}/qml2puppet/editor3d" SOURCES - cameracontrolhelper.cpp cameracontrolhelper.h + generalhelper.cpp generalhelper.h mousearea3d.cpp mousearea3d.h camerageometry.cpp camerageometry.h gridgeometry.cpp gridgeometry.h + selectionboxgeometry.cpp selectionboxgeometry.h ) extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index ca1c3654fb..fe42083d6e 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -197,14 +197,16 @@ QtcTool { "instances/qt5testnodeinstanceserver.h", "instances/servernodeinstance.cpp", "instances/servernodeinstance.h", - "editor3d/cameracontrolhelper.cpp", - "editor3d/cameracontrolhelper.h", + "editor3d/generalhelper.cpp", + "editor3d/generalhelper.h", "editor3d/mousearea3d.cpp", "editor3d/mousearea3d.h", "editor3d/camerageometry.cpp", "editor3d/camerageometry.h", "editor3d/gridgeometry.cpp", "editor3d/gridgeometry.h", + "editor3d/selectionboxgeometry.cpp", + "editor3d/selectionboxgeometry.h", "qml2puppetmain.cpp", ] } |