Files
qt-creator/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml
Miikka Heikkinen c789186418 QmlDesigner: Handle picking of models under View3D component properly
If a model defined inside the View3D component is picked on 3D editor,
the parent View3D is selected instead as there is no instance for
the model itself. This is similar to how Node based component picking
works.

Fixes: QDS-6934
Change-Id: I4f273972da8cb1c55f03cab323dd9804a5d10def
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
2022-05-31 12:02:49 +00:00

943 lines
37 KiB
QML

/****************************************************************************
**
** 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.12
import QtQuick3D 1.15
import MouseArea3D 1.0
Item {
id: viewRoot
width: 1024
height: 768
visible: true
property Node activeScene: null
property View3D editView: null
property string sceneId
property bool showEditLight: false
property bool showGrid: true
property bool showSelectionBox: true
property bool showIconGizmo: true
property bool showCameraFrustum: false
property bool usePerspective: true
property bool globalOrientation: false
property alias contentItem: contentItem
enum SelectionMode { Item, Group }
enum TransformMode { Move, Rotate, Scale }
property int selectionMode: EditView3D.SelectionMode.Item
property int transformMode: EditView3D.TransformMode.Move
property Node selectedNode: null // This is multiSelectionNode in multi-selection case
property var selectedNodes: [] // All selected nodes
property var lightIconGizmos: []
property var cameraGizmos: []
property var selectionBoxes: []
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
property bool shuttingDown: false
property real fps: 0
signal selectionChanged(var selectedNodes)
signal commitObjectProperty(var objects, var propNames)
signal changeObjectProperty(var objects, var propNames)
signal notifyActiveSceneChange()
onUsePerspectiveChanged: _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight)
onGlobalOrientationChanged: _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
onShowGridChanged: _generalHelper.storeToolState(sceneId, "showGrid", showGrid);
onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox);
onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo);
onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum);
onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode);
onActiveSceneChanged: updateActiveScene()
function aboutToShutDown()
{
shuttingDown = true;
}
function createEditView()
{
var component = Qt.createComponent("SceneView3D.qml");
if (component.status === Component.Ready) {
editView = component.createObject(viewRect,
{"usePerspective": usePerspective,
"showSceneLight": showEditLight,
"showGrid": showGrid,
"importScene": activeScene,
"cameraZoomFactor": cameraControl._zoomFactor,
"z": 1});
editView.usePerspective = Qt.binding(function() {return usePerspective;});
editView.showSceneLight = Qt.binding(function() {return showEditLight;});
editView.showGrid = Qt.binding(function() {return showGrid;});
editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;});
selectionBoxes.length = 0;
cameraControl.forceActiveFocus();
return true;
}
return false;
}
function updateActiveScene()
{
if (editView) {
// Destroy is async, so make sure we don't get any more updates for the old editView
_generalHelper.enableItemUpdate(editView, false);
editView.visible = false;
editView.destroy();
}
// importScene cannot be updated after initial set, so we need to reconstruct entire View3D
if (createEditView()) {
if (activeScene) {
var toolStates = _generalHelper.getToolStates(sceneId);
if (Object.keys(toolStates).length > 0) {
updateToolStates(toolStates, true);
} else {
// Don't inherit the edit light state from the previous scene, but rather
// turn the edit light on for scenes that do not have any scene
// lights, and turn it off for scenes that have.
var hasSceneLight = false;
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightIconGizmos[i].scene === activeScene) {
hasSceneLight = true;
break;
}
}
showEditLight = !hasSceneLight;
storeCurrentToolStates();
}
} else {
// When active scene is deleted, this function gets called by object deletion
// handlers without going through setActiveScene, so make sure sceneId is cleared.
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (!shuttingDown) {
sceneId = "";
storeCurrentToolStates();
}
}
notifyActiveSceneChange();
}
}
function setActiveScene(newScene, newSceneId)
{
var needExplicitUpdate = !activeScene && !newScene;
sceneId = newSceneId;
activeScene = newScene;
if (needExplicitUpdate)
updateActiveScene();
}
// Disables edit view update if scene doesn't match current activeScene.
// If it matches, updates are enabled.
function enableEditViewUpdate(scene)
{
if (editView)
_generalHelper.enableItemUpdate(editView, (scene && scene === activeScene));
}
function handleActiveSceneIdChange(newId)
{
if (sceneId !== newId) {
sceneId = newId;
storeCurrentToolStates();
}
}
function fitToView()
{
if (editView) {
var boxModels = [];
if (selectedNodes.length > 1) {
for (var i = 0; i < selectedNodes.length; ++i) {
if (selectionBoxes.length > i)
boxModels.push(selectionBoxes[i].model)
}
} else if (selectedNodes.length > 0 && selectionBoxes.length > 0) {
boxModels.push(selectionBoxes[0].model);
}
cameraControl.focusObject(boxModels, editView.camera.eulerRotation, true, false);
}
}
function alignCamerasToView()
{
if (editView) {
cameraControl.alignCameras(selectedNodes);
var propertyNames = ["position", "eulerRotation"];
viewRoot.changeObjectProperty(selectedNodes, propertyNames);
viewRoot.commitObjectProperty(selectedNodes, propertyNames);
}
}
function alignViewToCamera()
{
if (editView)
cameraControl.alignView(selectedNodes);
}
// If resetToDefault is true, tool states not specifically set to anything will be reset to
// their default state.
function updateToolStates(toolStates, resetToDefault)
{
if ("showEditLight" in toolStates)
showEditLight = toolStates.showEditLight;
else if (resetToDefault)
showEditLight = false;
if ("showGrid" in toolStates)
showGrid = toolStates.showGrid;
else if (resetToDefault)
showGrid = true;
if ("showSelectionBox" in toolStates)
showSelectionBox = toolStates.showSelectionBox;
else if (resetToDefault)
showSelectionBox = true;
if ("showIconGizmo" in toolStates)
showIconGizmo = toolStates.showIconGizmo;
else if (resetToDefault)
showIconGizmo = true;
if ("showCameraFrustum" in toolStates)
showCameraFrustum = toolStates.showCameraFrustum;
else if (resetToDefault)
showCameraFrustum = false;
if ("usePerspective" in toolStates)
usePerspective = toolStates.usePerspective;
else if (resetToDefault)
usePerspective = true;
if ("globalOrientation" in toolStates)
globalOrientation = toolStates.globalOrientation;
else if (resetToDefault)
globalOrientation = false;
if ("selectionMode" in toolStates)
selectionMode = toolStates.selectionMode;
else if (resetToDefault)
selectionMode = EditView3D.SelectionMode.Item;
if ("transformMode" in toolStates)
transformMode = toolStates.transformMode;
else if (resetToDefault)
transformMode = EditView3D.TransformMode.Move;
if ("editCamState" in toolStates)
cameraControl.restoreCameraState(toolStates.editCamState);
else if (resetToDefault)
cameraControl.restoreDefaultState();
}
function storeCurrentToolStates()
{
_generalHelper.storeToolState(sceneId, "showEditLight", showEditLight)
_generalHelper.storeToolState(sceneId, "showGrid", showGrid)
_generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox)
_generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo)
_generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum)
_generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
_generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
_generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
_generalHelper.storeToolState(sceneId, "transformMode", transformMode);
cameraControl.storeCameraState(0);
}
function ensureSelectionBoxes(count)
{
var needMore = count - selectionBoxes.length
if (needMore > 0) {
var component = Qt.createComponent("SelectionBox.qml");
if (component.status === Component.Ready) {
for (var i = 0; i < needMore; ++i) {
var geometryName = _generalHelper.generateUniqueName("SelectionBoxGeometry");
var boxParent = null;
if (editView)
boxParent = editView.sceneHelpers;
var box = component.createObject(boxParent, {"view3D": editView,
"geometryName": geometryName});
selectionBoxes[selectionBoxes.length] = box;
box.view3D = Qt.binding(function() {return editView;});
box.visible = Qt.binding(function() {return showSelectionBox;});
}
}
}
}
function selectObjects(objects)
{
// Create selection boxes as necessary. One more box than is actually needed is created, so
// that we always have a previously created box to use for new selection.
// This fixes an occasional visual glitch when creating a new box.
ensureSelectionBoxes(objects.length + 1)
var i;
for (i = 0; i < objects.length; ++i)
selectionBoxes[i].targetNode = objects[i];
for (i = objects.length; i < selectionBoxes.length; ++i)
selectionBoxes[i].targetNode = null;
selectedNodes = objects;
if (objects.length === 0) {
selectedNode = null;
} else if (objects.length > 1) {
selectedNode = multiSelectionNode;
_generalHelper.setMultiSelectionTargets(multiSelectionNode, objects);
} else {
selectedNode = objects[0];
}
}
function handleObjectClicked(object, multi)
{
if (object instanceof View3D) {
// View3D can be the resolved pick target in case the 3D editor is showing content
// of a component that has View3D as root. In that case locking is resolved on C++ side
// and we ignore multiselection.
selectObjects([]);
selectionChanged([object]);
return;
}
var clickedObject;
// Click on locked object is treated same as click on empty space
if (!_generalHelper.isLocked(object))
clickedObject = object;
if (selectionMode === EditView3D.SelectionMode.Group) {
while (clickedObject && clickedObject !== activeScene
&& (activeScene instanceof Model || clickedObject.parent !== activeScene)) {
clickedObject = clickedObject.parent;
}
}
// Object selection logic:
// Regular click: Clear any multiselection, single-selects the clicked object
// Ctrl-click: No objects selected: Act as single select
// One or more objects selected: Multiselect
// Null object always clears entire selection
var newSelection = [];
if (clickedObject) {
if (multi && selectedNodes.length > 0) {
var deselect = false;
for (var i = 0; i < selectedNodes.length; ++i) {
// Multiselecting already selected object clears that object from selection
if (selectedNodes[i] !== clickedObject)
newSelection[newSelection.length] = selectedNodes[i];
else
deselect = true;
}
if (!deselect)
newSelection[newSelection.length] = clickedObject;
} else {
newSelection[0] = clickedObject;
}
}
selectObjects(newSelection);
selectionChanged(newSelection);
}
function addLightGizmo(scene, obj)
{
// Insert into first available gizmo if we don't already have gizmo for this object
var slotFound = -1;
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (!lightIconGizmos[i].targetNode) {
slotFound = i;
} else if (lightIconGizmos[i].targetNode === obj) {
lightIconGizmos[i].scene = scene;
return;
}
}
if (slotFound !== -1) {
lightIconGizmos[slotFound].scene = scene;
lightIconGizmos[slotFound].targetNode = obj;
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
return;
}
// No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
if (gizmoComponent.status === Component.Ready) {
var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
"activeScene": activeScene,
"locked": _generalHelper.isLocked(obj),
"hidden": _generalHelper.isHidden(obj),
"globalShow": showIconGizmo});
lightIconGizmos[lightIconGizmos.length] = gizmo;
gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
gizmo.activeScene = Qt.binding(function() {return activeScene;});
gizmo.globalShow = Qt.binding(function() {return showIconGizmo;});
}
}
function addCameraGizmo(scene, obj)
{
// Insert into first available gizmo if we don't already have gizmo for this object
var slotFound = -1;
for (var i = 0; i < cameraGizmos.length; ++i) {
if (!cameraGizmos[i].targetNode) {
slotFound = i;
} else if (cameraGizmos[i].targetNode === obj) {
cameraGizmos[i].scene = scene;
return;
}
}
if (slotFound !== -1) {
cameraGizmos[slotFound].scene = scene;
cameraGizmos[slotFound].targetNode = obj;
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
return;
}
// No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
var frustum = frustumComponent.createObject(
overlayScene,
{"geometryName": geometryName, "viewPortRect": viewPortRect});
var gizmo = gizmoComponent.createObject(
overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene,
"locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj),
"globalShow": showIconGizmo, "globalShowFrustum": showCameraFrustum});
cameraGizmos[cameraGizmos.length] = gizmo;
gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
gizmo.activeScene = Qt.binding(function() {return activeScene;});
gizmo.globalShow = Qt.binding(function() {return showIconGizmo;});
gizmo.globalShowFrustum = Qt.binding(function() {return showCameraFrustum;});
frustum.viewPortRect = Qt.binding(function() {return viewPortRect;});
gizmo.connectFrustum(frustum);
}
}
function releaseLightGizmo(obj)
{
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightIconGizmos[i].targetNode === obj) {
lightIconGizmos[i].scene = null;
lightIconGizmos[i].targetNode = null;
return;
}
}
}
function releaseCameraGizmo(obj)
{
for (var i = 0; i < cameraGizmos.length; ++i) {
if (cameraGizmos[i].targetNode === obj) {
cameraGizmos[i].scene = null;
cameraGizmos[i].targetNode = null;
return;
}
}
}
function updateLightGizmoScene(scene, obj)
{
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightIconGizmos[i].targetNode === obj) {
lightIconGizmos[i].scene = scene;
return;
}
}
}
function updateCameraGizmoScene(scene, obj)
{
for (var i = 0; i < cameraGizmos.length; ++i) {
if (cameraGizmos[i].targetNode === obj) {
cameraGizmos[i].scene = scene;
return;
}
}
}
Component.onCompleted: {
createEditView();
selectObjects([]);
// Work-around the fact that the projection matrix for the camera is not calculated until
// the first frame is rendered, so any initial calls to mapFrom3DScene() will fail.
_generalHelper.requestOverlayUpdate();
}
onWidthChanged: _generalHelper.requestOverlayUpdate()
onHeightChanged: _generalHelper.requestOverlayUpdate()
Connections {
target: _generalHelper
function onLockedStateChanged(node)
{
for (var i = 0; i < cameraGizmos.length; ++i) {
if (cameraGizmos[i].targetNode === node) {
cameraGizmos[i].locked = _generalHelper.isLocked(node);
return;
}
}
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightIconGizmos[i].targetNode === node) {
lightIconGizmos[i].locked = _generalHelper.isLocked(node);
return;
}
}
}
function onHiddenStateChanged(node)
{
for (var i = 0; i < cameraGizmos.length; ++i) {
if (cameraGizmos[i].targetNode === node) {
cameraGizmos[i].hidden = _generalHelper.isHidden(node);
return;
}
}
for (var i = 0; i < lightIconGizmos.length; ++i) {
if (lightIconGizmos[i].targetNode === node) {
lightIconGizmos[i].hidden = _generalHelper.isHidden(node);
return;
}
}
}
}
Node {
id: overlayScene
PerspectiveCamera {
id: overlayPerspectiveCamera
clipFar: viewRoot.editView ? viewRoot.editView.perspectiveCamera.clipFar : 1000
clipNear: viewRoot.editView ? viewRoot.editView.perspectiveCamera.clipNear : 1
position: viewRoot.editView ? viewRoot.editView.perspectiveCamera.position : Qt.vector3d(0, 0, 0)
rotation: viewRoot.editView ? viewRoot.editView.perspectiveCamera.rotation : Qt.quaternion(1, 0, 0, 0)
}
OrthographicCamera {
id: overlayOrthoCamera
clipFar: viewRoot.editView ? viewRoot.editView.orthoCamera.clipFar : 1000
clipNear: viewRoot.editView ? viewRoot.editView.orthoCamera.clipNear : 1
position: viewRoot.editView ? viewRoot.editView.orthoCamera.position : Qt.vector3d(0, 0, 0)
rotation: viewRoot.editView ? viewRoot.editView.orthoCamera.rotation : Qt.quaternion(1, 0, 0, 0)
scale: viewRoot.editView ? viewRoot.editView.orthoCamera.scale : Qt.vector3d(0, 0, 0)
}
MouseArea3D {
id: gizmoDragHelper
view3D: overlayView
}
Node {
id: multiSelectionNode
objectName: "multiSelectionNode"
}
MoveGizmo {
id: moveGizmo
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
highlightOnHover: true
targetNode: viewRoot.selectedNode
globalOrientation: viewRoot.globalOrientation
visible: viewRoot.selectedNode && transformMode === EditView3D.TransformMode.Move
view3D: overlayView
dragHelper: gizmoDragHelper
property var propertyNames: ["position"]
onPositionCommit: {
if (targetNode == multiSelectionNode)
viewRoot.commitObjectProperty(_generalHelper.multiSelectionTargets(), propertyNames);
else
viewRoot.commitObjectProperty([viewRoot.selectedNode], propertyNames);
}
onPositionMove: {
if (targetNode == multiSelectionNode)
viewRoot.changeObjectProperty(_generalHelper.multiSelectionTargets(), propertyNames);
else
viewRoot.changeObjectProperty([viewRoot.selectedNode], propertyNames);
}
}
ScaleGizmo {
id: scaleGizmo
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
highlightOnHover: true
targetNode: viewRoot.selectedNode
visible: viewRoot.selectedNode && transformMode === EditView3D.TransformMode.Scale
view3D: overlayView
dragHelper: gizmoDragHelper
property var propertyNames: ["scale"]
property var propertyNamesMulti: ["position", "scale"]
onScaleCommit: {
if (targetNode == multiSelectionNode)
viewRoot.commitObjectProperty(_generalHelper.multiSelectionTargets(), propertyNamesMulti);
else
viewRoot.commitObjectProperty([viewRoot.selectedNode], propertyNames);
}
onScaleChange: {
if (targetNode == multiSelectionNode)
viewRoot.changeObjectProperty(_generalHelper.multiSelectionTargets(), propertyNamesMulti);
else
viewRoot.changeObjectProperty([viewRoot.selectedNode], propertyNames);
}
}
RotateGizmo {
id: rotateGizmo
scale: autoScale.getScale(Qt.vector3d(7, 7, 7))
highlightOnHover: true
targetNode: viewRoot.selectedNode
globalOrientation: viewRoot.globalOrientation
visible: viewRoot.selectedNode && transformMode === EditView3D.TransformMode.Rotate
view3D: overlayView
dragHelper: gizmoDragHelper
property var propertyNames: ["eulerRotation"]
property var propertyNamesMulti: ["position", "eulerRotation"]
onRotateCommit: {
if (targetNode == multiSelectionNode)
viewRoot.commitObjectProperty(_generalHelper.multiSelectionTargets(), propertyNamesMulti);
else
viewRoot.commitObjectProperty([viewRoot.selectedNode], propertyNames);
}
onRotateChange: {
if (targetNode == multiSelectionNode)
viewRoot.changeObjectProperty(_generalHelper.multiSelectionTargets(), propertyNamesMulti);
else
viewRoot.changeObjectProperty([viewRoot.selectedNode], propertyNames);
}
}
LightGizmo {
id: lightGizmo
targetNode: viewRoot.selectedNode != multiSelectionNode ? viewRoot.selectedNode : null
view3D: overlayView
dragHelper: gizmoDragHelper
onPropertyValueCommit: (propName)=> {
viewRoot.commitObjectProperty([targetNode], [propName]);
}
onPropertyValueChange: (propName)=> {
viewRoot.changeObjectProperty([targetNode], [propName]);
}
}
AutoScaleHelper {
id: autoScale
view3D: overlayView
position: moveGizmo.scenePosition
}
AutoScaleHelper {
id: pivotAutoScale
view3D: overlayView
position: pivotLine.startPos
}
Line3D {
id: pivotLine
visible: viewRoot.selectedNode && viewRoot.selectedNode != multiSelectionNode
name: "3D Edit View Pivot Line"
color: "#ddd600"
startPos: viewRoot.selectedNode ? viewRoot.selectedNode.scenePosition
: Qt.vector3d(0, 0, 0)
Connections {
target: viewRoot
function onSelectedNodeChanged()
{
pivotLine.endPos = gizmoDragHelper.pivotScenePosition(viewRoot.selectedNode);
}
}
Connections {
target: viewRoot.selectedNode
function onSceneTransformChanged()
{
pivotLine.endPos = gizmoDragHelper.pivotScenePosition(viewRoot.selectedNode);
}
}
Model {
id: pivotCap
source: "#Sphere"
scale: pivotAutoScale.getScale(Qt.vector3d(0.03, 0.03, 0.03))
position: pivotLine.startPos
materials: [
DefaultMaterial {
id: lineMat
lighting: DefaultMaterial.NoLighting
cullMode: Material.NoCulling
diffuseColor: pivotLine.color
}
]
}
}
}
Item {
id: contentItem
anchors.fill: parent
Rectangle {
id: viewRect
anchors.fill: parent
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
GradientStop { position: 0.0; color: "#999999" }
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: false
property MouseArea3D freeDraggerArea
property point pressPoint
property bool initialMoveBlock: false
onPressed: (mouse)=> {
if (viewRoot.editView) {
var pickResult = viewRoot.editView.pick(mouse.x, mouse.y);
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
mouse.modifiers & Qt.ControlModifier);
if (pickResult.objectHit && pickResult.objectHit instanceof Node) {
if (transformMode === EditView3D.TransformMode.Move)
freeDraggerArea = moveGizmo.freeDraggerArea;
else if (transformMode === EditView3D.TransformMode.Rotate)
freeDraggerArea = rotateGizmo.freeDraggerArea;
else if (transformMode === EditView3D.TransformMode.Scale)
freeDraggerArea = scaleGizmo.freeDraggerArea;
pressPoint.x = mouse.x;
pressPoint.y = mouse.y;
initialMoveBlock = true;
} else {
mouse.accepted = false;
}
}
}
onPositionChanged: (mouse)=> {
if (freeDraggerArea) {
if (initialMoveBlock && Math.abs(pressPoint.x - mouse.x) + Math.abs(pressPoint.y - mouse.y) > 10) {
// Don't force press event at actual press, as that puts the gizmo
// in free-dragging state, which is bad UX if drag is not actually done
freeDraggerArea.forcePressEvent(pressPoint.x, pressPoint.y);
freeDraggerArea.forceMoveEvent(mouse.x, mouse.y);
initialMoveBlock = false;
} else {
freeDraggerArea.forceMoveEvent(mouse.x, mouse.y);
}
}
}
function handleRelease(mouse)
{
if (freeDraggerArea) {
if (initialMoveBlock)
freeDraggerArea.forceReleaseEvent(pressPoint.x, pressPoint.y);
else
freeDraggerArea.forceReleaseEvent(mouse.x, mouse.y);
freeDraggerArea = null;
}
}
onReleased: (mouse)=> {
handleRelease(mouse);
}
onCanceled: (mouse)=> {
handleRelease(mouse);
}
}
DropArea {
anchors.fill: parent
}
View3D {
id: overlayView
anchors.fill: parent
camera: viewRoot.usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera
importScene: overlayScene
z: 2
}
Overlay2D {
id: gizmoLabel
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
targetView: overlayView
visible: targetNode.dragging
z: 3
Rectangle {
color: "white"
x: -width / 2
y: -height - 8
width: gizmoLabelText.width + 4
height: gizmoLabelText.height + 4
border.width: 1
Text {
id: gizmoLabelText
text: {
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (shuttingDown)
return text;
var l = Qt.locale();
var targetProperty;
if (viewRoot.selectedNode) {
if (gizmoLabel.targetNode === moveGizmo)
targetProperty = viewRoot.selectedNode.position;
else
targetProperty = viewRoot.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
}
}
}
Rectangle {
id: rotateGizmoLabel
color: "white"
x: rotateGizmo.currentMousePos.x - (10 + width)
y: rotateGizmo.currentMousePos.y - (10 + height)
width: rotateGizmoLabelText.width + 4
height: rotateGizmoLabelText.height + 4
border.width: 1
visible: rotateGizmo.dragging
parent: rotateGizmo.view3D
z: 3
Text {
id: rotateGizmoLabelText
text: {
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (shuttingDown)
return text;
var l = Qt.locale();
if (rotateGizmo.targetNode) {
var degrees = rotateGizmo.currentAngle * (180 / Math.PI);
return Number(degrees).toLocaleString(l, 'f', 1);
} else {
return "";
}
}
anchors.centerIn: parent
}
}
Rectangle {
id: lightGizmoLabel
color: "white"
x: lightGizmo.currentMousePos.x - (10 + width)
y: lightGizmo.currentMousePos.y - (10 + height)
width: lightGizmoLabelText.width + 4
height: lightGizmoLabelText.height + 4
border.width: 1
visible: lightGizmo.dragging
parent: lightGizmo.view3D
z: 3
Text {
id: lightGizmoLabelText
text: lightGizmo.currentLabel
anchors.centerIn: parent
}
}
EditCameraController {
id: cameraControl
camera: viewRoot.editView ? viewRoot.editView.camera : null
anchors.fill: parent
view3d: viewRoot.editView
sceneId: viewRoot.sceneId
}
}
AxisHelper {
anchors.right: parent.right
anchors.top: parent.top
width: 100
height: width
editCameraCtrl: cameraControl
selectedNode: viewRoot.selectedNodes.length === 1 ? viewRoot.selectionBoxes[0].model
: viewRoot.selectedNode
}
Text {
id: sceneLabel
text: viewRoot.sceneId
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 4
font.pixelSize: 14
color: "white"
}
Text {
id: fpsLabel
text: viewRoot.fps
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 4
font.pixelSize: 12
color: "white"
visible: viewRoot.fps > 0
}
}
}