QmlDesigner: Add user texture bundle

Fixes: QDS-12390
Change-Id: I512a8748bbb6a282589f05293507c110162e7f1d
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Mahmoud Badri
2024-04-09 17:50:11 +03:00
parent ece3a60cfa
commit 4591293fd9
12 changed files with 88 additions and 28 deletions

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick import QtQuick
import Qt.labs.qmlmodels
import HelperWidgets as HelperWidgets import HelperWidgets as HelperWidgets
import StudioControls as StudioControls import StudioControls as StudioControls
import StudioTheme as StudioTheme import StudioTheme as StudioTheme
@@ -99,17 +100,33 @@ HelperWidgets.ScrollView {
id: repeater id: repeater
model: categoryItems model: categoryItems
delegate: ContentLibraryMaterial { delegate: DelegateChooser {
width: root.cellWidth role: "itemType"
height: root.cellHeight
importerRunning: ContentLibraryBackend.userModel.importerRunning DelegateChoice {
roleValue: "material"
ContentLibraryMaterial {
width: root.cellWidth
height: root.cellHeight
onShowContextMenu: ctxMenu.popupMenu(modelData) importerRunning: ContentLibraryBackend.userModel.importerRunning
onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
onVisibleChanged: { onShowContextMenu: ctxMenu.popupMenu(modelData)
section.numVisibleItem += visible ? 1 : -1 onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
onVisibleChanged: {
section.numVisibleItem += visible ? 1 : -1
}
}
}
DelegateChoice {
roleValue: "texture"
delegate: ContentLibraryTexture {
width: root.cellWidth
height: root.cellHeight
// onShowContextMenu: ctxMenu.popupMenu(modelData) // TODO
}
} }
} }

View File

@@ -21,6 +21,7 @@ class ContentLibraryMaterial : public QObject
Q_PROPERTY(QString bundleMaterialBaseWebUrl MEMBER m_baseWebUrl CONSTANT) Q_PROPERTY(QString bundleMaterialBaseWebUrl MEMBER m_baseWebUrl CONSTANT)
Q_PROPERTY(QString bundleMaterialParentPath READ parentDirPath CONSTANT) Q_PROPERTY(QString bundleMaterialParentPath READ parentDirPath CONSTANT)
Q_PROPERTY(QStringList bundleMaterialFiles READ allFiles CONSTANT) Q_PROPERTY(QStringList bundleMaterialFiles READ allFiles CONSTANT)
Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
public: public:
ContentLibraryMaterial(QObject *parent, ContentLibraryMaterial(QObject *parent,
@@ -65,6 +66,7 @@ private:
QString m_downloadPath; QString m_downloadPath;
QString m_baseWebUrl; QString m_baseWebUrl;
QStringList m_allFiles; QStringList m_allFiles;
const QString m_itemType = "material";
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -12,10 +12,10 @@
namespace QmlDesigner { namespace QmlDesigner {
ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo,
const QString &dirPath, const QString &key, const QString &dirPath, const QString &suffix,
const QString &textureUrl, const QString &iconUrl, const QSize &dimensions, const qint64 sizeInBytes,
const QString &suffix, const QSize &dimensions, const QString &key, const QString &textureUrl,
const qint64 sizeInBytes, bool hasUpdate, bool isNew) const QString &iconUrl, bool hasUpdate, bool isNew)
: QObject(parent) : QObject(parent)
, m_iconPath(iconFileInfo.filePath()) , m_iconPath(iconFileInfo.filePath())
, m_dirPath(dirPath) , m_dirPath(dirPath)
@@ -82,10 +82,10 @@ QString ContentLibraryTexture::resolveToolTipText()
QString imageInfo; QString imageInfo;
if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) { if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) {
imageInfo = ImageUtils::imageInfo(m_dimensions, m_sizeInBytes); imageInfo = ImageUtils::imageInfoString(m_dimensions, m_sizeInBytes);
} else { } else {
QString fullDownloadPath = m_dirPath + '/' + fileName; QString fullDownloadPath = m_dirPath + '/' + fileName;
imageInfo = ImageUtils::imageInfo(fullDownloadPath); imageInfo = ImageUtils::imageInfoString(fullDownloadPath);
} }
return QString("%1\n%2").arg(fileName, imageInfo); return QString("%1\n%2").arg(fileName, imageInfo);

View File

@@ -24,12 +24,13 @@ class ContentLibraryTexture : public QObject
Q_PROPERTY(bool textureHasUpdate WRITE setHasUpdate READ hasUpdate NOTIFY hasUpdateChanged) Q_PROPERTY(bool textureHasUpdate WRITE setHasUpdate READ hasUpdate NOTIFY hasUpdateChanged)
Q_PROPERTY(bool textureIsNew MEMBER m_isNew CONSTANT) Q_PROPERTY(bool textureIsNew MEMBER m_isNew CONSTANT)
Q_PROPERTY(QString textureKey MEMBER m_textureKey CONSTANT) Q_PROPERTY(QString textureKey MEMBER m_textureKey CONSTANT)
Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
public: public:
ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, const QString &dirPath, ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, const QString &dirPath,
const QString &key, const QString &textureUrl, const QString &iconUrl,
const QString &suffix, const QSize &dimensions, const qint64 sizeInBytes, const QString &suffix, const QSize &dimensions, const qint64 sizeInBytes,
bool hasUpdate = false, bool isNew = false); const QString &key = {}, const QString &textureUrl = {},
const QString &iconUrl = {}, bool hasUpdate = false, bool isNew = false);
Q_INVOKABLE bool isDownloaded() const; Q_INVOKABLE bool isDownloaded() const;
Q_INVOKABLE void setDownloaded(); Q_INVOKABLE void setDownloaded();
@@ -71,6 +72,7 @@ private:
bool m_visible = true; bool m_visible = true;
bool m_hasUpdate = false; bool m_hasUpdate = false;
bool m_isNew = false; bool m_isNew = false;
const QString m_itemType = "texture";
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -21,8 +21,8 @@ void ContentLibraryTexturesCategory::addTexture(const QFileInfo &texIcon, const
bool hasUpdate, bool isNew) bool hasUpdate, bool isNew)
{ {
m_categoryTextures.append(new ContentLibraryTexture( m_categoryTextures.append(new ContentLibraryTexture(
this, texIcon, downloadPath, key, webTextureUrl, iconUrl, this, texIcon, downloadPath, suffix, dimensions, sizeInBytes,
suffix, dimensions, sizeInBytes, hasUpdate, isNew)); key, webTextureUrl, iconUrl, hasUpdate, isNew));
} }
bool ContentLibraryTexturesCategory::filter(const QString &searchText) bool ContentLibraryTexturesCategory::filter(const QString &searchText)

