QmlDesigner: Add navigator preview tooltip for materials

Request 3D preview image for material instances from puppet
to show on tooltip.

Support for effect previews is also done, but handler for it is not
registered, as effects cannot be shared between windows due to
issue QTBUG-86616.

Also refactored the preview image support out of navigator
to make it more accessible by other components.

Change-Id: Ie08ba218f929660c2e43d39578997a5a1a883efd
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2020-09-10 16:02:31 +03:00
parent f849bd1105
commit 90d9cb36f3
47 changed files with 848 additions and 103 deletions

View File

@@ -166,6 +166,7 @@ extend_qtc_plugin(QmlDesigner
puppettocreatorcommand.cpp puppettocreatorcommand.h
inputeventcommand.cpp inputeventcommand.h
view3dactioncommand.cpp view3dactioncommand.h
requestmodelnodepreviewimagecommand.cpp requestmodelnodepreviewimagecommand.h
)
extend_qtc_plugin(QmlDesigner

View File

@@ -194,6 +194,54 @@ void DesignerActionManager::registerAddResourceHandler(const AddResourceHandler
m_addResourceHandler.append(handler);
}
QHash<TypeName, ModelNodePreviewImageHandler> DesignerActionManager::modelNodePreviewHandlers() const
{
return m_modelNodePreviewImageHandlers;
}
void DesignerActionManager::registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler)
{
m_modelNodePreviewImageHandlers.insert(handler.type, handler);
// Registering a new handler potentially invalidates no-handler set
m_noModelNodePreviewImageHandlers.clear();
}
bool DesignerActionManager::hasModelNodePreviewHandler(const ModelNode &node) const
{
if (m_modelNodePreviewImageHandlers.contains(node.type()))
return true;
if (m_noModelNodePreviewImageHandlers.contains(node.type()))
return false;
// Node may be a subclass of a registered type
for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) {
if (node.isSubclassOf(handler.type)) {
ModelNodePreviewImageHandler subClassHandler = handler;
return true;
}
}
m_noModelNodePreviewImageHandlers.insert(node.type());
return false;
}
ModelNodePreviewImageOperation DesignerActionManager::modelNodePreviewOperation(const ModelNode &node) const
{
ModelNodePreviewImageOperation op = nullptr;
if (!m_noModelNodePreviewImageHandlers.contains(node.type())) {
int prio = -1;
for (const auto &handler : qAsConst(m_modelNodePreviewImageHandlers)) {
if (node.isSubclassOf(handler.type) && handler.priority > prio)
op = handler.operation;
}
if (!op)
m_noModelNodePreviewImageHandlers.insert(node.type());
}
return op;
}
class VisiblityModelNodeAction : public ModelNodeContextMenuAction
{
public:
@@ -1309,6 +1357,24 @@ void DesignerActionManager::createDefaultAddResourceHandler()
ModelNodeOperations::addFontToProject));
}
void DesignerActionManager::createDefaultModelNodePreviewImageHandlers()
{
registerModelNodePreviewHandler(
ModelNodePreviewImageHandler("QtQuick.Image",
ModelNodeOperations::previewImageDataForImageNode));
registerModelNodePreviewHandler(
ModelNodePreviewImageHandler("QtQuick3D.Texture",
ModelNodeOperations::previewImageDataForImageNode));
registerModelNodePreviewHandler(
ModelNodePreviewImageHandler("QtQuick3D.Material",
ModelNodeOperations::previewImageDataFor3DNode));
// TODO - Disabled until QTBUG-86616 is fixed
// registerModelNodePreviewHandler(
// ModelNodePreviewImageHandler("QtQuick3D.Effect",
// ModelNodeOperations::previewImageDataFor3DNode));
}
void DesignerActionManager::addDesignerAction(ActionInterface *newAction)
{
m_designerActions.append(QSharedPointer<ActionInterface>(newAction));

View File

@@ -27,11 +27,13 @@
#include <qmldesignercorelib_global.h>
#include "actioninterface.h"
#include "modelnode.h"
#include <coreplugin/actionmanager/command.h>
#include <utils/styledbar.h>
#include <QToolBar>
#include <QImage>
QT_BEGIN_NAMESPACE
class QGraphicsItem;
@@ -42,7 +44,8 @@ namespace QmlDesigner {
class DesignerActionManagerView;
using AddResourceOperation = std::function<bool (const QStringList&, const QString&)>;
using AddResourceOperation = std::function<bool (const QStringList &, const QString &)>;
using ModelNodePreviewImageOperation = std::function<QVariant (const ModelNode &)>;
struct AddResourceHandler
{
@@ -64,6 +67,23 @@ public:
int piority;
};
struct ModelNodePreviewImageHandler
{
public:
ModelNodePreviewImageHandler(const TypeName &t,
ModelNodePreviewImageOperation op,
int prio = 0)
: type(t)
, operation(op)
, priority(prio)
{
}
TypeName type;
ModelNodePreviewImageOperation operation = nullptr;
int priority = 0;
};
class DesignerActionToolBar : public Utils::StyledBar
{
public:
@@ -87,6 +107,8 @@ public:
void createDefaultDesignerActions();
void createDefaultAddResourceHandler();
void createDefaultModelNodePreviewImageHandlers();
DesignerActionManagerView *view();
DesignerActionToolBar *createToolBar(QWidget *parent = nullptr) const;
@@ -102,6 +124,11 @@ public:
QList<AddResourceHandler> addResourceHandler() const;
void registerAddResourceHandler(const AddResourceHandler &handler);
QHash<TypeName, ModelNodePreviewImageHandler> modelNodePreviewHandlers() const;
void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler);
bool hasModelNodePreviewHandler(const ModelNode &node) const;
ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const;
private:
void addTransitionEffectAction(const TypeName &typeName);
void addCustomTransitionEffectAction();
@@ -109,6 +136,8 @@ private:
QList<QSharedPointer<ActionInterface> > m_designerActions;
DesignerActionManagerView *m_designerActionManagerView;
QList<AddResourceHandler> m_addResourceHandler;
QMultiHash<TypeName, ModelNodePreviewImageHandler> m_modelNodePreviewImageHandlers;
mutable QSet<TypeName> m_noModelNodePreviewImageHandlers;
};
} //QmlDesigner

