QmlDesigner: Improve HDR image support

HDR images imported to the project are now shown on asset tab, though
they will only have the system default icon as Qt 2D rendering doesn't
support HDR images.

HDR images can also now be dragged into navigator, behaving like other
images when dragged into 3D elements that support them, or creating
a new Texture item if dragged elsewhere.

Task-number: QDS-2128
Change-Id: I16a23e93a2a51d65a2278400d3c6c6ffd3b62615
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2021-01-28 15:42:26 +02:00
parent d9cd74f06d
commit 5b582e042b
3 changed files with 144 additions and 62 deletions

View File

@@ -82,6 +82,13 @@ static const QStringList &supportedAudioSuffixes()
return retList; return retList;
} }
static const QStringList &supportedTexture3DSuffixes()
{
// These are file types only supported by 3D textures
static QStringList retList {"hdr"};
return retList;
}
static QPixmap defaultPixmapForType(const QString &type, const QSize &size) static QPixmap defaultPixmapForType(const QString &type, const QSize &size)
{ {
return QPixmap(QStringLiteral(":/ItemLibrary/images/asset_%1_%2.png").arg(type).arg(size.width())); return QPixmap(QStringLiteral(":/ItemLibrary/images/asset_%1_%2.png").arg(type).arg(size.width()));
@@ -123,6 +130,8 @@ public:
pixmap = defaultPixmapForType("sound", iconSize); pixmap = defaultPixmapForType("sound", iconSize);
else if (supportedShaderSuffixes().contains(suffix)) else if (supportedShaderSuffixes().contains(suffix))
pixmap = defaultPixmapForType("shader", iconSize); pixmap = defaultPixmapForType("shader", iconSize);
else if (supportedTexture3DSuffixes().contains(suffix))
pixmap = defaultPixmapForType("texture", iconSize);
if (pixmap.isNull()) if (pixmap.isNull())
return QFileIconProvider::icon(info); return QFileIconProvider::icon(info);
@@ -286,6 +295,9 @@ QPair<QString, QByteArray> CustomFileSystemModel::resourceTypeAndData(const QMod
} else if (supportedAudioSuffixes().contains(suffix)) { } else if (supportedAudioSuffixes().contains(suffix)) {
// No extra data for sounds // No extra data for sounds
return {"application/vnd.bauhaus.libraryresource.sound", {}}; return {"application/vnd.bauhaus.libraryresource.sound", {}};
} else if (supportedTexture3DSuffixes().contains(suffix)) {
// Data: Image format (suffix)
return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()};
} }
} }
return {}; return {};
@@ -303,6 +315,7 @@ const QSet<QString> &CustomFileSystemModel::supportedSuffixes() const
insertSuffixes(supportedShaderSuffixes()); insertSuffixes(supportedShaderSuffixes());
insertSuffixes(supportedFontSuffixes()); insertSuffixes(supportedFontSuffixes());
insertSuffixes(supportedAudioSuffixes()); insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
} }
return allSuffixes; return allSuffixes;
} }
@@ -352,6 +365,8 @@ QModelIndex CustomFileSystemModel::updatePath(const QString &newPath)
nameFilterList.append(filterTemplate.arg(searchFilter, ext)); nameFilterList.append(filterTemplate.arg(searchFilter, ext));
for (const QString &ext : supportedAudioSuffixes()) for (const QString &ext : supportedAudioSuffixes())
nameFilterList.append(filterTemplate.arg(searchFilter, ext)); nameFilterList.append(filterTemplate.arg(searchFilter, ext));
for (const QString &ext : supportedTexture3DSuffixes())
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
} }
m_files.clear(); m_files.clear();

View File

