Merge remote-tracking branch 'origin/qds/dev' into 13.0
Change-Id: I09a0e8514c8ad7badaa7af6d101c71d5c96b5465
@@ -109,7 +109,7 @@ if (WITH_QMLDESIGNER)
|
||||
set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
|
||||
endif()
|
||||
add_subdirectory(qmldesigner ${qmldesigner_builddir})
|
||||
add_subdirectory(effectmakernew)
|
||||
add_subdirectory(effectcomposer)
|
||||
add_subdirectory(studiowelcome)
|
||||
add_subdirectory(insight)
|
||||
endif()
|
||||
|
||||
@@ -110,6 +110,10 @@ GeneralSettingsWidget::GeneralSettingsWidget()
|
||||
m_languageBox->setObjectName("languageBox");
|
||||
m_languageBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||
m_languageBox->setMinimumContentsLength(20);
|
||||
if (Core::ICore::isQtDesignStudio()) {
|
||||
m_languageBox->setDisabled(true);
|
||||
m_languageBox->setToolTip("Qt Design Studio is currently available in English only.");
|
||||
}
|
||||
|
||||
m_codecBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||
m_codecBox->setMinimumContentsLength(20);
|
||||
@@ -211,7 +215,7 @@ void GeneralSettingsWidget::fillLanguageBox() const
|
||||
m_languageBox->addItem(Tr::tr("<System Language>"), QString());
|
||||
// need to add this explicitly, since there is no qm file for English
|
||||
m_languageBox->addItem(QLatin1String("English"), QLatin1String("C"));
|
||||
if (currentLocale == QLatin1String("C"))
|
||||
if (currentLocale == QLatin1String("C") || Core::ICore::isQtDesignStudio())
|
||||
m_languageBox->setCurrentIndex(m_languageBox->count() - 1);
|
||||
|
||||
const FilePath creatorTrPath = ICore::resourcePath("translations");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
add_qtc_plugin(EffectMakerNew
|
||||
add_qtc_plugin(EffectComposer
|
||||
CONDITION TARGET Qt::Quick AND TARGET QtCreator::QmlDesigner
|
||||
PLUGIN_DEPENDS
|
||||
QtCreator::QmlDesigner QtCreator::ProjectExplorer QtCreator::QmlProjectManager
|
||||
@@ -6,18 +6,18 @@ add_qtc_plugin(EffectMakerNew
|
||||
Qt::Core Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick
|
||||
QtCreator::Utils
|
||||
SOURCES
|
||||
effectmakerplugin.cpp
|
||||
effectmakerwidget.cpp effectmakerwidget.h
|
||||
effectmakerview.cpp effectmakerview.h
|
||||
effectmakermodel.cpp effectmakermodel.h
|
||||
effectmakernodesmodel.cpp effectmakernodesmodel.h
|
||||
effectmakeruniformsmodel.cpp effectmakeruniformsmodel.h
|
||||
effectcomposerplugin.cpp
|
||||
effectcomposerwidget.cpp effectcomposerwidget.h
|
||||
effectcomposerview.cpp effectcomposerview.h
|
||||
effectcomposermodel.cpp effectcomposermodel.h
|
||||
effectcomposernodesmodel.cpp effectcomposernodesmodel.h
|
||||
effectcomposeruniformsmodel.cpp effectcomposeruniformsmodel.h
|
||||
effectnode.cpp effectnode.h
|
||||
effectnodescategory.cpp effectnodescategory.h
|
||||
compositionnode.cpp compositionnode.h
|
||||
uniform.cpp uniform.h
|
||||
effectutils.cpp effectutils.h
|
||||
effectmakercontextobject.cpp effectmakercontextobject.h
|
||||
effectcomposercontextobject.cpp effectcomposercontextobject.h
|
||||
shaderfeatures.cpp shaderfeatures.h
|
||||
syntaxhighlighterdata.cpp syntaxhighlighterdata.h
|
||||
propertyhandler.cpp propertyhandler.h
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"Name" : "EffectMakerNew",
|
||||
"Name" : "EffectComposer",
|
||||
"Version" : "${IDE_VERSION}",
|
||||
"CompatVersion" : "${IDE_VERSION_COMPAT}",
|
||||
"Vendor" : "The Qt Company Ltd",
|
||||
@@ -8,7 +8,7 @@
|
||||
"",
|
||||
"Licensees holding valid Qt Enterprise licenses may use this plugin in accordance with the Qt Enterprise License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company."
|
||||
],
|
||||
"Description" : "Plugin for Effect Maker.",
|
||||
"Description" : "Plugin for Effect Composer.",
|
||||
"Url" : "http://www.qt.io",
|
||||
"DisabledByDefault" : true,
|
||||
${IDE_PLUGIN_DEPENDENCIES}
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "compositionnode.h"
|
||||
|
||||
#include "effectutils.h"
|
||||
#include "effectmakeruniformsmodel.h"
|
||||
#include "effectcomposeruniformsmodel.h"
|
||||
#include "propertyhandler.h"
|
||||
#include "uniform.h"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
CompositionNode::CompositionNode(const QString &effectName, const QString &qenPath,
|
||||
const QJsonObject &jsonObject)
|
||||
@@ -187,5 +187,5 @@ QString CompositionNode::name() const
|
||||
return m_name;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "effectmakeruniformsmodel.h"
|
||||
#include "effectcomposeruniformsmodel.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class CompositionNode : public QObject
|
||||
{
|
||||
@@ -70,10 +70,9 @@ private:
|
||||
bool m_isEnabled = true;
|
||||
int m_refCount = 0;
|
||||
|
||||
QList<Uniform*> m_uniforms;
|
||||
QList<Uniform *> m_uniforms;
|
||||
|
||||
EffectMakerUniformsModel m_unifomrsModel;
|
||||
EffectComposerUniformsModel m_unifomrsModel;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
|
||||
} // namespace EffectComposer
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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 "effectmakercontextobject.h"
|
||||
#include "effectcomposercontextobject.h"
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <bindingproperty.h>
|
||||
@@ -27,15 +27,15 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectMakerContextObject::EffectMakerContextObject(QQmlContext *context, QObject *parent)
|
||||
EffectComposerContextObject::EffectComposerContextObject(QQmlContext *context, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_qmlContext(context)
|
||||
{
|
||||
}
|
||||
|
||||
QString EffectMakerContextObject::convertColorToString(const QVariant &color)
|
||||
QString EffectComposerContextObject::convertColorToString(const QVariant &color)
|
||||
{
|
||||
QString colorString;
|
||||
QColor theColor;
|
||||
@@ -52,17 +52,17 @@ QString EffectMakerContextObject::convertColorToString(const QVariant &color)
|
||||
}
|
||||
|
||||
// TODO: this method is used by the ColorEditor helper widget, check if at all needed?
|
||||
QColor EffectMakerContextObject::colorFromString(const QString &colorString)
|
||||
QColor EffectComposerContextObject::colorFromString(const QString &colorString)
|
||||
{
|
||||
return colorString;
|
||||
}
|
||||
|
||||
int EffectMakerContextObject::majorVersion() const
|
||||
int EffectComposerContextObject::majorVersion() const
|
||||
{
|
||||
return m_majorVersion;
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setMajorVersion(int majorVersion)
|
||||
void EffectComposerContextObject::setMajorVersion(int majorVersion)
|
||||
{
|
||||
if (m_majorVersion == majorVersion)
|
||||
return;
|
||||
@@ -72,7 +72,7 @@ void EffectMakerContextObject::setMajorVersion(int majorVersion)
|
||||
emit majorVersionChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setStateName(const QString &newStateName)
|
||||
void EffectComposerContextObject::setStateName(const QString &newStateName)
|
||||
{
|
||||
if (newStateName == m_stateName)
|
||||
return;
|
||||
@@ -81,7 +81,7 @@ void EffectMakerContextObject::setStateName(const QString &newStateName)
|
||||
emit stateNameChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setAllStateNames(const QStringList &allStates)
|
||||
void EffectComposerContextObject::setAllStateNames(const QStringList &allStates)
|
||||
{
|
||||
if (allStates == m_allStateNames)
|
||||
return;
|
||||
@@ -90,7 +90,7 @@ void EffectMakerContextObject::setAllStateNames(const QStringList &allStates)
|
||||
emit allStateNamesChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setIsBaseState(bool newIsBaseState)
|
||||
void EffectComposerContextObject::setIsBaseState(bool newIsBaseState)
|
||||
{
|
||||
if (newIsBaseState == m_isBaseState)
|
||||
return;
|
||||
@@ -99,7 +99,7 @@ void EffectMakerContextObject::setIsBaseState(bool newIsBaseState)
|
||||
emit isBaseStateChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setSelectionChanged(bool newSelectionChanged)
|
||||
void EffectComposerContextObject::setSelectionChanged(bool newSelectionChanged)
|
||||
{
|
||||
if (newSelectionChanged == m_selectionChanged)
|
||||
return;
|
||||
@@ -108,7 +108,7 @@ void EffectMakerContextObject::setSelectionChanged(bool newSelectionChanged)
|
||||
emit selectionChangedChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setBackendValues(QQmlPropertyMap *newBackendValues)
|
||||
void EffectComposerContextObject::setBackendValues(QQmlPropertyMap *newBackendValues)
|
||||
{
|
||||
if (newBackendValues == m_backendValues)
|
||||
return;
|
||||
@@ -117,17 +117,17 @@ void EffectMakerContextObject::setBackendValues(QQmlPropertyMap *newBackendValue
|
||||
emit backendValuesChanged();
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::setModel(QmlDesigner::Model *model)
|
||||
void EffectComposerContextObject::setModel(QmlDesigner::Model *model)
|
||||
{
|
||||
m_model = model;
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::triggerSelectionChanged()
|
||||
void EffectComposerContextObject::triggerSelectionChanged()
|
||||
{
|
||||
setSelectionChanged(!m_selectionChanged);
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::hideCursor()
|
||||
void EffectComposerContextObject::hideCursor()
|
||||
{
|
||||
if (QApplication::overrideCursor())
|
||||
return;
|
||||
@@ -138,7 +138,7 @@ void EffectMakerContextObject::hideCursor()
|
||||
m_lastPos = QCursor::pos(w->screen());
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::restoreCursor()
|
||||
void EffectComposerContextObject::restoreCursor()
|
||||
{
|
||||
if (!QApplication::overrideCursor())
|
||||
return;
|
||||
@@ -149,7 +149,7 @@ void EffectMakerContextObject::restoreCursor()
|
||||
QCursor::setPos(w->screen(), m_lastPos);
|
||||
}
|
||||
|
||||
void EffectMakerContextObject::holdCursorInPlace()
|
||||
void EffectComposerContextObject::holdCursorInPlace()
|
||||
{
|
||||
if (!QApplication::overrideCursor())
|
||||
return;
|
||||
@@ -158,7 +158,7 @@ void EffectMakerContextObject::holdCursorInPlace()
|
||||
QCursor::setPos(w->screen(), m_lastPos);
|
||||
}
|
||||
|
||||
int EffectMakerContextObject::devicePixelRatio()
|
||||
int EffectComposerContextObject::devicePixelRatio()
|
||||
{
|
||||
if (QWidget *w = QApplication::activeWindow())
|
||||
return w->devicePixelRatio();
|
||||
@@ -166,7 +166,7 @@ int EffectMakerContextObject::devicePixelRatio()
|
||||
return 1;
|
||||
}
|
||||
|
||||
QStringList EffectMakerContextObject::allStatesForId(const QString &id)
|
||||
QStringList EffectComposerContextObject::allStatesForId(const QString &id)
|
||||
{
|
||||
if (m_model && m_model->rewriterView()) {
|
||||
const QmlDesigner::QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id);
|
||||
@@ -177,10 +177,10 @@ QStringList EffectMakerContextObject::allStatesForId(const QString &id)
|
||||
return {};
|
||||
}
|
||||
|
||||
bool EffectMakerContextObject::isBlocked(const QString &) const
|
||||
bool EffectComposerContextObject::isBlocked(const QString &) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include <QPoint>
|
||||
#include <QMouseEvent>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectMakerContextObject : public QObject
|
||||
class EffectComposerContextObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -32,7 +32,7 @@ class EffectMakerContextObject : public QObject
|
||||
Q_PROPERTY(QQmlPropertyMap *backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged)
|
||||
|
||||
public:
|
||||
EffectMakerContextObject(QQmlContext *context, QObject *parent = nullptr);
|
||||
EffectComposerContextObject(QQmlContext *context, QObject *parent = nullptr);
|
||||
|
||||
QString stateName() const { return m_stateName; }
|
||||
QStringList allStateNames() const { return m_allStateNames; }
|
||||
@@ -98,5 +98,5 @@ private:
|
||||
bool m_selectionChanged = false;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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 "effectcomposermodel.h"
|
||||
|
||||
#include "compositionnode.h"
|
||||
#include "effectutils.h"
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QLibraryInfo>
|
||||
#include <QVector2D>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
enum class FileType
|
||||
{
|
||||
@@ -49,12 +49,12 @@ static bool writeToFile(const QByteArray &buf, const QString &filename, FileType
|
||||
return true;
|
||||
}
|
||||
|
||||
EffectMakerModel::EffectMakerModel(QObject *parent)
|
||||
EffectComposerModel::EffectComposerModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> EffectMakerModel::roleNames() const
|
||||
QHash<int, QByteArray> EffectComposerModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[NameRole] = "nodeName";
|
||||
@@ -64,14 +64,14 @@ QHash<int, QByteArray> EffectMakerModel::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
int EffectMakerModel::rowCount(const QModelIndex &parent) const
|
||||
int EffectComposerModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_nodes.count();
|
||||
}
|
||||
|
||||
QVariant EffectMakerModel::data(const QModelIndex &index, int role) const
|
||||
QVariant EffectComposerModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.row() < m_nodes.size(), return {});
|
||||
QTC_ASSERT(roleNames().contains(role), return {});
|
||||
@@ -79,7 +79,7 @@ QVariant EffectMakerModel::data(const QModelIndex &index, int role) const
|
||||
return m_nodes.at(index.row())->property(roleNames().value(role));
|
||||
}
|
||||
|
||||
bool EffectMakerModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
bool EffectComposerModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid() || !roleNames().contains(role))
|
||||
return false;
|
||||
@@ -95,7 +95,7 @@ bool EffectMakerModel::setData(const QModelIndex &index, const QVariant &value,
|
||||
return true;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setIsEmpty(bool val)
|
||||
void EffectComposerModel::setIsEmpty(bool val)
|
||||
{
|
||||
if (m_isEmpty != val) {
|
||||
m_isEmpty = val;
|
||||
@@ -106,12 +106,12 @@ void EffectMakerModel::setIsEmpty(bool val)
|
||||
}
|
||||
}
|
||||
|
||||
void EffectMakerModel::addNode(const QString &nodeQenPath)
|
||||
void EffectComposerModel::addNode(const QString &nodeQenPath)
|
||||
{
|
||||
beginResetModel();
|
||||
auto *node = new CompositionNode({}, nodeQenPath);
|
||||
connect(qobject_cast<EffectMakerUniformsModel *>(node->uniformsModel()),
|
||||
&EffectMakerUniformsModel::dataChanged, this, [this] {
|
||||
connect(qobject_cast<EffectComposerUniformsModel *>(node->uniformsModel()),
|
||||
&EffectComposerUniformsModel::dataChanged, this, [this] {
|
||||
setHasUnsavedChanges(true);
|
||||
});
|
||||
|
||||
@@ -125,8 +125,8 @@ void EffectMakerModel::addNode(const QString &nodeQenPath)
|
||||
|
||||
const QString path = EffectUtils::nodesSourcesPath() + "/common/" + requiredId + ".qen";
|
||||
auto requiredNode = new CompositionNode({}, path);
|
||||
connect(qobject_cast<EffectMakerUniformsModel *>(requiredNode->uniformsModel()),
|
||||
&EffectMakerUniformsModel::dataChanged, this, [this] {
|
||||
connect(qobject_cast<EffectComposerUniformsModel *>(requiredNode->uniformsModel()),
|
||||
&EffectComposerUniformsModel::dataChanged, this, [this] {
|
||||
setHasUnsavedChanges(true);
|
||||
});
|
||||
requiredNode->setRefCount(1);
|
||||
@@ -144,7 +144,7 @@ void EffectMakerModel::addNode(const QString &nodeQenPath)
|
||||
emit nodesChanged();
|
||||
}
|
||||
|
||||
CompositionNode *EffectMakerModel::findNodeById(const QString &id) const
|
||||
CompositionNode *EffectComposerModel::findNodeById(const QString &id) const
|
||||
{
|
||||
for (CompositionNode *node : std::as_const(m_nodes)) {
|
||||
if (node->id() == id)
|
||||
@@ -153,7 +153,7 @@ CompositionNode *EffectMakerModel::findNodeById(const QString &id) const
|
||||
return {};
|
||||
}
|
||||
|
||||
void EffectMakerModel::moveNode(int fromIdx, int toIdx)
|
||||
void EffectComposerModel::moveNode(int fromIdx, int toIdx)
|
||||
{
|
||||
if (fromIdx == toIdx)
|
||||
return;
|
||||
@@ -167,7 +167,7 @@ void EffectMakerModel::moveNode(int fromIdx, int toIdx)
|
||||
bakeShaders();
|
||||
}
|
||||
|
||||
void EffectMakerModel::removeNode(int idx)
|
||||
void EffectComposerModel::removeNode(int idx)
|
||||
{
|
||||
beginResetModel();
|
||||
CompositionNode *node = m_nodes.takeAt(idx);
|
||||
@@ -193,7 +193,7 @@ void EffectMakerModel::removeNode(int idx)
|
||||
emit nodesChanged();
|
||||
}
|
||||
|
||||
void EffectMakerModel::clear(bool clearName)
|
||||
void EffectComposerModel::clear(bool clearName)
|
||||
{
|
||||
beginResetModel();
|
||||
qDeleteAll(m_nodes);
|
||||
@@ -209,14 +209,14 @@ void EffectMakerModel::clear(bool clearName)
|
||||
emit nodesChanged();
|
||||
}
|
||||
|
||||
void EffectMakerModel::assignToSelected()
|
||||
void EffectComposerModel::assignToSelected()
|
||||
{
|
||||
const QString effectsAssetsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory();
|
||||
const QString path = effectsAssetsDir + QDir::separator() + m_currentComposition + ".qep";
|
||||
emit assignToSelectedTriggered(path);
|
||||
}
|
||||
|
||||
QString EffectMakerModel::getUniqueEffectName() const
|
||||
QString EffectComposerModel::getUniqueEffectName() const
|
||||
{
|
||||
const QString effectsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory();
|
||||
const QString path = effectsDir + QDir::separator() + "Effect%1.qep";
|
||||
@@ -229,12 +229,12 @@ QString EffectMakerModel::getUniqueEffectName() const
|
||||
return QString("Effect%1").arg(num, 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString EffectMakerModel::fragmentShader() const
|
||||
QString EffectComposerModel::fragmentShader() const
|
||||
{
|
||||
return m_fragmentShader;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setFragmentShader(const QString &newFragmentShader)
|
||||
void EffectComposerModel::setFragmentShader(const QString &newFragmentShader)
|
||||
{
|
||||
if (m_fragmentShader == newFragmentShader)
|
||||
return;
|
||||
@@ -242,12 +242,12 @@ void EffectMakerModel::setFragmentShader(const QString &newFragmentShader)
|
||||
m_fragmentShader = newFragmentShader;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::vertexShader() const
|
||||
QString EffectComposerModel::vertexShader() const
|
||||
{
|
||||
return m_vertexShader;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setVertexShader(const QString &newVertexShader)
|
||||
void EffectComposerModel::setVertexShader(const QString &newVertexShader)
|
||||
{
|
||||
if (m_vertexShader == newVertexShader)
|
||||
return;
|
||||
@@ -255,20 +255,20 @@ void EffectMakerModel::setVertexShader(const QString &newVertexShader)
|
||||
m_vertexShader = newVertexShader;
|
||||
}
|
||||
|
||||
const QString &EffectMakerModel::qmlComponentString() const
|
||||
const QString &EffectComposerModel::qmlComponentString() const
|
||||
{
|
||||
return m_qmlComponentString;
|
||||
}
|
||||
|
||||
const QList<Uniform *> EffectMakerModel::allUniforms() const
|
||||
const QList<Uniform *> EffectComposerModel::allUniforms() const
|
||||
{
|
||||
QList<Uniform *> uniforms = {};
|
||||
for (const auto &node : std::as_const(m_nodes))
|
||||
uniforms.append(static_cast<EffectMakerUniformsModel *>(node->uniformsModel())->uniforms());
|
||||
uniforms.append(static_cast<EffectComposerUniformsModel *>(node->uniformsModel())->uniforms());
|
||||
return uniforms;
|
||||
}
|
||||
|
||||
const QString EffectMakerModel::getBufUniform()
|
||||
const QString EffectComposerModel::getBufUniform()
|
||||
{
|
||||
QList<Uniform *> uniforms = allUniforms();
|
||||
QString s;
|
||||
@@ -295,7 +295,7 @@ const QString EffectMakerModel::getBufUniform()
|
||||
return s;
|
||||
}
|
||||
|
||||
const QString EffectMakerModel::getVSUniforms()
|
||||
const QString EffectComposerModel::getVSUniforms()
|
||||
{
|
||||
QString s;
|
||||
s += "#version 440\n";
|
||||
@@ -313,7 +313,7 @@ const QString EffectMakerModel::getVSUniforms()
|
||||
return s;
|
||||
}
|
||||
|
||||
const QString EffectMakerModel::getFSUniforms()
|
||||
const QString EffectComposerModel::getFSUniforms()
|
||||
{
|
||||
const QList<Uniform *> uniforms = allUniforms();
|
||||
QString s;
|
||||
@@ -359,7 +359,7 @@ const QString EffectMakerModel::getFSUniforms()
|
||||
|
||||
// Detects common GLSL error messages and returns potential
|
||||
// additional error information related to them.
|
||||
QString EffectMakerModel::detectErrorMessage(const QString &errorMessage)
|
||||
QString EffectComposerModel::detectErrorMessage(const QString &errorMessage)
|
||||
{
|
||||
static QHash<QString, QString> nodeErrors {
|
||||
{ "'BLUR_HELPER_MAX_LEVEL' : undeclared identifier", "BlurHelper"},
|
||||
@@ -380,7 +380,7 @@ QString EffectMakerModel::detectErrorMessage(const QString &errorMessage)
|
||||
}
|
||||
|
||||
// Return first error message (if any)
|
||||
EffectError EffectMakerModel::effectError() const
|
||||
EffectError EffectComposerModel::effectError() const
|
||||
{
|
||||
for (const EffectError &e : std::as_const(m_effectErrors)) {
|
||||
if (!e.m_message.isEmpty())
|
||||
@@ -392,7 +392,7 @@ EffectError EffectMakerModel::effectError() const
|
||||
// Set the effect error message with optional type and lineNumber.
|
||||
// Type comes from ErrorTypes, defaulting to common errors (-1).
|
||||
// Note that type must match with UI editor tab index.
|
||||
void EffectMakerModel::setEffectError(const QString &errorMessage, int type, int lineNumber)
|
||||
void EffectComposerModel::setEffectError(const QString &errorMessage, int type, int lineNumber)
|
||||
{
|
||||
EffectError error;
|
||||
error.m_type = type;
|
||||
@@ -557,7 +557,7 @@ QJsonObject nodeToJson(const CompositionNode &node)
|
||||
return nodeObject;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::getQmlEffectString()
|
||||
QString EffectComposerModel::getQmlEffectString()
|
||||
{
|
||||
QString s;
|
||||
|
||||
@@ -571,7 +571,9 @@ import QtQuick
|
||||
Item {
|
||||
id: rootItem
|
||||
|
||||
// This is an internal property used by tooling to identify effect items
|
||||
property var _isEffectItem
|
||||
|
||||
property Item _oldParent: null
|
||||
)"
|
||||
};
|
||||
@@ -616,6 +618,20 @@ R"(
|
||||
)"
|
||||
};
|
||||
|
||||
if (m_shaderFeatures.enabled(ShaderFeatures::Mipmap)) {
|
||||
QString mipmap1{
|
||||
R"(parent.layer.smooth = true
|
||||
parent.layer.mipmap = true
|
||||
%1)"
|
||||
};
|
||||
QString mipmap2{
|
||||
R"(_oldParent.layer.smooth = false
|
||||
_oldParent.layer.mipmap = false
|
||||
%2)"
|
||||
};
|
||||
parentChanged = parentChanged.arg(mipmap1, mipmap2);
|
||||
}
|
||||
|
||||
parentChanged = parentChanged.arg(m_shaderFeatures.enabled(ShaderFeatures::Source)
|
||||
? QString("source = parent") : QString(),
|
||||
m_shaderFeatures.enabled(ShaderFeatures::Source)
|
||||
@@ -648,7 +664,7 @@ R"(
|
||||
return s;
|
||||
}
|
||||
|
||||
void EffectMakerModel::saveComposition(const QString &name)
|
||||
void EffectComposerModel::saveComposition(const QString &name)
|
||||
{
|
||||
const QString effectsAssetsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory();
|
||||
const QString path = effectsAssetsDir + QDir::separator() + name + ".qep";
|
||||
@@ -685,7 +701,7 @@ void EffectMakerModel::saveComposition(const QString &name)
|
||||
saveResources(name);
|
||||
}
|
||||
|
||||
void EffectMakerModel::openComposition(const QString &path)
|
||||
void EffectComposerModel::openComposition(const QString &path)
|
||||
{
|
||||
clear(true);
|
||||
|
||||
@@ -741,8 +757,8 @@ void EffectMakerModel::openComposition(const QString &path)
|
||||
|
||||
for (const auto &nodeElement : nodesArray) {
|
||||
auto *node = new CompositionNode(effectName, {}, nodeElement.toObject());
|
||||
connect(qobject_cast<EffectMakerUniformsModel *>(node->uniformsModel()),
|
||||
&EffectMakerUniformsModel::dataChanged, this, [this] {
|
||||
connect(qobject_cast<EffectComposerUniformsModel *>(node->uniformsModel()),
|
||||
&EffectComposerUniformsModel::dataChanged, this, [this] {
|
||||
setHasUnsavedChanges(true);
|
||||
});
|
||||
m_nodes.append(node);
|
||||
@@ -767,7 +783,7 @@ void EffectMakerModel::openComposition(const QString &path)
|
||||
emit nodesChanged();
|
||||
}
|
||||
|
||||
void EffectMakerModel::saveResources(const QString &name)
|
||||
void EffectComposerModel::saveResources(const QString &name)
|
||||
{
|
||||
// Make sure that uniforms are up-to-date
|
||||
updateCustomUniforms();
|
||||
@@ -878,7 +894,7 @@ void EffectMakerModel::saveResources(const QString &name)
|
||||
emit resourcesSaved(QString("Effects.%1.%1").arg(name).toUtf8(), effectPath);
|
||||
}
|
||||
|
||||
void EffectMakerModel::resetEffectError(int type)
|
||||
void EffectComposerModel::resetEffectError(int type)
|
||||
{
|
||||
if (m_effectErrors.contains(type)) {
|
||||
m_effectErrors.remove(type);
|
||||
@@ -887,7 +903,7 @@ void EffectMakerModel::resetEffectError(int type)
|
||||
}
|
||||
|
||||
// Get value in QML format that used for exports
|
||||
QString EffectMakerModel::valueAsString(const Uniform &uniform)
|
||||
QString EffectComposerModel::valueAsString(const Uniform &uniform)
|
||||
{
|
||||
if (uniform.type() == Uniform::Type::Bool) {
|
||||
return uniform.value().toBool() ? QString("true") : QString("false");
|
||||
@@ -905,7 +921,7 @@ QString EffectMakerModel::valueAsString(const Uniform &uniform)
|
||||
QVector4D v4 = uniform.value().value<QVector4D>();
|
||||
return QString("Qt.vector4d(%1, %2, %3, %4)").arg(v4.x()).arg(v4.y()).arg(v4.z()).arg(v4.w());
|
||||
} else if (uniform.type() == Uniform::Type::Sampler) {
|
||||
return getImageElementName(uniform);
|
||||
return getImageElementName(uniform, true);
|
||||
} else if (uniform.type() == Uniform::Type::Color) {
|
||||
return QString("\"%1\"").arg(uniform.value().toString());
|
||||
} else if (uniform.type() == Uniform::Type::Define) {
|
||||
@@ -917,7 +933,7 @@ QString EffectMakerModel::valueAsString(const Uniform &uniform)
|
||||
}
|
||||
|
||||
// Get value in QML binding that used for previews
|
||||
QString EffectMakerModel::valueAsBinding(const Uniform &uniform)
|
||||
QString EffectComposerModel::valueAsBinding(const Uniform &uniform)
|
||||
{
|
||||
if (uniform.type() == Uniform::Type::Bool
|
||||
|| uniform.type() == Uniform::Type::Int
|
||||
@@ -941,7 +957,7 @@ QString EffectMakerModel::valueAsBinding(const Uniform &uniform)
|
||||
QString sw = QString("g_propertyData.%1.w").arg(uniform.name());
|
||||
return QString("Qt.vector4d(%1, %2, %3, %4)").arg(sx, sy, sz, sw);
|
||||
} else if (uniform.type() == Uniform::Type::Sampler) {
|
||||
return getImageElementName(uniform);
|
||||
return getImageElementName(uniform, false);
|
||||
} else {
|
||||
qWarning() << QString("Unhandled const variable type: %1").arg(int(uniform.type())).toLatin1();
|
||||
return QString();
|
||||
@@ -949,7 +965,7 @@ QString EffectMakerModel::valueAsBinding(const Uniform &uniform)
|
||||
}
|
||||
|
||||
// Get value in GLSL format that is used for non-exported const properties
|
||||
QString EffectMakerModel::valueAsVariable(const Uniform &uniform)
|
||||
QString EffectComposerModel::valueAsVariable(const Uniform &uniform)
|
||||
{
|
||||
if (uniform.type() == Uniform::Type::Bool) {
|
||||
return uniform.value().toBool() ? QString("true") : QString("false");
|
||||
@@ -976,16 +992,16 @@ QString EffectMakerModel::valueAsVariable(const Uniform &uniform)
|
||||
}
|
||||
|
||||
// Return name for the image property Image element
|
||||
QString EffectMakerModel::getImageElementName(const Uniform &uniform)
|
||||
QString EffectComposerModel::getImageElementName(const Uniform &uniform, bool localFiles)
|
||||
{
|
||||
if (uniform.value().toString().isEmpty())
|
||||
if (localFiles && uniform.value().toString().isEmpty())
|
||||
return QStringLiteral("null");
|
||||
QString simplifiedName = uniform.name().simplified();
|
||||
simplifiedName = simplifiedName.remove(' ');
|
||||
return QStringLiteral("imageItem") + simplifiedName;
|
||||
}
|
||||
|
||||
const QString EffectMakerModel::getConstVariables()
|
||||
const QString EffectComposerModel::getConstVariables()
|
||||
{
|
||||
const QList<Uniform *> uniforms = allUniforms();
|
||||
QString s;
|
||||
@@ -1001,7 +1017,7 @@ const QString EffectMakerModel::getConstVariables()
|
||||
return s;
|
||||
}
|
||||
|
||||
const QString EffectMakerModel::getDefineProperties()
|
||||
const QString EffectComposerModel::getDefineProperties()
|
||||
{
|
||||
const QList<Uniform *> uniforms = allUniforms();
|
||||
QString s;
|
||||
@@ -1018,7 +1034,7 @@ const QString EffectMakerModel::getDefineProperties()
|
||||
return s;
|
||||
}
|
||||
|
||||
int EffectMakerModel::getTagIndex(const QStringList &code, const QString &tag)
|
||||
int EffectComposerModel::getTagIndex(const QStringList &code, const QString &tag)
|
||||
{
|
||||
int index = -1;
|
||||
int line = 0;
|
||||
@@ -1040,7 +1056,7 @@ int EffectMakerModel::getTagIndex(const QStringList &code, const QString &tag)
|
||||
return index;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::processVertexRootLine(const QString &line)
|
||||
QString EffectComposerModel::processVertexRootLine(const QString &line)
|
||||
{
|
||||
QString output;
|
||||
QStringList lineList = line.split(m_spaceReg, Qt::SkipEmptyParts);
|
||||
@@ -1054,7 +1070,7 @@ QString EffectMakerModel::processVertexRootLine(const QString &line)
|
||||
return output;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::processFragmentRootLine(const QString &line)
|
||||
QString EffectComposerModel::processFragmentRootLine(const QString &line)
|
||||
{
|
||||
QString output;
|
||||
QStringList lineList = line.split(m_spaceReg, Qt::SkipEmptyParts);
|
||||
@@ -1065,7 +1081,7 @@ QString EffectMakerModel::processFragmentRootLine(const QString &line)
|
||||
return output;
|
||||
}
|
||||
|
||||
QStringList EffectMakerModel::getDefaultRootVertexShader()
|
||||
QStringList EffectComposerModel::getDefaultRootVertexShader()
|
||||
{
|
||||
if (m_defaultRootVertexShader.isEmpty()) {
|
||||
m_defaultRootVertexShader << "void main() {";
|
||||
@@ -1079,7 +1095,7 @@ QStringList EffectMakerModel::getDefaultRootVertexShader()
|
||||
return m_defaultRootVertexShader;
|
||||
}
|
||||
|
||||
QStringList EffectMakerModel::getDefaultRootFragmentShader()
|
||||
QStringList EffectComposerModel::getDefaultRootFragmentShader()
|
||||
{
|
||||
if (m_defaultRootFragmentShader.isEmpty()) {
|
||||
m_defaultRootFragmentShader << "void main() {";
|
||||
@@ -1093,7 +1109,7 @@ QStringList EffectMakerModel::getDefaultRootFragmentShader()
|
||||
|
||||
// Remove all post-processing tags ("@tag") from the code.
|
||||
// Except "@nodes" tag as that is handled later.
|
||||
QStringList EffectMakerModel::removeTagsFromCode(const QStringList &codeLines)
|
||||
QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines)
|
||||
{
|
||||
QStringList s;
|
||||
for (const QString &line : codeLines) {
|
||||
@@ -1118,13 +1134,13 @@ QStringList EffectMakerModel::removeTagsFromCode(const QStringList &codeLines)
|
||||
return s;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::removeTagsFromCode(const QString &code)
|
||||
QString EffectComposerModel::removeTagsFromCode(const QString &code)
|
||||
{
|
||||
QStringList codeLines = removeTagsFromCode(code.split('\n'));
|
||||
return codeLines.join('\n');
|
||||
}
|
||||
|
||||
QString EffectMakerModel::getCustomShaderVaryings(bool outState)
|
||||
QString EffectComposerModel::getCustomShaderVaryings(bool outState)
|
||||
{
|
||||
QString output;
|
||||
QString direction = outState ? QStringLiteral("out") : QStringLiteral("in");
|
||||
@@ -1136,7 +1152,7 @@ QString EffectMakerModel::getCustomShaderVaryings(bool outState)
|
||||
return output;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::generateVertexShader(bool includeUniforms)
|
||||
QString EffectComposerModel::generateVertexShader(bool includeUniforms)
|
||||
{
|
||||
QString s;
|
||||
|
||||
@@ -1192,7 +1208,7 @@ QString EffectMakerModel::generateVertexShader(bool includeUniforms)
|
||||
return s;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::generateFragmentShader(bool includeUniforms)
|
||||
QString EffectComposerModel::generateFragmentShader(bool includeUniforms)
|
||||
{
|
||||
QString s;
|
||||
|
||||
@@ -1247,7 +1263,7 @@ QString EffectMakerModel::generateFragmentShader(bool includeUniforms)
|
||||
return s;
|
||||
}
|
||||
|
||||
void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader, bool preview)
|
||||
void EffectComposerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader, bool preview)
|
||||
{
|
||||
--m_remainingQsbTargets;
|
||||
|
||||
@@ -1279,7 +1295,7 @@ void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QS
|
||||
|
||||
// Generates string of the custom properties (uniforms) into ShaderEffect component
|
||||
// Also generates QML images elements for samplers.
|
||||
void EffectMakerModel::updateCustomUniforms()
|
||||
void EffectComposerModel::updateCustomUniforms()
|
||||
{
|
||||
QString exportedRootPropertiesString;
|
||||
QString previewEffectPropertiesString;
|
||||
@@ -1345,7 +1361,7 @@ void EffectMakerModel::updateCustomUniforms()
|
||||
m_exportedEffectPropertiesString = exportedEffectPropertiesString;
|
||||
}
|
||||
|
||||
void EffectMakerModel::createFiles()
|
||||
void EffectComposerModel::createFiles()
|
||||
{
|
||||
if (QFileInfo(m_vertexShaderFilename).exists())
|
||||
QFile(m_vertexShaderFilename).remove();
|
||||
@@ -1378,7 +1394,7 @@ void EffectMakerModel::createFiles()
|
||||
}
|
||||
}
|
||||
|
||||
void EffectMakerModel::bakeShaders()
|
||||
void EffectComposerModel::bakeShaders()
|
||||
{
|
||||
const QString failMessage = "Shader baking failed: ";
|
||||
|
||||
@@ -1460,12 +1476,12 @@ void EffectMakerModel::bakeShaders()
|
||||
|
||||
}
|
||||
|
||||
bool EffectMakerModel::shadersUpToDate() const
|
||||
bool EffectComposerModel::shadersUpToDate() const
|
||||
{
|
||||
return m_shadersUpToDate;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setShadersUpToDate(bool UpToDate)
|
||||
void EffectComposerModel::setShadersUpToDate(bool UpToDate)
|
||||
{
|
||||
if (m_shadersUpToDate == UpToDate)
|
||||
return;
|
||||
@@ -1473,9 +1489,22 @@ void EffectMakerModel::setShadersUpToDate(bool UpToDate)
|
||||
emit shadersUpToDateChanged();
|
||||
}
|
||||
|
||||
bool EffectComposerModel::isEnabled() const
|
||||
{
|
||||
return m_isEnabled;
|
||||
}
|
||||
|
||||
void EffectComposerModel::setIsEnabled(bool enabled)
|
||||
{
|
||||
if (m_isEnabled == enabled)
|
||||
return;
|
||||
m_isEnabled = enabled;
|
||||
emit isEnabledChanged();
|
||||
}
|
||||
|
||||
// Returns name for image mipmap property.
|
||||
// e.g. "myImage" -> "myImageMipmap".
|
||||
QString EffectMakerModel::mipmapPropertyName(const QString &name) const
|
||||
QString EffectComposerModel::mipmapPropertyName(const QString &name) const
|
||||
{
|
||||
QString simplifiedName = name.simplified();
|
||||
simplifiedName = simplifiedName.remove(' ');
|
||||
@@ -1483,41 +1512,43 @@ QString EffectMakerModel::mipmapPropertyName(const QString &name) const
|
||||
return simplifiedName;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::getQmlImagesString(bool localFiles)
|
||||
QString EffectComposerModel::getQmlImagesString(bool localFiles)
|
||||
{
|
||||
QString imagesString;
|
||||
const QList<Uniform *> uniforms = allUniforms();
|
||||
for (Uniform *uniform : uniforms) {
|
||||
if (uniform->type() == Uniform::Type::Sampler) {
|
||||
QString imagePath = uniform->value().toString();
|
||||
if (imagePath.isEmpty())
|
||||
// For preview, generate image element even if path is empty, as changing uniform values
|
||||
// will not trigger qml code regeneration
|
||||
if (localFiles && imagePath.isEmpty())
|
||||
continue;
|
||||
imagesString += " Image {\n";
|
||||
QString simplifiedName = getImageElementName(*uniform);
|
||||
imagesString += QString(" id: %1\n").arg(simplifiedName);
|
||||
imagesString += " anchors.fill: parent\n";
|
||||
imagesString += " Image {\n";
|
||||
QString simplifiedName = getImageElementName(*uniform, localFiles);
|
||||
imagesString += QString(" id: %1\n").arg(simplifiedName);
|
||||
imagesString += " anchors.fill: parent\n";
|
||||
// File paths are absolute, return as local when requested
|
||||
if (localFiles) {
|
||||
QFileInfo fi(imagePath);
|
||||
imagePath = fi.fileName();
|
||||
imagesString += QString(" source: \"%1\"\n").arg(imagePath);
|
||||
imagesString += QString(" source: \"%1\"\n").arg(imagePath);
|
||||
} else {
|
||||
imagesString += QString(" source: g_propertyData.%1\n").arg(uniform->name());
|
||||
imagesString += QString(" source: g_propertyData.%1\n").arg(uniform->name());
|
||||
|
||||
if (uniform->enableMipmap())
|
||||
imagesString += " mipmap: true\n";
|
||||
imagesString += " mipmap: true\n";
|
||||
else
|
||||
QString mipmapProperty = mipmapPropertyName(uniform->name());
|
||||
}
|
||||
|
||||
imagesString += " visible: false\n";
|
||||
imagesString += " }\n";
|
||||
imagesString += " visible: false\n";
|
||||
imagesString += " }\n";
|
||||
}
|
||||
}
|
||||
return imagesString;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::getQmlComponentString(bool localFiles)
|
||||
QString EffectComposerModel::getQmlComponentString(bool localFiles)
|
||||
{
|
||||
auto addProperty = [localFiles](const QString &name, const QString &var,
|
||||
const QString &type, bool blurHelper = false)
|
||||
@@ -1604,12 +1635,12 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles)
|
||||
return s;
|
||||
}
|
||||
|
||||
QString EffectMakerModel::currentComposition() const
|
||||
QString EffectComposerModel::currentComposition() const
|
||||
{
|
||||
return m_currentComposition;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setCurrentComposition(const QString &newCurrentComposition)
|
||||
void EffectComposerModel::setCurrentComposition(const QString &newCurrentComposition)
|
||||
{
|
||||
if (m_currentComposition == newCurrentComposition)
|
||||
return;
|
||||
@@ -1618,12 +1649,12 @@ void EffectMakerModel::setCurrentComposition(const QString &newCurrentCompositio
|
||||
emit currentCompositionChanged();
|
||||
}
|
||||
|
||||
bool EffectMakerModel::hasUnsavedChanges() const
|
||||
bool EffectComposerModel::hasUnsavedChanges() const
|
||||
{
|
||||
return m_hasUnsavedChanges;
|
||||
}
|
||||
|
||||
void EffectMakerModel::setHasUnsavedChanges(bool val)
|
||||
void EffectComposerModel::setHasUnsavedChanges(bool val)
|
||||
{
|
||||
if (m_hasUnsavedChanges == val)
|
||||
return;
|
||||
@@ -1632,7 +1663,7 @@ void EffectMakerModel::setHasUnsavedChanges(bool val)
|
||||
emit hasUnsavedChangesChanged();
|
||||
}
|
||||
|
||||
QStringList EffectMakerModel::uniformNames() const
|
||||
QStringList EffectComposerModel::uniformNames() const
|
||||
{
|
||||
QStringList usedList;
|
||||
const QList<Uniform *> uniforms = allUniforms();
|
||||
@@ -1641,14 +1672,14 @@ QStringList EffectMakerModel::uniformNames() const
|
||||
return usedList;
|
||||
}
|
||||
|
||||
bool EffectMakerModel::isDependencyNode(int index) const
|
||||
bool EffectComposerModel::isDependencyNode(int index) const
|
||||
{
|
||||
if (m_nodes.size() > index)
|
||||
return m_nodes[index]->isDependency();
|
||||
return false;
|
||||
}
|
||||
|
||||
void EffectMakerModel::updateQmlComponent()
|
||||
void EffectComposerModel::updateQmlComponent()
|
||||
{
|
||||
// Clear possible QML runtime errors
|
||||
resetEffectError(ErrorQMLRuntime);
|
||||
@@ -1657,11 +1688,11 @@ void EffectMakerModel::updateQmlComponent()
|
||||
|
||||
// Removes "file:" from the URL path.
|
||||
// So e.g. "file:///C:/myimages/steel1.jpg" -> "C:/myimages/steel1.jpg"
|
||||
QString EffectMakerModel::stripFileFromURL(const QString &urlString) const
|
||||
QString EffectComposerModel::stripFileFromURL(const QString &urlString) const
|
||||
{
|
||||
QUrl url(urlString);
|
||||
QString filePath = (url.scheme() == QStringLiteral("file")) ? url.toLocalFile() : url.toString();
|
||||
return filePath;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
@@ -21,7 +21,7 @@ namespace Utils {
|
||||
class Process;
|
||||
}
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class CompositionNode;
|
||||
class Uniform;
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
int m_type = -1;
|
||||
};
|
||||
|
||||
class EffectMakerModel : public QAbstractListModel
|
||||
class EffectComposerModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -46,11 +46,12 @@ class EffectMakerModel : public QAbstractListModel
|
||||
Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
|
||||
Q_PROPERTY(bool hasUnsavedChanges MEMBER m_hasUnsavedChanges WRITE setHasUnsavedChanges NOTIFY hasUnsavedChangesChanged)
|
||||
Q_PROPERTY(bool shadersUpToDate READ shadersUpToDate WRITE setShadersUpToDate NOTIFY shadersUpToDateChanged)
|
||||
Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
|
||||
Q_PROPERTY(QString qmlComponentString READ qmlComponentString)
|
||||
Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged)
|
||||
|
||||
public:
|
||||
EffectMakerModel(QObject *parent = nullptr);
|
||||
EffectComposerModel(QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
|
||||
@@ -73,6 +74,9 @@ public:
|
||||
bool shadersUpToDate() const;
|
||||
void setShadersUpToDate(bool newShadersUpToDate);
|
||||
|
||||
bool isEnabled() const;
|
||||
void setIsEnabled(bool enabled);
|
||||
|
||||
QString fragmentShader() const;
|
||||
void setFragmentShader(const QString &newFragmentShader);
|
||||
|
||||
@@ -105,6 +109,7 @@ signals:
|
||||
void selectedIndexChanged(int idx);
|
||||
void effectErrorChanged();
|
||||
void shadersUpToDateChanged();
|
||||
void isEnabledChanged();
|
||||
void shadersBaked();
|
||||
void currentCompositionChanged();
|
||||
void nodesChanged();
|
||||
@@ -143,7 +148,7 @@ private:
|
||||
QString valueAsString(const Uniform &uniform);
|
||||
QString valueAsBinding(const Uniform &uniform);
|
||||
QString valueAsVariable(const Uniform &uniform);
|
||||
QString getImageElementName(const Uniform &uniform);
|
||||
QString getImageElementName(const Uniform &uniform, bool localFiles);
|
||||
const QString getConstVariables();
|
||||
const QString getDefineProperties();
|
||||
int getTagIndex(const QStringList &code, const QString &tag);
|
||||
@@ -201,10 +206,11 @@ private:
|
||||
QString m_previewEffectPropertiesString;
|
||||
QString m_qmlComponentString;
|
||||
bool m_loadComponentImages = true;
|
||||
bool m_isEnabled = true;
|
||||
QString m_currentComposition;
|
||||
|
||||
const QRegularExpression m_spaceReg = QRegularExpression("\\s+");
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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 "effectcomposernodesmodel.h"
|
||||
#include "effectutils.h"
|
||||
|
||||
#include <utils/filepath.h>
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectMakerNodesModel::EffectMakerNodesModel(QObject *parent)
|
||||
EffectComposerNodesModel::EffectComposerNodesModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> EffectMakerNodesModel::roleNames() const
|
||||
QHash<int, QByteArray> EffectComposerNodesModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[CategoryNameRole] = "categoryName";
|
||||
@@ -25,14 +25,14 @@ QHash<int, QByteArray> EffectMakerNodesModel::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
int EffectMakerNodesModel::rowCount(const QModelIndex &parent) const
|
||||
int EffectComposerNodesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_categories.count();
|
||||
}
|
||||
|
||||
QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const
|
||||
QVariant EffectComposerNodesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.row() < m_categories.size(), return {});
|
||||
QTC_ASSERT(roleNames().contains(role), return {});
|
||||
@@ -40,7 +40,7 @@ QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const
|
||||
return m_categories.at(index.row())->property(roleNames().value(role));
|
||||
}
|
||||
|
||||
void EffectMakerNodesModel::loadModel()
|
||||
void EffectComposerNodesModel::loadModel()
|
||||
{
|
||||
if (m_modelLoaded)
|
||||
return;
|
||||
@@ -86,13 +86,13 @@ void EffectMakerNodesModel::loadModel()
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void EffectMakerNodesModel::resetModel()
|
||||
void EffectComposerNodesModel::resetModel()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void EffectMakerNodesModel::updateCanBeAdded(const QStringList &uniforms)
|
||||
void EffectComposerNodesModel::updateCanBeAdded(const QStringList &uniforms)
|
||||
{
|
||||
for (const EffectNodesCategory *cat : std::as_const(m_categories)) {
|
||||
const QList<EffectNode *> nodes = cat->nodes();
|
||||
@@ -108,4 +108,4 @@ void EffectMakerNodesModel::updateCanBeAdded(const QStringList &uniforms)
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectMakerNodesModel : public QAbstractListModel
|
||||
class EffectComposerNodesModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -19,7 +19,7 @@ class EffectMakerNodesModel : public QAbstractListModel
|
||||
};
|
||||
|
||||
public:
|
||||
EffectMakerNodesModel(QObject *parent = nullptr);
|
||||
EffectComposerNodesModel(QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
|
||||
@@ -40,5 +40,5 @@ private:
|
||||
bool m_modelLoaded = false;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
51
src/plugins/effectcomposer/effectcomposerplugin.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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 <effectcomposerview.h>
|
||||
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
|
||||
namespace EffectComposer {
|
||||
|
||||
static bool enableEffectComposer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
class EffectComposerPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "EffectComposer.json")
|
||||
|
||||
public:
|
||||
EffectComposerPlugin() {}
|
||||
~EffectComposerPlugin() override {}
|
||||
|
||||
bool delayedInitialize() override
|
||||
{
|
||||
if (m_delayedInitialized)
|
||||
return true;
|
||||
|
||||
if (enableEffectComposer()) {
|
||||
auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance();
|
||||
auto &viewManager = designerPlugin->viewManager();
|
||||
|
||||
viewManager.registerView(std::make_unique<EffectComposerView>(
|
||||
QmlDesigner::QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly()));
|
||||
}
|
||||
|
||||
m_delayedInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_delayedInitialized = false;
|
||||
};
|
||||
|
||||
} // namespace EffectComposer
|
||||
|
||||
#include "effectcomposerplugin.moc"
|
||||
@@ -1,21 +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
|
||||
|
||||
#include "effectmakeruniformsmodel.h"
|
||||
#include "effectcomposeruniformsmodel.h"
|
||||
|
||||
#include "propertyhandler.h"
|
||||
#include "uniform.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectMakerUniformsModel::EffectMakerUniformsModel(QObject *parent)
|
||||
EffectComposerUniformsModel::EffectComposerUniformsModel(QObject *parent)
|
||||
: QAbstractListModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> EffectMakerUniformsModel::roleNames() const
|
||||
QHash<int, QByteArray> EffectComposerUniformsModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[NameRole] = "uniformName";
|
||||
@@ -30,14 +30,14 @@ QHash<int, QByteArray> EffectMakerUniformsModel::roleNames() const
|
||||
return roles;
|
||||
}
|
||||
|
||||
int EffectMakerUniformsModel::rowCount(const QModelIndex &parent) const
|
||||
int EffectComposerUniformsModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
|
||||
return m_uniforms.size();
|
||||
}
|
||||
|
||||
QVariant EffectMakerUniformsModel::data(const QModelIndex &index, int role) const
|
||||
QVariant EffectComposerUniformsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.row() < m_uniforms.size(), return {});
|
||||
QTC_ASSERT(roleNames().contains(role), return {});
|
||||
@@ -45,7 +45,7 @@ QVariant EffectMakerUniformsModel::data(const QModelIndex &index, int role) cons
|
||||
return m_uniforms.at(index.row())->property(roleNames().value(role));
|
||||
}
|
||||
|
||||
bool EffectMakerUniformsModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
bool EffectComposerUniformsModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid() || !roleNames().contains(role))
|
||||
return false;
|
||||
@@ -71,23 +71,23 @@ bool EffectMakerUniformsModel::setData(const QModelIndex &index, const QVariant
|
||||
return true;
|
||||
}
|
||||
|
||||
void EffectMakerUniformsModel::resetModel()
|
||||
void EffectComposerUniformsModel::resetModel()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void EffectMakerUniformsModel::addUniform(Uniform *uniform)
|
||||
void EffectComposerUniformsModel::addUniform(Uniform *uniform)
|
||||
{
|
||||
beginInsertRows({}, m_uniforms.size(), m_uniforms.size());
|
||||
m_uniforms.append(uniform);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
QList<Uniform *> EffectMakerUniformsModel::uniforms() const
|
||||
QList<Uniform *> EffectComposerUniformsModel::uniforms() const
|
||||
{
|
||||
return m_uniforms;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class Uniform;
|
||||
|
||||
class EffectMakerUniformsModel : public QAbstractListModel
|
||||
class EffectComposerUniformsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EffectMakerUniformsModel(QObject *parent = nullptr);
|
||||
EffectComposerUniformsModel(QObject *parent = nullptr);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
|
||||
@@ -43,5 +43,5 @@ private:
|
||||
QList<Uniform *> m_uniforms;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
102
src/plugins/effectcomposer/effectcomposerview.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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 "effectcomposerview.h"
|
||||
|
||||
#include "effectcomposermodel.h"
|
||||
#include "effectcomposernodesmodel.h"
|
||||
#include "effectcomposerwidget.h"
|
||||
|
||||
#include <designermcumanager.h>
|
||||
#include <documentmanager.h>
|
||||
#include <modelnodeoperations.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectComposerContext::EffectComposerContext(QWidget *widget)
|
||||
: IContext(widget)
|
||||
{
|
||||
setWidget(widget);
|
||||
setContext(Core::Context(QmlDesigner::Constants::C_QMLEFFECTCOMPOSER,
|
||||
QmlDesigner::Constants::C_QT_QUICK_TOOLS_MENU));
|
||||
}
|
||||
|
||||
void EffectComposerContext::contextHelp(const HelpCallback &callback) const
|
||||
{
|
||||
qobject_cast<EffectComposerWidget *>(m_widget)->contextHelp(callback);
|
||||
}
|
||||
|
||||
EffectComposerView::EffectComposerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies)
|
||||
: AbstractView{externalDependencies}
|
||||
{
|
||||
}
|
||||
|
||||
EffectComposerView::~EffectComposerView()
|
||||
{}
|
||||
|
||||
bool EffectComposerView::hasWidget() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QmlDesigner::WidgetInfo EffectComposerView::widgetInfo()
|
||||
{
|
||||
if (m_widget.isNull()) {
|
||||
m_widget = new EffectComposerWidget{this};
|
||||
|
||||
connect(m_widget->effectComposerModel(), &EffectComposerModel::assignToSelectedTriggered, this,
|
||||
[&] (const QString &effectPath) {
|
||||
executeInTransaction("EffectComposerView::widgetInfo", [&] {
|
||||
const QList<QmlDesigner::ModelNode> selectedNodes = selectedModelNodes();
|
||||
for (const QmlDesigner::ModelNode &node : selectedNodes)
|
||||
QmlDesigner::ModelNodeOperations::handleItemLibraryEffectDrop(effectPath, node);
|
||||
});
|
||||
});
|
||||
|
||||
auto context = new EffectComposerContext(m_widget.data());
|
||||
Core::ICore::addContextObject(context);
|
||||
}
|
||||
|
||||
return createWidgetInfo(m_widget.data(), "EffectComposer",
|
||||
QmlDesigner::WidgetInfo::LeftPane, 0, tr("Effect Composer [beta]"));
|
||||
}
|
||||
|
||||
void EffectComposerView::customNotification([[maybe_unused]] const AbstractView *view,
|
||||
const QString &identifier,
|
||||
[[maybe_unused]] const QList<QmlDesigner::ModelNode> &nodeList,
|
||||
const QList<QVariant> &data)
|
||||
{
|
||||
if (identifier == "open_effectcomposer_composition" && data.count() > 0) {
|
||||
const QString compositionPath = data[0].toString();
|
||||
m_widget->openComposition(compositionPath);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectComposerView::modelAttached(QmlDesigner::Model *model)
|
||||
{
|
||||
AbstractView::modelAttached(model);
|
||||
|
||||
m_widget->effectComposerNodesModel()->loadModel();
|
||||
|
||||
QString currProjectPath = QmlDesigner::DocumentManager::currentProjectDirPath().toString();
|
||||
|
||||
if (m_currProjectPath != currProjectPath) { // starting a new project
|
||||
m_widget->effectComposerModel()->clear(true);
|
||||
m_widget->effectComposerModel()->setIsEnabled(
|
||||
!QmlDesigner::DesignerMcuManager::instance().isMCUProject());
|
||||
}
|
||||
|
||||
m_currProjectPath = currProjectPath;
|
||||
|
||||
m_widget->initView();
|
||||
}
|
||||
|
||||
void EffectComposerView::modelAboutToBeDetached(QmlDesigner::Model *model)
|
||||
{
|
||||
AbstractView::modelAboutToBeDetached(model);
|
||||
}
|
||||
|
||||
} // namespace EffectComposer
|
||||
@@ -9,24 +9,24 @@
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectMakerWidget;
|
||||
class EffectComposerWidget;
|
||||
|
||||
class EffectMakerContext : public Core::IContext
|
||||
class EffectComposerContext : public Core::IContext
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EffectMakerContext(QWidget *widget);
|
||||
EffectComposerContext(QWidget *widget);
|
||||
void contextHelp(const Core::IContext::HelpCallback &callback) const override;
|
||||
};
|
||||
|
||||
class EffectMakerView : public QmlDesigner::AbstractView
|
||||
class EffectComposerView : public QmlDesigner::AbstractView
|
||||
{
|
||||
public:
|
||||
EffectMakerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies);
|
||||
~EffectMakerView() override;
|
||||
EffectComposerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies);
|
||||
~EffectComposerView() override;
|
||||
|
||||
bool hasWidget() const override;
|
||||
QmlDesigner::WidgetInfo widgetInfo() override;
|
||||
@@ -39,7 +39,8 @@ private:
|
||||
void customNotification(const AbstractView *view, const QString &identifier,
|
||||
const QList<QmlDesigner::ModelNode> &nodeList, const QList<QVariant> &data) override;
|
||||
|
||||
QPointer<EffectMakerWidget> m_widget;
|
||||
QPointer<EffectComposerWidget> m_widget;
|
||||
QString m_currProjectPath;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
@@ -1,21 +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
|
||||
|
||||
#include "effectmakerwidget.h"
|
||||
#include "effectcomposerwidget.h"
|
||||
|
||||
#include "effectmakercontextobject.h"
|
||||
#include "effectmakermodel.h"
|
||||
#include "effectmakernodesmodel.h"
|
||||
#include "effectmakerview.h"
|
||||
#include "effectcomposercontextobject.h"
|
||||
#include "effectcomposermodel.h"
|
||||
#include "effectcomposernodesmodel.h"
|
||||
#include "effectcomposerview.h"
|
||||
#include "effectutils.h"
|
||||
#include "propertyhandler.h"
|
||||
|
||||
//#include "qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
#include "qmldesignerplugin.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <qmldesigner/documentmanager.h>
|
||||
#include <qmldesigner/qmldesignerconstants.h>
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <QQuickItem>
|
||||
#include <QTimer>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
static QString propertyEditorResourcesPath()
|
||||
{
|
||||
@@ -46,19 +46,19 @@ static QString propertyEditorResourcesPath()
|
||||
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
|
||||
}
|
||||
|
||||
EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
|
||||
: m_effectMakerModel{new EffectMakerModel(this)}
|
||||
, m_effectMakerNodesModel{new EffectMakerNodesModel(this)}
|
||||
, m_effectMakerView(view)
|
||||
EffectComposerWidget::EffectComposerWidget(EffectComposerView *view)
|
||||
: m_effectComposerModel{new EffectComposerModel(this)}
|
||||
, m_effectComposerNodesModel{new EffectComposerNodesModel(this)}
|
||||
, m_effectComposerView(view)
|
||||
, m_quickWidget{new StudioQuickWidget(this)}
|
||||
{
|
||||
setWindowTitle(tr("Effect Maker", "Title of effect maker widget"));
|
||||
setWindowTitle(tr("Effect Composer", "Title of effect composer widget"));
|
||||
setMinimumWidth(250);
|
||||
|
||||
m_quickWidget->quickWidget()->installEventFilter(this);
|
||||
|
||||
// create the inner widget
|
||||
m_quickWidget->quickWidget()->setObjectName(QmlDesigner::Constants::OBJECT_NAME_EFFECT_MAKER);
|
||||
m_quickWidget->quickWidget()->setObjectName(QmlDesigner::Constants::OBJECT_NAME_EFFECT_COMPOSER);
|
||||
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
QmlDesigner::Theme::setupTheme(m_quickWidget->engine());
|
||||
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
|
||||
@@ -74,7 +74,7 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
|
||||
setStyleSheet(QmlDesigner::Theme::replaceCssColors(
|
||||
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
|
||||
|
||||
QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(this, QmlDesigner::Constants::EVENT_EFFECTMAKER_TIME);
|
||||
QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(this, QmlDesigner::Constants::EVENT_EFFECTCOMPOSER_TIME);
|
||||
|
||||
m_quickWidget->rootContext()->setContextProperty("g_propertyData", &g_propertyData);
|
||||
|
||||
@@ -82,23 +82,21 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
|
||||
g_propertyData.insert(QString("blur_vs_path"), QString(blurPath + "bluritems.vert.qsb"));
|
||||
g_propertyData.insert(QString("blur_fs_path"), QString(blurPath + "bluritems.frag.qsb"));
|
||||
|
||||
auto map = m_quickWidget->registerPropertyMap("EffectMakerBackend");
|
||||
map->setProperties({{"effectMakerNodesModel", QVariant::fromValue(m_effectMakerNodesModel.data())},
|
||||
{"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())},
|
||||
auto map = m_quickWidget->registerPropertyMap("EffectComposerBackend");
|
||||
map->setProperties({{"effectComposerNodesModel", QVariant::fromValue(m_effectComposerNodesModel.data())},
|
||||
{"effectComposerModel", QVariant::fromValue(m_effectComposerModel.data())},
|
||||
{"rootView", QVariant::fromValue(this)}});
|
||||
QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(
|
||||
this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME);
|
||||
|
||||
connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, this, [this]() {
|
||||
m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames());
|
||||
connect(m_effectComposerModel.data(), &EffectComposerModel::nodesChanged, this, [this]() {
|
||||
m_effectComposerNodesModel->updateCanBeAdded(m_effectComposerModel->uniformNames());
|
||||
});
|
||||
|
||||
connect(m_effectMakerModel.data(), &EffectMakerModel::resourcesSaved,
|
||||
connect(m_effectComposerModel.data(), &EffectComposerModel::resourcesSaved,
|
||||
this, [this](const QmlDesigner::TypeName &type, const Utils::FilePath &path) {
|
||||
if (!m_importScan.timer) {
|
||||
m_importScan.timer = new QTimer(this);
|
||||
connect(m_importScan.timer, &QTimer::timeout,
|
||||
this, &EffectMakerWidget::handleImportScanTimer);
|
||||
this, &EffectComposerWidget::handleImportScanTimer);
|
||||
}
|
||||
|
||||
if (m_importScan.timer->isActive() && !m_importScan.future.isFinished())
|
||||
@@ -110,10 +108,27 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
|
||||
|
||||
m_importScan.timer->start(100);
|
||||
});
|
||||
|
||||
connect(m_effectComposerModel.data(), &EffectComposerModel::hasUnsavedChangesChanged,
|
||||
this, [this]() {
|
||||
if (m_effectComposerModel->hasUnsavedChanges() && !m_effectComposerModel->currentComposition().isEmpty()) {
|
||||
if (auto doc = QmlDesigner::QmlDesignerPlugin::instance()->documentManager().currentDesignDocument())
|
||||
doc->setModified();
|
||||
}
|
||||
});
|
||||
|
||||
connect(Core::EditorManager::instance(), &Core::EditorManager::aboutToSave,
|
||||
this, [this](Core::IDocument *document) {
|
||||
if (m_effectComposerModel->hasUnsavedChanges()) {
|
||||
QString compName = m_effectComposerModel->currentComposition();
|
||||
if (!compName.isEmpty())
|
||||
m_effectComposerModel->saveComposition(compName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool EffectMakerWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
bool EffectComposerWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(obj)
|
||||
Q_UNUSED(event)
|
||||
@@ -123,70 +138,76 @@ bool EffectMakerWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
void EffectMakerWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
|
||||
void EffectComposerWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
|
||||
{
|
||||
Q_UNUSED(callback)
|
||||
}
|
||||
|
||||
StudioQuickWidget *EffectMakerWidget::quickWidget() const
|
||||
StudioQuickWidget *EffectComposerWidget::quickWidget() const
|
||||
{
|
||||
return m_quickWidget.data();
|
||||
}
|
||||
|
||||
QPointer<EffectMakerModel> EffectMakerWidget::effectMakerModel() const
|
||||
QPointer<EffectComposerModel> EffectComposerWidget::effectComposerModel() const
|
||||
{
|
||||
return m_effectMakerModel;
|
||||
return m_effectComposerModel;
|
||||
}
|
||||
|
||||
QPointer<EffectMakerNodesModel> EffectMakerWidget::effectMakerNodesModel() const
|
||||
QPointer<EffectComposerNodesModel> EffectComposerWidget::effectComposerNodesModel() const
|
||||
{
|
||||
return m_effectMakerNodesModel;
|
||||
return m_effectComposerNodesModel;
|
||||
}
|
||||
|
||||
void EffectMakerWidget::addEffectNode(const QString &nodeQenPath)
|
||||
void EffectComposerWidget::addEffectNode(const QString &nodeQenPath)
|
||||
{
|
||||
m_effectMakerModel->addNode(nodeQenPath);
|
||||
m_effectComposerModel->addNode(nodeQenPath);
|
||||
|
||||
if (!nodeQenPath.isEmpty()) {
|
||||
using namespace QmlDesigner;
|
||||
QString id = nodeQenPath.split('/').last().chopped(4).prepend('_');
|
||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_EFFECTCOMPOSER_NODE + id);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectMakerWidget::focusSection(int section)
|
||||
void EffectComposerWidget::focusSection(int section)
|
||||
{
|
||||
Q_UNUSED(section)
|
||||
}
|
||||
|
||||
QRect EffectMakerWidget::screenRect() const
|
||||
QRect EffectComposerWidget::screenRect() const
|
||||
{
|
||||
if (m_quickWidget && m_quickWidget->screen())
|
||||
return m_quickWidget->screen()->availableGeometry();
|
||||
return {};
|
||||
}
|
||||
|
||||
QPoint EffectMakerWidget::globalPos(const QPoint &point) const
|
||||
QPoint EffectComposerWidget::globalPos(const QPoint &point) const
|
||||
{
|
||||
if (m_quickWidget)
|
||||
return m_quickWidget->mapToGlobal(point);
|
||||
return point;
|
||||
}
|
||||
|
||||
QSize EffectMakerWidget::sizeHint() const
|
||||
QSize EffectComposerWidget::sizeHint() const
|
||||
{
|
||||
return {420, 420};
|
||||
}
|
||||
|
||||
QString EffectMakerWidget::qmlSourcesPath()
|
||||
QString EffectComposerWidget::qmlSourcesPath()
|
||||
{
|
||||
#ifdef SHARE_QML_PATH
|
||||
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
||||
return QLatin1String(SHARE_QML_PATH) + "/effectMakerQmlSources";
|
||||
return QLatin1String(SHARE_QML_PATH) + "/effectComposerQmlSources";
|
||||
#endif
|
||||
return Core::ICore::resourcePath("qmldesigner/effectMakerQmlSources").toString();
|
||||
return Core::ICore::resourcePath("qmldesigner/effectComposerQmlSources").toString();
|
||||
}
|
||||
|
||||
void EffectMakerWidget::initView()
|
||||
void EffectComposerWidget::initView()
|
||||
{
|
||||
auto ctxObj = new EffectMakerContextObject(m_quickWidget->rootContext());
|
||||
auto ctxObj = new EffectComposerContextObject(m_quickWidget->rootContext());
|
||||
m_quickWidget->rootContext()->setContextObject(ctxObj);
|
||||
|
||||
m_backendModelNode.setup(m_effectMakerView->rootModelNode());
|
||||
m_backendModelNode.setup(m_effectComposerView->rootModelNode());
|
||||
m_quickWidget->rootContext()->setContextProperty("anchorBackend", &m_backendAnchorBinding);
|
||||
m_quickWidget->rootContext()->setContextProperty("modelNodeBackend", &m_backendModelNode);
|
||||
m_quickWidget->rootContext()->setContextProperty("activeDragSuffix", "");
|
||||
@@ -200,29 +221,29 @@ void EffectMakerWidget::initView()
|
||||
reloadQmlSource();
|
||||
}
|
||||
|
||||
void EffectMakerWidget::openComposition(const QString &path)
|
||||
void EffectComposerWidget::openComposition(const QString &path)
|
||||
{
|
||||
m_compositionPath = path;
|
||||
|
||||
if (effectMakerModel()->hasUnsavedChanges())
|
||||
if (effectComposerModel()->hasUnsavedChanges())
|
||||
QMetaObject::invokeMethod(quickWidget()->rootObject(), "promptToSaveBeforeOpen");
|
||||
else
|
||||
doOpenComposition();
|
||||
}
|
||||
|
||||
void EffectMakerWidget::doOpenComposition()
|
||||
void EffectComposerWidget::doOpenComposition()
|
||||
{
|
||||
effectMakerModel()->openComposition(m_compositionPath);
|
||||
effectComposerModel()->openComposition(m_compositionPath);
|
||||
}
|
||||
|
||||
void EffectMakerWidget::reloadQmlSource()
|
||||
void EffectComposerWidget::reloadQmlSource()
|
||||
{
|
||||
const QString effectMakerQmlPath = qmlSourcesPath() + "/EffectMaker.qml";
|
||||
QTC_ASSERT(QFileInfo::exists(effectMakerQmlPath), return);
|
||||
m_quickWidget->setSource(QUrl::fromLocalFile(effectMakerQmlPath));
|
||||
const QString effectComposerQmlPath = qmlSourcesPath() + "/EffectComposer.qml";
|
||||
QTC_ASSERT(QFileInfo::exists(effectComposerQmlPath), return);
|
||||
m_quickWidget->setSource(QUrl::fromLocalFile(effectComposerQmlPath));
|
||||
}
|
||||
|
||||
void EffectMakerWidget::handleImportScanTimer()
|
||||
void EffectComposerWidget::handleImportScanTimer()
|
||||
{
|
||||
++m_importScan.counter;
|
||||
|
||||
@@ -247,24 +268,24 @@ void EffectMakerWidget::handleImportScanTimer()
|
||||
m_importScan.timer->stop();
|
||||
m_importScan.counter = 0;
|
||||
} else if (m_importScan.counter == 101) {
|
||||
if (m_effectMakerView->model() && m_effectMakerView->model()->rewriterView()) {
|
||||
if (m_effectComposerView->model() && m_effectComposerView->model()->rewriterView()) {
|
||||
QmlDesigner::QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
|
||||
m_effectMakerView->model()->rewriterView()->forceAmend();
|
||||
m_effectComposerView->model()->rewriterView()->forceAmend();
|
||||
}
|
||||
} else if (m_importScan.counter == 102) {
|
||||
if (m_effectMakerView->model()) {
|
||||
if (m_effectComposerView->model()) {
|
||||
// If type is in use, we have to reset puppet to update 2D view
|
||||
if (!m_effectMakerView->allModelNodesOfType(
|
||||
m_effectMakerView->model()->metaInfo(m_importScan.type)).isEmpty()) {
|
||||
m_effectMakerView->resetPuppet();
|
||||
if (!m_effectComposerView->allModelNodesOfType(
|
||||
m_effectComposerView->model()->metaInfo(m_importScan.type)).isEmpty()) {
|
||||
m_effectComposerView->resetPuppet();
|
||||
}
|
||||
}
|
||||
} else if (m_importScan.counter >= 103) {
|
||||
// Refresh property view by resetting selection if any selected node is of updated type
|
||||
if (m_effectMakerView->model() && m_effectMakerView->hasSelectedModelNodes()) {
|
||||
const auto nodes = m_effectMakerView->selectedModelNodes();
|
||||
if (m_effectComposerView->model() && m_effectComposerView->hasSelectedModelNodes()) {
|
||||
const auto nodes = m_effectComposerView->selectedModelNodes();
|
||||
QmlDesigner::MetaInfoType metaType
|
||||
= m_effectMakerView->model()->metaInfo(m_importScan.type).type();
|
||||
= m_effectComposerView->model()->metaInfo(m_importScan.type).type();
|
||||
bool match = false;
|
||||
for (const QmlDesigner::ModelNode &node : nodes) {
|
||||
if (node.metaInfo().type() == metaType) {
|
||||
@@ -273,8 +294,8 @@ void EffectMakerWidget::handleImportScanTimer()
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
m_effectMakerView->clearSelectedModelNodes();
|
||||
m_effectMakerView->setSelectedModelNodes(nodes);
|
||||
m_effectComposerView->clearSelectedModelNodes();
|
||||
m_effectComposerView->setSelectedModelNodes(nodes);
|
||||
}
|
||||
}
|
||||
m_importScan.timer->stop();
|
||||
@@ -282,5 +303,5 @@ void EffectMakerWidget::handleImportScanTimer()
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h"
|
||||
#include "qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h"
|
||||
#include <qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h>
|
||||
#include <qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h>
|
||||
|
||||
#include <coreplugin/icontext.h>
|
||||
|
||||
@@ -17,19 +17,19 @@ QT_BEGIN_NAMESPACE
|
||||
class QTimer;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectMakerView;
|
||||
class EffectMakerModel;
|
||||
class EffectMakerNodesModel;
|
||||
class EffectComposerView;
|
||||
class EffectComposerModel;
|
||||
class EffectComposerNodesModel;
|
||||
|
||||
class EffectMakerWidget : public QFrame
|
||||
class EffectComposerWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EffectMakerWidget(EffectMakerView *view);
|
||||
~EffectMakerWidget() = default;
|
||||
EffectComposerWidget(EffectComposerView *view);
|
||||
~EffectComposerWidget() = default;
|
||||
|
||||
void contextHelp(const Core::IContext::HelpCallback &callback) const;
|
||||
|
||||
@@ -42,8 +42,8 @@ public:
|
||||
void openComposition(const QString &path);
|
||||
|
||||
StudioQuickWidget *quickWidget() const;
|
||||
QPointer<EffectMakerModel> effectMakerModel() const;
|
||||
QPointer<EffectMakerNodesModel> effectMakerNodesModel() const;
|
||||
QPointer<EffectComposerModel> effectComposerModel() const;
|
||||
QPointer<EffectComposerNodesModel> effectComposerNodesModel() const;
|
||||
|
||||
Q_INVOKABLE void addEffectNode(const QString &nodeQenPath);
|
||||
Q_INVOKABLE void focusSection(int section);
|
||||
@@ -60,9 +60,9 @@ private:
|
||||
void reloadQmlSource();
|
||||
void handleImportScanTimer();
|
||||
|
||||
QPointer<EffectMakerModel> m_effectMakerModel;
|
||||
QPointer<EffectMakerNodesModel> m_effectMakerNodesModel;
|
||||
QPointer<EffectMakerView> m_effectMakerView;
|
||||
QPointer<EffectComposerModel> m_effectComposerModel;
|
||||
QPointer<EffectComposerNodesModel> m_effectComposerNodesModel;
|
||||
QPointer<EffectComposerView> m_effectComposerView;
|
||||
QPointer<StudioQuickWidget> m_quickWidget;
|
||||
QmlDesigner::QmlModelNodeProxy m_backendModelNode;
|
||||
QmlDesigner::QmlAnchorBindingProxy m_backendAnchorBinding;
|
||||
@@ -79,5 +79,5 @@ private:
|
||||
QString m_compositionPath;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectNode::EffectNode(const QString &qenPath)
|
||||
: m_qenPath(qenPath)
|
||||
{
|
||||
const QFileInfo fileInfo = QFileInfo(qenPath);
|
||||
m_name = fileInfo.baseName();
|
||||
|
||||
QString iconPath = QStringLiteral("%1/icon/%2.svg").arg(fileInfo.absolutePath(), m_name);
|
||||
QString iconPath = QStringLiteral("%1/icon/%2.svg").arg(fileInfo.absolutePath(),
|
||||
fileInfo.baseName());
|
||||
if (!QFileInfo::exists(iconPath)) {
|
||||
QDir parentDir = QDir(fileInfo.absolutePath());
|
||||
parentDir.cdUp();
|
||||
@@ -26,8 +26,11 @@ EffectNode::EffectNode(const QString &qenPath)
|
||||
m_iconPath = QUrl::fromLocalFile(iconPath);
|
||||
|
||||
CompositionNode node({}, qenPath);
|
||||
const QList<Uniform *> uniforms = node.uniforms();
|
||||
|
||||
m_name = node.name();
|
||||
m_description = node.description();
|
||||
|
||||
const QList<Uniform *> uniforms = node.uniforms();
|
||||
for (const Uniform *uniform : uniforms)
|
||||
m_uniformNames.insert(uniform->name());
|
||||
}
|
||||
@@ -60,5 +63,5 @@ bool EffectNode::hasUniform(const QString &name)
|
||||
return m_uniformNames.contains(name);
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <QSet>
|
||||
#include <QUrl>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectNode : public QObject
|
||||
{
|
||||
@@ -42,5 +42,5 @@ private:
|
||||
QSet<QString> m_uniformNames;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "effectnodescategory.h"
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
EffectNodesCategory::EffectNodesCategory(const QString &name, const QList<EffectNode *> &nodes)
|
||||
: m_name(name),
|
||||
@@ -19,5 +19,5 @@ QList<EffectNode *> EffectNodesCategory::nodes() const
|
||||
return m_categoryNodes;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectNodesCategory : public QObject
|
||||
{
|
||||
@@ -27,5 +27,5 @@ private:
|
||||
QList<EffectNode *> m_categoryNodes;
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
QString EffectUtils::codeFromJsonArray(const QJsonArray &codeArray)
|
||||
{
|
||||
@@ -26,10 +26,9 @@ QString EffectUtils::nodesSourcesPath()
|
||||
{
|
||||
#ifdef SHARE_QML_PATH
|
||||
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
||||
return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes";
|
||||
return QLatin1String(SHARE_QML_PATH) + "/effectComposerNodes";
|
||||
#endif
|
||||
return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString();
|
||||
return Core::ICore::resourcePath("qmldesigner/effectComposerNodes").toString();
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
|
||||
} // namespace EffectComposer
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QJsonArray)
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class EffectUtils
|
||||
{
|
||||
@@ -19,5 +19,5 @@ public:
|
||||
static QString nodesSourcesPath();
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "propertyhandler.h"
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
QQmlPropertyMap g_propertyData;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <QQmlPropertyMap>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
// This will be used for binding dynamic properties
|
||||
// changes between C++ and QML.
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <QStringList>
|
||||
#include <QDebug>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
ShaderFeatures::ShaderFeatures()
|
||||
{
|
||||
@@ -73,8 +73,12 @@ void ShaderFeatures::checkLine(const QString &line, Features &features)
|
||||
if (m_gridMeshWidth > 1 || m_gridMeshHeight > 1)
|
||||
features.setFlag(GridMesh, true);
|
||||
}
|
||||
|
||||
if (line.contains("@blursources"))
|
||||
features.setFlag(BlurSources, true);
|
||||
|
||||
if (line.contains("textureLod("))
|
||||
features.setFlag(Mipmap, true);
|
||||
}
|
||||
|
||||
int ShaderFeatures::gridMeshHeight() const
|
||||
@@ -87,5 +91,5 @@ int ShaderFeatures::gridMeshWidth() const
|
||||
return m_gridMeshWidth;
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QFlags>
|
||||
#include <QString>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class ShaderFeatures
|
||||
{
|
||||
@@ -19,7 +19,8 @@ public:
|
||||
Mouse = 1 << 4,
|
||||
FragCoord = 1 << 5,
|
||||
GridMesh = 1 << 6,
|
||||
BlurSources = 1 << 7
|
||||
BlurSources = 1 << 7,
|
||||
Mipmap = 1 << 8
|
||||
};
|
||||
Q_DECLARE_FLAGS(Features, Feature)
|
||||
|
||||
@@ -40,5 +41,5 @@ private:
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ShaderFeatures::Features)
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "syntaxhighlighterdata.h"
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
static constexpr QByteArrayView shader_arg_names[] {
|
||||
{ "gl_Position" },
|
||||
@@ -186,6 +186,6 @@ QList<QByteArrayView> SyntaxHighlighterData::reservedFunctionNames()
|
||||
return { std::begin(shader_function_names), std::end(shader_function_names) };
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QByteArrayView>
|
||||
#include <QList>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class SyntaxHighlighterData
|
||||
{
|
||||
@@ -18,6 +18,6 @@ public:
|
||||
static QList<QByteArrayView> reservedFunctionNames();
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QVector2D>
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QString &qenPath)
|
||||
: m_qenPath(qenPath)
|
||||
@@ -28,11 +28,15 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS
|
||||
if (m_displayName.isEmpty())
|
||||
m_displayName = m_name;
|
||||
|
||||
QString resPath;
|
||||
value = propObj.contains("value") ? propObj.value("value").toString() : defaultValue;
|
||||
|
||||
if (m_type == Type::Sampler) {
|
||||
resPath = getResourcePath(effectName, defaultValue, qenPath);
|
||||
if (!defaultValue.isEmpty())
|
||||
defaultValue = resPath;
|
||||
defaultValue = getResourcePath(effectName, defaultValue, qenPath);
|
||||
if (!value.isEmpty())
|
||||
value = getResourcePath(effectName, value, qenPath);
|
||||
if (value.isEmpty())
|
||||
value = defaultValue;
|
||||
if (propObj.contains("enableMipmap"))
|
||||
m_enableMipmap = getBoolValue(propObj.value("enableMipmap"), false);
|
||||
// Update the mipmap property
|
||||
@@ -40,14 +44,6 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS
|
||||
g_propertyData[mipmapProperty] = m_enableMipmap;
|
||||
}
|
||||
|
||||
if (propObj.contains("value")) {
|
||||
value = propObj.value("value").toString();
|
||||
if (m_type == Type::Sampler)
|
||||
value = resPath;
|
||||
} else {
|
||||
// QEN files don't store the current value, so with those use default value
|
||||
value = defaultValue;
|
||||
}
|
||||
m_customValue = propObj.value("customValue").toString();
|
||||
m_useCustomValue = getBoolValue(propObj.value("useCustomValue"), false);
|
||||
|
||||
@@ -346,4 +342,4 @@ QString Uniform::typeToProperty(Uniform::Type type)
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
@@ -12,7 +12,7 @@ QT_FORWARD_DECLARE_CLASS(QColor)
|
||||
QT_FORWARD_DECLARE_CLASS(QJsonObject)
|
||||
QT_FORWARD_DECLARE_CLASS(QVector2D)
|
||||
|
||||
namespace EffectMaker {
|
||||
namespace EffectComposer {
|
||||
|
||||
class Uniform : public QObject
|
||||
{
|
||||
@@ -109,4 +109,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
} // namespace EffectComposer
|
||||
@@ -1,42 +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 "effectmakerview.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include <viewmanager.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
namespace EffectMaker {
|
||||
|
||||
static bool enableEffectMaker()
|
||||
{
|
||||
Utils::QtcSettings *settings = Core::ICore::settings();
|
||||
const Utils::Key enableModelManagerKey = "QML/Designer/UseExperimentalFeatures44";
|
||||
|
||||
return settings->value(enableModelManagerKey, false).toBool();
|
||||
}
|
||||
|
||||
class EffectMakerPlugin final : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "EffectMakerNew.json")
|
||||
|
||||
bool delayedInitialize() final
|
||||
{
|
||||
if (enableEffectMaker()) {
|
||||
auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance();
|
||||
auto &viewManager = designerPlugin->viewManager();
|
||||
|
||||
viewManager.registerView(std::make_unique<EffectMakerView>(
|
||||
QmlDesigner::QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace EffectMaker
|
||||
|
||||
#include "effectmakerplugin.moc"
|
||||
@@ -1,91 +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 "effectmakerview.h"
|
||||
|
||||
#include "effectmakermodel.h"
|
||||
#include "effectmakernodesmodel.h"
|
||||
#include "effectmakerwidget.h"
|
||||
|
||||
#include "qmldesignerconstants.h"
|
||||
|
||||
#include <modelnodeoperations.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
namespace EffectMaker {
|
||||
|
||||
EffectMakerContext::EffectMakerContext(QWidget *widget)
|
||||
: IContext(widget)
|
||||
{
|
||||
setWidget(widget);
|
||||
setContext(Core::Context(QmlDesigner::Constants::C_QMLEFFECTMAKER,
|
||||
QmlDesigner::Constants::C_QT_QUICK_TOOLS_MENU));
|
||||
}
|
||||
|
||||
void EffectMakerContext::contextHelp(const HelpCallback &callback) const
|
||||
{
|
||||
qobject_cast<EffectMakerWidget *>(m_widget)->contextHelp(callback);
|
||||
}
|
||||
|
||||
EffectMakerView::EffectMakerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies)
|
||||
: AbstractView{externalDependencies}
|
||||
{
|
||||
}
|
||||
|
||||
EffectMakerView::~EffectMakerView()
|
||||
{}
|
||||
|
||||
bool EffectMakerView::hasWidget() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QmlDesigner::WidgetInfo EffectMakerView::widgetInfo()
|
||||
{
|
||||
if (m_widget.isNull()) {
|
||||
m_widget = new EffectMakerWidget{this};
|
||||
|
||||
connect(m_widget->effectMakerModel(), &EffectMakerModel::assignToSelectedTriggered, this,
|
||||
[&] (const QString &effectPath) {
|
||||
executeInTransaction("EffectMakerView::widgetInfo", [&] {
|
||||
const QList<QmlDesigner::ModelNode> selectedNodes = selectedModelNodes();
|
||||
for (const QmlDesigner::ModelNode &node : selectedNodes)
|
||||
QmlDesigner::ModelNodeOperations::handleItemLibraryEffectDrop(effectPath, node);
|
||||
});
|
||||
});
|
||||
|
||||
auto context = new EffectMakerContext(m_widget.data());
|
||||
Core::ICore::addContextObject(context);
|
||||
}
|
||||
|
||||
return createWidgetInfo(m_widget.data(), "Effect Maker",
|
||||
QmlDesigner::WidgetInfo::LeftPane, 0, tr("Effect Maker"));
|
||||
}
|
||||
|
||||
void EffectMakerView::customNotification([[maybe_unused]] const AbstractView *view,
|
||||
const QString &identifier,
|
||||
[[maybe_unused]] const QList<QmlDesigner::ModelNode> &nodeList,
|
||||
const QList<QVariant> &data)
|
||||
{
|
||||
if (identifier == "open_effectmaker_composition" && data.count() > 0) {
|
||||
const QString compositionPath = data[0].toString();
|
||||
m_widget->openComposition(compositionPath);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectMakerView::modelAttached(QmlDesigner::Model *model)
|
||||
{
|
||||
AbstractView::modelAttached(model);
|
||||
|
||||
m_widget->effectMakerNodesModel()->loadModel();
|
||||
m_widget->effectMakerModel()->clear();
|
||||
m_widget->initView();
|
||||
}
|
||||
|
||||
void EffectMakerView::modelAboutToBeDetached(QmlDesigner::Model *model)
|
||||
{
|
||||
AbstractView::modelAboutToBeDetached(model);
|
||||
}
|
||||
|
||||
} // namespace EffectMaker
|
||||
@@ -503,7 +503,6 @@ 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
|
||||
|
||||
@@ -114,13 +114,28 @@ void AssetsLibraryModel::deleteFiles(const QStringList &filePaths, bool dontAskA
|
||||
if (dontAskAgain)
|
||||
QmlDesignerPlugin::settings().insert(DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, false);
|
||||
|
||||
QStringList deletedEffects;
|
||||
|
||||
for (const QString &filePath : filePaths) {
|
||||
if (QFileInfo::exists(filePath) && !QFile::remove(filePath)) {
|
||||
QMessageBox::warning(Core::ICore::dialogParent(),
|
||||
tr("Failed to Delete File"),
|
||||
tr("Could not delete \"%1\".").arg(filePath));
|
||||
QFileInfo fi(filePath);
|
||||
if (fi.exists()) {
|
||||
if (QFile::remove(filePath)) {
|
||||
if (Asset(filePath).isEffect()) {
|
||||
// If an effect composer effect was removed, also remove effect module from project
|
||||
QString effectName = fi.baseName();
|
||||
if (!effectName.isEmpty())
|
||||
deletedEffects.append(effectName);
|
||||
}
|
||||
} else {
|
||||
QMessageBox::warning(Core::ICore::dialogParent(),
|
||||
tr("Failed to Delete File"),
|
||||
tr("Could not delete \"%1\".").arg(filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deletedEffects.isEmpty())
|
||||
emit effectsDeleted(deletedEffects);
|
||||
}
|
||||
|
||||
bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &newName)
|
||||
|
||||
@@ -64,6 +64,7 @@ signals:
|
||||
void rootPathChanged();
|
||||
void haveFilesChanged();
|
||||
void fileChanged(const QString &path);
|
||||
void effectsDeleted(const QStringList &effectNames);
|
||||
|
||||
private:
|
||||
void setHaveFiles(bool value);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "assetslibrarymodel.h"
|
||||
#include "assetslibraryview.h"
|
||||
#include "designeractionmanager.h"
|
||||
#include "import.h"
|
||||
#include "nodemetainfo.h"
|
||||
#include "modelnodeoperations.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
#include "qmldesignerplugin.h"
|
||||
@@ -27,6 +29,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QImageReader>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QPointF>
|
||||
@@ -118,6 +121,9 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
|
||||
connect(m_assetsModel, &AssetsLibraryModel::fileChanged,
|
||||
QmlDesignerPlugin::instance(), &QmlDesignerPlugin::assetChanged);
|
||||
|
||||
connect(m_assetsModel, &AssetsLibraryModel::effectsDeleted,
|
||||
this, &AssetsLibraryWidget::handleDeleteEffects);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins({});
|
||||
layout->setSpacing(0);
|
||||
@@ -184,12 +190,12 @@ QString AssetsLibraryWidget::getUniqueEffectPath(const QString &parentFolder, co
|
||||
return path;
|
||||
}
|
||||
|
||||
bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openInEffectMaker)
|
||||
bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openInEffectComposer)
|
||||
{
|
||||
bool created = QFile(effectPath).open(QIODevice::WriteOnly);
|
||||
|
||||
if (created && openInEffectMaker) {
|
||||
openEffectMaker(effectPath);
|
||||
if (created && openInEffectComposer) {
|
||||
openEffectComposer(effectPath);
|
||||
emit directoryCreated(QFileInfo(effectPath).absolutePath());
|
||||
}
|
||||
|
||||
@@ -263,6 +269,73 @@ void AssetsLibraryWidget::setHasSceneEnv(bool b)
|
||||
emit hasSceneEnvChanged();
|
||||
}
|
||||
|
||||
void AssetsLibraryWidget::handleDeleteEffects(const QStringList &effectNames)
|
||||
{
|
||||
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
if (!document)
|
||||
return;
|
||||
|
||||
bool clearStacks = false;
|
||||
|
||||
// Remove usages of deleted effects from the current document
|
||||
m_assetsView->executeInTransaction(__FUNCTION__, [&]() {
|
||||
QList<ModelNode> allNodes = m_assetsView->allModelNodes();
|
||||
const QString typeTemplate = "Effects.%1.%1";
|
||||
const QString importUrlTemplate = "Effects.%1";
|
||||
const Imports imports = m_assetsView->model()->imports();
|
||||
Imports removedImports;
|
||||
for (const QString &effectName : effectNames) {
|
||||
if (effectName.isEmpty())
|
||||
continue;
|
||||
const TypeName type = typeTemplate.arg(effectName).toUtf8();
|
||||
for (ModelNode &node : allNodes) {
|
||||
if (node.metaInfo().typeName() == type) {
|
||||
clearStacks = true;
|
||||
node.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
const QString importPath = importUrlTemplate.arg(effectName);
|
||||
Import removedImport = Utils::findOrDefault(imports, [&importPath](const Import &import) {
|
||||
return import.url() == importPath;
|
||||
});
|
||||
if (!removedImport.isEmpty())
|
||||
removedImports.append(removedImport);
|
||||
}
|
||||
|
||||
if (!removedImports.isEmpty()) {
|
||||
m_assetsView->model()->changeImports({}, removedImports);
|
||||
clearStacks = true;
|
||||
}
|
||||
});
|
||||
|
||||
// The size check here is to weed out cases where project path somehow resolves
|
||||
// to just slash. Shortest legal currentProjectDirPath() would be "/a/".
|
||||
if (m_assetsModel->currentProjectDirPath().size() < 3)
|
||||
return;
|
||||
|
||||
Utils::FilePath effectsDir = ModelNodeOperations::getEffectsImportDirectory();
|
||||
|
||||
// Delete the effect modules
|
||||
for (const QString &effectName : effectNames) {
|
||||
Utils::FilePath eDir = effectsDir.pathAppended(effectName);
|
||||
if (eDir.exists() && eDir.toString().startsWith(m_assetsModel->currentProjectDirPath())) {
|
||||
QString error;
|
||||
eDir.removeRecursively(&error);
|
||||
if (!error.isEmpty()) {
|
||||
QMessageBox::warning(Core::ICore::dialogParent(),
|
||||
tr("Failed to Delete Effect Resources"),
|
||||
tr("Could not delete \"%1\".").arg(eDir.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset undo stack as removing effect components cannot be undone, and thus the stack will
|
||||
// contain only unworkable states.
|
||||
if (clearStacks)
|
||||
document->clearUndoRedoStacks();
|
||||
}
|
||||
|
||||
void AssetsLibraryWidget::invalidateThumbnail(const QString &id)
|
||||
{
|
||||
m_assetsIconProvider->invalidateThumbnail(id);
|
||||
@@ -359,9 +432,9 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
|
||||
return suffixes;
|
||||
}
|
||||
|
||||
void AssetsLibraryWidget::openEffectMaker(const QString &filePath)
|
||||
void AssetsLibraryWidget::openEffectComposer(const QString &filePath)
|
||||
{
|
||||
ModelNodeOperations::openEffectMaker(filePath);
|
||||
ModelNodeOperations::openEffectComposer(filePath);
|
||||
}
|
||||
|
||||
QString AssetsLibraryWidget::qmlSourcesPath()
|
||||
@@ -440,7 +513,7 @@ QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QStrin
|
||||
// Data: Image format (suffix)
|
||||
return {Constants::MIME_TYPE_ASSET_TEXTURE3D, asset.suffix().toUtf8()};
|
||||
} else if (asset.isEffect()) {
|
||||
// Data: Effect Maker format (suffix)
|
||||
// Data: Effect Composer format (suffix)
|
||||
return {Constants::MIME_TYPE_ASSET_EFFECT, asset.suffix().toUtf8()};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
const QString &targetDirPath = {});
|
||||
|
||||
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);
|
||||
Q_INVOKABLE void openEffectMaker(const QString &filePath);
|
||||
Q_INVOKABLE void openEffectComposer(const QString &filePath);
|
||||
Q_INVOKABLE int qtVersion() const;
|
||||
Q_INVOKABLE void invalidateThumbnail(const QString &id);
|
||||
Q_INVOKABLE QSize imageSize(const QString &id);
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
Q_INVOKABLE void updateContextMenuActionsEnableState();
|
||||
|
||||
Q_INVOKABLE QString getUniqueEffectPath(const QString &parentFolder, const QString &effectName);
|
||||
Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openInEffectMaker = true);
|
||||
Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openInEffectComposer = true);
|
||||
|
||||
Q_INVOKABLE bool canCreateEffects() const;
|
||||
|
||||
@@ -124,6 +124,8 @@ private:
|
||||
void setHasMaterialLibrary(bool enable);
|
||||
void setHasSceneEnv(bool b);
|
||||
|
||||
void handleDeleteEffects(const QStringList &effectNames);
|
||||
|
||||
QSize m_itemIconSize;
|
||||
|
||||
SynchronousImageCache &m_fontImageCache;
|
||||
|
||||
@@ -42,6 +42,79 @@ public:
|
||||
bool isValidRowId(int row) const { return row > -1 && row < elements.size(); }
|
||||
};
|
||||
|
||||
inline static bool isValidColorName(const QString &colorName)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
|
||||
return QColor::isValidColorName(colorName);
|
||||
#else
|
||||
constexpr QStringView colorPattern(
|
||||
u"(?<color>^(?:#(?:(?:[0-9a-fA-F]{2}){3,4}|(?:[0-9a-fA-F]){3,4}))$)");
|
||||
static const QRegularExpression colorRegex(colorPattern.toString());
|
||||
return colorRegex.match(colorName).hasMatch();
|
||||
#endif // >= Qt 6.4
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getCustomUrl
|
||||
* MimeType = <MainType/SubType>
|
||||
* Address = <Url|LocalFile>
|
||||
*
|
||||
* @param value The input value to be evaluated
|
||||
* @param dataType if the value is a valid url or image, the data type
|
||||
* will be stored to this parameter, otherwise, it will be Unknown
|
||||
* @param urlResult if the value is a valid url or image, the address
|
||||
* will be stored in this parameter, otherwise it will be empty.
|
||||
* @param subType if the value is a valid image, the image subtype
|
||||
* will be stored in this parameter, otherwise it will be empty.
|
||||
* @return true if the result is either url or image
|
||||
*/
|
||||
inline static bool getCustomUrl(const QString &value,
|
||||
CollectionDetails::DataType &dataType,
|
||||
QUrl *urlResult = nullptr,
|
||||
QString *subType = nullptr)
|
||||
{
|
||||
constexpr QStringView urlPattern(
|
||||
u"^(?<MimeType>"
|
||||
u"(?<MainType>image)\\/"
|
||||
u"(?<SubType>apng|avif|gif|jpeg|png|(?:svg\\+xml)|webp|xyz)\\:)?" // end of MimeType
|
||||
u"(?<Address>"
|
||||
u"(?<Url>https?:\\/\\/"
|
||||
u"(?:www\\.|(?!www))[A-z0-9][A-z0-9-]+[A-z0-9]\\.[^\\s]{2,}|www\\.[A-z0-9][A-z0-9-]+"
|
||||
u"[A-z0-9]\\.[^\\s]{2,}|https?:\\/\\/"
|
||||
u"(?:www\\.|(?!www))[A-z0-9]+\\.[^\\s]{2,}|www\\.[A-z0-9]+\\.[^\\s]{2,})|" // end of Url
|
||||
u"(?<LocalFile>("
|
||||
u"?:(?:[A-z]:)|(?:(?:\\\\|\\/){1,2}\\w+)\\$?)(?:(?:\\\\|\\/)(?:\\w[\\w ]*.*))+)" // end of LocalFile
|
||||
u"){1}$"); // end of Address
|
||||
static const QRegularExpression urlRegex(urlPattern.toString());
|
||||
|
||||
const QRegularExpressionMatch match = urlRegex.match(value);
|
||||
if (match.hasMatch()) {
|
||||
if (match.hasCaptured("Address")) {
|
||||
if (match.hasCaptured("MimeType") && match.captured("MainType") == "image")
|
||||
dataType = CollectionDetails::DataType::Image;
|
||||
else
|
||||
dataType = CollectionDetails::DataType::Url;
|
||||
|
||||
if (urlResult)
|
||||
urlResult->setUrl(match.captured("Address"));
|
||||
|
||||
if (subType)
|
||||
*subType = match.captured("SubType");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlResult)
|
||||
urlResult->clear();
|
||||
|
||||
if (subType)
|
||||
subType->clear();
|
||||
|
||||
dataType = CollectionDetails::DataType::Unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
static CollectionProperty::DataType collectionDataTypeFromJsonValue(const QJsonValue &value)
|
||||
{
|
||||
using DataType = CollectionDetails::DataType;
|
||||
@@ -53,10 +126,20 @@ static CollectionProperty::DataType collectionDataTypeFromJsonValue(const QJsonV
|
||||
return DataType::Unknown;
|
||||
case JsonType::Bool:
|
||||
return DataType::Boolean;
|
||||
case JsonType::Double:
|
||||
return DataType::Number;
|
||||
case JsonType::Double: {
|
||||
if (qFuzzyIsNull(std::remainder(value.toDouble(), 1)))
|
||||
return DataType::Integer;
|
||||
return DataType::Real;
|
||||
}
|
||||
case JsonType::String: {
|
||||
// TODO: Image, Color, Url
|
||||
const QString stringValue = value.toString();
|
||||
if (isValidColorName(stringValue))
|
||||
return DataType::Color;
|
||||
|
||||
DataType urlType;
|
||||
if (getCustomUrl(stringValue, urlType))
|
||||
return urlType;
|
||||
|
||||
return DataType::String;
|
||||
} break;
|
||||
default:
|
||||
@@ -72,12 +155,21 @@ static QVariant valueToVariant(const QJsonValue &value, CollectionDetails::DataT
|
||||
switch (type) {
|
||||
case DataType::String:
|
||||
return variantValue.toString();
|
||||
case DataType::Number:
|
||||
case DataType::Integer:
|
||||
return variantValue.toInt();
|
||||
case DataType::Real:
|
||||
return variantValue.toDouble();
|
||||
case DataType::Boolean:
|
||||
return variantValue.toBool();
|
||||
case DataType::Color:
|
||||
return variantValue.value<QColor>();
|
||||
case DataType::Image: {
|
||||
DataType type;
|
||||
QUrl url;
|
||||
if (getCustomUrl(variantValue.toString(), type, &url))
|
||||
return url;
|
||||
return variantValue.toString();
|
||||
}
|
||||
case DataType::Url:
|
||||
return variantValue.value<QUrl>();
|
||||
default:
|
||||
@@ -85,19 +177,38 @@ static QVariant valueToVariant(const QJsonValue &value, CollectionDetails::DataT
|
||||
}
|
||||
}
|
||||
|
||||
static QJsonValue variantToJsonValue(const QVariant &variant)
|
||||
static QJsonValue variantToJsonValue(
|
||||
const QVariant &variant, CollectionDetails::DataType type = CollectionDetails::DataType::Unknown)
|
||||
{
|
||||
using VariantType = QVariant::Type;
|
||||
using DataType = CollectionDetails::DataType;
|
||||
|
||||
switch (variant.type()) {
|
||||
case VariantType::Bool:
|
||||
if (type == CollectionDetails::DataType::Unknown) {
|
||||
static const QHash<VariantType, DataType> typeMap = {{VariantType::Bool, DataType::Boolean},
|
||||
{VariantType::Double, DataType::Real},
|
||||
{VariantType::Int, DataType::Integer},
|
||||
{VariantType::String, DataType::String},
|
||||
{VariantType::Color, DataType::Color},
|
||||
{VariantType::Url, DataType::Url}};
|
||||
type = typeMap.value(variant.type(), DataType::Unknown);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DataType::Boolean:
|
||||
return variant.toBool();
|
||||
case VariantType::Double:
|
||||
case VariantType::Int:
|
||||
case DataType::Real:
|
||||
return variant.toDouble();
|
||||
case VariantType::String:
|
||||
case VariantType::Color:
|
||||
case VariantType::Url:
|
||||
case DataType::Integer:
|
||||
return variant.toInt();
|
||||
case DataType::Image: {
|
||||
const QUrl url(variant.toUrl());
|
||||
if (url.isValid())
|
||||
return QString("image/xyz:%1").arg(url.toString());
|
||||
return {};
|
||||
}
|
||||
case DataType::String:
|
||||
case DataType::Color:
|
||||
case DataType::Url:
|
||||
default:
|
||||
return variant.toString();
|
||||
}
|
||||
@@ -255,7 +366,7 @@ bool CollectionDetails::setPropertyValue(int row, int column, const QVariant &va
|
||||
if (value == currentValue)
|
||||
return false;
|
||||
|
||||
element.insert(d->properties.at(column).name, QJsonValue::fromVariant(value));
|
||||
element.insert(d->properties.at(column).name, variantToJsonValue(value, typeAt(column)));
|
||||
markChanged();
|
||||
return true;
|
||||
}
|
||||
@@ -292,13 +403,14 @@ bool CollectionDetails::setPropertyType(int column, DataType type)
|
||||
if (property.type != type)
|
||||
changed = true;
|
||||
|
||||
const DataType formerType = property.type;
|
||||
property.type = type;
|
||||
|
||||
for (QJsonObject &element : d->elements) {
|
||||
if (element.contains(property.name)) {
|
||||
const QJsonValue value = element.value(property.name);
|
||||
const QVariant properTypedValue = valueToVariant(value, type);
|
||||
const QJsonValue properTypedJsonValue = variantToJsonValue(properTypedValue);
|
||||
const QVariant properTypedValue = valueToVariant(value, formerType);
|
||||
const QJsonValue properTypedJsonValue = variantToJsonValue(properTypedValue, type);
|
||||
element.insert(property.name, properTypedJsonValue);
|
||||
changed = true;
|
||||
}
|
||||
@@ -334,10 +446,19 @@ QVariant CollectionDetails::data(int row, int column) const
|
||||
const QString &propertyName = d->properties.at(column).name;
|
||||
const QJsonObject &elementNode = d->elements.at(row);
|
||||
|
||||
if (elementNode.contains(propertyName))
|
||||
return elementNode.value(propertyName).toVariant();
|
||||
if (!elementNode.contains(propertyName))
|
||||
return {};
|
||||
|
||||
return {};
|
||||
const QJsonValue cellValue = elementNode.value(propertyName);
|
||||
|
||||
if (typeAt(column) == DataType::Image) {
|
||||
const QUrl imageUrl = valueToVariant(cellValue, DataType::Image).toUrl();
|
||||
|
||||
if (imageUrl.isValid())
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
return cellValue.toVariant();
|
||||
}
|
||||
|
||||
QString CollectionDetails::propertyAt(int column) const
|
||||
@@ -375,13 +496,19 @@ DataTypeWarning::Warning CollectionDetails::cellWarningCheck(int row, int column
|
||||
const QString &propertyName = d->properties.at(column).name;
|
||||
const QJsonObject &element = d->elements.at(row);
|
||||
|
||||
if (typeAt(column) == DataType::Unknown || element.isEmpty()
|
||||
const DataType columnType = typeAt(column);
|
||||
const DataType cellType = typeAt(row, column);
|
||||
if (columnType == DataType::Unknown || element.isEmpty()
|
||||
|| data(row, column) == QVariant::fromValue(nullptr)) {
|
||||
return DataTypeWarning::Warning::None;
|
||||
}
|
||||
|
||||
if (element.contains(propertyName) && typeAt(column) != typeAt(row, column))
|
||||
return DataTypeWarning::Warning::CellDataTypeMismatch;
|
||||
if (element.contains(propertyName)) {
|
||||
if (columnType == DataType::Real && cellType == DataType::Integer)
|
||||
return DataTypeWarning::Warning::None;
|
||||
else if (columnType != cellType)
|
||||
return DataTypeWarning::Warning::CellDataTypeMismatch;
|
||||
}
|
||||
|
||||
return DataTypeWarning::Warning::None;
|
||||
}
|
||||
@@ -430,6 +557,14 @@ void CollectionDetails::swap(CollectionDetails &other)
|
||||
d.swap(other.d);
|
||||
}
|
||||
|
||||
void CollectionDetails::resetReference(const CollectionReference &reference)
|
||||
{
|
||||
if (d->reference != reference) {
|
||||
d->reference = reference;
|
||||
markChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CollectionDetails::registerDeclarativeType()
|
||||
{
|
||||
typedef CollectionDetails::DataType DataType;
|
||||
@@ -463,16 +598,23 @@ void CollectionDetails::resetPropertyType(const QString &propertyName)
|
||||
void CollectionDetails::resetPropertyType(CollectionProperty &property)
|
||||
{
|
||||
const QString &propertyName = property.name;
|
||||
DataType type = DataType::Unknown;
|
||||
DataType columnType = DataType::Unknown;
|
||||
for (const QJsonObject &element : std::as_const(d->elements)) {
|
||||
if (element.contains(propertyName)) {
|
||||
type = collectionDataTypeFromJsonValue(element.value(propertyName));
|
||||
if (type != DataType::Unknown)
|
||||
const DataType cellType = collectionDataTypeFromJsonValue(element.value(propertyName));
|
||||
if (cellType != DataType::Unknown) {
|
||||
if (columnType == DataType::Integer && cellType != DataType::Real)
|
||||
continue;
|
||||
|
||||
columnType = cellType;
|
||||
if (columnType == DataType::Integer)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property.type = type;
|
||||
property.type = columnType;
|
||||
}
|
||||
|
||||
void CollectionDetails::resetPropertyTypes()
|
||||
|
||||
@@ -60,7 +60,7 @@ class CollectionDetails
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum class DataType { Unknown, String, Url, Number, Boolean, Image, Color };
|
||||
enum class DataType { Unknown, String, Url, Integer, Real, Boolean, Image, Color };
|
||||
Q_ENUM(DataType)
|
||||
|
||||
explicit CollectionDetails();
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
bool markSaved();
|
||||
|
||||
void swap(CollectionDetails &other);
|
||||
void resetReference(const CollectionReference &reference);
|
||||
QString getCollectionAsJsonString() const;
|
||||
QString getCollectionAsCsvString() const;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
static QStringList typesStringList()
|
||||
{
|
||||
static const QStringList typesList = typeToStringHash().values();
|
||||
static const QStringList typesList = orderedTypeNames();
|
||||
return typesList;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,8 @@ private:
|
||||
{DataType::Unknown, "Unknown"},
|
||||
{DataType::String, "String"},
|
||||
{DataType::Url, "Url"},
|
||||
{DataType::Number, "Number"},
|
||||
{DataType::Real, "Real"},
|
||||
{DataType::Integer, "Integer"},
|
||||
{DataType::Boolean, "Boolean"},
|
||||
{DataType::Image, "Image"},
|
||||
{DataType::Color, "Color"},
|
||||
@@ -95,6 +96,29 @@ private:
|
||||
|
||||
return stringTypeHash;
|
||||
}
|
||||
|
||||
static QStringList orderedTypeNames()
|
||||
{
|
||||
const QList<DataType> orderedtypes{
|
||||
DataType::String,
|
||||
DataType::Integer,
|
||||
DataType::Real,
|
||||
DataType::Image,
|
||||
DataType::Color,
|
||||
DataType::Url,
|
||||
DataType::Boolean,
|
||||
DataType::Unknown,
|
||||
};
|
||||
|
||||
QStringList orderedNames;
|
||||
QHash<DataType, QString> typeStringHash = typeToStringHash();
|
||||
|
||||
for (const DataType &type : orderedtypes)
|
||||
orderedNames.append(typeStringHash.take(type));
|
||||
|
||||
Q_ASSERT(typeStringHash.isEmpty());
|
||||
return orderedNames;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -219,11 +243,16 @@ bool CollectionDetailsModel::removeColumns(int column, int count, const QModelIn
|
||||
bool columnsRemoved = m_currentCollection.removeColumns(column, count);
|
||||
endRemoveColumns();
|
||||
|
||||
if (!columnCount(parent))
|
||||
removeRows(0, rowCount(parent), parent);
|
||||
|
||||
int nextColumn = column - 1;
|
||||
if (nextColumn < 0 && columnCount(parent) > 0)
|
||||
nextColumn = 0;
|
||||
|
||||
selectColumn(nextColumn);
|
||||
|
||||
ensureSingleCell();
|
||||
return columnsRemoved;
|
||||
}
|
||||
|
||||
@@ -237,6 +266,7 @@ bool CollectionDetailsModel::removeRows(int row, int count, const QModelIndex &p
|
||||
bool rowsRemoved = m_currentCollection.removeElements(row, count);
|
||||
endRemoveRows();
|
||||
|
||||
ensureSingleCell();
|
||||
return rowsRemoved;
|
||||
}
|
||||
|
||||
@@ -317,8 +347,8 @@ bool CollectionDetailsModel::selectColumn(int section)
|
||||
|
||||
const int columns = columnCount();
|
||||
|
||||
if (m_selectedColumn >= columns)
|
||||
return false;
|
||||
if (section >= columns)
|
||||
section = columns - 1;
|
||||
|
||||
selectRow(-1);
|
||||
|
||||
@@ -415,6 +445,7 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q
|
||||
deselectAll();
|
||||
beginResetModel();
|
||||
switchToCollection(newReference);
|
||||
ensureSingleCell();
|
||||
endResetModel();
|
||||
}
|
||||
} else {
|
||||
@@ -427,6 +458,42 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q
|
||||
}
|
||||
}
|
||||
|
||||
void CollectionDetailsModel::removeCollection(const ModelNode &sourceNode, const QString &collection)
|
||||
{
|
||||
CollectionReference collectionRef{sourceNode, collection};
|
||||
if (!m_openedCollections.contains(collectionRef))
|
||||
return;
|
||||
|
||||
if (m_currentCollection.reference() == collectionRef)
|
||||
loadCollection({}, {});
|
||||
|
||||
m_openedCollections.remove(collectionRef);
|
||||
}
|
||||
|
||||
void CollectionDetailsModel::removeAllCollections()
|
||||
{
|
||||
loadCollection({}, {});
|
||||
m_openedCollections.clear();
|
||||
}
|
||||
|
||||
void CollectionDetailsModel::renameCollection(const ModelNode &sourceNode,
|
||||
const QString &oldName,
|
||||
const QString &newName)
|
||||
{
|
||||
CollectionReference oldRef{sourceNode, oldName};
|
||||
if (!m_openedCollections.contains(oldRef))
|
||||
return;
|
||||
|
||||
CollectionReference newReference{sourceNode, newName};
|
||||
bool collectionIsSelected = m_currentCollection.reference() == oldRef;
|
||||
CollectionDetails collection = m_openedCollections.take(oldRef);
|
||||
collection.resetReference(newReference);
|
||||
m_openedCollections.insert(newReference, collection);
|
||||
|
||||
if (collectionIsSelected)
|
||||
setCollectionName(newName);
|
||||
}
|
||||
|
||||
bool CollectionDetailsModel::saveDataStoreCollections()
|
||||
{
|
||||
const ModelNode node = m_currentCollection.reference().node;
|
||||
@@ -583,6 +650,7 @@ void CollectionDetailsModel::loadJsonCollection(const QString &source, const QSt
|
||||
SourceFormat sourceFormat = jsonFileIsOk ? SourceFormat::Json : SourceFormat::Unknown;
|
||||
beginResetModel();
|
||||
m_currentCollection.resetDetails(getJsonHeaders(collectionNodes), elements, sourceFormat);
|
||||
ensureSingleCell();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -635,9 +703,24 @@ void CollectionDetailsModel::loadCsvCollection(const QString &source,
|
||||
SourceFormat sourceFormat = csvFileIsOk ? SourceFormat::Csv : SourceFormat::Unknown;
|
||||
beginResetModel();
|
||||
m_currentCollection.resetDetails(headers, elements, sourceFormat);
|
||||
ensureSingleCell();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CollectionDetailsModel::ensureSingleCell()
|
||||
{
|
||||
if (!m_currentCollection.isValid())
|
||||
return;
|
||||
|
||||
if (!columnCount())
|
||||
addColumn(0, "Column 1", "String");
|
||||
|
||||
if (!rowCount())
|
||||
insertRow(0);
|
||||
|
||||
updateEmpty();
|
||||
}
|
||||
|
||||
QVariant CollectionDetailsModel::variantFromString(const QString &value)
|
||||
{
|
||||
constexpr QStringView typesPattern{u"(?<boolean>^(?:true|false)$)|"
|
||||
|
||||
@@ -61,6 +61,9 @@ public:
|
||||
static Q_INVOKABLE QStringList typesList();
|
||||
|
||||
void loadCollection(const ModelNode &sourceNode, const QString &collection);
|
||||
void removeCollection(const ModelNode &sourceNode, const QString &collection);
|
||||
void removeAllCollections();
|
||||
void renameCollection(const ModelNode &sourceNode, const QString &oldName, const QString &newName);
|
||||
|
||||
Q_INVOKABLE bool saveDataStoreCollections();
|
||||
Q_INVOKABLE bool exportCollection(const QUrl &url);
|
||||
@@ -81,6 +84,7 @@ private:
|
||||
void setCollectionName(const QString &newCollectionName);
|
||||
void loadJsonCollection(const QString &source, const QString &collection);
|
||||
void loadCsvCollection(const QString &source, const QString &collectionName);
|
||||
void ensureSingleCell();
|
||||
QVariant variantFromString(const QString &value);
|
||||
|
||||
QHash<CollectionReference, CollectionDetails> m_openedCollections;
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
#include "nodemetainfo.h"
|
||||
#include "propertymetainfo.h"
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <QColor>
|
||||
#include <QJsonArray>
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using CollectionDataVariant = std::variant<QString, bool, double, QUrl, QColor>;
|
||||
using CollectionDataVariant = std::variant<QString, bool, double, int, QUrl, QColor>;
|
||||
|
||||
inline bool operator<(const QColor &a, const QColor &b)
|
||||
{
|
||||
@@ -40,12 +40,15 @@ inline CollectionDataVariant valueToVariant(const QVariant &value,
|
||||
switch (type) {
|
||||
case DataType::String:
|
||||
return value.toString();
|
||||
case DataType::Number:
|
||||
case DataType::Real:
|
||||
return value.toDouble();
|
||||
case DataType::Integer:
|
||||
return value.toInt();
|
||||
case DataType::Boolean:
|
||||
return value.toBool();
|
||||
case DataType::Color:
|
||||
return value.value<QColor>();
|
||||
case DataType::Image:
|
||||
case DataType::Url:
|
||||
return value.value<QUrl>();
|
||||
default:
|
||||
@@ -290,6 +293,12 @@ bool ensureDataStoreExists(bool &justCreated)
|
||||
|
||||
if (qmlDirSaver.finalize()) {
|
||||
justCreated = true;
|
||||
|
||||
// Force code model reset to notice changes to existing module
|
||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (modelManager)
|
||||
modelManager->resetCodeModel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -498,8 +498,21 @@ void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collect
|
||||
return;
|
||||
}
|
||||
|
||||
CollectionListModel *list = m_collectionList.at(nodeIndex.row()).data();
|
||||
bool updateSelectedNames = list && list == m_previousSelectedList.data();
|
||||
emit collectionRenamed(oldName, newName);
|
||||
updateCollectionList(nodeIndex);
|
||||
|
||||
if (updateSelectedNames) {
|
||||
list = m_collectionList.at(nodeIndex.row()).data();
|
||||
if (m_selectedCollectionName == oldName) {
|
||||
list->selectCollectionName(newName);
|
||||
setSelectedCollectionName(newName);
|
||||
} else {
|
||||
// reselect to update ID if it's changed due to renaming and order changes
|
||||
list->selectCollectionName(m_selectedCollectionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,11 @@ CollectionView::CollectionView(ExternalDependenciesInterface &externalDependenci
|
||||
connect(ProjectExplorer::ProjectManager::instance(),
|
||||
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
||||
this,
|
||||
&CollectionView::resetDataStoreNode);
|
||||
[=] {
|
||||
resetDataStoreNode();
|
||||
if (m_widget.get())
|
||||
m_widget->collectionDetailsModel()->removeAllCollections();
|
||||
});
|
||||
resetDataStoreNode();
|
||||
}
|
||||
|
||||
@@ -91,6 +95,9 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo()
|
||||
this,
|
||||
[this](const QString &oldName, const QString &newName) {
|
||||
m_dataStore->renameCollection(oldName, newName);
|
||||
m_widget->collectionDetailsModel()->renameCollection(dataStoreNode(),
|
||||
oldName,
|
||||
newName);
|
||||
});
|
||||
|
||||
connect(sourceModel,
|
||||
@@ -98,6 +105,8 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo()
|
||||
this,
|
||||
[this](const QString &collectionName) {
|
||||
m_dataStore->removeCollection(collectionName);
|
||||
m_widget->collectionDetailsModel()->removeCollection(dataStoreNode(),
|
||||
collectionName);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ void CollectionWidget::reloadQmlSource()
|
||||
|
||||
QSize CollectionWidget::minimumSizeHint() const
|
||||
{
|
||||
return {300, 400};
|
||||
return {300, 300};
|
||||
}
|
||||
|
||||
bool CollectionWidget::loadJsonFile(const QUrl &url, const QString &collectionName)
|
||||
|
||||
@@ -251,7 +251,7 @@ const char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResourc
|
||||
const char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Qt 3D Studio Presentations");
|
||||
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
|
||||
"Effect Maker Files");
|
||||
"Effect Composer Files");
|
||||
|
||||
} //ComponentCoreConstants
|
||||
|
||||
|
||||
@@ -1623,22 +1623,22 @@ void updateImported3DAsset(const SelectionContext &selectionContext)
|
||||
}
|
||||
}
|
||||
|
||||
bool isNewEffectMakerActivated()
|
||||
bool isEffectComposerActivated()
|
||||
{
|
||||
const QVector<ExtensionSystem::PluginSpec *> specs = ExtensionSystem::PluginManager::plugins();
|
||||
return std::find_if(specs.begin(), specs.end(),
|
||||
[](ExtensionSystem::PluginSpec *spec) {
|
||||
return spec->name() == "EffectMakerNew" && spec->isEffectivelyEnabled();
|
||||
return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled();
|
||||
})
|
||||
!= specs.end();
|
||||
}
|
||||
|
||||
void openEffectMaker(const QString &filePath)
|
||||
void openEffectComposer(const QString &filePath)
|
||||
{
|
||||
if (ModelNodeOperations::isNewEffectMakerActivated()) {
|
||||
if (ModelNodeOperations::isEffectComposerActivated()) {
|
||||
QmlDesignerPlugin::instance()->viewManager()
|
||||
.emitCustomNotification("open_effectmaker_composition", {}, {filePath});
|
||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Effect Maker", true);
|
||||
.emitCustomNotification("open_effectcomposer_composition", {}, {filePath});
|
||||
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Effect Composer", true);
|
||||
} else {
|
||||
ModelNodeOperations::openOldEffectMaker(filePath);
|
||||
}
|
||||
@@ -1742,13 +1742,13 @@ bool validateEffect(const QString &effectPath)
|
||||
if (!qmlPath.exists()) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QObject::tr("Effect %1 is not complete.").arg(effectName));
|
||||
msgBox.setInformativeText(QObject::tr("Ensure that you have saved it in Qt Quick Effect Maker."
|
||||
msgBox.setInformativeText(QObject::tr("Ensure that you have saved it in the Effect Composer."
|
||||
"\nDo you want to edit this effect?"));
|
||||
msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
if (msgBox.exec() == QMessageBox::Yes)
|
||||
ModelNodeOperations::openEffectMaker(effectPath);
|
||||
ModelNodeOperations::openEffectComposer(effectPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -126,12 +126,12 @@ void updateImported3DAsset(const SelectionContext &selectionContext);
|
||||
|
||||
QMLDESIGNERCOMPONENTS_EXPORT Utils::FilePath getEffectsImportDirectory();
|
||||
QMLDESIGNERCOMPONENTS_EXPORT QString getEffectsDefaultDirectory(const QString &defaultDir = {});
|
||||
void openEffectMaker(const QString &filePath);
|
||||
void openEffectComposer(const QString &filePath);
|
||||
void openOldEffectMaker(const QString &filePath);
|
||||
QString getEffectIcon(const QString &effectPath);
|
||||
bool useLayerEffect();
|
||||
bool validateEffect(const QString &effectPath);
|
||||
bool isNewEffectMakerActivated();
|
||||
bool isEffectComposerActivated();
|
||||
|
||||
Utils::FilePath getImagesDefaultDirectory();
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ NodeMetaInfo dynamicTypeNameToNodeMetaInfo(const TypeName &typeName, Model *mode
|
||||
return model->metaInfo("QML.string");
|
||||
else if (typeName == "url")
|
||||
return model->metaInfo("QML.url");
|
||||
else if (typeName == "variant")
|
||||
else if (typeName == "var" || typeName == "variant")
|
||||
return model->metaInfo("QML.variant");
|
||||
else
|
||||
qWarning() << __FUNCTION__ << " type " << typeName << "not found";
|
||||
@@ -212,7 +212,7 @@ bool isDynamicVariantPropertyType(const TypeName &type)
|
||||
{
|
||||
// "variant" is considered value type as it is initialized as one.
|
||||
// This may need to change if we provide any kind of proper editor for it.
|
||||
static const QSet<TypeName> valueTypes{"int", "real", "color", "string", "bool", "url", "variant"};
|
||||
static const QSet<TypeName> valueTypes{"int", "real", "color", "string", "bool", "url", "var", "variant"};
|
||||
return valueTypes.contains(type);
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ QVariant defaultValueForType(const TypeName &type)
|
||||
value = false;
|
||||
else if (type == "url")
|
||||
value = "";
|
||||
else if (type == "variant")
|
||||
else if (type == "var" || type == "variant")
|
||||
value = "";
|
||||
|
||||
return value;
|
||||
|
||||
@@ -74,11 +74,7 @@ FormEditorScene *FormEditorItem::scene() const {
|
||||
FormEditorItem::FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene)
|
||||
: QGraphicsItem(scene->formLayerItem()),
|
||||
m_snappingLineCreator(this),
|
||||
m_qmlItemNode(qmlItemNode),
|
||||
m_borderWidth(1.0),
|
||||
m_highlightBoundingRect(false),
|
||||
m_blurContent(false),
|
||||
m_isContentVisible(true)
|
||||
m_qmlItemNode(qmlItemNode)
|
||||
{
|
||||
setCacheMode(QGraphicsItem::NoCache);
|
||||
setup();
|
||||
|
||||
@@ -129,11 +129,11 @@ private: // variables
|
||||
QPointer<QTimeLine> m_attentionTimeLine;
|
||||
QTransform m_inverseAttentionTransform;
|
||||
|
||||
double m_borderWidth;
|
||||
bool m_highlightBoundingRect;
|
||||
bool m_blurContent;
|
||||
bool m_isContentVisible;
|
||||
bool m_hasEffect;
|
||||
double m_borderWidth = 1.0;
|
||||
bool m_highlightBoundingRect = false;
|
||||
bool m_blurContent = false;
|
||||
bool m_isContentVisible = true;
|
||||
bool m_hasEffect = false;
|
||||
};
|
||||
|
||||
class FormEditorFlowItem : public FormEditorItem
|
||||
|
||||
@@ -1013,7 +1013,8 @@ void FormEditorView::updateHasEffects()
|
||||
item->setHasEffect(false);
|
||||
if (qmlNode.isEffectItem()) {
|
||||
FormEditorItem *parentItem = m_scene->itemForQmlItemNode(qmlNode.modelParentItem());
|
||||
parentItem->setHasEffect(true);
|
||||
if (parentItem)
|
||||
parentItem->setHasEffect(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,6 +427,12 @@ bool DesignDocument::hasProject() const
|
||||
return !DocumentManager::currentProjectDirPath().isEmpty();
|
||||
}
|
||||
|
||||
void DesignDocument::setModified()
|
||||
{
|
||||
if (!m_documentTextModifier.isNull())
|
||||
m_documentTextModifier->textDocument()->setModified(true);
|
||||
}
|
||||
|
||||
void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textModifer)
|
||||
{
|
||||
m_inFileComponentTextModifier.reset(textModifer);
|
||||
@@ -514,6 +520,13 @@ bool DesignDocument::isRedoAvailable() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void DesignDocument::clearUndoRedoStacks() const
|
||||
{
|
||||
const QPlainTextEdit *edit = plainTextEdit();
|
||||
if (edit)
|
||||
edit->document()->clearUndoRedoStacks();
|
||||
}
|
||||
|
||||
void DesignDocument::close()
|
||||
{
|
||||
m_documentLoaded = false;
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
#endif
|
||||
bool isUndoAvailable() const;
|
||||
bool isRedoAvailable() const;
|
||||
void clearUndoRedoStacks() const;
|
||||
|
||||
Model *currentModel() const;
|
||||
Model *documentModel() const;
|
||||
@@ -88,6 +89,8 @@ public:
|
||||
Utils::FilePath projectFolder() const;
|
||||
bool hasProject() const;
|
||||
|
||||
void setModified();
|
||||
|
||||
signals:
|
||||
void displayNameChanged(const QString &newFileName);
|
||||
void dirtyStateChanged(bool newState);
|
||||
|
||||
@@ -312,17 +312,13 @@ void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo,
|
||||
beginResetModel();
|
||||
clearSections();
|
||||
|
||||
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
Utils::FilePath qmlFileName = document->fileName();
|
||||
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName);
|
||||
QString projectName = project ? project->displayName() : "";
|
||||
|
||||
QStringList excludedImports {
|
||||
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1) + ".MaterialBundle",
|
||||
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1) + ".EffectBundle"
|
||||
};
|
||||
|
||||
// create import sections
|
||||
const QString projectName = DocumentManager::currentProjectName();
|
||||
const Imports usedImports = model->usedImports();
|
||||
QHash<QString, ItemLibraryImport *> importHash;
|
||||
for (const Import &import : model->imports()) {
|
||||
@@ -364,6 +360,7 @@ void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo,
|
||||
itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importUrl()));
|
||||
}
|
||||
|
||||
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
const bool blockNewImports = document->inFileComponentModelActive();
|
||||
const QList<ItemLibraryEntry> itemLibEntries = model->itemLibraryEntries();
|
||||
for (const ItemLibraryEntry &entry : itemLibEntries) {
|
||||
|
||||
@@ -147,9 +147,6 @@ static bool isInLayoutable(NodeAbstractProperty &parentProperty)
|
||||
static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty, const ModelNode &modelNode)
|
||||
{
|
||||
try {
|
||||
if (parentProperty.parentModelNode().type().startsWith("Effects."))
|
||||
return;
|
||||
|
||||
if (!modelNode.hasParentProperty() || parentProperty != modelNode.parentProperty()) {
|
||||
if (isInLayoutable(parentProperty)) {
|
||||
removePosition(modelNode);
|
||||
@@ -160,12 +157,12 @@ static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty
|
||||
parentProperty = parentProperty.parentModelNode().nodeAbstractProperty("layer.effect");
|
||||
QmlItemNode::placeEffectNode(parentProperty, modelNode, true);
|
||||
} else {
|
||||
QPointF scenePosition = QmlItemNode(modelNode).instanceScenePosition();
|
||||
QmlItemNode qmlNode(modelNode);
|
||||
QPointF scenePosition = qmlNode.instanceScenePosition();
|
||||
parentProperty.reparentHere(modelNode);
|
||||
if (!scenePosition.isNull())
|
||||
if (!scenePosition.isNull() && !qmlNode.isEffectItem())
|
||||
setScenePosition(modelNode, scenePosition);
|
||||
}
|
||||
|
||||
} else {
|
||||
parentProperty.reparentHere(modelNode);
|
||||
}
|
||||
@@ -550,28 +547,29 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
|
||||
if (widget)
|
||||
widget->setDragType("");
|
||||
|
||||
ModelNode targetNode = modelNodeForIndex(dropModelIndex);
|
||||
if (!targetNode.isValid() || QmlItemNode(targetNode).isEffectItem())
|
||||
return true;
|
||||
|
||||
if (dropModelIndex.model() == this) {
|
||||
if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
|
||||
handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex);
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)) {
|
||||
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
|
||||
ModelNode targetNode = modelNodeForIndex(rowModelIndex);
|
||||
targetNode = modelNodeForIndex(rowModelIndex);
|
||||
ModelNodeOperations::handleTextureDrop(mimeData, targetNode);
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) {
|
||||
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
|
||||
ModelNode targetNode = modelNodeForIndex(rowModelIndex);
|
||||
targetNode = modelNodeForIndex(rowModelIndex);
|
||||
ModelNodeOperations::handleMaterialDrop(mimeData, targetNode);
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
|
||||
QByteArray filePath = mimeData->data(Constants::MIME_TYPE_BUNDLE_TEXTURE);
|
||||
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
|
||||
if (targetNode.metaInfo().isQtQuick3DModel())
|
||||
m_view->emitCustomNotification("apply_asset_to_model3D", {targetNode}, {filePath}); // To MaterialBrowserView
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
|
||||
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
|
||||
if (targetNode.isValid())
|
||||
m_view->emitCustomNotification("drop_bundle_material", {targetNode}); // To ContentLibraryView
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_EFFECT)) {
|
||||
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
|
||||
if (targetNode.isValid())
|
||||
m_view->emitCustomNotification("drop_bundle_effect", {targetNode}); // To ContentLibraryView
|
||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
|
||||
@@ -888,6 +886,20 @@ void NavigatorTreeModel::moveNodesInteractive(NodeAbstractProperty &parentProper
|
||||
// is the default property of the parent and is of Component type.
|
||||
// In that case an implicit component will be created.
|
||||
|
||||
// We can only have single effect item child
|
||||
if (QmlItemNode(modelNode).isEffectItem()) {
|
||||
const QList<ModelNode> childNodes = parentProperty.parentModelNode().directSubModelNodes();
|
||||
bool skip = false;
|
||||
for (const ModelNode &node : childNodes) {
|
||||
if (QmlItemNode(node).isEffectItem()) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
bool nodeCanBeMovedToParentProperty = removeModelNodeFromNodeProperty(parentProperty, modelNode);
|
||||
if (nodeCanBeMovedToParentProperty) {
|
||||
reparentModelNodeToNodeProperty(parentProperty, modelNode);
|
||||
|
||||
@@ -297,7 +297,7 @@ void NavigatorView::dragStarted(QMimeData *mimeData)
|
||||
auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetsPaths[0]);
|
||||
QString assetType = assetTypeAndData.first;
|
||||
if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
|
||||
// We use arbitrary type name because at this time we don't have effect maker
|
||||
// We use arbitrary type name because at this time we don't have effect composer
|
||||
// specific type
|
||||
m_widget->update();
|
||||
} else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
|
||||
|
||||
@@ -299,6 +299,7 @@ void TextEditorView::jumpToModelNode(const ModelNode &modelNode)
|
||||
|
||||
m_widget->window()->windowHandle()->requestActivate();
|
||||
m_widget->textEditor()->widget()->setFocus();
|
||||
m_widget->textEditor()->editorWidget()->updateFoldingHighlight(QTextCursor());
|
||||
}
|
||||
|
||||
void TextEditorView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &/*propertyList*/)
|
||||
|
||||
@@ -625,7 +625,7 @@ void NodeInstanceView::nodeOrderChanged(const NodeListProperty &listProperty)
|
||||
|
||||
void NodeInstanceView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
|
||||
{
|
||||
restartProcess();
|
||||
delayedRestartProcess();
|
||||
}
|
||||
|
||||
void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
|
||||
|
||||
@@ -3108,7 +3108,12 @@ bool NodeMetaInfo::isVariant() const
|
||||
using namespace Storage::Info;
|
||||
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QVariant>());
|
||||
} else {
|
||||
return isValid() && simplifiedTypeName() == "QVariant";
|
||||
if (!isValid())
|
||||
return false;
|
||||
|
||||
const auto type = simplifiedTypeName();
|
||||
|
||||
return type == "QVariant" || type == "var" || type == "variant";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ QVariant BindingProperty::convertToLiteral(const TypeName &typeName, const QStri
|
||||
qreal realValue = testExpression.toDouble(&ok);
|
||||
if (ok)
|
||||
return realValue;
|
||||
} else if ("QVariant" == typeName || "variant" == typeName) {
|
||||
} else if ("QVariant" == typeName || "variant" == typeName || "var" == typeName) {
|
||||
bool ok;
|
||||
qreal realValue = testExpression.toDouble(&ok);
|
||||
if (ok) {
|
||||
|
||||
@@ -182,11 +182,8 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
|
||||
const QString effectName = QFileInfo(effectPath).baseName();
|
||||
Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
|
||||
try {
|
||||
if (!view->model()->hasImport(import, true, true)) {
|
||||
if (!view->model()->hasImport(import, true, true))
|
||||
view->model()->changeImports({import}, {});
|
||||
// Trigger async reset puppet to ensure full transaction is done before reset
|
||||
view->resetPuppet();
|
||||
}
|
||||
} catch (const Exception &) {
|
||||
QTC_ASSERT(false, return);
|
||||
}
|
||||
@@ -209,6 +206,17 @@ void QmlItemNode::placeEffectNode(NodeAbstractProperty &parentProperty, const Qm
|
||||
QmlObjectNode(oldEffect).destroy();
|
||||
}
|
||||
|
||||
if (!isLayerEffect) {
|
||||
// Delete previous effect child if one already exists
|
||||
ModelNode parentNode = parentProperty.parentModelNode();
|
||||
QList<ModelNode> children = parentNode.directSubModelNodes();
|
||||
for (ModelNode &child : children) {
|
||||
QmlItemNode qmlChild(child);
|
||||
if (qmlChild.isEffectItem())
|
||||
qmlChild.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
parentProperty.reparentHere(effectNode);
|
||||
|
||||
if (isLayerEffect)
|
||||
|
||||
@@ -652,60 +652,6 @@ public:
|
||||
return value;
|
||||
}
|
||||
|
||||
QVariant convertToVariant(const QString &astValue, const QString &propertyPrefix, AST::UiQualifiedId *propertyId)
|
||||
{
|
||||
const bool hasQuotes = astValue.trimmed().left(1) == u"\""
|
||||
&& astValue.trimmed().right(1) == u"\"";
|
||||
const QString cleanedValue = fixEscapedUnicodeChar(deEscape(stripQuotes(astValue.trimmed())));
|
||||
const Value *property = nullptr;
|
||||
const ObjectValue *containingObject = nullptr;
|
||||
QString name;
|
||||
if (!lookupProperty(propertyPrefix, propertyId, &property, &containingObject, &name)) {
|
||||
qCInfo(texttomodelMergerDebug) << Q_FUNC_INFO << "Unknown property"
|
||||
<< propertyPrefix + QLatin1Char('.') + toString(propertyId)
|
||||
<< "on line" << propertyId->identifierToken.startLine
|
||||
<< "column" << propertyId->identifierToken.startColumn;
|
||||
return hasQuotes ? QVariant(cleanedValue) : cleverConvert(cleanedValue);
|
||||
}
|
||||
|
||||
if (containingObject)
|
||||
containingObject->lookupMember(name, m_context, &containingObject);
|
||||
|
||||
if (const CppComponentValue * qmlObject = value_cast<CppComponentValue>(containingObject)) {
|
||||
const QString typeName = qmlObject->propertyType(name);
|
||||
if (qmlObject->getEnum(typeName).isValid()) {
|
||||
return QVariant(cleanedValue);
|
||||
} else {
|
||||
int type = QMetaType::type(typeName.toUtf8().constData());
|
||||
QVariant result;
|
||||
if (type)
|
||||
result = PropertyParser::read(type, cleanedValue);
|
||||
if (result.isValid())
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (property->asColorValue())
|
||||
return PropertyParser::read(QVariant::Color, cleanedValue);
|
||||
else if (property->asUrlValue())
|
||||
return PropertyParser::read(QVariant::Url, cleanedValue);
|
||||
|
||||
QVariant value(cleanedValue);
|
||||
if (property->asBooleanValue()) {
|
||||
value.convert(QVariant::Bool);
|
||||
return value;
|
||||
} else if (property->asNumberValue()) {
|
||||
value.convert(QVariant::Double);
|
||||
return value;
|
||||
} else if (property->asStringValue()) {
|
||||
// nothing to do
|
||||
} else { //property alias et al
|
||||
if (!hasQuotes)
|
||||
return cleverConvert(cleanedValue);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
QVariant convertToEnum(AST::Statement *rhs,
|
||||
const NodeMetaInfo &metaInfo,
|
||||
const QString &propertyPrefix,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include "qmldesignercomponents_global.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QSet>
|
||||
@@ -12,7 +14,7 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class DesignerMcuManager
|
||||
class QMLDESIGNERCOMPONENTS_EXPORT DesignerMcuManager
|
||||
{
|
||||
public:
|
||||
struct Version {
|
||||
|
||||
@@ -493,7 +493,8 @@ void DesignModeWidget::setup()
|
||||
|
||||
static bool isMcuDisabledView(const QString viewId)
|
||||
{
|
||||
static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser", "TextureEditor"};
|
||||
static const QStringList mcuDisabledViews = {"Editor3D", "MaterialEditor", "MaterialBrowser",
|
||||
"TextureEditor", "EffectComposer"};
|
||||
return mcuDisabledViews.contains(viewId);
|
||||
}
|
||||
|
||||
|
||||
@@ -358,6 +358,19 @@ Utils::FilePath DocumentManager::currentProjectDirPath()
|
||||
return {};
|
||||
}
|
||||
|
||||
QString DocumentManager::currentProjectName()
|
||||
{
|
||||
QTC_ASSERT(QmlDesignerPlugin::instance(), return {});
|
||||
|
||||
if (!QmlDesignerPlugin::instance()->currentDesignDocument())
|
||||
return {};
|
||||
|
||||
Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName();
|
||||
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::projectForFile(qmlFileName);
|
||||
|
||||
return project ? project->displayName() : "";
|
||||
}
|
||||
|
||||
QStringList DocumentManager::isoIconsQmakeVariableValue(const QString &proPath)
|
||||
{
|
||||
ProjectExplorer::Node *node = ProjectExplorer::ProjectTree::nodeForFile(Utils::FilePath::fromString(proPath));
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
static void addFileToVersionControl(const QString &directoryPath, const QString &newFilePath);
|
||||
static Utils::FilePath currentFilePath();
|
||||
static Utils::FilePath currentProjectDirPath();
|
||||
static QString currentProjectName();
|
||||
|
||||
static QStringList isoIconsQmakeVariableValue(const QString &proPath);
|
||||
static bool setIsoIconsQmakeVariableValue(const QString &proPath, const QStringList &value);
|
||||
|
||||
@@ -14,7 +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_QMLEFFECTCOMPOSER[] = "QmlDesigner::EffectComposer";
|
||||
const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator";
|
||||
const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor";
|
||||
const char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser";
|
||||
@@ -126,7 +126,8 @@ 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_EFFECTCOMPOSER_NODE[] = "effectComposerNode";
|
||||
const char EVENT_EFFECTCOMPOSER_TIME[] = "effectComposerTime";
|
||||
const char EVENT_ITEMLIBRARY_TIME[] = "itemLibrary";
|
||||
const char EVENT_TRANSLATIONVIEW_TIME[] = "translationView";
|
||||
const char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView";
|
||||
@@ -136,7 +137,6 @@ const char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser";
|
||||
const char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary";
|
||||
const char EVENT_INSIGHT_TIME[] = "insight";
|
||||
const char EVENT_MODELEDITOR_TIME[] = "modelEditor";
|
||||
const char EVENT_NEWEFFECTMAKER_TIME[] = "newEffectMaker";
|
||||
const char EVENT_TOOLBAR_MODE_CHANGE[] = "ToolBarTriggerModeChange";
|
||||
const char EVENT_TOOLBAR_PROJECT_SETTINGS[] = "ToolBarTriggerProjectSettings";
|
||||
const char EVENT_TOOLBAR_RUN_PROJECT[] = "ToolBarRunProject";
|
||||
@@ -159,7 +159,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_EFFECT_COMPOSER[] = "QQuickWidgetEffectComposer";
|
||||
const char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
|
||||
const char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor";
|
||||
const char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<file>source/textinputv2.qml</file>
|
||||
<file>source/component.qml</file>
|
||||
<file>source/component3d.qml</file>
|
||||
<file>source/extendedview3D_template.qml</file>
|
||||
<file>images/column-positioner-icon.png</file>
|
||||
<file>images/column-positioner-icon-16px.png</file>
|
||||
<file>images/default-icon.png</file>
|
||||
|
||||
@@ -850,4 +850,19 @@ MetaInfo {
|
||||
Property { name: "loadPrefix"; type: "string"; value: "lightmaps"; }
|
||||
}
|
||||
}
|
||||
|
||||
Type {
|
||||
name: "QtQuick3D.View3D"
|
||||
icon: ":/qtquickplugin/images/default3d16.png"
|
||||
|
||||
ItemLibraryEntry {
|
||||
name: "Extended View3D"
|
||||
category: "Items"
|
||||
libraryIcon: ":/qtquickplugin/images/default3d.png"
|
||||
version: "6.5"
|
||||
requiredImport: "QtQuick3D"
|
||||
QmlSource { source: ":/qtquickplugin/source/extendedview3D_template.qml" }
|
||||
toolTip: qsTr("A 2D surface where a 3D scene can be rendered. Includes ExtendedSceneEnvironment.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick
|
||||
import QtQuick3D
|
||||
import QtQuick3D.Helpers
|
||||
|
||||
View3D {
|
||||
width: 400
|
||||
height: 400
|
||||
environment: sceneEnvironment
|
||||
|
||||
ExtendedSceneEnvironment {
|
||||
id: sceneEnvironment
|
||||
antialiasingMode: SceneEnvironment.MSAA
|
||||
antialiasingQuality: SceneEnvironment.High
|
||||
}
|
||||
|
||||
Node {
|
||||
id: scene
|
||||
|
||||
DirectionalLight {
|
||||
id: directionalLight
|
||||
}
|
||||
|
||||
PerspectiveCamera {
|
||||
id: sceneCamera
|
||||
z: 350
|
||||
}
|
||||
|
||||
Model {
|
||||
id: cubeModel
|
||||
eulerRotation.x: 30
|
||||
eulerRotation.y: 45
|
||||
|
||||
source: "#Cube"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,9 +74,9 @@ const QStringList &Asset::supportedTexture3DSuffixes()
|
||||
return retList;
|
||||
}
|
||||
|
||||
const QStringList &Asset::supportedEffectMakerSuffixes()
|
||||
const QStringList &Asset::supportedEffectComposerSuffixes()
|
||||
{
|
||||
// These are file types only supported by Effect Maker
|
||||
// These are file types only supported by Effect Composer
|
||||
static QStringList retList {"*.qep"};
|
||||
return retList;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ const QSet<QString> &Asset::supportedSuffixes()
|
||||
insertSuffixes(supportedAudioSuffixes());
|
||||
insertSuffixes(supportedVideoSuffixes());
|
||||
insertSuffixes(supportedTexture3DSuffixes());
|
||||
insertSuffixes(supportedEffectMakerSuffixes());
|
||||
insertSuffixes(supportedEffectComposerSuffixes());
|
||||
}
|
||||
return allSuffixes;
|
||||
}
|
||||
@@ -204,7 +204,7 @@ void Asset::resolveType()
|
||||
m_type = Asset::Type::Video;
|
||||
else if (supportedTexture3DSuffixes().contains(m_suffix))
|
||||
m_type = Asset::Type::Texture3D;
|
||||
else if (supportedEffectMakerSuffixes().contains(m_suffix))
|
||||
else if (supportedEffectComposerSuffixes().contains(m_suffix))
|
||||
m_type = Asset::Type::Effect;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
static const QStringList &supportedAudioSuffixes();
|
||||
static const QStringList &supportedVideoSuffixes();
|
||||
static const QStringList &supportedTexture3DSuffixes();
|
||||
static const QStringList &supportedEffectMakerSuffixes();
|
||||
static const QStringList &supportedEffectComposerSuffixes();
|
||||
static const QSet<QString> &supportedSuffixes();
|
||||
static bool isSupported(const QString &path);
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
#include "utils/designersettings.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/appinfo.h>
|
||||
#include <utils/uniqueobjectptr.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
|
||||
class QmlDesignerBasePlugin::Data
|
||||
{
|
||||
public:
|
||||
@@ -29,6 +29,9 @@ public:
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
const char experimentalFeatures[] = "QML/Designer/UseExperimentalFeatures";
|
||||
|
||||
QmlDesignerBasePlugin *global;
|
||||
}
|
||||
|
||||
@@ -57,6 +60,19 @@ StudioConfigSettingsPage *QmlDesignerBasePlugin::studioConfigSettingsPage()
|
||||
return global->d->studioConfigSettingsPage.get();
|
||||
}
|
||||
|
||||
bool QmlDesignerBasePlugin::experimentalFeaturesEnabled()
|
||||
{
|
||||
return Core::ICore::settings()->value(experimentalFeaturesSettingsKey(), false).toBool();
|
||||
}
|
||||
|
||||
QByteArray QmlDesignerBasePlugin::experimentalFeaturesSettingsKey()
|
||||
{
|
||||
QString version = Utils::appInfo().displayVersion;
|
||||
version.remove('.');
|
||||
|
||||
return QByteArray(experimentalFeatures) + version.toLatin1();
|
||||
}
|
||||
|
||||
bool QmlDesignerBasePlugin::initialize(const QStringList &, QString *)
|
||||
{
|
||||
d = std::make_unique<Data>();
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
static QStyle *style();
|
||||
static class StudioConfigSettingsPage *studioConfigSettingsPage();
|
||||
|
||||
static bool experimentalFeaturesEnabled();
|
||||
static QByteArray experimentalFeaturesSettingsKey();
|
||||
|
||||
private:
|
||||
bool initialize(const QStringList &arguments, QString *errorMessage) override;
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace QmlDesigner {
|
||||
|
||||
namespace {
|
||||
|
||||
const char experimentalFeatures[] = "QML/Designer/UseExperimentalFeatures44";
|
||||
|
||||
bool hideBuildMenuSetting()
|
||||
{
|
||||
return Core::ICore::settings()
|
||||
@@ -57,6 +59,11 @@ bool hideToolsMenuSetting()
|
||||
return Core::ICore::settings()->value(Core::Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
|
||||
}
|
||||
|
||||
bool showExperimentalFeatures()
|
||||
{
|
||||
return Core::ICore::settings()->value(experimentalFeatures, false).toBool();
|
||||
}
|
||||
|
||||
void setSettingIfDifferent(const Key &key, bool value, bool &dirty)
|
||||
{
|
||||
QtcSettings *s = Core::ICore::settings();
|
||||
@@ -69,12 +76,11 @@ void setSettingIfDifferent(const Key &key, bool value, bool &dirty)
|
||||
} // namespace
|
||||
|
||||
StudioSettingsPage::StudioSettingsPage()
|
||||
: m_buildCheckBox(new QCheckBox(tr("Build")))
|
||||
, m_debugCheckBox(new QCheckBox(tr("Debug")))
|
||||
, m_analyzeCheckBox(new QCheckBox(tr("Analyze")))
|
||||
, m_toolsCheckBox(new QCheckBox(tr("Tools")))
|
||||
, m_pathChooserExamples(new Utils::PathChooser())
|
||||
, m_pathChooserBundles(new Utils::PathChooser())
|
||||
: m_buildCheckBox(new QCheckBox(tr("Build"))), m_debugCheckBox(new QCheckBox(tr("Debug"))),
|
||||
m_analyzeCheckBox(new QCheckBox(tr("Analyze"))), m_toolsCheckBox(new QCheckBox(tr("Tools"))),
|
||||
m_pathChooserExamples(new Utils::PathChooser()),
|
||||
m_pathChooserBundles(new Utils::PathChooser()),
|
||||
m_experimentalCheckBox(new QCheckBox(tr("Enable Experimental Features")))
|
||||
{
|
||||
const QString toolTip = tr(
|
||||
"Hide top-level menus with advanced functionality to simplify the UI. <b>Build</b> is "
|
||||
@@ -109,6 +115,7 @@ StudioSettingsPage::StudioSettingsPage()
|
||||
m_debugCheckBox->setChecked(hideDebugMenuSetting());
|
||||
m_analyzeCheckBox->setChecked(hideAnalyzeMenuSetting());
|
||||
m_toolsCheckBox->setChecked(hideToolsMenuSetting());
|
||||
m_experimentalCheckBox->setChecked(showExperimentalFeatures());
|
||||
|
||||
// Examples path setting
|
||||
auto examplesGroupBox = new QGroupBox(tr("Examples"));
|
||||
@@ -148,6 +155,18 @@ StudioSettingsPage::StudioSettingsPage()
|
||||
bundlesLayout->addWidget(m_pathChooserBundles);
|
||||
bundlesLayout->addWidget(bundlesResetButton);
|
||||
|
||||
auto experimentalGroupBox = new QGroupBox(tr("Experimental Features"));
|
||||
boxLayout->addWidget(experimentalGroupBox);
|
||||
|
||||
auto experimentalLayout = new QHBoxLayout(this);
|
||||
experimentalGroupBox->setLayout(experimentalLayout);
|
||||
|
||||
experimentalLayout->addWidget(m_experimentalCheckBox);
|
||||
m_experimentalCheckBox->setToolTip(
|
||||
tr("This option enables experimental features in Qt Design Studio. "
|
||||
"Please provide feedback and bug reports at: %1")
|
||||
.arg("https://bugreports.qt.io/projects/QDS"));
|
||||
|
||||
boxLayout->addSpacerItem(
|
||||
new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||
}
|
||||
@@ -172,6 +191,8 @@ void StudioSettingsPage::apply()
|
||||
m_toolsCheckBox->isChecked(),
|
||||
dirty);
|
||||
|
||||
setSettingIfDifferent(experimentalFeatures, m_experimentalCheckBox->isChecked(), dirty);
|
||||
|
||||
if (dirty) {
|
||||
Core::ICore::askForRestart(
|
||||
tr("The menu visibility change will take effect after restart."));
|
||||
|
||||
@@ -32,6 +32,7 @@ private:
|
||||
QCheckBox *m_toolsCheckBox;
|
||||
Utils::PathChooser *m_pathChooserExamples;
|
||||
Utils::PathChooser *m_pathChooserBundles;
|
||||
QCheckBox *m_experimentalCheckBox;
|
||||
};
|
||||
|
||||
class QMLDESIGNERBASE_EXPORT StudioConfigSettingsPage : public QObject, Core::IOptionsPage
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.9
|
||||
import welcome 1.0
|
||||
import StudioFonts 1.0
|
||||
|
||||
Image {
|
||||
id: account_icon
|
||||
|
||||
source: "images/" + (mouseArea.containsMouse ? "icon_hover.png" : "icon_default.png")
|
||||
|
||||
Text {
|
||||
id: account
|
||||
color: mouseArea.containsMouse ? Constants.textHoverColor
|
||||
: Constants.textDefaultColor
|
||||
text: qsTr("Account")
|
||||
anchors.top: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.family: StudioFonts.titilliumWeb_regular
|
||||
font.pixelSize: 16
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
anchors.margins: -25
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: Qt.openUrlExternally("https://login.qt.io/login/")
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Templates 2.15 as Controls
|
||||
import welcome 1.0
|
||||
|
||||
Controls.ScrollBar {
|
||||
id: scrollBar
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: active ? 1 : 2
|
||||
visible: orientation === Qt.Horizontal ? contentWidth > width : contentHeight > height
|
||||
minimumSize: orientation === Qt.Horizontal ? height / width : width / height
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: 13
|
||||
implicitHeight: 13
|
||||
color: active ? Constants.textHoverColor : Constants.textDefaultColor
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 16
|
||||
implicitHeight: 16
|
||||
color: "#3b3c3d"
|
||||
visible: active
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick.Templates 2.15 as Controls
|
||||
|
||||
Controls.ScrollView {
|
||||
id: control
|
||||
|
||||
Controls.ScrollBar.vertical: CustomScrollBar {
|
||||
parent: control
|
||||
x: control.mirrored ? 0 : control.width - width
|
||||
y: control.topPadding
|
||||
height: control.availableHeight
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
projectName: "ClusterTutorial"
|
||||
qmlFileName: "ClusterTutorial.qml"
|
||||
thumbnail: "images/tutorialclusterdemo_thumbnail.png"
|
||||
displayName: "Cluster Tutorial"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "CoffeeMachine"
|
||||
qmlFileName: "CoffeeMachine.qml"
|
||||
thumbnail: "images/coffeemachinedemo_thumbnail.png"
|
||||
displayName: "Coffee Machine"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "SideMenu"
|
||||
qmlFileName: "SideMenu.qml"
|
||||
thumbnail: "images/sidemenu_demo.png"
|
||||
displayName: "Side Menu"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "WebinarDemo"
|
||||
qmlFileName: "DesignStudioWebinar.qml"
|
||||
thumbnail: "images/webinardemo_thumbnail.png"
|
||||
displayName: "Webinar Demo"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "EBikeDesign"
|
||||
qmlFileName: "EBikeDesign.qml"
|
||||
thumbnail: "images/ebike_demo_thumbnail.png"
|
||||
displayName: "E-Bike Design"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "ProgressBar"
|
||||
qmlFileName: "ProgressBar.ui.qml"
|
||||
thumbnail: "images/progressbar_demo.png"
|
||||
displayName: "Progress Bar"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "washingMachineUI"
|
||||
qmlFileName: "washingMachineUI.qml"
|
||||
thumbnail: "images/washingmachinedemo_thumbnail.png"
|
||||
displayName: "Washing Machine"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "SimpleKeyboard"
|
||||
qmlFileName: "SimpleKeyboard.qml"
|
||||
thumbnail: "images/virtualkeyboard_thumbnail.png"
|
||||
displayName: "Virtual Keyboard"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "highendivisystem"
|
||||
qmlFileName: "Screen01.ui.qml"
|
||||
thumbnail: "images/highendivi_thumbnail.png"
|
||||
displayName: "Highend IVI System"
|
||||
url: "https://download.qt.io/learning/examples/qtdesignstudio/highendivisystem.zip"
|
||||
showDownload: true
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "digitalcluster"
|
||||
qmlFileName: "Screen01.ui.qml"
|
||||
thumbnail: "images/digital_cluster_thumbnail.png"
|
||||
displayName: "Digital Cluster"
|
||||
url: "https://download.qt.io/learning/examples/qtdesignstudio/digitalcluster.zip"
|
||||
showDownload: true
|
||||
}
|
||||
|
||||
ListElement {
|
||||
projectName: "effectdemo"
|
||||
qmlFileName: "Screen01.ui.qml"
|
||||
thumbnail: "images/effectdemo_thumbnail.png"
|
||||
displayName: "Effect Demo"
|
||||
url: "https://download.qt.io/learning/examples/qtdesignstudio/effectdemo.zip"
|
||||
showDownload: true
|
||||
}
|
||||
|
||||
|
||||
ListElement {
|
||||
projectName: "cppdemoproject"
|
||||
explicitQmlproject: "qml/qdsproject.qmlproject"
|
||||
qmlFileName: "Screen01.ui.qml"
|
||||
thumbnail: "images/cppdemo_thumbnail.png"
|
||||
displayName: "C++ Demo Project"
|
||||
url: "https://download.qt.io/learning/examples/qtdesignstudio/cppdemoproject.zip"
|
||||
showDownload: true
|
||||
}
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Timeline 1.0
|
||||
import welcome 1.0
|
||||
import StudioFonts 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
visible: true
|
||||
width: 270
|
||||
height: 175
|
||||
property alias imageSource: image.source
|
||||
property alias labelText: label.text
|
||||
|
||||
property alias downloadIcon: downloadCloud.visible
|
||||
|
||||
signal clicked()
|
||||
|
||||
onVisibleChanged: {
|
||||
animateOpacity.start()
|
||||
animateScale.start()
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: animateOpacity
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1.0
|
||||
duration: 400
|
||||
}
|
||||
NumberAnimation {
|
||||
id: animateScale
|
||||
property: "scale"
|
||||
from: 0
|
||||
to: 1.0
|
||||
duration: 400
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rectangle
|
||||
x: 0
|
||||
y: 0
|
||||
width: 270
|
||||
height: 146
|
||||
|
||||
MouseArea {
|
||||
x: 17
|
||||
y: 12
|
||||
height: 125
|
||||
anchors.bottomMargin: -label.height
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onHoveredChanged: {
|
||||
if (saturationEffect.desaturation === 1)
|
||||
saturationEffect.desaturation = 0
|
||||
if (saturationEffect.desaturation === 0)
|
||||
saturationEffect.desaturation = 1
|
||||
if (saturationEffect.desaturation === 0)
|
||||
rectangle.color = "#262728"
|
||||
if (saturationEffect.desaturation === 1)
|
||||
rectangle.color = "#404244"
|
||||
if (saturationEffect.desaturation === 0)
|
||||
label.color = "#686868"
|
||||
if (saturationEffect.desaturation === 1)
|
||||
label.color = Constants.textDefaultColor
|
||||
}
|
||||
|
||||
onExited: {
|
||||
saturationEffect.desaturation = 1
|
||||
rectangle.color = "#262728"
|
||||
label.color = "#686868"
|
||||
}
|
||||
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
SaturationEffect {
|
||||
id: saturationEffect
|
||||
x: 15
|
||||
y: 10
|
||||
width: 240
|
||||
height: 125
|
||||
desaturation: 0
|
||||
antialiasing: true
|
||||
Behavior on desaturation {
|
||||
PropertyAnimation {
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
width: 240
|
||||
height: 125
|
||||
mipmap: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
||||
Timeline {
|
||||
id: animation
|
||||
startFrame: 0
|
||||
enabled: true
|
||||
endFrame: 1000
|
||||
|
||||
KeyframeGroup {
|
||||
target: saturationEffect
|
||||
property: "desaturation"
|
||||
|
||||
Keyframe {
|
||||
frame: 0
|
||||
value: 1
|
||||
}
|
||||
|
||||
Keyframe {
|
||||
frame: 1000
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
|
||||
KeyframeGroup {
|
||||
target: label
|
||||
property: "color"
|
||||
|
||||
Keyframe {
|
||||
value: "#686868"
|
||||
frame: 0
|
||||
}
|
||||
|
||||
Keyframe {
|
||||
value: Constants.textDefaultColor
|
||||
frame: 1000
|
||||
}
|
||||
}
|
||||
|
||||
KeyframeGroup {
|
||||
target: rectangle
|
||||
property: "color"
|
||||
|
||||
Keyframe {
|
||||
value: "#262728"
|
||||
frame: 0
|
||||
}
|
||||
|
||||
Keyframe {
|
||||
value: "#404244"
|
||||
frame: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAnimation {
|
||||
id: propertyAnimation
|
||||
target: animation
|
||||
property: "currentFrame"
|
||||
running: false
|
||||
duration: 1000
|
||||
to: animation.endFrame
|
||||
from: animation.startFrame
|
||||
loops: 1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
x: 1
|
||||
y: 145
|
||||
color: "#686868"
|
||||
|
||||
renderType: Text.NativeRendering
|
||||
font.pixelSize: 14
|
||||
font.family: StudioFonts.titilliumWeb_regular
|
||||
}
|
||||
|
||||
Image {
|
||||
id: downloadCloud
|
||||
x: 210
|
||||
y: 118
|
||||
width: 60
|
||||
height: 60
|
||||
source: "images/downloadCloud.svg"
|
||||
sourceSize.height: 60
|
||||
sourceSize.width: 60
|
||||
fillMode: Image.PreserveAspectFit
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;formeditorZoom:1.3300000429153442}D{i:8}
|
||||
}
|
||||
##^##*/
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Templates 2.3
|
||||
import welcome 1.0
|
||||
import StudioFonts 1.0
|
||||
|
||||
Button {
|
||||
id: button
|
||||
|
||||
property color hoverColor: Constants.textHoverColor
|
||||
property color defaultColor: Constants.textDefaultColor
|
||||
property color checkedColor: Constants.textDefaultColor
|
||||
|
||||
text: "test"
|
||||
|
||||
implicitWidth: background.width
|
||||
implicitHeight: background.height
|
||||
|
||||
contentItem: Text {
|
||||
id: textButton
|
||||
text: button.text
|
||||
|
||||
color: checked ? button.checkedColor :
|
||||
button.hovered ? button.hoverColor :
|
||||
button.defaultColor
|
||||
font.family: StudioFonts.titilliumWeb_regular
|
||||
renderType: Text.NativeRendering
|
||||
font.pixelSize: 18
|
||||
}
|
||||
|
||||
background: Item {
|
||||
width: textButton.implicitWidth
|
||||
height: textButton.implicitHeight
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
MyButton {
|
||||
checkable: true
|
||||
autoExclusive: true
|
||||
defaultColor: "#686868"
|
||||
hoverColor: "#79797C"
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.9
|
||||
import welcome 1.0
|
||||
|
||||
GridView {
|
||||
id: root
|
||||
cellHeight: 180
|
||||
cellWidth: 285
|
||||
|
||||
clip: true
|
||||
|
||||
signal itemSelected(int index, variant item)
|
||||
|
||||
delegate: HoverOverDesaturate {
|
||||
id: hoverOverDesaturate
|
||||
imageSource: typeof(thumbnail) === "undefined" ? previewUrl : thumbnail
|
||||
labelText: displayName
|
||||
downloadIcon: typeof(showDownload) === "undefined" ? false : showDownload;
|
||||
onClicked: root.itemSelected(index, root.model.get(index))
|
||||
|
||||
SequentialAnimation {
|
||||
id: animation
|
||||
running: hoverOverDesaturate.visible
|
||||
|
||||
PropertyAction {
|
||||
target: hoverOverDesaturate
|
||||
property: "scale"
|
||||
value: 0.0
|
||||
}
|
||||
PauseAnimation {
|
||||
duration: model.index > 0 ? 100 * model.index : 0
|
||||
}
|
||||
NumberAnimation {
|
||||
target: hoverOverDesaturate
|
||||
property: "scale"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: 200
|
||||
easing.type: Easing.InOutExpo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real desaturation: 1.0
|
||||
|
||||
Rectangle {
|
||||
z: 10
|
||||
anchors.fill: parent
|
||||
color: "#2d2e30"
|
||||
anchors.margins: -16
|
||||
|
||||
opacity: root.desaturation * 0.6
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
displayName: "The Designer Tool Developers Love"
|
||||
thumbnail: "images/webinar1.png"
|
||||
url: "https://youtu.be/gU_tDbebAzM"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "From Photoshop to Prototype"
|
||||
thumbnail: "images/webinar2.png"
|
||||
url: "https://youtu.be/ZzbucmQPU44"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt for Designers and Developers"
|
||||
thumbnail: "images/designer_and_developers.png"
|
||||
url: "https://www.youtube.com/watch?v=EgjCvZWEPWk"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "QTWS - Designer and Developer Workflow"
|
||||
thumbnail: "images/qtws_video_thumbnail.png"
|
||||
url: "https://www.youtube.com/watch?v=4ug0EUdS2RM"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "QTWS - Turn UI designs into working prototypes"
|
||||
thumbnail: "images/bridging_the_gap.png"
|
||||
url: "https://www.youtube.com/watch?v=qQM2oEWRBOw&feature=emb_logo"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "What's New in Design Studio 1.5"
|
||||
thumbnail: "images/what_is_new_15.png"
|
||||
url: "https://www.youtube.com/watch?v=e-HAZrisi5o"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: UI Navigation"
|
||||
thumbnail: "images/Qt_QT_nav.png"
|
||||
url: "https://youtu.be/RfEYO-5Mw6s"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: Text Element"
|
||||
thumbnail: "images/Qt_QT_textElement.png"
|
||||
url: "https://youtu.be/yOUdg1o2KJM"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: Animated Image"
|
||||
thumbnail: "images/Qt_QT_animatedImage.png"
|
||||
url: "https://youtu.be/DVWd_xMMgvg"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: Slider Control"
|
||||
thumbnail: "images/Qt_QT_sliderControl.png"
|
||||
url: "https://youtu.be/Ed8WS03C-Vk"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: Bindings"
|
||||
thumbnail: "images/Qt_QT_bindings.png"
|
||||
url: "https://youtu.be/UfvA04CIXv0"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Qt Design Studio QuickTip: Interactive 3D"
|
||||
thumbnail: "images/Qt_QT_interactive3d.png"
|
||||
url: "https://youtu.be/w1yhDl93YI0"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Sketch Bridge Tutorial - Part 1"
|
||||
thumbnail: "images/sketchTutorial_1.png"
|
||||
url: "https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-1"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Sketch Bridge Tutorial - Part 2"
|
||||
thumbnail: "images/sketchTutorial_2.png"
|
||||
url: "https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-2"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Create New Project"
|
||||
thumbnail: "images/gettingStarted_newProject.png"
|
||||
url: "https://youtu.be/9ihYeC0YJ0M"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Using Qt Quick 3D Components"
|
||||
thumbnail: "images/gettingStarted_3dComponents.png"
|
||||
url: "https://youtu.be/u3kZJjlk3CY"
|
||||
}
|
||||
|
||||
ListElement {
|
||||
displayName: "Using Custom Shaders, Materials, and Effects"
|
||||
thumbnail: "images/gettingStarted_shaders.png"
|
||||
url: "https://youtu.be/bMXeeQw6BYs"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 90 KiB |