diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2022-08-12 12:47:21 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2022-08-18 11:10:42 +0000 |
commit | 326f70c40f3f6d5abad2e1f4cad03015538995b1 (patch) | |
tree | 0c04fbc435cd6fb3c8f5959283e3a95a62525176 | |
parent | 2e8574bd7696be5d7158b56a3500fbc97dab4ac2 (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>
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 |