forked from qt-creator/qt-creator
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 <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -12,20 +12,22 @@
|
||||
#include "addsignalhandlerdialog.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodehints.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <modelnode.h>
|
||||
#include <qmlitemnode.h>
|
||||
#include <variantproperty.h>
|
||||
#include <rewritingexception.h>
|
||||
#include <rewritertransaction.h>
|
||||
#include <choosefrompropertylistdialog.h>
|
||||
#include <documentmanager.h>
|
||||
#include <qmlanchors.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <signalhandlerproperty.h>
|
||||
#include <itemlibraryentry.h>
|
||||
#include <materialutils.h>
|
||||
#include <modelnode.h>
|
||||
#include <nodehints.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <qmlanchors.h>
|
||||
#include <qmlitemnode.h>
|
||||
#include <rewritertransaction.h>
|
||||
#include <rewritingexception.h>
|
||||
#include <signalhandlerproperty.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <componentcore_constants.h>
|
||||
#include <stylesheetmerger.h>
|
||||
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user