diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-10-31 10:46:14 +0200 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-11-08 12:53:21 +0000 |
commit | c67965fb2932a129ba6aa87875007fd5b70b24fd (patch) | |
tree | 102dc22716b776fbe9a8e68ce5c4685bf84ee33c /share/qtcreator/qml/qmlpuppet | |
parent | 96f3cef06ac52f2cb82aa4078306c673a040f839 (diff) | |
download | qt-creator-c67965fb2932a129ba6aa87875007fd5b70b24fd.tar.gz |
QmlDesigner: Add ScaleGizmo to 3D edit view
ScaleGizmo allows scaling in the direction of local or global axes,
as well as uniform scaling. Any scale component cannot be made
negative with ScaleGizmo.
Change-Id: I9b98d9593e07ded340178b07b73fa1b72421ba20
Fixes: QDS-1195
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Diffstat (limited to 'share/qtcreator/qml/qmlpuppet')
12 files changed, 561 insertions, 138 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index 0176a55dfa..67ae4c7b29 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -27,104 +27,29 @@ import QtQuick 2.0 import QtQuick3D 1.0 import MouseArea3D 1.0 -Model { +DirectionalDraggable { id: arrow - rotationOrder: Node.XYZr source: "meshes/arrow.mesh" - property View3D view3D - property alias color: material.emissiveColor - property Node targetNode: null - property bool dragging: false - - readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering - - property var _pointerPosPressed - property var _targetStartPos - signal positionCommit() signal positionMove() - materials: DefaultMaterial { - id: material - emissiveColor: "white" - lighting: DefaultMaterial.NoLighting - } - - function handlePressed(mouseArea, pointerPosition) + function localPos(sceneRelativeDistance) { - if (!targetNode) - return; - - var maskedPosition = Qt.vector3d(pointerPosition.x, 0, 0); - _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); - var sp = targetNode.scenePosition; - _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); - dragging = true; - } - - 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); - arrow.positionMove(); - } - - function handleReleased(mouseArea, pointerPosition) - { - if (!targetNode) - return; - - targetNode.position = posInParent(mouseArea, pointerPosition); - dragging = false; - arrow.positionCommit(); + onDragged: { + targetNode.position = localPos(sceneRelativeDistance); + positionMove(); } - MouseArea3D { - id: mouseAreaYZ - view3D: arrow.view3D - x: 0 - y: -1.5 - width: 12 - height: 3 - rotation: Qt.vector3d(0, 0, 90) - 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(0, 90, 90) - grabsMouse: targetNode - onPressed: arrow.handlePressed(mouseAreaXZ, pointerPosition) - onDragged: arrow.handleDragged(mouseAreaXZ, pointerPosition) - onReleased: arrow.handleReleased(mouseAreaXZ, pointerPosition) + onReleased: { + targetNode.position = localPos(sceneRelativeDistance); + positionCommit(); } } - diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml new file mode 100644 index 0000000000..243744210e --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/DirectionalDraggable.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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: rootModel + rotationOrder: Node.XYZr + + property View3D view3D + property alias color: material.emissiveColor + property Node targetNode: null + property bool dragging: false + property bool active: false + + readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering + + property var _pointerPosPressed + property var _targetStartPos + + signal pressed(var mouseArea) + signal dragged(var mouseArea, vector3d sceneRelativeDistance) + signal released(var mouseArea, vector3d sceneRelativeDistance) + + materials: DefaultMaterial { + id: material + emissiveColor: "white" + lighting: DefaultMaterial.NoLighting + } + + function handlePressed(mouseArea, scenePos) + { + if (!targetNode) + return; + + var maskedPosition = Qt.vector3d(scenePos.x, 0, 0); + _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); + var sp = targetNode.scenePosition; + _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); + dragging = true; + pressed(mouseArea); + } + + function calcRelativeDistance(mouseArea, scenePos) + { + var maskedPosition = Qt.vector3d(scenePos.x, 0, 0); + var scenePointerPos = mouseArea.mapPositionToScene(maskedPosition); + return Qt.vector3d(scenePointerPos.x - _pointerPosPressed.x, + scenePointerPos.y - _pointerPosPressed.y, + scenePointerPos.z - _pointerPosPressed.z); + } + + function handleDragged(mouseArea, scenePos) + { + if (!targetNode) + return; + + dragged(mouseArea, calcRelativeDistance(mouseArea, scenePos)); + } + + function handleReleased(mouseArea, scenePos) + { + if (!targetNode) + return; + + released(mouseArea, calcRelativeDistance(mouseArea, scenePos)); + dragging = false; + } + + MouseArea3D { + id: mouseAreaYZ + view3D: rootModel.view3D + x: 0 + y: -1.5 + width: 12 + height: 3 + rotation: Qt.vector3d(0, 0, 90) + grabsMouse: targetNode + active: rootModel.active + onPressed: rootModel.handlePressed(mouseAreaYZ, scenePos) + onDragged: rootModel.handleDragged(mouseAreaYZ, scenePos) + onReleased: rootModel.handleReleased(mouseAreaYZ, scenePos) + } + + MouseArea3D { + id: mouseAreaXZ + view3D: rootModel.view3D + x: 0 + y: -1.5 + width: 12 + height: 3 + rotation: Qt.vector3d(0, 90, 90) + grabsMouse: targetNode + active: rootModel.active + onPressed: rootModel.handlePressed(mouseAreaXZ, scenePos) + onDragged: rootModel.handleDragged(mouseAreaXZ, scenePos) + onReleased: rootModel.handleReleased(mouseAreaXZ, scenePos) + } +} + diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index b227cee23e..1dcca048e7 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -48,8 +48,8 @@ Window { property var cameraGizmos: [] signal objectClicked(var object) - signal commitObjectPosition(var object) - signal moveObjectPosition(var object) + signal commitObjectProperty(var object, var propName) + signal changeObjectProperty(var object, var propName) function selectObject(object) { selectedNode = object; @@ -113,11 +113,26 @@ Window { position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) globalOrientation: globalControl.checked - visible: selectedNode + visible: selectedNode && moveToolControl.checked view3D: overlayView - onPositionCommit: viewWindow.commitObjectPosition(selectedNode) - onPositionMove: viewWindow.moveObjectPosition(selectedNode) + onPositionCommit: viewWindow.commitObjectProperty(selectedNode, "position") + onPositionMove: viewWindow.changeObjectProperty(selectedNode, "position") + } + + ScaleGizmo { + id: scaleGizmo + scale: autoScale.getScale(Qt.vector3d(5, 5, 5)) + highlightOnHover: true + targetNode: viewWindow.selectedNode + position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition + : Qt.vector3d(0, 0, 0) + globalOrientation: globalControl.checked + visible: selectedNode && scaleToolControl.checked + view3D: overlayView + + onScaleCommit: viewWindow.commitObjectProperty(selectedNode, "scale") + onScaleChange: viewWindow.changeObjectProperty(selectedNode, "scale") } AutoScaleHelper { @@ -186,11 +201,11 @@ Window { Overlay2D { id: gizmoLabel - targetNode: moveGizmo + targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo targetView: overlayView offsetX: 0 offsetY: 45 - visible: moveGizmo.dragging + visible: targetNode.dragging Rectangle { color: "white" @@ -203,11 +218,18 @@ Window { id: gizmoLabelText text: { var l = Qt.locale(); - selectedNode - ? qsTr("x:") + Number(selectedNode.position.x).toLocaleString(l, 'f', 1) - + qsTr(" y:") + Number(selectedNode.position.y).toLocaleString(l, 'f', 1) - + qsTr(" z:") + Number(selectedNode.position.z).toLocaleString(l, 'f', 1) - : ""; + var targetProperty; + if (viewWindow.selectedNode) { + if (gizmoLabel.targetNode === moveGizmo) + targetProperty = viewWindow.selectedNode.position; + else + targetProperty = viewWindow.selectedNode.scale; + return qsTr("x:") + Number(targetProperty.x).toLocaleString(l, 'f', 1) + + qsTr(" y:") + Number(targetProperty.y).toLocaleString(l, 'f', 1) + + qsTr(" z:") + Number(targetProperty.z).toLocaleString(l, 'f', 1); + } else { + return ""; + } } anchors.centerIn: parent } @@ -252,6 +274,19 @@ Window { text: qsTr("Use Global Orientation") onCheckedChanged: cameraControl.forceActiveFocus() } + Column { + x: 8 + RadioButton { + id: moveToolControl + checked: false + text: qsTr("Move Tool") + } + RadioButton { + id: scaleToolControl + checked: true + text: qsTr("Scale Tool") + } + } } Text { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml index 7ad5a2a011..c035f9c85e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -49,8 +49,9 @@ Node { 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) + : Qt.rgba(1, 0, 0, 1) view3D: moveGizmo.view3D + active: moveGizmo.visible onPositionCommit: moveGizmo.positionCommit() onPositionMove: moveGizmo.positionMove() @@ -61,9 +62,10 @@ Node { 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) + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + : Qt.rgba(0, 0.6, 0, 1) view3D: moveGizmo.view3D + active: moveGizmo.visible onPositionCommit: moveGizmo.positionCommit() onPositionMove: moveGizmo.positionMove() @@ -74,9 +76,10 @@ Node { 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) + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) + : Qt.rgba(0, 0, 1, 1) view3D: moveGizmo.view3D + active: moveGizmo.visible onPositionCommit: moveGizmo.positionCommit() onPositionMove: moveGizmo.positionMove() @@ -108,13 +111,14 @@ Node { rotation: view3D.camera.rotation grabsMouse: moveGizmo.targetNode priority: 1 + active: moveGizmo.visible property var _pointerPosPressed property var _targetStartPos - function posInParent(pointerPosition) + function localPos(scenePos) { - var scenePointerPos = mapPositionToScene(pointerPosition); + var scenePointerPos = mapPositionToScene(scenePos); var sceneRelativeDistance = Qt.vector3d( scenePointerPos.x - _pointerPosPressed.x, scenePointerPos.y - _pointerPosPressed.y, @@ -132,7 +136,7 @@ Node { if (!moveGizmo.targetNode) return; - _pointerPosPressed = mapPositionToScene(pointerPosition); + _pointerPosPressed = mapPositionToScene(scenePos); var sp = moveGizmo.targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); } @@ -140,14 +144,14 @@ Node { if (!moveGizmo.targetNode) return; - moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.targetNode.position = localPos(scenePos); moveGizmo.positionMove(); } onReleased: { if (!moveGizmo.targetNode) return; - moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.targetNode.position = localPos(scenePos); moveGizmo.positionCommit(); } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleGizmo.qml new file mode 100644 index 0000000000..7f4a4f69b8 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleGizmo.qml @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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: scaleGizmo + + property View3D view3D + property bool highlightOnHover: false + property Node targetNode: null + property bool globalOrientation: true + readonly property bool dragging: scaleRodX.dragging || scaleRodY.dragging || scaleRodZ.dragging + || centerMouseArea.dragging + + signal scaleCommit() + signal scaleChange() + + Node { + rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation + + ScaleRod { + id: scaleRodX + objectName: "scaleRod X" + rotation: Qt.vector3d(0, 0, -90) + targetNode: scaleGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) + : Qt.rgba(1, 0, 0, 1) + view3D: scaleGizmo.view3D + active: scaleGizmo.visible + + onScaleCommit: scaleGizmo.scaleCommit() + onScaleChange: scaleGizmo.scaleChange() + } + + ScaleRod { + id: scaleRodY + objectName: "scaleRod Y" + rotation: Qt.vector3d(0, 0, 0) + targetNode: scaleGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + : Qt.rgba(0, 0.6, 0, 1) + view3D: scaleGizmo.view3D + active: scaleGizmo.visible + + onScaleCommit: scaleGizmo.scaleCommit() + onScaleChange: scaleGizmo.scaleChange() + } + + ScaleRod { + id: scaleRodZ + objectName: "scaleRod Z" + rotation: Qt.vector3d(90, 0, 0) + targetNode: scaleGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) + : Qt.rgba(0, 0, 1, 1) + view3D: scaleGizmo.view3D + active: scaleGizmo.visible + + onScaleCommit: scaleGizmo.scaleCommit() + onScaleChange: scaleGizmo.scaleChange() + } + } + + Model { + id: centerCube + + source: "#Cube" + 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: scaleGizmo.view3D + x: -60 + y: -60 + width: 120 + height: 120 + rotation: view3D.camera.rotation + grabsMouse: scaleGizmo.targetNode + priority: 1 + active: scaleGizmo.visible + + property var _startScale + property var _startScreenPos + + function localScale(screenPos) + { + var yDelta = screenPos.y - _startScreenPos.y; + if (yDelta === 0) + return; + var scaler = 1.0 + (yDelta * 0.025); + if (scaler === 0 ) + scaler = 0.0001; + if (scaler < 0) + scaler = -scaler; + return Qt.vector3d(scaler * _startScale.x, + scaler * _startScale.y, + scaler * _startScale.z); + } + + onPressed: { + if (!scaleGizmo.targetNode) + return; + + // Recreate vector so we don't follow the changes in targetNode.scale + _startScale = Qt.vector3d(scaleGizmo.targetNode.scale.x, + scaleGizmo.targetNode.scale.y, + scaleGizmo.targetNode.scale.z); + _startScreenPos = screenPos; + } + onDragged: { + if (!scaleGizmo.targetNode) + return; + + scaleGizmo.targetNode.scale = localScale(screenPos); + scaleGizmo.scaleChange(); + } + onReleased: { + if (!scaleGizmo.targetNode) + return; + + scaleGizmo.targetNode.scale = localScale(screenPos); + scaleGizmo.scaleCommit(); + } + } + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleRod.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleRod.qml new file mode 100644 index 0000000000..4ef6d8a0a7 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/ScaleRod.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 + +DirectionalDraggable { + id: scaleRod + source: "meshes/scalerod.mesh" + + signal scaleCommit() + signal scaleChange() + + property var _startScale + + Model { + source: "#Cube" + y: 10 + scale: Qt.vector3d(0.025, 0.025, 0.025) + materials: DefaultMaterial { + id: material + emissiveColor: scaleRod.color + lighting: DefaultMaterial.NoLighting + } + } + + function localScale(mouseArea, sceneRelativeDistance) + { + return mouseArea.getNewScale(targetNode, _startScale, _pointerPosPressed, + sceneRelativeDistance, sceneScale.x); + } + + onPressed: { + // Recreate vector so we don't follow the changes in targetNode.sceneScale + _startScale = Qt.vector3d(targetNode.sceneScale.x, + targetNode.sceneScale.y, + targetNode.sceneScale.z); + } + + onDragged: { + targetNode.scale = localScale(mouseArea, sceneRelativeDistance); + scaleChange(); + } + + onReleased: { + targetNode.scale = localScale(mouseArea, sceneRelativeDistance); + scaleCommit(); + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/scalerod.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/scalerod.mesh Binary files differnew file mode 100644 index 0000000000..b3c1bd883f --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/scalerod.mesh diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp index 4c1fdcc78e..fe84ed13a6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -60,6 +60,11 @@ bool MouseArea3D::grabsMouse() const return m_grabsMouse; } +bool MouseArea3D::active() const +{ + return m_active; +} + qreal MouseArea3D::x() const { return m_x; @@ -103,6 +108,15 @@ void MouseArea3D::setGrabsMouse(bool grabsMouse) emit grabsMouseChanged(grabsMouse); } +void MouseArea3D::setActive(bool active) +{ + if (m_active == active) + return; + + m_active = active; + emit activeChanged(active); +} + void MouseArea3D::setX(qreal x) { if (qFuzzyCompare(m_x, x)) @@ -190,6 +204,73 @@ QVector3D MouseArea3D::rayIntersectsPlane(const QVector3D &rayPos0, return rayPos0 + distanceFromRayPos0ToPlane * rayDirection; } +// Get a new scale based on a relative scene distance along an axis (used to adjust scale via drag) +// This function never returns a negative scaling +QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startScale, + const QVector3D &pressPos, + const QVector3D &sceneRelativeDistance, float scaler) +{ + if (node) { + // Note: This only returns correct scale when scale is positive + auto getScale = [&](const QMatrix4x4 &m) -> QVector3D { + return QVector3D(m.column(0).length(), m.column(1).length(), m.column(2).length()); + }; + const float constantDragScaler = 0.1f; + const float nonZeroValue = 0.0001f; + + if (qFuzzyIsNull(scaler)) + scaler = nonZeroValue; + + const QVector3D scenePos = node->scenePosition(); + const QMatrix4x4 parentTransform = node->parentNode()->sceneTransform(); + QMatrix4x4 newTransform = node->sceneTransform(); + QVector3D normalRelDist = sceneRelativeDistance.normalized(); + float direction = QVector3D::dotProduct((pressPos - scenePos).normalized(), normalRelDist); + float magnitude = constantDragScaler * sceneRelativeDistance.length() / scaler; + + // Reset everything but rotation to ensure translation and scale do not affect rotate below + newTransform(0,3) = 0; + newTransform(1,3) = 0; + newTransform(2,3) = 0; + QVector3D curScale = getScale(newTransform); + if (qFuzzyIsNull(curScale.x())) + curScale.setX(nonZeroValue); + if (qFuzzyIsNull(curScale.y())) + curScale.setY(nonZeroValue); + if (qFuzzyIsNull(curScale.z())) + curScale.setZ(nonZeroValue); + newTransform.scale({1.f / curScale.x(), 1.f / curScale.y(), 1.f / curScale.z()}); + + // Rotate relative distance according to object rotation + normalRelDist = newTransform.inverted().map(normalRelDist).normalized(); + + // Ensure scaling is always positive/negative according to direction + normalRelDist.setX(qAbs(normalRelDist.x())); + normalRelDist.setY(qAbs(normalRelDist.y())); + normalRelDist.setZ(qAbs(normalRelDist.z())); + QVector3D scaleVec = normalRelDist; + scaleVec *= magnitude; + if (direction > 0) { + scaleVec.setX(scaleVec.x() + 1.f); + scaleVec.setY(scaleVec.y() + 1.f); + scaleVec.setZ(scaleVec.z() + 1.f); + } else { + scaleVec.setX(1.f - scaleVec.x()); + scaleVec.setY(1.f - scaleVec.y()); + scaleVec.setZ(1.f - scaleVec.z()); + } + scaleVec *= startScale; + + newTransform = parentTransform; + newTransform.scale(scaleVec); + + const QMatrix4x4 localTransform = parentTransform.inverted() * newTransform; + return getScale(localTransform); + } + + return startScale; +} + QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const { const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0); @@ -207,8 +288,8 @@ 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)) { + if (!m_active || (m_grabsMouse && s_mouseGrab && s_mouseGrab != this + && (m_priority <= s_mouseGrab->m_priority || s_mouseGrab->m_dragging))) { return false; } @@ -227,7 +308,7 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event) m_mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); if (mouseOnTopOfMouseArea(m_mousePosInPlane)) { setDragging(true); - emit pressed(m_mousePosInPlane); + emit pressed(m_mousePosInPlane, mouseEvent->globalPos()); if (m_grabsMouse) { if (s_mouseGrab && s_mouseGrab != this) { s_mouseGrab->setDragging(false); @@ -250,7 +331,7 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event) if (qFuzzyCompare(mousePosInPlane.z(), -1)) mousePosInPlane = m_mousePosInPlane; setDragging(false); - emit released(mousePosInPlane); + emit released(mousePosInPlane, mouseEvent->globalPos()); if (m_grabsMouse) { if (s_mouseGrab && s_mouseGrab != this) { s_mouseGrab->setDragging(false); @@ -290,7 +371,7 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event) if (m_dragging && !qFuzzyCompare(mousePosInPlane.z(), -1)) { m_mousePosInPlane = mousePosInPlane; - emit dragged(mousePosInPlane); + emit dragged(mousePosInPlane, mouseEvent->globalPos()); } break; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h index 99a34be353..a7e1fa261e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h @@ -49,6 +49,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_INTERFACES(QQmlParserStatus) @@ -66,10 +67,12 @@ public: bool hovering() const; bool dragging() const; bool grabsMouse() const; + bool active() const; public slots: void setView3D(QQuick3DViewport *view3D); void setGrabsMouse(bool grabsMouse); + void setActive(bool active); void setX(qreal x); void setY(qreal y); @@ -82,6 +85,10 @@ public slots: const QVector3D &planePos, const QVector3D &planeNormal) const; + Q_INVOKABLE QVector3D getNewScale(QQuick3DNode *node, const QVector3D &startScale, + const QVector3D &pressPos, + const QVector3D &sceneRelativeDistance, float scaler); + signals: void view3DChanged(); @@ -93,9 +100,10 @@ signals: void hoveringChanged(); void draggingChanged(); - void pressed(const QVector3D &pointerPosition); - void released(const QVector3D &pointerPosition); - void dragged(const QVector3D &pointerPosition); + void activeChanged(bool active); + void pressed(const QVector3D &scenePos, const QPoint &screenPos); + void released(const QVector3D &scenePos, const QPoint &screenPos); + void dragged(const QVector3D &scenePos, const QPoint &screenPos); void grabsMouseChanged(bool grabsMouse); protected: @@ -118,6 +126,7 @@ private: bool m_hovering = false; bool m_dragging = false; + bool m_active = false; QVector3D getMousePosInPlane(const QPointF &mousePosInView) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index d97cc2d503..dbbd8f050e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -97,12 +97,12 @@ 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))); - QObject::connect(window, SIGNAL(moveObjectPosition(QVariant)), - this, SLOT(handleObjectPositionMove(QVariant))); - QObject::connect(&m_moveTimer, &QTimer::timeout, - this, &Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout); + QObject::connect(window, SIGNAL(commitObjectProperty(QVariant, QVariant)), + this, SLOT(handleObjectPropertyCommit(QVariant, QVariant))); + QObject::connect(window, SIGNAL(changeObjectProperty(QVariant, QVariant)), + this, SLOT(handleObjectPropertyChange(QVariant, QVariant))); + QObject::connect(&m_propertyChangeTimer, &QTimer::timeout, + this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout); //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); @@ -188,28 +188,36 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue( } } -void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) +void Qt5InformationNodeInstanceServer::handleObjectPropertyCommit(const QVariant &object, + const QVariant &propName) { - modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::End); - m_movedNode = {}; - m_moveTimer.stop(); + modifyVariantValue(object, propName.toByteArray(), + ValuesModifiedCommand::TransactionOption::End); + m_changedNode = {}; + m_changedProperty = {}; + m_propertyChangeTimer.stop(); } -void Qt5InformationNodeInstanceServer::handleObjectPositionMove(const QVariant &object) +void Qt5InformationNodeInstanceServer::handleObjectPropertyChange(const QVariant &object, + const QVariant &propName) { - if (m_movedNode.isNull()) { - modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::Start); - } else { - if (!m_moveTimer.isActive()) - m_moveTimer.start(); + PropertyName propertyName(propName.toByteArray()); + if (m_changedProperty != propertyName || m_changedNode != object) { + if (!m_changedNode.isNull()) + handleObjectPropertyCommit(m_changedNode, m_changedProperty); + modifyVariantValue(object, propertyName, + ValuesModifiedCommand::TransactionOption::Start); + } else if (!m_propertyChangeTimer.isActive()) { + m_propertyChangeTimer.start(); } - m_movedNode = object; + m_changedNode = object; + m_changedProperty = propertyName; } Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5NodeInstanceServer(nodeInstanceClient) { - m_moveTimer.setInterval(100); + m_propertyChangeTimer.setInterval(100); } void Qt5InformationNodeInstanceServer::sendTokenBack() @@ -282,9 +290,10 @@ void Qt5InformationNodeInstanceServer::modifyProperties( nodeInstanceClient()->valuesModified(createValuesModifiedCommand(properties)); } -void Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout() +void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout() { - modifyVariantValue(m_movedNode, "position", ValuesModifiedCommand::TransactionOption::None); + modifyVariantValue(m_changedNode, m_changedProperty, + ValuesModifiedCommand::TransactionOption::None); } QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index e8a0291a9f..918d18db67 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -51,8 +51,8 @@ public: private slots: void objectClicked(const QVariant &object); - void handleObjectPositionCommit(const QVariant &object); - void handleObjectPositionMove(const QVariant &object); + void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName); + void handleObjectPropertyChange(const QVariant &object, const QVariant &propName); protected: void collectItemChangesAndSendChangeCommands() override; @@ -64,7 +64,7 @@ protected: void modifyProperties(const QVector<InstancePropertyValueTriple> &properties); private: - void handleObjectPositionMoveTimeout(); + void handleObjectPropertyChangeTimeout(); QObject *createEditView3D(QQmlEngine *engine); void setup3DEditView(const QList<ServerNodeInstance> &instanceList); QObject *findRootNodeOf3DViewport(const QList<ServerNodeInstance> &instanceList) const; @@ -81,8 +81,9 @@ private: QSet<ServerNodeInstance> m_parentChangedSet; QList<ServerNodeInstance> m_completedComponentList; QList<TokenCommand> m_tokenList; - QTimer m_moveTimer; - QVariant m_movedNode; + QTimer m_propertyChangeTimer; + QVariant m_changedNode; + PropertyName m_changedProperty; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 4bbd30e8fc..ec02e9d256 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -15,7 +15,11 @@ <file>mockfiles/LightGizmo.qml</file> <file>mockfiles/IconGizmo.qml</file> <file>mockfiles/Overlay2D.qml</file> + <file>mockfiles/DirectionalDraggable.qml</file> + <file>mockfiles/ScaleRod.qml</file> + <file>mockfiles/ScaleGizmo.qml</file> <file>mockfiles/meshes/arrow.mesh</file> + <file>mockfiles/meshes/scalerod.mesh</file> <file>mockfiles/images/camera-pick-icon.png</file> <file>mockfiles/images/camera-pick-icon@2x.png</file> <file>mockfiles/images/light-pick-icon.png</file> |