From 1547929037bfff538188a2f4ad77037737f3d5a6 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 23 Dec 2020 14:58:58 +0200 Subject: [PATCH] QmlDesigner: Implement new asset drags Drag image to existing image/texture type - Update source property. Drag image containing multiple frames - Create AnimatedImage. Drag sound - Create new SoundEffect or update an existing one. Drag shader - Create new Shader or update an existing one. Drag font - Create new Text or update font on an existing one. Fixes: QDS-3389 Change-Id: I62cf964bbba7772ecbf6f1c6fadb0f9e41a86206 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../formeditor/abstractformeditortool.cpp | 5 +- .../components/formeditor/dragtool.cpp | 63 +++++-- .../components/formeditor/dragtool.h | 1 + .../itemlibrary/customfilesystemmodel.cpp | 43 ++++- .../itemlibrary/customfilesystemmodel.h | 3 + .../itemlibrary/itemlibraryresourceview.cpp | 33 ++-- .../navigator/navigatortreemodel.cpp | 171 +++++++++++++++++- .../components/navigator/navigatortreemodel.h | 3 + .../designercore/include/qmlitemnode.h | 11 ++ .../designercore/model/qmlitemnode.cpp | 56 +++++- 10 files changed, 352 insertions(+), 37 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp index fc7e8b97c7b..ec856fa5ca8 100644 --- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp @@ -234,8 +234,9 @@ void AbstractFormEditorTool::dropEvent(const QList &/*itemList*/ void AbstractFormEditorTool::dragEnterEvent(const QList &itemList, QGraphicsSceneDragDropEvent *event) { - if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo")) || - event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.libraryresource"))) { + if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo")) + || event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.libraryresource.image")) + || event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.libraryresource.font"))) { event->accept(); view()->changeToDragTool(); view()->currentTool()->dragEnterEvent(itemList, event); diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index 8bd2d827f5e..39ef7a37f52 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -136,6 +136,26 @@ void DragTool::createQmlItemNodeFromImage(const QString &imageName, } } +void DragTool::createQmlItemNodeFromFont(const QString &fontFamily, + const QmlItemNode &parentNode, + const QPointF &scenePos) +{ + if (parentNode.isValid()) { + MetaInfo metaInfo = MetaInfo::global(); + + FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode); + QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform() + .inverted().map(scenePos); + + m_dragNode = QmlItemNode::createQmlItemNodeFromFont(view(), fontFamily, positonInItemSpace, + parentNode); + + QList nodeList; + nodeList.append(m_dragNode); + m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList)); + } +} + FormEditorItem *DragTool::targetContainerOrRootItem(const QList &itemList, FormEditorItem *currentItem) { FormEditorItem *formEditorItem = containerFormEditorItem(itemList, {currentItem}); @@ -208,25 +228,29 @@ static bool canBeDropped(const QMimeData *mimeData) return NodeHints::fromItemLibraryEntry(itemLibraryEntryFromMimeData(mimeData)).canBeDroppedInFormEditor(); } -static bool canHandleMimeData(const QMimeData *mimeData) -{ - return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")) - || mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource")); -} - -static bool dragAndDropPossible(const QMimeData *mimeData) -{ - return canHandleMimeData(mimeData) && canBeDropped(mimeData); -} - static bool hasItemLibraryInfo(const QMimeData *mimeData) { return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo")); } -static bool hasLibraryResources(const QMimeData *mimeData) +static bool hasImageResource(const QMimeData *mimeData) { - return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource")); + return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource.image")); +} + +static bool hasFontResource(const QMimeData *mimeData) +{ + return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource.font")); +} + +static bool canHandleMimeData(const QMimeData *mimeData) +{ + return hasItemLibraryInfo(mimeData) || hasImageResource(mimeData) || hasFontResource(mimeData); +} + +static bool dragAndDropPossible(const QMimeData *mimeData) +{ + return canHandleMimeData(mimeData) && canBeDropped(mimeData); } void DragTool::dropEvent(const QList &/*itemList*/, QGraphicsSceneDragDropEvent *event) @@ -290,11 +314,16 @@ void DragTool::dragLeaveEvent(const QList &/*itemList*/, QGraph view()->changeToSelectionTool(); } -static QString libraryResourceImageName(const QMimeData *mimeData) +static QString libraryResourceFile(const QMimeData *mimeData) { return QString::fromUtf8((mimeData->data(QStringLiteral("application/vnd.bauhaus.libraryresource")))); } +static QString libraryResourceFont(const QMimeData *mimeData) +{ + return QString::fromUtf8((mimeData->data(QStringLiteral("application/vnd.bauhaus.libraryresource.font")))); +} + void DragTool::createDragNode(const QMimeData *mimeData, const QPointF &scenePosition, const QList &itemList) { if (!m_dragNode.hasModelNode()) { @@ -306,8 +335,10 @@ void DragTool::createDragNode(const QMimeData *mimeData, const QPointF &scenePos if (hasItemLibraryInfo(mimeData)) createQmlItemNode(itemLibraryEntryFromMimeData(mimeData), targetContainerQmlItemNode, scenePosition); - else if (hasLibraryResources(mimeData)) - createQmlItemNodeFromImage(libraryResourceImageName(mimeData), targetContainerQmlItemNode, scenePosition); + else if (hasImageResource(mimeData)) + createQmlItemNodeFromImage(libraryResourceFile(mimeData), targetContainerQmlItemNode, scenePosition); + else if (hasFontResource(mimeData)) + createQmlItemNodeFromFont(libraryResourceFont(mimeData), targetContainerQmlItemNode, scenePosition); m_blockMove = true; m_startPoint = scenePosition; diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 017177fc204..fee59b1bc95 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -81,6 +81,7 @@ protected: void abort(); void createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, const QmlItemNode &parentNode, const QPointF &scenePos); void createQmlItemNodeFromImage(const QString &imageName, const QmlItemNode &parentNode, const QPointF &scenePos); + void createQmlItemNodeFromFont(const QString &fontFamily, const QmlItemNode &parentNode, const QPointF &scenePos); FormEditorItem *targetContainerOrRootItem(const QList &itemList, FormEditorItem *urrentItem = nullptr); void begin(QPointF scenePos); void end(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp index 4d0d9e5462f..1a1f7b1b941 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.cpp @@ -53,6 +53,12 @@ static const QStringList &supportedImageSuffixes() return retList; } +static const QStringList &supportedFragmentShaderSuffixes() +{ + static const QStringList retList {"frag", "glsl", "glslf", "fsh"}; + return retList; +} + static const QStringList &supportedShaderSuffixes() { static const QStringList retList {"frag", "vert", @@ -131,6 +137,14 @@ static QPixmap generateFontImage(const QFileInfo &info, const QSize &size) return fontImageCache[key]; } +QString fontFamily(const QFileInfo &info) +{ + QRawFont font(info.absoluteFilePath(), 10); + if (font.isValid()) + return font.familyName(); + return {}; +} + class ItemLibraryFileIconProvider : public QFileIconProvider { public: @@ -147,7 +161,7 @@ public: if (supportedImageSuffixes().contains(suffix)) pixmap.load(info.absoluteFilePath()); - else if (supportedFontSuffixes().contains(suffix)) + else if (supportedFontSuffixes().contains(suffix)) pixmap = generateFontImage(info, iconSize); if (pixmap.isNull()) @@ -162,8 +176,8 @@ public: return icon; } - // Generated icon sizes should match ItemLibraryResourceView icon sizes - QList iconSizes = {{192, 192}, {96, 96}, {48, 48}, {32, 32}}; + // Generated icon sizes should match ItemLibraryResourceView needed icon sizes + QList iconSizes = {{192, 192}, {128, 128}, {96, 96}, {48, 48}, {32, 32}}; }; @@ -274,6 +288,29 @@ void CustomFileSystemModel::setSearchFilter(const QString &nameFilterList) setRootPath(m_fileSystemModel->rootPath()); } +QPair CustomFileSystemModel::resourceTypeAndData(const QModelIndex &index) const +{ + QFileInfo fi = fileInfo(index); + QString suffix = fi.suffix(); + if (!suffix.isEmpty()) { + if (supportedImageSuffixes().contains(suffix)) { + // Data: Image format (suffix) + return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; + } else if (supportedFontSuffixes().contains(suffix)) { + // Data: Font family name + return {"application/vnd.bauhaus.libraryresource.font", fontFamily(fi).toUtf8()}; + } else if (supportedShaderSuffixes().contains(suffix)) { + // Data: shader type, frament (f) or vertex (v) + return {"application/vnd.bauhaus.libraryresource.shader", + supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; + } else if (supportedAudioSuffixes().contains(suffix)) { + // No extra data for sounds + return {"application/vnd.bauhaus.libraryresource.sound", {}}; + } + } + return {}; +} + void CustomFileSystemModel::appendIfNotFiltered(const QString &file) { if (filterMetaIcons(file)) diff --git a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h b/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h index e0d8148ce65..ce552ccc231 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/customfilesystemmodel.h @@ -27,6 +27,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QFileIconProvider; @@ -60,6 +61,8 @@ public: Qt::ItemFlags flags(const QModelIndex &index) const override; void setSearchFilter(const QString &nameFilterList); + QPair resourceTypeAndData(const QModelIndex &index) const; + private: QModelIndex updatePath(const QString &newPath); QModelIndex fileSystemModelIndex(const QModelIndex &index) const; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp index ed522c42a5c..60b4eac3aed 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp @@ -108,23 +108,32 @@ void ItemLibraryResourceView::startDrag(Qt::DropActions /* supportedActions */) { if (debug) qDebug() << Q_FUNC_INFO; - QMimeData *mimeData = model()->mimeData(selectedIndexes()); - if (!mimeData) + const auto indexes = selectedIndexes(); + if (indexes.isEmpty()) + return; + + const QModelIndex &index = indexes.constFirst(); + if (!index.isValid()) return; auto fileSystemModel = qobject_cast(model()); Q_ASSERT(fileSystemModel); - QFileInfo fileInfo = fileSystemModel->fileInfo(selectedIndexes().constFirst()); - QPixmap pixmap(fileInfo.absoluteFilePath()); - if (!pixmap.isNull()) { - auto drag = new QDrag(this); - drag->setPixmap(QIcon(pixmap).pixmap(128, 128)); - auto mimeData = new QMimeData; - mimeData->setData(QLatin1String("application/vnd.bauhaus.libraryresource"), fileInfo.absoluteFilePath().toUtf8()); - drag->setMimeData(mimeData); - drag->exec(); - } + QPair typeAndData = fileSystemModel->resourceTypeAndData(index); + + if (typeAndData.first.isEmpty()) + return; + + QFileInfo fileInfo = fileSystemModel->fileInfo(index); + + auto drag = new QDrag(this); + drag->setPixmap(fileSystemModel->fileIcon(index).pixmap(128, 128)); + QMimeData *mimeData = new QMimeData; + mimeData->setData(QLatin1String("application/vnd.bauhaus.libraryresource"), + fileInfo.absoluteFilePath().toUtf8()); + mimeData->setData(typeAndData.first, typeAndData.second); + drag->setMimeData(mimeData); + drag->exec(); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index b3a2dbdef5e..df0288e3f49 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -498,8 +499,14 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (dropModelIndex.model() == this) { if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); - } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource")) { + } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.image")) { handleItemLibraryImageDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.font")) { + handleItemLibraryFontDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.shader")) { + handleItemLibraryShaderDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.sound")) { + handleItemLibrarySoundDrop(mimeData, rowNumber, dropModelIndex); } else if (mimeData->hasFormat("application/vnd.modelnode.list")) { handleInternalDrop(mimeData, rowNumber, dropModelIndex); } @@ -772,8 +779,10 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i targetNode.bindingProperty("texture").setExpression(newModelNode.validId()); } }); - } else if (targetNode.isSubclassOf("QtQuick3D.Texture")) { - // if dropping an image on a texture, set the texture source + } else if (targetNode.isSubclassOf("QtQuick3D.Texture") + || targetNode.isSubclassOf("QtQuick.Image") + || targetNode.isSubclassOf("QtQuick.BorderImage")) { + // if dropping an image on an existing texture or image, set the source targetNode.variantProperty("source").setValue(imagePath); } else { m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] { @@ -793,6 +802,162 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i } } +void NavigatorTreeModel::handleItemLibraryFontDrop(const QMimeData *mimeData, int rowNumber, + const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber); + if (foundTarget) { + ModelNode targetNode(modelNodeForIndex(rowModelIndex)); + + const QString fontFamily = QString::fromUtf8( + mimeData->data("application/vnd.bauhaus.libraryresource.font")); + + ModelNode newModelNode; + + m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryFontDrop", [&] { + if (targetNode.isSubclassOf("QtQuick.Text")) { + // if dropping into an existing Text, update font + targetNode.variantProperty("font.family").setValue(fontFamily); + } else { + // create a Text node + QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromFont( + m_view, fontFamily, QPointF(), targetProperty, false); + if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode())) + newModelNode = newItemNode.modelNode(); + else + newItemNode.destroy(); + } + }); + + if (newModelNode.isValid()) { + moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber); + m_view->setSelectedModelNode(newModelNode); + } + } +} + +void NavigatorTreeModel::handleItemLibraryShaderDrop(const QMimeData *mimeData, int rowNumber, + const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + Import import = Import::createLibraryImport(QStringLiteral("QtQuick3D")); + if (!m_view->model()->hasImport(import, true, true)) + return; + + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber); + if (foundTarget) { + ModelNode targetNode(modelNodeForIndex(rowModelIndex)); + ModelNode newModelNode; + + const QString shaderSource = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")); + const bool fragShader = mimeData->data("application/vnd.bauhaus.libraryresource.shader").startsWith('f'); + const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(shaderSource); + + m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryShaderDrop", [&] { + if (targetNode.isSubclassOf("QtQuick3D.Shader")) { + // if dropping into an existing Shader, update + if (fragShader) + targetNode.variantProperty("stage").setEnumeration("Shader.Fragment"); + else + targetNode.variantProperty("stage").setEnumeration("Shader.Vertex"); + targetNode.variantProperty("shader").setValue(relPath); + } else { + // create a new Shader + ItemLibraryEntry itemLibraryEntry; + itemLibraryEntry.setName("Shader"); + itemLibraryEntry.setType("QtQuick3D.Shader", 1, 0); + + // set shader properties + PropertyName prop = "shader"; + QString type = "QByteArray"; + QVariant val = relPath; + itemLibraryEntry.addProperty(prop, type, val); + prop = "stage"; + type = "enum"; + val = fragShader ? "Shader.Fragment" : "Shader.Vertex"; + itemLibraryEntry.addProperty(prop, type, val); + + // create a texture + newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, + targetProperty, false); + + // Rename the node based on shader source + QFileInfo fi(relPath); + newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), + "shader")); + } + }); + + if (newModelNode.isValid()) { + moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber); + m_view->setSelectedModelNode(newModelNode); + } + } +} + +void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber, + const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + Import import = Import::createLibraryImport(QStringLiteral("QtMultimedia")); + if (!m_view->model()->hasImport(import, true, true)) + return; + + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber); + if (foundTarget) { + ModelNode targetNode(modelNodeForIndex(rowModelIndex)); + ModelNode newModelNode; + + const QString soundSource = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")); + const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(soundSource); + + m_view->executeInTransaction("NavigatorTreeModel::handleItemLibrarySoundDrop", [&] { + if (targetNode.isSubclassOf("QtMultimedia.SoundEffect")) { + // if dropping into on an existing SoundEffect, update + targetNode.variantProperty("source").setValue(relPath); + } else { + // create a new SoundEffect + ItemLibraryEntry itemLibraryEntry; + itemLibraryEntry.setName("SoundEffect"); + itemLibraryEntry.setType("QtMultimedia.SoundEffect", 1, 0); + + // set shader properties + PropertyName prop = "source"; + QString type = "QUrl"; + QVariant val = relPath; + itemLibraryEntry.addProperty(prop, type, val); + + // create a texture + newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, + targetProperty, false); + + // Rename the node based on source + QFileInfo fi(relPath); + newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), + "soundEffect")); + } + }); + + if (newModelNode.isValid()) { + moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber); + m_view->setSelectedModelNode(newModelNode); + } + } +} + TypeName propertyType(const NodeAbstractProperty &property) { return property.parentModelNode().metaInfo().propertyTypeName(property.name()); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index bb2712148df..acde4a01763 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -115,6 +115,9 @@ private: void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryImageDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleItemLibraryFontDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleItemLibraryShaderDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); QList nodesToPersistentIndex(const QList &modelNodes); QPointer m_view; diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h index cd336b81d58..be672a2cc33 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h @@ -69,6 +69,17 @@ public: NodeAbstractProperty parentproperty, bool executeInTransaction = true); + static QmlItemNode createQmlItemNodeFromFont(AbstractView *view, + const QString &fontFamily, + const QPointF &position, + QmlItemNode parentQmlItemNode, + bool executeInTransaction = true); + static QmlItemNode createQmlItemNodeFromFont(AbstractView *view, + const QString &fontFamily, + const QPointF &position, + NodeAbstractProperty parentproperty, + bool executeInTransaction = true); + QList children() const; QList resources() const; QList allDirectSubNodes() const; diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 606d7a7c22a..683adedd2a7 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -106,7 +107,12 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromImage(AbstractView *view, const QS propertyPairList.append({PropertyName("source"), QVariant(relativeImageName)}); } - newQmlItemNode = QmlItemNode(view->createModelNode("QtQuick.Image", metaInfo.majorVersion(), metaInfo.minorVersion(), propertyPairList)); + TypeName type("QtQuick.Image"); + QImageReader reader(imageName); + if (reader.supportsAnimation()) + type = "QtQuick.AnimatedImage"; + + newQmlItemNode = QmlItemNode(view->createModelNode(type, metaInfo.majorVersion(), metaInfo.minorVersion(), propertyPairList)); parentproperty.reparentHere(newQmlItemNode); QFileInfo fi(relativeImageName); @@ -125,6 +131,54 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromImage(AbstractView *view, const QS return newQmlItemNode; } +QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view, + const QString &fontFamily, + const QPointF &position, + QmlItemNode parentQmlItemNode, + bool executeInTransaction) +{ + if (!parentQmlItemNode.isValid()) + parentQmlItemNode = QmlItemNode(view->rootModelNode()); + + NodeAbstractProperty parentProperty = parentQmlItemNode.defaultNodeAbstractProperty(); + + return QmlItemNode::createQmlItemNodeFromFont(view, fontFamily, position, + parentProperty, executeInTransaction); +} + +QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view, + const QString &fontFamily, + const QPointF &position, + NodeAbstractProperty parentproperty, + bool executeInTransaction) +{ + QmlItemNode newQmlItemNode; + + auto doCreateQmlItemNodeFromFont = [=, &newQmlItemNode, &parentproperty]() { + NodeMetaInfo metaInfo = view->model()->metaInfo("QtQuick.Text"); + QList> propertyPairList; + propertyPairList.append({PropertyName("x"), QVariant(qRound(position.x()))}); + propertyPairList.append({PropertyName("y"), QVariant(qRound(position.y()))}); + propertyPairList.append({PropertyName("font.family"), QVariant(fontFamily)}); + propertyPairList.append({PropertyName("text"), QVariant(fontFamily)}); + + newQmlItemNode = QmlItemNode(view->createModelNode("QtQuick.Text", metaInfo.majorVersion(), + metaInfo.minorVersion(), propertyPairList)); + parentproperty.reparentHere(newQmlItemNode); + + newQmlItemNode.setId(view->generateNewId("text", "text")); + + Q_ASSERT(newQmlItemNode.isValid()); + }; + + if (executeInTransaction) + view->executeInTransaction("QmlItemNode::createQmlItemNodeFromImage", doCreateQmlItemNodeFromFont); + else + doCreateQmlItemNodeFromFont(); + + return newQmlItemNode; +} + bool QmlItemNode::isValid() const { return isValidQmlItemNode(modelNode());