forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.11'
Conflicts: cmake/QtCreatorIDEBranding.cmake qbs/modules/qtc/qtc.qbs qtcreator_ide_branding.pri src/plugins/mcusupport/mcusupportrunconfiguration.cpp src/plugins/python/pythonproject.cpp src/plugins/qmakeprojectmanager/qmakestep.cpp src/plugins/qmlprojectmanager/qmlproject.cpp src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp Change-Id: I22507be28fd80c49c9fee0dff5937a40db176a82
This commit is contained in:
@@ -139,8 +139,9 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
|
||||
}
|
||||
|
||||
// Return value contains new lookAt point (xyz) and zoom factor (w)
|
||||
QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort)
|
||||
QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
||||
float oldZoom, bool updateZoom)
|
||||
{
|
||||
if (!camera)
|
||||
return QVector4D(0.f, 0.f, 0.f, 1.f);
|
||||
@@ -148,7 +149,8 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D();
|
||||
|
||||
// Get object bounds
|
||||
qreal maxExtent = 200.;
|
||||
const qreal defaultExtent = 200.;
|
||||
qreal maxExtent = defaultExtent;
|
||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) {
|
||||
auto targetPriv = QQuick3DObjectPrivate::get(targetObject);
|
||||
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
|
||||
@@ -172,6 +174,9 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z()));
|
||||
maxExtent *= maxScale;
|
||||
|
||||
if (maxExtent < 0.0001)
|
||||
maxExtent = defaultExtent;
|
||||
|
||||
// Adjust lookAt to look directly at the center of the object bounds
|
||||
lookAt = renderModel->globalTransform.map(center);
|
||||
lookAt.setZ(-lookAt.z()); // Render node transforms have inverted z
|
||||
@@ -189,11 +194,10 @@ QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float default
|
||||
|
||||
camera->setPosition(lookAt + newLookVector);
|
||||
|
||||
// Emprically determined algorithm for nice zoom
|
||||
float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f);
|
||||
float newZoomFactor = updateZoom ? qBound(.0001f, float(maxExtent / 700.), 10000.f) : oldZoom;
|
||||
float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
|
||||
|
||||
return QVector4D(lookAt,
|
||||
zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false));
|
||||
return QVector4D(lookAt, cameraZoomFactor);
|
||||
}
|
||||
|
||||
void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
@@ -204,6 +208,20 @@ void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &p
|
||||
});
|
||||
}
|
||||
|
||||
QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
|
||||
{
|
||||
if (pickNode) {
|
||||
// Check if the picked node actually specifies another node as the pick target
|
||||
QVariant componentVar = pickNode->property("_pickTarget");
|
||||
if (componentVar.isValid()) {
|
||||
auto componentNode = componentVar.value<QQuick3DNode *>();
|
||||
if (componentNode)
|
||||
return componentNode;
|
||||
}
|
||||
}
|
||||
return pickNode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +62,13 @@ public:
|
||||
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
||||
float defaultLookAtDistance, const QVector3D &lookAt,
|
||||
float zoomFactor, bool relative);
|
||||
Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort);
|
||||
Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
||||
float oldZoom, bool updateZoom = true);
|
||||
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant& value);
|
||||
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
|
||||
|
||||
|
||||
signals:
|
||||
void overlayUpdateNeeded();
|
||||
|
||||
@@ -322,11 +322,11 @@ QVector3D MouseArea3D::getNewScale(QQuick3DNode *node, const QVector3D &startSca
|
||||
scaleVec *= magnitude;
|
||||
|
||||
// Zero axes on scale vector indicate directions we don't want scaling to affect
|
||||
if (qFuzzyIsNull(scaleVec.x()))
|
||||
if (scaleDirVector.x() < 0.0001f)
|
||||
scaleVec.setX(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.y()))
|
||||
if (scaleDirVector.y() < 0.0001f)
|
||||
scaleVec.setY(1.f);
|
||||
if (qFuzzyIsNull(scaleVec.z()))
|
||||
if (scaleDirVector.z() < 0.0001f)
|
||||
scaleVec.setZ(1.f);
|
||||
scaleVec *= startScale;
|
||||
|
||||
@@ -344,11 +344,17 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||
QQuick3DNode *node, const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||
const QVector3D &nodePos, qreal prevAngle, bool trackBall)
|
||||
{
|
||||
const QVector3D cameraToNodeDir = getCameraToNodeDir(node);
|
||||
// Get camera to node direction in node orientation
|
||||
QVector3D cameraToNodeDir = getCameraToNodeDir(node);
|
||||
if (trackBall) {
|
||||
// Only the distance in plane direction is relevant in trackball drag
|
||||
QVector3D dragDir = QVector3D::crossProduct(getNormal(), cameraToNodeDir).normalized();
|
||||
QVector3D screenDragDir = m_view3D->mapFrom3DScene(node->scenePosition() + dragDir);
|
||||
QVector3D scenePos = node->scenePosition();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded) {
|
||||
scenePos.setZ(-scenePos.z());
|
||||
dragDir = -dragDir;
|
||||
}
|
||||
QVector3D screenDragDir = m_view3D->mapFrom3DScene(scenePos + dragDir);
|
||||
screenDragDir.setZ(0);
|
||||
dragDir = (screenDragDir - nodePos).normalized();
|
||||
const QVector3D pressToCurrent = (currentPos - pressPos);
|
||||
@@ -361,7 +367,9 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||
qreal angle = qAcos(qreal(QVector3D::dotProduct(nodeToPress, nodeToCurrent)));
|
||||
|
||||
// Determine drag direction left/right
|
||||
const QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
|
||||
QVector3D dragNormal = QVector3D::crossProduct(nodeToPress, nodeToCurrent).normalized();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded)
|
||||
dragNormal = -dragNormal;
|
||||
angle *= QVector3D::dotProduct(QVector3D(0.f, 0.f, 1.f), dragNormal) < 0 ? -1.0 : 1.0;
|
||||
|
||||
// Determine drag ring orientation relative to camera
|
||||
@@ -392,7 +400,10 @@ void QmlDesigner::Internal::MouseArea3D::applyRotationAngleToNode(
|
||||
{
|
||||
if (!qFuzzyIsNull(angle)) {
|
||||
node->setRotation(startRotation);
|
||||
node->rotate(qRadiansToDegrees(angle), getNormal(), QQuick3DNode::SceneSpace);
|
||||
QVector3D normal = getNormal();
|
||||
if (orientation() != node->orientation())
|
||||
normal.setZ(-normal.z());
|
||||
node->rotate(qRadiansToDegrees(angle), normal, QQuick3DNode::SceneSpace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,6 +418,10 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
|
||||
const float *dataPtr(sceneTransform().data());
|
||||
QVector3D xAxis = QVector3D(-dataPtr[0], -dataPtr[1], -dataPtr[2]).normalized();
|
||||
QVector3D yAxis = QVector3D(-dataPtr[4], -dataPtr[5], -dataPtr[6]).normalized();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded) {
|
||||
xAxis = QVector3D(-xAxis.x(), -xAxis.y(), xAxis.z());
|
||||
yAxis = QVector3D(-yAxis.x(), -yAxis.y(), yAxis.z());
|
||||
}
|
||||
|
||||
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
||||
|
||||
@@ -596,11 +611,14 @@ QVector3D MouseArea3D::getCameraToNodeDir(QQuick3DNode *node) const
|
||||
{
|
||||
QVector3D dir;
|
||||
if (qobject_cast<QQuick3DOrthographicCamera *>(m_view3D->camera())) {
|
||||
dir = m_view3D->camera()->cameraNode()->getDirection();
|
||||
// Camera direction has x and y flipped
|
||||
dir = QVector3D(-dir.x(), -dir.y(), dir.z());
|
||||
dir = -m_view3D->camera()->cameraNode()->getDirection();
|
||||
dir.setZ(-dir.z());
|
||||
} else {
|
||||
dir = (node->scenePosition() - m_view3D->camera()->scenePosition()).normalized();
|
||||
QVector3D camPos = m_view3D->camera()->scenePosition();
|
||||
QVector3D nodePos = node->scenePosition();
|
||||
if (node->orientation() == QQuick3DNode::RightHanded)
|
||||
nodePos.setZ(-nodePos.z());
|
||||
dir = (node->scenePosition() - camPos).normalized();
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
static const float floatMin = std::numeric_limits<float>::lowest();
|
||||
static const float floatMax = std::numeric_limits<float>::max();
|
||||
static const QVector3D maxVec = QVector3D(floatMax, floatMax, floatMax);
|
||||
static const QVector3D minVec = QVector3D(floatMin, floatMin, floatMin);
|
||||
|
||||
SelectionBoxGeometry::SelectionBoxGeometry()
|
||||
: QQuick3DGeometry()
|
||||
{
|
||||
@@ -133,11 +138,8 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
QByteArray vertexData;
|
||||
QByteArray indexData;
|
||||
|
||||
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);
|
||||
QVector3D minBounds = maxVec;
|
||||
QVector3D maxBounds = minVec;
|
||||
|
||||
if (m_targetNode) {
|
||||
auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode);
|
||||
@@ -154,10 +156,20 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
|
||||
rootRN->calculateGlobalVariables();
|
||||
}
|
||||
getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds, QMatrix4x4());
|
||||
getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds);
|
||||
appendVertexData(QMatrix4x4(), vertexData, indexData, minBounds, maxBounds);
|
||||
|
||||
// Track changes in ancestors, as they can move node without affecting node properties
|
||||
auto parentNode = m_targetNode->parentNode();
|
||||
while (parentNode) {
|
||||
trackNodeChanges(parentNode);
|
||||
parentNode = parentNode->parentNode();
|
||||
}
|
||||
} else {
|
||||
// Fill some dummy data so geometry won't get rejected
|
||||
appendVertexData(vertexData, indexData, minBounds, maxBounds);
|
||||
minBounds = {};
|
||||
maxBounds = {};
|
||||
appendVertexData(QMatrix4x4(), vertexData, indexData, minBounds, maxBounds);
|
||||
}
|
||||
|
||||
geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0,
|
||||
@@ -182,62 +194,73 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
|
||||
return node;
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
QByteArray &indexData, QVector3D &minBounds,
|
||||
QVector3D &maxBounds, const QMatrix4x4 &transform)
|
||||
void SelectionBoxGeometry::getBounds(
|
||||
QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData,
|
||||
QVector3D &minBounds, QVector3D &maxBounds)
|
||||
{
|
||||
QMatrix4x4 fullTransform;
|
||||
QMatrix4x4 localTransform;
|
||||
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;
|
||||
localTransform = 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);
|
||||
trackNodeChanges(node);
|
||||
}
|
||||
|
||||
QVector3D localMinBounds = maxVec;
|
||||
QVector3D localMaxBounds = minVec;
|
||||
|
||||
// Find bounds for children
|
||||
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);
|
||||
getBounds(childNode, vertexData, indexData, newMinBounds, newMaxBounds);
|
||||
minBoundsVec << newMinBounds;
|
||||
maxBoundsVec << newMaxBounds;
|
||||
}
|
||||
}
|
||||
|
||||
auto combineMinBounds = [](QVector3D &target, const QVector3D &source) {
|
||||
target.setX(qMin(source.x(), target.x()));
|
||||
target.setY(qMin(source.y(), target.y()));
|
||||
target.setZ(qMin(source.z(), target.z()));
|
||||
};
|
||||
auto combineMaxBounds = [](QVector3D &target, const QVector3D &source) {
|
||||
target.setX(qMax(source.x(), target.x()));
|
||||
target.setY(qMax(source.y(), target.y()));
|
||||
target.setZ(qMax(source.z(), target.z()));
|
||||
};
|
||||
auto transformCorner = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||
const QVector3D &corner) {
|
||||
QVector3D mappedCorner = m.map(corner);
|
||||
combineMinBounds(minTarget, mappedCorner);
|
||||
combineMaxBounds(maxTarget, mappedCorner);
|
||||
};
|
||||
auto transformCorners = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||
const QVector3D &minCorner, const QVector3D &maxCorner) {
|
||||
transformCorner(m, minTarget, maxTarget, minCorner);
|
||||
transformCorner(m, minTarget, maxTarget, maxCorner);
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), minCorner.y(), maxCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), maxCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), maxCorner.y(), minCorner.z()));
|
||||
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), maxCorner.z()));
|
||||
};
|
||||
|
||||
// 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()));
|
||||
}
|
||||
for (const auto &newBounds : qAsConst(minBoundsVec))
|
||||
combineMinBounds(localMinBounds, newBounds);
|
||||
for (const auto &newBounds : qAsConst(maxBoundsVec))
|
||||
combineMaxBounds(localMaxBounds, newBounds);
|
||||
|
||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(node)) {
|
||||
if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
|
||||
@@ -253,47 +276,38 @@ void SelectionBoxGeometry::getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
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()));
|
||||
combineMinBounds(localMinBounds, localMin);
|
||||
combineMaxBounds(localMaxBounds, localMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
combineMinBounds(localMinBounds, {});
|
||||
combineMaxBounds(localMaxBounds, {});
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (localMaxBounds == minVec) {
|
||||
localMinBounds = {};
|
||||
localMaxBounds = {};
|
||||
}
|
||||
|
||||
// Transform local space bounding box to parent space
|
||||
transformCorners(localTransform, minBounds, maxBounds, localMinBounds, localMaxBounds);
|
||||
|
||||
// Immediate child boxes
|
||||
if (node->parentNode() == m_targetNode)
|
||||
appendVertexData(localTransform, vertexData, indexData, localMinBounds, localMaxBounds);
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &indexData,
|
||||
const QVector3D &minBounds, const QVector3D &maxBounds)
|
||||
void SelectionBoxGeometry::appendVertexData(const QMatrix4x4 &m, QByteArray &vertexData,
|
||||
QByteArray &indexData, const QVector3D &minBounds,
|
||||
const QVector3D &maxBounds)
|
||||
{
|
||||
// Adjust bounds to reduce targetNode pixels obscuring the selection box
|
||||
QVector3D extents = (maxBounds - minBounds) / 1000.f;
|
||||
QVector3D minAdjBounds = minBounds - extents;
|
||||
QVector3D maxAdjBounds = maxBounds + extents;
|
||||
|
||||
int initialVertexSize = vertexData.size();
|
||||
int initialIndexSize = indexData.size();
|
||||
const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert
|
||||
@@ -305,14 +319,20 @@ void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &
|
||||
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();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
|
||||
*dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z();
|
||||
QVector3D corners[8];
|
||||
corners[0] = QVector3D(maxAdjBounds.x(), maxAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[1] = QVector3D(minAdjBounds.x(), maxAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[2] = QVector3D(minAdjBounds.x(), minAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[3] = QVector3D(maxAdjBounds.x(), minAdjBounds.y(), maxAdjBounds.z());
|
||||
corners[4] = QVector3D(maxAdjBounds.x(), maxAdjBounds.y(), minAdjBounds.z());
|
||||
corners[5] = QVector3D(minAdjBounds.x(), maxAdjBounds.y(), minAdjBounds.z());
|
||||
corners[6] = QVector3D(minAdjBounds.x(), minAdjBounds.y(), minAdjBounds.z());
|
||||
corners[7] = QVector3D(maxAdjBounds.x(), minAdjBounds.y(), minAdjBounds.z());
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
corners[i] = m.map(corners[i]);
|
||||
*dataPtr++ = corners[i].x(); *dataPtr++ = corners[i].y(); *dataPtr++ = corners[i].z();
|
||||
}
|
||||
|
||||
*indexPtr++ = 0 + indexAdd; *indexPtr++ = 1 + indexAdd;
|
||||
*indexPtr++ = 1 + indexAdd; *indexPtr++ = 2 + indexAdd;
|
||||
@@ -330,6 +350,22 @@ void SelectionBoxGeometry::appendVertexData(QByteArray &vertexData, QByteArray &
|
||||
*indexPtr++ = 7 + indexAdd; *indexPtr++ = 4 + indexAdd;
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::trackNodeChanges(QQuick3DNode *node)
|
||||
{
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::sceneScaleChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::sceneRotationChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
m_connections << QObject::connect(node, &QQuick3DNode::scenePositionChanged,
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,10 +69,11 @@ protected:
|
||||
QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override;
|
||||
|
||||
private:
|
||||
void getBounds(QQuick3DNode *node, QByteArray &vertexData, QByteArray &indexData,
|
||||
QVector3D &minBounds, QVector3D &maxBounds, const QMatrix4x4 &transform);
|
||||
void appendVertexData(QByteArray &vertexData, QByteArray &indexData,
|
||||
void getBounds(QQuick3DNode *node, QByteArray &vertexData,
|
||||
QByteArray &indexData, QVector3D &minBounds, QVector3D &maxBounds);
|
||||
void appendVertexData(const QMatrix4x4 &m, QByteArray &vertexData, QByteArray &indexData,
|
||||
const QVector3D &minBounds, const QVector3D &maxBounds);
|
||||
void trackNodeChanges(QQuick3DNode *node);
|
||||
|
||||
QQuick3DNode *m_targetNode = nullptr;
|
||||
QQuick3DViewport *m_view3D = nullptr;
|
||||
|
||||
@@ -332,6 +332,10 @@ void NodeInstanceServer::clearScene(const ClearSceneCommand &/*command*/)
|
||||
m_fileUrl.clear();
|
||||
}
|
||||
|
||||
void NodeInstanceServer::change3DView(const Change3DViewCommand &/*command*/)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeInstanceServer::changeSelection(const ChangeSelectionCommand & /*command*/)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ public:
|
||||
void changeIds(const ChangeIdsCommand &command) override;
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void clearScene(const ClearSceneCommand &command) override;
|
||||
void change3DView(const Change3DViewCommand &command) override;
|
||||
void removeInstances(const RemoveInstancesCommand &command) override;
|
||||
void removeProperties(const RemovePropertiesCommand &command) override;
|
||||
void reparentInstances(const ReparentInstancesCommand &command) override;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "changefileurlcommand.h"
|
||||
#include "clearscenecommand.h"
|
||||
#include "reparentinstancescommand.h"
|
||||
#include "change3dviewcommand.h"
|
||||
#include "changevaluescommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changeidscommand.h"
|
||||
@@ -57,7 +58,6 @@
|
||||
#include "createscenecommand.h"
|
||||
#include "tokencommand.h"
|
||||
#include "removesharedmemorycommand.h"
|
||||
#include "changeselectioncommand.h"
|
||||
#include "objectnodeinstance.h"
|
||||
#include <drop3dlibraryitemcommand.h>
|
||||
|
||||
@@ -124,13 +124,18 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
}
|
||||
|
||||
window->installEventFilter(this);
|
||||
QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant)));
|
||||
QObject::connect(window, SIGNAL(selectionChanged(QVariant)),
|
||||
this, SLOT(handleSelectionChanged(QVariant)));
|
||||
QObject::connect(window, SIGNAL(commitObjectProperty(QVariant, QVariant)),
|
||||
this, SLOT(handleObjectPropertyCommit(QVariant, QVariant)));
|
||||
QObject::connect(window, SIGNAL(changeObjectProperty(QVariant, QVariant)),
|
||||
this, SLOT(handleObjectPropertyChange(QVariant, QVariant)));
|
||||
QObject::connect(window, SIGNAL(activeChanged()),
|
||||
this, SLOT(handleActiveChanged()));
|
||||
QObject::connect(&m_propertyChangeTimer, &QTimer::timeout,
|
||||
this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout);
|
||||
QObject::connect(&m_selectionChangeTimer, &QTimer::timeout,
|
||||
this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout);
|
||||
|
||||
//For macOS we have to use the 4.1 core profile
|
||||
QSurfaceFormat surfaceFormat = window->requestedFormat();
|
||||
@@ -145,14 +150,21 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
return window;
|
||||
}
|
||||
|
||||
// an object is clicked in the 3D edit view. Null object indicates selection clearing.
|
||||
void Qt5InformationNodeInstanceServer::objectClicked(const QVariant &object)
|
||||
// The selection has changed in the 3D edit view. Empty list indicates selection is cleared.
|
||||
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
|
||||
{
|
||||
auto obj = object.value<QObject *>();
|
||||
ServerNodeInstance instance;
|
||||
if (obj)
|
||||
instance = instanceForObject(obj);
|
||||
selectInstance(instance);
|
||||
QList<ServerNodeInstance> instanceList;
|
||||
const QVariantList varObjs = objs.value<QVariantList>();
|
||||
for (const auto &object : varObjs) {
|
||||
auto obj = object.value<QObject *>();
|
||||
if (obj) {
|
||||
ServerNodeInstance instance = instanceForObject(obj);
|
||||
instanceList << instance;
|
||||
}
|
||||
}
|
||||
selectInstances(instanceList);
|
||||
// Hold selection changes reflected back from designer for a bit
|
||||
m_selectionChangeTimer.start(500);
|
||||
}
|
||||
|
||||
QVector<Qt5InformationNodeInstanceServer::InstancePropertyValueTriple>
|
||||
@@ -219,6 +231,65 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::showEditView(const QPoint &pos, const QSize &size)
|
||||
{
|
||||
m_blockViewActivate = false;
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->setPosition(pos);
|
||||
window->resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::hideEditView()
|
||||
{
|
||||
m_blockViewActivate = true;
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window)
|
||||
window->hide();
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::activateEditView()
|
||||
{
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
Qt::WindowFlags flags = window->flags();
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
window->setFlags(Qt::Popup);
|
||||
window->show();
|
||||
window->setFlags(flags);
|
||||
#else
|
||||
window->raise();
|
||||
window->setFlags(flags | Qt::WindowStaysOnTopHint);
|
||||
window->show();
|
||||
|
||||
window->requestActivate();
|
||||
window->raise();
|
||||
window->setFlags(flags);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::moveEditView(const QPoint &pos)
|
||||
{
|
||||
auto window = qobject_cast<QWindow*>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->setPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::resizeEditView(const QSize &size)
|
||||
{
|
||||
auto window = qobject_cast<QWindow *>(m_editView3D);
|
||||
if (window) {
|
||||
activateEditView();
|
||||
window->resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleObjectPropertyCommit(const QVariant &object,
|
||||
const QVariant &propName)
|
||||
{
|
||||
@@ -253,10 +324,19 @@ void Qt5InformationNodeInstanceServer::updateViewPortRect()
|
||||
viewPortProperty.write(viewPortrect);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleActiveChanged()
|
||||
{
|
||||
if (m_blockViewActivate)
|
||||
return;
|
||||
|
||||
activateEditView();
|
||||
}
|
||||
|
||||
Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
|
||||
Qt5NodeInstanceServer(nodeInstanceClient)
|
||||
{
|
||||
m_propertyChangeTimer.setInterval(100);
|
||||
m_selectionChangeTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::sendTokenBack()
|
||||
@@ -315,9 +395,9 @@ bool Qt5InformationNodeInstanceServer::isDirtyRecursiveForParentInstances(QQuick
|
||||
}
|
||||
|
||||
/* This method allows changing the selection from the puppet */
|
||||
void Qt5InformationNodeInstanceServer::selectInstance(const ServerNodeInstance &instance)
|
||||
void Qt5InformationNodeInstanceServer::selectInstances(const QList<ServerNodeInstance> &instanceList)
|
||||
{
|
||||
nodeInstanceClient()->selectionChanged(createChangeSelectionCommand({instance}));
|
||||
nodeInstanceClient()->selectionChanged(createChangeSelectionCommand(instanceList));
|
||||
}
|
||||
|
||||
/* This method allows changing property values from the puppet
|
||||
@@ -335,6 +415,11 @@ void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout()
|
||||
ValuesModifiedCommand::TransactionOption::None);
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout()
|
||||
{
|
||||
changeSelection(m_pendingSelectionChangeCommand);
|
||||
}
|
||||
|
||||
QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport(
|
||||
const QList<ServerNodeInstance> &instanceList) const
|
||||
{
|
||||
@@ -389,26 +474,25 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
|
||||
{
|
||||
ServerNodeInstance root = rootNodeInstance();
|
||||
|
||||
QObject *node = nullptr;
|
||||
bool showCustomLight = false;
|
||||
|
||||
if (root.isSubclassOf("QQuick3DNode")) {
|
||||
node = root.internalObject();
|
||||
m_rootNode = root.internalObject();
|
||||
showCustomLight = true; // Pure node scene we should add a custom light
|
||||
} else {
|
||||
node = findRootNodeOf3DViewport(instanceList);
|
||||
m_rootNode = findRootNodeOf3DViewport(instanceList);
|
||||
}
|
||||
|
||||
if (node) { // If we found a scene we create the edit view
|
||||
if (m_rootNode) { // If we found a scene we create the edit view
|
||||
m_editView3D = createEditView3D(engine());
|
||||
|
||||
if (!m_editView3D)
|
||||
return;
|
||||
|
||||
QQmlProperty sceneProperty(m_editView3D, "scene", context());
|
||||
node->setParent(m_editView3D);
|
||||
sceneProperty.write(objectToVariant(node));
|
||||
QQmlProperty parentProperty(node, "parent", 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);
|
||||
@@ -610,18 +694,41 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|
||||
if (!m_editView3D)
|
||||
return;
|
||||
|
||||
if (m_selectionChangeTimer.isActive()) {
|
||||
// If selection was recently changed by puppet, hold updating the selection for a bit to
|
||||
// avoid selection flicker, especially in multiselect cases.
|
||||
m_pendingSelectionChangeCommand = command;
|
||||
// Add additional time in case more commands are still coming through
|
||||
m_selectionChangeTimer.start(500);
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector<qint32> instanceIds = command.instanceIds();
|
||||
QVariantList selectedObjs;
|
||||
for (qint32 id : instanceIds) {
|
||||
if (hasInstanceForId(id)) {
|
||||
ServerNodeInstance instance = instanceForId(id);
|
||||
QObject *object = nullptr;
|
||||
if (instance.isSubclassOf("QQuick3DNode"))
|
||||
object = instance.internalObject();
|
||||
QMetaObject::invokeMethod(m_editView3D, "selectObject", Q_ARG(QVariant,
|
||||
objectToVariant(object)));
|
||||
return; // TODO: support multi-selection
|
||||
if (object && object != m_rootNode)
|
||||
selectedObjs << objectToVariant(object);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// using the new boxes immediately leads to visual glitches.
|
||||
int boxCount = m_editView3D->property("selectionBoxes").value<QVariantList>().size();
|
||||
if (boxCount < selectedObjs.size()) {
|
||||
QMetaObject::invokeMethod(m_editView3D, "ensureSelectionBoxes",
|
||||
Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size())));
|
||||
m_pendingSelectionChangeCommand = command;
|
||||
m_selectionChangeTimer.start(100);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(m_editView3D, "selectObjects",
|
||||
Q_ARG(QVariant, QVariant::fromValue(selectedObjs)));
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command)
|
||||
@@ -641,4 +748,18 @@ void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCo
|
||||
startRenderTimer();
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::change3DView(const Change3DViewCommand &command)
|
||||
{
|
||||
for (const InformationContainer &container : command.informationVector()) {
|
||||
if (container.name() == InformationName::ShowView)
|
||||
showEditView(container.information().toPoint(), container.secondInformation().toSize());
|
||||
else if (container.name() == InformationName::HideView)
|
||||
hideEditView();
|
||||
else if (container.name() == InformationName::MoveView)
|
||||
moveEditView(container.information().toPoint());
|
||||
else if (container.name() == InformationName::ResizeView)
|
||||
resizeEditView(container.secondInformation().toSize());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "qt5nodeinstanceserver.h"
|
||||
#include "tokencommand.h"
|
||||
#include "valueschangedcommand.h"
|
||||
#include "changeselectioncommand.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
@@ -42,6 +43,7 @@ public:
|
||||
|
||||
void reparentInstances(const ReparentInstancesCommand &command) override;
|
||||
void clearScene(const ClearSceneCommand &command) override;
|
||||
void change3DView(const Change3DViewCommand &command) override;
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void completeComponent(const CompleteComponentCommand &command) override;
|
||||
void token(const TokenCommand &command) override;
|
||||
@@ -50,10 +52,11 @@ public:
|
||||
void changePropertyValues(const ChangeValuesCommand &command) override;
|
||||
|
||||
private slots:
|
||||
void objectClicked(const QVariant &object);
|
||||
void handleSelectionChanged(const QVariant &objs);
|
||||
void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName);
|
||||
void handleObjectPropertyChange(const QVariant &object, const QVariant &propName);
|
||||
void updateViewPortRect();
|
||||
void handleActiveChanged();
|
||||
|
||||
protected:
|
||||
void collectItemChangesAndSendChangeCommands() override;
|
||||
@@ -62,11 +65,12 @@ protected:
|
||||
void sendTokenBack();
|
||||
bool isDirtyRecursiveForNonInstanceItems(QQuickItem *item) const;
|
||||
bool isDirtyRecursiveForParentInstances(QQuickItem *item) const;
|
||||
void selectInstance(const ServerNodeInstance &instance);
|
||||
void selectInstances(const QList<ServerNodeInstance> &instanceList);
|
||||
void modifyProperties(const QVector<InstancePropertyValueTriple> &properties);
|
||||
|
||||
private:
|
||||
void handleObjectPropertyChangeTimeout();
|
||||
void handleSelectionChangeTimeout();
|
||||
QObject *createEditView3D(QQmlEngine *engine);
|
||||
void setup3DEditView(const QList<ServerNodeInstance> &instanceList);
|
||||
QObject *findRootNodeOf3DViewport(const QList<ServerNodeInstance> &instanceList) const;
|
||||
@@ -80,14 +84,24 @@ private:
|
||||
const PropertyName &propertyName,
|
||||
ValuesModifiedCommand::TransactionOption option);
|
||||
|
||||
void showEditView(const QPoint &pos, const QSize &size);
|
||||
void hideEditView();
|
||||
void activateEditView();
|
||||
void moveEditView(const QPoint &pos);
|
||||
void resizeEditView(const QSize &size);
|
||||
|
||||
QObject *m_editView3D = nullptr;
|
||||
QSet<ServerNodeInstance> m_parentChangedSet;
|
||||
QList<ServerNodeInstance> m_completedComponentList;
|
||||
QList<TokenCommand> m_tokenList;
|
||||
QTimer m_propertyChangeTimer;
|
||||
QTimer m_selectionChangeTimer;
|
||||
QVariant m_changedNode;
|
||||
PropertyName m_changedProperty;
|
||||
ServerNodeInstance m_viewPortInstance;
|
||||
bool m_blockViewActivate = false;
|
||||
QObject *m_rootNode = nullptr;
|
||||
ChangeSelectionCommand m_pendingSelectionChangeCommand;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
#include <private/qquick3dnode_p.h>
|
||||
#include <private/qquick3dmodel_p.h>
|
||||
#include <private/qquick3dnode_p_p.h>
|
||||
#endif
|
||||
|
||||
@@ -73,7 +74,7 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildren)
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildInstances)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
auto node = quick3DNode();
|
||||
@@ -90,22 +91,42 @@ void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyT
|
||||
|
||||
}
|
||||
if (!parentHidden) {
|
||||
if (applyToChildren) {
|
||||
auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * {
|
||||
if (nodeInstanceServer()->hasInstanceForObject(obj)) {
|
||||
ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject()))
|
||||
return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
if (auto quick3dInstance = getQuick3DInstance(childItem)) {
|
||||
auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * {
|
||||
if (nodeInstanceServer()->hasInstanceForObject(obj)) {
|
||||
ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject()))
|
||||
return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
if (auto quick3dInstance = getQuick3DInstance(childItem)) {
|
||||
if (applyToChildInstances) {
|
||||
// Don't override explicit block in children
|
||||
if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor)
|
||||
quick3dInstance->setPickable(enable, false, true);
|
||||
}
|
||||
} else {
|
||||
// Children of components do not have instances, but will still need to be
|
||||
// pickable. These need to be set even if applyToChildInstances is false.
|
||||
std::function<void(QQuick3DNode *)> checkChildren;
|
||||
checkChildren = [&](QQuick3DNode *checkNode) {
|
||||
const auto childItems = checkNode->childItems();
|
||||
for (auto child : childItems) {
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(child))
|
||||
checkChildren(childNode);
|
||||
}
|
||||
if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) {
|
||||
QVariant value;
|
||||
if (enable)
|
||||
value = QVariant::fromValue(node);
|
||||
// Specify the actual pick target with dynamic property
|
||||
checkModel->setProperty("_pickTarget", value);
|
||||
checkModel->setPickable(enable);
|
||||
}
|
||||
};
|
||||
checkChildren(node);
|
||||
}
|
||||
}
|
||||
if (nodeType == QQuick3DObject::Model)
|
||||
@@ -115,7 +136,7 @@ void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyT
|
||||
#else
|
||||
Q_UNUSED(enable)
|
||||
Q_UNUSED(checkParent)
|
||||
Q_UNUSED(applyToChildren)
|
||||
Q_UNUSED(applyToChildInstances)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ protected:
|
||||
private:
|
||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||
QQuick3DNode *quick3DNode() const;
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildren);
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildInstances);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
Reference in New Issue
Block a user