diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 8eee99d9b27..f4cdddeaca1 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -12,9 +12,6 @@ import EffectMakerBackend Item { id: root - property var effectMakerModel: EffectMakerBackend.effectMakerModel - property var rootView: EffectMakerBackend.rootView - Column { id: col anchors.fill: parent @@ -28,7 +25,7 @@ Item { color: StudioTheme.Values.themeToolbarBackground Row { - // TODO: Filter row + // TODO } } @@ -62,6 +59,7 @@ Item { effectNodesWindow.x = a.x + b.x + effectNodesComboBox.width - effectNodesWindow.width effectNodesWindow.y = a.y + b.y + effectNodesComboBox.height - 1 + effectNodesWindow.show() effectNodesWindow.requestActivate() } @@ -74,7 +72,7 @@ Item { Window { id: effectNodesWindow - width: 600 + width: row.width height: Math.min(400, Screen.height - y - 40) // TODO: window sizing will be refined flags: Qt.Popup | Qt.FramelessWindowHint @@ -85,9 +83,84 @@ Item { Rectangle { anchors.fill: parent - color: StudioTheme.Values.themePopupBackground + color: StudioTheme.Values.themePanelBackground border.color: StudioTheme.Values.themeInteraction border.width: 1 + + Row { + id: row + + onWidthChanged: { + // Needed to update on first window showing, as row.width only gets + // correct value after the window is shown, so first showing is off + + var a = root.mapToGlobal(0, 0) + var b = effectNodesComboBox.mapToItem(root, 0, 0) + + effectNodesWindow.x = a.x + b.x + effectNodesComboBox.width - row.width + } + + padding: 10 + spacing: 10 + + Repeater { + model: EffectMakerBackend.effectMakerNodesModel + + Column { + spacing: 10 + + Text { + text: categoryName + color: StudioTheme.Values.themeTextColor + font.pointSize: StudioTheme.Values.baseFontSize + } + + Item { width: 1; height: 10 } // spacer + + Repeater { + model: categoryNodes + + Rectangle { + width: 180 + height: 30 + + color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction + : "transparent" + + MouseArea { + id: mouseArea + + anchors.fill: parent + hoverEnabled: true + } + + Row { + spacing: 5 + + Image { + id: nodeIcon + + width: 30 + height: 30 + + Rectangle { // TODO: placeholder until setting image source + anchors.fill: parent + color: "gray" + } + } + + Text { + text: modelData.nodeName + color: StudioTheme.Values.themeTextColor + font.pointSize: StudioTheme.Values.baseFontSize + anchors.verticalCenter: nodeIcon.verticalCenter + } + } + } + } + } + } + } } } } @@ -123,7 +196,7 @@ Item { Repeater { id: categories width: root.width - model: effectMakerModel + model: EffectMakerBackend.effectMakerModel delegate: HelperWidgets.Section { id: effectsSection diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 78895e0a340..409bf10c3fd 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -712,8 +712,9 @@ extend_qtc_plugin(QmlDesigner effectmakerwidget.cpp effectmakerwidget.h effectmakerview.cpp effectmakerview.h effectmakermodel.cpp effectmakermodel.h + effectmakernodesmodel.cpp effectmakernodesmodel.h effectnode.cpp effectnode.h - effectscategory.cpp effectscategory.h + effectnodescategory.cpp effectnodescategory.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp index 85c9e9942e3..5adae133b5c 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp @@ -40,13 +40,13 @@ QVariant EffectMakerModel::data(const QModelIndex &index, int role) const if (index.row() < 0 || index.row() >= m_categories.count()) return {}; - const EffectsCategory *category = m_categories[index.row()]; + const EffectNodesCategory *category = m_categories.at(index.row()); if (role == CategoryRole) return category->name(); if (role == EffectsRole) { QStringList effectsNames; - const QList effects = category->effects(); + const QList effects = category->nodes(); for (const EffectNode *effect : effects) effectsNames << effect->name(); @@ -90,7 +90,7 @@ void EffectMakerModel::loadModel() itEffects.next(); effects.push_back(new EffectNode(QFileInfo(itEffects.fileName()).baseName())); } - EffectsCategory *category = new EffectsCategory(itCategories.fileName(), effects); + EffectNodesCategory *category = new EffectNodesCategory(itCategories.fileName(), effects); m_categories.push_back(category); endInsertRows(); } diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h index e7ed32aa64f..1278a1c5af6 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h @@ -5,7 +5,7 @@ #include -#include "effectscategory.h" +#include "effectnodescategory.h" namespace Utils { class FilePath; @@ -37,7 +37,7 @@ public: void loadModel(); void resetModel(); - QList categories() { return m_categories; } + QList categories() { return m_categories; } Q_INVOKABLE void selectEffect(int idx, bool force = false); Q_INVOKABLE void applyToSelected(qint64 internalId, bool add = false); @@ -51,7 +51,7 @@ private: bool isValidIndex(int idx) const; static Utils::FilePath getQmlEffectsPath(); - QList m_categories; + QList m_categories; int m_selectedIndex = -1; bool m_isEmpty = true; diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.cpp new file mode 100644 index 00000000000..1c7ff72de1c --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "effectmakernodesmodel.h" + +#include +#include +#include + +#include + +#include + +namespace QmlDesigner { + +EffectMakerNodesModel::EffectMakerNodesModel(QObject *parent) + : QAbstractListModel{parent} +{ +} + +QHash EffectMakerNodesModel::roleNames() const +{ + QHash roles; + roles[CategoryNameRole] = "categoryName"; + roles[CategoryNodesRole] = "categoryNodes"; + + return roles; +} + +int EffectMakerNodesModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return m_categories.count(); +} + +QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const +{ + QTC_ASSERT(index.isValid() && index.row() < m_categories.size(), return {}); + QTC_ASSERT(roleNames().contains(role), return {}); + + return m_categories.at(index.row())->property(roleNames().value(role)); +} + +// static +Utils::FilePath EffectMakerNodesModel::getQmlEffectNodesPath() +{ + const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget(); + if (!target) { + qWarning() << __FUNCTION__ << "No project open"; + return ""; + } + + const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); + return baseQtVersion->qmlPath().pathAppended("QtQuickEffectMaker/defaultnodes"); +} + +void EffectMakerNodesModel::loadModel() +{ + const Utils::FilePath effectsPath = getQmlEffectNodesPath(); + + if (!effectsPath.exists()) { + qWarning() << __FUNCTION__ << "Effects not found."; + return; + } + + QDirIterator itCategories(effectsPath.toString(), QDir::Dirs | QDir::NoDotAndDotDot); + while (itCategories.hasNext()) { + itCategories.next(); + + if (itCategories.fileName() == "images") + continue; + + QList effects = {}; + Utils::FilePath categoryPath = effectsPath.resolvePath(itCategories.fileName()); + QDirIterator itEffects(categoryPath.toString(), QDir::Files | QDir::NoDotAndDotDot); + while (itEffects.hasNext()) { + itEffects.next(); + effects.push_back(new EffectNode(QFileInfo(itEffects.fileName()).baseName())); + } + EffectNodesCategory *category = new EffectNodesCategory(itCategories.fileName(), effects); + m_categories.push_back(category); + } + + resetModel(); +} + +void EffectMakerNodesModel::resetModel() +{ + beginResetModel(); + endResetModel(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.h new file mode 100644 index 00000000000..022111ea2c0 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakernodesmodel.h @@ -0,0 +1,43 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include "effectnodescategory.h" + +namespace Utils { +class FilePath; +} + +namespace QmlDesigner { + +class EffectMakerNodesModel : public QAbstractListModel +{ + Q_OBJECT + + enum Roles { + CategoryNameRole = Qt::UserRole + 1, + CategoryNodesRole + }; + +public: + EffectMakerNodesModel(QObject *parent = nullptr); + + QHash roleNames() const override; + int rowCount(const QModelIndex & parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void loadModel(); + void resetModel(); + + QList categories() const { return m_categories; } + +private: + static Utils::FilePath getQmlEffectNodesPath(); + + QList m_categories; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp index 7460fb0bd66..8ac65ed4558 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp @@ -4,7 +4,7 @@ #include "effectmakerview.h" #include "effectmakerwidget.h" -#include "effectmakermodel.h" +#include "effectmakernodesmodel.h" #include "designmodecontext.h" #include "nodeinstanceview.h" @@ -57,7 +57,7 @@ void EffectMakerView::modelAttached(Model *model) // Add some dummy effects data //m_widget->effectMakerModel()->setEffects({"Drop Shadow", "Colorize", "Fast Blue"}); // TODO - m_widget->effectMakerModel()->loadModel(); + m_widget->effectMakerNodesModel()->loadModel(); } void EffectMakerView::modelAboutToBeDetached(Model *model) diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp index 31ad0d5a2a1..bf85a77d115 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp @@ -4,6 +4,7 @@ #include "effectmakerwidget.h" #include "effectmakermodel.h" +#include "effectmakernodesmodel.h" #include "effectmakerview.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" @@ -33,6 +34,7 @@ static QString propertyEditorResourcesPath() EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) : m_effectMakerModel{new EffectMakerModel(this)} + , m_effectMakerNodesModel{new EffectMakerNodesModel(this)} , m_effectMakerView(view) , m_quickWidget{new StudioQuickWidget(this)} { @@ -59,7 +61,8 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_EFFECTMAKER_TIME); auto map = m_quickWidget->registerPropertyMap("EffectMakerBackend"); - map->setProperties({{"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())}, + map->setProperties({{"effectMakerNodesModel", QVariant::fromValue(m_effectMakerNodesModel.data())}, + {"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())}, {"rootView", QVariant::fromValue(this)}}); // init the first load of the QML UI elements @@ -91,6 +94,11 @@ QPointer EffectMakerWidget::effectMakerModel() const return m_effectMakerModel; } +QPointer EffectMakerWidget::effectMakerNodesModel() const +{ + return m_effectMakerNodesModel; +} + void EffectMakerWidget::focusSection(int section) { Q_UNUSED(section) diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h index 243c8aad14e..74df8d8eec1 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h @@ -13,6 +13,7 @@ namespace QmlDesigner { class EffectMakerView; class EffectMakerModel; +class EffectMakerNodesModel; class EffectMakerWidget : public QFrame { @@ -32,10 +33,10 @@ public: StudioQuickWidget *quickWidget() const; QPointer effectMakerModel() const; + QPointer effectMakerNodesModel() const; Q_INVOKABLE void focusSection(int section); - protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -43,6 +44,7 @@ private: void reloadQmlSource(); QPointer m_effectMakerModel; + QPointer m_effectMakerNodesModel; QPointer m_effectMakerView; QPointer m_quickWidget; }; diff --git a/src/plugins/qmldesigner/components/effectmaker/effectnode.h b/src/plugins/qmldesigner/components/effectmaker/effectnode.h index 74571193f7c..b9a51c7f044 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectnode.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectnode.h @@ -7,8 +7,12 @@ namespace QmlDesigner { -class EffectNode +class EffectNode : public QObject { + Q_OBJECT + + Q_PROPERTY(QString nodeName MEMBER m_name CONSTANT) + public: EffectNode(const QString &name); diff --git a/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.cpp b/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.cpp new file mode 100644 index 00000000000..36a8f0a0d06 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "effectnodescategory.h" + +namespace QmlDesigner { + +EffectNodesCategory::EffectNodesCategory(const QString &name, const QList &nodes) + : m_name(name), + m_categoryNodes(nodes) {} + +QString EffectNodesCategory::name() const +{ + return m_name; +} + +QList EffectNodesCategory::nodes() const +{ + return m_categoryNodes; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.h b/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.h new file mode 100644 index 00000000000..ba7d6868bc6 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectnodescategory.h @@ -0,0 +1,30 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "effectnode.h" + +#include + +namespace QmlDesigner { + +class EffectNodesCategory : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString categoryName MEMBER m_name CONSTANT) + Q_PROPERTY(QList categoryNodes MEMBER m_categoryNodes CONSTANT) + +public: + EffectNodesCategory(const QString &name, const QList &nodes); + + QString name() const; + QList nodes() const; + +private: + QString m_name; + QList m_categoryNodes; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp b/src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp deleted file mode 100644 index a5b4843fc53..00000000000 --- a/src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "effectscategory.h" - -namespace QmlDesigner { - -EffectsCategory::EffectsCategory(const QString &name, const QList &subcategories) - : m_name(name), - m_effects(subcategories) {} - -QString EffectsCategory::name() const -{ - return m_name; -} - -QList EffectsCategory::effects() const -{ - return m_effects; -} - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectscategory.h b/src/plugins/qmldesigner/components/effectmaker/effectscategory.h deleted file mode 100644 index aa4fc22eb92..00000000000 --- a/src/plugins/qmldesigner/components/effectmaker/effectscategory.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "effectnode.h" - -#include - -namespace QmlDesigner { - -class EffectsCategory -{ -public: - EffectsCategory(const QString &name, const QList &subcategories); - - QString name() const; - QList effects() const; - -private: - QString m_name; - QList m_effects; -}; - -} // namespace QmlDesigner