##// END OF EJS Templates
Format changes
Format changes

File last commit:

r847:90e991aec5fa
r847:90e991aec5fa
Show More
VisualizationDragDropContainer.cpp
301 lines | 10.1 KiB | text/x-c | CppLexer
/ gui / src / Visualization / VisualizationDragDropContainer.cpp
New visualization classes for the drag&drop
r841 #include "Visualization/VisualizationDragDropContainer.h"
#include "DragDropHelper.h"
Format changes
r847 #include "SqpApplication.h"
#include "Visualization/VisualizationDragWidget.h"
New visualization classes for the drag&drop
r841
#include <QDrag>
#include <QDragEnterEvent>
Format changes
r847 #include <QVBoxLayout>
New visualization classes for the drag&drop
r841
#include <memory>
struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
Format changes
r847 QVBoxLayout *m_Layout;
QStringList m_AcceptedMimeTypes;
QStringList m_MergeAllowedMimeTypes;
New visualization classes for the drag&drop
r841
Format changes
r847 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
New visualization classes for the drag&drop
r841 {
Format changes
r847 m_Layout = new QVBoxLayout(widget);
m_Layout->setContentsMargins(0, 0, 0, 0);
New visualization classes for the drag&drop
r841 }
Format changes
r847 bool acceptMimeData(const QMimeData *data) const
New visualization classes for the drag&drop
r841 {
Format changes
r847 for (const auto &type : m_AcceptedMimeTypes) {
if (data->hasFormat(type)) {
New visualization classes for the drag&drop
r841 return true;
Format changes
r847 }
New visualization classes for the drag&drop
r841 }
return false;
}
Format changes
r847 bool allowMergeMimeData(const QMimeData *data) const
New visualization classes for the drag&drop
r841 {
Format changes
r847 for (const auto &type : m_MergeAllowedMimeTypes) {
if (data->hasFormat(type)) {
New visualization classes for the drag&drop
r841 return true;
Format changes
r847 }
New visualization classes for the drag&drop
r841 }
return false;
}
bool hasPlaceHolder() const
{
Format changes
r847 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
New visualization classes for the drag&drop
r841 }
Format changes
r847 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
New visualization classes for the drag&drop
r841 {
Format changes
r847 VisualizationDragWidget *dragWidget = nullptr;
for (auto child : parent->children()) {
auto widget = qobject_cast<VisualizationDragWidget *>(child);
if (widget && widget->isVisible()) {
if (widget->frameGeometry().contains(pos)) {
New visualization classes for the drag&drop
r841 dragWidget = widget;
break;
}
}
}
return dragWidget;
}
Format changes
r847 bool cursorIsInContainer(QWidget *container) const
New visualization classes for the drag&drop
r841 {
Format changes
r847 auto adustNum = 18; // to be safe, in case of scrollbar on the side
auto containerRect = QRect(QPoint(), container->contentsRect().size())
.adjusted(adustNum, adustNum, -adustNum, -adustNum);
New visualization classes for the drag&drop
r841 qDebug() << containerRect << container->mapFromGlobal(QCursor::pos());
return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
}
};
VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
Format changes
r847 : QWidget{parent},
impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
New visualization classes for the drag&drop
r841 {
setAcceptDrops(true);
}
void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
{
Format changes
r847 impl->m_Layout->addWidget(dragWidget);
New visualization classes for the drag&drop
r841 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
Format changes
r847 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
&VisualizationDragDropContainer::startDrag);
New visualization classes for the drag&drop
r841 }
Format changes
r847 void VisualizationDragDropContainer::insertDragWidget(int index,
VisualizationDragWidget *dragWidget)
New visualization classes for the drag&drop
r841 {
Format changes
r847 impl->m_Layout->insertWidget(index, dragWidget);
New visualization classes for the drag&drop
r841 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
Format changes
r847 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
&VisualizationDragDropContainer::startDrag);
New visualization classes for the drag&drop
r841 }
void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
{
Format changes
r847 impl->m_AcceptedMimeTypes = mimeTypes;
New visualization classes for the drag&drop
r841 }
void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
{
Format changes
r847 impl->m_MergeAllowedMimeTypes = mimeTypes;
New visualization classes for the drag&drop
r841 }
int VisualizationDragDropContainer::countDragWidget() const
{
auto nbGraph = 0;
Format changes
r847 for (auto child : children()) {
auto widget = qobject_cast<VisualizationDragWidget *>(child);
if (widget) {
New visualization classes for the drag&drop
r841 nbGraph += 1;
}
}
return nbGraph;
}
Format changes
r847 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
const QPoint &dragPosition)
New visualization classes for the drag&drop
r841 {
Format changes
r847 auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r841
Format changes
r847 // Note: The management of the drag object is done by Qt
New visualization classes for the drag&drop
r841 auto *drag = new QDrag{dragWidget};
drag->setHotSpot(dragPosition);
auto mimeData = dragWidget->mimeData();
drag->setMimeData(mimeData);
auto pixmap = QPixmap(dragWidget->size());
dragWidget->render(&pixmap);
drag->setPixmap(pixmap);
auto image = pixmap.toImage();
mimeData->setImageData(image);
mimeData->setUrls({helper.imageTemporaryUrl(image)});
Format changes
r847 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
New visualization classes for the drag&drop
r841 helper.setCurrentDragWidget(dragWidget);
Format changes
r847 if (impl->cursorIsInContainer(this)) {
auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
New visualization classes for the drag&drop
r841 dragWidget->setVisible(false);
}
}
Format changes
r847 // Note: The exec() is blocking on windows but not on linux and macOS
New visualization classes for the drag&drop
r841 drag->exec(Qt::MoveAction | Qt::CopyAction);
}
void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
{
Format changes
r847 if (impl->acceptMimeData(event->mimeData())) {
New visualization classes for the drag&drop
r841 event->acceptProposedAction();
Format changes
r847 auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r841
Format changes
r847 if (!impl->hasPlaceHolder()) {
New visualization classes for the drag&drop
r841 auto dragWidget = helper.getCurrentDragWidget();
Format changes
r847 auto parentWidget
= qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
if (parentWidget) {
New visualization classes for the drag&drop
r841 dragWidget->setVisible(false);
}
auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
Format changes
r847 if (dragWidgetHovered) {
auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
hoveredWidgetIndex
+= 1; // Correction of the index if the drop occurs in the same container
}
New visualization classes for the drag&drop
r841
Format changes
r847 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
New visualization classes for the drag&drop
r841 }
Format changes
r847 else {
helper.insertPlaceHolder(impl->m_Layout, 0);
New visualization classes for the drag&drop
r841 }
}
}
else
event->ignore();
QWidget::dragEnterEvent(event);
}
void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
{
Q_UNUSED(event);
Format changes
r847 auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r841
Format changes
r847 if (!impl->cursorIsInContainer(this)) {
New visualization classes for the drag&drop
r841 helper.removePlaceHolder();
bool isInternal = true;
Format changes
r847 if (isInternal) {
// Only if the drag is strated from the visualization
// Show the drag widget at its original place
// So the drag widget doesn't stay hidden if the drop occurs outside the visualization
// drop zone (It is not possible to catch a drop event outside of the application)
New visualization classes for the drag&drop
r841
auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
Format changes
r847 if (dragWidget) {
New visualization classes for the drag&drop
r841 dragWidget->setVisible(true);
}
}
}
QWidget::dragLeaveEvent(event);
}
void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
{
Format changes
r847 if (impl->acceptMimeData(event->mimeData())) {
New visualization classes for the drag&drop
r841 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
Format changes
r847 if (dragWidgetHovered) {
New visualization classes for the drag&drop
r841 auto canMerge = impl->allowMergeMimeData(event->mimeData());
auto nbDragWidget = countDragWidget();
Format changes
r847 if (nbDragWidget > 0) {
New visualization classes for the drag&drop
r841 auto graphHeight = size().height() / nbDragWidget;
auto dropIndex = floor(event->pos().y() / graphHeight);
auto zoneSize = qMin(graphHeight / 3.0, 150.0);
auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
Format changes
r847 auto &helper = sqpApp->dragDropHelper();
auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
New visualization classes for the drag&drop
r841
Format changes
r847 if (isOnTop || isOnBottom) {
if (isOnBottom) {
New visualization classes for the drag&drop
r841 dropIndex += 1;
Format changes
r847 }
New visualization classes for the drag&drop
r841
Format changes
r847 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
dropIndex += 1; // Correction of the index if the drop occurs in the same
// container
}
New visualization classes for the drag&drop
r841
Format changes
r847 if (dropIndex != placeHolderIndex) {
helper.insertPlaceHolder(impl->m_Layout, dropIndex);
New visualization classes for the drag&drop
r841 }
}
Format changes
r847 else if (canMerge) {
// drop on the middle -> merge
if (impl->hasPlaceHolder()) {
New visualization classes for the drag&drop
r841 helper.removePlaceHolder();
}
}
}
}
}
else
event->ignore();
QWidget::dragMoveEvent(event);
}
void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
{
Format changes
r847 if (impl->acceptMimeData(event->mimeData())) {
New visualization classes for the drag&drop
r841 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
Format changes
r847 if (impl->hasPlaceHolder() && dragWidget) {
auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r841
Format changes
r847 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
New visualization classes for the drag&drop
r841
Format changes
r847 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
droppedIndex
-= 1; // Correction of the index if the drop occurs in the same container
}
New visualization classes for the drag&drop
r841
dragWidget->setVisible(true);
dragWidget->setStyleSheet("");
event->acceptProposedAction();
helper.removePlaceHolder();
emit dropOccured(droppedIndex, event->mimeData());
}
}
else
event->ignore();
QWidget::dropEvent(event);
}