From 64377d9e0ca33b8732072af120f45a76ed18d956 Mon Sep 17 00:00:00 2001 From: Amr Essam Date: Thu, 29 Jun 2023 15:06:11 +0300 Subject: [PATCH] QmlDesigner: Implement effect maker view Initial basic logic for a view and simple functionality to be extended. The view is hidden by default during development and enabled via an env var. Task-number: QDS-10401 Change-Id: I5c2e1e20aca6c53c1ed273136ee6204145f15def Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri Reviewed-by: Amr Elsayed --- .../effectMakerQmlSources/EffectMaker.qml | 106 +++++++++++++++ .../effectMakerQmlSources/EffectNode.qml | 72 +++++++++++ src/plugins/qmldesigner/CMakeLists.txt | 11 ++ .../components/componentcore/viewmanager.cpp | 9 ++ .../effectmaker/effectmakermodel.cpp | 121 ++++++++++++++++++ .../components/effectmaker/effectmakermodel.h | 61 +++++++++ .../effectmaker/effectmakerview.cpp | 68 ++++++++++ .../components/effectmaker/effectmakerview.h | 34 +++++ .../effectmaker/effectmakerwidget.cpp | 115 +++++++++++++++++ .../effectmaker/effectmakerwidget.h | 50 ++++++++ .../components/effectmaker/effectnode.cpp | 16 +++ .../components/effectmaker/effectnode.h | 21 +++ .../effectmaker/effectscategory.cpp | 22 ++++ .../components/effectmaker/effectscategory.h | 25 ++++ src/plugins/qmldesigner/designmodecontext.cpp | 13 ++ src/plugins/qmldesigner/designmodecontext.h | 9 ++ .../qmldesigner/qmldesignerconstants.h | 3 + 17 files changed, 756 insertions(+) create mode 100644 share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml create mode 100644 share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakerview.h create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectnode.cpp create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectnode.h create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp create mode 100644 src/plugins/qmldesigner/components/effectmaker/effectscategory.h diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml new file mode 100644 index 00000000000..82a5ab44193 --- /dev/null +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -0,0 +1,106 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import EffectMakerBackend + +Item { + id: root + + property var effectMakerModel: EffectMakerBackend.effectMakerModel + property var rootView: EffectMakerBackend.rootView + + Column { + id: col + anchors.fill: parent + spacing: 5 + + Rectangle { + id: topHeader + + width: parent.width + height: StudioTheme.Values.toolbarHeight + color: StudioTheme.Values.themeToolbarBackground + + Row { + // TODO: Filter row + } + } + + Rectangle { + id: previewHeader + + width: parent.width + height: StudioTheme.Values.toolbarHeight + color: StudioTheme.Values.themeToolbarBackground + + // TODO + } + + Image { + id: previewImage + + // TODO + } + + HelperWidgets.ScrollView { + id: scrollView + + width: parent.width + height: parent.height - y + clip: true + + Behavior on contentY { + id: contentYBehavior + PropertyAnimation { + id: scrollViewAnim + easing.type: Easing.InOutQuad + } + } + + Column { + Item { + width: scrollView.width + height: categories.height + + Column { + Repeater { + id: categories + width: root.width + model: effectMakerModel + + delegate: HelperWidgets.Section { + id: effectsSection + width: root.width + caption: model.categoryName + category: "EffectMaker" + + property var effectList: model.effectNames + + onExpandedChanged: { + effects.visible = expanded // TODO: update + } + + Repeater { + id: effects + model: effectList + width: parent.width + height: parent.height + delegate: EffectNode { + width: parent.width + //height: StudioTheme.Values.checkIndicatorHeight * 2 // TODO: update or remove + } + } + } + } + } + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml new file mode 100644 index 00000000000..808abf89abe --- /dev/null +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml @@ -0,0 +1,72 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuickDesignerTheme +import HelperWidgets +import StudioControls as StudioControls +import StudioTheme 1.0 as StudioTheme +import EffectMakerBackend + +// TODO: this will be redone based on new specs + +Rectangle { + property real margin: StudioTheme.Values.marginTopBottom + + id: root + height: col.height + margin * 2 + + signal showContextMenu() + + border.width: EffectMakerBackend.effectMakerModel.selectedIndex === index ? 3 : 0 + border.color: EffectMakerBackend.effectMakerModel.selectedIndex === index + ? StudioTheme.Values.themeControlOutlineInteraction + : "transparent" + color: "transparent" + visible: true // TODO: from rolename -> effectVisible + + MouseArea { + id: mouseArea + + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onPressed: (mouse) => { + EffectMakerBackend.effectMakerModel.selectEffect(index) + EffectMakerBackend.rootView.focusSection(0) // TODO: Set the correct section based on current effect + + if (mouse.button === Qt.LeftButton) + // TODO: Start dragging here + ; + else if (mouse.button === Qt.RightButton) + root.showContextMenu() + } + } + + ColumnLayout { + id: col + Layout.topMargin: margin + Layout.bottomMargin: margin + Row { + + width: parent.width + + Text { + anchors.verticalCenter: parent.verticalCenter + rightPadding: margin * 3 + text: '⋮⋮' + color: StudioTheme.Values.themeTextColorDisabled + font.letterSpacing: -10 + font.bold: true + font.pointSize: StudioTheme.Values.mediumIconFontSize + } + + StudioControls.CheckBox { + text: modelData + actionIndicatorVisible: false + } + } + } +} diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 166ff286dab..78895e0a340 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -457,6 +457,7 @@ add_qtc_plugin(QmlDesigner ${CMAKE_CURRENT_LIST_DIR}/components/propertyeditor ${CMAKE_CURRENT_LIST_DIR}/components/stateseditor ${CMAKE_CURRENT_LIST_DIR}/components/texteditor + ${CMAKE_CURRENT_LIST_DIR}/components/effectmaker PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/designercore #can not be a public dependency -> EXCLUDE_FROM_INSTALL in QmlDesignerCore @@ -705,6 +706,16 @@ extend_qtc_plugin(QmlDesigner assetslibraryiconprovider.cpp assetslibraryiconprovider.h ) +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/effectmaker + SOURCES + effectmakerwidget.cpp effectmakerwidget.h + effectmakerview.cpp effectmakerview.h + effectmakermodel.cpp effectmakermodel.h + effectnode.cpp effectnode.h + effectscategory.cpp effectscategory.h +) + extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/navigator SOURCES diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index fc30ab99f9d..b61f09885d7 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ public: , contentLibraryView{externalDependencies} , componentView{externalDependencies} , edit3DView{externalDependencies} + , effectMakerView{externalDependencies} , formEditorView{externalDependencies} , textEditorView{externalDependencies} , assetsLibraryView{externalDependencies} @@ -74,6 +76,7 @@ public: ContentLibraryView contentLibraryView; ComponentView componentView; Edit3DView edit3DView; + EffectMakerView effectMakerView; FormEditorView formEditorView; TextEditorView textEditorView; AssetsLibraryView assetsLibraryView; @@ -206,6 +209,9 @@ QList ViewManager::standardViews() const .toBool()) list.append(&d->debugView); + if (qEnvironmentVariableIsSet("ENABLE_QDS_EFFECTMAKER")) + list.append(&d->effectMakerView); + #ifdef CHECK_LICENSE if (checkLicense() == FoundLicense::enterprise) list.append(&d->contentLibraryView); @@ -381,6 +387,9 @@ QList ViewManager::widgetInfos() const widgetInfoList.append(d->textureEditorView.widgetInfo()); widgetInfoList.append(d->statesEditorView.widgetInfo()); + if (qEnvironmentVariableIsSet("ENABLE_QDS_EFFECTMAKER")) + widgetInfoList.append(d->effectMakerView.widgetInfo()); + #ifdef CHECK_LICENSE if (checkLicense() == FoundLicense::enterprise) widgetInfoList.append(d->contentLibraryView.widgetInfo()); diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp new file mode 100644 index 00000000000..85c9e9942e3 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp @@ -0,0 +1,121 @@ +// 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 "effectmakermodel.h" + +#include +#include +#include + +#include + +#include + +namespace QmlDesigner { + +EffectMakerModel::EffectMakerModel(QObject *parent) + : QAbstractListModel{parent} +{ +} + +QHash EffectMakerModel::roleNames() const +{ + QHash roles; + roles[CategoryRole] = "categoryName"; + roles[EffectsRole] = "effectNames"; + return roles; +} + +int EffectMakerModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return m_categories.count(); +} + +QVariant EffectMakerModel::data(const QModelIndex &index, int role) const +{ + // TODO: to be updated + + if (index.row() < 0 || index.row() >= m_categories.count()) + return {}; + + const EffectsCategory *category = m_categories[index.row()]; + if (role == CategoryRole) + return category->name(); + + if (role == EffectsRole) { + QStringList effectsNames; + const QList effects = category->effects(); + for (const EffectNode *effect : effects) + effectsNames << effect->name(); + + return effectsNames; + } + + return {}; +} + +// static +Utils::FilePath EffectMakerModel::getQmlEffectsPath() +{ + 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 EffectMakerModel::loadModel() +{ + const Utils::FilePath effectsPath = getQmlEffectsPath(); + + if (!effectsPath.exists()) { + qWarning() << __FUNCTION__ << "Effects are not found."; + return; + } + QDirIterator itCategories(effectsPath.toString(), QDir::Dirs | QDir::NoDotAndDotDot); + while (itCategories.hasNext()) { + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + 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())); + } + EffectsCategory *category = new EffectsCategory(itCategories.fileName(), effects); + m_categories.push_back(category); + endInsertRows(); + } +} + +void EffectMakerModel::resetModel() +{ + beginResetModel(); + endResetModel(); +} + +void EffectMakerModel::selectEffect(int idx, bool force) +{ + Q_UNUSED(idx) + Q_UNUSED(force) + + // TODO +} + +void EffectMakerModel::applyToSelected(qint64 internalId, bool add) +{ + Q_UNUSED(internalId) + Q_UNUSED(add) + + // TODO: remove? +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h new file mode 100644 index 00000000000..e7ed32aa64f --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h @@ -0,0 +1,61 @@ +// 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 "effectscategory.h" + +namespace Utils { +class FilePath; +} + +namespace QmlDesigner { + +class EffectMakerModel : public QAbstractListModel +{ + Q_OBJECT + + enum Roles { + CategoryRole = Qt::UserRole + 1, + EffectsRole + }; + + Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) + Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) + +public: + EffectMakerModel(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; + + bool isEmpty() const { return m_isEmpty; } + + void loadModel(); + void resetModel(); + + QList categories() { return m_categories; } + + Q_INVOKABLE void selectEffect(int idx, bool force = false); + Q_INVOKABLE void applyToSelected(qint64 internalId, bool add = false); + +signals: + void isEmptyChanged(); + void selectedIndexChanged(int idx); + void hasModelSelectionChanged(); + +private: + bool isValidIndex(int idx) const; + static Utils::FilePath getQmlEffectsPath(); + + QList m_categories; + + int m_selectedIndex = -1; + bool m_isEmpty = true; + bool m_hasModelSelection = false; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp new file mode 100644 index 00000000000..7460fb0bd66 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.cpp @@ -0,0 +1,68 @@ +// 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 "effectmakerview.h" + +#include "effectmakerwidget.h" +#include "effectmakermodel.h" +#include "designmodecontext.h" +#include "nodeinstanceview.h" + +#include + +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +EffectMakerView::EffectMakerView(ExternalDependenciesInterface &externalDependencies) + : AbstractView{externalDependencies} +{ +} + +EffectMakerView::~EffectMakerView() +{} + +bool EffectMakerView::hasWidget() const +{ + return true; +} + +WidgetInfo EffectMakerView::widgetInfo() +{ + if (m_widget.isNull()) { + m_widget = new EffectMakerWidget{this}; + + auto context = new Internal::EffectMakerContext(m_widget.data()); + Core::ICore::addContextObject(context); + } + + return createWidgetInfo(m_widget.data(), "Effect Maker", WidgetInfo::LeftPane, 0, tr("Effect Maker")); +} + +void EffectMakerView::customNotification(const AbstractView * /*view*/, + const QString & /*identifier*/, + const QList & /*nodeList*/, + const QList & /*data*/) +{ + // TODO +} + +void EffectMakerView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + // Add some dummy effects data + //m_widget->effectMakerModel()->setEffects({"Drop Shadow", "Colorize", "Fast Blue"}); // TODO + m_widget->effectMakerModel()->loadModel(); +} + +void EffectMakerView::modelAboutToBeDetached(Model *model) +{ + AbstractView::modelAboutToBeDetached(model); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerview.h b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.h new file mode 100644 index 00000000000..53e58acc67d --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerview.h @@ -0,0 +1,34 @@ +// 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 "abstractview.h" + +#include + +namespace QmlDesigner { + +class EffectMakerWidget; + +class EffectMakerView : public AbstractView +{ +public: + EffectMakerView(ExternalDependenciesInterface &externalDependencies); + ~EffectMakerView() override; + + bool hasWidget() const override; + WidgetInfo widgetInfo() override; + + // AbstractView + void modelAttached(Model *model) override; + void modelAboutToBeDetached(Model *model) override; + +private: + void customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) override; + + QPointer m_widget; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp new file mode 100644 index 00000000000..8a07cc10e7b --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.cpp @@ -0,0 +1,115 @@ +// 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 "effectmakerwidget.h" + +#include "effectmakermodel.h" +#include "effectmakerview.h" +#include "qmldesignerconstants.h" +#include "qmldesignerplugin.h" +#include "theme.h" + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace QmlDesigner { + +static QString propertyEditorResourcesPath() +{ +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString(); +} + +EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) + : m_effectMakerModel{new EffectMakerModel(this)} + , m_effectMakerView(view) + , m_effectMakerWidget{new StudioQuickWidget(this)} +{ + setWindowTitle(tr("Effect Maker", "Title of effect maker widget")); + setMinimumWidth(250); + + m_effectMakerWidget->quickWidget()->installEventFilter(this); + + // create the inner widget + m_effectMakerWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_EFFECT_MAKER); + m_effectMakerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + Theme::setupTheme(m_effectMakerWidget->engine()); + m_effectMakerWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_effectMakerWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); + + auto layout = new QHBoxLayout(this); + layout->setContentsMargins({}); + layout->setSpacing(0); + layout->addWidget(m_effectMakerWidget.data()); + + setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_EFFECTMAKER_TIME); + + auto map = m_effectMakerWidget->registerPropertyMap("EffectMakerBackend"); + map->setProperties({{"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())}, + {"rootView", QVariant::fromValue(this)}}); + + // init the first load of the QML UI elements + reloadQmlSource(); +} + +bool EffectMakerWidget::eventFilter(QObject *obj, QEvent *event) +{ + Q_UNUSED(obj) + Q_UNUSED(event) + + // TODO + + return false; +} + +void EffectMakerWidget::contextHelp(const Core::IContext::HelpCallback &callback) const +{ + Q_UNUSED(callback) +} + +StudioQuickWidget *EffectMakerWidget::quickWidget() const +{ + return m_effectMakerWidget.data(); +} + +QPointer EffectMakerWidget::effectMakerModel() const +{ + return m_effectMakerModel; +} + +void EffectMakerWidget::focusSection(int section) +{ + Q_UNUSED(section) +} + +QString EffectMakerWidget::qmlSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/effectMakerQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/effectMakerQmlSources").toString(); +} + +void EffectMakerWidget::reloadQmlSource() +{ + const QString effectMakerQmlPath = qmlSourcesPath() + "/EffectMaker.qml"; + QTC_ASSERT(QFileInfo::exists(effectMakerQmlPath), return); + m_effectMakerWidget->setSource(QUrl::fromLocalFile(effectMakerQmlPath)); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h new file mode 100644 index 00000000000..61e75df9885 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakerwidget.h @@ -0,0 +1,50 @@ +// 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 + +class StudioQuickWidget; + +namespace QmlDesigner { + +class EffectMakerView; +class EffectMakerModel; + +class EffectMakerWidget : public QFrame +{ + Q_OBJECT + +public: + EffectMakerWidget(EffectMakerView *view); + ~EffectMakerWidget() = default; + + void contextHelp(const Core::IContext::HelpCallback &callback) const; + + static QString qmlSourcesPath(); + void clearSearchFilter(); + + void delayedUpdateModel(); + void updateModel(); + + StudioQuickWidget *quickWidget() const; + QPointer effectMakerModel() const; + + Q_INVOKABLE void focusSection(int section); + + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + void reloadQmlSource(); + + QPointer m_effectMakerModel; + QPointer m_effectMakerView; + QPointer m_effectMakerWidget; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectnode.cpp b/src/plugins/qmldesigner/components/effectmaker/effectnode.cpp new file mode 100644 index 00000000000..777fe28ec82 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectnode.cpp @@ -0,0 +1,16 @@ +// 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 "effectnode.h" + +namespace QmlDesigner { + +EffectNode::EffectNode(const QString &name) + : m_name(name) {} + +QString EffectNode::name() const +{ + return m_name; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectnode.h b/src/plugins/qmldesigner/components/effectmaker/effectnode.h new file mode 100644 index 00000000000..74571193f7c --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectnode.h @@ -0,0 +1,21 @@ +// 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 + +namespace QmlDesigner { + +class EffectNode +{ +public: + EffectNode(const QString &name); + + QString name() const; + +private: + QString m_name; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp b/src/plugins/qmldesigner/components/effectmaker/effectscategory.cpp new file mode 100644 index 00000000000..a5b4843fc53 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectscategory.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 "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 new file mode 100644 index 00000000000..aa4fc22eb92 --- /dev/null +++ b/src/plugins/qmldesigner/components/effectmaker/effectscategory.h @@ -0,0 +1,25 @@ +// 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 diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp index ca1b927c3a6..fade9e9a953 100644 --- a/src/plugins/qmldesigner/designmodecontext.cpp +++ b/src/plugins/qmldesigner/designmodecontext.cpp @@ -5,6 +5,7 @@ #include "assetslibrarywidget.h" #include "designmodewidget.h" #include "edit3dwidget.h" +#include "effectmakerwidget.h" #include "formeditorwidget.h" #include "materialbrowserwidget.h" #include "navigatorwidget.h" @@ -98,6 +99,18 @@ void TextEditorContext::contextHelp(const HelpCallback &callback) const qobject_cast(m_widget)->contextHelp(callback); } +EffectMakerContext::EffectMakerContext(QWidget *widget) + : IContext(widget) +{ + setWidget(widget); + setContext(Core::Context(Constants::C_QMLEFFECTMAKER, Constants::C_QT_QUICK_TOOLS_MENU)); +} + +void EffectMakerContext::contextHelp(const HelpCallback &callback) const +{ + qobject_cast(m_widget)->contextHelp(callback); +} + } } diff --git a/src/plugins/qmldesigner/designmodecontext.h b/src/plugins/qmldesigner/designmodecontext.h index fab7fe0ea30..0829b2a8222 100644 --- a/src/plugins/qmldesigner/designmodecontext.h +++ b/src/plugins/qmldesigner/designmodecontext.h @@ -74,5 +74,14 @@ public: void contextHelp(const Core::IContext::HelpCallback &callback) const override; }; +class EffectMakerContext : public Core::IContext +{ + Q_OBJECT + +public: + EffectMakerContext(QWidget *widget); + void contextHelp(const Core::IContext::HelpCallback &callback) const override; +}; + } } diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 1e16848c6b5..660c9b2d5ca 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -14,6 +14,7 @@ const char C_DUPLICATE[] = "QmlDesigner.Duplicate"; const char C_QMLDESIGNER[] = "QmlDesigner::QmlDesignerMain"; const char C_QMLFORMEDITOR[] = "QmlDesigner::FormEditor"; const char C_QMLEDITOR3D[] = "QmlDesigner::Editor3D"; +const char C_QMLEFFECTMAKER[] = "QmlDesigner::EffectMaker"; const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator"; const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor"; const char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser"; @@ -122,6 +123,7 @@ const char EVENT_TEXTEDITOR_TIME[] = "textEditor"; const char EVENT_TEXTUREEDITOR_TIME[] = "textureEditor"; const char EVENT_PROPERTYEDITOR_TIME[] = "propertyEditor"; const char EVENT_ASSETSLIBRARY_TIME[] = "assetsLibrary"; +const char EVENT_EFFECTMAKER_TIME[] = "effectMaker"; const char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary"; const char EVENT_TRANSLATIONVIEW_TIME[] = "translationView"; const char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView"; @@ -152,6 +154,7 @@ const char OBJECT_NAME_ASSET_LIBRARY[] = "QQuickWidgetAssetLibrary"; const char OBJECT_NAME_CONTENT_LIBRARY[] = "QQuickWidgetContentLibrary"; const char OBJECT_NAME_BUSY_INDICATOR[] = "QQuickWidgetBusyIndicator"; const char OBJECT_NAME_COMPONENT_LIBRARY[] = "QQuickWidgetComponentLibrary"; +const char OBJECT_NAME_EFFECT_MAKER[] = "QQuickWidgetEffectMaker"; const char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser"; const char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor"; const char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";