forked from qt-creator/qt-creator
QmlDesigner: Allow saving a 3D node to the content library
Fixes: QDS-12393 Change-Id: I3112244bcbe74ea0f8f2eda8ccb6ad7470ca0e1e Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
@@ -65,7 +65,7 @@ public:
|
|||||||
externalDependencies,
|
externalDependencies,
|
||||||
true)
|
true)
|
||||||
, collectionView{externalDependencies}
|
, collectionView{externalDependencies}
|
||||||
, contentLibraryView{externalDependencies}
|
, contentLibraryView{imageCache, externalDependencies}
|
||||||
, componentView{externalDependencies}
|
, componentView{externalDependencies}
|
||||||
#ifndef QTC_USE_QML_DESIGNER_LITE
|
#ifndef QTC_USE_QML_DESIGNER_LITE
|
||||||
, edit3DView{externalDependencies}
|
, edit3DView{externalDependencies}
|
||||||
|
@@ -98,17 +98,35 @@ void ContentLibraryUserModel::addMaterial(const QString &name, const QString &qm
|
|||||||
const QUrl &icon, const QStringList &files)
|
const QUrl &icon, const QStringList &files)
|
||||||
{
|
{
|
||||||
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||||
|
|
||||||
QString typePrefix = compUtils.userMaterialsBundleType();
|
QString typePrefix = compUtils.userMaterialsBundleType();
|
||||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||||
|
|
||||||
auto libMat = new ContentLibraryMaterial(this, name, qml, type, icon, files,
|
auto libMat = new ContentLibraryMaterial(this, name, qml, type, icon, files,
|
||||||
Paths::bundlesPathSetting().append("/User/materials"));
|
Paths::bundlesPathSetting().append("/User/materials"));
|
||||||
|
|
||||||
m_userMaterials.append(libMat);
|
m_userMaterials.append(libMat);
|
||||||
|
|
||||||
int matSectionIdx = 0;
|
int matSectionIdx = 0;
|
||||||
emit dataChanged(index(matSectionIdx), index(matSectionIdx));
|
emit dataChanged(index(matSectionIdx), index(matSectionIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContentLibraryUserModel::add3DItem(const QString &name, const QString &qml,
|
||||||
|
const QUrl &icon, const QStringList &files)
|
||||||
|
{
|
||||||
|
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||||
|
|
||||||
|
QString typePrefix = compUtils.user3DBundleType();
|
||||||
|
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||||
|
|
||||||
|
m_user3DItems.append(new ContentLibraryItem(this, name, qml, type, icon, files));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentLibraryUserModel::refresh3DSection()
|
||||||
|
{
|
||||||
|
int sectionIdx = 2;
|
||||||
|
emit dataChanged(index(sectionIdx), index(sectionIdx));
|
||||||
|
}
|
||||||
|
|
||||||
void ContentLibraryUserModel::addTextures(const QStringList &paths)
|
void ContentLibraryUserModel::addTextures(const QStringList &paths)
|
||||||
{
|
{
|
||||||
QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
|
QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
|
||||||
@@ -198,7 +216,7 @@ void ContentLibraryUserModel::removeFromContentLib(ContentLibraryMaterial *mat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns unique library material's name and qml component
|
// returns unique library material's name and qml component
|
||||||
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(const QString &matName) const
|
QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(const QString &defaultName) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!m_bundleObjMaterial.isEmpty(), return {});
|
QTC_ASSERT(!m_bundleObjMaterial.isEmpty(), return {});
|
||||||
|
|
||||||
@@ -209,10 +227,9 @@ QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(
|
|||||||
for (const QString &matName : matNames)
|
for (const QString &matName : matNames)
|
||||||
matQmls.append(matsObj.value(matName).toObject().value("qml").toString().chopped(4)); // remove .qml
|
matQmls.append(matsObj.value(matName).toObject().value("qml").toString().chopped(4)); // remove .qml
|
||||||
|
|
||||||
QString retName = matName.isEmpty() ? "Material" : matName;
|
QString retName = defaultName.isEmpty() ? "Material" : defaultName.trimmed();
|
||||||
retName = retName.trimmed();
|
|
||||||
|
|
||||||
QString retQml = retName;
|
QString retQml = retName;
|
||||||
|
|
||||||
retQml.remove(' ');
|
retQml.remove(' ');
|
||||||
if (retQml.at(0).isLower())
|
if (retQml.at(0).isLower())
|
||||||
retQml[0] = retQml.at(0).toUpper();
|
retQml[0] = retQml.at(0).toUpper();
|
||||||
@@ -232,6 +249,32 @@ QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNameAndQml(
|
|||||||
return {retName, retQml + ".qml"};
|
return {retName, retQml + ".qml"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ContentLibraryUserModel::getUniqueLib3DQmlName(const QString &defaultName) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_bundleObj3D.isEmpty(), return {});
|
||||||
|
|
||||||
|
const QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
|
||||||
|
|
||||||
|
QStringList itemQmls;
|
||||||
|
for (const QJsonValueConstRef &itemRef : itemsArr)
|
||||||
|
itemQmls.append(itemRef.toObject().value("qml").toString().chopped(4)); // remove .qml
|
||||||
|
|
||||||
|
QString baseQml = defaultName.isEmpty() ? "Item" : defaultName.trimmed();
|
||||||
|
baseQml.remove(' ');
|
||||||
|
baseQml[0] = baseQml.at(0).toUpper();
|
||||||
|
baseQml.prepend("My");
|
||||||
|
|
||||||
|
QString uniqueQml = baseQml;
|
||||||
|
|
||||||
|
int counter = 1;
|
||||||
|
while (itemQmls.contains(uniqueQml)) {
|
||||||
|
uniqueQml = QString("%1%2").arg(uniqueQml).arg(counter);
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueQml + ".qml";
|
||||||
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
|
QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
|
||||||
{
|
{
|
||||||
static const QHash<int, QByteArray> roles {
|
static const QHash<int, QByteArray> roles {
|
||||||
@@ -242,11 +285,16 @@ QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
|
|||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject &ContentLibraryUserModel::bundleJsonObjectRef()
|
QJsonObject &ContentLibraryUserModel::bundleJsonMaterialObjectRef()
|
||||||
{
|
{
|
||||||
return m_bundleObjMaterial;
|
return m_bundleObjMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject &ContentLibraryUserModel::bundleJson3DObjectRef()
|
||||||
|
{
|
||||||
|
return m_bundleObj3D;
|
||||||
|
}
|
||||||
|
|
||||||
void ContentLibraryUserModel::loadBundles()
|
void ContentLibraryUserModel::loadBundles()
|
||||||
{
|
{
|
||||||
loadMaterialBundle();
|
loadMaterialBundle();
|
||||||
@@ -356,15 +404,15 @@ void ContentLibraryUserModel::load3DBundle()
|
|||||||
int section3DIdx = 2;
|
int section3DIdx = 2;
|
||||||
|
|
||||||
m_bundlePath3D = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d");
|
m_bundlePath3D = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d");
|
||||||
m_bundlePath3D.createDir();
|
m_bundlePath3D.ensureWritableDir();
|
||||||
|
m_bundlePath3D.pathAppended("icons").ensureWritableDir();
|
||||||
|
|
||||||
auto jsonFilePath = m_bundlePath3D.pathAppended("user_3d_bundle.json");
|
auto jsonFilePath = m_bundlePath3D.pathAppended("user_3d_bundle.json");
|
||||||
|
|
||||||
if (!jsonFilePath.exists()) {
|
if (!jsonFilePath.exists()) {
|
||||||
QByteArray jsonContent = "{\n";
|
QByteArray jsonContent = "{\n";
|
||||||
jsonContent += " \"id\": \"User3D\",\n";
|
jsonContent += " \"id\": \"User3D\",\n";
|
||||||
jsonContent += " \"items\": {\n";
|
jsonContent += " \"items\": []\n";
|
||||||
jsonContent += " }\n";
|
|
||||||
jsonContent += "}";
|
jsonContent += "}";
|
||||||
Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent);
|
Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent);
|
||||||
if (!res.has_value()) {
|
if (!res.has_value()) {
|
||||||
@@ -393,24 +441,21 @@ void ContentLibraryUserModel::load3DBundle()
|
|||||||
m_bundleObj3D["id"] = m_bundleId3D;
|
m_bundleObj3D["id"] = m_bundleId3D;
|
||||||
|
|
||||||
// parse 3d items
|
// parse 3d items
|
||||||
const QJsonObject itemsObj = m_bundleObj3D.value("items").toObject();
|
|
||||||
const QStringList itemNames = itemsObj.keys();
|
|
||||||
QString typePrefix = compUtils.user3DBundleType();
|
QString typePrefix = compUtils.user3DBundleType();
|
||||||
for (const QString &itemName : itemNames) {
|
const QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
|
||||||
const QJsonObject itemObj = itemsObj.value(itemName).toObject();
|
for (const QJsonValueConstRef &itemRef : itemsArr) {
|
||||||
|
const QJsonObject itemObj = itemRef.toObject();
|
||||||
|
|
||||||
|
QString name = itemObj.value("name").toString();
|
||||||
|
QString qml = itemObj.value("qml").toString();
|
||||||
|
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
||||||
|
QUrl icon = m_bundlePath3D.pathAppended(itemObj.value("icon").toString()).toUrl();
|
||||||
QStringList files;
|
QStringList files;
|
||||||
const QJsonArray assetsArr = itemObj.value("files").toArray();
|
const QJsonArray assetsArr = itemObj.value("files").toArray();
|
||||||
for (const QJsonValueConstRef &asset : assetsArr)
|
for (const QJsonValueConstRef &asset : assetsArr)
|
||||||
files.append(asset.toString());
|
files.append(asset.toString());
|
||||||
|
|
||||||
QUrl icon = m_bundlePath3D.pathAppended(itemObj.value("icon").toString()).toUrl();
|
m_user3DItems.append(new ContentLibraryItem(nullptr, name, qml, type, icon, files));
|
||||||
QString qml = itemObj.value("qml").toString();
|
|
||||||
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
|
|
||||||
|
|
||||||
auto bundleItem = new ContentLibraryItem(nullptr, itemName, qml, type, icon, files);
|
|
||||||
|
|
||||||
m_user3DItems.append(bundleItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bundle3DSharedFiles.clear();
|
m_bundle3DSharedFiles.clear();
|
||||||
|
@@ -43,7 +43,8 @@ public:
|
|||||||
void setSearchText(const QString &searchText);
|
void setSearchText(const QString &searchText);
|
||||||
void updateImportedState(const QStringList &importedItems);
|
void updateImportedState(const QStringList &importedItems);
|
||||||
|
|
||||||
QPair<QString, QString> getUniqueLibMaterialNameAndQml(const QString &matName) const;
|
QPair<QString, QString> getUniqueLibMaterialNameAndQml(const QString &defaultName = {}) const;
|
||||||
|
QString getUniqueLib3DQmlName(const QString &defaultName = {}) const;
|
||||||
|
|
||||||
void setQuick3DImportVersion(int major, int minor);
|
void setQuick3DImportVersion(int major, int minor);
|
||||||
|
|
||||||
@@ -59,12 +60,15 @@ public:
|
|||||||
void updateIsEmpty3D();
|
void updateIsEmpty3D();
|
||||||
|
|
||||||
void addMaterial(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
|
void addMaterial(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
|
||||||
|
void add3DItem(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
|
||||||
|
void refresh3DSection();
|
||||||
void addTextures(const QStringList &paths);
|
void addTextures(const QStringList &paths);
|
||||||
|
|
||||||
void add3DInstance(ContentLibraryItem *bundleItem);
|
void add3DInstance(ContentLibraryItem *bundleItem);
|
||||||
|
|
||||||
void setBundleObj(const QJsonObject &newBundleObj);
|
void setBundleObj(const QJsonObject &newBundleObj);
|
||||||
QJsonObject &bundleJsonObjectRef();
|
QJsonObject &bundleJsonMaterialObjectRef();
|
||||||
|
QJsonObject &bundleJson3DObjectRef();
|
||||||
|
|
||||||
void loadBundles();
|
void loadBundles();
|
||||||
|
|
||||||
|
@@ -44,8 +44,10 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
ContentLibraryView::ContentLibraryView(ExternalDependenciesInterface &externalDependencies)
|
ContentLibraryView::ContentLibraryView(AsynchronousImageCache &imageCache,
|
||||||
|
ExternalDependenciesInterface &externalDependencies)
|
||||||
: AbstractView(externalDependencies)
|
: AbstractView(externalDependencies)
|
||||||
|
, m_imageCache(imageCache)
|
||||||
, m_createTexture(this)
|
, m_createTexture(this)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -364,6 +366,8 @@ void ContentLibraryView::customNotification(const AbstractView *view,
|
|||||||
addLibMaterial(nodeList.first(), data.first().value<QPixmap>());
|
addLibMaterial(nodeList.first(), data.first().value<QPixmap>());
|
||||||
} else if (identifier == "add_assets_to_content_lib") {
|
} else if (identifier == "add_assets_to_content_lib") {
|
||||||
addLibAssets(data.first().toStringList());
|
addLibAssets(data.first().toStringList());
|
||||||
|
} else if (identifier == "add_3d_to_content_lib") {
|
||||||
|
addLib3DItem(nodeList.first());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,10 +517,10 @@ void ContentLibraryView::addLibMaterial(const ModelNode &mat, const QPixmap &ico
|
|||||||
qWarning() << __FUNCTION__ << "icon save failed";
|
qWarning() << __FUNCTION__ << "icon save failed";
|
||||||
|
|
||||||
// generate and save material Qml file
|
// generate and save material Qml file
|
||||||
const QStringList depAssets = writeLibMaterialQml(mat, qml);
|
const QStringList depAssets = writeLibItemQml(mat, qml);
|
||||||
|
|
||||||
// add the material to the bundle json
|
// add the material to the bundle json
|
||||||
QJsonObject &jsonRef = m_widget->userModel()->bundleJsonObjectRef();
|
QJsonObject &jsonRef = m_widget->userModel()->bundleJsonMaterialObjectRef();
|
||||||
QJsonObject matsObj = jsonRef.value("materials").toObject();
|
QJsonObject matsObj = jsonRef.value("materials").toObject();
|
||||||
QJsonObject matObj;
|
QJsonObject matObj;
|
||||||
matObj.insert("qml", qml);
|
matObj.insert("qml", qml);
|
||||||
@@ -554,14 +558,16 @@ void ContentLibraryView::addLibMaterial(const ModelNode &mat, const QPixmap &ico
|
|||||||
m_widget->userModel()->addMaterial(name, qml, QUrl::fromLocalFile(fullIconPath), depAssets);
|
m_widget->userModel()->addMaterial(name, qml, QUrl::fromLocalFile(fullIconPath), depAssets);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ContentLibraryView::writeLibMaterialQml(const ModelNode &mat, const QString &qml)
|
QStringList ContentLibraryView::writeLibItemQml(const ModelNode &node, const QString &qml)
|
||||||
{
|
{
|
||||||
QStringList depListIds;
|
QStringList depListIds;
|
||||||
auto [qmlString, assets] = modelNodeToQmlString(mat, depListIds);
|
auto [qmlString, assets] = modelNodeToQmlString(node, depListIds);
|
||||||
|
|
||||||
qmlString.prepend("import QtQuick\nimport QtQuick3D\n\n");
|
qmlString.prepend("import QtQuick\nimport QtQuick3D\n\n");
|
||||||
|
|
||||||
auto qmlPath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials/" + qml);
|
QString itemType = QLatin1String(node.metaInfo().isQtQuick3DMaterial() ? "material" : "3d");
|
||||||
|
auto qmlPath = Utils::FilePath::fromString(QLatin1String("%1/User/%2/%3")
|
||||||
|
.arg(Paths::bundlesPathSetting(), itemType, qml));
|
||||||
auto result = qmlPath.writeFileContents(qmlString.toUtf8());
|
auto result = qmlPath.writeFileContents(qmlString.toUtf8());
|
||||||
if (!result)
|
if (!result)
|
||||||
qWarning() << __FUNCTION__ << result.error();
|
qWarning() << __FUNCTION__ << result.error();
|
||||||
@@ -584,16 +590,24 @@ QPair<QString, QSet<QString>> ContentLibraryView::modelNodeToQmlString(const Mod
|
|||||||
|
|
||||||
qml += indent + "id: " + (depth == 0 ? "root" : node.id()) + " \n\n";
|
qml += indent + "id: " + (depth == 0 ? "root" : node.id()) + " \n\n";
|
||||||
|
|
||||||
|
const QList<PropertyName> excludedProps = {"x", "y", "z", "eulerRotation.x", "eulerRotation.y",
|
||||||
|
"eulerRotation.z", "scale.x", "scale.y", "scale.z",
|
||||||
|
"pivot.x", "pivot.y", "pivot.z"};
|
||||||
const QList<AbstractProperty> matProps = node.properties();
|
const QList<AbstractProperty> matProps = node.properties();
|
||||||
for (const AbstractProperty &p : matProps) {
|
for (const AbstractProperty &p : matProps) {
|
||||||
|
if (excludedProps.contains(p.name()))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (p.isVariantProperty()) {
|
if (p.isVariantProperty()) {
|
||||||
QVariant pValue = p.toVariantProperty().value();
|
QVariant pValue = p.toVariantProperty().value();
|
||||||
QString val;
|
QString val;
|
||||||
if (strcmp(pValue.typeName(), "QString") == 0 || strcmp(pValue.typeName(), "QColor") == 0) {
|
if (strcmp(pValue.typeName(), "QString") == 0 || strcmp(pValue.typeName(), "QColor") == 0) {
|
||||||
val = QLatin1String("\"%1\"").arg(pValue.toString());
|
val = QLatin1String("\"%1\"").arg(pValue.toString());
|
||||||
} else if (strcmp(pValue.typeName(), "QUrl") == 0) {
|
} else if (strcmp(pValue.typeName(), "QUrl") == 0) {
|
||||||
val = QLatin1String("\"%1\"").arg(pValue.toString());
|
QString pValueStr = pValue.toString();
|
||||||
assets.insert(pValue.toString());
|
val = QLatin1String("\"%1\"").arg(pValueStr);
|
||||||
|
if (!pValueStr.startsWith("#"))
|
||||||
|
assets.insert(pValue.toString());
|
||||||
} else if (strcmp(pValue.typeName(), "QmlDesigner::Enumeration") == 0) {
|
} else if (strcmp(pValue.typeName(), "QmlDesigner::Enumeration") == 0) {
|
||||||
val = pValue.value<QmlDesigner::Enumeration>().toString();
|
val = pValue.value<QmlDesigner::Enumeration>().toString();
|
||||||
} else {
|
} else {
|
||||||
@@ -649,6 +663,82 @@ void ContentLibraryView::addLibAssets(const QStringList &paths)
|
|||||||
m_widget->userModel()->addTextures(pathsInBundle);
|
m_widget->userModel()->addTextures(pathsInBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContentLibraryView::addLib3DItem(const ModelNode &node)
|
||||||
|
{
|
||||||
|
auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/");
|
||||||
|
|
||||||
|
QString name = node.variantProperty("objectName").value().toString();
|
||||||
|
QString qml = m_widget->userModel()->getUniqueLib3DQmlName(node.id());
|
||||||
|
QString iconPath = QLatin1String("icons/%1.png").arg(node.id()); // TODO: make sure path is unique
|
||||||
|
|
||||||
|
// generate and save item Qml file
|
||||||
|
const QStringList depAssets = writeLibItemQml(node, qml);
|
||||||
|
|
||||||
|
// generate and save icon
|
||||||
|
QString qmlPath = QLatin1String("%1/User/3d/%2").arg(Paths::bundlesPathSetting(), qml);
|
||||||
|
QString fullIconPath = bundlePath.pathAppended(iconPath).toString();
|
||||||
|
genAndSaveIcon(qmlPath, fullIconPath);
|
||||||
|
|
||||||
|
// add the item to the bundle json
|
||||||
|
QJsonObject &jsonRef = m_widget->userModel()->bundleJson3DObjectRef();
|
||||||
|
QJsonArray itemsArr = jsonRef.value("items").toArray();
|
||||||
|
QJsonObject itemObj;
|
||||||
|
itemObj.insert("name", name);
|
||||||
|
itemObj.insert("qml", qml);
|
||||||
|
itemObj.insert("icon", iconPath);
|
||||||
|
QJsonArray filesArr;
|
||||||
|
for (const QString &assetPath : depAssets)
|
||||||
|
filesArr.append(assetPath);
|
||||||
|
itemObj.insert("files", filesArr);
|
||||||
|
|
||||||
|
itemsArr.append(itemObj);
|
||||||
|
jsonRef["items"] = itemsArr;
|
||||||
|
|
||||||
|
auto result = bundlePath.pathAppended("user_3d_bundle.json")
|
||||||
|
.writeFileContents(QJsonDocument(jsonRef).toJson());
|
||||||
|
if (!result)
|
||||||
|
qWarning() << __FUNCTION__ << result.error();
|
||||||
|
|
||||||
|
// copy item's assets to bundle folder
|
||||||
|
for (const QString &assetPath : depAssets) {
|
||||||
|
Utils::FilePath assetPathSource = DocumentManager::currentResourcePath().pathAppended(assetPath);
|
||||||
|
Utils::FilePath assetPathTarget = bundlePath.pathAppended(assetPath);
|
||||||
|
assetPathTarget.parentDir().ensureWritableDir();
|
||||||
|
|
||||||
|
auto result = assetPathSource.copyFile(assetPathTarget);
|
||||||
|
if (!result)
|
||||||
|
qWarning() << __FUNCTION__ << result.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_widget->userModel()->add3DItem(name, qml, QUrl::fromLocalFile(fullIconPath), depAssets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generates an icon image from a qml component
|
||||||
|
* @param qmlPath path to the qml component file to be rendered
|
||||||
|
* @param iconPath output save path of the generated icon
|
||||||
|
*/
|
||||||
|
void ContentLibraryView::genAndSaveIcon(const QString &qmlPath, const QString &iconPath)
|
||||||
|
{
|
||||||
|
m_imageCache.requestSmallImage(
|
||||||
|
Utils::PathString{qmlPath},
|
||||||
|
[&, qmlPath, iconPath](const QImage &image) {
|
||||||
|
bool iconSaved = image.save(iconPath);
|
||||||
|
if (iconSaved)
|
||||||
|
m_widget->userModel()->refresh3DSection();
|
||||||
|
else
|
||||||
|
qWarning() << "ContentLibraryView::genAndSaveIcon(): icon save failed";
|
||||||
|
},
|
||||||
|
[](ImageCache::AbortReason abortReason) {
|
||||||
|
if (abortReason == ImageCache::AbortReason::Abort)
|
||||||
|
qWarning() << "ContentLibraryView::genAndSaveIcon(): icon generation aborted, reason: Abort";
|
||||||
|
else if (abortReason == ImageCache::AbortReason::Failed)
|
||||||
|
qWarning() << "ContentLibraryView::genAndSaveIcon(): icon generation aborted, reason: Failed";
|
||||||
|
else if (abortReason == ImageCache::AbortReason::NoEntry)
|
||||||
|
qWarning() << "ContentLibraryView::genAndSaveIcon(): icon generation aborted, reason: NoEntry";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ModelNode ContentLibraryView::getBundleMaterialDefaultInstance(const TypeName &type)
|
ModelNode ContentLibraryView::getBundleMaterialDefaultInstance(const TypeName &type)
|
||||||
{
|
{
|
||||||
ModelNode matLib = Utils3D::materialLibraryNode(this);
|
ModelNode matLib = Utils3D::materialLibraryNode(this);
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <asynchronousimagecache.h>
|
||||||
#include <abstractview.h>
|
#include <abstractview.h>
|
||||||
#include <createtexture.h>
|
#include <createtexture.h>
|
||||||
#include <nodemetainfo.h>
|
#include <nodemetainfo.h>
|
||||||
@@ -25,7 +26,8 @@ class ContentLibraryView : public AbstractView
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ContentLibraryView(ExternalDependenciesInterface &externalDependencies);
|
ContentLibraryView(AsynchronousImageCache &imageCache,
|
||||||
|
ExternalDependenciesInterface &externalDependencies);
|
||||||
~ContentLibraryView() override;
|
~ContentLibraryView() override;
|
||||||
|
|
||||||
bool hasWidget() const override;
|
bool hasWidget() const override;
|
||||||
@@ -55,7 +57,9 @@ private:
|
|||||||
void updateBundlesQuick3DVersion();
|
void updateBundlesQuick3DVersion();
|
||||||
void addLibMaterial(const ModelNode &mat, const QPixmap &icon);
|
void addLibMaterial(const ModelNode &mat, const QPixmap &icon);
|
||||||
void addLibAssets(const QStringList &paths);
|
void addLibAssets(const QStringList &paths);
|
||||||
QStringList writeLibMaterialQml(const ModelNode &mat, const QString &qml);
|
void addLib3DItem(const ModelNode &node);
|
||||||
|
void genAndSaveIcon(const QString &qmlPath, const QString &iconPath);
|
||||||
|
QStringList writeLibItemQml(const ModelNode &node, const QString &qml);
|
||||||
QPair<QString, QSet<QString>> modelNodeToQmlString(const ModelNode &node, QStringList &depListIds,
|
QPair<QString, QSet<QString>> modelNodeToQmlString(const ModelNode &node, QStringList &depListIds,
|
||||||
int depth = 0);
|
int depth = 0);
|
||||||
|
|
||||||
@@ -79,6 +83,7 @@ private:
|
|||||||
ContentLibraryMaterial *m_draggedBundleMaterial = nullptr;
|
ContentLibraryMaterial *m_draggedBundleMaterial = nullptr;
|
||||||
ContentLibraryTexture *m_draggedBundleTexture = nullptr;
|
ContentLibraryTexture *m_draggedBundleTexture = nullptr;
|
||||||
ContentLibraryItem *m_draggedBundleItem = nullptr;
|
ContentLibraryItem *m_draggedBundleItem = nullptr;
|
||||||
|
AsynchronousImageCache &m_imageCache;
|
||||||
bool m_bundleMaterialAddToSelected = false;
|
bool m_bundleMaterialAddToSelected = false;
|
||||||
bool m_hasQuick3DImport = false;
|
bool m_hasQuick3DImport = false;
|
||||||
qint32 m_sceneId = -1;
|
qint32 m_sceneId = -1;
|
||||||
|
@@ -359,6 +359,14 @@ void Edit3DWidget::createContextMenu()
|
|||||||
resetAction->setToolTip(tr("Reset all shading options for all viewports."));
|
resetAction->setToolTip(tr("Reset all shading options for all viewports."));
|
||||||
|
|
||||||
m_contextMenu->addSeparator();
|
m_contextMenu->addSeparator();
|
||||||
|
|
||||||
|
m_addToContentLibAction = m_contextMenu->addAction(
|
||||||
|
contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
|
||||||
|
tr("Add to Content Library"), [&] {
|
||||||
|
view()->emitCustomNotification("add_3d_to_content_lib", {m_contextMenuTarget});
|
||||||
|
});
|
||||||
|
|
||||||
|
m_contextMenu->addSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Edit3DWidget::isPasteAvailable() const
|
bool Edit3DWidget::isPasteAvailable() const
|
||||||
@@ -612,6 +620,7 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
|||||||
m_contextMenuPos3d = pos3d;
|
m_contextMenuPos3d = pos3d;
|
||||||
|
|
||||||
const bool isModel = modelNode.metaInfo().isQtQuick3DModel();
|
const bool isModel = modelNode.metaInfo().isQtQuick3DModel();
|
||||||
|
const bool isNode = modelNode.metaInfo().isQtQuick3DNode();
|
||||||
const bool allowAlign = view()->edit3DAction(View3DActionType::AlignCamerasToView)->action()->isEnabled();
|
const bool allowAlign = view()->edit3DAction(View3DActionType::AlignCamerasToView)->action()->isEnabled();
|
||||||
const bool isSingleComponent = view()->hasSingleSelectedModelNode() && modelNode.isComponent();
|
const bool isSingleComponent = view()->hasSingleSelectedModelNode() && modelNode.isComponent();
|
||||||
const bool anyNodeSelected = view()->hasSelectedModelNodes();
|
const bool anyNodeSelected = view()->hasSelectedModelNodes();
|
||||||
@@ -633,6 +642,7 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
|||||||
m_toggleGroupAction->setEnabled(true);
|
m_toggleGroupAction->setEnabled(true);
|
||||||
m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
|
m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
|
||||||
m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
|
m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
|
||||||
|
m_addToContentLibAction->setEnabled(isNode);
|
||||||
|
|
||||||
if (m_view) {
|
if (m_view) {
|
||||||
int idx = m_view->activeSplit();
|
int idx = m_view->activeSplit();
|
||||||
|
@@ -100,6 +100,7 @@ private:
|
|||||||
QPointer<QAction> m_selectParentAction;
|
QPointer<QAction> m_selectParentAction;
|
||||||
QPointer<QAction> m_toggleGroupAction;
|
QPointer<QAction> m_toggleGroupAction;
|
||||||
QPointer<QAction> m_wireFrameAction;
|
QPointer<QAction> m_wireFrameAction;
|
||||||
|
QPointer<QAction> m_addToContentLibAction;
|
||||||
QHash<int, QPointer<QAction>> m_matOverrideActions;
|
QHash<int, QPointer<QAction>> m_matOverrideActions;
|
||||||
QPointer<QMenu> m_createSubMenu;
|
QPointer<QMenu> m_createSubMenu;
|
||||||
ModelNode m_contextMenuTarget;
|
ModelNode m_contextMenuTarget;
|
||||||
|
Reference in New Issue
Block a user