View File

@@ -46,6 +46,8 @@
#include <nodelistproperty.h>
#include <nodeproperty.h>
#include <signalhandlerproperty.h>
#include <qmldesignerconstants.h>
#include <nodeinstanceview.h>
#include <componentcore_constants.h>
#include <stylesheetmerger.h>
@@ -78,6 +80,7 @@
#include <QFileDialog>
#include <QPushButton>
#include <QGridLayout>
#include <QImage>
#include <algorithm>
#include <functional>
@@ -1518,6 +1521,110 @@ void removeGroup(const SelectionContext &selectionContext)
});
}
struct ImageData {
QDateTime time;
QImage image;
QString type;
QString id;
QString info;
};
static QHash<QString, QHash<QString, ImageData>> imageDataMap;
static QVariant imageDataToVariant(const ImageData &imageData)
{
if (!imageData.image.isNull()) {
QVariantMap map;
map.insert("type", imageData.type);
map.insert("image", QVariant::fromValue<QImage>(imageData.image));
map.insert("id", imageData.id);
map.insert("info", imageData.info);
return map;
}
return {};
}
QVariant previewImageDataForImageNode(const ModelNode &modelNode)
{
// Images on file system can be cached globally as they are found by absolute paths
QHash<QString, ImageData> &localDataMap = imageDataMap[{}];
VariantProperty prop = modelNode.variantProperty("source");
QString imageSource = prop.value().toString();
QFileInfo imageFi(imageSource);
if (imageFi.isRelative())
imageSource = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo().dir().absoluteFilePath(imageSource);
imageFi = QFileInfo(imageSource);
QDateTime modified = imageFi.lastModified();
ImageData imageData;
bool reload = true;
if (localDataMap.contains(imageSource)) {
imageData = localDataMap[imageSource];
if (modified == imageData.time)
reload = false;
}
if (reload) {
QImage originalImage;
originalImage.load(imageSource);
if (!originalImage.isNull()) {
imageData.image = originalImage.scaled(Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2,
Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS * 2,
Qt::KeepAspectRatio);
imageData.image.setDevicePixelRatio(2.);
double imgSize = double(imageFi.size());
imageData.type = QStringLiteral("%1 (%2)").arg(QString::fromLatin1(modelNode.type())).arg(imageFi.suffix());
imageData.id = modelNode.id();
static QStringList units({QObject::tr("B"), QObject::tr("KB"), QObject::tr("MB"), QObject::tr("GB")});
int unitIndex = 0;
while (imgSize > 1024. && unitIndex < units.size() - 1) {
++unitIndex;
imgSize /= 1024.;
}
imageData.info = QStringLiteral("%1 x %2 (%3%4)").arg(originalImage.width()).arg(originalImage.height())
.arg(QString::number(imgSize, 'g', 3)).arg(units[unitIndex]);
localDataMap.insert(imageSource, imageData);
}
}
return imageDataToVariant(imageData);
}
QVariant previewImageDataFor3DNode(const ModelNode &modelNode)
{
QFileInfo docFi = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo();
QHash<QString, ImageData> &localDataMap = imageDataMap[docFi.absoluteFilePath()];
ImageData imageData;
static const QImage placeHolder(":/navigator/icon/tooltip_placeholder.png");
// We need puppet to generate the image, which needs to be asynchronous.
// Until the image is ready, we show a placeholder
const QString id = modelNode.id();
if (localDataMap.contains(id)) {
imageData = localDataMap[id];
} else {
imageData.type = QString::fromLatin1(modelNode.type());
imageData.id = id;
imageData.image = placeHolder;
localDataMap.insert(id, imageData);
}
modelNode.model()->nodeInstanceView()->requestModelNodePreviewImage(modelNode);
return imageDataToVariant(imageData);
}
void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image)
{
QFileInfo docFi = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo();
QString docPath = docFi.absoluteFilePath();
if (imageDataMap.contains(docPath)) {
QHash<QString, ImageData> &localDataMap = imageDataMap[docPath];
if (localDataMap.contains(modelNode.id()))
localDataMap[modelNode.id()].image = image;
}
}
} // namespace ModelNodeOperations
} //QmlDesigner

