forked from qt-creator/qt-creator
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:
@@ -82,6 +82,13 @@ static const QStringList &supportedAudioSuffixes()
|
||||
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)
|
||||
{
|
||||
return QPixmap(QStringLiteral(":/ItemLibrary/images/asset_%1_%2.png").arg(type).arg(size.width()));
|
||||
@@ -123,6 +130,8 @@ public:
|
||||
pixmap = defaultPixmapForType("sound", iconSize);
|
||||
else if (supportedShaderSuffixes().contains(suffix))
|
||||
pixmap = defaultPixmapForType("shader", iconSize);
|
||||
else if (supportedTexture3DSuffixes().contains(suffix))
|
||||
pixmap = defaultPixmapForType("texture", iconSize);
|
||||
|
||||
if (pixmap.isNull())
|
||||
return QFileIconProvider::icon(info);
|
||||
@@ -286,6 +295,9 @@ QPair<QString, QByteArray> CustomFileSystemModel::resourceTypeAndData(const QMod
|
||||
} else if (supportedAudioSuffixes().contains(suffix)) {
|
||||
// No extra data for sounds
|
||||
return {"application/vnd.bauhaus.libraryresource.sound", {}};
|
||||
} else if (supportedTexture3DSuffixes().contains(suffix)) {
|
||||
// Data: Image format (suffix)
|
||||
return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
@@ -303,6 +315,7 @@ const QSet<QString> &CustomFileSystemModel::supportedSuffixes() const
|
||||
insertSuffixes(supportedShaderSuffixes());
|
||||
insertSuffixes(supportedFontSuffixes());
|
||||
insertSuffixes(supportedAudioSuffixes());
|
||||
insertSuffixes(supportedTexture3DSuffixes());
|
||||
}
|
||||
return allSuffixes;
|
||||
}
|
||||
@@ -352,6 +365,8 @@ QModelIndex CustomFileSystemModel::updatePath(const QString &newPath)
|
||||
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||
for (const QString &ext : supportedAudioSuffixes())
|
||||
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||
for (const QString &ext : supportedTexture3DSuffixes())
|
||||
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||
}
|
||||
|
||||
m_files.clear();
|
||||
|
@@ -507,6 +507,8 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
|
||||
handleItemLibraryShaderDrop(mimeData, rowNumber, dropModelIndex);
|
||||
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.sound")) {
|
||||
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")) {
|
||||
handleInternalDrop(mimeData, rowNumber, dropModelIndex);
|
||||
}
|
||||
@@ -728,71 +730,21 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i
|
||||
|
||||
ModelNode newModelNode;
|
||||
|
||||
auto createTextureNode = [&](const NodeAbstractProperty &targetProp) -> bool {
|
||||
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
|
||||
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) {
|
||||
if (!dropAsImage3dTexture(targetNode, targetProperty, imagePath, newModelNode)) {
|
||||
if (targetNode.isSubclassOf("QtQuick.Image")
|
||||
|| targetNode.isSubclassOf("QtQuick.BorderImage")) {
|
||||
// if dropping an image on an existing image, set the source
|
||||
targetNode.variantProperty("source").setValue(imagePath);
|
||||
} else {
|
||||
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
|
||||
if (createTextureNode(targetProperty) && dialog) {
|
||||
// Automatically set the texture to selected property
|
||||
targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newModelNode.validId());
|
||||
}
|
||||
// create an image
|
||||
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(m_view, imageSource, QPointF(), targetProperty, false);
|
||||
if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode()))
|
||||
newModelNode = newItemNode.modelNode();
|
||||
else
|
||||
newItemNode.destroy();
|
||||
});
|
||||
}
|
||||
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")) {
|
||||
// if dropping an image on an existing texture or image, set the source
|
||||
targetNode.variantProperty("source").setValue(imagePath);
|
||||
} else {
|
||||
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
|
||||
// create an image
|
||||
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(m_view, imageSource, QPointF(), targetProperty, false);
|
||||
if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode()))
|
||||
newModelNode = newItemNode.modelNode();
|
||||
else
|
||||
newItemNode.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
if (newModelNode.isValid()) {
|
||||
@@ -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)
|
||||
{
|
||||
return property.parentModelNode().metaInfo().propertyTypeName(property.name());
|
||||
|
@@ -118,6 +118,10 @@ private:
|
||||
void handleItemLibraryFontDrop(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 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);
|
||||
|
||||
QPointer<NavigatorView> m_view;
|
||||
|
Reference in New Issue
Block a user