summaryrefslogtreecommitdiff
path: root/share/qtcreator/qml
diff options
context:
space:
mode:
Diffstat (limited to 'share/qtcreator/qml')
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml3
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml133
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml (renamed from share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h)66
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml25
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml128
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml197
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/HelperGrid.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml31
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml19
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml9
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml3
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml66
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/ToggleButton.qml70
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/ToolBarButton.qml6
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient.pngbin0 -> 1054 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient@2x.pngbin0 -> 1268 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.pngbin0 -> 1420 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient@2x.pngbin0 -> 3367 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.pngbin0 -> 1189 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off@2x.pngbin0 -> 1430 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.pngbin0 -> 1355 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on@2x.pngbin0 -> 1766 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.pngbin0 -> 266 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.pngbin0 -> 386 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.pngbin0 -> 266 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.pngbin0 -> 386 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/global.pngbin0 -> 433 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.pngbin0 -> 561 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/local.pngbin0 -> 1309 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.pngbin0 -> 1960 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.pngbin0 -> 1310 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.pngbin0 -> 1727 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.pngbin0 -> 1391 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.pngbin0 -> 1971 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.pngbin0 -> 1177 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient@2x.pngbin0 -> 2634 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.meshbin0 -> 158516 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp78
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri10
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp210
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h80
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp19
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp336
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h90
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp32
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp60
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h1
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc28
53 files changed, 1459 insertions, 263 deletions
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
new file mode 100644
index 0000000000..bd6404a36c
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient.png
Binary files differ
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
new file mode 100644
index 0000000000..463f3ac481
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/area_light_gradient@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png
new file mode 100644
index 0000000000..f3c013e157
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient.png
Binary files differ
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
new file mode 100644
index 0000000000..87d60515f5
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/directional_light_gradient@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png
new file mode 100644
index 0000000000..73e6e92374
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off.png
Binary files differ
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
new file mode 100644
index 0000000000..5166264e16
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_off@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png
new file mode 100644
index 0000000000..7660c28546
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on.png
Binary files differ
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
new file mode 100644
index 0000000000..836bd2a0d5
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/edit_light_on@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png
new file mode 100644
index 0000000000..056e9ec3c8
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png
new file mode 100644
index 0000000000..4b05f83d46
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_active@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png
new file mode 100644
index 0000000000..b8f98d9f12
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png
new file mode 100644
index 0000000000..eac4361253
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/fit_selected@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png
new file mode 100644
index 0000000000..1bd09c680a
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png
new file mode 100644
index 0000000000..a2a857fb10
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/global@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png
new file mode 100644
index 0000000000..0a608f6816
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png
new file mode 100644
index 0000000000..a5c931e750
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/local@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png
new file mode 100644
index 0000000000..35b36203fa
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png
new file mode 100644
index 0000000000..443c73e444
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/ortho@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png
new file mode 100644
index 0000000000..9a48e76399
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png
new file mode 100644
index 0000000000..88a4eab9c6
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/persp@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png
new file mode 100644
index 0000000000..5136b39fc2
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient.png
Binary files differ
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
new file mode 100644
index 0000000000..ccbfb1c846
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/point_light_gradient@2x.png
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
new file mode 100644
index 0000000000..3e9e4958e4
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh
Binary files differ
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 &currentPos)
+{
+ 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 &currentPos,
+ 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 &currentPos);
+ Q_INVOKABLE QVector3D panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform,
+ const QVector3D &startPosition, const QVector3D &startLookAt,
+ const QVector3D &pressPos, const QVector3D &currentPos,
+ 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>