Import QQEM effects via drag or add button

Be able to add effects using file system drag&drop or using the add resource button
(cherry picked from commit 02f7c9c3eb)

Task-number: QTBUG-100626
Change-Id: I33c3ebe29797325a2ed1819bd867e97ae3f8b61c
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Tomi Korpipaa
2022-10-03 14:06:29 +03:00
committed by Tim Jenssen
parent 35d2c36482
commit dca06351fd
18 changed files with 250 additions and 41 deletions

View File

@@ -162,6 +162,7 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
readonly property string suffix: fileName.substr(-4)
readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
readonly property bool isEffect: suffix === ".qep"
property bool currFileSelected: false
MouseArea {
@@ -180,7 +181,7 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
allowTooltip = true
}
onPositionChanged: tooltipBackend.reposition()
onPressed: (mouse)=> {
onPressed: (mouse) => {
forceActiveFocus()
allowTooltip = false
tooltipBackend.hideTooltip()
@@ -212,7 +213,7 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
}
}
onReleased: (mouse)=> {
onReleased: (mouse) => {
allowTooltip = true
if (mouse.button === Qt.LeftButton) {
if (!(mouse.modifiers & Qt.ControlModifier))
@@ -222,6 +223,14 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
}
}
onDoubleClicked: (mouse) => {
forceActiveFocus()
allowTooltip = false
tooltipBackend.hideTooltip()
if (mouse.button === Qt.LeftButton && isEffect)
rootView.openEffectMaker(filePath)
}
ToolTip {
visible: !isFont && mouseArea.containsMouse && !contextMenu.visible
text: filePath

View File

@@ -0,0 +1,40 @@
{
"version": 1,
"supportedProjectTypes": [ ],
"id": "J.QEP",
"category": "U.QEP",
"trDescription": "Creates an Effect Maker file.",
"trDisplayName": "Effect File (Effect Maker)",
"trDisplayCategory": "Effects",
"iconText": "qep",
"platformIndependent": true,
"enabled": true,
"options": { "key": "DefaultSuffix", "value": "qep" },
"pages" :
[
{
"trDisplayName": "Location",
"trShortTitle": "Location",
"typeId": "File"
},
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
],
"generators" :
[
{
"typeId": "File",
"data":
{
"source": "file.qep",
"target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": false
}
}
]
}

View File

@@ -230,7 +230,7 @@ QObject *AssetsLibraryModel::rootDir() const
bool AssetsLibraryModel::isEmpty() const
{
return m_isEmpty;
};
}
void AssetsLibraryModel::setIsEmpty(bool empty)
{
@@ -238,7 +238,7 @@ void AssetsLibraryModel::setIsEmpty(bool empty)
m_isEmpty = empty;
emit isEmptyChanged();
}
};
}
QVariant AssetsLibraryModel::data(const QModelIndex &index, int role) const
{
@@ -398,6 +398,13 @@ const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
return retList;
}
const QStringList &AssetsLibraryModel::supportedEffectMakerSuffixes()
{
// These are file types only supported by Effect Maker
static QStringList retList {"*.qep"};
return retList;
}
const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
{
static QSet<QString> allSuffixes;
@@ -412,6 +419,7 @@ const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedVideoSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
insertSuffixes(supportedEffectMakerSuffixes());
}
return allSuffixes;
}

View File

@@ -66,6 +66,7 @@ public:
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
static const QStringList &supportedEffectMakerSuffixes();
static const QSet<QString> &supportedSuffixes();
const QSet<QString> &previewableSuffixes() const;

View File

