diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-10-23 16:02:56 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-10-25 07:51:09 +0000 |
commit | 1fe204565a681d8882475327647f127f70509523 (patch) | |
tree | 3154fbd3cace708e068c2d48d3f6febf9523fa81 /share/qtcreator/qml | |
parent | 44ddca544caa61f290d502fdf62f5bdbaf2b4f34 (diff) | |
download | qt-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')
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 Binary files differnew file mode 100644 index 0000000000..f872b5e008 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh 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> |