View File

@@ -27,6 +27,8 @@
#include "selectioncontext.h"
QT_FORWARD_DECLARE_CLASS(QImage)
namespace QmlDesigner {
namespace ModelNodeOperations {
@@ -84,5 +86,10 @@ void selectFlowEffect(const SelectionContext &selectionContext);
void mergeWithTemplate(const SelectionContext &selectionContext);
void removeGroup(const SelectionContext &selectionContext);
// ModelNodePreviewImageOperations
QVariant previewImageDataFor3DNode(const ModelNode &modelNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode);
void updatePreviewImageForNode(const ModelNode &modelNode, const QImage &image);
} // namespace ModelNodeOperationso
} //QmlDesigner

View File

@@ -12,5 +12,6 @@
<file>export_checked@2x.png</file>
<file>export_unchecked.png</file>
<file>export_unchecked@2x.png</file>
<file>tooltip_placeholder.png</file>
</qresource>
</RCC>

View File

@@ -40,6 +40,7 @@
#include <invalididexception.h>
#include <rewritingexception.h>
#include <qmlitemnode.h>
#include <designeractionmanager.h>
#include <coreplugin/icore.h>
@@ -53,7 +54,6 @@
#include <QPointF>
#include <QDir>
#include <QFileInfo>
#include <QDateTime>
#include <coreplugin/messagebox.h>
@@ -181,6 +181,7 @@ static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty
NavigatorTreeModel::NavigatorTreeModel(QObject *parent) : QAbstractItemModel(parent)
{
m_actionManager = &QmlDesignerPlugin::instance()->viewManager().designerActionManager();
}
NavigatorTreeModel::~NavigatorTreeModel() = default;
@@ -201,13 +202,6 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
if (role == ItemIsVisibleRole) //independent of column
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
auto hasImageToolTip = [modelNode]() -> bool {
if (modelNode.isValid() && modelNode.metaInfo().isValid())
return modelNode.type() == "QtQuick.Image" || modelNode.type() == "QtQuick3D.Texture";
else
return false;
};
if (index.column() == 0) {
if (role == Qt::DisplayRole) {
return modelNode.displayName();
@@ -229,7 +223,7 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
}
if (modelNode.metaInfo().isValid()) {
if (hasImageToolTip())
if (m_actionManager->hasModelNodePreviewHandler(modelNode))
return {}; // Images have special tooltip popup, so suppress regular one
else
return modelNode.type();
@@ -239,62 +233,9 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
} else if (role == ToolTipImageRole) {
if (currentQmlObjectNode.hasError()) // Error already shown on regular tooltip
return {};
if (hasImageToolTip()) {
VariantProperty prop = modelNode.variantProperty("source");
QString imageSource = prop.value().toString();
QFileInfo fi(imageSource);
if (fi.isRelative())
imageSource = QmlDesignerPlugin::instance()->documentManager().currentFilePath().toFileInfo().dir().absoluteFilePath(imageSource);
fi = QFileInfo(imageSource);
QDateTime modified = fi.lastModified();
struct ImageData {
QDateTime time;
QImage image;
QString type;
QString id;
QString info;
};
static QHash<QString, ImageData> toolTipImageMap;
ImageData imageData;
bool reload = true;
if (toolTipImageMap.contains(imageSource)) {
imageData = toolTipImageMap[imageSource];
if (modified == imageData.time)
reload = false;
}
if (reload) {
QImage originalImage;
originalImage.load(imageSource);
if (!originalImage.isNull()) {
imageData.image = originalImage.scaled(150, 150, Qt::KeepAspectRatio);
double imgSize = double(fi.size());
imageData.type = QStringLiteral("%1 (%2)").arg(QString::fromLatin1(modelNode.type())).arg(fi.suffix());
imageData.id = modelNode.id();
static QStringList units({tr("B"), tr("KB"), tr("MB"), tr("GB")});
int unitIndex = 0;
while (imgSize > 1024. && unitIndex < units.size() - 1) {
++unitIndex;
imgSize /= 1024.;
}
imageData.info = QStringLiteral("%1 x %2 (%3%4)").arg(originalImage.width()).arg(originalImage.height())
.arg(QString::number(imgSize, 'g', 3)).arg(units[unitIndex]);
toolTipImageMap.insert(imageSource, imageData);
}
}
if (!imageData.image.isNull()) {
QVariantMap map;
map.insert("type", imageData.type);
map.insert("image", QVariant::fromValue<QImage>(imageData.image));
map.insert("id", imageData.id);
map.insert("info", imageData.info);
return map;
}
}
auto op = m_actionManager->modelNodePreviewOperation(modelNode);
if (op)
return op(modelNode);
} else if (role == ModelNodeRole) {
return QVariant::fromValue<ModelNode>(modelNode);
}
@@ -898,4 +839,9 @@ void NavigatorTreeModel::resetModel()
endResetModel();
}
void NavigatorTreeModel::updateToolTipImage(const ModelNode &node, const QImage &image)
{
emit toolTipImageUpdated(node.id(), image);
}
} // QmlDesigner

