From fc1c720aece967a4e563b6385e71b12057797a01 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 1 Nov 2023 14:39:28 +0100 Subject: [PATCH] QmlDesigner: Move the functions to handle assets drops Moving those functions to ModelNodeOperations allows reuse in other views like e.g. the TextEditor. Change-Id: I7eee1c6080b4208ffaab6637f0debf78ec648c8e Reviewed-by: Miikka Heikkinen --- .../componentcore/modelnodeoperations.cpp | 429 +++++++++++++++++- .../componentcore/modelnodeoperations.h | 24 + .../navigator/navigatortreemodel.cpp | 365 ++------------- .../components/navigator/navigatortreemodel.h | 16 +- 4 files changed, 474 insertions(+), 360 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 12bb4d54604..1ed1c09b0c1 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -12,20 +12,22 @@ #include "addsignalhandlerdialog.h" #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -1739,6 +1741,409 @@ void jumpToCodeOperation(const SelectionContext &selectionState) jumpToCode(selectionState.currentSingleSelectedNode()); } +static bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const ModelNode &node) +{ + NodeAbstractProperty parentProp = targetProperty.parentProperty(); + if (parentProp.isValid()) { + ModelNode targetModel = parentProp.parentModelNode(); + parentProp.reparentHere(node); + return true; + } + return false; +} + +ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath) +{ + AbstractView *view = targetProp.view(); + QTC_ASSERT(view, return {}); + + 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(view, + itemLibraryEntry, + {}, + targetProp, + false); + + // Rename the node based on source image + QFileInfo fi(imagePath); + newModelNode.setIdWithoutRefactoring( + view->model()->generateNewId(fi.baseName(), "textureImage")); + return newModelNode; + } + return {}; +} + +bool dropAsImage3dTexture(const ModelNode &targetNode, + const NodeAbstractProperty &targetProp, + const QString &imagePath, + ModelNode &newNode, + bool &outMoveNodesAfter) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + auto bindToProperty = [&](const PropertyName &propName, bool sibling) { + view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { + newNode = createTextureNode(targetProp, imagePath); + if (newNode.isValid()) { + targetNode.bindingProperty(propName).setExpression(newNode.validId()); + + // If dropping an image on e.g. TextureInput, create a texture on the same level as + // target, as the target doesn't support Texture children (QTBUG-86219) + if (sibling) + outMoveNodesAfter = !moveNodeToParent(targetProp, newNode); + } + }); + }; + + if (targetNode.metaInfo().isQtQuick3DDefaultMaterial() + || targetNode.metaInfo().isQtQuick3DPrincipledMaterial() + || targetNode.metaInfo().isQtQuick3DSpecularGlossyMaterial()) { + // if dropping an image on a material, create a texture instead of image + // Show texture property selection dialog + auto dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, + view->model()->metaInfo( + "QtQuick3D.Texture"), + Core::ICore::dialogParent()); + if (!dialog) + return false; + + dialog->exec(); + + if (dialog->result() == QDialog::Accepted) { + view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { + newNode = createTextureNode(targetProp, imagePath); + if (newNode.isValid()) // Automatically set the texture to selected property + targetNode.bindingProperty(dialog->selectedProperty()) + .setExpression(newNode.validId()); + }); + } + + delete dialog; + return true; + } else if (targetNode.metaInfo().isQtQuick3DTextureInput()) { + bindToProperty("texture", true); + return newNode.isValid(); + } else if (targetNode.metaInfo().isQtQuick3DParticles3DSpriteParticle3D()) { + bindToProperty("sprite", false); + return newNode.isValid(); + } else if (targetNode.metaInfo().isQtQuick3DSceneEnvironment()) { + bindToProperty("lightProbe", false); + return newNode.isValid(); + } else if (targetNode.metaInfo().isQtQuick3DTexture()) { + // if dropping an image on an existing texture, set the source + targetNode.variantProperty("source").setValue(imagePath); + return true; + } else if (targetNode.metaInfo().isQtQuick3DModel()) { + QTimer::singleShot(0, view, [targetNode, imagePath, view]() { + if (view && targetNode.isValid()) { + // To MaterialBrowserView. Done async to avoid custom notification in transaction + view->emitCustomNotification("apply_asset_to_model3D", + {targetNode}, + {DocumentManager::currentFilePath() + .absolutePath() + .pathAppended(imagePath) + .cleanPath() + .toString()}); + } + }); + return true; + } + + return false; +} + +ModelNode handleItemLibraryEffectDrop(const QString &effectPath, const ModelNode &targetNode) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + ModelNode newModelNode; + + if ((targetNode.hasParentProperty() && targetNode.parentProperty().name() == "layer.effect") + || !targetNode.metaInfo().isQtQuickItem()) { + return newModelNode; + } + + if (ModelNodeOperations::validateEffect(effectPath)) { + bool layerEffect = ModelNodeOperations::useLayerEffect(); + newModelNode = QmlItemNode::createQmlItemNodeForEffect(view, + targetNode, + effectPath, + layerEffect); + } + + return newModelNode; +} + +void handleTextureDrop(const QMimeData *mimeData, const ModelNode &targetModelNode) +{ + AbstractView *view = targetModelNode.view(); + QTC_ASSERT(view, return ); + + QmlObjectNode targetNode(targetModelNode); + + if (!targetNode.isValid()) + return; + + qint32 internalId = mimeData->data(Constants::MIME_TYPE_TEXTURE).toInt(); + ModelNode texNode = view->modelNodeForInternalId(internalId); + QTC_ASSERT(texNode.isValid(), return ); + + if (targetNode.modelNode().metaInfo().isQtQuick3DModel()) { + view->emitCustomNotification("apply_texture_to_model3D", {targetNode, texNode}); + } else { + auto *dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, + texNode, + Core::ICore::dialogParent()); + if (dialog) { + bool soloProperty = dialog->isSoloProperty(); + if (!soloProperty) + dialog->exec(); + + if (soloProperty || dialog->result() == QDialog::Accepted) + targetNode.setBindingProperty(dialog->selectedProperty(), texNode.id()); + + delete dialog; + } + } +} + +void handleMaterialDrop(const QMimeData *mimeData, const ModelNode &targetNode) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return ); + + if (!targetNode.metaInfo().isQtQuick3DModel()) + return; + + qint32 internalId = mimeData->data(Constants::MIME_TYPE_MATERIAL).toInt(); + ModelNode matNode = view->modelNodeForInternalId(internalId); + + view->executeInTransaction(__FUNCTION__, [&] { + MaterialUtils::assignMaterialTo3dModel(view, targetNode, matNode); + }); +} + +ModelNode handleItemLibraryImageDrop(const QString &imagePath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + const QString imagePathRelative + = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( + imagePath); // relative to .ui.qml file + + ModelNode newModelNode; + + if (!dropAsImage3dTexture(targetNode, + targetProperty, + imagePathRelative, + newModelNode, + outMoveNodesAfter)) { + if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) { + // if dropping an image on an existing image, set the source + targetNode.variantProperty("source").setValue(imagePathRelative); + } else { + // create an image + QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(view, + imagePath, + QPointF(), + targetProperty, + false); + if (NodeHints::fromModelNode(targetProperty.parentModelNode()) + .canBeContainerFor(newItemNode.modelNode())) { + newModelNode = newItemNode.modelNode(); + } else { + newItemNode.destroy(); + } + } + } + + return newModelNode; +} + +ModelNode handleItemLibraryFontDrop(const QString &fontFamily, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + ModelNode newModelNode; + + if (targetNode.metaInfo().isQtQuickText()) { + // if dropping into an existing Text, update font + targetNode.variantProperty("font.family").setValue(fontFamily); + } else { + // create a Text node + QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromFont(view, + fontFamily, + QPointF(), + targetProperty, + false); + if (NodeHints::fromModelNode(targetProperty.parentModelNode()) + .canBeContainerFor(newItemNode.modelNode())) { + newModelNode = newItemNode.modelNode(); + } else { + newItemNode.destroy(); + } + } + + return newModelNode; +} + +ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, + bool isFragShader, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + ModelNode newModelNode; + + const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( + shaderPath); + + if (targetNode.metaInfo().isQtQuick3DShader()) { + // if dropping into an existing Shader, update + targetNode.variantProperty("stage").setEnumeration(isFragShader ? "Shader.Fragment" + : "Shader.Vertex"); + targetNode.variantProperty("shader").setValue(relPath); + } else { + view->executeInTransaction("NavigatorTreeModel::handleItemLibraryShaderDrop", [&] { + // create a new Shader + ItemLibraryEntry itemLibraryEntry; + itemLibraryEntry.setName("Shader"); + itemLibraryEntry.setType("QtQuick3D.Shader", 1, 0); + + // set shader properties + PropertyName prop = "shader"; + QString type = "QUrl"; + QVariant val = relPath; + itemLibraryEntry.addProperty(prop, type, val); + prop = "stage"; + type = "enum"; + val = isFragShader ? "Shader.Fragment" : "Shader.Vertex"; + itemLibraryEntry.addProperty(prop, type, val); + + // create a texture + newModelNode = QmlItemNode::createQmlObjectNode(view, + itemLibraryEntry, + {}, + targetProperty, + false); + + // Rename the node based on shader source + QFileInfo fi(relPath); + newModelNode.setIdWithoutRefactoring( + view->model()->generateNewId(fi.baseName(), "shader")); + // Passes can't have children, so move shader node under parent + if (targetProperty.parentModelNode().metaInfo().isQtQuick3DPass()) { + BindingProperty listProp = targetNode.bindingProperty("shaders"); + listProp.addModelNodeToArray(newModelNode); + outMoveNodesAfter = !moveNodeToParent(targetProperty, newModelNode); + } + }); + } + + return newModelNode; +} + +ModelNode handleItemLibrarySoundDrop(const QString &soundPath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + ModelNode newModelNode; + + const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( + soundPath); + + if (targetNode.metaInfo().isQtMultimediaSoundEffect()) { + // if dropping into on an existing SoundEffect, update + targetNode.variantProperty("source").setValue(relPath); + } else { + // create a new SoundEffect + ItemLibraryEntry itemLibraryEntry; + itemLibraryEntry.setName("SoundEffect"); + itemLibraryEntry.setType("QtMultimedia.SoundEffect", 1, 0); + + // set source property + PropertyName prop = "source"; + QString type = "QUrl"; + QVariant val = relPath; + itemLibraryEntry.addProperty(prop, type, val); + + // create a texture + newModelNode = QmlItemNode::createQmlObjectNode(view, + itemLibraryEntry, + {}, + targetProperty, + false); + + // Rename the node based on source + QFileInfo fi(relPath); + newModelNode.setIdWithoutRefactoring( + view->model()->generateNewId(fi.baseName(), "soundEffect")); + } + + return newModelNode; +} + +ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter) +{ + AbstractView *view = targetNode.view(); + QTC_ASSERT(view, return {}); + + Import import = Import::createLibraryImport(QStringLiteral("QtQuick3D")); + if (!view->model()->hasImport(import, true, true)) + return {}; + + const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( + tex3DPath); // relative to qml file + + ModelNode newModelNode; + + if (!dropAsImage3dTexture(targetNode, + targetProperty, + imagePath, + newModelNode, + outMoveNodesAfter)) { + view->executeInTransaction("NavigatorTreeModel::handleItemLibraryTexture3dDrop", [&] { + // create a standalone Texture3D at drop location + newModelNode = createTextureNode(targetProperty, imagePath); + if (!NodeHints::fromModelNode(targetProperty.parentModelNode()) + .canBeContainerFor(newModelNode)) + newModelNode.destroy(); + }); + } + + return newModelNode; +} + } // namespace ModelNodeOperations } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index d30a69b6049..c73530e02dd 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -133,6 +133,30 @@ bool validateEffect(const QString &effectPath); Utils::FilePath getImagesDefaultDirectory(); +//Item Library and Assets related drop operations +ModelNode handleItemLibraryEffectDrop(const QString &effectPath, const ModelNode &targetNode); +void handleTextureDrop(const QMimeData *mimeData, const ModelNode &targetModelNode); +void handleMaterialDrop(const QMimeData *mimeData, const ModelNode &targetNode); +ModelNode handleItemLibraryImageDrop(const QString &imagePath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter); +ModelNode handleItemLibraryFontDrop(const QString &fontFamily, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode); +ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, + bool isFragShader, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter); +ModelNode handleItemLibrarySoundDrop(const QString &soundPath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode); +ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, + NodeAbstractProperty targetProperty, + const ModelNode &targetNode, + bool &outMoveNodesAfter); + // ModelNodePreviewImageOperations QVariant previewImageDataForGenericNode(const ModelNode &modelNode); QVariant previewImageDataForImageNode(const ModelNode &modelNode); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 33ed88ed722..4f6d6f6068a 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -554,9 +554,13 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); } else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)) { - handleTextureDrop(mimeData, dropModelIndex); + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + ModelNode targetNode = modelNodeForIndex(rowModelIndex); + ModelNodeOperations::handleTextureDrop(mimeData, targetNode); } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { - handleMaterialDrop(mimeData, dropModelIndex); + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + ModelNode targetNode = modelNodeForIndex(rowModelIndex); + ModelNodeOperations::handleMaterialDrop(mimeData, targetNode); } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) { QByteArray filePath = mimeData->data(Constants::MIME_TYPE_BUNDLE_TEXTURE); ModelNode targetNode(modelNodeForIndex(dropModelIndex)); @@ -607,23 +611,36 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, QString assetType = assetTypeAndData.first; QString assetData = QString::fromUtf8(assetTypeAndData.second); if (assetType == Constants::MIME_TYPE_ASSET_IMAGE) { - currNode = handleItemLibraryImageDrop(assetPath, targetProperty, - rowModelIndex, moveNodesAfter); + currNode + = ModelNodeOperations::handleItemLibraryImageDrop(assetPath, + targetProperty, + modelNodeForIndex( + rowModelIndex), + moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_FONT) { - currNode = handleItemLibraryFontDrop(assetData, // assetData is fontFamily - targetProperty, rowModelIndex); + currNode = ModelNodeOperations::handleItemLibraryFontDrop( + assetData, // assetData is fontFamily + targetProperty, + modelNodeForIndex(rowModelIndex)); } else if (assetType == Constants::MIME_TYPE_ASSET_SHADER) { - currNode = handleItemLibraryShaderDrop(assetPath, assetData == "f", - targetProperty, rowModelIndex, - moveNodesAfter); + currNode = ModelNodeOperations::handleItemLibraryShaderDrop( + assetPath, + assetData == "f", + targetProperty, + modelNodeForIndex(rowModelIndex), + moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_SOUND) { - currNode = handleItemLibrarySoundDrop(assetPath, targetProperty, - rowModelIndex); + currNode = ModelNodeOperations::handleItemLibrarySoundDrop( + assetPath, targetProperty, modelNodeForIndex(rowModelIndex)); } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { - currNode = handleItemLibraryTexture3dDrop(assetPath, targetProperty, - rowModelIndex, moveNodesAfter); + currNode = ModelNodeOperations::handleItemLibraryTexture3dDrop( + assetPath, + targetProperty, + modelNodeForIndex(rowModelIndex), + moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) { - currNode = handleItemLibraryEffectDrop(assetPath, rowModelIndex); + currNode = ModelNodeOperations::handleItemLibraryEffectDrop( + assetPath, modelNodeForIndex(rowModelIndex)); moveNodesAfter = false; } @@ -785,109 +802,6 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in } } -void NavigatorTreeModel::handleTextureDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex) -{ - QTC_ASSERT(m_view, return); - - const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); - QmlObjectNode targetNode = modelNodeForIndex(rowModelIndex); - if (!targetNode.isValid()) - return; - - qint32 internalId = mimeData->data(Constants::MIME_TYPE_TEXTURE).toInt(); - ModelNode texNode = m_view->modelNodeForInternalId(internalId); - QTC_ASSERT(texNode.isValid(), return); - - if (targetNode.modelNode().metaInfo().isQtQuick3DModel()) { - m_view->emitCustomNotification("apply_texture_to_model3D", {targetNode, texNode}); - } else { - auto *dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, texNode, Core::ICore::dialogParent()); - if (dialog) { - bool soloProperty = dialog->isSoloProperty(); - if (!soloProperty) - dialog->exec(); - - if (soloProperty || dialog->result() == QDialog::Accepted) - targetNode.setBindingProperty(dialog->selectedProperty(), texNode.id()); - - delete dialog; - } - } -} - -void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex) -{ - QTC_ASSERT(m_view, return); - - const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); - ModelNode targetNode = modelNodeForIndex(rowModelIndex); - if (!targetNode.metaInfo().isQtQuick3DModel()) - return; - - qint32 internalId = mimeData->data(Constants::MIME_TYPE_MATERIAL).toInt(); - ModelNode matNode = m_view->modelNodeForInternalId(internalId); - - m_view->executeInTransaction(__FUNCTION__, [&] { - MaterialUtils::assignMaterialTo3dModel(m_view, targetNode, matNode); - }); -} - -ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePath, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, - bool &outMoveNodesAfter) -{ - QTC_ASSERT(m_view, return {}); - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - - const QString imagePathRelative = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(imagePath); // relative to .ui.qml file - - ModelNode newModelNode; - - if (!dropAsImage3dTexture(targetNode, targetProperty, imagePathRelative, newModelNode, outMoveNodesAfter)) { - if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) { - // if dropping an image on an existing image, set the source - targetNode.variantProperty("source").setValue(imagePathRelative); - } else { - // create an image - QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(m_view, imagePath, QPointF(), targetProperty, false); - if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode())) - newModelNode = newItemNode.modelNode(); - else - newItemNode.destroy(); - } - } - - return newModelNode; -} - -ModelNode NavigatorTreeModel::handleItemLibraryFontDrop(const QString &fontFamily, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex) -{ - QTC_ASSERT(m_view, return {}); - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - - ModelNode newModelNode; - - if (targetNode.metaInfo().isQtQuickText()) { - // if dropping into an existing Text, update font - targetNode.variantProperty("font.family").setValue(fontFamily); - } else { - // create a Text node - QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromFont( - m_view, fontFamily, QPointF(), targetProperty, false); - if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode())) - newModelNode = newItemNode.modelNode(); - else - newItemNode.destroy(); - } - - return newModelNode; -} - void NavigatorTreeModel::addImport(const QString &importName) { if (!ModelUtils::addImportWithCheck(importName, m_view->model())) @@ -900,227 +814,12 @@ bool QmlDesigner::NavigatorTreeModel::moveNodeToParent(const NodeAbstractPropert NodeAbstractProperty parentProp = targetProperty.parentProperty(); if (parentProp.isValid()) { ModelNode targetModel = parentProp.parentModelNode(); - int targetRowNumber = rowCount(indexForModelNode(targetModel)); - moveNodesInteractive(parentProp, {node}, targetRowNumber, false); + parentProp.reparentHere(node); return true; } return false; } -ModelNode NavigatorTreeModel::handleItemLibraryShaderDrop(const QString &shaderPath, bool isFragShader, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, - bool &outMoveNodesAfter) -{ - QTC_ASSERT(m_view, return {}); - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - ModelNode newModelNode; - - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(shaderPath); - - if (targetNode.metaInfo().isQtQuick3DShader()) { - // if dropping into an existing Shader, update - targetNode.variantProperty("stage").setEnumeration(isFragShader ? "Shader.Fragment" - : "Shader.Vertex"); - targetNode.variantProperty("shader").setValue(relPath); - } else { - m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryShaderDrop", [&] { - // create a new Shader - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("Shader"); - itemLibraryEntry.setType("QtQuick3D.Shader", 1, 0); - - // set shader properties - PropertyName prop = "shader"; - QString type = "QUrl"; - QVariant val = relPath; - itemLibraryEntry.addProperty(prop, type, val); - prop = "stage"; - type = "enum"; - val = isFragShader ? "Shader.Fragment" : "Shader.Vertex"; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, - targetProperty, false); - - // Rename the node based on shader source - QFileInfo fi(relPath); - newModelNode.setIdWithoutRefactoring( - m_view->model()->generateNewId(fi.baseName(), "shader")); - // Passes can't have children, so move shader node under parent - if (targetProperty.parentModelNode().metaInfo().isQtQuick3DPass()) { - BindingProperty listProp = targetNode.bindingProperty("shaders"); - listProp.addModelNodeToArray(newModelNode); - outMoveNodesAfter = !moveNodeToParent(targetProperty, newModelNode); - } - }); - } - - return newModelNode; -} - -ModelNode NavigatorTreeModel::handleItemLibrarySoundDrop(const QString &soundPath, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex) -{ - QTC_ASSERT(m_view, return {}); - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - ModelNode newModelNode; - - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(soundPath); - - if (targetNode.metaInfo().isQtMultimediaSoundEffect()) { - // if dropping into on an existing SoundEffect, update - targetNode.variantProperty("source").setValue(relPath); - } else { - // create a new SoundEffect - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("SoundEffect"); - itemLibraryEntry.setType("QtMultimedia.SoundEffect", 1, 0); - - // set source property - PropertyName prop = "source"; - QString type = "QUrl"; - QVariant val = relPath; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, - targetProperty, false); - - // Rename the node based on source - QFileInfo fi(relPath); - newModelNode.setIdWithoutRefactoring( - m_view->model()->generateNewId(fi.baseName(), "soundEffect")); - } - - return newModelNode; -} - -ModelNode NavigatorTreeModel::handleItemLibraryTexture3dDrop(const QString &tex3DPath, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, - bool &outMoveNodesAfter) -{ - QTC_ASSERT(m_view, return {}); - - Import import = Import::createLibraryImport(QStringLiteral("QtQuick3D")); - if (!m_view->model()->hasImport(import, true, true)) - return {}; - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - - const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir() - .relativeFilePath(tex3DPath); // relative to qml file - - ModelNode newModelNode; - - if (!dropAsImage3dTexture(targetNode, targetProperty, imagePath, newModelNode, outMoveNodesAfter)) { - 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(); - }); - } - - return newModelNode; -} - -ModelNode NavigatorTreeModel::handleItemLibraryEffectDrop(const QString &effectPath, const QModelIndex &rowModelIndex) -{ - QTC_ASSERT(m_view, return {}); - - ModelNode targetNode(modelNodeForIndex(rowModelIndex)); - ModelNode newModelNode; - - if ((targetNode.hasParentProperty() && targetNode.parentProperty().name() == "layer.effect") - || !targetNode.metaInfo().isQtQuickItem()) - return newModelNode; - - if (ModelNodeOperations::validateEffect(effectPath)) { - bool layerEffect = ModelNodeOperations::useLayerEffect(); - newModelNode = QmlItemNode::createQmlItemNodeForEffect(m_view, targetNode, effectPath, layerEffect); - } - - return newModelNode; -} - -bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode, - const NodeAbstractProperty &targetProp, - const QString &imagePath, - ModelNode &newNode, - bool &outMoveNodesAfter) -{ - auto bindToProperty = [&](const PropertyName &propName, bool sibling) { - m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); - if (newNode.isValid()) { - targetNode.bindingProperty(propName).setExpression(newNode.validId()); - - // If dropping an image on e.g. TextureInput, create a texture on the same level as - // target, as the target doesn't support Texture children (QTBUG-86219) - if (sibling) - outMoveNodesAfter = !moveNodeToParent(targetProp, newNode); - } - }); - }; - - if (targetNode.metaInfo().isQtQuick3DDefaultMaterial() - || targetNode.metaInfo().isQtQuick3DPrincipledMaterial() - || targetNode.metaInfo().isQtQuick3DSpecularGlossyMaterial()) { - // if dropping an image on a material, create a texture instead of image - // Show texture property selection dialog - auto dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, - m_view->model()->metaInfo( - "QtQuick3D.Texture"), - Core::ICore::dialogParent()); - if (!dialog) - return false; - - dialog->exec(); - - if (dialog->result() == QDialog::Accepted) { - m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); - if (newNode.isValid()) // Automatically set the texture to selected property - targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newNode.validId()); - }); - } - - delete dialog; - return true; - } else if (targetNode.metaInfo().isQtQuick3DTextureInput()) { - bindToProperty("texture", true); - return newNode.isValid(); - } else if (targetNode.metaInfo().isQtQuick3DParticles3DSpriteParticle3D()) { - bindToProperty("sprite", false); - return newNode.isValid(); - } else if (targetNode.metaInfo().isQtQuick3DSceneEnvironment()) { - bindToProperty("lightProbe", false); - return newNode.isValid(); - } else if (targetNode.metaInfo().isQtQuick3DTexture()) { - // if dropping an image on an existing texture, set the source - targetNode.variantProperty("source").setValue(imagePath); - return true; - } else if (targetNode.metaInfo().isQtQuick3DModel()) { - QTimer::singleShot(0, this, [this, targetNode, imagePath]() { - if (m_view && targetNode.isValid()) { - // To MaterialBrowserView. Done async to avoid custom notification in transaction - m_view->emitCustomNotification( - "apply_asset_to_model3D", {targetNode}, - {DocumentManager::currentFilePath().absolutePath().pathAppended(imagePath).cleanPath().toString()}); - } - }); - return true; - } - - return false; -} - ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath) { diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index ab45294b75f..25a4d9637e7 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -93,21 +93,7 @@ private: int targetIndex, bool executeInTransaction = true); void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); - void handleTextureDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex); - void handleMaterialDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex); - ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, bool &outMoveNodesAfter); - ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex); - ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, bool isFragShader, - NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, - bool &outMoveNodesAfter); - ModelNode handleItemLibrarySoundDrop(const QString &soundPath, NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex); - ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, NodeAbstractProperty targetProperty, - const QModelIndex &rowModelIndex, bool &outMoveNodesAfter); - ModelNode handleItemLibraryEffectDrop(const QString &effectPath, const QModelIndex &rowModelIndex); + bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath);