diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-10-30 10:52:51 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-11-01 08:49:12 +0000 |
commit | 97788c457eed2bb7e97eadf87900f9bef9329e78 (patch) | |
tree | dd124e00e52168b36d9d19a23e465e1526a6a3fa | |
parent | d4797587b12944ccb0880115dc550127e2a1470e (diff) | |
download | qt-creator-97788c457eed2bb7e97eadf87900f9bef9329e78.tar.gz |
QmlDesigner: MoveGizmo improvements in 3D edit view
Mouse press and release are now properly handled by MouseArea3D.
This fixes various issues:
- No need to move the mouse after release for release to register.
- Drag is no longer limited to the 3D edit window, though it is still
limited to the screen.
- Drag arrows no longer register start of drag if you click outside
the arrow and then move the cursor over the arrow while holding the
mouse button down.
Also added the missing center ball to the MoveGizmo to allow free
dragging along the camera plane.
Change-Id: Iab55ae79f8af024534510e5fd29379532ac74025
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
5 files changed, 237 insertions, 82 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index 74eaeac509..0176a55dfa 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -35,7 +35,7 @@ Model { property View3D view3D property alias color: material.emissiveColor property Node targetNode: null - property bool isDragging: false + property bool dragging: false readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering @@ -47,7 +47,7 @@ Model { materials: DefaultMaterial { id: material - emissiveColor: mouseAreaFront.hovering ? "white" : Qt.rgba(1.0, 0.0, 0.0, 1.0) + emissiveColor: "white" lighting: DefaultMaterial.NoLighting } @@ -60,7 +60,7 @@ Model { _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); var sp = targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); - isDragging = true; + dragging = true; } function posInParent(mouseArea, pointerPosition) @@ -95,7 +95,7 @@ Model { return; targetNode.position = posInParent(mouseArea, pointerPosition); - isDragging = false; + dragging = false; arrow.positionCommit(); } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index b4a86490c5..e19e75acb8 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -112,11 +112,7 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) - - rotation: globalControl.checked || !viewWindow.selectedNode - ? Qt.vector3d(0, 0, 0) - : viewWindow.selectedNode.sceneRotation - + globalOrientation: globalControl.checked visible: selectedNode view3D: overlayView @@ -194,7 +190,7 @@ Window { targetView: overlayView offsetX: 0 offsetY: 45 - visible: moveGizmo.isDragging + visible: moveGizmo.dragging Rectangle { color: "white" diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml index ded8acc7d3..7ad5a2a011 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -25,56 +25,131 @@ import QtQuick 2.0 import QtQuick3D 1.0 +import MouseArea3D 1.0 Node { - id: arrows + id: moveGizmo property View3D view3D property bool highlightOnHover: false property Node targetNode: null - readonly property bool isDragging: arrowX.isDragging || arrowY.isDragging || arrowZ.isDragging - - scale: Qt.vector3d(5, 5, 5) + property bool globalOrientation: true + readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging + || centerMouseArea.dragging signal positionCommit() signal positionMove() - Arrow { - id: arrowX - objectName: "Arrow X" - rotation: Qt.vector3d(0, 0, -90) - 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() - onPositionMove: arrows.positionMove() - } + Node { + rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation + + Arrow { + id: arrowX + objectName: "Arrow X" + rotation: Qt.vector3d(0, 0, -90) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) + : Qt.rgba(1, 0, 0, 1) + view3D: moveGizmo.view3D + + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } + + Arrow { + id: arrowY + objectName: "Arrow Y" + rotation: Qt.vector3d(0, 0, 0) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) + : Qt.rgba(0, 0, 1, 1) + view3D: moveGizmo.view3D + + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } + + Arrow { + id: arrowZ + objectName: "Arrow Z" + rotation: Qt.vector3d(90, 0, 0) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + : Qt.rgba(0, 0.6, 0, 1) + view3D: moveGizmo.view3D + + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } - Arrow { - id: arrowY - objectName: "Arrow Y" - rotation: Qt.vector3d(0, 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() - onPositionMove: arrows.positionMove() } - Arrow { - id: arrowZ - objectName: "Arrow Z" - rotation: Qt.vector3d(90, 0, 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() - onPositionMove: arrows.positionMove() + Model { + id: centerBall + + source: "#Sphere" + scale: Qt.vector3d(0.024, 0.024, 0.024) + materials: DefaultMaterial { + id: material + emissiveColor: highlightOnHover + && (centerMouseArea.hovering || centerMouseArea.dragging) + ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1)) + : Qt.rgba(0.5, 0.5, 0.5, 1) + lighting: DefaultMaterial.NoLighting + } + + MouseArea3D { + id: centerMouseArea + view3D: moveGizmo.view3D + x: -60 + y: -60 + width: 120 + height: 120 + rotation: view3D.camera.rotation + grabsMouse: moveGizmo.targetNode + priority: 1 + + property var _pointerPosPressed + property var _targetStartPos + + function posInParent(pointerPosition) + { + var scenePointerPos = mapPositionToScene(pointerPosition); + 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 moveGizmo.targetNode.parent.mapPositionFromScene(newScenePos); + } + + onPressed: { + if (!moveGizmo.targetNode) + return; + + _pointerPosPressed = mapPositionToScene(pointerPosition); + var sp = moveGizmo.targetNode.scenePosition; + _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); + } + onDragged: { + if (!moveGizmo.targetNode) + return; + + moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.positionMove(); + } + onReleased: { + if (!moveGizmo.targetNode) + return; + + moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.positionCommit(); + } + } } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp index e3ec5c704b..4c1fdcc78e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -80,6 +80,11 @@ qreal MouseArea3D::height() const return m_height; } +int MouseArea3D::priority() const +{ + return m_priority; +} + void MouseArea3D::setView3D(QQuick3DViewport *view3D) { if (m_view3D == view3D) @@ -134,6 +139,15 @@ void MouseArea3D::setHeight(qreal height) emit heightChanged(height); } +void MouseArea3D::setPriority(int level) +{ + if (m_priority == level) + return; + + m_priority = level; + emit priorityChanged(level); +} + void MouseArea3D::componentComplete() { if (!m_view3D) { @@ -193,51 +207,94 @@ QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const bool MouseArea3D::eventFilter(QObject *, QEvent *event) { + if (m_grabsMouse && s_mouseGrab && s_mouseGrab != this + && (m_priority <= s_mouseGrab->m_priority || s_mouseGrab->m_dragging)) { + return false; + } + + auto mouseOnTopOfMouseArea = [this](const QVector3D &mousePosInPlane) -> bool { + return !qFuzzyCompare(mousePosInPlane.z(), -1) + && mousePosInPlane.x() >= float(m_x) + && mousePosInPlane.x() <= float(m_x + m_width) + && mousePosInPlane.y() >= float(m_y) + && mousePosInPlane.y() <= float(m_y + m_height); + }; + switch (event->type()) { + case QEvent::MouseButtonPress: { + auto const mouseEvent = static_cast<QMouseEvent *>(event); + if (mouseEvent->button() == Qt::LeftButton) { + m_mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); + if (mouseOnTopOfMouseArea(m_mousePosInPlane)) { + setDragging(true); + emit pressed(m_mousePosInPlane); + if (m_grabsMouse) { + if (s_mouseGrab && s_mouseGrab != this) { + s_mouseGrab->setDragging(false); + s_mouseGrab->setHovering(false); + } + s_mouseGrab = this; + setHovering(true); + } + event->accept(); + return true; + } + } + break; + } + case QEvent::MouseButtonRelease: { + auto const mouseEvent = static_cast<QMouseEvent *>(event); + if (mouseEvent->button() == Qt::LeftButton) { + if (m_dragging) { + QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); + if (qFuzzyCompare(mousePosInPlane.z(), -1)) + mousePosInPlane = m_mousePosInPlane; + setDragging(false); + emit released(mousePosInPlane); + if (m_grabsMouse) { + if (s_mouseGrab && s_mouseGrab != this) { + s_mouseGrab->setDragging(false); + s_mouseGrab->setHovering(false); + } + if (mouseOnTopOfMouseArea(mousePosInPlane)) { + s_mouseGrab = this; + setHovering(true); + } else { + s_mouseGrab = nullptr; + setHovering(false); + } + } + event->accept(); + return true; + } + } + break; + } + case QEvent::MouseMove: 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 hasMouse = mouseOnTopOfMouseArea(mousePosInPlane); - const bool buttonPressed = QGuiApplication::mouseButtons().testFlag(Qt::LeftButton); + setHovering(hasMouse); - // 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_grabsMouse) { + if (m_hovering && s_mouseGrab && s_mouseGrab != this) + s_mouseGrab->setHovering(false); - if (m_hovering != mouseOnTopOfMouseArea) { - m_hovering = mouseOnTopOfMouseArea; - emit hoveringChanged(); + if (m_hovering || m_dragging) + s_mouseGrab = this; + else if (s_mouseGrab == this) + s_mouseGrab = nullptr; } - 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) + if (m_dragging && !qFuzzyCompare(mousePosInPlane.z(), -1)) { + m_mousePosInPlane = mousePosInPlane; emit dragged(mousePosInPlane); + } - break; } + break; + } default: break; } @@ -245,6 +302,24 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event) return false; } +void MouseArea3D::setDragging(bool enable) +{ + if (m_dragging == enable) + return; + + m_dragging = enable; + emit draggingChanged(); +} + +void MouseArea3D::setHovering(bool enable) +{ + if (m_hovering == enable) + return; + + m_hovering = enable; + emit hoveringChanged(); +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h index b42b438b47..99a34be353 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h @@ -48,6 +48,7 @@ class MouseArea3D : public QQuick3DNode 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_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged) Q_INTERFACES(QQmlParserStatus) @@ -60,6 +61,7 @@ public: qreal y() const; qreal width() const; qreal height() const; + int priority() const; bool hovering() const; bool dragging() const; @@ -73,6 +75,7 @@ public slots: void setY(qreal y); void setWidth(qreal width); void setHeight(qreal height); + void setPriority(int level); Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0, const QVector3D &rayPos1, @@ -86,6 +89,7 @@ signals: void yChanged(qreal y); void widthChanged(qreal width); void heightChanged(qreal height); + void priorityChanged(int level); void hoveringChanged(); void draggingChanged(); @@ -100,6 +104,9 @@ protected: bool eventFilter(QObject *obj, QEvent *event) override; private: + void setDragging(bool enable); + void setHovering(bool enable); + Q_DISABLE_COPY(MouseArea3D) QQuick3DViewport *m_view3D = nullptr; @@ -107,6 +114,7 @@ private: qreal m_y; qreal m_width; qreal m_height; + int m_priority = 0; bool m_hovering = false; bool m_dragging = false; @@ -115,6 +123,7 @@ private: static MouseArea3D *s_mouseGrab; bool m_grabsMouse; + QVector3D m_mousePosInPlane; }; } |