forked from qt-creator/qt-creator
QmlDesigner: Implement RotateGizmo for 3D edit view
Added a gizmo for rotating selected object either freely or locked around X, Y, Z, or camera axis. Change-Id: Ib43c7dd3fc0f49f384d5920fce21ea932c4fc90d Task-number: QDS-1196 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -100,12 +100,15 @@ Window {
|
|||||||
PerspectiveCamera {
|
PerspectiveCamera {
|
||||||
id: overlayPerspectiveCamera
|
id: overlayPerspectiveCamera
|
||||||
clipFar: editPerspectiveCamera.clipFar
|
clipFar: editPerspectiveCamera.clipFar
|
||||||
|
clipNear: editPerspectiveCamera.clipNear
|
||||||
position: editPerspectiveCamera.position
|
position: editPerspectiveCamera.position
|
||||||
rotation: editPerspectiveCamera.rotation
|
rotation: editPerspectiveCamera.rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
OrthographicCamera {
|
OrthographicCamera {
|
||||||
id: overlayOrthoCamera
|
id: overlayOrthoCamera
|
||||||
|
clipFar: editOrthoCamera.clipFar
|
||||||
|
clipNear: editOrthoCamera.clipNear
|
||||||
position: editOrthoCamera.position
|
position: editOrthoCamera.position
|
||||||
rotation: editOrthoCamera.rotation
|
rotation: editOrthoCamera.rotation
|
||||||
}
|
}
|
||||||
@@ -140,6 +143,21 @@ Window {
|
|||||||
onScaleChange: viewWindow.changeObjectProperty(selectedNode, "scale")
|
onScaleChange: viewWindow.changeObjectProperty(selectedNode, "scale")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RotateGizmo {
|
||||||
|
id: rotateGizmo
|
||||||
|
scale: autoScale.getScale(Qt.vector3d(7, 7, 7))
|
||||||
|
highlightOnHover: true
|
||||||
|
targetNode: viewWindow.selectedNode
|
||||||
|
position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition
|
||||||
|
: Qt.vector3d(0, 0, 0)
|
||||||
|
globalOrientation: globalControl.checked
|
||||||
|
visible: selectedNode && btnRotate.selected
|
||||||
|
view3D: overlayView
|
||||||
|
|
||||||
|
onRotateCommit: viewWindow.commitObjectProperty(selectedNode, "rotation")
|
||||||
|
onRotateChange: viewWindow.changeObjectProperty(selectedNode, "rotation")
|
||||||
|
}
|
||||||
|
|
||||||
AutoScaleHelper {
|
AutoScaleHelper {
|
||||||
id: autoScale
|
id: autoScale
|
||||||
view3D: overlayView
|
view3D: overlayView
|
||||||
@@ -193,12 +211,15 @@ Window {
|
|||||||
y: 200
|
y: 200
|
||||||
z: -300
|
z: -300
|
||||||
clipFar: 100000
|
clipFar: 100000
|
||||||
|
clipNear: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
OrthographicCamera {
|
OrthographicCamera {
|
||||||
id: editOrthoCamera
|
id: editOrthoCamera
|
||||||
y: 200
|
y: 200
|
||||||
z: -300
|
z: -300
|
||||||
|
clipFar: 100000
|
||||||
|
clipNear: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,7 +367,19 @@ Window {
|
|||||||
id: usePerspectiveCheckbox
|
id: usePerspectiveCheckbox
|
||||||
checked: true
|
checked: true
|
||||||
text: qsTr("Use Perspective Projection")
|
text: qsTr("Use Perspective Projection")
|
||||||
onCheckedChanged: cameraControl.forceActiveFocus()
|
onCheckedChanged: {
|
||||||
|
// Since WasdController always acts on active camera, we need to update pos/rot
|
||||||
|
// to the other camera when we change
|
||||||
|
if (checked) {
|
||||||
|
editPerspectiveCamera.position = editOrthoCamera.position;
|
||||||
|
editPerspectiveCamera.rotation = editOrthoCamera.rotation;
|
||||||
|
} else {
|
||||||
|
editOrthoCamera.position = editPerspectiveCamera.position;
|
||||||
|
editOrthoCamera.rotation = editPerspectiveCamera.rotation;
|
||||||
|
}
|
||||||
|
designStudioNativeCameraControlHelper.requestOverlayUpdate();
|
||||||
|
cameraControl.forceActiveFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
|
221
share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml
Normal file
221
share/qtcreator/qml/qmlpuppet/mockfiles/RotateGizmo.qml
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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: rotateGizmo
|
||||||
|
|
||||||
|
property View3D view3D
|
||||||
|
property bool highlightOnHover: true
|
||||||
|
property Node targetNode: null
|
||||||
|
property bool globalOrientation: true
|
||||||
|
readonly property bool dragging: cameraRing.dragging
|
||||||
|
|| rotRingX.dragging || rotRingY.dragging || rotRingZ.dragging
|
||||||
|
property real currentAngle
|
||||||
|
property point currentMousePos
|
||||||
|
|
||||||
|
signal rotateCommit()
|
||||||
|
signal rotateChange()
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: angleLabel
|
||||||
|
color: "white"
|
||||||
|
x: rotateGizmo.currentMousePos.x - (10 + width)
|
||||||
|
y: rotateGizmo.currentMousePos.y - (10 + height)
|
||||||
|
width: gizmoLabelText.width + 4
|
||||||
|
height: gizmoLabelText.height + 4
|
||||||
|
border.width: 1
|
||||||
|
visible: rotateGizmo.dragging
|
||||||
|
parent: rotateGizmo.view3D
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: gizmoLabelText
|
||||||
|
text: {
|
||||||
|
var l = Qt.locale();
|
||||||
|
if (rotateGizmo.targetNode) {
|
||||||
|
var degrees = currentAngle * (180 / Math.PI);
|
||||||
|
return qsTr(Number(degrees).toLocaleString(l, 'f', 1));
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node {
|
||||||
|
rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation
|
||||||
|
|
||||||
|
RotateRing {
|
||||||
|
id: rotRingX
|
||||||
|
objectName: "Rotate Ring X"
|
||||||
|
rotation: Qt.vector3d(0, 90, 0)
|
||||||
|
targetNode: rotateGizmo.targetNode
|
||||||
|
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1))
|
||||||
|
: Qt.rgba(1, 0, 0, 1)
|
||||||
|
priority: 40
|
||||||
|
view3D: rotateGizmo.view3D
|
||||||
|
active: rotateGizmo.visible
|
||||||
|
|
||||||
|
onRotateCommit: rotateGizmo.rotateCommit()
|
||||||
|
onRotateChange: rotateGizmo.rotateChange()
|
||||||
|
onCurrentAngleChanged: rotateGizmo.currentAngle = currentAngle
|
||||||
|
onCurrentMousePosChanged: rotateGizmo.currentMousePos = currentMousePos
|
||||||
|
}
|
||||||
|
|
||||||
|
RotateRing {
|
||||||
|
id: rotRingY
|
||||||
|
objectName: "Rotate Ring Y"
|
||||||
|
rotation: Qt.vector3d(90, 0, 0)
|
||||||
|
targetNode: rotateGizmo.targetNode
|
||||||
|
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1))
|
||||||
|
: Qt.rgba(0, 0.6, 0, 1)
|
||||||
|
// Just a smidge smaller than higher priority rings so that it doesn't obscure them
|
||||||
|
scale: Qt.vector3d(0.998, 0.998, 0.998)
|
||||||
|
priority: 30
|
||||||
|
view3D: rotateGizmo.view3D
|
||||||
|
active: rotateGizmo.visible
|
||||||
|
|
||||||
|
onRotateCommit: rotateGizmo.rotateCommit()
|
||||||
|
onRotateChange: rotateGizmo.rotateChange()
|
||||||
|
onCurrentAngleChanged: rotateGizmo.currentAngle = currentAngle
|
||||||
|
onCurrentMousePosChanged: rotateGizmo.currentMousePos = currentMousePos
|
||||||
|
}
|
||||||
|
|
||||||
|
RotateRing {
|
||||||
|
id: rotRingZ
|
||||||
|
objectName: "Rotate Ring Z"
|
||||||
|
rotation: Qt.vector3d(0, 0, 0)
|
||||||
|
targetNode: rotateGizmo.targetNode
|
||||||
|
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1))
|
||||||
|
: Qt.rgba(0, 0, 1, 1)
|
||||||
|
// Just a smidge smaller than higher priority rings so that it doesn't obscure them
|
||||||
|
scale: Qt.vector3d(0.996, 0.996, 0.996)
|
||||||
|
priority: 20
|
||||||
|
view3D: rotateGizmo.view3D
|
||||||
|
active: rotateGizmo.visible
|
||||||
|
|
||||||
|
onRotateCommit: rotateGizmo.rotateCommit()
|
||||||
|
onRotateChange: rotateGizmo.rotateChange()
|
||||||
|
onCurrentAngleChanged: rotateGizmo.currentAngle = currentAngle
|
||||||
|
onCurrentMousePosChanged: rotateGizmo.currentMousePos = currentMousePos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RotateRing {
|
||||||
|
id: cameraRing
|
||||||
|
objectName: "cameraRing"
|
||||||
|
rotation: rotateGizmo.view3D.camera.rotation
|
||||||
|
targetNode: rotateGizmo.targetNode
|
||||||
|
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1))
|
||||||
|
: Qt.rgba(0.5, 0.5, 0.5, 1)
|
||||||
|
// Just a smidge smaller than higher priority rings so that it doesn't obscure them
|
||||||
|
scale: Qt.vector3d(0.994, 0.994, 0.994)
|
||||||
|
priority: 10
|
||||||
|
view3D: rotateGizmo.view3D
|
||||||
|
active: rotateGizmo.visible
|
||||||
|
|
||||||
|
onRotateCommit: rotateGizmo.rotateCommit()
|
||||||
|
onRotateChange: rotateGizmo.rotateChange()
|
||||||
|
onCurrentAngleChanged: rotateGizmo.currentAngle = currentAngle
|
||||||
|
onCurrentMousePosChanged: rotateGizmo.currentMousePos = currentMousePos
|
||||||
|
}
|
||||||
|
|
||||||
|
Model {
|
||||||
|
id: freeRotator
|
||||||
|
|
||||||
|
source: "#Sphere"
|
||||||
|
materials: DefaultMaterial {
|
||||||
|
id: material
|
||||||
|
emissiveColor: "black"
|
||||||
|
opacity: mouseAreaFree.hovering ? 0.15 : 0
|
||||||
|
lighting: DefaultMaterial.NoLighting
|
||||||
|
}
|
||||||
|
scale: Qt.vector3d(0.15, 0.15, 0.15)
|
||||||
|
|
||||||
|
property vector3d _pointerPosPressed
|
||||||
|
property vector3d _targetPosOnScreen
|
||||||
|
property vector3d _startRotation
|
||||||
|
|
||||||
|
function handlePressed(screenPos)
|
||||||
|
{
|
||||||
|
if (!rotateGizmo.targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_targetPosOnScreen = view3D.mapFrom3DScene(rotateGizmo.targetNode.scenePosition);
|
||||||
|
_targetPosOnScreen.z = 0;
|
||||||
|
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
|
||||||
|
|
||||||
|
// Recreate vector so we don't follow the changes in targetNode.rotation
|
||||||
|
_startRotation = Qt.vector3d(rotateGizmo.targetNode.rotation.x,
|
||||||
|
rotateGizmo.targetNode.rotation.y,
|
||||||
|
rotateGizmo.targetNode.rotation.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragged(screenPos)
|
||||||
|
{
|
||||||
|
if (!rotateGizmo.targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mouseAreaFree.applyFreeRotation(
|
||||||
|
rotateGizmo.targetNode, _startRotation, _pointerPosPressed,
|
||||||
|
Qt.vector3d(screenPos.x, screenPos.y, 0), _targetPosOnScreen);
|
||||||
|
|
||||||
|
rotateGizmo.rotateChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReleased(screenPos)
|
||||||
|
{
|
||||||
|
if (!rotateGizmo.targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mouseAreaFree.applyFreeRotation(
|
||||||
|
rotateGizmo.targetNode, _startRotation, _pointerPosPressed,
|
||||||
|
Qt.vector3d(screenPos.x, screenPos.y, 0), _targetPosOnScreen);
|
||||||
|
|
||||||
|
rotateGizmo.rotateCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea3D {
|
||||||
|
id: mouseAreaFree
|
||||||
|
view3D: rotateGizmo.view3D
|
||||||
|
rotation: rotateGizmo.view3D.camera.rotation
|
||||||
|
objectName: "Free rotator plane"
|
||||||
|
x: -50
|
||||||
|
y: -50
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
circlePickArea: Qt.point(25, 50)
|
||||||
|
grabsMouse: rotateGizmo.targetNode
|
||||||
|
active: rotateGizmo.visible
|
||||||
|
onPressed: freeRotator.handlePressed(screenPos)
|
||||||
|
onDragged: freeRotator.handleDragged(screenPos)
|
||||||
|
onReleased: freeRotator.handleReleased(screenPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
133
share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml
Normal file
133
share/qtcreator/qml/qmlpuppet/mockfiles/RotateRing.qml
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick3D 1.0
|
||||||
|
import MouseArea3D 1.0
|
||||||
|
|
||||||
|
Model {
|
||||||
|
id: rotateRing
|
||||||
|
|
||||||
|
property View3D view3D
|
||||||
|
property alias color: material.emissiveColor
|
||||||
|
property Node targetNode: null
|
||||||
|
property bool dragging: false
|
||||||
|
property bool active: false
|
||||||
|
property alias hovering: mouseAreaMain.hovering
|
||||||
|
property alias priority: mouseAreaMain.priority
|
||||||
|
property real currentAngle
|
||||||
|
property point currentMousePos
|
||||||
|
|
||||||
|
property vector3d _pointerPosPressed
|
||||||
|
property vector3d _targetPosOnScreen
|
||||||
|
property vector3d _startRotation
|
||||||
|
property bool _trackBall
|
||||||
|
|
||||||
|
signal rotateCommit()
|
||||||
|
signal rotateChange()
|
||||||
|
|
||||||
|
source: "meshes/ring.mesh"
|
||||||
|
|
||||||
|
Model {
|
||||||
|
id: pickModel
|
||||||
|
objectName: "PickModel for " + rotateRing.objectName
|
||||||
|
source: "meshes/ringselect.mesh"
|
||||||
|
pickable: true
|
||||||
|
}
|
||||||
|
|
||||||
|
materials: DefaultMaterial {
|
||||||
|
id: material
|
||||||
|
emissiveColor: "white"
|
||||||
|
lighting: DefaultMaterial.NoLighting
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyLocalRotation(screenPos)
|
||||||
|
{
|
||||||
|
currentAngle = mouseAreaMain.getNewRotationAngle(targetNode, _pointerPosPressed,
|
||||||
|
Qt.vector3d(screenPos.x, screenPos.y, 0),
|
||||||
|
_targetPosOnScreen, currentAngle,
|
||||||
|
_trackBall);
|
||||||
|
mouseAreaMain.applyRotationAngleToNode(targetNode, _startRotation, currentAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePressed(screenPos, angle)
|
||||||
|
{
|
||||||
|
if (!targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_targetPosOnScreen = view3D.mapFrom3DScene(targetNode.scenePosition);
|
||||||
|
_targetPosOnScreen.z = 0;
|
||||||
|
_pointerPosPressed = Qt.vector3d(screenPos.x, screenPos.y, 0);
|
||||||
|
dragging = true;
|
||||||
|
_trackBall = angle < 0.1;
|
||||||
|
|
||||||
|
// Recreate vector so we don't follow the changes in targetNode.rotation
|
||||||
|
_startRotation = Qt.vector3d(targetNode.rotation.x,
|
||||||
|
targetNode.rotation.y,
|
||||||
|
targetNode.rotation.z);
|
||||||
|
currentAngle = 0;
|
||||||
|
currentMousePos = screenPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragged(screenPos)
|
||||||
|
{
|
||||||
|
if (!targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
applyLocalRotation(screenPos);
|
||||||
|
currentMousePos = screenPos;
|
||||||
|
rotateChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReleased(screenPos)
|
||||||
|
{
|
||||||
|
if (!targetNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
applyLocalRotation(screenPos);
|
||||||
|
rotateCommit();
|
||||||
|
dragging = false;
|
||||||
|
currentAngle = 0;
|
||||||
|
currentMousePos = screenPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea3D {
|
||||||
|
id: mouseAreaMain
|
||||||
|
view3D: rotateRing.view3D
|
||||||
|
objectName: "Main plane of " + rotateRing.objectName
|
||||||
|
x: -30
|
||||||
|
y: -30
|
||||||
|
width: 60
|
||||||
|
height: 60
|
||||||
|
circlePickArea: Qt.point(9.2, 1.4)
|
||||||
|
grabsMouse: targetNode
|
||||||
|
active: rotateRing.active
|
||||||
|
pickNode: pickModel
|
||||||
|
minAngle: 0.05
|
||||||
|
onPressed: rotateRing.handlePressed(screenPos, angle)
|
||||||
|
onDragged: rotateRing.handleDragged(screenPos)
|
||||||
|
onReleased: rotateRing.handleReleased(screenPos)
|
||||||
|
}
|
||||||
|
}
|
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/ring.mesh
Normal file
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/ring.mesh
Normal file
Binary file not shown.
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/ringselect.mesh
Normal file
BIN
share/qtcreator/qml/qmlpuppet/mockfiles/meshes/ringselect.mesh
Normal file
Binary file not shown.
@@ -29,11 +29,15 @@
|
|||||||
|
|
||||||
#include <QtGui/qguiapplication.h>
|
#include <QtGui/qguiapplication.h>
|
||||||
#include <QtQml/qqmlinfo.h>
|
#include <QtQml/qqmlinfo.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dcamera_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
|
||||||
|
#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
|
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
|
||||||
|
static const qreal s_mouseDragMultiplier = .02;
|
||||||
|
|
||||||
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
|
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
|
||||||
: QQuick3DNode(parent)
|
: QQuick3DNode(parent)
|
||||||
@@ -65,6 +69,21 @@ bool MouseArea3D::active() const
|
|||||||
return m_active;
|
return m_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPointF MouseArea3D::circlePickArea() const
|
||||||
|
{
|
||||||
|
return m_circlePickArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal MouseArea3D::minAngle() const
|
||||||
|
{
|
||||||
|
return m_minAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuick3DNode *MouseArea3D::pickNode() const
|
||||||
|
{
|
||||||
|
return m_pickNode;
|
||||||
|
}
|
||||||
|
|
||||||
qreal MouseArea3D::x() const
|
qreal MouseArea3D::x() const
|
||||||
{
|
{
|
||||||
return m_x;
|
return m_x;
|
||||||
@@ -105,7 +124,7 @@ void MouseArea3D::setGrabsMouse(bool grabsMouse)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_grabsMouse = grabsMouse;
|
m_grabsMouse = grabsMouse;
|
||||||
emit grabsMouseChanged(grabsMouse);
|
emit grabsMouseChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setActive(bool active)
|
void MouseArea3D::setActive(bool active)
|
||||||
@@ -114,7 +133,37 @@ void MouseArea3D::setActive(bool active)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_active = active;
|
m_active = active;
|
||||||
emit activeChanged(active);
|
emit activeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseArea3D::setCirclePickArea(const QPointF &pickArea)
|
||||||
|
{
|
||||||
|
if (m_circlePickArea == pickArea)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_circlePickArea = pickArea;
|
||||||
|
emit circlePickAreaChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the minimum angle for circle picking. At lower angles we fall back to picking on pickNode
|
||||||
|
void MouseArea3D::setMinAngle(qreal angle)
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(m_minAngle, angle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_minAngle = angle;
|
||||||
|
emit minAngleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the fallback pick node when circle picking can't be done due to low angle
|
||||||
|
// Pick node can't be used except in low angles, as long as only bounding box picking is supported
|
||||||
|
void MouseArea3D::setPickNode(QQuick3DNode *node)
|
||||||
|
{
|
||||||
|
if (m_pickNode == node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pickNode = node;
|
||||||
|
emit pickNodeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setX(qreal x)
|
void MouseArea3D::setX(qreal x)
|
||||||
@@ -123,7 +172,7 @@ void MouseArea3D::setX(qreal x)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_x = x;
|
m_x = x;
|
||||||
emit xChanged(x);
|
emit xChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setY(qreal y)
|
void MouseArea3D::setY(qreal y)
|
||||||
@@ -132,7 +181,7 @@ void MouseArea3D::setY(qreal y)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_y = y;
|
m_y = y;
|
||||||
emit yChanged(y);
|
emit yChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setWidth(qreal width)
|
void MouseArea3D::setWidth(qreal width)
|
||||||
@@ -141,7 +190,7 @@ void MouseArea3D::setWidth(qreal width)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_width = width;
|
m_width = width;
|
||||||
emit widthChanged(width);
|
emit widthChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setHeight(qreal height)
|
void MouseArea3D::setHeight(qreal height)
|
||||||
@@ -150,7 +199,7 @@ void MouseArea3D::setHeight(qreal height)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_height = height;
|
m_height = height;
|
||||||
emit heightChanged(height);
|
emit heightChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::setPriority(int level)
|
void MouseArea3D::setPriority(int level)
|
||||||
@@ -159,7 +208,7 @@ void MouseArea3D::setPriority(int level)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_priority = level;
|
m_priority = level;
|
||||||
emit priorityChanged(level);
|
emit priorityChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseArea3D::componentComplete()
|
void MouseArea3D::componentComplete()
|
||||||
@@ -278,6 +327,84 @@ QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startSca
|
|||||||
return startScale;
|
return startScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||||
|
QQuick3DNode *node, const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||||
|
const QVector3D &nodePos, qreal prevAngle, bool trackBall)
|
||||||
|
{
|
||||||
|
const QVector3D cameraToNodeDir = getCameraToNodeDir(node);
|
||||||
|
if (trackBall) {
|
||||||
|
// Only the distance in plane direction is relevant in trackball drag
|
||||||
|
QVector3D dragDir = QVector3D::crossProduct(getNormal(), cameraToNodeDir).normalized();
|
||||||
|
QVector3D screenDragDir = m_view3D->mapFrom3DScene(node->scenePosition() + dragDir);
|
||||||
|
screenDragDir.setZ(0);
|
||||||
|
dragDir = (screenDragDir - nodePos).normalized();
|
||||||
|
const QVector3D pressToCurrent = (currentPos - pressPos);
|
||||||
|
float magnitude = QVector3D::dotProduct(pressToCurrent, dragDir);
|
||||||
|
qreal angle = -s_mouseDragMultiplier * qreal(magnitude);
|
||||||
|
return angle;
|
||||||
|
} else {
|
||||||
|
const QVector3D nodeToPress = (pressPos - nodePos).normalized();
|
||||||
|
const QVector3D nodeToCurrent = (currentPos - nodePos).normalized();
|
||||||
|
qreal angle = qAcos(qreal(QVector3D::dotProduct(nodeToPress, nodeToCurrent)));
|
||||||
|
|
||||||
|
// Determine drag direction left/right
|
||||||
|
const QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
|
||||||
|
angle *= QVector3D::dotProduct(QVector3D(0.f, 0.f, 1.f), dragNormal) < 0 ? -1.0 : 1.0;
|
||||||
|
|
||||||
|
// Determine drag ring orientation relative to camera
|
||||||
|
angle *= QVector3D::dotProduct(getNormal(), cameraToNodeDir) < 0 ? 1.0 : -1.0;
|
||||||
|
|
||||||
|
qreal adjustedPrevAngle = prevAngle;
|
||||||
|
const qreal PI_2 = M_PI * 2.0;
|
||||||
|
while (adjustedPrevAngle < -PI_2)
|
||||||
|
adjustedPrevAngle += PI_2;
|
||||||
|
while (adjustedPrevAngle > PI_2)
|
||||||
|
adjustedPrevAngle -= PI_2;
|
||||||
|
|
||||||
|
// at M_PI rotation, the angle flips to negative
|
||||||
|
if (qAbs(angle - adjustedPrevAngle) > M_PI) {
|
||||||
|
if (angle > adjustedPrevAngle)
|
||||||
|
return prevAngle - (PI_2 - angle + adjustedPrevAngle);
|
||||||
|
else
|
||||||
|
return prevAngle + (PI_2 + angle - adjustedPrevAngle);
|
||||||
|
} else {
|
||||||
|
return prevAngle + angle - adjustedPrevAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlDesigner::Internal::MouseArea3D::applyRotationAngleToNode(
|
||||||
|
QQuick3DNode *node, const QVector3D &startRotation, qreal angle)
|
||||||
|
{
|
||||||
|
if (!qFuzzyIsNull(angle)) {
|
||||||
|
node->setRotation(startRotation);
|
||||||
|
node->rotate(qRadiansToDegrees(angle), getNormal(), QQuick3DNode::SceneSpace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRotation,
|
||||||
|
const QVector3D &pressPos, const QVector3D ¤tPos)
|
||||||
|
{
|
||||||
|
QVector3D dragVector = currentPos - pressPos;
|
||||||
|
|
||||||
|
if (dragVector.length() < 0.001f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const float *dataPtr(sceneTransform().data());
|
||||||
|
QVector3D xAxis = QVector3D(-dataPtr[0], -dataPtr[1], -dataPtr[2]).normalized();
|
||||||
|
QVector3D yAxis = QVector3D(-dataPtr[4], -dataPtr[5], -dataPtr[6]).normalized();
|
||||||
|
|
||||||
|
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
||||||
|
|
||||||
|
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * s_mouseDragMultiplier);
|
||||||
|
|
||||||
|
finalAxis.normalize();
|
||||||
|
|
||||||
|
node->setRotation(startRotation);
|
||||||
|
node->rotate(degrees, finalAxis, QQuick3DNode::SceneSpace);
|
||||||
|
}
|
||||||
|
|
||||||
QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const
|
QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const
|
||||||
{
|
{
|
||||||
const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0);
|
const QVector3D mousePos1(float(mousePosInView.x()), float(mousePosInView.y()), 0);
|
||||||
@@ -300,12 +427,50 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mouseOnTopOfMouseArea = [this](const QVector3D &mousePosInPlane) -> bool {
|
qreal pickAngle = 0.;
|
||||||
return !qFuzzyCompare(mousePosInPlane.z(), -1)
|
|
||||||
|
auto mouseOnTopOfMouseArea = [this, &pickAngle](
|
||||||
|
const QVector3D &mousePosInPlane, const QPointF &mousePos) -> bool {
|
||||||
|
const bool onPlane = !qFuzzyCompare(mousePosInPlane.z(), -1)
|
||||||
&& mousePosInPlane.x() >= float(m_x)
|
&& mousePosInPlane.x() >= float(m_x)
|
||||||
&& mousePosInPlane.x() <= float(m_x + m_width)
|
&& mousePosInPlane.x() <= float(m_x + m_width)
|
||||||
&& mousePosInPlane.y() >= float(m_y)
|
&& mousePosInPlane.y() >= float(m_y)
|
||||||
&& mousePosInPlane.y() <= float(m_y + m_height);
|
&& mousePosInPlane.y() <= float(m_y + m_height);
|
||||||
|
|
||||||
|
bool onCircle = true;
|
||||||
|
bool pickSuccess = false;
|
||||||
|
if (!qFuzzyIsNull(m_circlePickArea.y()) || !qFuzzyIsNull(m_minAngle)) {
|
||||||
|
|
||||||
|
QVector3D cameraToMouseAreaDir = getCameraToNodeDir(this);
|
||||||
|
const QVector3D mouseAreaDir = getNormal();
|
||||||
|
qreal angle = qreal(QVector3D::dotProduct(cameraToMouseAreaDir, mouseAreaDir));
|
||||||
|
// Do not allow selecting ring that is nearly perpendicular to camera, as dragging along
|
||||||
|
// that plane would be difficult
|
||||||
|
pickAngle = qAcos(angle);
|
||||||
|
pickAngle = pickAngle > M_PI_2 ? pickAngle - M_PI_2 : M_PI_2 - pickAngle;
|
||||||
|
if (pickAngle > m_minAngle) {
|
||||||
|
if (!qFuzzyIsNull(m_circlePickArea.y())) {
|
||||||
|
qreal ringCenter = m_circlePickArea.x();
|
||||||
|
// Thickness is increased according to the angle to camera to keep projected
|
||||||
|
// circle thickness constant at all angles.
|
||||||
|
qreal divisor = qSin(pickAngle) * 2.; // This is never zero
|
||||||
|
qreal thickness = ((m_circlePickArea.y() / divisor));
|
||||||
|
qreal mousePosRadius = qSqrt(qreal(mousePosInPlane.x() * mousePosInPlane.x())
|
||||||
|
+ qreal(mousePosInPlane.y() * mousePosInPlane.y()));
|
||||||
|
onCircle = ringCenter - thickness <= mousePosRadius
|
||||||
|
&& ringCenter + thickness >= mousePosRadius;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fall back to picking on the pickNode. At this angle, bounding box pick is not
|
||||||
|
// a problem
|
||||||
|
onCircle = false;
|
||||||
|
if (m_pickNode) {
|
||||||
|
QQuick3DPickResult pr = m_view3D->pick(float(mousePos.x()), float(mousePos.y()));
|
||||||
|
pickSuccess = pr.objectHit() == m_pickNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (onCircle && onPlane) || pickSuccess;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (event->type()) {
|
switch (event->type()) {
|
||||||
@@ -313,9 +478,9 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event)
|
|||||||
auto const mouseEvent = static_cast<QMouseEvent *>(event);
|
auto const mouseEvent = static_cast<QMouseEvent *>(event);
|
||||||
if (mouseEvent->button() == Qt::LeftButton) {
|
if (mouseEvent->button() == Qt::LeftButton) {
|
||||||
m_mousePosInPlane = getMousePosInPlane(mouseEvent->pos());
|
m_mousePosInPlane = getMousePosInPlane(mouseEvent->pos());
|
||||||
if (mouseOnTopOfMouseArea(m_mousePosInPlane)) {
|
if (mouseOnTopOfMouseArea(m_mousePosInPlane, mouseEvent->pos())) {
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
emit pressed(m_mousePosInPlane, mouseEvent->globalPos());
|
emit pressed(m_mousePosInPlane, mouseEvent->pos(), pickAngle);
|
||||||
if (m_grabsMouse) {
|
if (m_grabsMouse) {
|
||||||
if (s_mouseGrab && s_mouseGrab != this) {
|
if (s_mouseGrab && s_mouseGrab != this) {
|
||||||
s_mouseGrab->setDragging(false);
|
s_mouseGrab->setDragging(false);
|
||||||
@@ -338,13 +503,13 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event)
|
|||||||
if (qFuzzyCompare(mousePosInPlane.z(), -1))
|
if (qFuzzyCompare(mousePosInPlane.z(), -1))
|
||||||
mousePosInPlane = m_mousePosInPlane;
|
mousePosInPlane = m_mousePosInPlane;
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
emit released(mousePosInPlane, mouseEvent->globalPos());
|
emit released(mousePosInPlane, mouseEvent->pos());
|
||||||
if (m_grabsMouse) {
|
if (m_grabsMouse) {
|
||||||
if (s_mouseGrab && s_mouseGrab != this) {
|
if (s_mouseGrab && s_mouseGrab != this) {
|
||||||
s_mouseGrab->setDragging(false);
|
s_mouseGrab->setDragging(false);
|
||||||
s_mouseGrab->setHovering(false);
|
s_mouseGrab->setHovering(false);
|
||||||
}
|
}
|
||||||
if (mouseOnTopOfMouseArea(mousePosInPlane)) {
|
if (mouseOnTopOfMouseArea(mousePosInPlane, mouseEvent->pos())) {
|
||||||
s_mouseGrab = this;
|
s_mouseGrab = this;
|
||||||
setHovering(true);
|
setHovering(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -362,7 +527,7 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event)
|
|||||||
case QEvent::HoverMove: {
|
case QEvent::HoverMove: {
|
||||||
auto const mouseEvent = static_cast<QMouseEvent *>(event);
|
auto const mouseEvent = static_cast<QMouseEvent *>(event);
|
||||||
const QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos());
|
const QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos());
|
||||||
const bool hasMouse = mouseOnTopOfMouseArea(mousePosInPlane);
|
const bool hasMouse = mouseOnTopOfMouseArea(mousePosInPlane, mouseEvent->pos());
|
||||||
|
|
||||||
setHovering(hasMouse);
|
setHovering(hasMouse);
|
||||||
|
|
||||||
@@ -376,9 +541,9 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event)
|
|||||||
s_mouseGrab = nullptr;
|
s_mouseGrab = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_dragging && !qFuzzyCompare(mousePosInPlane.z(), -1)) {
|
if (m_dragging && (m_circlePickArea.y() > 0. || !qFuzzyCompare(mousePosInPlane.z(), -1))) {
|
||||||
m_mousePosInPlane = mousePosInPlane;
|
m_mousePosInPlane = mousePosInPlane;
|
||||||
emit dragged(mousePosInPlane, mouseEvent->globalPos());
|
emit dragged(mousePosInPlane, mouseEvent->pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -408,6 +573,25 @@ void MouseArea3D::setHovering(bool enable)
|
|||||||
emit hoveringChanged();
|
emit hoveringChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector3D MouseArea3D::getNormal() const
|
||||||
|
{
|
||||||
|
const float *dataPtr(sceneTransform().data());
|
||||||
|
return QVector3D(dataPtr[8], dataPtr[9], dataPtr[10]).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D MouseArea3D::getCameraToNodeDir(QQuick3DNode *node) const
|
||||||
|
{
|
||||||
|
QVector3D dir;
|
||||||
|
if (qobject_cast<QQuick3DOrthographicCamera *>(m_view3D->camera())) {
|
||||||
|
dir = m_view3D->camera()->cameraNode()->getDirection();
|
||||||
|
// Camera direction has x and y flipped
|
||||||
|
dir = QVector3D(-dir.x(), -dir.y(), dir.z());
|
||||||
|
} else {
|
||||||
|
dir = (node->scenePosition() - m_view3D->camera()->scenePosition()).normalized();
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,9 +28,11 @@
|
|||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
|
|
||||||
#include <QtGui/qvector3d.h>
|
#include <QtGui/qvector3d.h>
|
||||||
|
#include <QtCore/qpoint.h>
|
||||||
#include <QtCore/qpointer.h>
|
#include <QtCore/qpointer.h>
|
||||||
|
|
||||||
#include <QtQuick3D/private/qquick3dnode_p.h>
|
#include <QtQuick3D/private/qquick3dnode_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dmodel_p.h>
|
||||||
#include <QtQuick3D/private/qquick3dviewport_p.h>
|
#include <QtQuick3D/private/qquick3dviewport_p.h>
|
||||||
#include <QtQuick3D/private/qtquick3dglobal_p.h>
|
#include <QtQuick3D/private/qtquick3dglobal_p.h>
|
||||||
|
|
||||||
@@ -50,6 +52,9 @@ class MouseArea3D : public QQuick3DNode
|
|||||||
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
||||||
Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
|
Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
|
||||||
Q_PROPERTY(int active READ active WRITE setActive NOTIFY activeChanged)
|
Q_PROPERTY(int active READ active WRITE setActive NOTIFY activeChanged)
|
||||||
|
Q_PROPERTY(QPointF circlePickArea READ circlePickArea WRITE setCirclePickArea NOTIFY circlePickAreaChanged)
|
||||||
|
Q_PROPERTY(qreal minAngle READ minAngle WRITE setMinAngle NOTIFY minAngleChanged)
|
||||||
|
Q_PROPERTY(QQuick3DNode *pickNode READ pickNode WRITE setPickNode NOTIFY pickNodeChanged)
|
||||||
|
|
||||||
Q_INTERFACES(QQmlParserStatus)
|
Q_INTERFACES(QQmlParserStatus)
|
||||||
|
|
||||||
@@ -68,11 +73,17 @@ public:
|
|||||||
bool dragging() const;
|
bool dragging() const;
|
||||||
bool grabsMouse() const;
|
bool grabsMouse() const;
|
||||||
bool active() const;
|
bool active() const;
|
||||||
|
QPointF circlePickArea() const;
|
||||||
|
qreal minAngle() const;
|
||||||
|
QQuick3DNode *pickNode() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setView3D(QQuick3DViewport *view3D);
|
void setView3D(QQuick3DViewport *view3D);
|
||||||
void setGrabsMouse(bool grabsMouse);
|
void setGrabsMouse(bool grabsMouse);
|
||||||
void setActive(bool active);
|
void setActive(bool active);
|
||||||
|
void setCirclePickArea(const QPointF &pickArea);
|
||||||
|
void setMinAngle(qreal angle);
|
||||||
|
void setPickNode(QQuick3DNode *node);
|
||||||
|
|
||||||
void setX(qreal x);
|
void setX(qreal x);
|
||||||
void setY(qreal y);
|
void setY(qreal y);
|
||||||
@@ -89,22 +100,35 @@ public slots:
|
|||||||
const QVector3D &pressPos,
|
const QVector3D &pressPos,
|
||||||
const QVector3D &sceneRelativeDistance, bool global);
|
const QVector3D &sceneRelativeDistance, bool global);
|
||||||
|
|
||||||
|
Q_INVOKABLE qreal getNewRotationAngle(QQuick3DNode *node, const QVector3D &pressPos,
|
||||||
|
const QVector3D ¤tPos, const QVector3D &nodePos,
|
||||||
|
qreal prevAngle, bool trackBall);
|
||||||
|
Q_INVOKABLE void applyRotationAngleToNode(QQuick3DNode *node, const QVector3D &startRotation,
|
||||||
|
qreal angle);
|
||||||
|
Q_INVOKABLE void applyFreeRotation(QQuick3DNode *node, const QVector3D &startRotation,
|
||||||
|
const QVector3D &pressPos, const QVector3D ¤tPos);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void view3DChanged();
|
void view3DChanged();
|
||||||
|
|
||||||
void xChanged(qreal x);
|
void xChanged();
|
||||||
void yChanged(qreal y);
|
void yChanged();
|
||||||
void widthChanged(qreal width);
|
void widthChanged();
|
||||||
void heightChanged(qreal height);
|
void heightChanged();
|
||||||
void priorityChanged(int level);
|
void priorityChanged();
|
||||||
|
|
||||||
void hoveringChanged();
|
void hoveringChanged();
|
||||||
void draggingChanged();
|
void draggingChanged();
|
||||||
void activeChanged(bool active);
|
void activeChanged();
|
||||||
void pressed(const QVector3D &scenePos, const QPoint &screenPos);
|
void grabsMouseChanged();
|
||||||
|
void circlePickAreaChanged();
|
||||||
|
void minAngleChanged();
|
||||||
|
void pickNodeChanged();
|
||||||
|
|
||||||
|
// angle parameter is only set if circlePickArea is specified
|
||||||
|
void pressed(const QVector3D &scenePos, const QPoint &screenPos, qreal angle);
|
||||||
void released(const QVector3D &scenePos, const QPoint &screenPos);
|
void released(const QVector3D &scenePos, const QPoint &screenPos);
|
||||||
void dragged(const QVector3D &scenePos, const QPoint &screenPos);
|
void dragged(const QVector3D &scenePos, const QPoint &screenPos);
|
||||||
void grabsMouseChanged(bool grabsMouse);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void classBegin() override {}
|
void classBegin() override {}
|
||||||
@@ -114,6 +138,8 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void setDragging(bool enable);
|
void setDragging(bool enable);
|
||||||
void setHovering(bool enable);
|
void setHovering(bool enable);
|
||||||
|
QVector3D getNormal() const;
|
||||||
|
QVector3D getCameraToNodeDir(QQuick3DNode *node) const;
|
||||||
|
|
||||||
Q_DISABLE_COPY(MouseArea3D)
|
Q_DISABLE_COPY(MouseArea3D)
|
||||||
QQuick3DViewport *m_view3D = nullptr;
|
QQuick3DViewport *m_view3D = nullptr;
|
||||||
@@ -133,6 +159,9 @@ private:
|
|||||||
static MouseArea3D *s_mouseGrab;
|
static MouseArea3D *s_mouseGrab;
|
||||||
bool m_grabsMouse;
|
bool m_grabsMouse;
|
||||||
QVector3D m_mousePosInPlane;
|
QVector3D m_mousePosInPlane;
|
||||||
|
QPointF m_circlePickArea;
|
||||||
|
qreal m_minAngle = 0.;
|
||||||
|
QQuick3DNode *m_pickNode = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -22,8 +22,12 @@
|
|||||||
<file>mockfiles/ScaleRod.qml</file>
|
<file>mockfiles/ScaleRod.qml</file>
|
||||||
<file>mockfiles/ScaleGizmo.qml</file>
|
<file>mockfiles/ScaleGizmo.qml</file>
|
||||||
<file>mockfiles/ToolBarButton.qml</file>
|
<file>mockfiles/ToolBarButton.qml</file>
|
||||||
|
<file>mockfiles/RotateGizmo.qml</file>
|
||||||
|
<file>mockfiles/RotateRing.qml</file>
|
||||||
<file>mockfiles/meshes/arrow.mesh</file>
|
<file>mockfiles/meshes/arrow.mesh</file>
|
||||||
<file>mockfiles/meshes/scalerod.mesh</file>
|
<file>mockfiles/meshes/scalerod.mesh</file>
|
||||||
|
<file>mockfiles/meshes/ring.mesh</file>
|
||||||
|
<file>mockfiles/meshes/ringselect.mesh</file>
|
||||||
<file>mockfiles/images/camera-pick-icon.png</file>
|
<file>mockfiles/images/camera-pick-icon.png</file>
|
||||||
<file>mockfiles/images/camera-pick-icon@2x.png</file>
|
<file>mockfiles/images/camera-pick-icon@2x.png</file>
|
||||||
<file>mockfiles/images/light-pick-icon.png</file>
|
<file>mockfiles/images/light-pick-icon.png</file>
|
||||||
|
Reference in New Issue
Block a user