aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2022-08-12 12:47:21 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2022-08-18 11:10:42 +0000
commit326f70c40f3f6d5abad2e1f4cad03015538995b1 (patch)
tree0c04fbc435cd6fb3c8f5959283e3a95a62525176
parent2e8574bd7696be5d7158b56a3500fbc97dab4ac2 (diff)
QmlDesigner: Add support for component materials
Component materials can now be seen on material browser and their properties are properly shown on material editor Fixes: QDS-7390 Change-Id: I3f7edfe655bdb0da1fa71739c825d09d6101c386 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml18
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml13
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp70
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h27
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp2
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp108
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h7
8 files changed, 223 insertions, 24 deletions
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
index 67b5042c49..19d25e7fdc 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
@@ -64,6 +64,24 @@ PropertyEditorPane {
Item { width: 1; height: 10 }
Loader {
+ id: specificsTwo
+
+ property string theSource: specificQmlData
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ visible: theSource !== ""
+ sourceComponent: specificQmlComponent
+
+ onTheSourceChanged: {
+ active = false
+ active = true
+ }
+ }
+
+ Item { width: 1; height: 10 }
+
+ Loader {
id: specificsOne
anchors.left: parent.left
anchors.right: parent.right
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
index 3044171ad8..80ac9b2aac 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
@@ -227,17 +227,8 @@ Column {
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
ComboBox {
- currentIndex: {
- if (backendValues.__classNamePrivateInternal.value === "CustomMaterial")
- return 2
-
- if (backendValues.__classNamePrivateInternal.value === "PrincipledMaterial")
- return 1
-
- return 0
- }
-
- model: ["DefaultMaterial", "PrincipledMaterial", "CustomMaterial"]
+ currentIndex: possibleTypeIndex
+ model: possibleTypes
showExtendedFunctionButton: false
implicitWidth: StudioTheme.Values.singleControlColumnWidth
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index 51595656d5..ac792f6470 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -163,7 +163,7 @@ void MaterialBrowserView::refreshModel(bool updateImages)
bool MaterialBrowserView::isMaterial(const ModelNode &node) const
{
- if (!node.isValid() || node.isComponent())
+ if (!node.isValid())
return false;
return node.isSubclassOf("QtQuick3D.Material");
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
index 9323435db7..31105e84dc 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
@@ -32,6 +32,7 @@
#include <qmlmodelnodeproxy.h>
#include <qmlobjectnode.h>
#include <qmltimeline.h>
+#include <documentmanager.h>
#include <coreplugin/messagebox.h>
#include <utils/algorithm.h>
@@ -47,12 +48,24 @@
namespace QmlDesigner {
-MaterialEditorContextObject::MaterialEditorContextObject(QObject *parent)
+MaterialEditorContextObject::MaterialEditorContextObject(QQmlContext *context, QObject *parent)
: QObject(parent)
+ , m_qmlContext(context)
{
qmlRegisterUncreatableType<MaterialEditorContextObject>("ToolBarAction", 1, 0, "ToolBarAction", "Enum type");
}
+QQmlComponent *MaterialEditorContextObject::specificQmlComponent()
+{
+ if (m_specificQmlComponent)
+ return m_specificQmlComponent;
+
+ m_specificQmlComponent = new QQmlComponent(m_qmlContext->engine(), this);
+ m_specificQmlComponent->setData(m_specificQmlData.toUtf8(), QUrl::fromLocalFile("specifics.qml"));
+
+ return m_specificQmlComponent;
+}
+
QString MaterialEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
@@ -158,8 +171,10 @@ void MaterialEditorContextObject::changeTypeName(const QString &typeName)
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
- if (msgBox.exec() == QMessageBox::Cancel)
+ if (msgBox.exec() == QMessageBox::Cancel) {
+ updatePossibleTypeIndex();
return;
+ }
for (const auto &p : std::as_const(incompatibleProperties))
m_selectedMaterial.removeProperty(p);
@@ -275,6 +290,20 @@ void MaterialEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl)
emit specificsUrlChanged();
}
+void MaterialEditorContextObject::setSpecificQmlData(const QString &newSpecificQmlData)
+{
+ if (newSpecificQmlData == m_specificQmlData)
+ return;
+
+ m_specificQmlData = newSpecificQmlData;
+
+ delete m_specificQmlComponent;
+ m_specificQmlComponent = nullptr;
+
+ emit specificQmlComponentChanged();
+ emit specificQmlDataChanged();
+}
+
void MaterialEditorContextObject::setStateName(const QString &newStateName)
{
if (newStateName == m_stateName)
@@ -293,6 +322,23 @@ void MaterialEditorContextObject::setAllStateNames(const QStringList &allStates)
emit allStateNamesChanged();
}
+void MaterialEditorContextObject::setPossibleTypes(const QStringList &types)
+{
+ if (types == m_possibleTypes)
+ return;
+
+ m_possibleTypes = types;
+ emit possibleTypesChanged();
+
+ updatePossibleTypeIndex();
+}
+
+void MaterialEditorContextObject::setCurrentType(const QString &type)
+{
+ m_currentType = type.split('.').last();
+ updatePossibleTypeIndex();
+}
+
void MaterialEditorContextObject::setIsBaseState(bool newIsBaseState)
{
if (newIsBaseState == m_isBaseState)
@@ -339,6 +385,20 @@ void MaterialEditorContextObject::setHasAliasExport(bool hasAliasExport)
emit hasAliasExportChanged();
}
+void MaterialEditorContextObject::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 MaterialEditorContextObject::hideCursor()
{
if (QApplication::overrideCursor())
@@ -403,4 +463,10 @@ bool MaterialEditorContextObject::isBlocked(const QString &propName) const
return false;
}
+void MaterialEditorContextObject::goIntoComponent()
+{
+ QTC_ASSERT(m_model, return);
+ DocumentManager::goIntoComponent(m_selectedMaterial);
+}
+
} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h
index ed1540d574..07ce582d44 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.h
@@ -43,9 +43,13 @@ class MaterialEditorContextObject : public QObject
Q_OBJECT
Q_PROPERTY(QUrl specificsUrl READ specificsUrl WRITE setSpecificsUrl NOTIFY specificsUrlChanged)
+ Q_PROPERTY(QString specificQmlData READ specificQmlData WRITE setSpecificQmlData NOTIFY specificQmlDataChanged)
+ Q_PROPERTY(QQmlComponent *specificQmlComponent READ specificQmlComponent NOTIFY specificQmlComponentChanged)
Q_PROPERTY(QString stateName READ stateName WRITE setStateName NOTIFY stateNameChanged)
Q_PROPERTY(QStringList allStateNames READ allStateNames WRITE setAllStateNames NOTIFY allStateNamesChanged)
+ Q_PROPERTY(QStringList possibleTypes READ possibleTypes WRITE setPossibleTypes NOTIFY possibleTypesChanged)
+ Q_PROPERTY(int possibleTypeIndex READ possibleTypeIndex NOTIFY possibleTypeIndexChanged)
Q_PROPERTY(bool isBaseState READ isBaseState WRITE setIsBaseState NOTIFY isBaseStateChanged)
Q_PROPERTY(bool selectionChanged READ selectionChanged WRITE setSelectionChanged NOTIFY selectionChangedChanged)
@@ -61,11 +65,15 @@ class MaterialEditorContextObject : public QObject
Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged)
public:
- MaterialEditorContextObject(QObject *parent = nullptr);
+ MaterialEditorContextObject(QQmlContext *context, QObject *parent = nullptr);
QUrl specificsUrl() const { return m_specificsUrl; }
+ QString specificQmlData() const {return m_specificQmlData; }
+ QQmlComponent *specificQmlComponent();
QString stateName() const { return m_stateName; }
QStringList allStateNames() const { return m_allStateNames; }
+ QStringList possibleTypes() const { return m_possibleTypes; }
+ int possibleTypeIndex() const { return m_possibleTypeIndex; }
bool isBaseState() const { return m_isBaseState; }
bool selectionChanged() const { return m_selectionChanged; }
@@ -87,6 +95,7 @@ public:
Q_INVOKABLE QStringList allStatesForId(const QString &id);
Q_INVOKABLE bool isBlocked(const QString &propName) const;
+ Q_INVOKABLE void goIntoComponent();
enum ToolBarAction {
ApplyToSelected = 0,
@@ -117,8 +126,11 @@ public:
void setSelectedMaterial(const ModelNode &matNode);
void setSpecificsUrl(const QUrl &newSpecificsUrl);
+ void setSpecificQmlData(const QString &newSpecificQmlData);
void setStateName(const QString &newStateName);
void setAllStateNames(const QStringList &allStates);
+ void setPossibleTypes(const QStringList &types);
+ void setCurrentType(const QString &type);
void setIsBaseState(bool newIsBaseState);
void setSelectionChanged(bool newSelectionChanged);
void setBackendValues(QQmlPropertyMap *newBackendValues);
@@ -129,8 +141,12 @@ public:
signals:
void specificsUrlChanged();
+ void specificQmlDataChanged();
+ void specificQmlComponentChanged();
void stateNameChanged();
void allStateNamesChanged();
+ void possibleTypesChanged();
+ void possibleTypeIndexChanged();
void isBaseStateChanged();
void selectionChangedChanged();
void backendValuesChanged();
@@ -142,15 +158,22 @@ signals:
void hasModelSelectionChanged();
private:
+ void updatePossibleTypeIndex();
+
QUrl m_specificsUrl;
+ QString m_specificQmlData;
+ QQmlComponent *m_specificQmlComponent = nullptr;
+ QQmlContext *m_qmlContext = nullptr;
QString m_stateName;
QStringList m_allStateNames;
+ QStringList m_possibleTypes;
+ int m_possibleTypeIndex = -1;
+ QString m_currentType;
int m_majorVersion = 1;
QQmlPropertyMap *m_backendValues = nullptr;
- QQmlComponent *m_qmlComponent = nullptr;
Model *m_model = nullptr;
QPoint m_lastPos;
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
index 79e0e80fc5..588d62f892 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
@@ -102,7 +102,7 @@ public:
MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialEditor)
: m_view(new QQuickWidget)
, m_materialEditorTransaction(new MaterialEditorTransaction(materialEditor))
- , m_contextObject(new MaterialEditorContextObject())
+ , m_contextObject(new MaterialEditorContextObject(m_view->rootContext()))
, m_materialEditorImageProvider(new MaterialEditorImageProvider())
{
m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index 295935e8ac..d9e36363d9 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -51,6 +51,7 @@
#include <qmldesignerplugin.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <propertyeditorqmlbackend.h>
#include <QApplication>
#include <QDebug>
@@ -83,6 +84,10 @@ MaterialEditorView::MaterialEditorView(QWidget *parent)
}
});
+ m_typeUpdateTimer.setSingleShot(true);
+ m_typeUpdateTimer.setInterval(500);
+ connect(&m_typeUpdateTimer, &QTimer::timeout, this, &MaterialEditorView::updatePossibleTypes);
+
m_stackedWidget->setStyleSheet(Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
m_stackedWidget->setMinimumWidth(250);
@@ -526,14 +531,30 @@ void MaterialEditorView::setupQmlBackend()
{
QUrl qmlPaneUrl;
QUrl qmlSpecificsUrl;
+ QString specificQmlData;
+ QString currentTypeName;
if (m_selectedMaterial.isValid() && m_hasQuick3DImport) {
qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/MaterialEditorPane.qml");
+ TypeName diffClassName;
NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo();
- QDir importDir(metaInfo.importDirectoryPath() + Constants::QML_DESIGNER_SUBFOLDER);
- QString typeName = QString::fromUtf8(metaInfo.typeName().split('.').constLast());
- qmlSpecificsUrl = QUrl::fromLocalFile(importDir.absoluteFilePath(typeName + "Specifics.qml"));
+ if (metaInfo.isValid()) {
+ diffClassName = metaInfo.typeName();
+ const QList<NodeMetaInfo> hierarchy = metaInfo.classHierarchy();
+ for (const NodeMetaInfo &metaInfo : hierarchy) {
+ if (PropertyEditorQmlBackend::checkIfUrlExists(qmlSpecificsUrl))
+ break;
+ qmlSpecificsUrl = PropertyEditorQmlBackend::getQmlFileUrl(metaInfo.typeName()
+ + "Specifics", metaInfo);
+ diffClassName = metaInfo.typeName();
+ }
+ }
+ if (metaInfo.isValid() && diffClassName != m_selectedMaterial.type()) {
+ specificQmlData = PropertyEditorQmlBackend::templateGeneration(
+ metaInfo, model()->metaInfo(diffClassName), m_selectedMaterial);
+ }
+ currentTypeName = QString::fromLatin1(m_selectedMaterial.type());
} else {
qmlPaneUrl = QUrl::fromLocalFile(materialEditorResourcesPath() + "/EmptyMaterialEditorPane.qml");
}
@@ -566,11 +587,15 @@ void MaterialEditorView::setupQmlBackend()
currentQmlBackend->widget()->installEventFilter(this);
currentQmlBackend->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
currentQmlBackend->contextObject()->setHasMaterialRoot(m_hasMaterialRoot);
-
- m_stackedWidget->setCurrentWidget(currentQmlBackend->widget());
+ currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
+ currentQmlBackend->contextObject()->setCurrentType(currentTypeName);
m_qmlBackEnd = currentQmlBackend;
+
+ delayedTypeUpdate();
initPreviewData();
+
+ m_stackedWidget->setCurrentWidget(m_qmlBackEnd->widget());
}
void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value)
@@ -636,6 +661,53 @@ void MaterialEditorView::initPreviewData()
}
}
+void MaterialEditorView::delayedTypeUpdate()
+{
+ m_typeUpdateTimer.start();
+}
+
+static Import entryToImport(const ItemLibraryEntry &entry)
+{
+ if (entry.majorVersion() == -1 && entry.minorVersion() == -1)
+ return Import::createFileImport(entry.requiredImport());
+ return Import::createLibraryImport(entry.requiredImport(),
+ QString::number(entry.majorVersion()) + QLatin1Char('.') +
+ QString::number(entry.minorVersion()));
+}
+
+void MaterialEditorView::updatePossibleTypes()
+{
+ QTC_ASSERT(model(), return);
+
+ if (!m_qmlBackEnd)
+ return;
+
+ // Ensure basic types are always first
+ static const QStringList basicTypes {"DefaultMaterial", "PrincipledMaterial", "CustomMaterial"};
+ QStringList allTypes = basicTypes;
+
+ const QList<ItemLibraryEntry> itemLibEntries = m_itemLibraryInfo->entries();
+ for (const ItemLibraryEntry &entry : itemLibEntries) {
+ NodeMetaInfo metaInfo = model()->metaInfo(entry.typeName());
+ bool valid = metaInfo.isValid()
+ && (metaInfo.majorVersion() >= entry.majorVersion()
+ || metaInfo.majorVersion() < 0);
+ if (valid && metaInfo.isSubclassOf("QtQuick3D.Material")) {
+ bool addImport = entry.requiredImport().isEmpty();
+ if (!addImport) {
+ Import import = entryToImport(entry);
+ addImport = model()->hasImport(import, true, true);
+ }
+ if (addImport) {
+ QString typeName = QString::fromLatin1(entry.typeName().split('.').last());
+ if (!allTypes.contains(typeName))
+ allTypes.append(typeName);
+ }
+ }
+ }
+ m_qmlBackEnd->contextObject()->setPossibleTypes(allTypes);
+}
+
void MaterialEditorView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
@@ -653,6 +725,18 @@ void MaterialEditorView::modelAttached(Model *model)
m_ensureMatLibTimer.start(500);
}
+ if (m_itemLibraryInfo.data() != model->metaInfo().itemLibraryInfo()) {
+ if (m_itemLibraryInfo) {
+ disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
+ this, &MaterialEditorView::delayedTypeUpdate);
+ }
+ m_itemLibraryInfo = model->metaInfo().itemLibraryInfo();
+ if (m_itemLibraryInfo) {
+ connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
+ this, &MaterialEditorView::delayedTypeUpdate);
+ }
+ }
+
if (!m_setupCompleted) {
reloadQml();
m_setupCompleted = true;
@@ -816,10 +900,20 @@ void MaterialEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
m_locked = false;
}
-void MaterialEditorView::nodeTypeChanged(const ModelNode &node, const TypeName &, int, int)
+void MaterialEditorView::nodeTypeChanged(const ModelNode &node, const TypeName &typeName, int, int)
{
- if (node == m_selectedMaterial)
+ if (node == m_selectedMaterial) {
+ m_qmlBackEnd->contextObject()->setCurrentType(QString::fromLatin1(typeName));
delayedResetView();
+ }
+}
+
+void MaterialEditorView::rootNodeTypeChanged(const QString &type, int, int)
+{
+ if (rootModelNode() == m_selectedMaterial) {
+ m_qmlBackEnd->contextObject()->setCurrentType(type);
+ delayedResetView();
+ }
}
void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap)
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index cda537280f..64260ead76 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -26,6 +26,8 @@
#pragma once
#include <abstractview.h>
+#include <itemlibraryinfo.h>
+
#include <QHash>
#include <QPointer>
#include <QTimer>
@@ -70,6 +72,7 @@ public:
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
+ void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
@@ -119,9 +122,12 @@ private:
bool noValidSelection() const;
void initPreviewData();
+ void delayedTypeUpdate();
+ void updatePossibleTypes();
ModelNode m_selectedMaterial;
QTimer m_ensureMatLibTimer;
+ QTimer m_typeUpdateTimer;
QShortcut *m_updateShortcut = nullptr;
int m_timerId = 0;
QStackedWidget *m_stackedWidget = nullptr;
@@ -134,6 +140,7 @@ private:
bool m_hasMaterialRoot = false;
QPointer<QColorDialog> m_colorDialog;
+ QPointer<ItemLibraryInfo> m_itemLibraryInfo;
};
} // namespace QmlDesigner