View File

@@ -32,12 +32,14 @@
#include <QAbstractItemModel>
#include <QPointer>
#include <QDateTime>
namespace QmlDesigner {
class Model;
class NavigatorView;
class ModelNode;
class DesignerActionManager;
class NavigatorTreeModel : public QAbstractItemModel, public NavigatorModelInterface
{
@@ -91,6 +93,11 @@ public:
void setFilter(bool showOnlyVisibleItems) override;
void resetModel() override;
void updateToolTipImage(const ModelNode &node, const QImage &image);
signals:
void toolTipImageUpdated(const QString &id, const QImage &image) const;
private:
void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList<ModelNode> &modelNodes,
int targetIndex, bool executeInTransaction = true);
@@ -102,6 +109,7 @@ private:
QPointer<NavigatorView> m_view;
mutable QHash<ModelNode, QModelIndex> m_nodeIndexHash;
bool m_showOnlyVisibleItems = true;
DesignerActionManager *m_actionManager = nullptr;
};
} // namespace QmlDesigner

View File

@@ -168,6 +168,12 @@ NavigatorTreeView::NavigatorTreeView(QWidget *parent)
setMinimumWidth(240);
setRootIsDecorated(false);
setIndentation(indentation() * 0.5);
m_toolTipHideTimer.setSingleShot(true);
connect(&m_toolTipHideTimer, &QTimer::timeout, [this]() {
if (m_previewToolTip && m_previewToolTip->isVisible())
m_previewToolTip->hide();
});
}
void NavigatorTreeView::drawSelectionBackground(QPainter *painter, const QStyleOption &option)
@@ -187,22 +193,30 @@ bool NavigatorTreeView::viewportEvent(QEvent *event)
QVariantMap imgMap = navModel->data(index, ToolTipImageRole).toMap();
if (!imgMap.isEmpty()) {
if (!m_previewToolTip)
m_toolTipHideTimer.stop();
if (!m_previewToolTip) {
m_previewToolTip = new PreviewToolTip(QApplication::activeWindow());
connect(navModel, &NavigatorTreeModel::toolTipImageUpdated,
[this](const QString &id, const QImage &image) {
if (m_previewToolTip && m_previewToolTip->id() == id)
m_previewToolTip->setImage(image);
});
}
m_previewToolTip->setId(imgMap["id"].toString());
m_previewToolTip->setType(imgMap["type"].toString());
m_previewToolTip->setInfo(imgMap["info"].toString());
m_previewToolTip->setImage(imgMap["image"].value<QImage>());
m_previewToolTip->move(helpEvent->pos());
m_previewToolTip->move(m_previewToolTip->parentWidget()->mapFromGlobal(helpEvent->globalPos())
+ QPoint(15, 15));
if (!m_previewToolTip->isVisible())
m_previewToolTip->show();
} else if (m_previewToolTip) {
m_previewToolTip->hide();
m_toolTipHideTimer.start(0);
}
}
} else if (event->type() == QEvent::Leave) {
if (m_previewToolTip)
m_previewToolTip->hide();
m_toolTipHideTimer.start(500);
}
return QTreeView::viewportEvent(event);

