forked from qt-creator/qt-creator
QmlDesigner: Add planar move and scale handles to gizmos
Change-Id: Icae60ec35fc84d731243a005e97b174fa9a94815 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -278,12 +278,12 @@ Window {
|
||||
x: 8
|
||||
RadioButton {
|
||||
id: moveToolControl
|
||||
checked: false
|
||||
checked: true
|
||||
text: qsTr("Move Tool")
|
||||
}
|
||||
RadioButton {
|
||||
id: scaleToolControl
|
||||
checked: true
|
||||
checked: false
|
||||
text: qsTr("Scale Tool")
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,8 @@ Node {
|
||||
property Node targetNode: null
|
||||
property bool globalOrientation: true
|
||||
readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging
|
||||
|| centerMouseArea.dragging
|
||||
|| planeX.dragging || planeY.dragging || planeZ.dragging
|
||||
|| centerBall.dragging
|
||||
|
||||
signal positionCommit()
|
||||
signal positionMove()
|
||||
@@ -45,7 +46,6 @@ Node {
|
||||
|
||||
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))
|
||||
@@ -59,7 +59,6 @@ Node {
|
||||
|
||||
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.6, 0, 1))
|
||||
@@ -73,7 +72,6 @@ Node {
|
||||
|
||||
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, 1, 1))
|
||||
@@ -85,75 +83,72 @@ Node {
|
||||
onPositionMove: moveGizmo.positionMove()
|
||||
}
|
||||
|
||||
PlanarMoveHandle {
|
||||
id: planeX
|
||||
|
||||
y: 10
|
||||
z: 10
|
||||
|
||||
rotation: Qt.vector3d(0, 90, 0)
|
||||
targetNode: moveGizmo.targetNode
|
||||
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1))
|
||||
: Qt.rgba(1, 0, 0, 1)
|
||||
view3D: moveGizmo.view3D
|
||||
active: moveGizmo.visible
|
||||
|
||||
onPositionCommit: moveGizmo.positionCommit()
|
||||
onPositionMove: moveGizmo.positionMove()
|
||||
}
|
||||
|
||||
PlanarMoveHandle {
|
||||
id: planeY
|
||||
|
||||
x: 10
|
||||
z: 10
|
||||
|
||||
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
|
||||
active: moveGizmo.visible
|
||||
|
||||
onPositionCommit: moveGizmo.positionCommit()
|
||||
onPositionMove: moveGizmo.positionMove()
|
||||
}
|
||||
|
||||
PlanarMoveHandle {
|
||||
id: planeZ
|
||||
|
||||
x: 10
|
||||
y: 10
|
||||
|
||||
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
|
||||
active: moveGizmo.visible
|
||||
|
||||
onPositionCommit: moveGizmo.positionCommit()
|
||||
onPositionMove: moveGizmo.positionMove()
|
||||
}
|
||||
}
|
||||
|
||||
Model {
|
||||
PlanarMoveHandle {
|
||||
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
|
||||
}
|
||||
color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1))
|
||||
: Qt.rgba(0.5, 0.5, 0.5, 1)
|
||||
rotation: view3D.camera.rotation
|
||||
priority: 1
|
||||
targetNode: moveGizmo.targetNode
|
||||
|
||||
MouseArea3D {
|
||||
id: centerMouseArea
|
||||
view3D: moveGizmo.view3D
|
||||
x: -60
|
||||
y: -60
|
||||
width: 120
|
||||
height: 120
|
||||
rotation: view3D.camera.rotation
|
||||
grabsMouse: moveGizmo.targetNode
|
||||
priority: 1
|
||||
active: moveGizmo.visible
|
||||
view3D: moveGizmo.view3D
|
||||
active: moveGizmo.visible
|
||||
|
||||
property var _pointerPosPressed
|
||||
property var _targetStartPos
|
||||
|
||||
function localPos(scenePos)
|
||||
{
|
||||
var scenePointerPos = mapPositionToScene(scenePos);
|
||||
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(scenePos);
|
||||
var sp = moveGizmo.targetNode.scenePosition;
|
||||
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
|
||||
}
|
||||
onDragged: {
|
||||
if (!moveGizmo.targetNode)
|
||||
return;
|
||||
|
||||
moveGizmo.targetNode.position = localPos(scenePos);
|
||||
moveGizmo.positionMove();
|
||||
}
|
||||
onReleased: {
|
||||
if (!moveGizmo.targetNode)
|
||||
return;
|
||||
|
||||
moveGizmo.targetNode.position = localPos(scenePos);
|
||||
moveGizmo.positionCommit();
|
||||
}
|
||||
}
|
||||
onPositionCommit: moveGizmo.positionCommit()
|
||||
onPositionMove: moveGizmo.positionMove()
|
||||
}
|
||||
}
|
||||
|
118
share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml
Normal file
118
share/qtcreator/qml/qmlpuppet/mockfiles/PlanarDraggable.qml
Normal file
@@ -0,0 +1,118 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
|
||||
property View3D view3D
|
||||
property alias color: gizmoMaterial.emissiveColor
|
||||
property alias priority: mouseArea.priority
|
||||
property Node targetNode: null
|
||||
property bool dragging: false
|
||||
property bool active: false
|
||||
|
||||
readonly property bool hovering: mouseArea.hovering
|
||||
|
||||
property var _pointerPosPressed
|
||||
property var _targetStartPos
|
||||
|
||||
signal pressed(var mouseArea)
|
||||
signal dragged(var mouseArea, vector3d sceneRelativeDistance)
|
||||
signal released(var mouseArea, vector3d sceneRelativeDistance)
|
||||
|
||||
rotationOrder: Node.XYZr
|
||||
source: "#Rectangle"
|
||||
|
||||
// Workaround for Material.DisableCulling bug QTBUG-79768: Show the back with another model
|
||||
Model {
|
||||
source: rootModel.source
|
||||
rotationOrder: rootModel.rotationOrder
|
||||
materials: gizmoMaterial
|
||||
rotation: Qt.vector3d(0, 180, 0)
|
||||
}
|
||||
|
||||
DefaultMaterial {
|
||||
id: gizmoMaterial
|
||||
emissiveColor: "white"
|
||||
lighting: DefaultMaterial.NoLighting
|
||||
}
|
||||
materials: gizmoMaterial
|
||||
|
||||
function handlePressed(mouseArea, scenePos)
|
||||
{
|
||||
if (!targetNode)
|
||||
return;
|
||||
|
||||
_pointerPosPressed = mouseArea.mapPositionToScene(scenePos);
|
||||
var sp = targetNode.scenePosition;
|
||||
_targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z);
|
||||
dragging = true;
|
||||
pressed(mouseArea);
|
||||
}
|
||||
|
||||
function calcRelativeDistance(mouseArea, scenePos)
|
||||
{
|
||||
var scenePointerPos = mouseArea.mapPositionToScene(scenePos);
|
||||
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: mouseArea
|
||||
view3D: rootModel.view3D
|
||||
x: -60
|
||||
y: -60
|
||||
width: 120
|
||||
height: 120
|
||||
grabsMouse: targetNode
|
||||
active: rootModel.active
|
||||
onPressed: rootModel.handlePressed(mouseArea, scenePos)
|
||||
onDragged: rootModel.handleDragged(mouseArea, scenePos)
|
||||
onReleased: rootModel.handleReleased(mouseArea, scenePos)
|
||||
}
|
||||
}
|
||||
|
55
share/qtcreator/qml/qmlpuppet/mockfiles/PlanarMoveHandle.qml
Normal file
55
share/qtcreator/qml/qmlpuppet/mockfiles/PlanarMoveHandle.qml
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
|
||||
PlanarDraggable {
|
||||
id: planarHandle
|
||||
scale: Qt.vector3d(0.024, 0.024, 0.024)
|
||||
|
||||
signal positionCommit()
|
||||
signal positionMove()
|
||||
|
||||
function localPos(sceneRelativeDistance)
|
||||
{
|
||||
var newScenePos = Qt.vector3d(
|
||||
_targetStartPos.x + sceneRelativeDistance.x,
|
||||
_targetStartPos.y + sceneRelativeDistance.y,
|
||||
_targetStartPos.z + sceneRelativeDistance.z);
|
||||
return targetNode.parent.mapPositionFromScene(newScenePos);
|
||||
}
|
||||
|
||||
onDragged: {
|
||||
targetNode.position = localPos(sceneRelativeDistance);
|
||||
positionMove();
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
targetNode.position = localPos(sceneRelativeDistance);
|
||||
positionCommit();
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
|
||||
PlanarDraggable {
|
||||
id: planarHandle
|
||||
scale: Qt.vector3d(0.024, 0.024, 0.024)
|
||||
|
||||
property bool globalOrientation: false
|
||||
|
||||
signal scaleCommit()
|
||||
signal scaleChange()
|
||||
|
||||
property var _startScale
|
||||
|
||||
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 = mouseArea.getNewScale(targetNode, _startScale,
|
||||
_pointerPosPressed, sceneRelativeDistance,
|
||||
globalOrientation);
|
||||
scaleChange();
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
targetNode.scale = mouseArea.getNewScale(targetNode, _startScale,
|
||||
_pointerPosPressed, sceneRelativeDistance,
|
||||
globalOrientation);
|
||||
scaleCommit();
|
||||
}
|
||||
}
|
@@ -35,6 +35,7 @@ Node {
|
||||
property Node targetNode: null
|
||||
property bool globalOrientation: true
|
||||
readonly property bool dragging: scaleRodX.dragging || scaleRodY.dragging || scaleRodZ.dragging
|
||||
|| planeX.dragging || planeY.dragging || planeZ.dragging
|
||||
|| centerMouseArea.dragging
|
||||
|
||||
signal scaleCommit()
|
||||
@@ -45,13 +46,13 @@ Node {
|
||||
|
||||
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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
@@ -59,13 +60,13 @@ Node {
|
||||
|
||||
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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
@@ -73,13 +74,67 @@ Node {
|
||||
|
||||
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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
}
|
||||
|
||||
PlanarScaleHandle {
|
||||
id: planeX
|
||||
|
||||
y: 10
|
||||
z: 10
|
||||
|
||||
rotation: Qt.vector3d(0, 90, 0)
|
||||
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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
}
|
||||
|
||||
PlanarScaleHandle {
|
||||
id: planeY
|
||||
|
||||
x: 10
|
||||
z: 10
|
||||
|
||||
rotation: Qt.vector3d(90, 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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
}
|
||||
|
||||
PlanarScaleHandle {
|
||||
id: planeZ
|
||||
|
||||
x: 10
|
||||
y: 10
|
||||
|
||||
rotation: Qt.vector3d(0, 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
|
||||
globalOrientation: scaleGizmo.globalOrientation
|
||||
|
||||
onScaleCommit: scaleGizmo.scaleCommit()
|
||||
onScaleChange: scaleGizmo.scaleChange()
|
||||
@@ -121,7 +176,7 @@ Node {
|
||||
if (yDelta === 0)
|
||||
return;
|
||||
var scaler = 1.0 + (yDelta * 0.025);
|
||||
if (scaler === 0 )
|
||||
if (scaler === 0)
|
||||
scaler = 0.0001;
|
||||
if (scaler < 0)
|
||||
scaler = -scaler;
|
||||
|
@@ -31,6 +31,8 @@ DirectionalDraggable {
|
||||
id: scaleRod
|
||||
source: "meshes/scalerod.mesh"
|
||||
|
||||
property bool globalOrientation: false
|
||||
|
||||
signal scaleCommit()
|
||||
signal scaleChange()
|
||||
|
||||
@@ -39,7 +41,7 @@ DirectionalDraggable {
|
||||
Model {
|
||||
source: "#Cube"
|
||||
y: 10
|
||||
scale: Qt.vector3d(0.025, 0.025, 0.025)
|
||||
scale: Qt.vector3d(0.020, 0.020, 0.020)
|
||||
materials: DefaultMaterial {
|
||||
id: material
|
||||
emissiveColor: scaleRod.color
|
||||
@@ -47,12 +49,6 @@ DirectionalDraggable {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -61,12 +57,16 @@ DirectionalDraggable {
|
||||
}
|
||||
|
||||
onDragged: {
|
||||
targetNode.scale = localScale(mouseArea, sceneRelativeDistance);
|
||||
targetNode.scale = mouseArea.getNewScale(targetNode, _startScale,
|
||||
_pointerPosPressed, sceneRelativeDistance,
|
||||
globalOrientation);
|
||||
scaleChange();
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
targetNode.scale = localScale(mouseArea, sceneRelativeDistance);
|
||||
targetNode.scale = mouseArea.getNewScale(targetNode, _startScale,
|
||||
_pointerPosPressed, sceneRelativeDistance,
|
||||
globalOrientation);
|
||||
scaleCommit();
|
||||
}
|
||||
}
|
||||
|
@@ -204,34 +204,36 @@ 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
|
||||
// Get a new scale based on a relative scene distance along a drag axis.
|
||||
// This function never returns a negative scaling.
|
||||
// Note that scaling a rotated object in global coordinate space can't be meaningfully done without
|
||||
// distorting the object beyond what current scale property can represent, so global scaling is
|
||||
// effectively same as local scaling.
|
||||
QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startScale,
|
||||
const QVector3D &pressPos,
|
||||
const QVector3D &sceneRelativeDistance, float scaler)
|
||||
const QVector3D &sceneRelativeDistance, bool global)
|
||||
{
|
||||
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;
|
||||
const QVector3D nodeToPressPos = pressPos - scenePos;
|
||||
const QVector3D nodeToRelPos = nodeToPressPos + sceneRelativeDistance;
|
||||
const float sceneToPressLen = nodeToPressPos.length();
|
||||
QVector3D scaleDirVector = nodeToRelPos;
|
||||
float magnitude = (scaleDirVector.length() / sceneToPressLen);
|
||||
scaleDirVector.normalize();
|
||||
|
||||
// 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;
|
||||
// Reset everything but rotation to ensure translation and scale don't affect rotation below
|
||||
newTransform(0, 3) = 0;
|
||||
newTransform(1, 3) = 0;
|
||||
newTransform(2, 3) = 0;
|
||||
QVector3D curScale = getScale(newTransform);
|
||||
if (qFuzzyIsNull(curScale.x()))
|
||||
curScale.setX(nonZeroValue);
|
||||
@@ -241,24 +243,29 @@ QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startSca
|
||||
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();
|
||||
// Rotate the local scale vector so that scale axes are parallel to global axes for easier
|
||||
// scale vector manipulation
|
||||
if (!global)
|
||||
scaleDirVector = newTransform.inverted().map(scaleDirVector).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;
|
||||
scaleDirVector.setX(qAbs(scaleDirVector.x()));
|
||||
scaleDirVector.setY(qAbs(scaleDirVector.y()));
|
||||
scaleDirVector.setZ(qAbs(scaleDirVector.z()));
|
||||
|
||||
// Make sure the longest scale vec axis is equal to 1 before applying magnitude to avoid
|
||||
// initial jump in size when planar drag starts
|
||||
float maxDir = qMax(qMax(scaleDirVector.x(), scaleDirVector.y()), scaleDirVector.z());
|
||||
QVector3D scaleVec = scaleDirVector / maxDir;
|
||||
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());
|
||||
}
|
||||
|
||||
// Zero axes on scale vector indicate directions we don't want scaling to affect
|
||||
if (qFuzzyIsNull(scaleVec.x()))
|
||||
scaleVec.setX(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.y()))
|
||||
scaleVec.setY(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.z()))
|
||||
scaleVec.setZ(1.f);
|
||||
scaleVec *= startScale;
|
||||
|
||||
newTransform = parentTransform;
|
||||
|
@@ -87,7 +87,7 @@ public slots:
|
||||
|
||||
Q_INVOKABLE QVector3D getNewScale(QQuick3DNode *node, const QVector3D &startScale,
|
||||
const QVector3D &pressPos,
|
||||
const QVector3D &sceneRelativeDistance, float scaler);
|
||||
const QVector3D &sceneRelativeDistance, bool global);
|
||||
|
||||
signals:
|
||||
void view3DChanged();
|
||||
|
@@ -16,6 +16,9 @@
|
||||
<file>mockfiles/IconGizmo.qml</file>
|
||||
<file>mockfiles/Overlay2D.qml</file>
|
||||
<file>mockfiles/DirectionalDraggable.qml</file>
|
||||
<file>mockfiles/PlanarDraggable.qml</file>
|
||||
<file>mockfiles/PlanarMoveHandle.qml</file>
|
||||
<file>mockfiles/PlanarScaleHandle.qml</file>
|
||||
<file>mockfiles/ScaleRod.qml</file>
|
||||
<file>mockfiles/ScaleGizmo.qml</file>
|
||||
<file>mockfiles/meshes/arrow.mesh</file>
|
||||
|
Reference in New Issue
Block a user