@@ -507,6 +507,8 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
handleItemLibraryShaderDrop(mimeData, rowNumber, dropModelIndex); handleItemLibraryShaderDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.sound")) { } else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.sound")) {
handleItemLibrarySoundDrop(mimeData, rowNumber, dropModelIndex); handleItemLibrarySoundDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.texture3d")) {
handleItemLibraryTexture3dDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.modelnode.list")) { } else if (mimeData->hasFormat("application/vnd.modelnode.list")) {
handleInternalDrop(mimeData, rowNumber, dropModelIndex); handleInternalDrop(mimeData, rowNumber, dropModelIndex);
} }
@@ -728,61 +730,10 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i
ModelNode newModelNode; ModelNode newModelNode;
auto createTextureNode = [&](const NodeAbstractProperty &targetProp) -> bool { if (!dropAsImage3dTexture(targetNode, targetProperty, imagePath, newModelNode)) {
if (targetProp.isValid()) { if (targetNode.isSubclassOf("QtQuick.Image")
// create a texture item lib
ItemLibraryEntry itemLibraryEntry;
itemLibraryEntry.setName("Texture");
itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0);
// set texture source
PropertyName prop = "source";
QString type = "QUrl";
QVariant val = imagePath;
itemLibraryEntry.addProperty(prop, type, val);
// create a texture
newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, targetProp, false);
// Rename the node based on source image
QFileInfo fi(imagePath);
newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), "textureImage"));
return newModelNode.isValid();
}
return false;
};
if (targetNode.isSubclassOf("QtQuick3D.Material")) {
// if dropping an image on a default material, create a texture instead of image
ChooseTexturePropertyDialog *dialog = nullptr;
if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) {
// Show texture property selection dialog
dialog = new ChooseTexturePropertyDialog(targetNode, Core::ICore::dialogParent());
dialog->exec();
}
if (!dialog || dialog->result() == QDialog::Accepted) {
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
if (createTextureNode(targetProperty) && dialog) {
// Automatically set the texture to selected property
targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newModelNode.validId());
}
});
}
delete dialog;
} else if (targetNode.isSubclassOf("QtQuick3D.TextureInput")) {
// If dropping an image on a TextureInput, create a texture on the same level as
// TextureInput, as the TextureInput doesn't support Texture children (QTBUG-86219)
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
NodeAbstractProperty parentProp = targetProperty.parentProperty();
if (createTextureNode(parentProp)) {
// Automatically set the texture to texture property
targetNode.bindingProperty("texture").setExpression(newModelNode.validId());
}
});
} else if (targetNode.isSubclassOf("QtQuick3D.Texture")
|| targetNode.isSubclassOf("QtQuick.Image")
|| targetNode.isSubclassOf("QtQuick.BorderImage")) { || targetNode.isSubclassOf("QtQuick.BorderImage")) {
// if dropping an image on an existing texture or image, set the source // if dropping an image on an existing image, set the source
targetNode.variantProperty("source").setValue(imagePath); targetNode.variantProperty("source").setValue(imagePath);
} else { } else {
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] { m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
@@ -794,6 +745,7 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i
newItemNode.destroy(); newItemNode.destroy();
}); });
} }
}
if (newModelNode.isValid()) { if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber); moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
@@ -958,6 +910,117 @@ void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, i
} }
} }
void NavigatorTreeModel::handleItemLibraryTexture3dDrop(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));
const QString imageSource = QString::fromUtf8(
mimeData->data("application/vnd.bauhaus.libraryresource")); // absolute path
const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir()
.relativeFilePath(imageSource); // relative to qml file
ModelNode newModelNode;
if (!dropAsImage3dTexture(targetNode, targetProperty, imagePath, newModelNode)) {
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryTexture3dDrop", [&] {
// create a standalone Texture3D at drop location
newModelNode = createTextureNode(targetProperty, imagePath);
if (!NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newModelNode))
newModelNode.destroy();
});
}
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
}
}
bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode,
const NodeAbstractProperty &targetProp,
const QString &imagePath,
ModelNode &newNode)
{
if (targetNode.isSubclassOf("QtQuick3D.Material")) {
// if dropping an image on a default material, create a texture instead of image
ChooseTexturePropertyDialog *dialog = nullptr;
if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) {
// Show texture property selection dialog
dialog = new ChooseTexturePropertyDialog(targetNode, Core::ICore::dialogParent());
dialog->exec();
}
if (!dialog || dialog->result() == QDialog::Accepted) {
m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
newNode = createTextureNode(targetProp, imagePath);
if (newNode.isValid() && dialog) {
// Automatically set the texture to selected property
targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newNode.validId());
}
});
}
delete dialog;
return newNode.isValid();
} else if (targetNode.isSubclassOf("QtQuick3D.TextureInput")) {
// If dropping an image on a TextureInput, create a texture on the same level as
// TextureInput, as the TextureInput doesn't support Texture children (QTBUG-86219)
m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] {
NodeAbstractProperty parentProp = targetProp.parentProperty();
newNode = createTextureNode(parentProp, imagePath);
if (newNode.isValid()) {
// Automatically set the texture to texture property
targetNode.bindingProperty("texture").setExpression(newNode.validId());
}
});
return newNode.isValid();
} else if (targetNode.isSubclassOf("QtQuick3D.Texture")) {
// if dropping an image on an existing texture, set the source
targetNode.variantProperty("source").setValue(imagePath);
return true;
}
return false;
}
ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targetProp,
const QString &imagePath)
{
if (targetProp.isValid()) {
// create a texture item lib
ItemLibraryEntry itemLibraryEntry;
itemLibraryEntry.setName("Texture");
itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0);
// set texture source
PropertyName prop = "source";
QString type = "QUrl";
QVariant val = imagePath;
itemLibraryEntry.addProperty(prop, type, val);
// create a texture
ModelNode newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {},
targetProp, false);
// Rename the node based on source image
QFileInfo fi(imagePath);
newModelNode.setIdWithoutRefactoring(m_view->generateNewId(fi.baseName(), "textureImage"));
return newModelNode;
}
return {};
}
TypeName propertyType(const NodeAbstractProperty &property) TypeName propertyType(const NodeAbstractProperty &property)
{ {
return property.parentModelNode().metaInfo().propertyTypeName(property.name()); return property.parentModelNode().metaInfo().propertyTypeName(property.name());

View File

@@ -118,6 +118,10 @@ private:
void handleItemLibraryFontDrop(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 handleItemLibraryShaderDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryTexture3dDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp,
const QString &imagePath, ModelNode &newNode);
ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath);
QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes); QList<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
QPointer<NavigatorView> m_view; QPointer<NavigatorView> m_view;