QmlDesigner: Implement multi-selection in the asset library

Multi-selected assets can be dragged to the form editor
and navigator. Also increased font size for newly
created text as it was so small and some relvant
cleanups.

Change-Id: Icf28b627a8392309520b7071209812e1ae051e84
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Mahmoud Badri
2021-06-15 17:24:24 +03:00
parent 0945b8d0dc
commit 5369aea1ed
9 changed files with 388 additions and 371 deletions

View File

@@ -32,6 +32,8 @@ import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Item {
property var selectedAssets: ({})
DropArea {
id: dropArea
@@ -142,7 +144,8 @@ Item {
width: assetsView.width -
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
height: img.height
color: mouseArea.containsMouse ? "#444444" : "transparent"
color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction
: (mouseArea.containsMouse ? "#444444" : "transparent")
Row {
spacing: 5
@@ -178,11 +181,33 @@ Item {
onPositionChanged: tooltipBackend.reposition()
onPressed: {
forceActiveFocus()
if (mouse.button === Qt.LeftButton)
rootView.startDragAsset(filePath, mapToGlobal(mouse.x, mouse.y))
else
if (mouse.button === Qt.LeftButton) {
var ctrlDown = mouse.modifiers & Qt.ControlModifier
if (!selectedAssets[filePath] && !ctrlDown)
selectedAssets = {}
selectedAssets[filePath] = true
selectedAssetsChanged()
var selectedAssetsArr = []
for (var assetPath in selectedAssets) {
if (selectedAssets[assetPath])
selectedAssetsArr.push(assetPath)
}
rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y))
} else {
print("TODO: impl context menu")
}
}
onReleased: {
if (mouse.button === Qt.LeftButton) {
if (!(mouse.modifiers & Qt.ControlModifier))
selectedAssets = {}
selectedAssets[filePath] = true
selectedAssetsChanged()
}
}
ToolTip {
visible: !isFont && mouseArea.containsMouse

View File

@@ -27,6 +27,7 @@
#include "formeditorview.h"
#include "formeditorwidget.h"
#include "formeditorscene.h"
#include "itemlibrarywidget.h"
#include <modelnodecontextmenu.h>
@@ -234,9 +235,21 @@ void AbstractFormEditorTool::dropEvent(const QList<QGraphicsItem*> &/*itemList*/
void AbstractFormEditorTool::dragEnterEvent(const QList<QGraphicsItem*> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo"))
|| event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.libraryresource.image"))
|| event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.libraryresource.font"))) {
bool hasValidAssets = false;
if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data("application/vnd.bauhaus.libraryresource")).split(",");
for (const QString &assetPath : assetPaths) {
QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.image"
|| assetType == "application/vnd.bauhaus.libraryresource.font") {
hasValidAssets = true;
break;
}
}
}
if (event->mimeData()->hasFormat(QLatin1String("application/vnd.bauhaus.itemlibraryinfo")) || hasValidAssets) {
event->accept();
view()->changeToDragTool();
view()->currentTool()->dragEnterEvent(itemList, event);

View File

@@ -27,6 +27,7 @@
#include "formeditorscene.h"
#include "formeditorview.h"
#include "itemlibrarywidget.h"
#include <metainfo.h>
#include <nodehints.h>
#include <rewritingexception.h>
@@ -45,9 +46,7 @@ namespace QmlDesigner {
DragTool::DragTool(FormEditorView *editorView)
: AbstractFormEditorTool(editorView),
m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
m_blockMove(false),
m_isAborted(false)
m_selectionIndicator(editorView->scene()->manipulatorLayerItem())
{
}
@@ -57,7 +56,7 @@ void DragTool::clear()
{
m_moveManipulator.clear();
m_selectionIndicator.clear();
m_movingItem = nullptr;
m_movingItems.clear();
}
void DragTool::mousePressEvent(const QList<QGraphicsItem *> &, QGraphicsSceneMouseEvent *) {}
@@ -83,9 +82,9 @@ void DragTool::updateMoveManipulator() {}
void DragTool::beginWithPoint(const QPointF &beginPoint)
{
m_movingItem = scene()->itemForQmlItemNode(m_dragNode);
m_movingItems = scene()->itemsForQmlItemNodes(m_dragNodes);
m_moveManipulator.setItem(m_movingItem);
m_moveManipulator.setItems(m_movingItems);
m_moveManipulator.begin(beginPoint);
}
@@ -108,17 +107,17 @@ void DragTool::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry,
adjustedParentNode = view()->rootModelNode();
}
m_dragNode = QmlItemNode::createQmlItemNode(view(), itemLibraryEntry, itemPos, adjustedParentNode);
m_dragNodes.append(QmlItemNode::createQmlItemNode(view(), itemLibraryEntry, itemPos, adjustedParentNode));
if (rootIsFlow)
m_dragNode.setFlowItemPosition(positonInItemSpace);
if (rootIsFlow) {
for (QmlItemNode &dragNode : m_dragNodes)
dragNode.setFlowItemPosition(positonInItemSpace);
}
QList<QmlItemNode> nodeList;
nodeList.append(m_dragNode);
m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(m_dragNodes));
}
void DragTool::createQmlItemNodeFromImage(const QString &imageName,
void DragTool::createQmlItemNodeFromImage(const QString &imagePath,
const QmlItemNode &parentNode,
const QPointF &scenePosition)
{
@@ -128,15 +127,11 @@ void DragTool::createQmlItemNodeFromImage(const QString &imageName,
FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform().inverted().map(scenePosition);
m_dragNode = QmlItemNode::createQmlItemNodeFromImage(view(), imageName, positonInItemSpace, parentNode);
QList<QmlItemNode> nodeList;
nodeList.append(m_dragNode);
m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
m_dragNodes.append(QmlItemNode::createQmlItemNodeFromImage(view(), imagePath, positonInItemSpace, parentNode));
}
}
void DragTool::createQmlItemNodeFromFont(const QString &fontFamily,
void DragTool::createQmlItemNodeFromFont(const QString &fontPath,
const QmlItemNode &parentNode,
const QPointF &scenePos)
{
@@ -147,18 +142,18 @@ void DragTool::createQmlItemNodeFromFont(const QString &fontFamily,
QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform()
.inverted().map(scenePos);
m_dragNode = QmlItemNode::createQmlItemNodeFromFont(view(), fontFamily, positonInItemSpace,
parentNode);
const auto typeAndData = ItemLibraryWidget::getAssetTypeAndData(fontPath);
QString fontFamily = QString::fromUtf8(typeAndData.second);
QList<QmlItemNode> nodeList;
nodeList.append(m_dragNode);
m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
m_dragNodes.append(QmlItemNode::createQmlItemNodeFromFont(view(), fontFamily,
positonInItemSpace, parentNode));
}
}
FormEditorItem *DragTool::targetContainerOrRootItem(const QList<QGraphicsItem *> &itemList, FormEditorItem *currentItem)
FormEditorItem *DragTool::targetContainerOrRootItem(const QList<QGraphicsItem *> &itemList,
const QList<FormEditorItem *> &currentItems)
{
FormEditorItem *formEditorItem = containerFormEditorItem(itemList, {currentItem});
FormEditorItem *formEditorItem = containerFormEditorItem(itemList, currentItems);
if (!formEditorItem)
formEditorItem = scene()->rootFormEditorItem();
@@ -168,19 +163,27 @@ FormEditorItem *DragTool::targetContainerOrRootItem(const QList<QGraphicsItem *>
void DragTool::formEditorItemsChanged(const QList<FormEditorItem *> &itemList)
{
if (m_movingItem && itemList.contains(m_movingItem)) {
QList<FormEditorItem *> updateItemList;
updateItemList.append(m_movingItem);
m_selectionIndicator.updateItems(updateItemList);
if (!m_movingItems.isEmpty()) {
for (auto item : std::as_const(m_movingItems)) {
if (itemList.contains(item)) {
m_selectionIndicator.updateItems(m_movingItems);
break;
}
}
}
}
void DragTool::instancesCompleted(const QList<FormEditorItem *> &itemList)
{
m_moveManipulator.synchronizeInstanceParent(itemList);
foreach (FormEditorItem* item, itemList)
if (item->qmlItemNode() == m_dragNode)
for (FormEditorItem *item : itemList) {
for (const QmlItemNode &dragNode : std::as_const(m_dragNodes)) {
if (item->qmlItemNode() == dragNode) {
clearMoveDelay();
break;
}
}
}
}
void DragTool::instancesParentChanged(const QList<FormEditorItem *> &itemList)
@@ -194,7 +197,7 @@ void DragTool::clearMoveDelay()
{
if (m_blockMove) {
m_blockMove = false;
if (m_dragNode.isValid())
if (!m_dragNodes.isEmpty())
beginWithPoint(m_startPoint);
}
}
@@ -206,8 +209,11 @@ void DragTool::abort()
if (!m_isAborted) {
m_isAborted = true;
if (m_dragNode.isValid())
m_dragNode.destroy();
for (auto &node : m_dragNodes) {
if (node.isValid())
node.destroy();
}
m_dragNodes.clear();
}
}
@@ -233,48 +239,38 @@ static bool hasItemLibraryInfo(const QMimeData *mimeData)
return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"));
}
static bool hasImageResource(const QMimeData *mimeData)
{
return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource.image"));
}
static bool hasFontResource(const QMimeData *mimeData)
{
return mimeData->hasFormat(QStringLiteral("application/vnd.bauhaus.libraryresource.font"));
}
static bool canHandleMimeData(const QMimeData *mimeData)
{
return hasItemLibraryInfo(mimeData) || hasImageResource(mimeData) || hasFontResource(mimeData);
}
static bool dragAndDropPossible(const QMimeData *mimeData)
{
return canHandleMimeData(mimeData) && canBeDropped(mimeData);
}
void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
{
if (dragAndDropPossible(event->mimeData())) {
if (canBeDropped(event->mimeData())) {
event->accept();
end(generateUseSnapping(event->modifiers()));
if (m_dragNode.isValid()) {
if ((m_dragNode.instanceParentItem().isValid()
&& m_dragNode.instanceParent().modelNode().metaInfo().isLayoutable())
|| m_dragNode.isFlowItem()) {
m_dragNode.removeProperty("x");
m_dragNode.removeProperty("y");
view()->resetPuppet(); //Otherwise the layout might not reposition the item
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 (resetPuppet)
view()->resetPuppet(); // Otherwise the layout might not reposition the items
commitTransaction();
if (m_dragNode.isValid())
view()->setSelectedModelNode(m_dragNode);
m_dragNode = QmlItemNode();
if (!m_dragNodes.isEmpty()) {
QList<ModelNode> nodeList;
for (auto &node : std::as_const(m_dragNodes)) {
if (node.isValid())
nodeList.append(node);
}
view()->setSelectedModelNodes(nodeList);
}
m_dragNodes.clear();
view()->changeToSelectionTool();
}
@@ -282,11 +278,10 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSc
void DragTool::dragEnterEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
{
if (dragAndDropPossible(event->mimeData())) {
if (canBeDropped(event->mimeData())) {
m_blockMove = false;
if (hasItemLibraryInfo(event->mimeData())) {
view()->widgetInfo().widget->setFocus();
m_isAborted = false;
}
@@ -300,13 +295,17 @@ void DragTool::dragEnterEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraph
void DragTool::dragLeaveEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
{
if (dragAndDropPossible(event->mimeData())) {
if (canBeDropped(event->mimeData())) {
event->accept();
m_moveManipulator.end();
clear();
if (m_dragNode.isValid())
m_dragNode.destroy();
for (auto &node : m_dragNodes) {
if (node.isValid())
node.destroy();
}
m_dragNodes.clear();
commitTransaction();
}
@@ -314,31 +313,31 @@ void DragTool::dragLeaveEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraph
view()->changeToSelectionTool();
}
static QString libraryResourceFile(const QMimeData *mimeData)
void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition,
const QList<QGraphicsItem *> &itemList)
{
return QString::fromUtf8((mimeData->data(QStringLiteral("application/vnd.bauhaus.libraryresource"))));
}
static QString libraryResourceFont(const QMimeData *mimeData)
{
return QString::fromUtf8((mimeData->data(QStringLiteral("application/vnd.bauhaus.libraryresource.font"))));
}
void DragTool::createDragNode(const QMimeData *mimeData, const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList)
{
if (!m_dragNode.hasModelNode()) {
if (m_dragNodes.isEmpty()) {
FormEditorItem *targetContainerFormEditorItem = targetContainerOrRootItem(itemList);
if (targetContainerFormEditorItem) {
QmlItemNode targetContainerQmlItemNode;
if (targetContainerFormEditorItem)
targetContainerQmlItemNode = targetContainerFormEditorItem->qmlItemNode();
QmlItemNode targetContainerQmlItemNode = targetContainerFormEditorItem->qmlItemNode();
if (hasItemLibraryInfo(mimeData))
createQmlItemNode(itemLibraryEntryFromMimeData(mimeData), targetContainerQmlItemNode, scenePosition);
else if (hasImageResource(mimeData))
createQmlItemNodeFromImage(libraryResourceFile(mimeData), targetContainerQmlItemNode, scenePosition);
else if (hasFontResource(mimeData))
createQmlItemNodeFromFont(libraryResourceFont(mimeData), targetContainerQmlItemNode, scenePosition);
if (hasItemLibraryInfo(mimeData)) {
createQmlItemNode(itemLibraryEntryFromMimeData(mimeData), targetContainerQmlItemNode,
scenePosition);
} else {
const QStringList assetPaths = QString::fromUtf8(mimeData
->data("application/vnd.bauhaus.libraryresource")).split(",");
for (const QString &assetPath : assetPaths) {
QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.image")
createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition);
else if (assetType == "application/vnd.bauhaus.libraryresource.font")
createQmlItemNodeFromFont(assetPath, targetContainerQmlItemNode, scenePosition);
}
if (!m_dragNodes.isEmpty())
m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(m_dragNodes));
}
m_blockMove = true;
m_startPoint = scenePosition;
@@ -348,18 +347,22 @@ void DragTool::createDragNode(const QMimeData *mimeData, const QPointF &scenePos
void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (!m_blockMove && !m_isAborted && dragAndDropPossible(event->mimeData())) {
if (!m_blockMove && !m_isAborted && canBeDropped(event->mimeData())) {
event->accept();
if (m_dragNode.isValid()) {
if (!m_dragNodes.isEmpty()) {
FormEditorItem *targetContainerItem = targetContainerOrRootItem(itemList);
if (targetContainerItem) {
move(event->scenePos(), itemList);
} else {
end();
m_dragNode.destroy();
for (auto &node : m_dragNodes) {
if (node.isValid())
node.destroy();
}
m_dragNodes.clear();
}
} else {
createDragNode(event->mimeData(), event->scenePos(), itemList);
createDragNodes(event->mimeData(), event->scenePos(), itemList);
}
} else {
event->ignore();
@@ -380,12 +383,12 @@ void DragTool::end(Snapper::Snapping useSnapping)
void DragTool::move(const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList)
{
if (m_movingItem) {
FormEditorItem *containerItem = targetContainerOrRootItem(itemList, m_movingItem);
if (containerItem && m_movingItem->parentItem() &&
containerItem != m_movingItem->parentItem()) {
const QmlItemNode movingNode = m_movingItem->qmlItemNode();
if (!m_movingItems.isEmpty()) {
FormEditorItem *containerItem = targetContainerOrRootItem(itemList, m_movingItems);
for (auto &movingItem : std::as_const(m_movingItems)) {
if (containerItem && movingItem->parentItem() &&
containerItem != movingItem->parentItem()) {
const QmlItemNode movingNode = movingItem->qmlItemNode();
const QmlItemNode containerNode = containerItem->qmlItemNode();
qCInfo(dragToolInfo()) << Q_FUNC_INFO << movingNode << containerNode << movingNode.canBereparentedTo(containerNode);
@@ -393,6 +396,7 @@ void DragTool::move(const QPointF &scenePosition, const QList<QGraphicsItem *>
if (movingNode.canBereparentedTo(containerNode))
m_moveManipulator.reparentTo(containerItem);
}
}
Snapper::Snapping useSnapping = Snapper::UseSnapping;
@@ -409,4 +413,4 @@ void DragTool::commitTransaction()
}
}
}
} // namespace QmlDesigner

View File

@@ -80,22 +80,23 @@ public:
protected:
void abort();
void createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, const QmlItemNode &parentNode, const QPointF &scenePos);
void createQmlItemNodeFromImage(const QString &imageName, const QmlItemNode &parentNode, const QPointF &scenePos);
void createQmlItemNodeFromFont(const QString &fontFamily, const QmlItemNode &parentNode, const QPointF &scenePos);
FormEditorItem *targetContainerOrRootItem(const QList<QGraphicsItem*> &itemList, FormEditorItem *urrentItem = nullptr);
void createQmlItemNodeFromImage(const QString &imagePath, const QmlItemNode &parentNode, const QPointF &scenePos);
void createQmlItemNodeFromFont(const QString &fontPath, const QmlItemNode &parentNode, const QPointF &scenePos);
FormEditorItem *targetContainerOrRootItem(const QList<QGraphicsItem *> &itemList,
const QList<FormEditorItem *> &currentItems = {});
void begin(QPointF scenePos);
void end();
void end(Snapper::Snapping useSnapping);
void move(const QPointF &scenePos, const QList<QGraphicsItem *> &itemList);
void createDragNode(const QMimeData *mimeData, const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList);
void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList);
void commitTransaction();
private:
MoveManipulator m_moveManipulator;
SelectionIndicator m_selectionIndicator;
FormEditorItem *m_movingItem = nullptr;
QList<FormEditorItem *> m_movingItems;
RewriterTransaction m_rewriterTransaction;
QmlItemNode m_dragNode;
QList<QmlItemNode> m_dragNodes;
bool m_blockMove;
QPointF m_startPoint;
bool m_isAborted;

View File

@@ -117,24 +117,23 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
m_itemToDrag = {};
}
} else if (!m_assetToDrag.isEmpty()) {
} else if (!m_assetsToDrag.isEmpty()) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) {
auto drag = new QDrag(this);
drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetToDrag, nullptr, {128, 128}));
drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128}));
QMimeData *mimeData = new QMimeData;
mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetToDrag.toUtf8());
mimeData->setData(m_assetToDragTypeAndData.first, m_assetToDragTypeAndData.second);
mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetsToDrag.join(',').toUtf8());
drag->setMimeData(mimeData);
drag->exec();
drag->deleteLater();
m_assetToDrag.clear();
m_assetsToDrag.clear();
}
}
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_itemToDrag = {};
m_assetToDrag.clear();
m_assetsToDrag.clear();
}
return QObject::eventFilter(obj, event);
@@ -471,30 +470,24 @@ void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPo
m_dragStartPoint = mousePos.toPoint();
}
void ItemLibraryWidget::startDragAsset(const QString &assetPath, const QPointF &mousePos)
void ItemLibraryWidget::startDragAsset(const QStringList &assetPaths, const QPointF &mousePos)
{
QFileInfo fileInfo(assetPath);
m_assetToDragTypeAndData = getAssetTypeAndData(fileInfo);
if (m_assetToDragTypeAndData.first.isEmpty())
return;
// Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay
// active (and blocks mouse release) if mouse is released at the same spot of the drag start.
m_assetToDrag = fileInfo.absoluteFilePath();
m_assetsToDrag = assetPaths;
m_dragStartPoint = mousePos.toPoint();
}
QPair<QString, QByteArray> ItemLibraryWidget::getAssetTypeAndData(const QFileInfo &fi) const
QPair<QString, QByteArray> ItemLibraryWidget::getAssetTypeAndData(const QString &assetPath)
{
QString suffix = "*." + fi.suffix().toLower();
QString suffix = "*." + assetPath.split('.').last().toLower();
if (!suffix.isEmpty()) {
if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) {
// Data: Image format (suffix)
return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()};
} else if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix)) {
// Data: Font family name
QRawFont font(fi.absoluteFilePath(), 10);
QRawFont font(assetPath, 10);
QString fontFamily = font.isValid() ? font.familyName() : "";
return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()};
} else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) {

View File

@@ -90,10 +90,10 @@ public:
void setResourcePath(const QString &resourcePath);
void setModel(Model *model);
void setFlowMode(bool b);
QPair<QString, QByteArray> getAssetTypeAndData(const QFileInfo &fi) const;
static QPair<QString, QByteArray> getAssetTypeAndData(const QString &assetPath);
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
Q_INVOKABLE void startDragAsset(const QString &assetPath, const QPointF &mousePos);
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void removeImport(const QString &importUrl);
Q_INVOKABLE void addImportForItem(const QString &importUrl);
Q_INVOKABLE void handleTabChanged(int index);
@@ -143,7 +143,7 @@ private:
AsynchronousImageCache &m_imageCache;
QPointer<Model> m_model;
QVariant m_itemToDrag;
QString m_assetToDrag;
QStringList m_assetsToDrag;
QPair<QString, QByteArray> m_assetToDragTypeAndData;
bool m_updateRetry = false;
QString m_filterText;

View File

@@ -27,6 +27,7 @@
#include "navigatorview.h"
#include "choosetexturepropertydialog.h"
#include "qmldesignerplugin.h"
#include "itemlibrarywidget.h"
#include <bindingproperty.h>
#include <designersettings.h>
@@ -484,39 +485,6 @@ QModelIndex NavigatorTreeModel::createIndexFromModelNode(int row, int column, co
return index;
}
bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
Qt::DropAction action,
int rowNumber,
int /*columnNumber*/,
const QModelIndex &dropModelIndex)
{
if (action == Qt::IgnoreAction)
return true;
if (m_reverseItemOrder)
rowNumber = rowCount(dropModelIndex) - rowNumber;
if (dropModelIndex.model() == this) {
if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.image")) {
handleItemLibraryImageDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.font")) {
handleItemLibraryFontDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.shader")) {
handleItemLibraryShaderDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.sound")) {
handleItemLibrarySoundDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource.texture3d")) {
handleItemLibraryTexture3dDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.modelnode.list")) {
handleInternalDrop(mimeData, rowNumber, dropModelIndex);
}
}
return false; // don't let the view do drag&drop on its own
}
static bool findTargetProperty(const QModelIndex &rowModelIndex,
NavigatorTreeModel *navigatorTreeModel,
NodeAbstractProperty *targetProperty,
@@ -551,6 +519,62 @@ static bool findTargetProperty(const QModelIndex &rowModelIndex,
return true;
}
bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
Qt::DropAction action,
int rowNumber,
int /*columnNumber*/,
const QModelIndex &dropModelIndex)
{
if (action == Qt::IgnoreAction)
return true;
if (m_reverseItemOrder)
rowNumber = rowCount(dropModelIndex) - rowNumber;
if (dropModelIndex.model() == this) {
if (mimeData->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex);
} else if (mimeData->hasFormat("application/vnd.bauhaus.libraryresource")) {
QStringList assetsPaths = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")).split(",");
NodeAbstractProperty targetProperty;
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
QList<ModelNode> addedNodes;
ModelNode currNode;
for (const QString &assetPath : std::as_const(assetsPaths)) {
auto assetTypeAndData = ItemLibraryWidget::getAssetTypeAndData(assetPath);
QString assetType = assetTypeAndData.first;
QString assetData = QString::fromUtf8(assetTypeAndData.second);
if (assetType == "application/vnd.bauhaus.libraryresource.image")
currNode = handleItemLibraryImageDrop(assetPath, targetProperty, rowModelIndex);
else if (assetType == "application/vnd.bauhaus.libraryresource.font")
currNode = handleItemLibraryFontDrop(assetData, targetProperty, rowModelIndex); // assetData is fontFamily
else if (assetType == "application/vnd.bauhaus.libraryresource.shader")
currNode = handleItemLibraryShaderDrop(assetPath, assetData == "f", targetProperty, rowModelIndex);
else if (assetType == "application/vnd.bauhaus.libraryresource.sound")
currNode = handleItemLibrarySoundDrop(assetPath, targetProperty, rowModelIndex);
else if (assetType == "application/vnd.bauhaus.libraryresource.texture3d")
currNode = handleItemLibraryTexture3dDrop(assetPath, targetProperty, rowModelIndex);
if (currNode.isValid())
addedNodes.append(currNode);
}
if (!addedNodes.isEmpty()) {
moveNodesInteractive(targetProperty, addedNodes, rowNumber);
m_view->setSelectedModelNodes(addedNodes);
}
}
} else if (mimeData->hasFormat("application/vnd.modelnode.list")) {
handleInternalDrop(mimeData, rowNumber, dropModelIndex);
}
}
return false; // don't let the view do drag&drop on its own
}
void NavigatorTreeModel::handleInternalDrop(const QMimeData *mimeData,
int rowNumber,
const QModelIndex &dropModelIndex)
@@ -583,6 +607,7 @@ static ItemLibraryEntry createItemLibraryEntryFromMimeData(const QByteArray &dat
void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex)
{
QTC_ASSERT(m_view, return);
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
@@ -714,31 +739,27 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
}
}
void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex)
ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePath,
NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex)
{
QTC_ASSERT(m_view, return);
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
QTC_ASSERT(m_view, return {});
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
ModelNode targetNode(modelNodeForIndex(rowModelIndex));
const QString imageSource = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource")); // absolute path
const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(imageSource); // relative to .ui.qml file
const QString imagePathRelative = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(imagePath); // relative to .ui.qml file
ModelNode newModelNode;
if (!dropAsImage3dTexture(targetNode, targetProperty, imagePath, newModelNode)) {
if (!dropAsImage3dTexture(targetNode, targetProperty, imagePathRelative, newModelNode)) {
if (targetNode.isSubclassOf("QtQuick.Image")
|| targetNode.isSubclassOf("QtQuick.BorderImage")) {
// if dropping an image on an existing image, set the source
targetNode.variantProperty("source").setValue(imagePath);
targetNode.variantProperty("source").setValue(imagePathRelative);
} else {
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryImageDrop", [&] {
// create an image
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(m_view, imageSource, QPointF(), targetProperty, false);
QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(m_view, imagePath, QPointF(), targetProperty, false);
if (NodeHints::fromModelNode(targetProperty.parentModelNode()).canBeContainerFor(newItemNode.modelNode()))
newModelNode = newItemNode.modelNode();
else
@@ -747,28 +768,17 @@ void NavigatorTreeModel::handleItemLibraryImageDrop(const QMimeData *mimeData, i
}
}
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
}
return newModelNode;
}
void NavigatorTreeModel::handleItemLibraryFontDrop(const QMimeData *mimeData, int rowNumber,
const QModelIndex &dropModelIndex)
ModelNode NavigatorTreeModel::handleItemLibraryFontDrop(const QString &fontFamily,
NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex)
{
QTC_ASSERT(m_view, return);
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
QTC_ASSERT(m_view, return {});
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
ModelNode targetNode(modelNodeForIndex(rowModelIndex));
const QString fontFamily = QString::fromUtf8(
mimeData->data("application/vnd.bauhaus.libraryresource.font"));
ModelNode newModelNode;
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryFontDrop", [&] {
@@ -786,17 +796,15 @@ void NavigatorTreeModel::handleItemLibraryFontDrop(const QMimeData *mimeData, in
}
});
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
}
return newModelNode;
}
void NavigatorTreeModel::handleItemLibraryShaderDrop(const QMimeData *mimeData, int rowNumber,
const QModelIndex &dropModelIndex)
ModelNode NavigatorTreeModel::handleItemLibraryShaderDrop(const QString &shaderPath, bool isFragShader,
NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex)
{
QTC_ASSERT(m_view, return);
QTC_ASSERT(m_view, return {});
Import import = Import::createLibraryImport(QStringLiteral("QtQuick3D"));
bool addImport = false;
if (!m_view->model()->hasImport(import, true, true)) {
@@ -811,26 +819,16 @@ void NavigatorTreeModel::handleItemLibraryShaderDrop(const QMimeData *mimeData,
}
}
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
ModelNode targetNode(modelNodeForIndex(rowModelIndex));
ModelNode newModelNode;
const QString shaderSource = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource"));
const bool fragShader = mimeData->data("application/vnd.bauhaus.libraryresource.shader").startsWith('f');
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(shaderSource);
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(shaderPath);
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryShaderDrop", [&] {
if (targetNode.isSubclassOf("QtQuick3D.Shader")) {
// if dropping into an existing Shader, update
if (fragShader)
targetNode.variantProperty("stage").setEnumeration("Shader.Fragment");
else
targetNode.variantProperty("stage").setEnumeration("Shader.Vertex");
targetNode.variantProperty("stage").setEnumeration(isFragShader ? "Shader.Fragment"
: "Shader.Vertex");
targetNode.variantProperty("shader").setValue(relPath);
} else {
// create a new Shader
@@ -845,7 +843,7 @@ void NavigatorTreeModel::handleItemLibraryShaderDrop(const QMimeData *mimeData,
itemLibraryEntry.addProperty(prop, type, val);
prop = "stage";
type = "enum";
val = fragShader ? "Shader.Fragment" : "Shader.Vertex";
val = isFragShader ? "Shader.Fragment" : "Shader.Vertex";
itemLibraryEntry.addProperty(prop, type, val);
// create a texture
@@ -859,20 +857,18 @@ void NavigatorTreeModel::handleItemLibraryShaderDrop(const QMimeData *mimeData,
}
});
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
if (addImport)
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
}
return newModelNode;
}
void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber,
const QModelIndex &dropModelIndex)
ModelNode NavigatorTreeModel::handleItemLibrarySoundDrop(const QString &soundPath,
NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex)
{
QTC_ASSERT(m_view, return);
QTC_ASSERT(m_view, return {});
Import import = Import::createLibraryImport(QStringLiteral("QtMultimedia"));
bool addImport = false;
if (!m_view->model()->hasImport(import, true, true)) {
@@ -887,17 +883,10 @@ void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, i
}
}
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
ModelNode targetNode(modelNodeForIndex(rowModelIndex));
ModelNode newModelNode;
const QString soundSource = QString::fromUtf8(mimeData->data("application/vnd.bauhaus.libraryresource"));
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(soundSource);
const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(soundPath);
m_view->executeInTransaction("NavigatorTreeModel::handleItemLibrarySoundDrop", [&] {
if (targetNode.isSubclassOf("QtMultimedia.SoundEffect")) {
@@ -909,7 +898,7 @@ void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, i
itemLibraryEntry.setName("SoundEffect");
itemLibraryEntry.setType("QtMultimedia.SoundEffect", 1, 0);
// set shader properties
// set source property
PropertyName prop = "source";
QString type = "QUrl";
QVariant val = relPath;
@@ -926,36 +915,26 @@ void NavigatorTreeModel::handleItemLibrarySoundDrop(const QMimeData *mimeData, i
}
});
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
if (addImport)
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
}
return newModelNode;
}
void NavigatorTreeModel::handleItemLibraryTexture3dDrop(const QMimeData *mimeData, int rowNumber,
const QModelIndex &dropModelIndex)
ModelNode NavigatorTreeModel::handleItemLibraryTexture3dDrop(const QString &tex3DPath,
NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex)
{
QTC_ASSERT(m_view, return);
QTC_ASSERT(m_view, return {});
Import import = Import::createLibraryImport(QStringLiteral("QtQuick3D"));
if (!m_view->model()->hasImport(import, true, true))
return;
return {};
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
int targetRowNumber = rowNumber;
NodeAbstractProperty targetProperty;
bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber);
if (foundTarget) {
ModelNode targetNode(modelNodeForIndex(rowModelIndex));
const QString imageSource = QString::fromUtf8(
mimeData->data("application/vnd.bauhaus.libraryresource")); // absolute path
const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir()
.relativeFilePath(imageSource); // relative to qml file
.relativeFilePath(tex3DPath); // relative to qml file
ModelNode newModelNode;
@@ -968,11 +947,7 @@ void NavigatorTreeModel::handleItemLibraryTexture3dDrop(const QMimeData *mimeDat
});
}
if (newModelNode.isValid()) {
moveNodesInteractive(targetProperty, {newModelNode}, targetRowNumber);
m_view->setSelectedModelNode(newModelNode);
}
}
return newModelNode;
}
bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode,

View File

@@ -114,11 +114,16 @@ private:
int targetIndex, bool executeInTransaction = true);
void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryImageDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryFontDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryShaderDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibrarySoundDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryTexture3dDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex);
ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex);
ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, bool isFragShader,
NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex);
ModelNode handleItemLibrarySoundDrop(const QString &soundPath, NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex);
ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex);
bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp,
const QString &imagePath, ModelNode &newNode);
ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath);

View File

@@ -161,6 +161,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
propertyPairList.append({PropertyName("x"), QVariant(qRound(position.x()))});
propertyPairList.append({PropertyName("y"), QVariant(qRound(position.y()))});
propertyPairList.append({PropertyName("font.family"), QVariant(fontFamily)});
propertyPairList.append({PropertyName("font.pointSize"), 20});
propertyPairList.append({PropertyName("text"), QVariant(fontFamily)});
newQmlItemNode = QmlItemNode(view->createModelNode("QtQuick.Text", metaInfo.majorVersion(),