QmlDesigner: Get the material image based on request id

A request id is used for comparing requests instead of image sizes
Returned image sizes was not always the same as requested ones because
of pixelRateRatio.

Fixes: QDS-12961
Change-Id: I2f0ed7ea00047f296872a02958322f3448984f09
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2024-06-06 17:35:25 +03:00
parent 79e6c6809b
commit 1e3f8afdce
18 changed files with 129 additions and 60 deletions

View File

@@ -10,13 +10,17 @@ namespace QmlDesigner {
RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand() = default;
RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand(qint32 id, const QSize &size,
RequestModelNodePreviewImageCommand::RequestModelNodePreviewImageCommand(
qint32 id,
const QSize &size,
const QString &componentPath,
qint32 renderItemId)
qint32 renderItemId,
const QByteArray &requestId)
: m_instanceId(id)
, m_size(size)
, m_componentPath(componentPath)
, m_renderItemId(renderItemId)
, m_requestId(requestId)
{
}
@@ -40,12 +44,18 @@ qint32 RequestModelNodePreviewImageCommand::renderItemId() const
return m_renderItemId;
}
QByteArray RequestModelNodePreviewImageCommand::requestId() const
{
return m_requestId;
}
QDataStream &operator<<(QDataStream &out, const RequestModelNodePreviewImageCommand &command)
{
out << int(command.instanceId());
out << command.size();
out << command.componentPath();
out << command.renderItemId();
out << command.requestId();
return out;
}
@@ -56,6 +66,7 @@ QDataStream &operator>>(QDataStream &in, RequestModelNodePreviewImageCommand &co
in >> command.m_size;
in >> command.m_componentPath;
in >> command.m_renderItemId;
in >> command.m_requestId;
return in;
}
@@ -65,7 +76,8 @@ QDebug operator <<(QDebug debug, const RequestModelNodePreviewImageCommand &comm
<< "instanceId: " << command.instanceId() << ", "
<< "size: " << command.size() << ", "
<< "componentPath: " << command.componentPath() << ", "
<< "renderItemId: " << command.renderItemId() << ")";
<< "renderItemId: " << command.renderItemId() << ", "
<< "requestId: " << command.requestId() << ")";
}
} // namespace QmlDesigner

View File

@@ -18,28 +18,34 @@ class RequestModelNodePreviewImageCommand
public:
RequestModelNodePreviewImageCommand();
explicit RequestModelNodePreviewImageCommand(qint32 id, const QSize &size,
const QString &componentPath, qint32 renderItemId);
explicit RequestModelNodePreviewImageCommand(
qint32 id,
const QSize &size,
const QString &componentPath,
qint32 renderItemId,
const QByteArray &requestId = {});
qint32 instanceId() const;
QSize size() const;
QString componentPath() const;
qint32 renderItemId() const;
QByteArray requestId() const;
private:
qint32 m_instanceId;
QSize m_size;
QString m_componentPath;
qint32 m_renderItemId;
QByteArray m_requestId;
};
inline bool operator==(const RequestModelNodePreviewImageCommand &first,
const RequestModelNodePreviewImageCommand &second)
{
return first.instanceId() == second.instanceId()
&& first.size() == second.size()
return first.instanceId() == second.instanceId() && first.size() == second.size()
&& first.componentPath() == second.componentPath()
&& first.renderItemId() == second.renderItemId();
&& first.renderItemId() == second.renderItemId()
&& first.requestId() == second.requestId();
}
inline size_t qHash(const RequestModelNodePreviewImageCommand &key, size_t seed = 0)
@@ -47,9 +53,11 @@ inline size_t qHash(const RequestModelNodePreviewImageCommand &key, size_t seed
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
return ::qHash(key.instanceId(), seed)
^ ::qHash(std::make_pair(key.size().width(), key.size().height()), seed)
^ ::qHash(key.componentPath(), seed) ^ ::qHash(key.renderItemId(), seed);
^ ::qHash(key.componentPath(), seed) ^ ::qHash(key.renderItemId(), seed)
^ ::qHash(key.requestId(), seed);
#else
return qHashMulti(seed, key.instanceId(), key.size(), key.componentPath(), key.renderItemId());
return qHashMulti(
seed, key.instanceId(), key.size(), key.componentPath(), key.renderItemId(), key.requestId());
#endif
}

View File

