QmlDesigner: Links that add QtQuick3D import now also add default View3D

Links in 3D view and Content Library that add QtQuick3D import now also
add a View3D with extended scene environment, if View3D doesn't already
exist in the scene.

Fixes: QDS-14821
Change-Id: I9df6fd832e8bd0721ae2a451e7d2f3613af884fb
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Ali Kianian <ali.kianian@qt.io>
This commit is contained in:
Miikka Heikkinen
2025-02-28 14:54:08 +02:00
parent 20fe6e1e60
commit c9c0c0838d
12 changed files with 128 additions and 154 deletions

View File

@@ -477,7 +477,6 @@ extend_qtc_plugin(QmlDesigner
materialbrowserwidget.cpp materialbrowserwidget.h
materialbrowsermodel.cpp materialbrowsermodel.h
materialbrowsertexturesmodel.cpp materialbrowsertexturesmodel.h
materialutils.cpp materialutils.h
)
extend_qtc_plugin(QmlDesigner

View File

@@ -18,7 +18,6 @@
#include <designmodewidget.h>
#include <documentmanager.h>
#include <itemlibraryentry.h>
#include <materialutils.h>
#include <modelnode.h>
#include <modelnodeutils.h>
#include <nodehints.h>
@@ -2093,7 +2092,7 @@ void handleMaterialDrop(const QMimeData *mimeData, const ModelNode &targetNode)
ModelNode matNode = view->modelNodeForInternalId(internalId);
view->executeInTransaction(__FUNCTION__, [&] {
MaterialUtils::assignMaterialTo3dModel(view, targetNode, matNode);
Utils3D::assignMaterialTo3dModel(view, targetNode, matNode);
});
}

View File

@@ -3,14 +3,20 @@
#include "utils3d.h"
#include <itemlibraryentry.h>
#include <modelutils.h>
#include <nodeabstractproperty.h>
#include <nodelistproperty.h>
#include <nodemetainfo.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <qmldesignertr.h>
#include <qmlitemnode.h>
#include <qmlobjectnode.h>
#include <variantproperty.h>
#include <coreplugin/messagebox.h>
#include <utils/qtcassert.h>
#include <QRegularExpression>
@@ -342,5 +348,111 @@ ModelNode createMaterial(AbstractView *view, const NodeMetaInfo &metaInfo)
}
#endif
void addQuick3DImportAndView3D(AbstractView *view)
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (!view || !view->model() || !document || document->inFileComponentModelActive()) {
Core::AsynchronousMessageBox::warning(Tr::tr("Failed to Add Import"),
Tr::tr("Could not add QtQuick3D import to the document."));
return;
}
QString importName{"QtQuick3D"};
if (view->model()->hasImport(importName))
return;
view->executeInTransaction(__FUNCTION__, [&] {
Import import = Import::createLibraryImport(importName);
view->model()->changeImports({import}, {});
if (!view->rootModelNode().metaInfo().isQtQuickItem())
return;
ensureMaterialLibraryNode(view);
#ifndef QDS_USE_PROJECTSTORAGE
});
view->executeInTransaction(__FUNCTION__, [&] {
#endif
NodeMetaInfo view3dInfo = view->model()->qtQuick3DView3DMetaInfo();
if (!view->allModelNodesOfType(view3dInfo).isEmpty())
return;
const QList<ItemLibraryEntry> entries = view->model()->itemLibraryEntries();
// Use template file to identify correct entry, as name could be localized in the future
const QString view3dSource{"extendedview3D_template.qml"};
auto templateMatch = [&view3dSource](const ItemLibraryEntry &entry) -> bool {
return entry.templatePath().endsWith(view3dSource);
};
auto iter = std::ranges::find_if(entries, templateMatch);
if (iter == entries.end())
return;
NodeAbstractProperty targetProp = view->rootModelNode().defaultNodeAbstractProperty();
QmlObjectNode newQmlObjectNode = QmlItemNode::createQmlObjectNode(
view, *iter, QPointF(), targetProp, false);
const QList<ModelNode> models = newQmlObjectNode.modelNode().subModelNodesOfType(
view->model()->qtQuick3DModelMetaInfo());
if (!models.isEmpty())
assignMaterialTo3dModel(view, models.at(0));
});
}
// Assigns given material to a 3D model.
// The assigned material is also inserted into material library if not already there.
// If given material is not valid, first existing material from material library is used,
// or if material library is empty, a new material is created.
// This function should be called only from inside a transaction, as it potentially does many
// changes to model.
void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
const ModelNode &materialNode)
{
QTC_ASSERT(modelNode.metaInfo().isQtQuick3DModel(), return);
ModelNode matLib = Utils3D::materialLibraryNode(view);
if (!matLib)
return;
ModelNode newMaterialNode;
if (materialNode.metaInfo().isQtQuick3DMaterial()) {
newMaterialNode = materialNode;
} else {
const QList<ModelNode> materials = matLib.directSubModelNodes();
auto isMaterial = [](const ModelNode &node) -> bool {
return node.metaInfo().isQtQuick3DMaterial();
};
if (auto iter = std::ranges::find_if(materials, isMaterial); iter != materials.end())
newMaterialNode = *iter;
// if no valid material, create a new default material
if (!newMaterialNode) {
#ifdef QDS_USE_PROJECTSTORAGE
newMaterialNode = view->createModelNode("PrincipledMaterial");
#else
NodeMetaInfo metaInfo = view->model()->qtQuick3DPrincipledMaterialMetaInfo();
newMaterialNode = view->createModelNode("QtQuick3D.PrincipledMaterial",
metaInfo.majorVersion(),
metaInfo.minorVersion());
#endif
newMaterialNode.ensureIdExists();
}
}
QTC_ASSERT(newMaterialNode, return);
VariantProperty matNameProp = newMaterialNode.variantProperty("objectName");
if (matNameProp.value().isNull())
matNameProp.setValue("New Material");
if (!newMaterialNode.hasParentProperty()
|| newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) {
matLib.defaultNodeListProperty().reparentHere(newMaterialNode);
}
QmlObjectNode(modelNode).setBindingProperty("materials", newMaterialNode.id());
}
} // namespace Utils3D
} // namespace QmlDesigner

