aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hartmann <thomas.hartmann@qt.io>2022-02-15 16:12:13 +0100
committerThomas Hartmann <thomas.hartmann@qt.io>2022-02-22 10:43:49 +0000
commit3f078ee89d32857f99b1805274d74cd3dd8572ba (patch)
treefc7a604c2ff086b43583d6440a3204bd5e0d7ad9
parent298765c2628d4f8b90ba7e5ca4eb3119643a777b (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>
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp5
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp8
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp39
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp5
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp35
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.h17
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp4
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorscene.h3
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp26
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.h1
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;