diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index 856ff32390d..74498f185b0 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ #include "assetexporter.h" +#include "assetexportpluginconstants.h" #include "componentexporter.h" #include "exportnotification.h" @@ -154,21 +155,47 @@ bool AssetExporter::isBusy() const m_currentState == AssetExporter::ParsingState::WritingJson; } -Utils::FilePath AssetExporter::exportAsset(const QmlObjectNode &node, const Component *component, - const QString &uuid) +const QPixmap &AssetExporter::generateAsset(const ModelNode &node) { + static QPixmap nullPixmap; if (m_cancelled) + return nullPixmap; + + const QString uuid = node.auxiliaryData(Constants::UuidAuxTag).toString(); + QTC_ASSERT(!uuid.isEmpty(), return nullPixmap); + + if (!m_assets.contains(uuid)) { + // Generate asset. + QmlObjectNode objectNode(node); + QPixmap asset = objectNode.toQmlItemNode().instanceRenderPixmap(); + m_assets[uuid] = asset; + } + return m_assets[uuid]; +} + +Utils::FilePath AssetExporter::assetPath(const ModelNode &node, const Component *component, + const QString &suffix) const +{ + const QString uuid = node.auxiliaryData(Constants::UuidAuxTag).toString(); + if (!component || uuid.isEmpty()) return {}; - const Utils::FilePath assetExportDir = m_perComponentExport ? componentExportDir(component) : - m_exportPath; - const QString fileName = uuid + ".png"; - const Utils::FilePath assetPath = assetExportDir.pathAppended("assets").pathAppended(fileName); - if (m_assetDumper) - m_assetDumper->dumpAsset(node.toQmlItemNode().instanceRenderPixmap(), assetPath); + + const Utils::FilePath assetExportDir = + m_perComponentExport ? componentExportDir(component) : m_exportPath; + const Utils::FilePath assetPath = assetExportDir.pathAppended("assets") + .pathAppended(uuid + suffix + ".png"); return assetPath; } +void AssetExporter::exportAsset(const QPixmap &asset, const Utils::FilePath &path) +{ + if (m_cancelled || !m_assetDumper) + return; + + m_assetDumper->dumpAsset(asset, path); +} + void AssetExporter::exportComponent(const ModelNode &rootNode) { qCDebug(loggerInfo) << "Exporting component" << rootNode.id(); diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h index cd5b302e166..55b1432d223 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h @@ -71,8 +71,10 @@ public: void cancel(); bool isBusy() const; - Utils::FilePath exportAsset(const QmlObjectNode& node, const Component *component, - const QString &uuid); + const QPixmap &generateAsset(const ModelNode &node); + Utils::FilePath assetPath(const ModelNode &node, const Component *component, + const QString &suffix = {}) const; + void exportAsset(const QPixmap &asset, const Utils::FilePath &path); QByteArray generateUuid(const ModelNode &node); signals: @@ -108,6 +110,7 @@ private: bool m_perComponentExport = false; std::vector> m_components; QSet m_usedHashes; + QHash m_assets; std::unique_ptr m_assetDumper; bool m_cancelled = false; }; diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportpluginconstants.h b/src/plugins/qmldesigner/assetexporterplugin/assetexportpluginconstants.h index 5f09b748603..36033a5ea2e 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexportpluginconstants.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportpluginconstants.h @@ -63,6 +63,7 @@ const char ImportsTag[] = "extraImports"; const char UuidTag[] = "uuid"; const char ClipTag[] = "clip"; const char AssetDataTag[] = "assetData"; +const char ReferenceAssetTag[] = "referenceAsset"; const char AssetPathTag[] = "assetPath"; const char AssetBoundsTag[] = "assetBounds"; const char OpacityTag[] = "opacity"; diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp index a84cfe72c3e..d3e2edfc82b 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp @@ -31,6 +31,7 @@ #include "model.h" #include "nodeabstractproperty.h" #include "nodemetainfo.h" +#include "qmlitemnode.h" #include "rewriterview.h" #include "utils/qtcassert.h" @@ -38,6 +39,7 @@ #include #include #include +#include namespace { Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.modelExporter", QtInfoMsg) @@ -86,6 +88,7 @@ void Component::exportComponent() // Change the export type to component QJsonObject metadata = m_json.value(MetadataTag).toObject(); metadata.insert(ExportTypeTag, ExportTypeComponent); + addReferenceAsset(metadata); m_json.insert(MetadataTag, metadata); addImports(); } @@ -152,6 +155,37 @@ QJsonObject Component::nodeToJson(const ModelNode &node) return jsonObject; } +void Component::addReferenceAsset(QJsonObject &metadataObject) const +{ + QPixmap refAsset = m_exporter.generateAsset(m_rootNode); + stichChildrendAssets(m_rootNode, refAsset); + Utils::FilePath refAssetPath = m_exporter.assetPath(m_rootNode, this, "_ref"); + m_exporter.exportAsset(refAsset, refAssetPath); + QJsonObject assetData; + if (metadataObject.contains(AssetDataTag)) + assetData = metadataObject[AssetDataTag].toObject(); + assetData.insert(ReferenceAssetTag, refAssetPath.toString()); + metadataObject.insert(AssetDataTag, assetData); +} + +void Component::stichChildrendAssets(const ModelNode &node, QPixmap &parentPixmap) const +{ + if (!node.hasAnySubModelNodes()) + return; + + QPainter painter(&parentPixmap); + for (const ModelNode &child : node.directSubModelNodes()) { + QPixmap childPixmap = m_exporter.generateAsset(child); + if (childPixmap.isNull()) + continue; + stichChildrendAssets(child, childPixmap); + QTransform cTransform = QmlObjectNode(child).toQmlItemNode().instanceTransform(); + painter.setTransform(cTransform); + painter.drawPixmap(QPoint(0, 0), childPixmap); + } + painter.end(); +} + void Component::addImports() { QJsonArray importsArray; diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h index 3f2fa6ee8a9..533586c3809 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h @@ -88,6 +88,8 @@ public: private: ModelNodeParser* createNodeParser(const ModelNode &node) const; QJsonObject nodeToJson(const ModelNode &node); + void addReferenceAsset(QJsonObject &metadataObject) const; + void stichChildrendAssets(const ModelNode &node, QPixmap &parentPixmap) const; void addImports(); private: diff --git a/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp b/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp index b498efbd35a..75111848156 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/parsers/assetnodeparser.cpp @@ -54,10 +54,12 @@ QJsonObject AssetNodeParser::json(Component &component) const { QJsonObject jsonObject = ItemNodeParser::json(component); - Utils::FilePath assetPath = component.exporter().exportAsset(objectNode(), &component, uuid()); + AssetExporter &exporter = component.exporter(); + const Utils::FilePath assetPath = exporter.assetPath(m_node, &component); + exporter.exportAsset(exporter.generateAsset(m_node), assetPath); + QJsonObject assetData; assetData.insert(AssetPathTag, assetPath.toString()); - QJsonObject metadata = jsonObject.value(MetadataTag).toObject(); metadata.insert(AssetDataTag, assetData); jsonObject.insert(MetadataTag, metadata);