diff options
author | Miikka Heikkinen <[email protected]> | 2024-05-23 12:34:57 +0300 |
---|---|---|
committer | Miikka Heikkinen <[email protected]> | 2024-05-23 10:48:44 +0000 |
commit | 8bfe8056459d264cf2b83de0269f7034eb2f6b2b (patch) | |
tree | 34e670b4ae6d8a9199c401a5b8ac73982b18de65 | |
parent | d3452545796bdf4ee87daf5b24b42ecf7d6036af (diff) |
QmlDesigner: Allow rotation of 3D import preview
3D import preview can now be rotated using left mouse button and
dragging the preview image. This causes camera to orbit around the
previewed model, similar to rotation to 3D edit view orbit camera.
Close/Cancel button logic was also improved.
Fixes: QDS-12795
Change-Id: I0c7d1ad28f8fe779b9bedc4bf76be704078d91a6
Reviewed-by: Mahmoud Badri <[email protected]>
10 files changed, 129 insertions, 36 deletions
diff --git a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h index 06df0f79754..206fb760956 100644 --- a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h +++ b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h @@ -56,7 +56,8 @@ enum class View3DActionType { EditCameraMove, EditCameraStopAllMoves, SetLastSceneEnvData, - Import3dUpdatePreviewImage + Import3dUpdatePreviewImage, + Import3dRotatePreviewModel }; constexpr bool isNanotraceEnabled() diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp index 87014cbe603..608bf42eb36 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp @@ -5,6 +5,7 @@ #include <QImage> #include <QLinearGradient> +#include <QMouseEvent> #include <QPainter> namespace QmlDesigner { @@ -52,5 +53,30 @@ void Import3dCanvas::resizeEvent(QResizeEvent *) emit requestImageUpdate(); } +void Import3dCanvas::mousePressEvent(QMouseEvent *e) +{ + if (e->buttons() == Qt::LeftButton) + m_dragPos = e->position(); + else + m_dragPos = {}; +} + +void Import3dCanvas::mouseReleaseEvent(QMouseEvent *) +{ + m_dragPos = {}; +} + +void Import3dCanvas::mouseMoveEvent(QMouseEvent *e) +{ + if (m_dragPos.isNull()) + return; + + const QPointF curPos = e->position(); + const QPointF delta = curPos - m_dragPos; + + m_dragPos = curPos; + + emit requestRotation(delta); +} } diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h index 22bcc04d70f..72fb19acffc 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h +++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h @@ -4,7 +4,7 @@ #include <QEvent> #include <QImage> -#include <QPointer> +#include <QPointF> #include <QWidget> namespace QmlDesigner { @@ -20,13 +20,18 @@ public: signals: void requestImageUpdate(); + void requestRotation(const QPointF &delta); protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; private: QImage m_image; + QPointF m_dragPos; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 4e49cd2b807..8af81a7b82e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -221,6 +221,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( this, &ItemLibraryAssetImportDialog::updateUi); connect(canvas(), &Import3dCanvas::requestImageUpdate, this, &ItemLibraryAssetImportDialog::onRequestImageUpdate); + connect(canvas(), &Import3dCanvas::requestRotation, + this, &ItemLibraryAssetImportDialog::onRequestRotation); connect(&m_importer, &ItemLibraryAssetImporter::errorReported, this, &ItemLibraryAssetImportDialog::addError); @@ -856,9 +858,10 @@ Rectangle { width: %1 height: %2 - property string sceneModelName: "%3" + property alias sceneNode: sceneNode property alias view3d: view3d property string extents + property string sceneModelName: "%3" gradient: Gradient { GradientStop { position: 1.0; color: "#222222" } @@ -877,9 +880,9 @@ Rectangle { PerspectiveCamera { id: viewCamera - z: 600 - y: 600 x: 600 + y: 600 + z: 600 eulerRotation.x: -45 eulerRotation.y: -45 clipFar: 100000 @@ -889,6 +892,10 @@ Rectangle { DirectionalLight { rotation: viewCamera.rotation } + + Node { + id: sceneNode + } } Text { @@ -1041,7 +1048,8 @@ void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, ui->acceptButton->setEnabled(true); ui->importButton->setEnabled(true); - addInfo(tr("Generating import preview for %1.").arg(compName)); + addInfo(tr("Import is ready for preview.")); + addInfo(tr("Click \"Accept\" to finish the import or adjust options an click \"Import\" to import again.")); } void ItemLibraryAssetImportDialog::onRequestImageUpdate() @@ -1050,6 +1058,12 @@ void ItemLibraryAssetImportDialog::onRequestImageUpdate() m_nodeInstanceView->view3DAction(View3DActionType::Import3dUpdatePreviewImage, canvas()->size()); } +void ItemLibraryAssetImportDialog::onRequestRotation(const QPointF &delta) +{ + if (m_nodeInstanceView) + m_nodeInstanceView->view3DAction(View3DActionType::Import3dRotatePreviewModel, delta); +} + void ItemLibraryAssetImportDialog::onImportNearlyFinished() { // Canceling import is no longer doable @@ -1063,19 +1077,29 @@ void ItemLibraryAssetImportDialog::onImportFinished() QString interruptStr = tr("Import interrupted."); addError(interruptStr); setImportProgress(0, interruptStr); + if (m_explicitClose) + QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose); } else { QString doneStr = tr("Import done."); addInfo(doneStr); setImportProgress(100, doneStr); if (m_closeOnFinish) { // Add small delay to allow user to visually confirm import finishing - QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::onClose); + QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose); } } } void ItemLibraryAssetImportDialog::onClose() { + ui->importButton->setEnabled(false); + ui->acceptButton->setEnabled(false); + m_explicitClose = true; + doClose(); +} + +void ItemLibraryAssetImportDialog::doClose() +{ if (m_importer.isImporting()) { addInfo(tr("Canceling import.")); m_importer.cancelImport(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h index efbd189c2fd..635be6db696 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h @@ -68,9 +68,11 @@ private: void setImportProgress(int value, const QString &text); void onImportReadyForPreview(const QString &path, const QString &compName); void onRequestImageUpdate(); + void onRequestRotation(const QPointF &delta); void onImportNearlyFinished(); void onImportFinished(); void onClose(); + void doClose(); void onAccept(); void toggleAdvanced(); @@ -116,5 +118,6 @@ private: OptionsData m_advancedData; bool m_advancedMode = false; int m_dialogHeight = 350; + bool m_explicitClose = false; }; } diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp index 1ccea6049c8..3baf91c1464 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp @@ -462,17 +462,19 @@ QVector4D GeneralHelper::approachNode( // a selection box for bound calculations to work. This is used to focus the view for // various preview image generations, where doing things asynchronously is not good // and recalculating bounds for every frame is not a problem. -QVector3D GeneralHelper::calculateNodeBoundsAndFocusCamera( - QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, - float defaultLookAtDistance, bool closeUp) +void GeneralHelper::calculateBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, + float defaultLookAtDistance, + bool closeUp, QVector3D &lookAt, + QVector3D &extents) { QVector3D minBounds; QVector3D maxBounds; getBounds(viewPort, node, minBounds, maxBounds); - QVector3D extents = maxBounds - minBounds; - QVector3D lookAt = minBounds + (extents / 2.f); + extents = maxBounds - minBounds; + lookAt = minBounds + (extents / 2.f); float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x()) + qreal(extents.y()) * qreal(extents.y()) + qreal(extents.z()) * qreal(extents.z())); @@ -506,8 +508,17 @@ QVector3D GeneralHelper::calculateNodeBoundsAndFocusCamera( perspectiveCamera->setClipFar(maxDist * 1.01); } } +} - return extents; +void GeneralHelper::calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, + float defaultLookAtDistance, + bool closeUp) +{ + QVector3D extents; + QVector3D lookAt; + calculateBoundsAndFocusCamera(camera, node, viewPort, defaultLookAtDistance, closeUp, + lookAt, extents); } // Aligns any cameras found in nodes list to a camera. diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h index 996a06488f4..f1b57f4122f 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h @@ -72,11 +72,12 @@ public: bool closeUp = false); Q_INVOKABLE QVector4D approachNode(QQuick3DCamera *camera, float defaultLookAtDistance, QObject *node, QQuick3DViewport *viewPort); - Q_INVOKABLE QVector3D calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, - QQuick3DNode *node, - QQuick3DViewport *viewPort, - float defaultLookAtDistance, - bool closeUp); + void calculateBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, float defaultLookAtDistance, + bool closeUp, QVector3D &lookAt, QVector3D &extents); + Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, + float defaultLookAtDistance, bool closeUp); Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes); Q_INVOKABLE QVector4D alignView(QQuick3DCamera *camera, const QVariant &nodes, const QVector3D &lookAtPoint, float defaultLookAtDistance); diff --git a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserver.h index 65542dedc25..09c87b3af92 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserver.h +++ b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserver.h @@ -258,6 +258,7 @@ protected: void setRenderTimerInterval(int timerInterval); int renderTimerInterval() const; void setSlowRenderTimerInterval(int timerInterval); + TimerMode timerMode() const { return m_timerMode; } virtual void initializeView() = 0; virtual void initializeAuxiliaryViews(); diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp index b5afa949ec2..5d45a881af5 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp @@ -68,6 +68,19 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc } break; } + case View3DActionType::Import3dRotatePreviewModel: { + QObject *obj = rootItem(); + QQmlProperty sceneNodeProp(obj, "sceneNode", context()); + auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>(); + if (sceneNode) { + QPointF delta = command.value().toPointF(); + m_generalHelper->orbitCamera(m_view3D->camera(), m_view3D->camera()->eulerRotation(), + m_lookAt, {}, {float(delta.x()), float(delta.y()), 0.f}); + m_keepRendering = true; + startRenderTimer(); + } + break; + } default: break; } @@ -75,12 +88,10 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc void Qt5Import3dNodeInstanceServer::startRenderTimer() { - if (timerId() != 0) - killTimer(timerId()); - - int timerId = startTimer(renderTimerInterval()); + if (m_keepRendering && timerMode() == TimerMode::NormalTimer) + return; - setTimerId(timerId); + NodeInstanceServer::startRenderTimer(); } void Qt5Import3dNodeInstanceServer::cleanup() @@ -126,24 +137,28 @@ void Qt5Import3dNodeInstanceServer::render() m_view3D = qobject_cast<QQuick3DViewport *>(viewObj); if (m_view3D) { QQmlProperty sceneModelNameProp(obj, "sceneModelName", context()); - QString sceneModelName = sceneModelNameProp.read().toString(); - QFileInfo fi(fileUrl().toLocalFile()); - QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml"; - QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous); - m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context())); - if (m_previewNode) { - engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership); - m_previewNode->setParent(m_view3D); - m_view3D->setImportScene(m_previewNode); + QQmlProperty sceneNodeProp(obj, "sceneNode", context()); + auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>(); + if (sceneNode) { + QString sceneModelName = sceneModelNameProp.read().toString(); + QFileInfo fi(fileUrl().toLocalFile()); + QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml"; + QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous); + m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context())); + if (m_previewNode) { + engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership); + m_previewNode->setParentItem(sceneNode); + m_previewNode->setParent(sceneNode); + } } } } // Render scene once to ensure geometries are intialized so bounds calculations work correctly if (m_renderCount == 2 && m_view3D) { - QVector3D extents = - m_generalHelper->calculateNodeBoundsAndFocusCamera(m_view3D->camera(), m_previewNode, - m_view3D, 1040, false); + QVector3D extents; + m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), m_previewNode, + m_view3D, 1050, false, m_lookAt, extents); auto getExtentStr = [&extents](int idx) -> QString { int prec = 0; float val = extents[idx]; @@ -176,7 +191,11 @@ void Qt5Import3dNodeInstanceServer::render() nodeInstanceClient()->handlePuppetToCreatorCommand( {PuppetToCreatorCommand::Import3DPreviewImage, QVariant::fromValue(imgContainer)}); - slowDownRenderTimer(); // No more renders needed for now + + if (!m_keepRendering) + slowDownRenderTimer(); + + m_keepRendering = false; } #else slowDownRenderTimer(); diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h index bc3506ea3c0..a68401ef9fd 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h @@ -35,11 +35,13 @@ private: void cleanup(); int m_renderCount = 0; + bool m_keepRendering = false; #ifdef QUICK3D_MODULE QQuick3DViewport *m_view3D = nullptr; Internal::GeneralHelper *m_generalHelper = nullptr; QQuick3DNode *m_previewNode = nullptr; + QVector3D m_lookAt; #endif }; |