View File

@@ -37,7 +37,7 @@ public:
void setHasSceneEnv(bool b); void setHasSceneEnv(bool b);
void resetModel(); void resetModel();
void loadTextureBundle(const QString &m_textureBundleUrl, const QString &bundlePath, void loadTextureBundle(const QString &textureBundleUrl, const QString &bundlePath,
const QVariantMap &metaData); const QVariantMap &metaData);
signals: signals:

View File

@@ -6,9 +6,11 @@
#include "contentlibrarybundleimporter.h" #include "contentlibrarybundleimporter.h"
#include "contentlibrarymaterial.h" #include "contentlibrarymaterial.h"
#include "contentlibrarymaterialscategory.h" #include "contentlibrarymaterialscategory.h"
#include "contentlibrarytexture.h"
#include "contentlibrarywidget.h" #include "contentlibrarywidget.h"
#include <designerpaths.h> #include <designerpaths.h>
#include <imageutils.h>
#include <qmldesignerplugin.h> #include <qmldesignerplugin.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
@@ -16,6 +18,7 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QQmlEngine> #include <QQmlEngine>
@@ -28,9 +31,10 @@ ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_widget(parent) , m_widget(parent)
{ {
m_userCategories = {tr("Materials")/*, tr("Textures"), tr("3D"), tr("Effects"), tr("2D components")*/}; // TODO m_userCategories = {tr("Materials"), tr("Textures")/*, tr("3D"), tr("Effects"), tr("2D components")*/}; // TODO
loadMaterialBundle(); loadMaterialBundle();
loadTextureBundle();
} }
int ContentLibraryUserModel::rowCount(const QModelIndex &) const int ContentLibraryUserModel::rowCount(const QModelIndex &) const
@@ -262,6 +266,32 @@ void ContentLibraryUserModel::loadMaterialBundle()
emit matBundleExistsChanged(); emit matBundleExistsChanged();
} }
void ContentLibraryUserModel::loadTextureBundle()
{
if (!m_userTextures.isEmpty())
return;
QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
bundleDir.mkpath(".");
bundleDir.mkdir("icons");
const QFileInfoList fileInfos = bundleDir.entryInfoList(QDir::Files);
for (const QFileInfo &fileInfo : fileInfos) {
auto iconFileInfo = QFileInfo(fileInfo.path().append("/icons/").append(fileInfo.fileName()));
QPair<QSize, qint64> info = ImageUtils::imageInfo(fileInfo.path());
QString dirPath = fileInfo.path();
QString suffix = '.' + fileInfo.suffix();
QSize imgDims = info.first;
qint64 imgFileSize = info.second;
auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
m_userTextures.append(tex);
}
int texSectionIdx = 1;
emit dataChanged(index(texSectionIdx, 0), index(texSectionIdx, 0));
}
bool ContentLibraryUserModel::hasRequiredQuick3DImport() const bool ContentLibraryUserModel::hasRequiredQuick3DImport() const
{ {
return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3; return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;

View File

@@ -3,7 +3,7 @@
#pragma once #pragma once
#include "nodemetainfo.h" #include "modelfwd.h"
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QJsonObject> #include <QJsonObject>
@@ -16,6 +16,7 @@ class ContentLibraryEffect;
class ContentLibraryMaterial; class ContentLibraryMaterial;
class ContentLibraryTexture; class ContentLibraryTexture;
class ContentLibraryWidget; class ContentLibraryWidget;
class NodeMetaInfo;
namespace Internal { namespace Internal {
class ContentLibraryBundleImporter; class ContentLibraryBundleImporter;
@@ -94,6 +95,7 @@ signals:
private: private:
void loadMaterialBundle(); void loadMaterialBundle();
void loadTextureBundle();
bool isValidIndex(int idx) const; bool isValidIndex(int idx) const;
void createImporter(const QString &bundlePath, const QString &bundleId, void createImporter(const QString &bundlePath, const QString &bundleId,
const QStringList &sharedFiles); const QStringList &sharedFiles);

View File

@@ -63,7 +63,7 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
return tr("Texture has no source image."); return tr("Texture has no source image.");
ModelNode texNode = m_textureList.at(index.row()); ModelNode texNode = m_textureList.at(index.row());
QString info = ImageUtils::imageInfo(source); QString info = ImageUtils::imageInfoString(source);
if (info.isEmpty()) if (info.isEmpty())
return tr("Texture has no data."); return tr("Texture has no data.");

View File

@@ -1946,7 +1946,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo
imageData.pixmap = originalPixmap.scaled(dim, dim, Qt::KeepAspectRatio); imageData.pixmap = originalPixmap.scaled(dim, dim, Qt::KeepAspectRatio);
imageData.pixmap.setDevicePixelRatio(ratio); imageData.pixmap.setDevicePixelRatio(ratio);
imageData.time = modified; imageData.time = modified;
imageData.info = ImageUtils::imageInfo(imageSource); imageData.info = ImageUtils::imageInfoString(imageSource);
m_imageDataMap.insert(imageData.id, imageData); m_imageDataMap.insert(imageData.id, imageData);
} }
} }