@@ -56,6 +56,11 @@ QRectF ImageContainer::rect() const
return m_rect;
}
QByteArray ImageContainer::requestId() const
{
return m_requestId;
}
void ImageContainer::setImage(const QImage &image)
{
QTC_ASSERT(m_image.isNull(), /**/);
@@ -68,6 +73,11 @@ void ImageContainer::setRect(const QRectF &rectangle)
m_rect = rectangle;
}
void ImageContainer::setRequestId(const QByteArray &newRequestId)
{
m_requestId = newRequestId;
}
void ImageContainer::removeSharedMemorys(const QVector<qint32> &keyNumberVector)
{
for (qint32 keyNumber : keyNumberVector) {
@@ -151,6 +161,7 @@ QDataStream &operator<<(QDataStream &out, const ImageContainer &container)
out << container.instanceId();
out << container.keyNumber();
out << container.rect();
out << container.requestId();
const QImage image = container.image();
@@ -236,6 +247,7 @@ QDataStream &operator>>(QDataStream &in, ImageContainer &container)
in >> container.m_instanceId;
in >> container.m_keyNumber;
in >> container.m_rect;
in >> container.m_requestId;
in >> sharedMemoryIsUsed;
if (sharedMemoryIsUsed) {
@@ -259,10 +271,11 @@ bool operator <(const ImageContainer &first, const ImageContainer &second)
QDebug operator <<(QDebug debug, const ImageContainer &container)
{
return debug.nospace() << "ImageContainer("
<< "instanceId: " << container.instanceId() << ", "
<< "size: " << container.image().size() << ")";
debug.nospace() << "ImageContainer("
<< "instanceId: " << container.instanceId() << ", ";
if (!container.requestId().isEmpty())
debug << "requestId: " << container.requestId() << ", ";
return debug << "size: " << container.image().size() << ")";
}
} // namespace QmlDesigner

View File

@@ -23,9 +23,11 @@ public:
QImage image() const;
qint32 keyNumber() const;
QRectF rect() const;
QByteArray requestId() const;
void setImage(const QImage &image);
void setRect(const QRectF &rectangle);
void setRequestId(const QByteArray &newRequestId);
static void removeSharedMemorys(const QVector<qint32> &keyNumberVector);
@@ -34,6 +36,7 @@ private:
qint32 m_instanceId;
qint32 m_keyNumber;
QRectF m_rect;
QByteArray m_requestId;
};
QDataStream &operator<<(QDataStream &out, const ImageContainer &container);

View File

@@ -333,16 +333,16 @@ void MaterialBrowserView::selectedNodesChanged(const QList<ModelNode> &selectedN
m_widget->materialBrowserModel()->selectMaterial(idx);
}
void MaterialBrowserView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
void MaterialBrowserView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
if (!isMaterial(node))
return;
// There might be multiple requests for different preview pixmap sizes.
// Here only the one with the default size is picked.
const double ratio = externalDependencies().formEditorDevicePixelRatio();
const int dim = Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * ratio;
if (pixmap.width() == dim && pixmap.height() == dim)
if (requestId.isEmpty())
m_widget->updateMaterialPreview(node, pixmap);
}

View File

@@ -34,7 +34,9 @@ public:
void modelAboutToBeDetached(Model *model) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override;
void modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId) override;
void nodeIdChanged(const ModelNode &node, const QString &newId, const QString &oldId) override;
void variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags propertyChange) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;

View File

@@ -42,6 +42,8 @@
namespace QmlDesigner {
static const char MATERIAL_EDITOR_IMAGE_REQUEST_ID[] = "MaterialEditor";
MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
, m_stackedWidget(new QStackedWidget)
@@ -859,10 +861,12 @@ void MaterialEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty
// request render image for the selected material node
void MaterialEditorView::requestPreviewRender()
{
if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid())
if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) {
model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial,
{},
m_previewSize);
m_previewSize,
MATERIAL_EDITOR_IMAGE_REQUEST_ID);
}
}
bool MaterialEditorView::hasWidget() const
@@ -946,14 +950,14 @@ void MaterialEditorView::rootNodeTypeChanged(const QString &type, int, int)
}
}
void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
if (node != m_selectedMaterial)
return;
if (m_previewSize.isValid() && pixmap.size() != m_previewSize)
return;
if (requestId == MATERIAL_EDITOR_IMAGE_REQUEST_ID)
m_qmlBackEnd->updateMaterialPreview(pixmap);
}