View File

@@ -54,5 +54,10 @@ ModelNode createMaterial(AbstractView *view, const TypeName &typeName);
ModelNode createMaterial(AbstractView *view, const NodeMetaInfo &metaInfo);
#endif
void addQuick3DImportAndView3D(AbstractView *view);
void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
const ModelNode &materialNode = {});
} // namespace Utils3D
} // namespace QmlDesigner

View File

@@ -35,8 +35,6 @@
#include <utils/algorithm.h>
#include <coreplugin/messagebox.h>
#ifndef QMLDESIGNER_TEST
#include <projectexplorer/kit.h>
#include <projectexplorer/projectmanager.h>
@@ -77,23 +75,7 @@ WidgetInfo ContentLibraryView::widgetInfo()
m_bundleHelper = std::make_unique<BundleHelper>(this, m_widget);
connect(m_widget, &ContentLibraryWidget::importQtQuick3D, this, [&] {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (document && !document->inFileComponentModelActive() && model()) {
#ifdef QDS_USE_PROJECTSTORAGE
Import import = Import::createLibraryImport("QtQuick3D");
model()->changeImports({import}, {});
return;
#else
if (ModelUtils::addImportWithCheck(
"QtQuick3D",
[](const Import &import) { return !import.hasVersion() || import.majorVersion() >= 6; },
model())) {
return;
}
#endif
}
Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"),
tr("Could not add QtQuick3D import to project."));
Utils3D::addQuick3DImportAndView3D(this);
});
connect(m_widget, &ContentLibraryWidget::bundleMaterialDragStarted, this,
[&] (QmlDesigner::ContentLibraryMaterial *mat) {

View File

@@ -17,7 +17,6 @@
#include <designericons.h>
#include <designersettings.h>
#include <designmodewidget.h>
#include <materialutils.h>
#include <metainfo.h>
#include <modelutils.h>
#include <nodeabstractproperty.h>
@@ -33,7 +32,6 @@
#include <variantproperty.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <qmldesignerutils/asset.h>
@@ -481,7 +479,7 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
createdNode = QmlVisualNode::createQml3DNode(
this, m_droppedEntry, edit3DWidget()->canvas()->activeScene(), pos3d).modelNode();
if (createdNode.metaInfo().isQtQuick3DModel())
MaterialUtils::assignMaterialTo3dModel(this, createdNode);
Utils3D::assignMaterialTo3dModel(this, createdNode);
});
if (createdNode.isValid())
setSelectedModelNode(createdNode);
@@ -489,7 +487,7 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
bool isModel = modelNode.metaInfo().isQtQuick3DModel();
if (m_droppedModelNode.isValid() && isModel) {
executeInTransaction(__FUNCTION__, [&] {
MaterialUtils::assignMaterialTo3dModel(this, modelNode, m_droppedModelNode);
Utils3D::assignMaterialTo3dModel(this, modelNode, m_droppedModelNode);
});
}
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) {
@@ -1400,27 +1398,6 @@ Edit3DBakeLightsAction *Edit3DView::bakeLightsAction() const
return m_bakeLightsAction.get();
}
void Edit3DView::addQuick3DImport()
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (document && !document->inFileComponentModelActive() && model()) {
#ifdef QDS_USE_PROJECTSTORAGE
Import import = Import::createLibraryImport("QtQuick3D");
model()->changeImports({import}, {});
return;
#else
if (ModelUtils::addImportWithCheck(
"QtQuick3D",
[](const Import &import) { return !import.hasVersion() || import.majorVersion() >= 6; },
model())) {
return;
}
#endif
}
Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"),
tr("Could not add QtQuick3D import to project."));
}
// This method is called upon right-clicking the view to prepare for context-menu creation. The actual
// context menu is created when nodeAtPosReady() is received from puppet
void Edit3DView::startContextMenu(const QPoint &pos)

