EffectMaker: Block adding same effect node twice

The actual blocking is done at uniform level, as the problem of having
same effect node twice is duplicate uniforms.

Fixes: QDS-11470
Change-Id: I77b15b4a207efaebff39b4f6b1700d70262abcdb
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Miikka Heikkinen
2023-12-05 16:05:06 +02:00
parent 9184db8dfb
commit b5370c435e
8 changed files with 92 additions and 13 deletions

View File

@@ -15,19 +15,21 @@ Rectangle {
width: 140 width: 140
height: 32 height: 32
color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction color: mouseArea.containsMouse && modelData.canBeAdded
: "transparent" ? StudioTheme.Values.themeControlBackgroundInteraction : "transparent"
signal addEffectNode(var nodeQenPath) signal addEffectNode(var nodeQenPath)
MouseArea { ToolTipArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
tooltip: modelData.canBeAdded ? "" : qsTr("Existing effect has conflicting properties, this effect cannot be added.")
onClicked: { onClicked: {
if (modelData.canBeAdded)
root.addEffectNode(modelData.nodeQenPath) root.addEffectNode(modelData.nodeQenPath)
} }
} }
@@ -41,13 +43,15 @@ Rectangle {
width: 32 width: 32
height: 32 height: 32
color: StudioTheme.Values.themeTextColor color: modelData.canBeAdded ? StudioTheme.Values.themeTextColor
: StudioTheme.Values.themeTextColorDisabled
source: modelData.nodeIcon source: modelData.nodeIcon
} }
Text { Text {
text: modelData.nodeName text: modelData.nodeName
color: StudioTheme.Values.themeTextColor color: modelData.canBeAdded ? StudioTheme.Values.themeTextColor
: StudioTheme.Values.themeTextColorDisabled
font.pointSize: StudioTheme.Values.smallFontSize font.pointSize: StudioTheme.Values.smallFontSize
anchors.verticalCenter: nodeIcon.verticalCenter anchors.verticalCenter: nodeIcon.verticalCenter
} }

View File

@@ -112,6 +112,8 @@ void EffectMakerModel::addNode(const QString &nodeQenPath)
setIsEmpty(false); setIsEmpty(false);
bakeShaders(); bakeShaders();
emit nodesChanged();
} }
void EffectMakerModel::moveNode(int fromIdx, int toIdx) void EffectMakerModel::moveNode(int fromIdx, int toIdx)
@@ -138,6 +140,8 @@ void EffectMakerModel::removeNode(int idx)
setIsEmpty(true); setIsEmpty(true);
else else
bakeShaders(); bakeShaders();
emit nodesChanged();
} }
void EffectMakerModel::clear() void EffectMakerModel::clear()
@@ -148,6 +152,7 @@ void EffectMakerModel::clear()
endResetModel(); endResetModel();
setIsEmpty(true); setIsEmpty(true);
emit nodesChanged();
} }
QString EffectMakerModel::fragmentShader() const QString EffectMakerModel::fragmentShader() const
@@ -181,7 +186,7 @@ const QString &EffectMakerModel::qmlComponentString() const
return m_qmlComponentString; return m_qmlComponentString;
} }
const QList<Uniform *> EffectMakerModel::allUniforms() const QList<Uniform *> EffectMakerModel::allUniforms() const
{ {
QList<Uniform *> uniforms = {}; QList<Uniform *> uniforms = {};
for (const auto &node : std::as_const(m_nodes)) for (const auto &node : std::as_const(m_nodes))
@@ -604,10 +609,6 @@ void EffectMakerModel::openComposition(const QString &path)
return; return;
} }
// Get effects dir
const Utils::FilePath effectsResDir = QmlDesigner::ModelNodeOperations::getEffectsImportDirectory();
const QString effectsResPath = effectsResDir.pathAppended(effectName).toString();
if (json.contains("nodes") && json["nodes"].isArray()) { if (json.contains("nodes") && json["nodes"].isArray()) {
const QJsonArray nodesArray = json["nodes"].toArray(); const QJsonArray nodesArray = json["nodes"].toArray();
for (const auto &nodeElement : nodesArray) { for (const auto &nodeElement : nodesArray) {
@@ -620,6 +621,8 @@ void EffectMakerModel::openComposition(const QString &path)
setIsEmpty(m_nodes.isEmpty()); setIsEmpty(m_nodes.isEmpty());
bakeShaders(); bakeShaders();
} }
emit nodesChanged();
} }
void EffectMakerModel::exportResources(const QString &name) void EffectMakerModel::exportResources(const QString &name)
@@ -1438,6 +1441,15 @@ void EffectMakerModel::setCurrentComposition(const QString &newCurrentCompositio
emit currentCompositionChanged(); emit currentCompositionChanged();
} }
QStringList EffectMakerModel::uniformNames() const
{
QStringList usedList;
const QList<Uniform *> uniforms = allUniforms();
for (const auto uniform : uniforms)
usedList.append(uniform->name());
return usedList;
}
void EffectMakerModel::updateQmlComponent() void EffectMakerModel::updateQmlComponent()
{ {
// Clear possible QML runtime errors // Clear possible QML runtime errors

View File

@@ -89,6 +89,8 @@ public:
QString currentComposition() const; QString currentComposition() const;
void setCurrentComposition(const QString &newCurrentComposition); void setCurrentComposition(const QString &newCurrentComposition);
QStringList uniformNames() const;
signals: signals:
void isEmptyChanged(); void isEmptyChanged();
void selectedIndexChanged(int idx); void selectedIndexChanged(int idx);
@@ -97,6 +99,7 @@ signals:
void shadersBaked(); void shadersBaked();
void currentCompositionChanged(); void currentCompositionChanged();
void nodesChanged();
private: private:
enum Roles { enum Roles {
@@ -116,7 +119,7 @@ private:
bool isValidIndex(int idx) const; bool isValidIndex(int idx) const;
const QList<Uniform *> allUniforms(); const QList<Uniform *> allUniforms() const;
const QString getBufUniform(); const QString getBufUniform();
const QString getVSUniforms(); const QString getVSUniforms();

View File

@@ -52,6 +52,9 @@ QString EffectMakerNodesModel::nodesSourcesPath() const
void EffectMakerNodesModel::loadModel() void EffectMakerNodesModel::loadModel()
{ {
if (m_modelLoaded)
return;
auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath()); auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath());
if (!nodesPath.exists()) { if (!nodesPath.exists()) {
@@ -88,6 +91,8 @@ void EffectMakerNodesModel::loadModel()
return a->name() < b->name(); return a->name() < b->name();
}); });
m_modelLoaded = true;
resetModel(); resetModel();
} }
@@ -97,4 +102,20 @@ void EffectMakerNodesModel::resetModel()
endResetModel(); endResetModel();
} }
void EffectMakerNodesModel::updateCanBeAdded(const QStringList &uniforms)
{
for (const EffectNodesCategory *cat : std::as_const(m_categories)) {
const QList<EffectNode *> nodes = cat->nodes();
for (EffectNode *node : nodes) {
bool match = false;
for (const QString &uniform : uniforms) {
match = node->hasUniform(uniform);
if (match)
break;
}
node->setCanBeAdded(!match);
}
}
}
} // namespace EffectMaker } // namespace EffectMaker