View File

@@ -26,6 +26,7 @@
#pragma once
#include <QTreeView>
#include <QTimer>
namespace QmlDesigner {
@@ -42,5 +43,6 @@ public:
private:
PreviewToolTip *m_previewToolTip = nullptr;
QTimer m_toolTipHideTimer;
};
}

View File

@@ -40,6 +40,7 @@
#include <variantproperty.h>
#include <qmlitemnode.h>
#include <rewritingexception.h>
#include <nodeinstanceview.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
@@ -229,6 +230,11 @@ void NavigatorView::enableWidget()
m_widget->enableNavigator();
}
void NavigatorView::modelNodePreviewImageChanged(const ModelNode &node, const QImage &image)
{
m_treeModel->updateToolTipImage(node, image);
}
ModelNode NavigatorView::modelNodeForIndex(const QModelIndex &modelIndex) const
{
return modelIndex.model()->data(modelIndex, ModelNodeRole).value<ModelNode>();

View File

@@ -38,6 +38,7 @@ class QTreeView;
class QItemSelection;
class QModelIndex;
class QAbstractItemModel;
class QImage;
QT_END_NAMESPACE
namespace QmlDesigner {
@@ -95,6 +96,8 @@ public:
void disableWidget() override;
void enableWidget() override;
void modelNodePreviewImageChanged(const ModelNode &node, const QImage &image) override;
private:
ModelNode modelNodeForIndex(const QModelIndex &modelIndex) const;
void changeSelection(const QItemSelection &selected, const QItemSelection &deselected);

View File

@@ -67,4 +67,9 @@ void PreviewToolTip::setImage(const QImage &image)
m_ui->imageLabel->setPixmap(QPixmap::fromImage(image));
}
QString PreviewToolTip::id() const
{
return m_ui->idLabel->text();
}
}