View File

@@ -93,7 +93,6 @@ public:
Edit3DAction *edit3DAction(View3DActionType type) const;
Edit3DBakeLightsAction *bakeLightsAction() const;
void addQuick3DImport();
void startContextMenu(const QPoint &pos);
void showContextMenu();
void dropMaterial(const ModelNode &matNode, const QPointF &pos);

View File

@@ -17,7 +17,6 @@
#include <designmodewidget.h>
#include <externaldependenciesinterface.h>
#include <generatedcomponentutils.h>
#include <materialutils.h>
#include <metainfo.h>
#include <nodeabstractproperty.h>
#include <nodehints.h>
@@ -566,7 +565,7 @@ void Edit3DWidget::onCreateAction(QAction *action)
// if added node is a Model, assign it a material
if (modelNode.metaInfo().isQtQuick3DModel())
MaterialUtils::assignMaterialTo3dModel(m_view, modelNode);
Utils3D::assignMaterialTo3dModel(m_view, modelNode);
});
}
@@ -732,8 +731,7 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
void Edit3DWidget::linkActivated([[maybe_unused]] const QString &link)
{
if (m_view)
m_view->addQuick3DImport();
Utils3D::addQuick3DImportAndView3D(m_view);
}
Edit3DCanvas *Edit3DWidget::canvas() const

View File

@@ -7,13 +7,13 @@
#include "assetslibrarywidget.h"
#include "formeditorscene.h"
#include "formeditorview.h"
#include "materialutils.h"
#include "qmldesignerconstants.h"
#include <designeractionmanager.h>
#include <itemlibraryentry.h>
#include <modelnodeoperations.h>
#include <nodehints.h>
#include <rewritingexception.h>
#include <utils3d.h>
#include <utils/qtcassert.h>
@@ -455,7 +455,7 @@ void DragTool::handleView3dDrop()
const QList<ModelNode> models = dragNode.modelNode().subModelNodesOfType(
model->qtQuick3DModelMetaInfo());
QTC_ASSERT(models.size() == 1, return);
MaterialUtils::assignMaterialTo3dModel(view(), models.at(0));
Utils3D::assignMaterialTo3dModel(view(), models.at(0));
}
}
}

