diff options
author | Thomas Hartmann <thomas.hartmann@qt.io> | 2022-02-15 16:12:13 +0100 |
---|---|---|
committer | Thomas Hartmann <thomas.hartmann@qt.io> | 2022-02-22 10:43:49 +0000 |
commit | 3f078ee89d32857f99b1805274d74cd3dd8572ba (patch) | |
tree | fc7a604c2ff086b43583d6440a3204bd5e0d7ad9 | |
parent | 298765c2628d4f8b90ba7e5ca4eb3119643a777b (diff) |
QmlDesigner: Add preview of pure 3D component in form editor
If the root node is a 3D node we show a preview similar to
the state preview in the form editor. The size of the preview
is hard coded as (640, 480).
Change-Id: If7f96522b093c17422fa38102bffe11ede016063
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
12 files changed, 144 insertions, 7 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index c97de4636a..908e06ea50 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -398,6 +398,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QQuickItemPrivate *pItem = QQuickItemPrivate::get(item); + const bool rootIs3dNode = rootNodeInstance().isSubclassOf("QQuick3DNode"); + const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); if (renderEffects) { @@ -426,6 +428,9 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QRectF renderBoundingRect; if (instance.isValid()) renderBoundingRect = instance.boundingRect(); + + else if (rootIs3dNode) + renderBoundingRect = item->boundingRect(); else renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 6fe0807d01..ae33334372 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -133,6 +133,14 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() nodeInstanceClient()->synchronizeWithClientProcess(); } + if (rootNodeInstance().isSubclassOf("QQuick3DNode") && rootNodeInstance().contentItem() + && DesignerSupport::isDirty(rootNodeInstance().contentItem(), + DesignerSupport::ContentUpdateMask) + && nodeInstanceClient()->bytesToWrite() < 10000) { + Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); + nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); + } + inFunction = false; } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index ec0beb521d..0c70ccca8f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -55,6 +55,8 @@ namespace QmlDesigner { namespace Internal { +const QRectF preview3dBoundingRect(0, 0, 640, 480); + Quick3DNodeInstance::Quick3DNodeInstance(QObject *node) : ObjectNodeInstance(node) { @@ -97,7 +99,7 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // In case this is the scene root, we need to create a dummy View3D for the scene // in preview puppets - if (instanceId() == 0 && nodeInstanceServer()->isPreviewServer()) { + if (instanceId() == 0 && (!nodeInstanceServer()->isInformationServer())) { auto helper = new QmlDesigner::Internal::GeneralHelper(); engine()->rootContext()->setContextProperty("_generalHelper", helper); @@ -111,8 +113,8 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo nodeInstanceServer()->setRootItem(m_dummyRootView); } -#endif -#endif +#endif // QT_VERSION +#endif // QUICK3D_MODULE ObjectNodeInstance::initialize(objectNodeInstance, flags); } @@ -122,7 +124,7 @@ QImage Quick3DNodeInstance::renderImage() const if (!isRootNodeInstance() || !m_dummyRootView) return {}; - QSize size(640, 480); + QSize size = preview3dBoundingRect.size().toSize(); nodeInstanceServer()->quickWindow()->resize(size); m_dummyRootView->setSize(size); @@ -190,13 +192,37 @@ bool Quick3DNodeInstance::isRenderable() const return m_dummyRootView; } +bool Quick3DNodeInstance::hasContent() const +{ + return true; +} + QRectF Quick3DNodeInstance::boundingRect() const { + //The information server has no m_dummyRootView therefore we use the hardcoded value + if (nodeInstanceServer()->isInformationServer()) + return preview3dBoundingRect; + if (m_dummyRootView) return m_dummyRootView->boundingRect(); return ObjectNodeInstance::boundingRect(); } +QRectF Quick3DNodeInstance::contentItemBoundingBox() const +{ + return boundingRect(); +} + +QPointF Quick3DNodeInstance::position() const +{ + return QPointF(0, 0); +} + +QSizeF Quick3DNodeInstance::size() const +{ + return boundingRect().size(); +} + QList<ServerNodeInstance> Quick3DNodeInstance::stateInstances() const { QList<ServerNodeInstance> instanceList; @@ -212,6 +238,11 @@ QList<ServerNodeInstance> Quick3DNodeInstance::stateInstances() const return instanceList; } +QQuickItem *Quick3DNodeInstance::contentItem() const +{ + return m_dummyRootView; +} + Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const { return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 322762af26..b3b4f78972 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -51,10 +51,16 @@ public: QImage renderPreviewImage(const QSize &previewImageSize) const override; bool isRenderable() const override; + bool hasContent() const override; QRectF boundingRect() const override; + QRectF contentItemBoundingBox() const override; + QPointF position() const override; + QSizeF size() const override; QList<ServerNodeInstance> stateInstances() const override; + QQuickItem *contentItem() const override; + protected: explicit Quick3DNodeInstance(QObject *node); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 9803f6d79e..f6c7f94bca 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -162,6 +162,11 @@ bool ServerNodeInstance::isComponentWrap() const return m_nodeInstance->isComponentWrap(); } +QQuickItem *ServerNodeInstance::contentItem() const +{ + return m_nodeInstance->contentItem(); +} + void ServerNodeInstance::updateDirtyNodeRecursive() { m_nodeInstance->updateAllDirtyNodesRecursive(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 0e5ca3547d..bc79cb4f68 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -188,6 +188,8 @@ public: bool isComponentWrap() const; + QQuickItem *contentItem() const; + private: // functions ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp index 4f000e1295..95d92e68fe 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -2226,4 +2226,39 @@ void FormEditorFlowWildcardItem::paint(QPainter *painter, const QStyleOptionGrap FormEditorFlowDecisionItem::paint(painter, option, widget); } +void FormEditor3dPreview::updateGeometry() +{ + prepareGeometryChange(); + + m_selectionBoundingRect = qmlItemNode().instanceBoundingRect().adjusted(0, 0, 1., 1.); + m_boundingRect = qmlItemNode().instanceBoundingRect(); + m_paintedBoundingRect = m_boundingRect; + setTransform(QTransform()); + +} + +QPointF FormEditor3dPreview::instancePosition() const +{ + return QPointF(0, 0); +} + +void FormEditor3dPreview::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + if (!painter->isActive()) + return; + + painter->save(); + + bool showPlaceHolder = qmlItemNode().instanceIsRenderPixmapNull(); + + if (showPlaceHolder) + paintPlaceHolderForInvisbleItem(painter); + else + painter->drawPixmap(m_boundingRect.topLeft(), qmlItemNode().instanceRenderPixmap()); + + painter->restore(); +} + } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h index 2213f42a66..a9e70145e2 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h @@ -171,6 +171,23 @@ private: QPointF m_oldPos; }; +class FormEditor3dPreview : public FormEditorItem +{ + friend FormEditorScene; + +public: + void updateGeometry() override; + QPointF instancePosition() const override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; + +protected: + FormEditor3dPreview(const QmlItemNode &qmlItemNode, FormEditorScene *scene) + : FormEditorItem(qmlItemNode, scene) + { + setHighlightBoundingRect(true); + } +}; + class FormEditorFlowActionItem : public FormEditorItem { friend FormEditorScene; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp index bbc1f283e1..dea52631d8 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp @@ -173,7 +173,9 @@ FormEditorItem *FormEditorScene::addFormEditorItem(const QmlItemNode &qmlItemNod { FormEditorItem *formEditorItem = nullptr; - if (type == Flow) + if (type == Preview3d) + formEditorItem = new FormEditor3dPreview(qmlItemNode, this); + else if (type == Flow) formEditorItem = new FormEditorFlowItem(qmlItemNode, this); else if (type == FlowAction) formEditorItem = new FormEditorFlowActionItem(qmlItemNode, this); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h index 070d587776..2d15af77a2 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h @@ -58,7 +58,8 @@ public: FlowAction, FlowTransition, FlowDecision, - FlowWildcard + FlowWildcard, + Preview3d }; FormEditorScene(FormEditorWidget *widget, FormEditorView *editorView); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index c2d63d2183..e07c17cb04 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -46,6 +46,7 @@ #include <nodelistproperty.h> #include <nodemetainfo.h> #include <rewriterview.h> +#include <qml3dnode.h> #include <zoomaction.h> #include <coreplugin/icore.h> @@ -655,6 +656,14 @@ static void updateTransitions(FormEditorScene *scene, const QmlItemNode &qmlItem void FormEditorView::instancesCompleted(const QVector<ModelNode> &completedNodeList) { + if (Qml3DNode::isValidQml3DNode(rootModelNode())) { + if (completedNodeList.contains(rootModelNode())) { + FormEditorItem *item = scene()->itemForQmlItemNode(rootModelNode()); + if (item) + scene()->synchronizeTransformation(item); + } + } + const bool isFlow = rootModelNode().isValid() && QmlItemNode(rootModelNode()).isFlowView(); QList<FormEditorItem*> itemNodeList; for (const ModelNode &node : completedNodeList) { @@ -724,6 +733,10 @@ void FormEditorView::instancesRenderImageChanged(const QVector<ModelNode> &nodeL if (QmlItemNode::isValidQmlItemNode(node)) if (FormEditorItem *item = scene()->itemForQmlItemNode(QmlItemNode(node))) item->update(); + if (Qml3DNode::isValidQml3DNode(node)) { + if (FormEditorItem *item = scene()->itemForQmlItemNode(node)) + item->update(); + } } } @@ -795,6 +808,9 @@ void FormEditorView::setupFormEditorWidget() if (QmlItemNode::isValidQmlItemNode(rootModelNode())) setupFormEditorItemTree(rootModelNode()); + if (Qml3DNode::isValidQml3DNode(rootModelNode())) + setupFormEditor3DView(); + m_formEditorWidget->initialize(); if (!rewriterView()->errors().isEmpty()) @@ -903,7 +919,8 @@ void FormEditorView::checkRootModelNode() QTC_ASSERT(rootModelNode().isValid(), return); - if (!rootModelNode().metaInfo().isGraphicalItem()) + if (!rootModelNode().metaInfo().isGraphicalItem() + && !Qml3DNode::isValidQml3DNode(rootModelNode())) m_formEditorWidget->showErrorMessageBox( {DocumentMessage(tr("%1 is not supported as the root element by Form Editor.") .arg(rootModelNode().simplifiedTypeName()))}); @@ -911,6 +928,13 @@ void FormEditorView::checkRootModelNode() m_formEditorWidget->hideErrorMessageBox(); } +void FormEditorView::setupFormEditor3DView() +{ + m_scene->addFormEditorItem(rootModelNode(), FormEditorScene::Preview3d); + FormEditorItem *item = m_scene->itemForQmlItemNode(rootModelNode()); + item->updateGeometry(); +} + void FormEditorView::reset() { QTimer::singleShot(200, this, &FormEditorView::delayedReset); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h index 1db4ae1b4d..c15f73498b 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -151,6 +151,7 @@ private: void resetNodeInstanceView(); void addOrRemoveFormEditorItem(const ModelNode &node); void checkRootModelNode(); + void setupFormEditor3DView(); QPointer<FormEditorWidget> m_formEditorWidget; QPointer<FormEditorScene> m_scene; |