forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -398,6 +398,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item)
|
|||||||
|
|
||||||
QQuickItemPrivate *pItem = QQuickItemPrivate::get(item);
|
QQuickItemPrivate *pItem = QQuickItemPrivate::get(item);
|
||||||
|
|
||||||
|
const bool rootIs3dNode = rootNodeInstance().isSubclassOf("QQuick3DNode");
|
||||||
|
|
||||||
const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS");
|
const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS");
|
||||||
|
|
||||||
if (renderEffects) {
|
if (renderEffects) {
|
||||||
@@ -426,6 +428,9 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item)
|
|||||||
QRectF renderBoundingRect;
|
QRectF renderBoundingRect;
|
||||||
if (instance.isValid())
|
if (instance.isValid())
|
||||||
renderBoundingRect = instance.boundingRect();
|
renderBoundingRect = instance.boundingRect();
|
||||||
|
|
||||||
|
else if (rootIs3dNode)
|
||||||
|
renderBoundingRect = item->boundingRect();
|
||||||
else
|
else
|
||||||
renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item);
|
renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item);
|
||||||
|
|
||||||
|
@@ -133,6 +133,14 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
|||||||
nodeInstanceClient()->synchronizeWithClientProcess();
|
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;
|
inFunction = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,8 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
const QRectF preview3dBoundingRect(0, 0, 640, 480);
|
||||||
|
|
||||||
Quick3DNodeInstance::Quick3DNodeInstance(QObject *node)
|
Quick3DNodeInstance::Quick3DNodeInstance(QObject *node)
|
||||||
: ObjectNodeInstance(node)
|
: ObjectNodeInstance(node)
|
||||||
{
|
{
|
||||||
@@ -97,7 +99,7 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo
|
|||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#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 case this is the scene root, we need to create a dummy View3D for the scene
|
||||||
// in preview puppets
|
// in preview puppets
|
||||||
if (instanceId() == 0 && nodeInstanceServer()->isPreviewServer()) {
|
if (instanceId() == 0 && (!nodeInstanceServer()->isInformationServer())) {
|
||||||
auto helper = new QmlDesigner::Internal::GeneralHelper();
|
auto helper = new QmlDesigner::Internal::GeneralHelper();
|
||||||
engine()->rootContext()->setContextProperty("_generalHelper", helper);
|
engine()->rootContext()->setContextProperty("_generalHelper", helper);
|
||||||
|
|
||||||
@@ -111,8 +113,8 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo
|
|||||||
|
|
||||||
nodeInstanceServer()->setRootItem(m_dummyRootView);
|
nodeInstanceServer()->setRootItem(m_dummyRootView);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // QT_VERSION
|
||||||
#endif
|
#endif // QUICK3D_MODULE
|
||||||
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +124,7 @@ QImage Quick3DNodeInstance::renderImage() const
|
|||||||
if (!isRootNodeInstance() || !m_dummyRootView)
|
if (!isRootNodeInstance() || !m_dummyRootView)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
QSize size(640, 480);
|
QSize size = preview3dBoundingRect.size().toSize();
|
||||||
nodeInstanceServer()->quickWindow()->resize(size);
|
nodeInstanceServer()->quickWindow()->resize(size);
|
||||||
m_dummyRootView->setSize(size);
|
m_dummyRootView->setSize(size);
|
||||||
|
|
||||||
@@ -190,13 +192,37 @@ bool Quick3DNodeInstance::isRenderable() const
|
|||||||
return m_dummyRootView;
|
return m_dummyRootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Quick3DNodeInstance::hasContent() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QRectF Quick3DNodeInstance::boundingRect() const
|
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)
|
if (m_dummyRootView)
|
||||||
return m_dummyRootView->boundingRect();
|
return m_dummyRootView->boundingRect();
|
||||||
return ObjectNodeInstance::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> Quick3DNodeInstance::stateInstances() const
|
||||||
{
|
{
|
||||||
QList<ServerNodeInstance> instanceList;
|
QList<ServerNodeInstance> instanceList;
|
||||||
@@ -212,6 +238,11 @@ QList<ServerNodeInstance> Quick3DNodeInstance::stateInstances() const
|
|||||||
return instanceList;
|
return instanceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QQuickItem *Quick3DNodeInstance::contentItem() const
|
||||||
|
{
|
||||||
|
return m_dummyRootView;
|
||||||
|
}
|
||||||
|
|
||||||
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
||||||
{
|
{
|
||||||
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
||||||
|
@@ -51,10 +51,16 @@ public:
|
|||||||
QImage renderPreviewImage(const QSize &previewImageSize) const override;
|
QImage renderPreviewImage(const QSize &previewImageSize) const override;
|
||||||
|
|
||||||
bool isRenderable() const override;
|
bool isRenderable() const override;
|
||||||
|
bool hasContent() const override;
|
||||||
QRectF boundingRect() const override;
|
QRectF boundingRect() const override;
|
||||||
|
QRectF contentItemBoundingBox() const override;
|
||||||
|
QPointF position() const override;
|
||||||
|
QSizeF size() const override;
|
||||||
|
|
||||||
QList<ServerNodeInstance> stateInstances() const override;
|
QList<ServerNodeInstance> stateInstances() const override;
|
||||||
|
|
||||||
|
QQuickItem *contentItem() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Quick3DNodeInstance(QObject *node);
|
explicit Quick3DNodeInstance(QObject *node);
|
||||||
|
|
||||||
|
@@ -162,6 +162,11 @@ bool ServerNodeInstance::isComponentWrap() const
|
|||||||
return m_nodeInstance->isComponentWrap();
|
return m_nodeInstance->isComponentWrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QQuickItem *ServerNodeInstance::contentItem() const
|
||||||
|
{
|
||||||
|
return m_nodeInstance->contentItem();
|
||||||
|
}
|
||||||
|
|
||||||
void ServerNodeInstance::updateDirtyNodeRecursive()
|
void ServerNodeInstance::updateDirtyNodeRecursive()
|
||||||
{
|
{
|
||||||
m_nodeInstance->updateAllDirtyNodesRecursive();
|
m_nodeInstance->updateAllDirtyNodesRecursive();
|
||||||
|
@@ -188,6 +188,8 @@ public:
|
|||||||
|
|
||||||
bool isComponentWrap() const;
|
bool isComponentWrap() const;
|
||||||
|
|
||||||
|
QQuickItem *contentItem() const;
|
||||||
|
|
||||||
private: // functions
|
private: // functions
|
||||||
ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);
|
ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance);
|
||||||
|
|
||||||
|
@@ -2226,4 +2226,39 @@ void FormEditorFlowWildcardItem::paint(QPainter *painter, const QStyleOptionGrap
|
|||||||
FormEditorFlowDecisionItem::paint(painter, option, widget);
|
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
|
} //QmlDesigner
|
||||||
|
@@ -171,6 +171,23 @@ private:
|
|||||||
QPointF m_oldPos;
|
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
|
class FormEditorFlowActionItem : public FormEditorItem
|
||||||
{
|
{
|
||||||
friend FormEditorScene;
|
friend FormEditorScene;
|
||||||
|
@@ -173,7 +173,9 @@ FormEditorItem *FormEditorScene::addFormEditorItem(const QmlItemNode &qmlItemNod
|
|||||||
{
|
{
|
||||||
FormEditorItem *formEditorItem = nullptr;
|
FormEditorItem *formEditorItem = nullptr;
|
||||||
|
|
||||||
if (type == Flow)
|
if (type == Preview3d)
|
||||||
|
formEditorItem = new FormEditor3dPreview(qmlItemNode, this);
|
||||||
|
else if (type == Flow)
|
||||||
formEditorItem = new FormEditorFlowItem(qmlItemNode, this);
|
formEditorItem = new FormEditorFlowItem(qmlItemNode, this);
|
||||||
else if (type == FlowAction)
|
else if (type == FlowAction)
|
||||||
formEditorItem = new FormEditorFlowActionItem(qmlItemNode, this);
|
formEditorItem = new FormEditorFlowActionItem(qmlItemNode, this);
|
||||||
|
@@ -58,7 +58,8 @@ public:
|
|||||||
FlowAction,
|
FlowAction,
|
||||||
FlowTransition,
|
FlowTransition,
|
||||||
FlowDecision,
|
FlowDecision,
|
||||||
FlowWildcard
|
FlowWildcard,
|
||||||
|
Preview3d
|
||||||
};
|
};
|
||||||
|
|
||||||
FormEditorScene(FormEditorWidget *widget, FormEditorView *editorView);
|
FormEditorScene(FormEditorWidget *widget, FormEditorView *editorView);
|
||||||
|
@@ -46,6 +46,7 @@
|
|||||||
#include <nodelistproperty.h>
|
#include <nodelistproperty.h>
|
||||||
#include <nodemetainfo.h>
|
#include <nodemetainfo.h>
|
||||||
#include <rewriterview.h>
|
#include <rewriterview.h>
|
||||||
|
#include <qml3dnode.h>
|
||||||
#include <zoomaction.h>
|
#include <zoomaction.h>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -655,6 +656,14 @@ static void updateTransitions(FormEditorScene *scene, const QmlItemNode &qmlItem
|
|||||||
|
|
||||||
void FormEditorView::instancesCompleted(const QVector<ModelNode> &completedNodeList)
|
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();
|
const bool isFlow = rootModelNode().isValid() && QmlItemNode(rootModelNode()).isFlowView();
|
||||||
QList<FormEditorItem*> itemNodeList;
|
QList<FormEditorItem*> itemNodeList;
|
||||||
for (const ModelNode &node : completedNodeList) {
|
for (const ModelNode &node : completedNodeList) {
|
||||||
@@ -724,6 +733,10 @@ void FormEditorView::instancesRenderImageChanged(const QVector<ModelNode> &nodeL
|
|||||||
if (QmlItemNode::isValidQmlItemNode(node))
|
if (QmlItemNode::isValidQmlItemNode(node))
|
||||||
if (FormEditorItem *item = scene()->itemForQmlItemNode(QmlItemNode(node)))
|
if (FormEditorItem *item = scene()->itemForQmlItemNode(QmlItemNode(node)))
|
||||||
item->update();
|
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()))
|
if (QmlItemNode::isValidQmlItemNode(rootModelNode()))
|
||||||
setupFormEditorItemTree(rootModelNode());
|
setupFormEditorItemTree(rootModelNode());
|
||||||
|
|
||||||
|
if (Qml3DNode::isValidQml3DNode(rootModelNode()))
|
||||||
|
setupFormEditor3DView();
|
||||||
|
|
||||||
m_formEditorWidget->initialize();
|
m_formEditorWidget->initialize();
|
||||||
|
|
||||||
if (!rewriterView()->errors().isEmpty())
|
if (!rewriterView()->errors().isEmpty())
|
||||||
@@ -903,7 +919,8 @@ void FormEditorView::checkRootModelNode()
|
|||||||
|
|
||||||
QTC_ASSERT(rootModelNode().isValid(), return);
|
QTC_ASSERT(rootModelNode().isValid(), return);
|
||||||
|
|
||||||
if (!rootModelNode().metaInfo().isGraphicalItem())
|
if (!rootModelNode().metaInfo().isGraphicalItem()
|
||||||
|
&& !Qml3DNode::isValidQml3DNode(rootModelNode()))
|
||||||
m_formEditorWidget->showErrorMessageBox(
|
m_formEditorWidget->showErrorMessageBox(
|
||||||
{DocumentMessage(tr("%1 is not supported as the root element by Form Editor.")
|
{DocumentMessage(tr("%1 is not supported as the root element by Form Editor.")
|
||||||
.arg(rootModelNode().simplifiedTypeName()))});
|
.arg(rootModelNode().simplifiedTypeName()))});
|
||||||
@@ -911,6 +928,13 @@ void FormEditorView::checkRootModelNode()
|
|||||||
m_formEditorWidget->hideErrorMessageBox();
|
m_formEditorWidget->hideErrorMessageBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormEditorView::setupFormEditor3DView()
|
||||||
|
{
|
||||||
|
m_scene->addFormEditorItem(rootModelNode(), FormEditorScene::Preview3d);
|
||||||
|
FormEditorItem *item = m_scene->itemForQmlItemNode(rootModelNode());
|
||||||
|
item->updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
void FormEditorView::reset()
|
void FormEditorView::reset()
|
||||||
{
|
{
|
||||||
QTimer::singleShot(200, this, &FormEditorView::delayedReset);
|
QTimer::singleShot(200, this, &FormEditorView::delayedReset);
|
||||||
|
@@ -151,6 +151,7 @@ private:
|
|||||||
void resetNodeInstanceView();
|
void resetNodeInstanceView();
|
||||||
void addOrRemoveFormEditorItem(const ModelNode &node);
|
void addOrRemoveFormEditorItem(const ModelNode &node);
|
||||||
void checkRootModelNode();
|
void checkRootModelNode();
|
||||||
|
void setupFormEditor3DView();
|
||||||
|
|
||||||
QPointer<FormEditorWidget> m_formEditorWidget;
|
QPointer<FormEditorWidget> m_formEditorWidget;
|
||||||
QPointer<FormEditorScene> m_scene;
|
QPointer<FormEditorScene> m_scene;
|
||||||
|
Reference in New Issue
Block a user