diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc index e8d66548c32..05459423349 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc @@ -32,7 +32,6 @@ mockfiles/qt6/FadeHandle.qml mockfiles/qt6/HelperGrid.qml mockfiles/qt6/IconGizmo.qml - mockfiles/qt6/IconRenderer3D.qml mockfiles/qt6/LightGizmo.qml mockfiles/qt6/LightIconGizmo.qml mockfiles/qt6/LightModel.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index 06320524bf3..c36d8c227c3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -32,7 +32,7 @@ View3D { property Material previewMaterial - function fitToViewPort() + function fitToViewPort(closeUp) { // No need to zoom this view, this is here just to avoid runtime warnings } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index de3e3ee431c..a6d5c6b1db5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -41,6 +41,8 @@ Item { property var modelViewComponent property var nodeViewComponent + property bool closeUp: false + function destroyView() { previewObject = null; @@ -96,7 +98,15 @@ Item { function fitToViewPort() { - view.fitToViewPort(); + view.fitToViewPort(closeUp); + } + + // Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins + // and the background is removed, in order to generate a preview suitable for library icons. + function setIconMode(enable) + { + closeUp = enable; + backgroundRect.visible = !enable; } View3D { @@ -108,10 +118,15 @@ Item { id: contentItem anchors.fill: parent - Rectangle { + Item { id: viewRect anchors.fill: parent + } + Rectangle { + id: backgroundRect + anchors.fill: parent + z: -1 gradient: Gradient { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index e61a9a8fb25..5c8b9e1cd72 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -34,11 +34,11 @@ View3D { property Model sourceModel - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml index 91008abb251..e8931719d7f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml @@ -32,11 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml deleted file mode 100644 index 623bf21cdec..00000000000 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconRenderer3D.qml +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -import QtQuick 6.0 -import QtQuick3D 6.0 - -Item { - id: viewRoot - width: 1024 - height: 1024 - visible: true - - property alias view3D: view3D - property alias camPos: viewCamera.position - - function setSceneToBox() - { - selectionBox.targetNode = view3D.importScene; - } - - function fitAndHideBox() - { - cameraControl.focusObject(selectionBox.model, viewCamera.eulerRotation, true, true); - if (cameraControl._zoomFactor < 0.1) - view3D.importScene.scale = view3D.importScene.scale.times(10); - if (cameraControl._zoomFactor > 10) - view3D.importScene.scale = view3D.importScene.scale.times(0.1); - - selectionBox.visible = false; - } - - View3D { - id: view3D - camera: viewCamera - environment: sceneEnv - - SceneEnvironment { - id: sceneEnv - antialiasingMode: SceneEnvironment.MSAA - antialiasingQuality: SceneEnvironment.VeryHigh - } - - PerspectiveCamera { - id: viewCamera - position: Qt.vector3d(-200, 200, 200) - eulerRotation: Qt.vector3d(-45, -45, 0) - } - - DirectionalLight { - rotation: viewCamera.rotation - } - - SelectionBox { - id: selectionBox - view3D: view3D - geometryName: "SB" - } - - EditCameraController { - id: cameraControl - camera: view3D.camera - view3d: view3D - ignoreToolState: true - } - } -} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index aae5891e082..ed5cfea56f4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -32,7 +32,7 @@ View3D { property Material previewMaterial - function fitToViewPort() + function fitToViewPort(closeUp) { // No need to zoom this view, this is here just to avoid runtime warnings } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 4bd07e57d12..5caac0047c4 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -41,6 +41,8 @@ Item { property var modelViewComponent property var nodeViewComponent + property bool closeUp: false + function destroyView() { previewObject = null; @@ -96,17 +98,30 @@ Item { function fitToViewPort() { - view.fitToViewPort(); + view.fitToViewPort(closeUp); + } + + // Enables/disables icon mode. When in icon mode, camera is zoomed bit closer to reduce margins + // and the background is removed, in order to generate a preview suitable for library icons. + function setIconMode(enable) + { + closeUp = enable; + backgroundRect.visible = !enable; } Item { id: contentItem anchors.fill: parent - Rectangle { + Item { id: viewRect anchors.fill: parent + } + Rectangle { + id: backgroundRect + anchors.fill: parent + z: -1 gradient: Gradient { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 19b3c4c35d7..1762e3c9a4d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -34,11 +34,11 @@ View3D { property Model sourceModel - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml index a48eb665191..7bbfbf281ac 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml @@ -32,11 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - function fitToViewPort() + function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, - 1040); + 1040, closeUp); } SceneEnvironment { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 3b774c3f4a6..7e843012be6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -308,7 +308,7 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul // and recalculating bounds for every frame is not a problem. void GeneralHelper::calculateNodeBoundsAndFocusCamera( QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, - float defaultLookAtDistance) + float defaultLookAtDistance, bool closeUp) { QVector3D minBounds; QVector3D maxBounds; @@ -317,7 +317,9 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera( QVector3D extents = maxBounds - minBounds; QVector3D lookAt = minBounds + (extents / 2.f); - float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z())); + float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x()) + + qreal(extents.y()) * qreal(extents.y()) + + qreal(extents.z()) * qreal(extents.z())); // Reset camera position to default zoom QMatrix4x4 m = camera->sceneTransform(); @@ -328,9 +330,27 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera( camera->setPosition(lookAt + newLookVector); - float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function + // CloseUp divisor is used for icon generation, where we can allow some extreme models to go + // slightly out of bounds for better results generally. The other divisor is used for other + // previews, where the image is larger to begin with and we would also like some margin + // between preview edge and the rendered model, so we can be more conservative with the zoom. + // The divisor values are empirically selected to provide nice result. + float divisor = closeUp ? 1250.f : 1050.f; + float newZoomFactor = maxExtent / divisor; zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); + + if (auto perspectiveCamera = qobject_cast(camera)) { + // Fix camera near/far clips in case we are dealing with extreme zooms + const float cameraDist = qAbs((camera->position() - lookAt).length()); + const float minDist = cameraDist - (maxExtent / 2.f); + const float maxDist = cameraDist + (maxExtent / 2.f); + if (minDist < perspectiveCamera->clipNear() || maxDist > perspectiveCamera->clipFar()) { + perspectiveCamera->setClipNear(minDist * 0.99); + perspectiveCamera->setClipFar(maxDist * 1.01); + } + + } } // Aligns any cameras found in nodes list to a camera. @@ -823,12 +843,13 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec if (auto childNode = qobject_cast(child)) { QVector3D newMinBounds = minBounds; QVector3D newMaxBounds = maxBounds; - hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); // Ignore any subtrees that do not have Model in them as we don't need those // for visual bounds calculations - if (hasModel) { + if (childHasModel) { minBoundsVec << newMinBounds; maxBoundsVec << newMaxBounds; + hasModel = true; } } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 562848c7720..98974cfda9f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -77,7 +77,7 @@ public: bool closeUp = false); Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, - float defaultLookAtDistance); + float defaultLookAtDistance, bool closeUp); Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes); Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes, const QVector3D &lookAtPoint); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp index 589f57cb5f1..cae64ad04c1 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.cpp @@ -57,6 +57,9 @@ void Quick3DRenderableNodeInstance::initialize(const ObjectNodeInstance::Pointer // In case this is the scene root, we need to create a dummy View3D for the scene // in preview puppets if (instanceId() == 0 && (!nodeInstanceServer()->isInformationServer())) { + nodeInstanceServer()->quickWindow()->setDefaultAlphaBuffer(true); + nodeInstanceServer()->quickWindow()->setColor(Qt::transparent); + auto helper = new QmlDesigner::Internal::GeneralHelper(); engine()->rootContext()->setContextProperty("_generalHelper", helper); @@ -199,6 +202,14 @@ QQuickItem *Quick3DRenderableNodeInstance::contentItem() const return m_dummyRootView; } +void Quick3DRenderableNodeInstance::setPropertyVariant(const PropertyName &name, + const QVariant &value) +{ + if (m_dummyRootView && name == "isLibraryIcon") + QMetaObject::invokeMethod(m_dummyRootView, "setIconMode", Q_ARG(QVariant, value)); + ObjectNodeInstance::setPropertyVariant(name, value); +} + Qt5NodeInstanceServer *Quick3DRenderableNodeInstance::qt5NodeInstanceServer() const { return qobject_cast(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h index ae03cb1b90f..208144cb52f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3drenderablenodeinstance.h @@ -52,6 +52,7 @@ public: QList stateInstances() const override; QQuickItem *contentItem() const override; + void setPropertyVariant(const PropertyName &name, const QVariant &value) override; protected: explicit Quick3DRenderableNodeInstance(QObject *node); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index 7e22efe016f..e3aae0cb7d5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -401,7 +401,6 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) qmlInfo.append(outDir.relativeFilePath(qmlIt.filePath())); qmlInfo.append('\n'); - // Generate item library icon for qml file based on root component QFile qmlFile(qmlIt.filePath()); if (qmlFile.open(QIODevice::ReadOnly)) { QString iconFileName = outDir.path() + '/' @@ -410,6 +409,8 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) QString iconFileName2x = iconFileName + "@2x"; QByteArray content = qmlFile.readAll(); int braceIdx = content.indexOf('{'); + QString impVersionStr; + int impVersionMajor = -1; if (braceIdx != -1) { int nlIdx = content.lastIndexOf('\n', braceIdx); QByteArray rootItem = content.mid(nlIdx, braceIdx - nlIdx).trimmed(); @@ -423,8 +424,9 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) out << "canBeDroppedInView3D: true" << Qt::endl; file.close(); - // Add quick3D import unless it is already added - if (m_requiredImports.first().url() != "QtQuick3D") { + // Assume that all assets import the same QtQuick3D version, + // since they are being imported with same kit + if (impVersionMajor == -1) { QByteArray import3dStr{"import QtQuick3D"}; int importIdx = content.indexOf(import3dStr); if (importIdx != -1 && importIdx < braceIdx) { @@ -433,15 +435,25 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) QByteArray versionStr = content.mid(importIdx, nlIdx - importIdx).trimmed(); // There could be 'as abc' after version, so just take first part QList parts = versionStr.split(' '); - QString impVersion; - if (parts.size() >= 1) - impVersion = QString::fromUtf8(parts[0]); - m_requiredImports.prepend(Import::createLibraryImport( - "QtQuick3D", impVersion)); + if (parts.size() >= 1) { + impVersionStr = QString::fromUtf8(parts[0]); + if (impVersionStr.isEmpty()) + impVersionMajor = 6; + else + impVersionMajor = impVersionStr.left(1).toInt(); + } } } + + // Add quick3D import unless it is already added + if (impVersionMajor > 0 + && m_requiredImports.first().url() != "QtQuick3D") { + m_requiredImports.prepend(Import::createLibraryImport( + "QtQuick3D", impVersionStr)); + } } - if (startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6 + && startIconProcess(24, iconFileName, qmlIt.filePath())) { // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp index e7dbbee0857..5144a5220fb 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp @@ -92,7 +92,9 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS } }, Qt::QueuedConnection); - }); + }, + "libIcon", + ImageCache::LibraryIconAuxiliaryData{true}); return response.release(); } diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 530724315a0..7890086bd5f 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -74,7 +74,7 @@ ImageCacheCollector::~ImageCacheCollector() = default; void ImageCacheCollector::start(Utils::SmallStringView name, Utils::SmallStringView state, - const ImageCache::AuxiliaryData &, + const ImageCache::AuxiliaryData &auxiliaryData, CaptureCallback captureCallback, AbortCallback abortCallback) { @@ -96,13 +96,22 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); + bool is3DRoot = !rewriterView.inErrorState() + && (rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") + || rewriterView.rootModelNode().isSubclassOf("Quick3D.Material")); + if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() - && !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) { + && !is3DRoot)) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); return; } + if (is3DRoot) { + if (auto libIcon = Utils::get_if(&auxiliaryData)) + rewriterView.rootModelNode().setAuxiliaryData("isLibraryIcon@NodeInstance", libIcon->enable); + } + ModelNode stateNode = rewriterView.modelNodeForId(QString{state}); if (stateNode.isValid()) diff --git a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h index ae87681626a..61660271fc9 100644 --- a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h +++ b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h @@ -54,7 +54,16 @@ public: QString text; }; -using AuxiliaryData = Utils::variant; +class LibraryIconAuxiliaryData +{ +public: + bool enable; +}; + +using AuxiliaryData = Utils::variant; enum class AbortReason : char { Abort, Failed }; diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index 9ff3289e459..342e0a65fb6 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -445,10 +445,9 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const QString iconPath = qmlIt.fileInfo().absolutePath() + '/' + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name + Constants::QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX; - if (!QFileInfo::exists(iconPath)) - iconPath = defaultIconPath; - itemLibraryEntry.setLibraryEntryIconPath(iconPath); - itemLibraryEntry.setTypeIcon(QIcon(iconPath)); + if (QFileInfo::exists(iconPath)) + itemLibraryEntry.setLibraryEntryIconPath(iconPath); + itemLibraryEntry.setTypeIcon(QIcon(defaultIconPath)); // load hints file if exists QFile hintsFile(qmlIt.fileInfo().absolutePath() + '/' + name + ".hints");