View File

@@ -46,6 +46,8 @@ public:
void setInfo(const QString &info);
void setImage(const QImage &image);
QString id() const;
private:
Ui::PreviewToolTip *m_ui;
};

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>160</height>
<height>166</height>
</rect>
</property>
<property name="sizePolicy">
@@ -18,8 +18,8 @@
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>150</height>
<width>300</width>
<height>140</height>
</size>
</property>
<property name="maximumSize">
@@ -90,8 +90,8 @@
</property>
<property name="minimumSize">
<size>
<width>140</width>
<height>140</height>
<width>150</width>
<height>150</height>
</size>
</property>
<property name="frameShape">

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -186,6 +186,7 @@ public:
void emitInstanceToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
void emitRenderImage3DChanged(const QImage &image);
void emitUpdateActiveScene3D(const QVariantMap &sceneState);
void emitModelNodelPreviewImageChanged(const ModelNode &node, const QImage &image);
void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
@@ -245,6 +246,7 @@ public:
virtual void renderImage3DChanged(const QImage &image);
virtual void updateActiveScene3D(const QVariantMap &sceneState);
virtual void modelNodePreviewImageChanged(const ModelNode &node, const QImage &image);
void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion);

View File

@@ -138,6 +138,7 @@ public:
void sendInputEvent(QInputEvent *e) const;
void view3DAction(const View3DActionCommand &command);
void requestModelNodePreviewImage(const ModelNode &node);
void edit3DViewResized(const QSize &size) const;
void handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) override;

View File

@@ -60,6 +60,7 @@
#include <update3dviewstatecommand.h>
#include <valueschangedcommand.h>
#include <view3dactioncommand.h>
#include <requestmodelnodepreviewimagecommand.h>
#include <import.h>
#include <nodeinstanceview.h>
@@ -293,6 +294,11 @@ void NodeInstanceServerProxy::view3DAction(const View3DActionCommand &command)
writeCommand(QVariant::fromValue(command));
}
void NodeInstanceServerProxy::requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command)
{
writeCommand(QVariant::fromValue(command));
}
void NodeInstanceServerProxy::changeLanguage(const ChangeLanguageCommand &command)
{
writeCommand(QVariant::fromValue(command));

View File

@@ -81,6 +81,7 @@ public:
void benchmark(const QString &message) override;
void inputEvent(const InputEventCommand &command) override;
void view3DAction(const View3DActionCommand &command) override;
void requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command) override;
void changeLanguage(const ChangeLanguageCommand &command) override;
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;

View File