View File

@@ -55,7 +55,9 @@ public:
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override;
void modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId) override;
void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;

View File

@@ -364,13 +364,13 @@ void NavigatorView::enableWidget()
m_widget->enableNavigator();
}
void NavigatorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
void NavigatorView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
// There might be multiple requests for different preview pixmap sizes.
// Here only the one with the default size is picked.
const double ratio = externalDependencies().formEditorDevicePixelRatio();
const int dim = Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * ratio;
if (pixmap.width() == dim && pixmap.height() == dim)
if (requestId.isEmpty())
m_treeModel->updateToolTipPixmap(node, pixmap);
}

View File

@@ -83,7 +83,9 @@ public:
void disableWidget() override;
void enableWidget() override;
void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override;
void modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId) override;
private:
ModelNode modelNodeForIndex(const QModelIndex &modelIndex) const;

View File

@@ -57,7 +57,9 @@ void PreviewToolTip::setInfo(const QString &info)
void PreviewToolTip::setPixmap(const QPixmap &pixmap)
{
m_ui->imageLabel->setPixmap(pixmap);
QPixmap scaled = pixmap.scaled(m_ui->labelBackground->size(), Qt::KeepAspectRatio);
scaled.setDevicePixelRatio(1.);
m_ui->imageLabel->setPixmap(scaled);
}
QString PreviewToolTip::id() const

View File

@@ -148,7 +148,9 @@ public:
void emitInstanceToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
void emitRenderImage3DChanged(const QImage &image);
void emitUpdateActiveScene3D(const QVariantMap &sceneState);
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void emitModelNodelPreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId);
void emitImport3DSupportChanged(const QVariantMap &supportMap);
void emitNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d);
void emitView3DAction(View3DActionType type, const QVariant &value);
@@ -227,7 +229,9 @@ public:
virtual void updateActiveScene3D(const QVariantMap &sceneState);
virtual void updateImport3DSupport(const QVariantMap &supportMap);
virtual void nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d);
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
virtual void modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId);
virtual void view3DAction(View3DActionType type, const QVariant &value);

View File

@@ -136,14 +136,16 @@ public:
void view3DAction(View3DActionType type, const QVariant &value) override;
void requestModelNodePreviewImage(const ModelNode &node,
const ModelNode &renderNode,
const QSize &size = {}) const;
const QSize &size = {},
const QByteArray &requestId = {}) const;
void edit3DViewResized(const QSize &size) const;
void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override;
QVariant previewImageDataForGenericNode(const ModelNode &modelNode,
const ModelNode &renderNode,
const QSize &size = {}) const;
const QSize &size = {},
const QByteArray &requestId = {}) const;
QVariant previewImageDataForImageNode(const ModelNode &modelNode) const;
void setCrashCallback(std::function<void()> crashCallback)
@@ -229,7 +231,9 @@ private: // functions
QString info;
};
QVariant modelNodePreviewImageDataToVariant(const ModelNodePreviewImageData &imageData) const;
void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image);
void updatePreviewImageForNode(const ModelNode &modelNode,
const QImage &image,
const QByteArray &requestId);
void updateWatcher(const QString &path);
void handleShaderChanges();

View File

