Moved custom tree view dragging logic from Entity Outliner to common class so it could be re-used for the UI Editor tree view.

Signed-off-by: Chris Galvan <chgalvan@amazon.com>
This commit is contained in:
Chris Galvan
2021-08-12 11:15:55 -05:00
parent d273298840
commit b5828e327d
6 changed files with 165 additions and 86 deletions
@@ -8,6 +8,7 @@
#include <AzQtComponents/Components/Widgets/TreeView.h>
#include <QDrag>
#include <QEvent>
#include <QSettings>
#include <QPainter>
@@ -252,5 +253,109 @@ namespace AzQtComponents
return qobject_cast<QTreeView*>(widget) && !qobject_cast<TableView*>(widget);
}
StyledTreeView::StyledTreeView(QWidget* parent)
: QTreeView(parent)
{
}
void StyledTreeView::startDrag(Qt::DropActions supportedActions)
{
if (!selectionModel()->selectedIndexes().empty())
{
StartCustomDrag(selectionModel()->selectedIndexes(), supportedActions);
}
}
void StyledTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
StartCustomDragInternal(this, indexList, supportedActions);
}
void StyledTreeView::StartCustomDragInternal(QAbstractItemView* itemView, const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
QMimeData* mimeData = itemView->model()->mimeData(indexList);
if (mimeData)
{
QDrag* drag = new QDrag(itemView);
drag->setPixmap(QPixmap::fromImage(CreateDragImage(itemView, indexList)));
drag->setMimeData(mimeData);
Qt::DropAction defDropAction = Qt::IgnoreAction;
if (itemView->defaultDropAction() != Qt::IgnoreAction && (supportedActions & itemView->defaultDropAction()))
{
defDropAction = itemView->defaultDropAction();
}
else if (supportedActions & Qt::CopyAction && itemView->dragDropMode() != QAbstractItemView::InternalMove)
{
defDropAction = Qt::CopyAction;
}
drag->exec(supportedActions, defDropAction);
}
}
QImage StyledTreeView::CreateDragImage(QAbstractItemView* itemView, const QModelIndexList& indexList)
{
// Generate a drag image of the item icon and text, normally done internally, and inaccessible
QRect rect(0, 0, 0, 0);
for (const auto& index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = itemView->visualRect(index);
rect.setHeight(rect.height() + itemRect.height());
rect.setWidth(AZStd::GetMax(rect.width(), itemRect.width()));
}
QImage dragImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
QPainter dragPainter(&dragImage);
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
dragPainter.fillRect(dragImage.rect(), Qt::transparent);
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
dragPainter.setOpacity(0.35f);
dragPainter.fillRect(rect, QColor("#222222"));
dragPainter.setOpacity(1.0f);
int imageY = 0;
for (const auto& index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = itemView->visualRect(index);
dragPainter.drawPixmap(QPoint(0, imageY),
itemView->model()->data(index, Qt::DecorationRole).value<QIcon>().pixmap(QSize(16, 16)));
dragPainter.setPen(
itemView->model()->data(index, Qt::ForegroundRole).value<QBrush>().color());
dragPainter.setFont(
itemView->font());
dragPainter.drawText(QRect(20, imageY, rect.width() - 20, rect.height()),
itemView->model()->data(index, Qt::DisplayRole).value<QString>());
imageY += itemRect.height();
}
dragPainter.end();
return dragImage;
}
StyledTreeWidget::StyledTreeWidget(QWidget* parent)
: QTreeWidget(parent)
{
}
void StyledTreeWidget::startDrag(Qt::DropActions supportedActions)
{
if (!selectionModel()->selectedIndexes().empty())
{
StyledTreeView::StartCustomDragInternal(this, selectionModel()->selectedIndexes(), supportedActions);
}
}
} // namespace AzQtComponents
#include <Components/Widgets/moc_TreeView.cpp>
@@ -9,8 +9,11 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AzQtComponents/AzQtComponentsAPI.h>
#include <AzQtComponents/Components/Widgets/TableView.h>
#include <QTreeWidget>
#endif
namespace AzQtComponents
@@ -68,4 +71,46 @@ namespace AzQtComponents
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
//! For most of the custom QTreeView styling, we override in AzQtComponents::Style class,
//! but there are some cases (e.g. drag/drop) that can only be overriden by an actual
//! subclass of the QTreeView
class AZ_QT_COMPONENTS_API StyledTreeView
: public QTreeView
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StyledTreeView, AZ::SystemAllocator, 0);
explicit StyledTreeView(QWidget* parent = nullptr);
//! NOTE: QTreeWidget derives from QTreeView, but because we need a custom dervied class
//! of QTreeView, then we can't inherit our custom drag methods in our custom derived
//! class of QTreeWidget, so these functions are made static so they can be shared
static void StartCustomDragInternal(QAbstractItemView* itemView, const QModelIndexList& indexList, Qt::DropActions supportedActions);
static QImage CreateDragImage(QAbstractItemView* itemView, const QModelIndexList& indexList);
protected:
void startDrag(Qt::DropActions supportedActions) override;
virtual void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions);
};
//! For most of the custom QTreeWidget styling, we override in AzQtComponents::Style class,
//! but there are some cases (e.g. drag/drop) that can only be overriden by an actual
//! subclass of the QTreeWidget.
class AZ_QT_COMPONENTS_API StyledTreeWidget
: public QTreeWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StyledTreeWidget, AZ::SystemAllocator, 0);
explicit StyledTreeWidget(QWidget* parent = nullptr);
protected:
void startDrag(Qt::DropActions supportedActions) override;
};
} // namespace AzQtComponents