QmlDesigner: Add backend for materials in PropertyEditor

Task-number: QDS-14784
Change-Id: I531124231545971c5ceb171da8685efeb3eaf0fb
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2025-02-20 11:30:17 +02:00
parent 037b32ef33
commit 7222a14808
7 changed files with 486 additions and 13 deletions

View File

@@ -422,6 +422,7 @@ extend_qtc_plugin(QmlDesigner
propertynamevalidator.cpp propertynamevalidator.h
tooltip.cpp tooltip.h
qmlanchorbindingproxy.cpp qmlanchorbindingproxy.h
qmlmaterialnodeproxy.cpp qmlmaterialnodeproxy.h
qmlmodelnodeproxy.cpp qmlmodelnodeproxy.h
quick2propertyeditorview.cpp quick2propertyeditorview.h
propertyeditorutils.cpp propertyeditorutils.h

View File

@@ -30,6 +30,7 @@
#include <coreplugin/messagebox.h>
#include <qmljs/qmljssimplereader.h>
#include <utils/algorithm.h>
#include <utils/array.h>
#include <utils/environment.h>
#include <utils/fileutils.h>
#include <utils/smallstring.h>
@@ -90,6 +91,19 @@ namespace QmlDesigner {
using namespace Qt::StringLiterals;
static bool isMaterialAuxiliaryKey(AuxiliaryDataKeyView key)
{
static constexpr auto previewKeys = Utils::to_array<AuxiliaryDataKeyView>(
materialPreviewEnvDocProperty,
materialPreviewEnvValueDocProperty,
materialPreviewModelDocProperty,
materialPreviewEnvProperty,
materialPreviewEnvValueProperty,
materialPreviewModelProperty);
return std::ranges::find(previewKeys, key) != std::ranges::end(previewKeys);
}
PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor,
AsynchronousImageCache &imageCache)
: m_view(Utils::makeUniqueObjectPtr<Quick2PropertyEditorView>(imageCache))
@@ -307,19 +321,41 @@ void PropertyEditorQmlBackend::handleInstancePropertyChangedInModelNodeProxy(
m_backendModelNode.handleInstancePropertyChanged(modelNode, propertyName);
}
void PropertyEditorQmlBackend::handleAuxiliaryDataChanges(const QmlObjectNode &qmlObjectNode,
AuxiliaryDataKeyView key)
{
if (qmlObjectNode.isRootModelNode() && isMaterialAuxiliaryKey(key)) {
m_backendMaterialNode.handleAuxiliaryPropertyChanges();
m_view->instanceImageProvider()->invalidate();
}
}
void PropertyEditorQmlBackend::handleVariantPropertyChangedInModelNodeProxy(const VariantProperty &property)
{
m_backendModelNode.handleVariantPropertyChanged(property);
updateInstanceImage();
}
void PropertyEditorQmlBackend::handleBindingPropertyChangedInModelNodeProxy(const BindingProperty &property)
{
m_backendModelNode.handleBindingPropertyChanged(property);
updateInstanceImage();
}
void PropertyEditorQmlBackend::handleBindingPropertyInModelNodeProxyAboutToChange(
const BindingProperty &property)
{
if (m_backendMaterialNode.materialNode()) {
ModelNode expressionNode = property.resolveToModelNode();
if (expressionNode.metaInfo().isQtQuick3DTexture())
updateInstanceImage();
}
}
void PropertyEditorQmlBackend::handlePropertiesRemovedInModelNodeProxy(const AbstractProperty &property)
{
m_backendModelNode.handlePropertiesRemoved(property);
updateInstanceImage();
}
void PropertyEditorQmlBackend::handleModelNodePreviewPixmapChanged(const ModelNode &node,
@@ -496,10 +532,15 @@ void QmlDesigner::PropertyEditorQmlBackend::createPropertyEditorValues(const Qml
#endif
}
void PropertyEditorQmlBackend::updateInstanceImage()
{
m_view->instanceImageProvider()->invalidate();
refreshPreview();
}
void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor)
{
if (qmlObjectNode.isValid()) {
m_contextObject->setModel(propertyEditor->model());
qCInfo(propertyEditorBenchmark) << Q_FUNC_INFO;
@@ -517,6 +558,8 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
m_backendModelNode.setup(qmlObjectNode.modelNode());
context()->setContextProperty("modelNodeBackend", &m_backendModelNode);
m_backendMaterialNode.setup(qmlObjectNode);
// className
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
@@ -607,6 +650,7 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
contextObject()->setHasQuick3DImport(propertyEditor->model()->hasImport("QtQuick3D"));
m_view->instanceImageProvider()->setModelNode(propertyEditor->firstSelectedModelNode());
updateInstanceImage();
qCInfo(propertyEditorBenchmark) << "final:" << time.elapsed();
} else {
@@ -950,6 +994,7 @@ void PropertyEditorQmlBackend::setupContextProperties()
{
context()->setContextProperties({
{"modelNodeBackend", QVariant::fromValue(&m_backendModelNode)},
{"materialNodeBackend", QVariant::fromValue(&m_backendMaterialNode)},
{"anchorBackend", QVariant::fromValue(&m_backendAnchorBinding)},
{"transaction", QVariant::fromValue(m_propertyEditorTransaction.get())},
{"dummyBackendValue", QVariant::fromValue(m_dummyPropertyEditorValue.get())},

View File

@@ -7,6 +7,7 @@
#include "propertyeditorcontextobject.h"
#include "propertyeditorvalue.h"
#include "qmlanchorbindingproxy.h"
#include "qmlmaterialnodeproxy.h"
#include "qmlmodelnodeproxy.h"
#include "quick2propertyeditorview.h"
@@ -84,8 +85,10 @@ public:
void handleInstancePropertyChangedInModelNodeProxy(const ModelNode &modelNode,
PropertyNameView propertyName);
void handleAuxiliaryDataChanges(const QmlObjectNode &qmlObjectNode, AuxiliaryDataKeyView key);
void handleVariantPropertyChangedInModelNodeProxy(const VariantProperty &property);
void handleBindingPropertyChangedInModelNodeProxy(const BindingProperty &property);
void handleBindingPropertyInModelNodeProxyAboutToChange(const BindingProperty &property);
void handlePropertiesRemovedInModelNodeProxy(const AbstractProperty &property);
void handleModelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
@@ -95,6 +98,7 @@ public:
void refreshBackendModel();
void refreshPreview();
void updateInstanceImage();
void setupContextProperties();
@@ -124,6 +128,7 @@ private:
Utils::UniqueObjectPtr<Quick2PropertyEditorView> m_view = nullptr;
QmlAnchorBindingProxy m_backendAnchorBinding;
QmlMaterialNodeProxy m_backendMaterialNode;
QmlModelNodeProxy m_backendModelNode;
std::unique_ptr<PropertyEditorTransaction> m_propertyEditorTransaction;
std::unique_ptr<PropertyEditorValue> m_dummyPropertyEditorValue;

View File

@@ -755,6 +755,7 @@ void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
QTC_ASSERT(m_qmlBackEndForCurrentType, return );
bool changed = false;
for (const AbstractProperty &property : propertyList) {
m_qmlBackEndForCurrentType->handlePropertiesRemovedInModelNodeProxy(property);
@@ -765,6 +766,7 @@ void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) {
m_locked = true;
changed = true;
const PropertyName propertyName = property.name().toByteArray();
PropertyName convertedpropertyName = propertyName;
@@ -814,6 +816,8 @@ void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(m_selectedNode);
}
}
if (changed)
m_qmlBackEndForCurrentType->updateInstanceImage();
}
void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
@@ -823,6 +827,11 @@ void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>&
QTC_ASSERT(m_qmlBackEndForCurrentType, return );
bool changed = false;
bool selectedNodeIsMaterial = m_selectedNode.metaInfo().isQtQuick3DMaterial();
bool selectedNodeHasBindingProperties = !m_selectedNode.bindingProperties().isEmpty();
for (const VariantProperty &property : propertyList) {
m_qmlBackEndForCurrentType->handleVariantPropertyChangedInModelNodeProxy(property);
@@ -841,17 +850,38 @@ void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>&
setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).instanceValue(property.name()));
else
setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).modelValue(property.name()));
changed = true;
}
if (!changed) {
// Check if property changes affects the selected node preview
if (selectedNodeIsMaterial && selectedNodeHasBindingProperties
&& node.metaInfo().isQtQuick3DTexture()) {
changed = true;
}
}
}
void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags /*propertyChange*/)
if (changed)
m_qmlBackEndForCurrentType->updateInstanceImage();
}
void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
PropertyChangeFlags /*propertyChange*/)
{
if (locked() || noValidSelection())
if (noValidSelection())
return;
QTC_ASSERT(m_qmlBackEndForCurrentType, return);
if (locked()) {
for (const BindingProperty &property : propertyList)
m_qmlBackEndForCurrentType->handleBindingPropertyInModelNodeProxyAboutToChange(property);
return;
}
bool changed = false;
for (const BindingProperty &property : propertyList) {
m_qmlBackEndForCurrentType->handleBindingPropertyChangedInModelNodeProxy(property);
@@ -868,8 +898,12 @@ void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty> &
QString exp = QmlObjectNode(m_selectedNode).bindingProperty(property.name()).expression();
m_qmlBackEndForCurrentType->setExpression(property.name(), exp);
m_locked = false;
changed = true;
}
}
if (changed)
m_qmlBackEndForCurrentType->updateInstanceImage();
}
void PropertyEditorView::auxiliaryDataChanged(const ModelNode &node,
@@ -879,10 +913,21 @@ void PropertyEditorView::auxiliaryDataChanged(const ModelNode &node,
if (noValidSelection())
return;
bool saved = false;
QScopeGuard rootGuard([this, node, key, &saved] {
if (node.isRootNode()) {
if (!saved)
m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(m_selectedNode, key);
m_qmlBackEndForCurrentType->handleAuxiliaryDataChanges(node, key);
}
});
if (!node.isSelected())
return;
m_qmlBackEndForCurrentType->setValueforAuxiliaryProperties(m_selectedNode, key);
saved = true;
if (key == insightEnabledProperty)
m_qmlBackEndForCurrentType->contextObject()->setInsightEnabled(data.toBool());
@@ -979,7 +1024,7 @@ void PropertyEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
QTC_ASSERT(m_qmlBackEndForCurrentType, return );
m_locked = true;
bool changed = false;
using ModelNodePropertyPair = QPair<ModelNode, PropertyName>;
for (const ModelNodePropertyPair &propertyPair : propertyList) {
const ModelNode modelNode = propertyPair.first;
@@ -989,20 +1034,21 @@ void PropertyEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
m_qmlBackEndForCurrentType->handleInstancePropertyChangedInModelNodeProxy(modelNode,
propertyName);
if (qmlObjectNode.isValid() && m_qmlBackEndForCurrentType && modelNode == m_selectedNode
if (qmlObjectNode.isValid() && modelNode == m_selectedNode
&& qmlObjectNode.currentState().isValid()) {
const AbstractProperty property = modelNode.property(propertyName);
if (modelNode == m_selectedNode || qmlObjectNode.propertyChangeForCurrentState() == qmlObjectNode) {
if ( !modelNode.hasProperty(propertyName) || modelNode.property(property.name()).isBindingProperty() )
if (!modelNode.hasProperty(propertyName) || property.isBindingProperty())
setValue(modelNode, property.name(), qmlObjectNode.instanceValue(property.name()));
else
setValue(modelNode, property.name(), qmlObjectNode.modelValue(property.name()));
changed = true;
}
}
}
if (changed)
m_qmlBackEndForCurrentType->updateInstanceImage();
m_locked = false;
}
void PropertyEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)

View File

@@ -0,0 +1,285 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmlmaterialnodeproxy.h"
#include <auxiliarydataproperties.h>
#include <designmodewidget.h>
#include <nodeinstanceview.h>
#include <nodelistproperty.h>
#include <qmldesignerplugin.h>
#include <utils3d.h>
#include <QQmlEngine>
namespace QmlDesigner {
using namespace Qt::StringLiterals;
static void renameMaterial(ModelNode &material, const QString &newName)
{
QTC_ASSERT(material.isValid(), return);
QmlObjectNode(material).setNameAndId(newName, "material");
}
QmlMaterialNodeProxy::QmlMaterialNodeProxy()
: QObject()
, m_previewUpdateTimer(this)
{
m_previewUpdateTimer.setInterval(200);
m_previewUpdateTimer.setSingleShot(true);
m_previewUpdateTimer.callOnTimeout(
std::bind_front(&QmlMaterialNodeProxy::updatePreviewModel, this));
}
QmlMaterialNodeProxy::~QmlMaterialNodeProxy() = default;
void QmlMaterialNodeProxy::setup(const QmlObjectNode &objectNode)
{
const QmlObjectNode material = objectNode.metaInfo().isQtQuick3DMaterial() ? objectNode
: QmlObjectNode{};
setMaterialNode(material);
updatePossibleTypes();
updatePreviewModel();
}
ModelNode QmlMaterialNodeProxy::materialNode() const
{
return m_materialNode;
}
void QmlMaterialNodeProxy::setPossibleTypes(const QStringList &types)
{
if (types == m_possibleTypes)
return;
m_possibleTypes = types;
emit possibleTypesChanged();
updatePossibleTypeIndex();
}
void QmlMaterialNodeProxy::updatePossibleTypes()
{
static const QStringList basicTypes{
"CustomMaterial",
"DefaultMaterial",
"PrincipledMaterial",
"SpecularGlossyMaterial",
};
const QString &matType = materialNode().simplifiedTypeName();
setPossibleTypes(basicTypes.contains(matType) ? basicTypes : QStringList{matType});
setCurrentType(matType);
}
void QmlMaterialNodeProxy::setCurrentType(const QString &type)
{
m_currentType = type.split('.').last();
updatePossibleTypeIndex();
}
void QmlMaterialNodeProxy::toolBarAction(int action)
{
QTC_ASSERT(hasQuick3DImport(), return);
switch (ToolBarAction(action)) {
case ToolBarAction::ApplyToSelected: {
Utils3D::applyMaterialToModels(materialView(),
materialNode(),
Utils3D::getSelectedModels(materialView()));
break;
}
case ToolBarAction::ApplyToSelectedAdd: {
Utils3D::applyMaterialToModels(materialView(),
materialNode(),
Utils3D::getSelectedModels(materialView()),
true);
break;
}
case ToolBarAction::AddNewMaterial: {
if (!materialNode())
break;
ModelNode newMatNode;
AbstractView *view = materialView();
view->executeInTransaction(__FUNCTION__, [&] {
ModelNode matLib = Utils3D::materialLibraryNode(view);
if (!matLib.isValid())
return;
#ifdef QDS_USE_PROJECTSTORAGE
ModelNode newMatNode = view->createModelNode("PrincipledMaterial");
#else
NodeMetaInfo metaInfo = materialView()->model()->qtQuick3DPrincipledMaterialMetaInfo();
newMatNode = materialView()->createModelNode("QtQuick3D.PrincipledMaterial",
metaInfo.majorVersion(),
metaInfo.minorVersion());
#endif
renameMaterial(newMatNode, "New Material");
Utils3D::materialLibraryNode(view).defaultNodeListProperty().reparentHere(newMatNode);
});
QTimer::singleShot(0, this, [newMatNode]() {
newMatNode.model()->setSelectedModelNodes({newMatNode});
});
break;
}
case ToolBarAction::DeleteCurrentMaterial: {
if (materialNode().isValid())
materialView()->executeInTransaction(__FUNCTION__, [&] { materialNode().destroy(); });
break;
}
case ToolBarAction::OpenMaterialBrowser: {
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser", true);
break;
}
}
}
void QmlMaterialNodeProxy::setPreviewEnv(const QString &envAndValue)
{
if (envAndValue.isEmpty())
return;
if (!hasQuick3DImport())
return;
AbstractView *view = m_materialNode.modelNode().view();
ModelNode rootModelNode = view->rootModelNode();
QStringList parts = envAndValue.split('=');
QString env = parts[0];
QString value;
if (parts.size() > 1)
value = parts[1];
if (env == "Color" && value.isEmpty())
value = rootModelNode.auxiliaryDataWithDefault(materialPreviewColorDocProperty).toString();
auto renderPreviews = [rootModelNode](const QString &auxEnv, const QString &auxValue) {
if (!rootModelNode)
return;
rootModelNode.setAuxiliaryData(materialPreviewEnvDocProperty, auxEnv);
rootModelNode.setAuxiliaryData(materialPreviewEnvProperty, auxEnv);
rootModelNode.setAuxiliaryData(materialPreviewEnvValueDocProperty, auxValue);
rootModelNode.setAuxiliaryData(materialPreviewEnvValueProperty, auxValue);
if (auxEnv == "Color" && !auxValue.isEmpty())
rootModelNode.setAuxiliaryData(materialPreviewColorDocProperty, auxEnv);
rootModelNode.view()->emitCustomNotification("refresh_material_browser", {});
};
QMetaObject::invokeMethod(view, renderPreviews, env, value);
}
void QmlMaterialNodeProxy::setPreviewModel(const QString &modelStr)
{
if (modelStr.isEmpty())
return;
if (!hasQuick3DImport())
return;
AbstractView *view = m_materialNode.modelNode().view();
ModelNode rootModelNode = view->rootModelNode();
auto renderPreviews = [rootModelNode](const QString &modelStr) {
if (!rootModelNode)
return;
rootModelNode.setAuxiliaryData(materialPreviewModelDocProperty, modelStr);
rootModelNode.setAuxiliaryData(materialPreviewModelProperty, modelStr);
rootModelNode.view()->emitCustomNotification("refresh_material_browser", {});
};
QMetaObject::invokeMethod(view, renderPreviews, modelStr);
}
void QmlMaterialNodeProxy::handleAuxiliaryPropertyChanges()
{
if (!hasQuick3DImport())
return;
m_previewUpdateTimer.start();
}
void QmlMaterialNodeProxy::registerDeclarativeType()
{
qmlRegisterType<QmlMaterialNodeProxy>("HelperWidgets", 2, 0, "QmlMaterialNodeProxy");
}
void QmlMaterialNodeProxy::updatePossibleTypeIndex()
{
int newIndex = -1;
if (!m_currentType.isEmpty())
newIndex = m_possibleTypes.indexOf(m_currentType);
// Emit valid possible type index change even if the index doesn't change, as currentIndex on
// QML side will change to default internally if model is updated
if (m_possibleTypeIndex != -1 || m_possibleTypeIndex != newIndex) {
m_possibleTypeIndex = newIndex;
emit possibleTypeIndexChanged();
}
}
void QmlMaterialNodeProxy::updatePreviewModel()
{
if (!hasQuick3DImport())
return;
AbstractView *view = m_materialNode.modelNode().view();
ModelNode rootModelNode = view->rootModelNode();
// Read auxiliary preview Data
QString env = rootModelNode.auxiliaryDataWithDefault(materialPreviewEnvDocProperty).toString();
QString envValue = rootModelNode.auxiliaryDataWithDefault(materialPreviewEnvValueDocProperty)
.toString();
QString modelStr = rootModelNode.auxiliaryDataWithDefault(materialPreviewModelDocProperty).toString();
if (!envValue.isEmpty() && env != "Basic") {
env += '=';
env += envValue;
}
if (env.isEmpty())
env = "SkyBox=preview_studio";
if (modelStr.isEmpty())
modelStr = "#Sphere";
// Set node proxy properties
if (m_previewModel != modelStr) {
m_previewModel = modelStr;
emit previewModelChanged();
}
if (m_previewEnv != env) {
m_previewEnv = env;
emit previewEnvChanged();
}
}
void QmlMaterialNodeProxy::setMaterialNode(const QmlObjectNode &material)
{
if (material == m_materialNode)
return;
m_materialNode = material;
emit materialNodeChanged();
}
bool QmlMaterialNodeProxy::hasQuick3DImport() const
{
return materialNode().isValid() && materialNode().model()->hasImport("QtQuick3D"_L1);
}
AbstractView *QmlMaterialNodeProxy::materialView() const
{
return materialNode().view();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,89 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <qmlobjectnode.h>
#include <QObject>
#include <QTimer>
namespace QmlDesigner {
class ModelNode;
class QmlMaterialNodeProxy : public QObject
{
Q_OBJECT
Q_PROPERTY(ModelNode materialNode READ materialNode NOTIFY materialNodeChanged)
Q_PROPERTY(QStringList possibleTypes READ possibleTypes NOTIFY possibleTypesChanged)
Q_PROPERTY(int possibleTypeIndex READ possibleTypeIndex NOTIFY possibleTypeIndexChanged)
Q_PROPERTY(QString previewEnv MEMBER m_previewEnv WRITE setPreviewEnv NOTIFY previewEnvChanged)
Q_PROPERTY(QString previewModel MEMBER m_previewModel WRITE setPreviewModel NOTIFY previewModelChanged)
public:
enum class ToolBarAction {
ApplyToSelected = 0,
ApplyToSelectedAdd,
AddNewMaterial,
DeleteCurrentMaterial,
OpenMaterialBrowser
};
Q_ENUM(ToolBarAction)
explicit QmlMaterialNodeProxy();
~QmlMaterialNodeProxy() override;
void setup(const QmlObjectNode &objectNode);
QStringList possibleTypes() const { return m_possibleTypes; }
ModelNode materialNode() const;
int possibleTypeIndex() const { return m_possibleTypeIndex; }
void setCurrentType(const QString &type);
Q_INVOKABLE void toolBarAction(int action);
void setPreviewEnv(const QString &envAndValue);
void setPreviewModel(const QString &modelStr);
void handleAuxiliaryPropertyChanges();
static void registerDeclarativeType();
signals:
void possibleTypesChanged();
void possibleTypeIndexChanged();
void materialNodeChanged();
void previewEnvChanged();
void previewModelChanged();
private: // Methods
void setPossibleTypes(const QStringList &types);
void updatePossibleTypes();
void updatePossibleTypeIndex();
void updatePreviewModel();
void setMaterialNode(const QmlObjectNode &material);
bool hasQuick3DImport() const;
AbstractView *materialView() const;
private:
bool m_has3DModelSelection = false;
QmlObjectNode m_materialNode;
QStringList m_possibleTypes;
int m_possibleTypeIndex = -1;
QString m_currentType;
QString m_previewEnv;
QString m_previewModel;
QTimer m_previewUpdateTimer;
};
} // namespace QmlDesigner

View File

@@ -26,6 +26,7 @@
#include "propertymodel.h"
#include "propertynamevalidator.h"
#include "qmlanchorbindingproxy.h"
#include "qmlmaterialnodeproxy.h"
#include "richtexteditor/richtexteditorproxy.h"
#include "selectiondynamicpropertiesproxymodel.h"
#include "theme.h"
@@ -65,6 +66,7 @@ void Quick2PropertyEditorView::registerQmlTypes()
ListValidator::registerDeclarativeType();
ColorPaletteBackend::registerDeclarativeType();
QmlAnchorBindingProxy::registerDeclarativeType();
QmlMaterialNodeProxy::registerDeclarativeType();
BindingEditor::registerDeclarativeType();
ActionEditor::registerDeclarativeType();
AnnotationEditor::registerDeclarativeType();