@@ -43,11 +43,18 @@
#include <utils/stylehelper.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include "utils/environment.h"
#include "utils/filepath.h"
#include "utils/qtcprocess.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <QApplication>
#include <QDrag>
#include <QFileDialog>
@@ -64,6 +71,9 @@
#include <QQmlContext>
#include <QQuickItem>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
namespace QmlDesigner {
static QString propertyEditorResourcesPath()
@@ -141,11 +151,17 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
// If project directory contents change, or one of the asset files is modified, we must
// reconstruct the model to update the icons
connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) {
connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged,
[this](const QString &changedDirPath) {
Q_UNUSED(changedDirPath)
m_assetCompressionTimer.start();
});
connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::fileChanged,
[](const QString &changeFilePath) {
QmlDesignerPlugin::instance()->emitAssetChanged(changeFilePath);
});
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
@@ -245,6 +261,48 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
return suffixes;
}
void AssetsLibraryWidget::openEffectMaker(const QString &filePath)
{
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (!target) {
qWarning() << __FUNCTION__ << "No project open";
return;
}
Utils::FilePath projectPath = target->project()->projectDirectory();
QString effectName = QFileInfo(filePath).baseName();
QString effectResDir = "asset_imports/Effects/" + effectName;
Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir);
if (!effectResPath.exists())
QDir(projectPath.toString()).mkpath(effectResDir);
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
auto effectMakerPath = baseQtVersion->binPath().pathAppended("QQEffectMaker").withExecutableSuffix();
if (!effectMakerPath.exists()) {
qWarning() << __FUNCTION__ << "Cannot find EffectMaker app";
return;
}
Utils::FilePath effectPath = Utils::FilePath::fromString(filePath);
QString effectContents = QString::fromUtf8(effectPath.fileContents());
QStringList arguments;
arguments << filePath;
if (effectContents.isEmpty())
arguments << "--create";
arguments << "--exportpath" << effectResPath.toString();
Utils::Environment env = Utils::Environment::systemEnvironment();
if (env.osType() == Utils::OsTypeMac)
env.appendOrSet("QSG_RHI_BACKEND", "metal");
m_qqemProcess.reset(new Utils::QtcProcess);
m_qqemProcess->setEnvironment(env);
m_qqemProcess->setCommand({ effectMakerPath, arguments });
m_qqemProcess->start();
}
}
void AssetsLibraryWidget::setModel(Model *model)
{
m_model = model;
@@ -316,6 +374,9 @@ QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QStrin
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) {
// Data: Image format (suffix)
return {Constants::MIME_TYPE_ASSET_TEXTURE3D, suffix.toUtf8()};
} else if (AssetsLibraryModel::supportedEffectMakerSuffixes().contains(suffix)) {
// Data: Effect Maker format (suffix)
return {Constants::MIME_TYPE_ASSET_EFFECT, suffix.toUtf8()};
}
}
return {};

View File

@@ -42,7 +42,10 @@ QT_BEGIN_NAMESPACE
class QShortcut;
QT_END_NAMESPACE
namespace Utils { class FileSystemWatcher; }
namespace Utils {
class FileSystemWatcher;
class QtcProcess;
}
namespace QmlDesigner {
@@ -83,6 +86,7 @@ public:
const QList<QUrl> &complexFilePaths,
const QString &targetDirPath = {});
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);
Q_INVOKABLE void openEffectMaker(const QString &filePath);
signals:
void itemActivated(const QString &itemName);
@@ -114,6 +118,8 @@ private:
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
std::unique_ptr<Utils::QtcProcess> m_qqemProcess;
};
} // namespace QmlDesigner

View File

@@ -233,8 +233,8 @@ const char addShadersDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResource
const char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "3D Assets");
const char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
"Qt 3D Studio Presentations");
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Add Custom Effect");
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
"Effect Maker Files");
} //ComponentCoreConstants

View File

@@ -1614,10 +1614,23 @@ void updateImported3DAsset(const SelectionContext &selectionContext)
if (selectionContext.view()) {
selectionContext.view()->emitCustomNotification(
"UpdateImported3DAsset", {selectionContext.currentSingleSelectedNode()});
}
}
Utils::FilePath getEffectsDirectory()
{
QString defaultDir = "asset_imports/Effects";
Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
Utils::FilePath effectsPath = projectPath.pathAppended(defaultDir);
if (!effectsPath.exists()) {
QDir dir(projectPath.toString());
dir.mkpath(defaultDir);
}
return effectsPath;
}
} // namespace ModelNodeOperations
} //QmlDesigner

View File

