forked from qt-creator/qt-creator
QmlDesigner: Add support for multiple views to 3D edit view
Any subtree of Nodes can be shown in 3D edit view. Selecting any Node or their children, or View3D changes the view in 3D edit view to the relevant scene. Fixes: QDS-1494 Fixes: QDS-1565 Change-Id: I2d5a6f88bab2a20b74c347351235f79fb530519b Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -40,7 +40,7 @@ DirectionalDraggable {
|
|||||||
_targetStartPos.x + sceneRelativeDistance.x,
|
_targetStartPos.x + sceneRelativeDistance.x,
|
||||||
_targetStartPos.y + sceneRelativeDistance.y,
|
_targetStartPos.y + sceneRelativeDistance.y,
|
||||||
_targetStartPos.z + sceneRelativeDistance.z);
|
_targetStartPos.z + sceneRelativeDistance.z);
|
||||||
return targetNode.parent.mapPositionFromScene(newScenePos);
|
return targetNode.parent ? targetNode.parent.mapPositionFromScene(newScenePos) : newScenePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDragged: {
|
onDragged: {
|
||||||
|
@@ -37,9 +37,9 @@ View3D {
|
|||||||
Node {
|
Node {
|
||||||
OrthographicCamera {
|
OrthographicCamera {
|
||||||
id: axisHelperCamera
|
id: axisHelperCamera
|
||||||
rotation: editCameraCtrl.camera.rotation
|
rotation: editCameraCtrl.camera ? editCameraCtrl.camera.rotation : Qt.vector3d(0, 0, 0)
|
||||||
position: editCameraCtrl.camera.position.minus(editCameraCtrl._lookAtPoint)
|
position: editCameraCtrl.camera ? editCameraCtrl.camera.position.minus(editCameraCtrl._lookAtPoint)
|
||||||
.normalized().times(600)
|
.normalized().times(600) : Qt.vector3d(0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoScaleHelper {
|
AutoScaleHelper {
|
||||||
|
@@ -46,6 +46,9 @@ Item {
|
|||||||
property Camera _prevCamera: null
|
property Camera _prevCamera: null
|
||||||
|
|
||||||
function restoreCameraState(cameraState) {
|
function restoreCameraState(cameraState) {
|
||||||
|
if (!camera)
|
||||||
|
return;
|
||||||
|
|
||||||
_lookAtPoint = cameraState[0];
|
_lookAtPoint = cameraState[0];
|
||||||
_zoomFactor = cameraState[1];
|
_zoomFactor = cameraState[1];
|
||||||
camera.position = cameraState[2];
|
camera.position = cameraState[2];
|
||||||
@@ -55,6 +58,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function storeCameraState(delay) {
|
function storeCameraState(delay) {
|
||||||
|
if (!camera)
|
||||||
|
return;
|
||||||
|
|
||||||
var cameraState = [];
|
var cameraState = [];
|
||||||
cameraState[0] = _lookAtPoint;
|
cameraState[0] = _lookAtPoint;
|
||||||
cameraState[1] = _zoomFactor;
|
cameraState[1] = _zoomFactor;
|
||||||
@@ -66,6 +72,9 @@ Item {
|
|||||||
|
|
||||||
function focusObject(targetObject, rotation, updateZoom)
|
function focusObject(targetObject, rotation, updateZoom)
|
||||||
{
|
{
|
||||||
|
if (!camera)
|
||||||
|
return;
|
||||||
|
|
||||||
camera.rotation = rotation;
|
camera.rotation = rotation;
|
||||||
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
|
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
|
||||||
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, updateZoom);
|
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, updateZoom);
|
||||||
@@ -76,16 +85,19 @@ Item {
|
|||||||
|
|
||||||
function zoomRelative(distance)
|
function zoomRelative(distance)
|
||||||
{
|
{
|
||||||
|
if (!camera)
|
||||||
|
return;
|
||||||
|
|
||||||
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
|
_zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance,
|
||||||
_lookAtPoint, _zoomFactor, true);
|
_lookAtPoint, _zoomFactor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
cameraCtrl._defaultCameraLookAtDistance = cameraCtrl.camera.position.length();
|
cameraCtrl._defaultCameraLookAtDistance = Qt.vector3d(0, 600, -600).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
onCameraChanged: {
|
onCameraChanged: {
|
||||||
if (_prevCamera) {
|
if (camera && _prevCamera) {
|
||||||
// Reset zoom on previous camera to ensure it's properties are good to copy to new cam
|
// Reset zoom on previous camera to ensure it's properties are good to copy to new cam
|
||||||
_generalHelper.zoomCamera(_prevCamera, 0, _defaultCameraLookAtDistance, _lookAtPoint,
|
_generalHelper.zoomCamera(_prevCamera, 0, _defaultCameraLookAtDistance, _lookAtPoint,
|
||||||
1, false);
|
1, false);
|
||||||
@@ -106,7 +118,7 @@ Item {
|
|||||||
hoverEnabled: false
|
hoverEnabled: false
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onPositionChanged: {
|
onPositionChanged: {
|
||||||
if (mouse.modifiers === Qt.AltModifier && cameraCtrl._dragging) {
|
if (cameraCtrl.camera && mouse.modifiers === Qt.AltModifier && cameraCtrl._dragging) {
|
||||||
var currentPoint = Qt.vector3d(mouse.x, mouse.y, 0);
|
var currentPoint = Qt.vector3d(mouse.x, mouse.y, 0);
|
||||||
if (cameraCtrl._button == Qt.LeftButton) {
|
if (cameraCtrl._button == Qt.LeftButton) {
|
||||||
_generalHelper.orbitCamera(cameraCtrl.camera, cameraCtrl._startRotation,
|
_generalHelper.orbitCamera(cameraCtrl.camera, cameraCtrl._startRotation,
|
||||||
@@ -124,7 +136,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPressed: {
|
onPressed: {
|
||||||
if (mouse.modifiers === Qt.AltModifier) {
|
if (cameraCtrl.camera && mouse.modifiers === Qt.AltModifier) {
|
||||||
cameraCtrl._dragging = true;
|
cameraCtrl._dragging = true;
|
||||||
cameraCtrl._startRotation = cameraCtrl.camera.rotation;
|
cameraCtrl._startRotation = cameraCtrl.camera.rotation;
|
||||||
cameraCtrl._startPosition = cameraCtrl.camera.position;
|
cameraCtrl._startPosition = cameraCtrl.camera.position;
|
||||||
@@ -147,9 +159,11 @@ Item {
|
|||||||
onCanceled: handleRelease()
|
onCanceled: handleRelease()
|
||||||
|
|
||||||
onWheel: {
|
onWheel: {
|
||||||
// Emprically determined divisor for nice zoom
|
if (cameraCtrl.camera) {
|
||||||
cameraCtrl.zoomRelative(wheel.angleDelta.y / -40);
|
// Emprically determined divisor for nice zoom
|
||||||
cameraCtrl.storeCameraState(500);
|
cameraCtrl.zoomRelative(wheel.angleDelta.y / -40);
|
||||||
|
cameraCtrl.storeCameraState(500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,8 @@ Window {
|
|||||||
// need all those flags otherwise the title bar disappears after setting WindowStaysOnTopHint flag later
|
// need all those flags otherwise the title bar disappears after setting WindowStaysOnTopHint flag later
|
||||||
flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
|
flags: Qt.Window | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
|
||||||
|
|
||||||
property alias scene: editView.importScene
|
property Node activeScene: null
|
||||||
|
property View3D editView: null
|
||||||
|
|
||||||
property alias showEditLight: btnEditViewLight.toggled
|
property alias showEditLight: btnEditViewLight.toggled
|
||||||
property alias usePerspective: btnPerspective.toggled
|
property alias usePerspective: btnPerspective.toggled
|
||||||
@@ -63,6 +64,31 @@ Window {
|
|||||||
onShowEditLightChanged: _generalHelper.storeToolState("showEditLight", showEditLight)
|
onShowEditLightChanged: _generalHelper.storeToolState("showEditLight", showEditLight)
|
||||||
onGlobalOrientationChanged: _generalHelper.storeToolState("globalOrientation", globalOrientation)
|
onGlobalOrientationChanged: _generalHelper.storeToolState("globalOrientation", globalOrientation)
|
||||||
|
|
||||||
|
onActiveSceneChanged: {
|
||||||
|
// importScene cannot be updated after initial set, so we need to reconstruct entire View3D
|
||||||
|
var component = Qt.createComponent("SceneView3D.qml");
|
||||||
|
if (component.status === Component.Ready) {
|
||||||
|
var oldView = editView;
|
||||||
|
|
||||||
|
if (editView)
|
||||||
|
editView.visible = false;
|
||||||
|
|
||||||
|
editView = component.createObject(viewRect,
|
||||||
|
{"usePerspective": usePerspective,
|
||||||
|
"showSceneLight": showEditLight,
|
||||||
|
"importScene": activeScene,
|
||||||
|
"z": 1});
|
||||||
|
editView.usePerspective = Qt.binding(function() {return usePerspective;});
|
||||||
|
editView.showSceneLight = Qt.binding(function() {return showEditLight;});
|
||||||
|
|
||||||
|
selectionBoxes.length = 0;
|
||||||
|
ensureSelectionBoxes(1);
|
||||||
|
|
||||||
|
if (oldView)
|
||||||
|
oldView.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateToolStates(toolStates) {
|
function updateToolStates(toolStates) {
|
||||||
// Init the stored state so we don't unnecessarily reflect changes back to creator
|
// Init the stored state so we don't unnecessarily reflect changes back to creator
|
||||||
_generalHelper.initToolStates(toolStates);
|
_generalHelper.initToolStates(toolStates);
|
||||||
@@ -103,9 +129,13 @@ Window {
|
|||||||
if (component.status === Component.Ready) {
|
if (component.status === Component.Ready) {
|
||||||
for (var i = 0; i < needMore; ++i) {
|
for (var i = 0; i < needMore; ++i) {
|
||||||
var geometryName = _generalHelper.generateUniqueName("SelectionBoxGeometry");
|
var geometryName = _generalHelper.generateUniqueName("SelectionBoxGeometry");
|
||||||
var box = component.createObject(mainSceneHelpers, {"view3D": editView,
|
var boxParent = null;
|
||||||
|
if (editView)
|
||||||
|
boxParent = editView.sceneHelpers;
|
||||||
|
var box = component.createObject(boxParent, {"view3D": editView,
|
||||||
"geometryName": geometryName});
|
"geometryName": geometryName});
|
||||||
selectionBoxes[selectionBoxes.length] = box;
|
selectionBoxes[selectionBoxes.length] = box;
|
||||||
|
box.view3D = Qt.binding(function() {return editView;});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +163,7 @@ Window {
|
|||||||
function handleObjectClicked(object, multi) {
|
function handleObjectClicked(object, multi) {
|
||||||
var theObject = object;
|
var theObject = object;
|
||||||
if (btnSelectGroup.selected) {
|
if (btnSelectGroup.selected) {
|
||||||
while (theObject && theObject.parent !== scene)
|
while (theObject && theObject.parent !== activeScene)
|
||||||
theObject = theObject.parent;
|
theObject = theObject.parent;
|
||||||
}
|
}
|
||||||
// Object selection logic:
|
// Object selection logic:
|
||||||
@@ -162,11 +192,12 @@ Window {
|
|||||||
selectionChanged(newSelection);
|
selectionChanged(newSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLightGizmo(obj)
|
function addLightGizmo(scene, obj)
|
||||||
{
|
{
|
||||||
// Insert into first available gizmo
|
// Insert into first available gizmo
|
||||||
for (var i = 0; i < lightGizmos.length; ++i) {
|
for (var i = 0; i < lightGizmos.length; ++i) {
|
||||||
if (!lightGizmos[i].targetNode) {
|
if (!lightGizmos[i].targetNode) {
|
||||||
|
lightGizmos[i].scene = scene;
|
||||||
lightGizmos[i].targetNode = obj;
|
lightGizmos[i].targetNode = obj;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -177,18 +208,21 @@ Window {
|
|||||||
if (component.status === Component.Ready) {
|
if (component.status === Component.Ready) {
|
||||||
var gizmo = component.createObject(overlayScene,
|
var gizmo = component.createObject(overlayScene,
|
||||||
{"view3D": overlayView, "targetNode": obj,
|
{"view3D": overlayView, "targetNode": obj,
|
||||||
"selectedNodes": selectedNodes});
|
"selectedNodes": selectedNodes, "scene": scene,
|
||||||
|
"activeScene": activeScene});
|
||||||
lightGizmos[lightGizmos.length] = gizmo;
|
lightGizmos[lightGizmos.length] = gizmo;
|
||||||
gizmo.clicked.connect(handleObjectClicked);
|
gizmo.clicked.connect(handleObjectClicked);
|
||||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||||
|
gizmo.activeScene = Qt.binding(function() {return activeScene;});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCameraGizmo(obj)
|
function addCameraGizmo(scene, obj)
|
||||||
{
|
{
|
||||||
// Insert into first available gizmo
|
// Insert into first available gizmo
|
||||||
for (var i = 0; i < cameraGizmos.length; ++i) {
|
for (var i = 0; i < cameraGizmos.length; ++i) {
|
||||||
if (!cameraGizmos[i].targetNode) {
|
if (!cameraGizmos[i].targetNode) {
|
||||||
|
cameraGizmos[i].scene = scene;
|
||||||
cameraGizmos[i].targetNode = obj;
|
cameraGizmos[i].targetNode = obj;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -200,11 +234,13 @@ Window {
|
|||||||
var gizmo = component.createObject(
|
var gizmo = component.createObject(
|
||||||
overlayScene,
|
overlayScene,
|
||||||
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
|
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
|
||||||
"viewPortRect": viewPortRect, "selectedNodes": selectedNodes});
|
"viewPortRect": viewPortRect, "selectedNodes": selectedNodes,
|
||||||
|
"scene": scene, "activeScene": activeScene});
|
||||||
cameraGizmos[cameraGizmos.length] = gizmo;
|
cameraGizmos[cameraGizmos.length] = gizmo;
|
||||||
gizmo.clicked.connect(handleObjectClicked);
|
gizmo.clicked.connect(handleObjectClicked);
|
||||||
gizmo.viewPortRect = Qt.binding(function() {return viewPortRect;});
|
gizmo.viewPortRect = Qt.binding(function() {return viewPortRect;});
|
||||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||||
|
gizmo.activeScene = Qt.binding(function() {return activeScene;});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,19 +269,19 @@ Window {
|
|||||||
|
|
||||||
PerspectiveCamera {
|
PerspectiveCamera {
|
||||||
id: overlayPerspectiveCamera
|
id: overlayPerspectiveCamera
|
||||||
clipFar: editPerspectiveCamera.clipFar
|
clipFar: viewWindow.editView ? viewWindow.editView.perpectiveCamera.clipFar : 1000
|
||||||
clipNear: editPerspectiveCamera.clipNear
|
clipNear: viewWindow.editView ? viewWindow.editView.perpectiveCamera.clipNear : 1
|
||||||
position: editPerspectiveCamera.position
|
position: viewWindow.editView ? viewWindow.editView.perpectiveCamera.position : Qt.vector3d(0, 0, 0)
|
||||||
rotation: editPerspectiveCamera.rotation
|
rotation: viewWindow.editView ? viewWindow.editView.perpectiveCamera.rotation : Qt.vector3d(0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
OrthographicCamera {
|
OrthographicCamera {
|
||||||
id: overlayOrthoCamera
|
id: overlayOrthoCamera
|
||||||
clipFar: editOrthoCamera.clipFar
|
clipFar: viewWindow.editView ? viewWindow.editView.orthoCamera.clipFar : 1000
|
||||||
clipNear: editOrthoCamera.clipNear
|
clipNear: viewWindow.editView ? viewWindow.editView.orthoCamera.clipNear : 1
|
||||||
position: editOrthoCamera.position
|
position: viewWindow.editView ? viewWindow.editView.orthoCamera.position : Qt.vector3d(0, 0, 0)
|
||||||
rotation: editOrthoCamera.rotation
|
rotation: viewWindow.editView ? viewWindow.editView.orthoCamera.rotation : Qt.vector3d(0, 0, 0)
|
||||||
scale: editOrthoCamera.scale
|
scale: viewWindow.editView ? viewWindow.editView.orthoCamera.scale : Qt.vector3d(0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea3D {
|
MouseArea3D {
|
||||||
@@ -349,6 +385,7 @@ Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: viewRect
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
@@ -361,11 +398,13 @@ Window {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var pickResult = editView.pick(mouse.x, mouse.y);
|
if (viewWindow.editView) {
|
||||||
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
|
var pickResult = viewWindow.editView.pick(mouse.x, mouse.y);
|
||||||
mouse.modifiers & Qt.ControlModifier);
|
handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
|
||||||
if (!pickResult.objectHit)
|
mouse.modifiers & Qt.ControlModifier);
|
||||||
mouse.accepted = false;
|
if (!pickResult.objectHit)
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,57 +412,12 @@ Window {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
View3D {
|
|
||||||
id: editView
|
|
||||||
anchors.fill: parent
|
|
||||||
camera: usePerspective ? editPerspectiveCamera : editOrthoCamera
|
|
||||||
|
|
||||||
Node {
|
|
||||||
id: mainSceneHelpers
|
|
||||||
|
|
||||||
HelperGrid {
|
|
||||||
id: helperGrid
|
|
||||||
lines: 50
|
|
||||||
step: 50
|
|
||||||
}
|
|
||||||
|
|
||||||
PointLight {
|
|
||||||
id: editLight
|
|
||||||
visible: showEditLight
|
|
||||||
position: usePerspective ? editPerspectiveCamera.position
|
|
||||||
: editOrthoCamera.position
|
|
||||||
quadraticFade: 0
|
|
||||||
linearFade: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initial camera position and rotation should be such that they look at origin.
|
|
||||||
// Otherwise EditCameraController._lookAtPoint needs to be initialized to correct
|
|
||||||
// point.
|
|
||||||
PerspectiveCamera {
|
|
||||||
id: editPerspectiveCamera
|
|
||||||
z: -600
|
|
||||||
y: 600
|
|
||||||
rotation.x: 45
|
|
||||||
clipFar: 100000
|
|
||||||
clipNear: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
OrthographicCamera {
|
|
||||||
id: editOrthoCamera
|
|
||||||
z: -600
|
|
||||||
y: 600
|
|
||||||
rotation.x: 45
|
|
||||||
clipFar: 100000
|
|
||||||
clipNear: -10000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
View3D {
|
View3D {
|
||||||
id: overlayView
|
id: overlayView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
camera: usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera
|
camera: usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera
|
||||||
importScene: overlayScene
|
importScene: overlayScene
|
||||||
|
z: 2
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay2D {
|
Overlay2D {
|
||||||
@@ -431,6 +425,7 @@ Window {
|
|||||||
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
|
targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo
|
||||||
targetView: overlayView
|
targetView: overlayView
|
||||||
visible: targetNode.dragging
|
visible: targetNode.dragging
|
||||||
|
z: 3
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: "white"
|
color: "white"
|
||||||
@@ -463,9 +458,9 @@ Window {
|
|||||||
|
|
||||||
EditCameraController {
|
EditCameraController {
|
||||||
id: cameraControl
|
id: cameraControl
|
||||||
camera: editView.camera
|
camera: viewWindow.editView ? viewWindow.editView.camera : null
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
view3d: editView
|
view3d: viewWindow.editView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,10 +552,10 @@ Window {
|
|||||||
togglable: false
|
togglable: false
|
||||||
|
|
||||||
onSelectedChanged: {
|
onSelectedChanged: {
|
||||||
if (selected) {
|
if (viewWindow.editView && selected) {
|
||||||
var targetNode = viewWindow.selectedNodes.length > 0
|
var targetNode = viewWindow.selectedNodes.length > 0
|
||||||
? selectionBoxes[0].model : null;
|
? selectionBoxes[0].model : null;
|
||||||
cameraControl.focusObject(targetNode, editView.camera.rotation, true);
|
cameraControl.focusObject(targetNode, viewWindow.editView.camera.rotation, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,8 @@ import QtGraphicalEffects 1.12
|
|||||||
Node {
|
Node {
|
||||||
id: iconGizmo
|
id: iconGizmo
|
||||||
|
|
||||||
|
property Node activeScene: null
|
||||||
|
property Node scene: null
|
||||||
property View3D view3D
|
property View3D view3D
|
||||||
property bool highlightOnHover: true
|
property bool highlightOnHover: true
|
||||||
property Node targetNode: null
|
property Node targetNode: null
|
||||||
@@ -50,7 +52,7 @@ Node {
|
|||||||
|
|
||||||
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
|
||||||
rotation: targetNode ? targetNode.sceneRotation : Qt.vector3d(0, 0, 0)
|
rotation: targetNode ? targetNode.sceneRotation : Qt.vector3d(0, 0, 0)
|
||||||
visible: targetNode ? targetNode.visible : false
|
visible: activeScene === scene && (targetNode ? targetNode.visible : false)
|
||||||
|
|
||||||
Overlay2D {
|
Overlay2D {
|
||||||
id: iconOverlay
|
id: iconOverlay
|
||||||
|
@@ -40,7 +40,7 @@ PlanarDraggable {
|
|||||||
_targetStartPos.x + sceneRelativeDistance.x,
|
_targetStartPos.x + sceneRelativeDistance.x,
|
||||||
_targetStartPos.y + sceneRelativeDistance.y,
|
_targetStartPos.y + sceneRelativeDistance.y,
|
||||||
_targetStartPos.z + sceneRelativeDistance.z);
|
_targetStartPos.z + sceneRelativeDistance.z);
|
||||||
return targetNode.parent.mapPositionFromScene(newScenePos);
|
return targetNode.parent ? targetNode.parent.mapPositionFromScene(newScenePos) : newScenePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDragged: {
|
onDragged: {
|
||||||
|
80
share/qtcreator/qml/qmlpuppet/mockfiles/SceneView3D.qml
Normal file
80
share/qtcreator/qml/qmlpuppet/mockfiles/SceneView3D.qml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 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.14
|
||||||
|
|
||||||
|
View3D {
|
||||||
|
id: sceneView
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
property bool usePerspective: false
|
||||||
|
property bool showSceneLight: false
|
||||||
|
property alias sceneHelpers: sceneHelpers
|
||||||
|
property alias perpectiveCamera: scenePerspectiveCamera
|
||||||
|
property alias orthoCamera: sceneOrthoCamera
|
||||||
|
|
||||||
|
camera: usePerspective ? scenePerspectiveCamera : sceneOrthoCamera
|
||||||
|
|
||||||
|
Node {
|
||||||
|
id: sceneHelpers
|
||||||
|
|
||||||
|
HelperGrid {
|
||||||
|
id: helperGrid
|
||||||
|
lines: 50
|
||||||
|
step: 50
|
||||||
|
}
|
||||||
|
|
||||||
|
PointLight {
|
||||||
|
id: sceneLight
|
||||||
|
visible: showSceneLight
|
||||||
|
position: usePerspective ? scenePerspectiveCamera.position
|
||||||
|
: sceneOrthoCamera.position
|
||||||
|
quadraticFade: 0
|
||||||
|
linearFade: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial camera position and rotation should be such that they look at origin.
|
||||||
|
// Otherwise EditCameraController._lookAtPoint needs to be initialized to correct
|
||||||
|
// point.
|
||||||
|
PerspectiveCamera {
|
||||||
|
id: scenePerspectiveCamera
|
||||||
|
z: -600
|
||||||
|
y: 600
|
||||||
|
rotation.x: 45
|
||||||
|
clipFar: 100000
|
||||||
|
clipNear: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
OrthographicCamera {
|
||||||
|
id: sceneOrthoCamera
|
||||||
|
z: -600
|
||||||
|
y: 600
|
||||||
|
rotation.x: 45
|
||||||
|
clipFar: 100000
|
||||||
|
clipNear: -10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -154,8 +154,11 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
|||||||
// Explicitly set local transform of root node to target node parent's global transform
|
// Explicitly set local transform of root node to target node parent's global transform
|
||||||
// to avoid having to reparent the selection box. This has to be done directly on render
|
// to avoid having to reparent the selection box. This has to be done directly on render
|
||||||
// nodes.
|
// nodes.
|
||||||
targetRN->parent->calculateGlobalVariables();
|
QMatrix4x4 m;
|
||||||
QMatrix4x4 m = targetRN->parent->globalTransform;
|
if (targetRN->parent) {
|
||||||
|
targetRN->parent->calculateGlobalVariables();
|
||||||
|
m = targetRN->parent->globalTransform;
|
||||||
|
}
|
||||||
rootRN->localTransform = m;
|
rootRN->localTransform = m;
|
||||||
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
|
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
|
||||||
rootRN->calculateGlobalVariables();
|
rootRN->calculateGlobalVariables();
|
||||||
|
@@ -81,6 +81,12 @@
|
|||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
#include <QtQuick3D/private/qquick3dnode_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dviewport_p.h>
|
||||||
|
#include <QtQuick3D/private/qquick3dscenerootnode_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
static QVariant objectToVariant(QObject *object)
|
static QVariant objectToVariant(QObject *object)
|
||||||
@@ -255,12 +261,12 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(
|
|||||||
const PropertyName &propertyName,
|
const PropertyName &propertyName,
|
||||||
ValuesModifiedCommand::TransactionOption option)
|
ValuesModifiedCommand::TransactionOption option)
|
||||||
{
|
{
|
||||||
PropertyName targetPopertyName;
|
PropertyName targetPropertyName;
|
||||||
|
|
||||||
// Position is a special case, because the position can be 'position.x 'or simply 'x'.
|
// Position is a special case, because the position can be 'position.x 'or simply 'x'.
|
||||||
// We prefer 'x'.
|
// We prefer 'x'.
|
||||||
if (propertyName != "position")
|
if (propertyName != "position")
|
||||||
targetPopertyName = propertyName;
|
targetPropertyName = propertyName;
|
||||||
|
|
||||||
auto *obj = node.value<QObject *>();
|
auto *obj = node.value<QObject *>();
|
||||||
|
|
||||||
@@ -275,7 +281,7 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(
|
|||||||
// We do have to split position into position.x, position.y, position.z
|
// We do have to split position into position.x, position.y, position.z
|
||||||
ValuesModifiedCommand command = createValuesModifiedCommand(vectorToPropertyValue(
|
ValuesModifiedCommand command = createValuesModifiedCommand(vectorToPropertyValue(
|
||||||
instance,
|
instance,
|
||||||
targetPopertyName,
|
targetPropertyName,
|
||||||
obj->property(propertyName)));
|
obj->property(propertyName)));
|
||||||
|
|
||||||
command.transactionOption = option;
|
command.transactionOption = option;
|
||||||
@@ -318,14 +324,32 @@ void Qt5InformationNodeInstanceServer::handleToolStateChanged(const QString &too
|
|||||||
QVariant::fromValue(data)});
|
QVariant::fromValue(data)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::updateViewPortRect()
|
void Qt5InformationNodeInstanceServer::handleView3DSizeChange()
|
||||||
{
|
{
|
||||||
QRectF viewPortrect(0, 0, m_viewPortInstance.internalObject()->property("width").toDouble(),
|
QObject *view3D = sender();
|
||||||
m_viewPortInstance.internalObject()->property("height").toDouble());
|
if (view3D == m_active3DView.internalObject())
|
||||||
|
updateView3DRect(view3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Qt5InformationNodeInstanceServer::updateView3DRect(QObject *view3D)
|
||||||
|
{
|
||||||
|
QRectF viewPortrect(0., 0., 1000., 1000.);
|
||||||
|
if (view3D) {
|
||||||
|
viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(),
|
||||||
|
view3D->property("height").toDouble());
|
||||||
|
}
|
||||||
QQmlProperty viewPortProperty(m_editView3D, "viewPortRect", context());
|
QQmlProperty viewPortProperty(m_editView3D, "viewPortRect", context());
|
||||||
viewPortProperty.write(viewPortrect);
|
viewPortProperty.write(viewPortrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
|
||||||
|
{
|
||||||
|
QQmlProperty sceneProperty(m_editView3D, "activeScene", context());
|
||||||
|
sceneProperty.write(objectToVariant(m_active3DScene));
|
||||||
|
if (m_active3DView.isValid())
|
||||||
|
updateView3DRect(m_active3DView.internalObject());
|
||||||
|
}
|
||||||
|
|
||||||
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
|
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
|
||||||
Qt5NodeInstanceServer(nodeInstanceClient)
|
Qt5NodeInstanceServer(nodeInstanceClient)
|
||||||
{
|
{
|
||||||
@@ -425,65 +449,147 @@ void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout()
|
|||||||
changeSelection(m_pendingSelectionChangeCommand);
|
changeSelection(m_pendingSelectionChangeCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport(
|
|
||||||
const QList<ServerNodeInstance> &instanceList) const
|
|
||||||
{
|
|
||||||
for (const ServerNodeInstance &instance : instanceList) {
|
|
||||||
if (instance.isSubclassOf("QQuick3DViewport")) {
|
|
||||||
QObject *rootObj = nullptr;
|
|
||||||
int viewChildCount = 0;
|
|
||||||
for (const ServerNodeInstance &child : instanceList) { /* Look for scene node */
|
|
||||||
/* The QQuick3DViewport always creates a root node.
|
|
||||||
* This root node contains the complete scene. */
|
|
||||||
if (child.isSubclassOf("QQuick3DNode") && child.parent() == instance) {
|
|
||||||
// Implicit root node is not visible in editor, so there is often another node
|
|
||||||
// added below it that serves as the actual scene root node.
|
|
||||||
// If the found root is the only node child of the view, assume that is the case.
|
|
||||||
++viewChildCount;
|
|
||||||
if (!rootObj)
|
|
||||||
rootObj = child.internalObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (viewChildCount == 1)
|
|
||||||
return rootObj;
|
|
||||||
else if (rootObj)
|
|
||||||
return rootObj->property("parent").value<QObject *>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
|
void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
|
||||||
const QList<ServerNodeInstance> &instanceList) const
|
const QList<ServerNodeInstance> &instanceList) const
|
||||||
{
|
{
|
||||||
QObjectList cameras;
|
QHash<QObject *, QObjectList> cameras;
|
||||||
QObjectList lights;
|
QHash<QObject *, QObjectList> lights;
|
||||||
|
|
||||||
for (const ServerNodeInstance &instance : instanceList) {
|
for (const ServerNodeInstance &instance : instanceList) {
|
||||||
if (instance.isSubclassOf("QQuick3DCamera"))
|
if (instance.isSubclassOf("QQuick3DCamera"))
|
||||||
cameras << instance.internalObject();
|
cameras[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
else if (instance.isSubclassOf("QQuick3DAbstractLight"))
|
else if (instance.isSubclassOf("QQuick3DAbstractLight"))
|
||||||
lights << instance.internalObject();
|
lights[find3DSceneRoot(instance)] << instance.internalObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &obj : qAsConst(cameras)) {
|
auto cameraIt = cameras.constBegin();
|
||||||
QMetaObject::invokeMethod(m_editView3D, "addCameraGizmo",
|
while (cameraIt != cameras.constEnd()) {
|
||||||
Q_ARG(QVariant, objectToVariant(obj)));
|
const auto cameraObjs = cameraIt.value();
|
||||||
|
for (auto &obj : cameraObjs) {
|
||||||
|
QMetaObject::invokeMethod(m_editView3D, "addCameraGizmo",
|
||||||
|
Q_ARG(QVariant, objectToVariant(cameraIt.key())),
|
||||||
|
Q_ARG(QVariant, objectToVariant(obj)));
|
||||||
|
}
|
||||||
|
++cameraIt;
|
||||||
}
|
}
|
||||||
for (auto &obj : qAsConst(lights)) {
|
auto lightIt = lights.constBegin();
|
||||||
QMetaObject::invokeMethod(m_editView3D, "addLightGizmo",
|
while (lightIt != lights.constEnd()) {
|
||||||
Q_ARG(QVariant, objectToVariant(obj)));
|
const auto lightObjs = lightIt.value();
|
||||||
|
for (auto &obj : lightObjs) {
|
||||||
|
QMetaObject::invokeMethod(m_editView3D, "addLightGizmo",
|
||||||
|
Q_ARG(QVariant, objectToVariant(lightIt.key())),
|
||||||
|
Q_ARG(QVariant, objectToVariant(obj)));
|
||||||
|
}
|
||||||
|
++lightIt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerNodeInstance Qt5InformationNodeInstanceServer::findViewPort(
|
void Qt5InformationNodeInstanceServer::addViewPorts(const QList<ServerNodeInstance> &instanceList)
|
||||||
const QList<ServerNodeInstance> &instanceList)
|
|
||||||
{
|
{
|
||||||
for (const ServerNodeInstance &instance : instanceList) {
|
for (const ServerNodeInstance &instance : instanceList) {
|
||||||
if (instance.isSubclassOf("QQuick3DViewport"))
|
if (instance.isSubclassOf("QQuick3DViewport")) {
|
||||||
return instance;
|
m_view3Ds << instance;
|
||||||
|
QObject *obj = instance.internalObject();
|
||||||
|
QObject::connect(obj, SIGNAL(widthChanged()), this, SLOT(handleView3DSizeChange()));
|
||||||
|
QObject::connect(obj, SIGNAL(heightChanged()), this, SLOT(handleView3DSizeChange()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ServerNodeInstance();
|
}
|
||||||
|
|
||||||
|
ServerNodeInstance Qt5InformationNodeInstanceServer::findView3DForInstance(const ServerNodeInstance &instance) const
|
||||||
|
{
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
if (!instance.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// View3D of an instance is one of the following, in order of priority:
|
||||||
|
// - Any direct ancestor View3D of the instance
|
||||||
|
// - Any View3D that specifies the instance's scene as importScene
|
||||||
|
ServerNodeInstance checkInstance = instance;
|
||||||
|
while (checkInstance.isValid()) {
|
||||||
|
if (checkInstance.isSubclassOf("QQuick3DViewport"))
|
||||||
|
return checkInstance;
|
||||||
|
else
|
||||||
|
checkInstance = checkInstance.parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no ancestor View3D was found, check if the scene root is specified as importScene in
|
||||||
|
// some View3D.
|
||||||
|
QObject *sceneRoot = find3DSceneRoot(instance);
|
||||||
|
for (const auto &view3D : qAsConst(m_view3Ds)) {
|
||||||
|
auto view = qobject_cast<QQuick3DViewport *>(view3D.internalObject());
|
||||||
|
if (sceneRoot == view->importScene())
|
||||||
|
return view3D;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject *Qt5InformationNodeInstanceServer::find3DSceneRoot(const ServerNodeInstance &instance) const
|
||||||
|
{
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
// The root of a 3D scene is any QQuick3DNode that doesn't have QQuick3DNode as parent.
|
||||||
|
// One exception is QQuick3DSceneRootNode that has only a single child QQuick3DNode (not
|
||||||
|
// a subclass of one, but exactly QQuick3DNode). In that case we consider the single child node
|
||||||
|
// to be the scene root (as QQuick3DSceneRootNode is not visible in the navigator scene graph).
|
||||||
|
|
||||||
|
if (!instance.isValid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
QQuick3DNode *childNode = nullptr;
|
||||||
|
auto countChildNodes = [&childNode](QQuick3DViewport *view) -> int {
|
||||||
|
QQuick3DNode *sceneNode = view->scene();
|
||||||
|
QList<QQuick3DObject *> children = sceneNode->childItems();
|
||||||
|
int nodeCount = 0;
|
||||||
|
for (const auto &child : children) {
|
||||||
|
auto nodeChild = qobject_cast<QQuick3DNode *>(child);
|
||||||
|
if (nodeChild) {
|
||||||
|
++nodeCount;
|
||||||
|
childNode = nodeChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
// In case of View3D is selected, the root scene is whatever is contained in View3D, or
|
||||||
|
// importScene, in case there is no content in View3D
|
||||||
|
QObject *obj = instance.internalObject();
|
||||||
|
auto view = qobject_cast<QQuick3DViewport *>(obj);
|
||||||
|
if (view) {
|
||||||
|
int nodeCount = countChildNodes(view);
|
||||||
|
if (nodeCount == 0)
|
||||||
|
return view->importScene();
|
||||||
|
else if (nodeCount == 1)
|
||||||
|
return childNode;
|
||||||
|
else
|
||||||
|
return view->scene();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerNodeInstance checkInstance = instance;
|
||||||
|
bool foundNode = checkInstance.isSubclassOf("QQuick3DNode");
|
||||||
|
while (checkInstance.isValid()) {
|
||||||
|
ServerNodeInstance parentInstance = checkInstance.parent();
|
||||||
|
if (parentInstance.isSubclassOf("QQuick3DViewport")) {
|
||||||
|
view = qobject_cast<QQuick3DViewport *>(parentInstance.internalObject());
|
||||||
|
int nodeCount = countChildNodes(view);
|
||||||
|
if (nodeCount == 1)
|
||||||
|
return checkInstance.internalObject();
|
||||||
|
else
|
||||||
|
return view->scene();
|
||||||
|
} else if (parentInstance.isSubclassOf("QQuick3DNode")) {
|
||||||
|
foundNode = true;
|
||||||
|
checkInstance = parentInstance;
|
||||||
|
} else {
|
||||||
|
if (!foundNode) {
|
||||||
|
// We haven't found any node yet, continue the search
|
||||||
|
checkInstance = parentInstance;
|
||||||
|
} else {
|
||||||
|
return checkInstance.internalObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeInstance> &instanceList,
|
void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeInstance> &instanceList,
|
||||||
@@ -491,38 +597,28 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
|
|||||||
{
|
{
|
||||||
ServerNodeInstance root = rootNodeInstance();
|
ServerNodeInstance root = rootNodeInstance();
|
||||||
|
|
||||||
bool showCustomLight = false;
|
addViewPorts(instanceList);
|
||||||
|
|
||||||
if (root.isSubclassOf("QQuick3DNode")) {
|
// Find any scene to show
|
||||||
m_rootNode = root.internalObject();
|
for (const auto &instance : instanceList) {
|
||||||
showCustomLight = true; // Pure node scene we should add a custom light
|
if (instance.isSubclassOf("QQuick3DNode")) {
|
||||||
} else {
|
m_active3DScene = find3DSceneRoot(instance);
|
||||||
m_rootNode = findRootNodeOf3DViewport(instanceList);
|
m_active3DView = findView3DForInstance(instance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_rootNode) { // If we found a scene we create the edit view
|
if (m_active3DScene) {
|
||||||
m_editView3D = createEditView3D(engine());
|
m_editView3D = createEditView3D(engine());
|
||||||
|
|
||||||
if (!m_editView3D)
|
if (!m_editView3D) {
|
||||||
|
m_active3DScene = nullptr;
|
||||||
|
m_active3DView = {};
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QQmlProperty sceneProperty(m_editView3D, "scene", context());
|
|
||||||
m_rootNode->setParent(m_editView3D);
|
|
||||||
sceneProperty.write(objectToVariant(m_rootNode));
|
|
||||||
QQmlProperty parentProperty(m_rootNode, "parent", context());
|
|
||||||
parentProperty.write(objectToVariant(m_editView3D));
|
|
||||||
QQmlProperty showLightProperty(m_editView3D, "showLight", context());
|
|
||||||
showLightProperty.write(showCustomLight);
|
|
||||||
|
|
||||||
m_viewPortInstance = findViewPort(instanceList);
|
|
||||||
if (m_viewPortInstance.internalObject()) {
|
|
||||||
QObject::connect(m_viewPortInstance.internalObject(), SIGNAL(widthChanged()),
|
|
||||||
this, SLOT(updateViewPortRect()));
|
|
||||||
QObject::connect(m_viewPortInstance.internalObject(), SIGNAL(heightChanged()),
|
|
||||||
this, SLOT(updateViewPortRect()));
|
|
||||||
updateViewPortRect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateActiveSceneToEditView3D();
|
||||||
|
|
||||||
createCameraAndLightGizmos(instanceList);
|
createCameraAndLightGizmos(instanceList);
|
||||||
|
|
||||||
QMetaObject::invokeMethod(m_editView3D, "updateToolStates", Q_ARG(QVariant, toolStates));
|
QMetaObject::invokeMethod(m_editView3D, "updateToolStates", Q_ARG(QVariant, toolStates));
|
||||||
@@ -711,19 +807,33 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a scene root of the selection to update active scene shown
|
||||||
const QVector<qint32> instanceIds = command.instanceIds();
|
const QVector<qint32> instanceIds = command.instanceIds();
|
||||||
QVariantList selectedObjs;
|
QVariantList selectedObjs;
|
||||||
|
QObject *firstSceneRoot = nullptr;
|
||||||
|
ServerNodeInstance firstInstance;
|
||||||
for (qint32 id : instanceIds) {
|
for (qint32 id : instanceIds) {
|
||||||
if (hasInstanceForId(id)) {
|
if (hasInstanceForId(id)) {
|
||||||
ServerNodeInstance instance = instanceForId(id);
|
ServerNodeInstance instance = instanceForId(id);
|
||||||
|
QObject *sceneRoot = find3DSceneRoot(instance);
|
||||||
|
if (!firstSceneRoot && sceneRoot) {
|
||||||
|
firstSceneRoot = sceneRoot;
|
||||||
|
firstInstance = instance;
|
||||||
|
}
|
||||||
QObject *object = nullptr;
|
QObject *object = nullptr;
|
||||||
if (instance.isSubclassOf("QQuick3DNode"))
|
if (firstSceneRoot && sceneRoot == firstSceneRoot && instance.isSubclassOf("QQuick3DNode"))
|
||||||
object = instance.internalObject();
|
object = instance.internalObject();
|
||||||
if (object && object != m_rootNode)
|
if (object && (firstSceneRoot != object || instance.isSubclassOf("QQuick3DModel")))
|
||||||
selectedObjs << objectToVariant(object);
|
selectedObjs << objectToVariant(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (firstSceneRoot && m_active3DScene != firstSceneRoot) {
|
||||||
|
m_active3DScene = firstSceneRoot;
|
||||||
|
m_active3DView = findView3DForInstance(firstInstance);
|
||||||
|
updateActiveSceneToEditView3D();
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
|
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
|
||||||
// case when the first selection processed is a multiselection, we wait a bit as
|
// case when the first selection processed is a multiselection, we wait a bit as
|
||||||
// using the new boxes immediately leads to visual glitches.
|
// using the new boxes immediately leads to visual glitches.
|
||||||
|
@@ -62,7 +62,7 @@ private slots:
|
|||||||
void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName);
|
void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName);
|
||||||
void handleObjectPropertyChange(const QVariant &object, const QVariant &propName);
|
void handleObjectPropertyChange(const QVariant &object, const QVariant &propName);
|
||||||
void handleToolStateChanged(const QString &tool, const QVariant &toolState);
|
void handleToolStateChanged(const QString &tool, const QVariant &toolState);
|
||||||
void updateViewPortRect();
|
void handleView3DSizeChange();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void collectItemChangesAndSendChangeCommands() override;
|
void collectItemChangesAndSendChangeCommands() override;
|
||||||
@@ -81,9 +81,10 @@ private:
|
|||||||
QObject *createEditView3D(QQmlEngine *engine);
|
QObject *createEditView3D(QQmlEngine *engine);
|
||||||
void setup3DEditView(const QList<ServerNodeInstance> &instanceList,
|
void setup3DEditView(const QList<ServerNodeInstance> &instanceList,
|
||||||
const QVariantMap &toolStates);
|
const QVariantMap &toolStates);
|
||||||
QObject *findRootNodeOf3DViewport(const QList<ServerNodeInstance> &instanceList) const;
|
|
||||||
void createCameraAndLightGizmos(const QList<ServerNodeInstance> &instanceList) const;
|
void createCameraAndLightGizmos(const QList<ServerNodeInstance> &instanceList) const;
|
||||||
ServerNodeInstance findViewPort(const QList<ServerNodeInstance> &instanceList);
|
void addViewPorts(const QList<ServerNodeInstance> &instanceList);
|
||||||
|
ServerNodeInstance findView3DForInstance(const ServerNodeInstance &instance) const;
|
||||||
|
QObject *find3DSceneRoot(const ServerNodeInstance &instance) const;
|
||||||
QVector<InstancePropertyValueTriple> vectorToPropertyValue(const ServerNodeInstance &instance,
|
QVector<InstancePropertyValueTriple> vectorToPropertyValue(const ServerNodeInstance &instance,
|
||||||
const PropertyName &propertyName,
|
const PropertyName &propertyName,
|
||||||
const QVariant &variant);
|
const QVariant &variant);
|
||||||
@@ -91,8 +92,13 @@ private:
|
|||||||
const PropertyName &propertyName,
|
const PropertyName &propertyName,
|
||||||
ValuesModifiedCommand::TransactionOption option);
|
ValuesModifiedCommand::TransactionOption option);
|
||||||
bool dropAcceptable(QDragMoveEvent *event) const;
|
bool dropAcceptable(QDragMoveEvent *event) const;
|
||||||
|
void updateView3DRect(QObject *view3D);
|
||||||
|
void updateActiveSceneToEditView3D();
|
||||||
|
|
||||||
QObject *m_editView3D = nullptr;
|
QObject *m_editView3D = nullptr;
|
||||||
|
QVector<ServerNodeInstance> m_view3Ds;
|
||||||
|
ServerNodeInstance m_active3DView;
|
||||||
|
QObject *m_active3DScene = nullptr;
|
||||||
QSet<ServerNodeInstance> m_parentChangedSet;
|
QSet<ServerNodeInstance> m_parentChangedSet;
|
||||||
QList<ServerNodeInstance> m_completedComponentList;
|
QList<ServerNodeInstance> m_completedComponentList;
|
||||||
QList<TokenCommand> m_tokenList;
|
QList<TokenCommand> m_tokenList;
|
||||||
@@ -100,8 +106,6 @@ private:
|
|||||||
QTimer m_selectionChangeTimer;
|
QTimer m_selectionChangeTimer;
|
||||||
QVariant m_changedNode;
|
QVariant m_changedNode;
|
||||||
PropertyName m_changedProperty;
|
PropertyName m_changedProperty;
|
||||||
ServerNodeInstance m_viewPortInstance;
|
|
||||||
QObject *m_rootNode = nullptr;
|
|
||||||
ChangeSelectionCommand m_pendingSelectionChangeCommand;
|
ChangeSelectionCommand m_pendingSelectionChangeCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
<file>mockfiles/ToggleButton.qml</file>
|
<file>mockfiles/ToggleButton.qml</file>
|
||||||
<file>mockfiles/RotateGizmo.qml</file>
|
<file>mockfiles/RotateGizmo.qml</file>
|
||||||
<file>mockfiles/RotateRing.qml</file>
|
<file>mockfiles/RotateRing.qml</file>
|
||||||
|
<file>mockfiles/SceneView3D.qml</file>
|
||||||
<file>mockfiles/SelectionBox.qml</file>
|
<file>mockfiles/SelectionBox.qml</file>
|
||||||
<file>mockfiles/AxisHelper.qml</file>
|
<file>mockfiles/AxisHelper.qml</file>
|
||||||
<file>mockfiles/AxisHelperArm.qml</file>
|
<file>mockfiles/AxisHelperArm.qml</file>
|
||||||
|
Reference in New Issue
Block a user