summaryrefslogtreecommitdiff
path: root/share/qtcreator/qml
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-23 16:02:56 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-25 07:51:09 +0000
commit1fe204565a681d8882475327647f127f70509523 (patch)
tree3154fbd3cace708e068c2d48d3f6febf9523fa81 /share/qtcreator/qml
parent44ddca544caa61f290d502fdf62f5bdbaf2b4f34 (diff)
downloadqt-creator-1fe204565a681d8882475327647f127f70509523.tar.gz
QmlDesigner: Add support for move gadget to 3D edit view
This proof-of-concept move gadget is based on the move gadget in studio example of QtQuick3D. Change-Id: I1b596443a3e99c16ed214bc464c5367a0f7aa503 Fixes: QDS-1125 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Pasi Keränen <pasi.keranen@qt.io>
Diffstat (limited to 'share/qtcreator/qml')
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml126
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml85
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml98
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml79
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.meshbin0 -> 6356 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri7
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp251
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h125
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp32
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h3
-rw-r--r--share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc4
11 files changed, 781 insertions, 29 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml
new file mode 100644
index 0000000000..7c9ef09589
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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 MouseArea3D 1.0
+
+Model {
+ id: arrow
+ rotationOrder: Node.XYZr
+ source: "meshes/Arrow.mesh"
+
+ property View3D view3D
+ property alias color: material.emissiveColor
+ property Node targetNode: null
+
+ readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering
+
+ property var _pointerPosPressed
+ property var _targetStartPos
+
+ signal positionCommit()
+
+ materials: DefaultMaterial {
+ id: material
+ emissiveColor: mouseAreaFront.hovering ? "white" : Qt.rgba(1.0, 0.0, 0.0, 1.0)
+ lighting: DefaultMaterial.NoLighting
+ }
+
+ function handlePressed(mouseArea, pointerPosition)
+ {
+ if (!targetNode)
+ return;
+
+ var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0);
+ _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition);
+ var sp = targetNode.positionInScene;
+ _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
+ }
+
+ function posInParent(mouseArea, pointerPosition)
+ {
+ var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0);
+ var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition);
+ var sceneRelativeDistance = Qt.vector3d(
+ scenePointerPos.x - _pointerPosPressed.x,
+ scenePointerPos.y - _pointerPosPressed.y,
+ scenePointerPos.z - _pointerPosPressed.z);
+
+ var newScenePos = Qt.vector3d(
+ _targetStartPos.x + sceneRelativeDistance.x,
+ _targetStartPos.y + sceneRelativeDistance.y,
+ _targetStartPos.z + sceneRelativeDistance.z);
+
+ return targetNode.parent.mapPositionFromScene(newScenePos);
+ }
+
+ function handleDragged(mouseArea, pointerPosition)
+ {
+ if (!targetNode)
+ return;
+
+ targetNode.position = posInParent(mouseArea, pointerPosition);
+ }
+
+ function handleReleased(mouseArea, pointerPosition)
+ {
+ if (!targetNode)
+ return;
+
+ targetNode.position = posInParent(mouseArea, pointerPosition);
+ arrow.positionCommit();
+ }
+
+ MouseArea3D {
+ id: mouseAreaYZ
+ view3D: arrow.view3D
+ x: 0
+ y: -1.5
+ width: 12
+ height: 3
+ rotation: Qt.vector3d(0, 90, 0)
+ grabsMouse: targetNode
+ onPressed: arrow.handlePressed(mouseAreaYZ, pointerPosition)
+ onDragged: arrow.handleDragged(mouseAreaYZ, pointerPosition)
+ onReleased: arrow.handleReleased(mouseAreaYZ, pointerPosition)
+ }
+
+ MouseArea3D {
+ id: mouseAreaXZ
+ view3D: arrow.view3D
+ x: 0
+ y: -1.5
+ width: 12
+ height: 3
+ rotation: Qt.vector3d(90, 90, 0)
+ grabsMouse: targetNode
+ onPressed: arrow.handlePressed(mouseAreaXZ, pointerPosition)
+ onDragged: arrow.handleDragged(mouseAreaXZ, pointerPosition)
+ onReleased: arrow.handleReleased(mouseAreaXZ, pointerPosition)
+ }
+
+}
+
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml
new file mode 100644
index 0000000000..c8d21604d3
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 MouseArea3D 1.0
+
+Node {
+ id: overlayNode
+
+ property View3D view3D
+ property Node target: parent
+ property bool autoScale: true
+
+ // Read-only
+ property real relativeScale: 1
+
+ onGlobalTransformChanged: updateScale()
+ onAutoScaleChanged: updateScale()
+ Connections {
+ target: view3D.camera
+ onGlobalTransformChanged: updateScale()
+ }
+
+ Connections {
+ target: window
+ onFirstFrameReady: updateScale()
+ }
+
+ function getScale(baseScale)
+ {
+ return Qt.vector3d(baseScale.x * relativeScale, baseScale.y * relativeScale,
+ baseScale.z * relativeScale);
+ }
+
+ function updateScale()
+ {
+ if (!autoScale) {
+ target.scale = Qt.vector3d(1, 1, 1);
+ } else {
+ // Calculate the distance independent scale by first mapping the targets position to
+ // the view. We then measure up a distance on the view (100px) that we use as an
+ // "anchor" distance. Map the two positions back to the target node, and measure the
+ // distance between them now, in the 3D scene. The difference of the two distances,
+ // view and scene, will tell us what the distance independent scale should be.
+ var posInView1 = view3D.mapFrom3DScene(positionInScene);
+ var posInView2 = Qt.vector3d(posInView1.x + 100, posInView1.y, posInView1.z);
+
+ var rayPos1 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 0));
+ var rayPos2 = view3D.mapTo3DScene(Qt.vector3d(posInView2.x, posInView2.y, 10));
+
+ var planeNormal = view3D.camera.forward;
+ var rayHitPos = helper.rayIntersectsPlane(rayPos1, rayPos2, positionInScene,
+ planeNormal);
+ relativeScale = positionInScene.minus(rayHitPos).length() / 100;
+ }
+ }
+
+ MouseArea3D {
+ id: helper
+ view3D: overlayNode.view3D
+ }
+}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
index b9849d484c..b0ec597cba 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
@@ -42,7 +42,46 @@ Window {
property alias showEditLight: editLightCheckbox.checked
property alias usePerspective: usePerspectiveCheckbox.checked
+ property Node selectedNode: null
+
signal objectClicked(var object)
+ signal commitObjectPosition(var object)
+
+ Node {
+ id: overlayScene
+
+ Camera {
+ id: overlayCamera
+ projectionMode: usePerspectiveCheckbox.checked ? Camera.Perspective
+ : Camera.Orthographic
+ clipFar: editCamera.clipFar
+ position: editCamera.position
+ rotation: editCamera.rotation
+ }
+
+ MoveGizmo {
+ id: moveGizmo
+ scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
+ highlightOnHover: true
+ targetNode: viewWindow.selectedNode
+ position: viewWindow.selectedNode ? viewWindow.selectedNode.positionInScene
+ : Qt.vector3d(0, 0, 0)
+ rotation: globalControl.checked || !viewWindow.selectedNode
+ ? Qt.vector3d(0, 0, 0)
+ : viewWindow.selectedNode.rotationInScene
+
+ visible: selectedNode
+ view3D: overlayView
+
+ onPositionCommit: viewWindow.commitObjectPosition(selectedNode)
+ }
+
+ AutoScaleHelper {
+ id: autoScale
+ view3D: overlayView
+ position: moveGizmo.positionInScene
+ }
+ }
Rectangle {
id: sceneBg
@@ -55,39 +94,45 @@ Window {
var pickResult = editView.pick(eventPoint.scenePosition.x,
eventPoint.scenePosition.y);
viewWindow.objectClicked(pickResult.objectHit);
+ selectedNode = pickResult.objectHit; // TODO selection needs to come from studio
}
}
View3D {
id: editView
anchors.fill: parent
- enableWireframeMode: true
camera: editCamera
- AxisHelper {
- id: axisGrid
- enableXZGrid: true
- enableAxisLines: false
- }
-
- PointLight {
- id: pointLight
- visible: showEditLight
- position: editCamera.position
- }
-
- Camera {
- id: editCamera
- y: 200
- z: -300
- clipFar: 100000
- projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic
+ Node {
+ id: mainSceneHelpers
+
+ AxisHelper {
+ id: axisGrid
+ enableXZGrid: true
+ enableAxisLines: false
+ }
+
+ PointLight {
+ id: pointLight
+ visible: showEditLight
+ position: editCamera.position
+ }
+
+ Camera {
+ id: editCamera
+ y: 200
+ z: -300
+ clipFar: 100000
+ projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic
+ }
}
+ }
- Component.onCompleted: {
- pointLight.setParentItem(editView.scene);
- editCamera.setParentItem(editView.scene);
- }
+ View3D {
+ id: overlayView
+ anchors.fill: parent
+ camera: overlayCamera
+ scene: overlayScene
}
WasdController {
@@ -121,6 +166,13 @@ Window {
text: qsTr("Use Perspective Projection")
onCheckedChanged: cameraControl.forceActiveFocus()
}
+
+ CheckBox {
+ id: globalControl
+ checked: true
+ text: qsTr("Use global orientation")
+ onCheckedChanged: cameraControl.forceActiveFocus()
+ }
}
Text {
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml
new file mode 100644
index 0000000000..62a4e9e7c7
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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
+
+Node {
+ id: arrows
+
+ property View3D view3D
+ property bool highlightOnHover: false
+ property Node targetNode: null
+
+ scale: Qt.vector3d(5, 5, 5)
+
+ property alias arrowX: arrowX
+ property alias arrowY: arrowY
+ property alias arrowZ: arrowZ
+
+ signal positionCommit()
+
+ Arrow {
+ id: arrowX
+ objectName: "Arrow X"
+ rotation: Qt.vector3d(0, -90, 0)
+ targetNode: arrows.targetNode
+ color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(1, 0, 0, 1))
+ : Qt.rgba(1, 0, 0, 1)
+ view3D: arrows.view3D
+
+ onPositionCommit: arrows.positionCommit()
+ }
+
+ Arrow {
+ id: arrowY
+ objectName: "Arrow Y"
+ rotation: Qt.vector3d(90, 0, 0)
+ targetNode: arrows.targetNode
+ color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0, 1, 1))
+ : Qt.rgba(0, 0, 1, 1)
+ view3D: arrows.view3D
+
+ onPositionCommit: arrows.positionCommit()
+ }
+
+ Arrow {
+ id: arrowZ
+ objectName: "Arrow Z"
+ rotation: Qt.vector3d(0, 180, 0)
+ targetNode: arrows.targetNode
+ color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1))
+ : Qt.rgba(0, 0.6, 0, 1)
+ view3D: arrows.view3D
+
+ onPositionCommit: arrows.positionCommit()
+ }
+}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh
new file mode 100644
index 0000000000..f872b5e008
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh
Binary files differ
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri
index 7b86f8bc82..a052b7285c 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri
@@ -1,2 +1,5 @@
-HEADERS += $$PWD/cameracontrolhelper.h
-SOURCES += $$PWD/cameracontrolhelper.cpp
+HEADERS += $$PWD/cameracontrolhelper.h \
+ $$PWD/mousearea3d.h
+
+SOURCES += $$PWD/cameracontrolhelper.cpp \
+ $$PWD/mousearea3d.cpp
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
new file mode 100644
index 0000000000..e3ec5c704b
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** 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 "mousearea3d.h"
+
+#include <QtGui/qguiapplication.h>
+#include <QtQml/qqmlinfo.h>
+
+namespace QmlDesigner {
+namespace Internal {
+
+MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
+
+MouseArea3D::MouseArea3D(QQuick3DNode *parent)
+ : QQuick3DNode(parent)
+{
+}
+
+QQuick3DViewport *MouseArea3D::view3D() const
+{
+ return m_view3D;
+}
+
+bool MouseArea3D::hovering() const
+{
+ return m_hovering;
+}
+
+bool MouseArea3D::dragging() const
+{
+ return m_dragging;
+}
+
+bool MouseArea3D::grabsMouse() const
+{
+ return m_grabsMouse;
+}
+
+qreal MouseArea3D::x() const
+{
+ return m_x;
+}
+
+qreal MouseArea3D::y() const
+{
+ return m_y;
+}
+
+qreal MouseArea3D::width() const
+{
+ return m_width;
+}
+
+qreal MouseArea3D::height() const
+{
+ return m_height;
+}
+
+void MouseArea3D::setView3D(QQuick3DViewport *view3D)
+{
+ if (m_view3D == view3D)
+ return;
+
+ m_view3D = view3D;
+ emit view3DChanged();
+}
+
+void MouseArea3D::setGrabsMouse(bool grabsMouse)
+{
+ if (m_grabsMouse == grabsMouse)
+ return;
+
+ m_grabsMouse = grabsMouse;
+ emit grabsMouseChanged(grabsMouse);
+}
+
+void MouseArea3D::setX(qreal x)
+{
+ if (qFuzzyCompare(m_x, x))
+ return;
+
+ m_x = x;
+ emit xChanged(x);
+}
+
+void MouseArea3D::setY(qreal y)
+{
+ if (qFuzzyCompare(m_y, y))
+ return;
+
+ m_y = y;
+ emit yChanged(y);
+}
+
+void MouseArea3D::setWidth(qreal width)
+{
+ if (qFuzzyCompare(m_width, width))
+ return;
+
+ m_width = width;
+ emit widthChanged(width);
+}
+
+void MouseArea3D::setHeight(qreal height)
+{
+ if (qFuzzyCompare(m_height, height))
+ return;
+
+ m_height = height;
+ emit heightChanged(height);
+}
+
+void MouseArea3D::componentComplete()
+{
+ if (!m_view3D) {
+ qmlDebug(this) << "property 'view3D' is not set!";
+ return;
+ }
+ m_view3D->setAcceptedMouseButtons(Qt::LeftButton);
+ m_view3D->setAcceptHoverEvents(true);
+ m_view3D->setAcceptTouchEvents(false);
+ m_view3D->installEventFilter(this);
+}
+
+QVector3D MouseArea3D::rayIntersectsPlane(const QVector3D &rayPos0,
+ const QVector3D &rayPos1,
+ const QVector3D &planePos,
+ const QVector3D &planeNormal) const
+{
+ QVector3D rayDirection = rayPos1 - rayPos0;
+ QVector3D rayPos0RelativeToPlane = rayPos0 - planePos;
+
+ float dotPlaneRayDirection = QVector3D::dotProduct(planeNormal, rayDirection);
+ float dotPlaneRayPos0 = -QVector3D::dotProduct(planeNormal, rayPos0RelativeToPlane);
+
+ if (qFuzzyIsNull(dotPlaneRayDirection)) {
+ // The ray is is parallel to the plane. Note that if dotLinePos0 == 0, it
+ // additionally means that the line lies in plane as well. In any case, we
+ // signal that we cannot find a single intersection point.
+ return QVector3D(0, 0, -1);
+ }
+
+ // Since we work with a ray (that has a start), distanceFromLinePos0ToPlane
+ // must be above 0. If it was a line segment (with an end), it also need to be less than 1.
+ // (Note: a third option would be a "line", which is different from a ray or segment in that
+ // it has neither a start, nor an end). Then we wouldn't need to check the distance at all.
+ // But that would also mean that the line could intersect the plane behind the camera, if
+ // the line were directed away from the plane when looking forward.
+ float distanceFromRayPos0ToPlane = dotPlaneRayPos0 / dotPlaneRayDirection;
+ if (distanceFromRayPos0ToPlane <= 0)
+ return QVector3D(0, 0, -1);
+ return rayPos0 + distanceFromRayPos0ToPlane * rayDirection;
+}
+
+QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const
+{
+ const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0);
+ const QVector3D mousePos2(float(mousePosInView.x()), float(mousePosInView.y()), 1);
+ const QVector3D rayPos0 = m_view3D->mapTo3DScene(mousePos1);
+ const QVector3D rayPos1 = m_view3D->mapTo3DScene(mousePos2);
+ const QVector3D globalPlanePosition = mapPositionToScene(QVector3D(0, 0, 0));
+ const QVector3D intersectGlobalPos = rayIntersectsPlane(rayPos0, rayPos1,
+ globalPlanePosition, forward());
+ if (qFuzzyCompare(intersectGlobalPos.z(), -1))
+ return intersectGlobalPos;
+
+ return mapPositionFromScene(intersectGlobalPos);
+}
+
+bool MouseArea3D::eventFilter(QObject *, QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::HoverMove: {
+ if (m_grabsMouse && s_mouseGrab && s_mouseGrab != this)
+ break;
+
+ auto const mouseEvent = static_cast<QMouseEvent *>(event);
+ const QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos());
+ if (qFuzzyCompare(mousePosInPlane.z(), -1))
+ break;
+
+ const bool mouseOnTopOfMouseArea =
+ mousePosInPlane.x() >= float(m_x) &&
+ mousePosInPlane.x() <= float(m_x + m_width) &&
+ mousePosInPlane.y() >= float(m_y) &&
+ mousePosInPlane.y() <= float(m_y + m_height);
+
+ const bool buttonPressed = QGuiApplication::mouseButtons().testFlag(Qt::LeftButton);
+
+ // The filter will detect a mouse press on the view, but not a mouse release, since the
+ // former is not accepted by the view, which means that the release will end up being
+ // sent elsewhere. So we need this extra logic inside HoverMove, rather than in
+ // MouseButtonRelease, which would otherwise be more elegant.
+
+ if (m_hovering != mouseOnTopOfMouseArea) {
+ m_hovering = mouseOnTopOfMouseArea;
+ emit hoveringChanged();
+ }
+
+ if (!m_dragging && m_hovering && buttonPressed) {
+ m_dragging = true;
+ emit pressed(mousePosInPlane);
+ emit draggingChanged();
+ } else if (m_dragging && !buttonPressed) {
+ m_dragging = false;
+ emit released(mousePosInPlane);
+ emit draggingChanged();
+ }
+
+ if (m_grabsMouse)
+ s_mouseGrab = m_hovering || m_dragging ? this : nullptr;
+
+ if (m_dragging)
+ emit dragged(mousePosInPlane);
+
+ break; }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+}
+}
+
+#endif // QUICK3D_MODULE
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h
new file mode 100644
index 0000000000..b42b438b47
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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 <QtGui/qvector3d.h>
+#include <QtCore/qpointer.h>
+
+#include <QtQuick3D/private/qquick3dnode_p.h>
+#include <QtQuick3D/private/qquick3dviewport_p.h>
+#include <QtQuick3D/private/qtquick3dglobal_p.h>
+
+namespace QmlDesigner {
+namespace Internal {
+
+class MouseArea3D : public QQuick3DNode
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuick3DViewport *view3D READ view3D WRITE setView3D NOTIFY view3DChanged)
+ Q_PROPERTY(bool grabsMouse READ grabsMouse WRITE setGrabsMouse NOTIFY grabsMouseChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged)
+ Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ MouseArea3D(QQuick3DNode *parent = nullptr);
+
+ QQuick3DViewport *view3D() const;
+
+ qreal x() const;
+ qreal y() const;
+ qreal width() const;
+ qreal height() const;
+
+ bool hovering() const;
+ bool dragging() const;
+ bool grabsMouse() const;
+
+public slots:
+ void setView3D(QQuick3DViewport *view3D);
+ void setGrabsMouse(bool grabsMouse);
+
+ void setX(qreal x);
+ void setY(qreal y);
+ void setWidth(qreal width);
+ void setHeight(qreal height);
+
+ Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0,
+ const QVector3D &rayPos1,
+ const QVector3D &planePos,
+ const QVector3D &planeNormal) const;
+
+signals:
+ void view3DChanged();
+
+ void xChanged(qreal x);
+ void yChanged(qreal y);
+ void widthChanged(qreal width);
+ void heightChanged(qreal height);
+
+ void hoveringChanged();
+ void draggingChanged();
+ void pressed(const QVector3D &pointerPosition);
+ void released(const QVector3D &pointerPosition);
+ void dragged(const QVector3D &pointerPosition);
+ void grabsMouseChanged(bool grabsMouse);
+
+protected:
+ void classBegin() override {}
+ void componentComplete() override;
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(MouseArea3D)
+ QQuick3DViewport *m_view3D = nullptr;
+
+ qreal m_x;
+ qreal m_y;
+ qreal m_width;
+ qreal m_height;
+
+ bool m_hovering = false;
+ bool m_dragging = false;
+
+ QVector3D getMousePosInPlane(const QPointF &mousePosInView) const;
+
+ static MouseArea3D *s_mouseGrab;
+ bool m_grabsMouse;
+};
+
+}
+}
+
+QML_DECLARE_TYPE(QmlDesigner::Internal::MouseArea3D)
+
+#endif // QUICK3D_MODULE
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 685136cb2d..0cb95c98d9 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -59,6 +59,7 @@
#include "dummycontextobject.h"
#include "../editor3d/cameracontrolhelper.h"
+#include "../editor3d/mousearea3d.h"
#include <designersupportdelegate.h>
@@ -77,9 +78,13 @@ static QVariant objectToVariant(QObject *object)
QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
{
- QmlDesigner::Internal::CameraControlHelper *helper = new QmlDesigner::Internal::CameraControlHelper();
+ auto helper = new QmlDesigner::Internal::CameraControlHelper();
engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper);
+#ifdef QUICK3D_MODULE
+ qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D");
+#endif
+
QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"));
QWindow *window = qobject_cast<QWindow *>(component.create());
@@ -90,6 +95,8 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
}
QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant)));
+ QObject::connect(window, SIGNAL(commitObjectPosition(QVariant)),
+ this, SLOT(handleObjectPositionCommit(QVariant)));
//For macOS we have to use the 4.1 core profile
QSurfaceFormat surfaceFormat = window->requestedFormat();
@@ -101,10 +108,29 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
return window;
}
-// an object is clicked in the 3D edit view
+// an object is clicked in the 3D edit view. Null object indicates selection clearing.
void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object)
{
- selectInstance(instanceForObject(object.value<QObject *>()));
+ auto obj = object.value<QObject *>();
+ ServerNodeInstance instance;
+ if (obj)
+ instance = instanceForObject(obj);
+ selectInstance(instance);
+}
+
+void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object)
+{
+ QObject *obj = object.value<QObject *>();
+ if (obj) {
+ ServerNodeInstance instance = instanceForObject(obj);
+ QVector<InstancePropertyValueTriple> modifiedpropertyList;
+ InstancePropertyValueTriple propTriple;
+ propTriple.instance = instance;
+ propTriple.propertyName = "position";
+ propTriple.propertyValue = obj->property(propTriple.propertyName.constData());
+ modifiedpropertyList.append(propTriple);
+ nodeInstanceClient()->valuesModified(createValuesModifiedCommand(modifiedpropertyList));
+ }
}
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
index 2e39339583..243b333904 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
@@ -44,8 +44,9 @@ public:
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
void changeSelection(const ChangeSelectionCommand &command) override;
-public slots:
+private slots:
void objectClicked(const QVariant &object);
+ void handleObjectPositionCommit(const QVariant &object);
protected:
void collectItemChangesAndSendChangeCommands() override;
diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
index 8354e475f1..001591a96d 100644
--- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
+++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc
@@ -8,5 +8,9 @@
<file>mockfiles/GenericBackend.qml</file>
<file>mockfiles/Dialog.qml</file>
<file>mockfiles/EditView3D.qml</file>
+ <file>mockfiles/Arrow.qml</file>
+ <file>mockfiles/AutoScaleHelper.qml</file>
+ <file>mockfiles/MoveGizmo.qml</file>
+ <file>mockfiles/meshes/Arrow.mesh</file>
</qresource>
</RCC>