@@ -27,6 +27,8 @@
#include "selectioncontext.h"
#include <utils/fileutils.h>
namespace QmlDesigner {
enum class AddFilesResult { Succeeded, Failed, Cancelled };
@@ -77,7 +79,7 @@ void addItemToStackedContainer(const SelectionContext &selectionContext);
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void addTabBarToStackedContainer(const SelectionContext &selectionContext);
AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
@@ -98,6 +100,8 @@ void addMouseAreaFill(const SelectionContext &selectionContext);
void openSignalDialog(const SelectionContext &selectionContext);
void updateImported3DAsset(const SelectionContext &selectionContext);
QMLDESIGNERCORE_EXPORT Utils::FilePath getEffectsDirectory();
// ModelNodePreviewImageOperations
QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode);

View File

@@ -242,7 +242,8 @@ void AbstractFormEditorTool::dragEnterEvent(const QList<QGraphicsItem*> &itemLis
for (const QString &assetPath : assetPaths) {
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == Constants::MIME_TYPE_ASSET_IMAGE
|| assetType == Constants::MIME_TYPE_ASSET_FONT) {
|| assetType == Constants::MIME_TYPE_ASSET_FONT
|| assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
hasValidAssets = true;
break;
}

View File

@@ -240,38 +240,64 @@ static bool hasItemLibraryInfo(const QMimeData *mimeData)
return mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
}
void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (canBeDropped(event->mimeData())) {
event->accept();
end(generateUseSnapping(event->modifiers()));
QString effectPath;
const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data(Constants::MIME_TYPE_ASSETS)).split(',');
for (auto &path : assetPaths) {
auto assetType = AssetsLibraryWidget::getAssetTypeAndData(path).first;
if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
effectPath = path;
break;
}
}
bool resetPuppet = false;
for (auto &node : m_dragNodes) {
if (node.isValid()) {
if ((node.instanceParentItem().isValid()
&& node.instanceParent().modelNode().metaInfo().isLayoutable())
|| node.isFlowItem()) {
node.removeProperty("x");
node.removeProperty("y");
resetPuppet = true;
if (!effectPath.isEmpty()) {
FormEditorItem *targetContainerFormEditorItem = targetContainerOrRootItem(itemList);
if (targetContainerFormEditorItem) {
QmlItemNode parentQmlItemNode = targetContainerFormEditorItem->qmlItemNode();
QString effectName = QFileInfo(effectPath).baseName();
QmlItemNode effectNode = QmlItemNode::createQmlItemNodeForEffect(view(), parentQmlItemNode, effectName);
view()->setSelectedModelNodes({effectNode});
view()->resetPuppet();
commitTransaction();
}
} else {
for (QmlItemNode &node : m_dragNodes) {
if (node.isValid()) {
if ((node.instanceParentItem().isValid()
&& node.instanceParent().modelNode().metaInfo().isLayoutable())
|| node.isFlowItem()) {
node.removeProperty("x");
node.removeProperty("y");
resetPuppet = true;
}
}
}
}
if (resetPuppet)
view()->resetPuppet(); // Otherwise the layout might not reposition the items
if (resetPuppet)
view()->resetPuppet(); // Otherwise the layout might not reposition the items
commitTransaction();
commitTransaction();
if (!m_dragNodes.isEmpty()) {
QList<ModelNode> nodeList;
for (auto &node : std::as_const(m_dragNodes)) {
if (node.isValid())
nodeList.append(node);
if (!m_dragNodes.isEmpty()) {
QList<ModelNode> nodeList;
for (auto &node : std::as_const(m_dragNodes)) {
if (node.isValid())
nodeList.append(node);
}
view()->setSelectedModelNodes(nodeList);
}
view()->setSelectedModelNodes(nodeList);
m_dragNodes.clear();
}
m_dragNodes.clear();
view()->changeToSelectionTool();
}
@@ -347,10 +373,17 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo
void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (!m_blockMove && !m_isAborted && canBeDropped(event->mimeData())) {
FormEditorItem *targetContainerItem = targetContainerOrRootItem(itemList);
const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data(Constants::MIME_TYPE_ASSETS)).split(',');
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPaths[0]).first;
if (!m_blockMove
&& !m_isAborted
&& canBeDropped(event->mimeData())
&& assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
event->accept();
if (!m_dragNodes.isEmpty()) {
FormEditorItem *targetContainerItem = targetContainerOrRootItem(itemList);
if (targetContainerItem) {
move(event->scenePos(), itemList);
} else {
@@ -364,7 +397,7 @@ void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSc
} else {
createDragNodes(event->mimeData(), event->scenePos(), itemList);
}
} else {
} else if (assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
event->ignore();
}
}

View File

@@ -81,7 +81,9 @@ public:
const QPointF &position,
NodeAbstractProperty parentproperty,
bool executeInTransaction = true);
static QmlItemNode createQmlItemNodeForEffect(AbstractView *view,
const QmlItemNode &parentNode,
const QString &effectName);
QList<QmlItemNode> children() const;
QList<QmlObjectNode> resources() const;
QList<QmlObjectNode> allDirectSubNodes() const;

View File

@@ -181,6 +181,33 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
return newQmlItemNode;
}
QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
const QmlItemNode &parentNode,
const QString &effectName)
{
QmlItemNode newQmlItemNode;
QmlDesigner::Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
try {
if (!view->model()->hasImport(import, true, true))
view->model()->changeImports({import}, {});
} catch (const Exception &e) {
QTC_ASSERT(false, return QmlItemNode());
}
TypeName type(effectName.toUtf8());
newQmlItemNode = QmlItemNode(view->createModelNode(type, 1, 0));
NodeAbstractProperty parentProperty = parentNode.defaultNodeAbstractProperty();
parentProperty.reparentHere(newQmlItemNode);
newQmlItemNode.modelNode().bindingProperty("source").setExpression("parent");
newQmlItemNode.modelNode().bindingProperty("anchors.fill").setExpression("parent");
QTC_ASSERT(newQmlItemNode.isValid(), return QmlItemNode());
return newQmlItemNode;
}
bool QmlItemNode::isValid() const
{
return isValidQmlItemNode(modelNode());

View File

@@ -530,10 +530,6 @@ public:
qDebug() << astTypeNode->name.toString() << typeName;
qDebug() << metaInfo.isValid() << metaInfo.typeName();
qDebug() << metaInfo.directSuperClass().typeName();
if (!metaInfo.isFileComponent() && m_model == m_model->metaInfoProxyModel()
&& metaInfo.isValid())
throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "test", "test");
}
typeName = QString::fromUtf8(metaInfo.typeName());
@@ -1961,7 +1957,7 @@ void ModelValidator::typeDiffers(bool /*isRootNode*/,
Q_UNUSED(minorVersion)
Q_UNUSED(majorVersion)
QTC_ASSERT(modelNode.type() == typeName, return );
QTC_ASSERT(modelNode.type() == typeName, return);
if (modelNode.majorVersion() != majorVersion) {
qDebug() << Q_FUNC_INFO << modelNode;

View File

@@ -105,6 +105,7 @@ const char MIME_TYPE_ASSET_SOUND[] = "application/vnd.qtdesignstudio.asset
const char MIME_TYPE_ASSET_VIDEO[] = "application/vnd.qtdesignstudio.asset.video";
const char MIME_TYPE_ASSET_TEXTURE3D[] = "application/vnd.qtdesignstudio.asset.texture3d";
const char MIME_TYPE_MODELNODE_LIST[] = "application/vnd.qtdesignstudio.modelnode.list";
const char MIME_TYPE_ASSET_EFFECT[] = "application/vnd.qtdesignstudio.asset.effect";
// Menus
const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces";

View File

@@ -641,6 +641,11 @@ void QmlDesignerPlugin::emitCurrentTextEditorChanged(Core::IEditor *editor)
d->blockEditorChange = false;
}
void QmlDesignerPlugin::emitAssetChanged(const QString &assetPath)
{
emit assetChanged(assetPath);
}
double QmlDesignerPlugin::formEditorDevicePixelRatio()
{
if (QmlDesignerPlugin::settings().value(DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO).toBool())

View File

@@ -85,6 +85,8 @@ public:
void switchToTextModeDeferred();
void emitCurrentTextEditorChanged(Core::IEditor *editor);
void emitAssetChanged(const QString &assetPath);
static double formEditorDevicePixelRatio();
static void emitUsageStatistics(const QString &identifier);
@@ -101,7 +103,7 @@ public:
signals:
void usageStatisticsNotifier(const QString &identifier);
void usageStatisticsUsageTimer(const QString &identifier, int elapsed);
void assetChanged(const QString &assetPath);
private: // functions
void integrateIntoQtCreator(QWidget *modeWidget);