@@ -1779,7 +1779,7 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
if (node.isValid()) {
const double ratio = m_externalDependencies.formEditorDevicePixelRatio();
image.setDevicePixelRatio(ratio);
updatePreviewImageForNode(node, image);
updatePreviewImageForNode(node, image, container.requestId());
}
}
} else if (command.type() == PuppetToCreatorCommand::Import3DSupport) {
@@ -1824,7 +1824,8 @@ void NodeInstanceView::view3DAction(View3DActionType type, const QVariant &value
void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node,
const ModelNode &renderNode,
const QSize &size) const
const QSize &size,
const QByteArray &requestId) const
{
if (m_nodeInstanceServer && node.isValid() && hasInstanceForModelNode(node)) {
auto instance = instanceForModelNode(node);
@@ -1842,16 +1843,17 @@ void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node,
componentPath = ModelUtils::componentFilePath(node);
}
if (size.isValid()) {
imageSize = size;
} else {
const double ratio = m_externalDependencies.formEditorDevicePixelRatio();
if (size.isValid()) {
imageSize = size * ratio;
} else {
const int dim = Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * ratio;
imageSize = {dim, dim};
}
m_nodeInstanceServer->requestModelNodePreviewImage(RequestModelNodePreviewImageCommand(
instance.instanceId(), imageSize, componentPath, renderItemId));
instance.instanceId(), imageSize, componentPath, renderItemId, requestId));
}
}
}
@@ -1997,7 +1999,8 @@ void NodeInstanceView::endNanotrace()
QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &modelNode,
const ModelNode &renderNode,
const QSize &size) const
const QSize &size,
const QByteArray &requestId) const
{
if (!modelNode.isValid())
return {};
@@ -2014,23 +2017,23 @@ QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &model
imageData.id = id;
// There might be multiple requests for different preview pixmap sizes.
// Here only the one with the default size is stored.
const double ratio = externalDependencies().formEditorDevicePixelRatio();
const int dim = Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * ratio;
if (size.width() == dim && size.height() == dim)
// Here only the one with no request id is stored.
if (requestId.isEmpty())
m_imageDataMap.insert(id, imageData);
}
requestModelNodePreviewImage(modelNode, renderNode, size);
requestModelNodePreviewImage(modelNode, renderNode, size, requestId);
return modelNodePreviewImageDataToVariant(imageData);
}
void NodeInstanceView::updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image)
void NodeInstanceView::updatePreviewImageForNode(const ModelNode &modelNode,
const QImage &image,
const QByteArray &requestId)
{
QPixmap pixmap = QPixmap::fromImage(image);
if (m_imageDataMap.contains(modelNode.id()))
m_imageDataMap[modelNode.id()].pixmap = pixmap;
emitModelNodelPreviewPixmapChanged(modelNode, pixmap);
emitModelNodelPreviewPixmapChanged(modelNode, pixmap, requestId);
}
void NodeInstanceView::updateWatcher(const QString &path)

View File

@@ -385,7 +385,9 @@ void AbstractView::updateImport3DSupport(const QVariantMap &/*supportMap*/)
// position of the requested view position.
void AbstractView::nodeAtPosReady(const ModelNode &/*modelNode*/, const QVector3D &/*pos3d*/) {}
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode &/*node*/, const QPixmap &/*pixmap*/)
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/,
const QPixmap & /*pixmap*/,
const QByteArray & /*requestId*/)
{
}
@@ -749,10 +751,12 @@ void AbstractView::emitUpdateActiveScene3D(const QVariantMap &sceneState)
model()->d->notifyUpdateActiveScene3D(sceneState);
}
void AbstractView::emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
void AbstractView::emitModelNodelPreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
if (model())
model()->d->notifyModelNodePreviewPixmapChanged(node, pixmap);
model()->d->notifyModelNodePreviewPixmapChanged(node, pixmap, requestId);
}
void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap)

View File

@@ -715,10 +715,12 @@ void ModelPrivate::notifyUpdateActiveScene3D(const QVariantMap &sceneState)
notifyInstanceChanges([&](AbstractView *view) { view->updateActiveScene3D(sceneState); });
}
void ModelPrivate::notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
void ModelPrivate::notifyModelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
notifyInstanceChanges(
[&](AbstractView *view) { view->modelNodePreviewPixmapChanged(node, pixmap); });
[&](AbstractView *view) { view->modelNodePreviewPixmapChanged(node, pixmap, requestId); });
}
void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap)

View File

@@ -221,7 +221,9 @@ public:
void notifyRenderImage3DChanged(const QImage &image);
void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void notifyModelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId);
void notifyImport3DSupportChanged(const QVariantMap &supportMap);
void notifyNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d);
void notifyView3DAction(View3DActionType type, const QVariant &value);

View File

@@ -1377,6 +1377,7 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView(
// Key number is selected so that it is unlikely to conflict other ImageContainer use.
ImageContainer imgContainer(cmd.instanceId(), {}, 2100000001 + cmd.instanceId());
imgContainer.setImage(renderImage);
imgContainer.setRequestId(cmd.requestId());
// send the rendered image to creator process
nodeInstanceClient()->handlePuppetToCreatorCommand(
@@ -1472,6 +1473,7 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView(const Reques
if (!renderImage.isNull()) {
imgContainer.setImage(renderImage);
imgContainer.setRequestId(cmd.requestId());
// send the rendered image to creator process
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::RenderModelNodePreviewImage,