summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-11-21 17:37:09 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-11-22 14:02:48 +0000
commit389f96b0ee8b2485290aee5c3c1eac05403f04ac (patch)
treeeaa9b5f9fa444ef089822d278b5a148176242ced
parent9dac42f153b42c057713aadfa48aa2873643b2f3 (diff)
downloadqt-creator-389f96b0ee8b2485290aee5c3c1eac05403f04ac.tar.gz
QmlDesigner: Implement group selection boxes in 3D edit view
Object's selection box now includes the bounds of all of its descendants. Selection boxes of immediate children of a selected object are also drawn. Individual/group selection buttons also now work as expected. Change-Id: Ice7ef9a536e32c6bb6da70fe23bf0a38e72c14f8 Fixes: QDS-1210 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml17
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h13
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp206
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h11
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp20
7 files changed, 210 insertions, 65 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
index 56faf67ec4..7af8cf0cba 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml
@@ -55,9 +55,14 @@ Window {
selectedNode = object;
}
- function emitObjectClicked(object) {
- selectObject(object);
- objectClicked(object);
+ function handleObjectClicked(object) {
+ var theObject = object;
+ if (btnSelectGroup.selected) {
+ while (theObject && theObject.parent !== scene)
+ theObject = theObject.parent;
+ }
+ selectObject(theObject);
+ objectClicked(theObject);
}
function addLightGizmo(obj)
@@ -68,7 +73,7 @@ Window {
{"view3D": overlayView, "targetNode": obj,
"selectedNode": selectedNode});
lightGizmos[lightGizmos.length] = gizmo;
- gizmo.clicked.connect(emitObjectClicked);
+ gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNode = Qt.binding(function() {return selectedNode;});
}
}
@@ -83,7 +88,7 @@ Window {
{"view3D": overlayView, "targetNode": obj, "geometryName": geometryName,
"viewPortRect": viewPortRect, "selectedNode": selectedNode});
cameraGizmos[cameraGizmos.length] = gizmo;
- gizmo.clicked.connect(emitObjectClicked);
+ gizmo.clicked.connect(handleObjectClicked);
gizmo.viewPortRect = Qt.binding(function() {return viewPortRect;});
gizmo.selectedNode = Qt.binding(function() {return selectedNode;});
}
@@ -178,7 +183,7 @@ Window {
onTapped: {
var pickResult = editView.pick(eventPoint.scenePosition.x,
eventPoint.scenePosition.y);
- emitObjectClicked(pickResult.objectHit);
+ handleObjectClicked(pickResult.objectHit);
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml
index 6465cab2b7..08de0a7ae1 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml
@@ -52,7 +52,7 @@ Node {
orientation: selectionBox.targetNode ? selectionBox.targetNode.orientation : Node.LeftHanded
rotationOrder: selectionBox.targetNode ? selectionBox.targetNode.rotationOrder : Node.YXZ
- visible: selectionBox.targetNode && selectionBox.targetNode instanceof Model
+ visible: selectionBox.targetNode && !selectionBoxGeometry.isEmpty
materials: [
DefaultMaterial {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
index 30be47d2dc..f5c7c6e656 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
@@ -29,15 +29,17 @@
#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
#include <QtQuick3D/private/qquick3dperspectivecamera_p.h>
#include <QtQuick3D/private/qquick3dobject_p_p.h>
+#include <QtQuick3D/private/qquick3dcamera_p.h>
+#include <QtQuick3D/private/qquick3dnode_p.h>
#include <QtQuick3D/private/qquick3dmodel_p.h>
+#include <QtQuick3D/private/qquick3dviewport_p.h>
+#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
#include <QtQuick3DUtils/private/qssgbounds3_p.h>
#include <QtQuick/qquickwindow.h>
-#include <QtCore/qhash.h>
#include <QtCore/qmath.h>
-#include <QtGui/qmatrix4x4.h>
namespace QmlDesigner {
namespace Internal {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
index 8a1cbe7001..16007e6798 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
@@ -27,14 +27,21 @@
#ifdef QUICK3D_MODULE
-#include <QtQuick3D/private/qquick3dcamera_p.h>
-#include <QtQuick3D/private/qquick3dnode_p.h>
-#include <QtQuick3D/private/qquick3dviewport_p.h>
#include <QtCore/qobject.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qhash.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+class QQuick3DCamera;
+class QQuick3DNode;
+class QQuick3DViewport;
+QT_END_NAMESPACE
namespace QmlDesigner {
namespace Internal {
+
class GeneralHelper : public QObject
{
Q_OBJECT
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp
index 452d924427..db6218c331 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp
@@ -35,6 +35,9 @@
#include <QtQuick3D/private/qquick3dmodel_p.h>
#include <QtQuick3D/private/qquick3dobject_p_p.h>
#include <QtQuick/qquickwindow.h>
+#include <QtCore/qvector.h>
+
+#include <limits>
namespace QmlDesigner {
namespace Internal {
@@ -46,6 +49,9 @@ SelectionBoxGeometry::SelectionBoxGeometry()
SelectionBoxGeometry::~SelectionBoxGeometry()
{
+ for (auto &connection : qAsConst(m_connections))
+ QObject::disconnect(connection);
+ m_connections.clear();
}
QQuick3DNode *SelectionBoxGeometry::targetNode() const
@@ -63,6 +69,11 @@ QQuick3DViewport *SelectionBoxGeometry::view3D() const
return m_view3D;
}
+bool QmlDesigner::Internal::SelectionBoxGeometry::isEmpty() const
+{
+ return m_isEmpty;
+}
+
void SelectionBoxGeometry::setTargetNode(QQuick3DNode *targetNode)
{
if (m_targetNode == targetNode)
@@ -111,13 +122,18 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
QSSGRenderGeometry *geometry = static_cast<QSSGRenderGeometry *>(node);
geometry->clear();
+ for (auto &connection : qAsConst(m_connections))
+ QObject::disconnect(connection);
+ m_connections.clear();
QByteArray vertexData;
QByteArray indexData;
- QVector3D minBounds(-100.f, -100.f, -100.f);
- QVector3D maxBounds(100.f, 100.f, 100.f);
- QVector3D extents;
+ static const float floatMin = std::numeric_limits<float>::lowest();
+ static const float floatMax = std::numeric_limits<float>::max();
+
+ QVector3D minBounds = QVector3D(floatMax, floatMax, floatMax);
+ QVector3D maxBounds = QVector3D(floatMin, floatMin, floatMin);
if (m_targetNode) {
auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode);
@@ -134,33 +150,12 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
rootRN->calculateGlobalVariables();
}
- if (auto modelNode = qobject_cast<QQuick3DModel *>(m_targetNode)) {
- auto nodePriv = QQuick3DObjectPrivate::get(m_targetNode);
- if (auto renderModel = static_cast<QSSGRenderModel *>(nodePriv->spatialNode)) {
- QWindow *window = static_cast<QWindow *>(m_view3D->window());
- if (window) {
- auto context = QSSGRenderContextInterface::getRenderContextInterface(
- quintptr(window));
- if (!context.isNull()) {
- auto bufferManager = context->bufferManager();
- QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
- QVector3D center = bounds.center();
- extents = bounds.extents();
- minBounds = center - extents;
- maxBounds = center + extents;
- }
- }
- }
- }
+ getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds, QMatrix4x4());
+ } else {
+ // Fill some dummy data so geometry won't get rejected
+ appendVertexData(vertexData, indexData, minBounds, maxBounds);
}
- // Adjust bounds to reduce targetNode pixels obscuring the selection box
- extents /= 1000.f;
- minBounds -= extents;
- maxBounds += extents;
-
- fillVertexData(vertexData, indexData, minBounds, maxBounds);
-
geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0,
QSSGRenderGeometry::Attribute::ComponentType::F32Type);
geometry->addAttribute(QSSGRenderGeometry::Attribute::IndexSemantic, 0,
@@ -171,19 +166,138 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
geometry->setPrimitiveType(QSSGRenderGeometry::Lines);
geometry->setBounds(minBounds, maxBounds);
+ bool empty = minBounds.isNull() && maxBounds.isNull();
+ if (m_isEmpty != empty) {
+ m_isEmpty = empty;
+ // Delay notification until we're done with spatial node updates
+ QTimer::singleShot(0, this, &SelectionBoxGeometry::isEmptyChanged);
+ }
+
return node;
}
-void SelectionBoxGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexData,
- const QVector3D &minBounds, const QVector3D &maxBounds)
+void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData,
+ QByteArray &indexData, QVector3D &minBounds,
+ QVector3D &maxBounds, const QMatrix4x4 &transform)
+{
+ QMatrix4x4 fullTransform;
+ auto nodePriv = QQuick3DObjectPrivate::get(node);
+ auto renderNode = static_cast<QSSGRenderNode *>(nodePriv->spatialNode);
+
+ // All transforms are relative to targetNode transform, so its local transform is ignored
+ if (node != m_targetNode) {
+ if (renderNode) {
+ if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty))
+ renderNode->calculateLocalTransform();
+ fullTransform = transform * renderNode->localTransform;
+ }
+
+ m_connections << QObject::connect(node, &QQuick3DNode::scaleChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ m_connections << QObject::connect(node, &QQuick3DNode::rotationChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ m_connections << QObject::connect(node, &QQuick3DNode::positionChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ m_connections << QObject::connect(node, &QQuick3DNode::pivotChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ m_connections << QObject::connect(node, &QQuick3DNode::orientationChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ m_connections << QObject::connect(node, &QQuick3DNode::rotationOrderChanged,
+ this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
+ }
+
+ QVector<QVector3D> minBoundsVec;
+ QVector<QVector3D> maxBoundsVec;
+
+ // Check for children
+ const auto children = node->childItems();
+ for (const auto child : children) {
+ if (auto childNode = qobject_cast<QQuick3DNode *>(child)) {
+ QVector3D newMinBounds = minBounds;
+ QVector3D newMaxBounds = maxBounds;
+ getBounds(childNode, vertexData, indexData, newMinBounds, newMaxBounds, fullTransform);
+ minBoundsVec << newMinBounds;
+ maxBoundsVec << newMaxBounds;
+ }
+ }
+
+ // Combine all child bounds
+ for (const auto &newBounds : qAsConst(minBoundsVec)) {
+ minBounds.setX(qMin(newBounds.x(), minBounds.x()));
+ minBounds.setY(qMin(newBounds.y(), minBounds.y()));
+ minBounds.setZ(qMin(newBounds.z(), minBounds.z()));
+ }
+ for (const auto &newBounds : qAsConst(maxBoundsVec)) {
+ maxBounds.setX(qMax(newBounds.x(), maxBounds.x()));
+ maxBounds.setY(qMax(newBounds.y(), maxBounds.y()));
+ maxBounds.setZ(qMax(newBounds.z(), maxBounds.z()));
+ }
+
+ if (auto modelNode = qobject_cast<QQuick3DModel *>(node)) {
+ if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
+ QWindow *window = static_cast<QWindow *>(m_view3D->window());
+ if (window) {
+ auto context = QSSGRenderContextInterface::getRenderContextInterface(
+ quintptr(window));
+ if (!context.isNull()) {
+ auto bufferManager = context->bufferManager();
+ QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
+ QVector3D center = bounds.center();
+ QVector3D extents = bounds.extents();
+ QVector3D localMin = center - extents;
+ QVector3D localMax = center + extents;
+
+ // Transform all corners of the local bounding box to find final extent in
+ // in parent space
+
+ auto checkCorner = [&minBounds, &maxBounds, &fullTransform]
+ (const QVector3D &corner) {
+ QVector3D mappedCorner = fullTransform.map(corner);
+ minBounds.setX(qMin(mappedCorner.x(), minBounds.x()));
+ minBounds.setY(qMin(mappedCorner.y(), minBounds.y()));
+ minBounds.setZ(qMin(mappedCorner.z(), minBounds.z()));
+ maxBounds.setX(qMax(mappedCorner.x(), maxBounds.x()));
+ maxBounds.setY(qMax(mappedCorner.y(), maxBounds.y()));
+ maxBounds.setZ(qMax(mappedCorner.z(), maxBounds.z()));
+ };
+
+ checkCorner(localMin);
+ checkCorner(localMax);
+ checkCorner(QVector3D(localMin.x(), localMin.y(), localMax.z()));
+ checkCorner(QVector3D(localMin.x(), localMax.y(), localMin.z()));
+ checkCorner(QVector3D(localMax.x(), localMin.y(), localMin.z()));
+ checkCorner(QVector3D(localMin.x(), localMax.y(), localMax.z()));
+ checkCorner(QVector3D(localMax.x(), localMax.y(), localMin.z()));
+ checkCorner(QVector3D(localMax.x(), localMin.y(), localMax.z()));
+ }
+ }
+ }
+ }
+
+ // Target node and immediate children get selection boxes
+ if (transform.isIdentity()) {
+ // Adjust bounds to reduce targetNode pixels obscuring the selection box
+ QVector3D extents = (maxBounds - minBounds) / 1000.f;
+ QVector3D minAdjBounds = minBounds - extents;
+ QVector3D maxAdjBounds = maxBounds + extents;
+
+ appendVertexData(vertexData, indexData, minAdjBounds, maxAdjBounds);
+ }
+}
+
+void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &indexData,
+ const QVector3D &minBounds, const QVector3D &maxBounds)
{
+ int initialVertexSize = vertexData.size();
+ int initialIndexSize = indexData.size();
const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert
- vertexData.resize(vertexSize);
+ quint16 indexAdd = quint16(initialVertexSize / 12);
+ vertexData.resize(initialVertexSize + vertexSize);
const int indexSize = int(sizeof(quint16)) * 12 * 2; // 12 lines, 2 vert/line
- indexData.resize(indexSize);
+ indexData.resize(initialIndexSize + indexSize);
- auto dataPtr = reinterpret_cast<float *>(vertexData.data());
- auto indexPtr = reinterpret_cast<quint16 *>(indexData.data());
+ auto dataPtr = reinterpret_cast<float *>(vertexData.data() + initialVertexSize);
+ auto indexPtr = reinterpret_cast<quint16 *>(indexData.data() + initialIndexSize);
*dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z();
*dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z();
@@ -194,20 +308,20 @@ void SelectionBoxGeometry::fillVertexData(QByteArray &vertexData, QByteArray &in
*dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
*dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
- *indexPtr++ = 0; *indexPtr++ = 1;
- *indexPtr++ = 1; *indexPtr++ = 2;
- *indexPtr++ = 2; *indexPtr++ = 3;
- *indexPtr++ = 3; *indexPtr++ = 0;
+ *indexPtr++ = 0 + indexAdd; *indexPtr++ = 1 + indexAdd;
+ *indexPtr++ = 1 + indexAdd; *indexPtr++ = 2 + indexAdd;
+ *indexPtr++ = 2 + indexAdd; *indexPtr++ = 3 + indexAdd;
+ *indexPtr++ = 3 + indexAdd; *indexPtr++ = 0 + indexAdd;
- *indexPtr++ = 0; *indexPtr++ = 4;
- *indexPtr++ = 1; *indexPtr++ = 5;
- *indexPtr++ = 2; *indexPtr++ = 6;
- *indexPtr++ = 3; *indexPtr++ = 7;
+ *indexPtr++ = 0 + indexAdd; *indexPtr++ = 4 + indexAdd;
+ *indexPtr++ = 1 + indexAdd; *indexPtr++ = 5 + indexAdd;
+ *indexPtr++ = 2 + indexAdd; *indexPtr++ = 6 + indexAdd;
+ *indexPtr++ = 3 + indexAdd; *indexPtr++ = 7 + indexAdd;
- *indexPtr++ = 4; *indexPtr++ = 5;
- *indexPtr++ = 5; *indexPtr++ = 6;
- *indexPtr++ = 6; *indexPtr++ = 7;
- *indexPtr++ = 7; *indexPtr++ = 4;
+ *indexPtr++ = 4 + indexAdd; *indexPtr++ = 5 + indexAdd;
+ *indexPtr++ = 5 + indexAdd; *indexPtr++ = 6 + indexAdd;
+ *indexPtr++ = 6 + indexAdd; *indexPtr++ = 7 + indexAdd;
+ *indexPtr++ = 7 + indexAdd; *indexPtr++ = 4 + indexAdd;
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h
index afe5efd8cf..ef472a5113 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h
@@ -40,6 +40,7 @@ class SelectionBoxGeometry : public QQuick3DGeometry
Q_PROPERTY(QQuick3DNode *targetNode READ targetNode WRITE setTargetNode NOTIFY targetNodeChanged)
Q_PROPERTY(QQuick3DNode *rootNode READ rootNode WRITE setRootNode NOTIFY rootNodeChanged)
Q_PROPERTY(QQuick3DViewport *view3D READ view3D WRITE setView3D NOTIFY view3DChanged)
+ Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged)
public:
SelectionBoxGeometry();
@@ -48,6 +49,7 @@ public:
QQuick3DNode *targetNode() const;
QQuick3DNode *rootNode() const;
QQuick3DViewport *view3D() const;
+ bool isEmpty() const;
public Q_SLOTS:
void setTargetNode(QQuick3DNode *targetNode);
@@ -58,17 +60,22 @@ Q_SIGNALS:
void targetNodeChanged();
void rootNodeChanged();
void view3DChanged();
+ void isEmptyChanged();
protected:
QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override;
private:
- void fillVertexData(QByteArray &vertexData, QByteArray &indexData,
- const QVector3D &minBounds, const QVector3D &maxBounds);
+ void getBounds(QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData,
+ QVector3D &minBounds, QVector3D &maxBounds, const QMatrix4x4 &transform);
+ void appendVertexData(QByteArray &vertexData, QByteArray &indexData,
+ const QVector3D &minBounds, const QVector3D &maxBounds);
QQuick3DNode *m_targetNode = nullptr;
QQuick3DViewport *m_view3D = nullptr;
QQuick3DNode *m_rootNode = nullptr;
+ bool m_isEmpty = true;
+ QVector<QMetaObject::Connection> m_connections;
};
}
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index d3747ab3b3..95360eaa4f 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -340,12 +340,24 @@ QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport(
{
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)
- return child.internalObject()->property("parent").value<QObject *>();
+ 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;
@@ -603,10 +615,8 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
if (hasInstanceForId(id)) {
ServerNodeInstance instance = instanceForId(id);
QObject *object = nullptr;
- if (instance.isSubclassOf("QQuick3DModel") || instance.isSubclassOf("QQuick3DCamera")
- || instance.isSubclassOf("QQuick3DAbstractLight")) {
+ if (instance.isSubclassOf("QQuick3DNode"))
object = instance.internalObject();
- }
QMetaObject::invokeMethod(m_editView3D, "selectObject", Q_ARG(QVariant,
objectToVariant(object)));
return; // TODO: support multi-selection