View File

@@ -1,76 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "materialutils.h"
#include "abstractview.h"
#include "nodelistproperty.h"
#include "nodemetainfo.h"
#include "qmlobjectnode.h"
#include "variantproperty.h"
#include <utils3d.h>
#include <utils/qtcassert.h>
namespace QmlDesigner {
// Assigns given material to a 3D model.
// The assigned material is also inserted into material library if not already there.
// If given material is not valid, first existing material from material library is used,
// or if material library is empty, a new material is created.
// This function should be called only from inside a transaction, as it potentially does many
// changes to model.
void MaterialUtils::assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
const ModelNode &materialNode)
{
QTC_ASSERT(modelNode.isValid() && modelNode.metaInfo().isQtQuick3DModel(), return);
ModelNode matLib = Utils3D::materialLibraryNode(view);
if (!matLib.isValid())
return;
ModelNode newMaterialNode;
if (materialNode.isValid() && materialNode.metaInfo().isQtQuick3DMaterial()) {
newMaterialNode = materialNode;
} else {
const QList<ModelNode> materials = matLib.directSubModelNodes();
if (materials.size() > 0) {
for (const ModelNode &mat : materials) {
if (mat.metaInfo().isQtQuick3DMaterial()) {
newMaterialNode = mat;
break;
}
}
}
// if no valid material, create a new default material
if (!newMaterialNode.isValid()) {
#ifdef QDS_USE_PROJECTSTORAGE
newMaterialNode = view->createModelNode("PrincipledMaterial");
#else
NodeMetaInfo metaInfo = view->model()->qtQuick3DPrincipledMaterialMetaInfo();
newMaterialNode = view->createModelNode("QtQuick3D.PrincipledMaterial",
metaInfo.majorVersion(),
metaInfo.minorVersion());
#endif
newMaterialNode.ensureIdExists();
}
}
QTC_ASSERT(newMaterialNode.isValid(), return);
VariantProperty matNameProp = newMaterialNode.variantProperty("objectName");
if (matNameProp.value().isNull())
matNameProp.setValue("New Material");
if (!newMaterialNode.hasParentProperty()
|| newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) {
matLib.defaultNodeListProperty().reparentHere(newMaterialNode);
}
QmlObjectNode(modelNode).setBindingProperty("materials", newMaterialNode.id());
}
} // namespace QmlDesigner

View File

@@ -1,20 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "modelnode.h"
namespace QmlDesigner {
class AbstractView;
class MaterialUtils
{
public:
MaterialUtils();
static void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
const ModelNode &materialNode = {});
};
} // namespace QmlDesigner

View File

@@ -20,7 +20,6 @@
#include <designmodewidget.h>
#include <import.h>
#include <itemlibraryentry.h>
#include <materialutils.h>
#include <modelutils.h>
#include <nodeabstractproperty.h>
#include <nodehints.h>
@@ -773,7 +772,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
newQmlObjectNode.destroy();
return;
}
MaterialUtils::assignMaterialTo3dModel(m_view, targetNode, newModelNode);
Utils3D::assignMaterialTo3dModel(m_view, targetNode, newModelNode);
} else {
ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded(
targetNode, newModelNode, Core::ICore::dialogParent());
@@ -814,9 +813,9 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
const QList<ModelNode> models = newModelNode.subModelNodesOfType(
m_view->model()->qtQuick3DModelMetaInfo());
QTC_ASSERT(models.size() == 1, return);
MaterialUtils::assignMaterialTo3dModel(m_view, models.at(0));
Utils3D::assignMaterialTo3dModel(m_view, models.at(0));
} else if (newModelNode.metaInfo().isQtQuick3DModel()) {
MaterialUtils::assignMaterialTo3dModel(m_view, newModelNode);
Utils3D::assignMaterialTo3dModel(m_view, newModelNode);
}
if (!validContainer) {