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:
Orgad Shaneh
2019-12-06 13:04:17 +02:00
145 changed files with 2761 additions and 634 deletions

View File

@@ -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;
}
}
}

View File

@@ -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();

View File

@@ -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 &currentPos,
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;
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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*/)
{
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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