forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.11'
Conflicts: src/plugins/designer/codemodelhelpers.cpp Change-Id: I78906f2fbbfd27d254589a272ebca423b0b80699
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "cameracontrolhelper.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
CameraControlHelper::CameraControlHelper()
|
||||
: QObject()
|
||||
{
|
||||
m_inputUpdateTimer.setInterval(16);
|
||||
QObject::connect(&m_inputUpdateTimer, &QTimer::timeout,
|
||||
this, &CameraControlHelper::handleUpdateTimer);
|
||||
|
||||
m_overlayUpdateTimer.setInterval(16);
|
||||
m_overlayUpdateTimer.setSingleShot(true);
|
||||
QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout,
|
||||
this, &CameraControlHelper::overlayUpdateNeeded);
|
||||
}
|
||||
|
||||
bool CameraControlHelper::enabled()
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void CameraControlHelper::handleUpdateTimer()
|
||||
{
|
||||
emit updateInputs();
|
||||
}
|
||||
|
||||
void CameraControlHelper::setEnabled(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
m_inputUpdateTimer.start();
|
||||
else
|
||||
m_inputUpdateTimer.stop();
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
void CameraControlHelper::requestOverlayUpdate()
|
||||
{
|
||||
if (!m_overlayUpdateTimer.isActive())
|
||||
m_overlayUpdateTimer.start();
|
||||
}
|
||||
|
||||
QString CameraControlHelper::generateUniqueName(const QString &nameRoot)
|
||||
{
|
||||
static QHash<QString, int> counters;
|
||||
int count = counters[nameRoot]++;
|
||||
return QStringLiteral("%1_%2").arg(nameRoot).arg(count);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
class CameraControlHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
|
||||
|
||||
public:
|
||||
CameraControlHelper();
|
||||
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
Q_INVOKABLE void requestOverlayUpdate();
|
||||
Q_INVOKABLE QString generateUniqueName(const QString &nameRoot);
|
||||
|
||||
public slots:
|
||||
void handleUpdateTimer();
|
||||
|
||||
signals:
|
||||
void updateInputs();
|
||||
void enabledChanged(bool enabled);
|
||||
void overlayUpdateNeeded();
|
||||
|
||||
private:
|
||||
bool m_enabled = false;
|
||||
QTimer m_inputUpdateTimer;
|
||||
QTimer m_overlayUpdateTimer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
HEADERS += $$PWD/cameracontrolhelper.h \
|
||||
HEADERS += $$PWD/generalhelper.h \
|
||||
$$PWD/mousearea3d.h \
|
||||
$$PWD/camerageometry.h \
|
||||
$$PWD/gridgeometry.h
|
||||
$$PWD/gridgeometry.h \
|
||||
$$PWD/selectionboxgeometry.h
|
||||
|
||||
SOURCES += $$PWD/cameracontrolhelper.cpp \
|
||||
SOURCES += $$PWD/generalhelper.cpp \
|
||||
$$PWD/mousearea3d.cpp \
|
||||
$$PWD/camerageometry.cpp \
|
||||
$$PWD/gridgeometry.cpp
|
||||
$$PWD/gridgeometry.cpp \
|
||||
$$PWD/selectionboxgeometry.cpp
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "generalhelper.h"
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
|
||||
#include "selectionboxgeometry.h"
|
||||
|
||||
#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/qmath.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
GeneralHelper::GeneralHelper()
|
||||
: QObject()
|
||||
{
|
||||
m_overlayUpdateTimer.setInterval(16);
|
||||
m_overlayUpdateTimer.setSingleShot(true);
|
||||
QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout,
|
||||
this, &GeneralHelper::overlayUpdateNeeded);
|
||||
}
|
||||
|
||||
void GeneralHelper::requestOverlayUpdate()
|
||||
{
|
||||
if (!m_overlayUpdateTimer.isActive())
|
||||
m_overlayUpdateTimer.start();
|
||||
}
|
||||
|
||||
QString GeneralHelper::generateUniqueName(const QString &nameRoot)
|
||||
{
|
||||
static QHash<QString, int> counters;
|
||||
int count = counters[nameRoot]++;
|
||||
return QStringLiteral("%1_%2").arg(nameRoot).arg(count);
|
||||
}
|
||||
|
||||
void GeneralHelper::orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation,
|
||||
const QVector3D &lookAtPoint, const QVector3D &pressPos,
|
||||
const QVector3D ¤tPos)
|
||||
{
|
||||
QVector3D dragVector = currentPos - pressPos;
|
||||
|
||||
if (dragVector.length() < 0.001f)
|
||||
return;
|
||||
|
||||
camera->setRotation(startRotation);
|
||||
QVector3D newRotation(dragVector.y(), dragVector.x(), 0.f);
|
||||
newRotation *= 0.5f; // Emprically determined multiplier for nice drag
|
||||
newRotation += startRotation;
|
||||
|
||||
camera->setRotation(newRotation);
|
||||
|
||||
const QVector3D oldLookVector = camera->position() - lookAtPoint;
|
||||
QMatrix4x4 m = camera->sceneTransform();
|
||||
const float *dataPtr(m.data());
|
||||
QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]);
|
||||
newLookVector.normalize();
|
||||
newLookVector *= oldLookVector.length();
|
||||
|
||||
camera->setPosition(lookAtPoint + newLookVector);
|
||||
}
|
||||
|
||||
// Pans camera and returns the new look-at point
|
||||
QVector3D GeneralHelper::panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform,
|
||||
const QVector3D &startPosition, const QVector3D &startLookAt,
|
||||
const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||
float zoomFactor)
|
||||
{
|
||||
QVector3D dragVector = currentPos - pressPos;
|
||||
|
||||
if (dragVector.length() < 0.001f)
|
||||
return startLookAt;
|
||||
|
||||
const float *dataPtr(startTransform.data());
|
||||
const QVector3D xAxis = QVector3D(dataPtr[0], dataPtr[1], dataPtr[2]).normalized();
|
||||
const QVector3D yAxis = QVector3D(dataPtr[4], dataPtr[5], dataPtr[6]).normalized();
|
||||
const QVector3D xDelta = -1.f * xAxis * dragVector.x();
|
||||
const QVector3D yDelta = yAxis * dragVector.y();
|
||||
const QVector3D delta = (xDelta + yDelta) * zoomFactor;
|
||||
|
||||
camera->setPosition(startPosition + delta);
|
||||
return startLookAt + delta;
|
||||
}
|
||||
|
||||
float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float defaultLookAtDistance,
|
||||
const QVector3D &lookAt, float zoomFactor, bool relative)
|
||||
{
|
||||
// Emprically determined divisor for nice zoom
|
||||
float multiplier = 1.f + (distance / 40.f);
|
||||
float newZoomFactor = relative ? qBound(.0001f, zoomFactor * multiplier, 10000.f)
|
||||
: zoomFactor;
|
||||
|
||||
if (qobject_cast<QQuick3DOrthographicCamera *>(camera)) {
|
||||
// Ortho camera we can simply scale
|
||||
camera->setScale(QVector3D(newZoomFactor, newZoomFactor, newZoomFactor));
|
||||
} else if (qobject_cast<QQuick3DPerspectiveCamera *>(camera)) {
|
||||
// Perspective camera is zoomed by moving camera forward or backward while keeping the
|
||||
// look-at point the same
|
||||
const QVector3D lookAtVec = (camera->position() - lookAt).normalized();
|
||||
const float newDistance = defaultLookAtDistance * newZoomFactor;
|
||||
camera->setPosition(lookAt + (lookAtVec * newDistance));
|
||||
}
|
||||
|
||||
return newZoomFactor;
|
||||
}
|
||||
|
||||
// Return value contains new lookAt point (xyz) and zoom factor (w)
|
||||
QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort)
|
||||
{
|
||||
if (!camera)
|
||||
return QVector4D(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D();
|
||||
|
||||
// Get object bounds
|
||||
qreal maxExtent = 200.;
|
||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) {
|
||||
auto targetPriv = QQuick3DObjectPrivate::get(targetObject);
|
||||
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
|
||||
QWindow *window = static_cast<QWindow *>(viewPort->window());
|
||||
if (window) {
|
||||
auto context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
|
||||
if (!context.isNull()) {
|
||||
QSSGBounds3 bounds;
|
||||
auto geometry = qobject_cast<SelectionBoxGeometry *>(modelNode->geometry());
|
||||
if (geometry) {
|
||||
bounds = geometry->bounds();
|
||||
} else {
|
||||
auto bufferManager = context->bufferManager();
|
||||
bounds = renderModel->getModelBounds(bufferManager);
|
||||
}
|
||||
|
||||
QVector3D center = bounds.center();
|
||||
const QVector3D e = bounds.extents();
|
||||
const QVector3D s = targetObject->sceneScale();
|
||||
qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z()));
|
||||
maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z()));
|
||||
maxExtent *= maxScale;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset camera position to default zoom
|
||||
QMatrix4x4 m = camera->sceneTransform();
|
||||
const float *dataPtr(m.data());
|
||||
QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]);
|
||||
newLookVector.normalize();
|
||||
newLookVector *= defaultLookAtDistance;
|
||||
|
||||
camera->setPosition(lookAt + newLookVector);
|
||||
|
||||
// Emprically determined algorithm for nice zoom
|
||||
float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f);
|
||||
|
||||
return QVector4D(lookAt,
|
||||
zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false));
|
||||
}
|
||||
|
||||
void GeneralHelper::delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant &value)
|
||||
{
|
||||
QTimer::singleShot(delay, [obj, property, value]() {
|
||||
obj->setProperty(property.toLatin1().constData(), value);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QUICK3D_MODULE
|
||||
@@ -0,0 +1,80 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
|
||||
#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
|
||||
|
||||
public:
|
||||
GeneralHelper();
|
||||
|
||||
Q_INVOKABLE void requestOverlayUpdate();
|
||||
Q_INVOKABLE QString generateUniqueName(const QString &nameRoot);
|
||||
|
||||
Q_INVOKABLE void orbitCamera(QQuick3DCamera *camera, const QVector3D &startRotation,
|
||||
const QVector3D &lookAtPoint, const QVector3D &pressPos,
|
||||
const QVector3D ¤tPos);
|
||||
Q_INVOKABLE QVector3D panCamera(QQuick3DCamera *camera, const QMatrix4x4 startTransform,
|
||||
const QVector3D &startPosition, const QVector3D &startLookAt,
|
||||
const QVector3D &pressPos, const QVector3D ¤tPos,
|
||||
float zoomFactor);
|
||||
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 void delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant& value);
|
||||
|
||||
signals:
|
||||
void overlayUpdateNeeded();
|
||||
|
||||
private:
|
||||
QTimer m_overlayUpdateTimer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QUICK3D_MODULE
|
||||
@@ -37,7 +37,6 @@ namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
MouseArea3D *MouseArea3D::s_mouseGrab = nullptr;
|
||||
static const qreal s_mouseDragMultiplier = .02;
|
||||
|
||||
MouseArea3D::MouseArea3D(QQuick3DNode *parent)
|
||||
: QQuick3DNode(parent)
|
||||
@@ -124,6 +123,13 @@ void MouseArea3D::setGrabsMouse(bool grabsMouse)
|
||||
return;
|
||||
|
||||
m_grabsMouse = grabsMouse;
|
||||
|
||||
if (!m_grabsMouse && s_mouseGrab == this) {
|
||||
setDragging(false);
|
||||
setHovering(false);
|
||||
s_mouseGrab = nullptr;
|
||||
}
|
||||
|
||||
emit grabsMouseChanged();
|
||||
}
|
||||
|
||||
@@ -133,6 +139,13 @@ void MouseArea3D::setActive(bool active)
|
||||
return;
|
||||
|
||||
m_active = active;
|
||||
|
||||
if (!m_active && s_mouseGrab == this) {
|
||||
setDragging(false);
|
||||
setHovering(false);
|
||||
s_mouseGrab = nullptr;
|
||||
}
|
||||
|
||||
emit activeChanged();
|
||||
}
|
||||
|
||||
@@ -340,7 +353,7 @@ qreal QmlDesigner::Internal::MouseArea3D::getNewRotationAngle(
|
||||
dragDir = (screenDragDir - nodePos).normalized();
|
||||
const QVector3D pressToCurrent = (currentPos - pressPos);
|
||||
float magnitude = QVector3D::dotProduct(pressToCurrent, dragDir);
|
||||
qreal angle = -s_mouseDragMultiplier * qreal(magnitude);
|
||||
qreal angle = -mouseDragMultiplier() * qreal(magnitude);
|
||||
return angle;
|
||||
} else {
|
||||
const QVector3D nodeToPress = (pressPos - nodePos).normalized();
|
||||
@@ -397,7 +410,7 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
|
||||
|
||||
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
|
||||
|
||||
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * s_mouseDragMultiplier);
|
||||
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * mouseDragMultiplier());
|
||||
|
||||
finalAxis.normalize();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class MouseArea3D : public QQuick3DNode
|
||||
Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged)
|
||||
Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
|
||||
Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged)
|
||||
Q_PROPERTY(int active READ active WRITE setActive NOTIFY activeChanged)
|
||||
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
|
||||
Q_PROPERTY(QPointF circlePickArea READ circlePickArea WRITE setCirclePickArea NOTIFY circlePickAreaChanged)
|
||||
Q_PROPERTY(qreal minAngle READ minAngle WRITE setMinAngle NOTIFY minAngleChanged)
|
||||
Q_PROPERTY(QQuick3DNode *pickNode READ pickNode WRITE setPickNode NOTIFY pickNodeChanged)
|
||||
@@ -77,6 +77,8 @@ public:
|
||||
qreal minAngle() const;
|
||||
QQuick3DNode *pickNode() const;
|
||||
|
||||
static qreal mouseDragMultiplier() { return .02; }
|
||||
|
||||
public slots:
|
||||
void setView3D(QQuick3DViewport *view3D);
|
||||
void setGrabsMouse(bool grabsMouse);
|
||||
@@ -157,7 +159,7 @@ private:
|
||||
QVector3D getMousePosInPlane(const QPointF &mousePosInView) const;
|
||||
|
||||
static MouseArea3D *s_mouseGrab;
|
||||
bool m_grabsMouse;
|
||||
bool m_grabsMouse = false;
|
||||
QVector3D m_mousePosInPlane;
|
||||
QPointF m_circlePickArea;
|
||||
qreal m_minAngle = 0.;
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
|
||||
#include "selectionboxgeometry.h"
|
||||
|
||||
#include <QtQuick3DRuntimeRender/private/qssgrendergeometry_p.h>
|
||||
#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
|
||||
#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
|
||||
#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
|
||||
#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 {
|
||||
|
||||
SelectionBoxGeometry::SelectionBoxGeometry()
|
||||
: QQuick3DGeometry()
|
||||
{
|
||||
}
|
||||
|
||||
SelectionBoxGeometry::~SelectionBoxGeometry()
|
||||
{
|
||||
for (auto &connection : qAsConst(m_connections))
|
||||
QObject::disconnect(connection);
|
||||
m_connections.clear();
|
||||
}
|
||||
|
||||
QQuick3DNode *SelectionBoxGeometry::targetNode() const
|
||||
{
|
||||
return m_targetNode;
|
||||
}
|
||||
|
||||
QQuick3DNode *SelectionBoxGeometry::rootNode() const
|
||||
{
|
||||
return m_rootNode;
|
||||
}
|
||||
|
||||
QQuick3DViewport *SelectionBoxGeometry::view3D() const
|
||||
{
|
||||
return m_view3D;
|
||||
}
|
||||
|
||||
bool QmlDesigner::Internal::SelectionBoxGeometry::isEmpty() const
|
||||
{
|
||||
return m_isEmpty;
|
||||
}
|
||||
|
||||
QSSGBounds3 SelectionBoxGeometry::bounds() const
|
||||
{
|
||||
return m_bounds;
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::setTargetNode(QQuick3DNode *targetNode)
|
||||
{
|
||||
if (m_targetNode == targetNode)
|
||||
return;
|
||||
|
||||
if (m_targetNode)
|
||||
m_targetNode->disconnect(this);
|
||||
m_targetNode = targetNode;
|
||||
|
||||
if (auto model = qobject_cast<QQuick3DModel *>(m_targetNode)) {
|
||||
QObject::connect(model, &QQuick3DModel::sourceChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
QObject::connect(model, &QQuick3DModel::geometryChanged,
|
||||
this, &SelectionBoxGeometry::update, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
emit targetNodeChanged();
|
||||
update();
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::setRootNode(QQuick3DNode *rootNode)
|
||||
{
|
||||
if (m_rootNode == rootNode)
|
||||
return;
|
||||
|
||||
m_rootNode = rootNode;
|
||||
|
||||
emit rootNodeChanged();
|
||||
update();
|
||||
}
|
||||
|
||||
void SelectionBoxGeometry::setView3D(QQuick3DViewport *view)
|
||||
{
|
||||
if (m_view3D == view)
|
||||
return;
|
||||
|
||||
m_view3D = view;
|
||||
|
||||
emit view3DChanged();
|
||||
update();
|
||||
}
|
||||
|
||||
QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphObject *node)
|
||||
{
|
||||
node = QQuick3DGeometry::updateSpatialNode(node);
|
||||
QSSGRenderGeometry *geometry = static_cast<QSSGRenderGeometry *>(node);
|
||||
|
||||
geometry->clear();
|
||||
for (auto &connection : qAsConst(m_connections))
|
||||
QObject::disconnect(connection);
|
||||
m_connections.clear();
|
||||
|
||||
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);
|
||||
|
||||
if (m_targetNode) {
|
||||
auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode);
|
||||
auto targetPriv = QQuick3DObjectPrivate::get(m_targetNode);
|
||||
auto rootRN = static_cast<QSSGRenderNode *>(rootPriv->spatialNode);
|
||||
auto targetRN = static_cast<QSSGRenderNode *>(targetPriv->spatialNode);
|
||||
if (rootRN && targetRN) {
|
||||
// Explicitly set local transform of root node to target node parent's global transform
|
||||
// to avoid having to reparent the selection box. This has to be done directly on render
|
||||
// nodes.
|
||||
targetRN->parent->calculateGlobalVariables();
|
||||
QMatrix4x4 m = targetRN->parent->globalTransform;
|
||||
rootRN->localTransform = m;
|
||||
rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty);
|
||||
rootRN->calculateGlobalVariables();
|
||||
}
|
||||
getBounds(m_targetNode, vertexData, indexData, minBounds, maxBounds, QMatrix4x4());
|
||||
} else {
|
||||
// Fill some dummy data so geometry won't get rejected
|
||||
appendVertexData(vertexData, indexData, minBounds, maxBounds);
|
||||
}
|
||||
|
||||
geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0,
|
||||
QSSGRenderGeometry::Attribute::ComponentType::F32Type);
|
||||
geometry->addAttribute(QSSGRenderGeometry::Attribute::IndexSemantic, 0,
|
||||
QSSGRenderGeometry::Attribute::ComponentType::U16Type);
|
||||
geometry->setStride(12);
|
||||
geometry->setVertexData(vertexData);
|
||||
geometry->setIndexData(indexData);
|
||||
geometry->setPrimitiveType(QSSGRenderGeometry::Lines);
|
||||
geometry->setBounds(minBounds, maxBounds);
|
||||
|
||||
m_bounds = QSSGBounds3(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::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
|
||||
quint16 indexAdd = quint16(initialVertexSize / 12);
|
||||
vertexData.resize(initialVertexSize + vertexSize);
|
||||
const int indexSize = int(sizeof(quint16)) * 12 * 2; // 12 lines, 2 vert/line
|
||||
indexData.resize(initialIndexSize + indexSize);
|
||||
|
||||
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();
|
||||
|
||||
*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 + indexAdd; *indexPtr++ = 4 + indexAdd;
|
||||
*indexPtr++ = 1 + indexAdd; *indexPtr++ = 5 + indexAdd;
|
||||
*indexPtr++ = 2 + indexAdd; *indexPtr++ = 6 + indexAdd;
|
||||
*indexPtr++ = 3 + indexAdd; *indexPtr++ = 7 + indexAdd;
|
||||
|
||||
*indexPtr++ = 4 + indexAdd; *indexPtr++ = 5 + indexAdd;
|
||||
*indexPtr++ = 5 + indexAdd; *indexPtr++ = 6 + indexAdd;
|
||||
*indexPtr++ = 6 + indexAdd; *indexPtr++ = 7 + indexAdd;
|
||||
*indexPtr++ = 7 + indexAdd; *indexPtr++ = 4 + indexAdd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // QUICK3D_MODULE
|
||||
@@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
|
||||
#include <QtQuick3D/private/qquick3dnode_p.h>
|
||||
#include <QtQuick3D/private/qquick3dgeometry_p.h>
|
||||
#include <QtQuick3D/private/qquick3dviewport_p.h>
|
||||
#include <QtQuick3DUtils/private/qssgbounds3_p.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
|
||||
class SelectionBoxGeometry : public QQuick3DGeometry
|
||||
{
|
||||
Q_OBJECT
|
||||
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();
|
||||
~SelectionBoxGeometry() override;
|
||||
|
||||
QQuick3DNode *targetNode() const;
|
||||
QQuick3DNode *rootNode() const;
|
||||
QQuick3DViewport *view3D() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
QSSGBounds3 bounds() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setTargetNode(QQuick3DNode *targetNode);
|
||||
void setRootNode(QQuick3DNode *rootNode);
|
||||
void setView3D(QQuick3DViewport *view);
|
||||
|
||||
Q_SIGNALS:
|
||||
void targetNodeChanged();
|
||||
void rootNodeChanged();
|
||||
void view3DChanged();
|
||||
void isEmptyChanged();
|
||||
|
||||
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,
|
||||
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;
|
||||
QSSGBounds3 m_bounds;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
QML_DECLARE_TYPE(QmlDesigner::Internal::SelectionBoxGeometry)
|
||||
|
||||
#endif // QUICK3D_MODULE
|
||||
@@ -62,10 +62,11 @@
|
||||
#include <drop3dlibraryitemcommand.h>
|
||||
|
||||
#include "dummycontextobject.h"
|
||||
#include "../editor3d/cameracontrolhelper.h"
|
||||
#include "../editor3d/generalhelper.h"
|
||||
#include "../editor3d/mousearea3d.h"
|
||||
#include "../editor3d/camerageometry.h"
|
||||
#include "../editor3d/gridgeometry.h"
|
||||
#include "../editor3d/selectionboxgeometry.h"
|
||||
|
||||
#include <designersupportdelegate.h>
|
||||
|
||||
@@ -104,13 +105,13 @@ bool Qt5InformationNodeInstanceServer::eventFilter(QObject *, QEvent *event)
|
||||
|
||||
QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
{
|
||||
auto helper = new QmlDesigner::Internal::CameraControlHelper();
|
||||
engine->rootContext()->setContextProperty("designStudioNativeCameraControlHelper", helper);
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
auto helper = new QmlDesigner::Internal::GeneralHelper();
|
||||
engine->rootContext()->setContextProperty("_generalHelper", helper);
|
||||
qmlRegisterType<QmlDesigner::Internal::MouseArea3D>("MouseArea3D", 1, 0, "MouseArea3D");
|
||||
qmlRegisterType<QmlDesigner::Internal::CameraGeometry>("CameraGeometry", 1, 0, "CameraGeometry");
|
||||
qmlRegisterType<QmlDesigner::Internal::GridGeometry>("GridGeometry", 1, 0, "GridGeometry");
|
||||
qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry");
|
||||
#endif
|
||||
|
||||
QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"));
|
||||
@@ -136,7 +137,10 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine)
|
||||
surfaceFormat.setVersion(4, 1);
|
||||
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
|
||||
window->setFormat(surfaceFormat);
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
helper->setParent(window);
|
||||
#endif
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -336,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;
|
||||
@@ -599,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
|
||||
|
||||
@@ -56,17 +56,7 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo
|
||||
InstanceContainer::NodeFlags flags)
|
||||
{
|
||||
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (quick3DNode()) {
|
||||
QQuick3DObject::Type nodeType = quick3DNode()->type();
|
||||
if (nodeType == QQuick3DObject::Camera || nodeType == QQuick3DObject::Light
|
||||
|| nodeType == QQuick3DObject::Model || nodeType == QQuick3DObject::Image
|
||||
|| nodeType == QQuick3DObject::Text) {
|
||||
setPropertyVariant("pickable", true); // allow 3D objects to receive mouse clicks
|
||||
}
|
||||
}
|
||||
#endif
|
||||
setPickable(true, true, false);
|
||||
}
|
||||
|
||||
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
||||
@@ -83,6 +73,48 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildren)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
auto node = quick3DNode();
|
||||
if (node) {
|
||||
QQuick3DObject::Type nodeType = node->type();
|
||||
bool parentHidden = false;
|
||||
if (checkParent) {
|
||||
// First check if any parent node is already hidden. Never set pickable on that case.
|
||||
auto parentNode = node->parentNode();
|
||||
while (parentNode && !parentHidden) {
|
||||
parentHidden = QQuick3DNodePrivate::get(parentNode)->m_isHiddenInEditor;
|
||||
parentNode = parentNode->parentNode();
|
||||
}
|
||||
|
||||
}
|
||||
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)) {
|
||||
// Don't override explicit block in children
|
||||
if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor)
|
||||
quick3dInstance->setPickable(enable, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeType == QQuick3DObject::Model)
|
||||
setPropertyVariant("pickable", enable); // allow 3D objects to receive mouse clicks
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object)
|
||||
{
|
||||
Pointer instance(new Quick3DNodeInstance(object));
|
||||
@@ -94,8 +126,12 @@ void Quick3DNodeInstance::setHideInEditor(bool b)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
QQuick3DNodePrivate *privateNode = QQuick3DNodePrivate::get(quick3DNode());
|
||||
if (privateNode)
|
||||
if (privateNode) {
|
||||
privateNode->setIsHiddenInEditor(b);
|
||||
|
||||
// Hidden objects should not be pickable
|
||||
setPickable(!b, true, true);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(b)
|
||||
#endif
|
||||
|
||||
@@ -53,6 +53,7 @@ protected:
|
||||
private:
|
||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||
QQuick3DNode *quick3DNode() const;
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildren);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace Internal {
|
||||
class GraphicsObjectNodeInstance;
|
||||
class QmlStateNodeInstance;
|
||||
class QuickItemNodeInstance;
|
||||
class Quick3DNodeInstance;
|
||||
}
|
||||
|
||||
class ServerNodeInstance
|
||||
@@ -82,6 +83,7 @@ class ServerNodeInstance
|
||||
friend class QmlDesigner::Internal::ObjectNodeInstance;
|
||||
friend class QmlDesigner::Internal::QmlPropertyChangesNodeInstance;
|
||||
friend class QmlDesigner::Internal::QmlStateNodeInstance;
|
||||
friend class QmlDesigner::Internal::Quick3DNodeInstance;
|
||||
|
||||
public:
|
||||
enum ComponentWrap {
|
||||
|
||||
Reference in New Issue
Block a user