@@ -71,6 +71,7 @@
#include "valueschangedcommand.h"
#include "variantproperty.h"
#include "view3dactioncommand.h"
#include "requestmodelnodepreviewimagecommand.h"
#include <designersettings.h>
#include <metainfo.h>
@@ -1487,6 +1488,16 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
} else if (command.type() == PuppetToCreatorCommand::ActiveSceneChanged) {
const auto sceneState = qvariant_cast<QVariantMap>(command.data());
emitUpdateActiveScene3D(sceneState);
} else if (command.type() == PuppetToCreatorCommand::RenderModelNodePreviewImage) {
ImageContainer container = qvariant_cast<ImageContainer>(command.data());
QImage image = container.image();
if (hasModelNodeForInternalId(container.instanceId()) && !image.isNull()) {
auto node = modelNodeForInternalId(container.instanceId());
if (node.isValid()) {
image.setDevicePixelRatio(2.);
emitModelNodelPreviewImageChanged(node, image);
}
}
}
}
@@ -1511,6 +1522,20 @@ void NodeInstanceView::view3DAction(const View3DActionCommand &command)
m_nodeInstanceServer->view3DAction(command);
}
void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node)
{
if (node.isValid()) {
auto instance = instanceForModelNode(node);
if (instance.isValid()) {
m_nodeInstanceServer->requestModelNodePreviewImage(
RequestModelNodePreviewImageCommand(
instance.instanceId(),
QSize(Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS,
Constants::MODELNODE_PREVIEW_IMAGE_DIMENSIONS)));
}
}
}
void NodeInstanceView::edit3DViewResized(const QSize &size) const
{
m_nodeInstanceServer->update3DViewState(Update3dViewStateCommand(size));

View File

@@ -382,6 +382,10 @@ void AbstractView::updateActiveScene3D(const QVariantMap & /*sceneState*/)
{
}
void AbstractView::modelNodePreviewImageChanged(const ModelNode & /*node*/, const QImage & /*image*/)
{
}
QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList) const
{
return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this));
@@ -766,6 +770,12 @@ void AbstractView::emitUpdateActiveScene3D(const QVariantMap &sceneState)
model()->d->notifyUpdateActiveScene3D(sceneState);
}
void AbstractView::emitModelNodelPreviewImageChanged(const ModelNode &node, const QImage &image)
{
if (model())
model()->d->notifyModelNodePreviewImageChanged(node, image);
}
void AbstractView::emitRewriterEndTransaction()
{
if (model())

View File

@@ -26,6 +26,7 @@
#include "model.h"
#include "model_p.h"
#include <modelnode.h>
#include <modelnodeoperations.h>
#include "internalnode_p.h"
#include "invalidpropertyexception.h"
#include "invalidargumentexception.h"
@@ -700,6 +701,16 @@ void ModelPrivate::notifyUpdateActiveScene3D(const QVariantMap &sceneState)
}
}
void ModelPrivate::notifyModelNodePreviewImageChanged(const ModelNode &node, const QImage &image)
{
ModelNodeOperations::updatePreviewImageForNode(node, image);
for (const QPointer<AbstractView> &view : qAsConst(m_viewList)) {
Q_ASSERT(view != nullptr);
view->modelNodePreviewImageChanged(node, image);
}
}
void ModelPrivate::notifyRewriterBeginTransaction()
{
bool resetModel = false;

View File

@@ -160,6 +160,7 @@ public:
void notifyRenderImage3DChanged(const QImage &image);
void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
void notifyModelNodePreviewImageChanged(const ModelNode &node, const QImage &image);
void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings);

View File

@@ -224,6 +224,7 @@ void DesignModeWidget::setup()
auto &actionManager = viewManager().designerActionManager();
actionManager.createDefaultDesignerActions();
actionManager.createDefaultAddResourceHandler();
actionManager.createDefaultModelNodePreviewImageHandlers();
actionManager.polishActions();
auto settings = Core::ICore::settings(QSettings::UserScope);

View File

@@ -75,6 +75,8 @@ const char QT_QUICK_3D_MODULE_NAME[] = "QtQuick3D";
// Menus
const char M_WINDOW_WORKSPACES[] = "QmlDesigner.Menu.Window.Workspaces";
const int MODELNODE_PREVIEW_IMAGE_DIMENSIONS = 150;
namespace Internal {
enum { debug = 0 };
}

View File

@@ -188,6 +188,8 @@ Project {
"commands/inputeventcommand.h",
"commands/view3dactioncommand.cpp",
"commands/view3dactioncommand.h",
"commands/requestmodelnodepreviewimagecommand.cpp",
"commands/requestmodelnodepreviewimagecommand.h",
"container/addimportcontainer.cpp",
"container/addimportcontainer.h",
"container/idcontainer.cpp",