View File

@@ -30,11 +30,14 @@ public:
QList<EffectNodesCategory *> categories() const { return m_categories; } QList<EffectNodesCategory *> categories() const { return m_categories; }
void updateCanBeAdded(const QStringList &uniforms);
private: private:
QString nodesSourcesPath() const; QString nodesSourcesPath() const;
QList<EffectNodesCategory *> m_categories; QList<EffectNodesCategory *> m_categories;
bool m_probeNodesDir = false; bool m_probeNodesDir = false;
bool m_modelLoaded = false;
}; };
} // namespace EffectMaker } // namespace EffectMaker

View File

@@ -76,6 +76,10 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
{"rootView", QVariant::fromValue(this)}}); {"rootView", QVariant::fromValue(this)}});
QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime( QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(
this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME); this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME);
connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, [this]() {
m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames());
});
} }

View File

@@ -2,6 +2,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "effectnode.h" #include "effectnode.h"
#include "compositionnode.h"
#include "uniform.h"
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@@ -22,6 +24,12 @@ EffectNode::EffectNode(const QString &qenPath)
iconPath = QStringLiteral("%1/%2").arg(parentDir.path(), "placeholder.svg"); iconPath = QStringLiteral("%1/%2").arg(parentDir.path(), "placeholder.svg");
} }
m_iconPath = QUrl::fromLocalFile(iconPath); m_iconPath = QUrl::fromLocalFile(iconPath);
CompositionNode node({}, qenPath);
const QList<Uniform *> uniforms = node.uniforms();
for (const Uniform *uniform : uniforms)
m_uniformNames.insert(uniform->name());
} }
QString EffectNode::name() const QString EffectNode::name() const
@@ -39,5 +47,18 @@ QString EffectNode::qenPath() const
return m_qenPath; return m_qenPath;
} }
void EffectNode::setCanBeAdded(bool enabled)
{
if (enabled != m_canBeAdded) {
m_canBeAdded = enabled;
emit canBeAddedChanged();
}
}
bool EffectNode::hasUniform(const QString &name)
{
return m_uniformNames.contains(name);
}
} // namespace EffectMaker } // namespace EffectMaker

View File

@@ -4,6 +4,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QSet>
#include <QUrl> #include <QUrl>
namespace EffectMaker { namespace EffectMaker {
@@ -16,6 +17,7 @@ class EffectNode : public QObject
Q_PROPERTY(QString nodeDescription MEMBER m_description CONSTANT) Q_PROPERTY(QString nodeDescription MEMBER m_description CONSTANT)
Q_PROPERTY(QUrl nodeIcon MEMBER m_iconPath CONSTANT) Q_PROPERTY(QUrl nodeIcon MEMBER m_iconPath CONSTANT)
Q_PROPERTY(QString nodeQenPath MEMBER m_qenPath CONSTANT) Q_PROPERTY(QString nodeQenPath MEMBER m_qenPath CONSTANT)
Q_PROPERTY(bool canBeAdded MEMBER m_canBeAdded NOTIFY canBeAddedChanged)
public: public:
EffectNode(const QString &qenPath); EffectNode(const QString &qenPath);
@@ -24,11 +26,20 @@ public:
QString description() const; QString description() const;
QString qenPath() const; QString qenPath() const;
void setCanBeAdded(bool enabled);
bool hasUniform(const QString &name);
signals:
void canBeAddedChanged();
private: private:
QString m_name; QString m_name;
QString m_description; QString m_description;
QString m_qenPath; QString m_qenPath;
QUrl m_iconPath; QUrl m_iconPath;
bool m_canBeAdded = true;
QSet<QString> m_uniformNames;
}; };
} // namespace EffectMaker } // namespace EffectMaker