View File

@@ -11,7 +11,7 @@
namespace QmlDesigner { namespace QmlDesigner {
QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes) QString ImageUtils::imageInfoString(const QSize &dimensions, qint64 sizeInBytes)
{ {
return QLatin1String("%1 x %2\n%3") return QLatin1String("%1 x %2\n%3")
.arg(QString::number(dimensions.width()), .arg(QString::number(dimensions.width()),
@@ -20,7 +20,7 @@ QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes)
sizeInBytes, 2, QLocale::DataSizeTraditionalFormat)); sizeInBytes, 2, QLocale::DataSizeTraditionalFormat));
} }
QString QmlDesigner::ImageUtils::imageInfo(const QString &path) QPair<QSize, qint64> QmlDesigner::ImageUtils::imageInfo(const QString &path)
{ {
QFileInfo info(path); QFileInfo info(path);
if (!info.exists()) if (!info.exists())
@@ -52,7 +52,13 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return {}; return {};
return imageInfo(QSize(width, height), info.size()); return {QSize(width, height), info.size()};
}
QString ImageUtils::imageInfoString(const QString &path)
{
QPair<QSize, qint64> info = imageInfo(path);
return imageInfoString(info.first, info.second);
} }
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -12,8 +12,9 @@ class ImageUtils
public: public:
ImageUtils(); ImageUtils();
static QString imageInfo(const QSize &dimensions, qint64 sizeInBytes); static QPair<QSize, qint64> imageInfo(const QString &path);
static QString imageInfo(const QString &path); static QString imageInfoString(const QString &path);
static QString imageInfoString(const QSize &dimensions, qint64 sizeInBytes);
}; };
} // namespace QmlDesigner } // namespace QmlDesigner