forked from qt-creator/qt-creator
QmlDesigner: Implement effect maker nodes popup and load data in it
Change-Id: I95625f2eaf8aac71679b2f816dd20a9167849830 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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<EffectNode *> effects = category->effects();
|
||||
const QList<EffectNode *> 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();
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "effectscategory.h"
|
||||
#include "effectnodescategory.h"
|
||||
|
||||
namespace Utils {
|
||||
class FilePath;
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
void loadModel();
|
||||
void resetModel();
|
||||
|
||||
QList<EffectsCategory *> categories() { return m_categories; }
|
||||
QList<EffectNodesCategory *> 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<EffectsCategory *> m_categories;
|
||||
QList<EffectNodesCategory *> m_categories;
|
||||
|
||||
int m_selectedIndex = -1;
|
||||
bool m_isEmpty = true;
|
||||
|
@@ -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 <projectexplorer/kit.h>
|
||||
#include <projectexplorer/projecttree.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
EffectMakerNodesModel::EffectMakerNodesModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> EffectMakerNodesModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> 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<EffectNode *> 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
|
@@ -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 <QStandardItemModel>
|
||||
|
||||
#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<int, QByteArray> 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<EffectNodesCategory *> categories() const { return m_categories; }
|
||||
|
||||
private:
|
||||
static Utils::FilePath getQmlEffectNodesPath();
|
||||
|
||||
QList<EffectNodesCategory *> m_categories;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -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)
|
||||
|
@@ -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<EffectMakerModel> EffectMakerWidget::effectMakerModel() const
|
||||
return m_effectMakerModel;
|
||||
}
|
||||
|
||||
QPointer<EffectMakerNodesModel> EffectMakerWidget::effectMakerNodesModel() const
|
||||
{
|
||||
return m_effectMakerNodesModel;
|
||||
}
|
||||
|
||||
void EffectMakerWidget::focusSection(int section)
|
||||
{
|
||||
Q_UNUSED(section)
|
||||
|
@@ -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> effectMakerModel() const;
|
||||
QPointer<EffectMakerNodesModel> effectMakerNodesModel() const;
|
||||
|
||||
Q_INVOKABLE void focusSection(int section);
|
||||
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
@@ -43,6 +44,7 @@ private:
|
||||
void reloadQmlSource();
|
||||
|
||||
QPointer<EffectMakerModel> m_effectMakerModel;
|
||||
QPointer<EffectMakerNodesModel> m_effectMakerNodesModel;
|
||||
QPointer<EffectMakerView> m_effectMakerView;
|
||||
QPointer<StudioQuickWidget> m_quickWidget;
|
||||
};
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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<EffectNode *> &nodes)
|
||||
: m_name(name),
|
||||
m_categoryNodes(nodes) {}
|
||||
|
||||
QString EffectNodesCategory::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QList<EffectNode *> EffectNodesCategory::nodes() const
|
||||
{
|
||||
return m_categoryNodes;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -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 <QObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class EffectNodesCategory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString categoryName MEMBER m_name CONSTANT)
|
||||
Q_PROPERTY(QList<EffectNode *> categoryNodes MEMBER m_categoryNodes CONSTANT)
|
||||
|
||||
public:
|
||||
EffectNodesCategory(const QString &name, const QList<EffectNode *> &nodes);
|
||||
|
||||
QString name() const;
|
||||
QList<EffectNode *> nodes() const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QList<EffectNode *> m_categoryNodes;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -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<EffectNode *> &subcategories)
|
||||
: m_name(name),
|
||||
m_effects(subcategories) {}
|
||||
|
||||
QString EffectsCategory::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QList<EffectNode *> EffectsCategory::effects() const
|
||||
{
|
||||
return m_effects;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -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 <QObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class EffectsCategory
|
||||
{
|
||||
public:
|
||||
EffectsCategory(const QString &name, const QList<EffectNode *> &subcategories);
|
||||
|
||||
QString name() const;
|
||||
QList<EffectNode *> effects() const;
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QList<EffectNode *> m_effects;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
Reference in New Issue
Block a user