DragDropHelper.cpp
248 lines
| 7.4 KiB
| text/x-c
|
CppLexer
r837 | #include "DragDropHelper.h" | |||
#include "Visualization/VisualizationDragWidget.h" | ||||
#include "SqpApplication.h" | ||||
#include <QDragMoveEvent> | ||||
#include <QDragEnterEvent> | ||||
#include <QScrollBar> | ||||
#include <QScrollArea> | ||||
#include <QVBoxLayout> | ||||
#include <QTimer> | ||||
#include <QDir> | ||||
const QString DragDropHelper::MIME_TYPE_GRAPH = "scqlop/graph"; | ||||
const QString DragDropHelper::MIME_TYPE_ZONE = "scqlop/zone"; | ||||
r840 | const int SCROLL_SPEED = 5; | |||
const int SCROLL_ZONE_SIZE = 50; | ||||
struct DragDropScroller::DragDropScrollerPrivate { | ||||
QList<QScrollArea*> m_scrollAreas; | ||||
QScrollArea* m_currentScrollArea = nullptr; | ||||
std::unique_ptr<QTimer> m_timer = nullptr; | ||||
enum class ScrollDirection {up, down, unknown}; | ||||
ScrollDirection m_direction = ScrollDirection::unknown; | ||||
explicit DragDropScrollerPrivate() | ||||
: m_timer{std::make_unique<QTimer>()} | ||||
{ | ||||
m_timer->setInterval(0); | ||||
} | ||||
}; | ||||
DragDropScroller::DragDropScroller(QObject* parent) | ||||
: QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()} | ||||
{ | ||||
connect(impl->m_timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer); | ||||
} | ||||
void DragDropScroller::addScrollArea(QScrollArea* scrollArea) | ||||
{ | ||||
impl->m_scrollAreas << scrollArea; | ||||
scrollArea->viewport()->setAcceptDrops(true); | ||||
} | ||||
void DragDropScroller::removeScrollArea(QScrollArea* scrollArea) | ||||
{ | ||||
impl->m_scrollAreas.removeAll(scrollArea); | ||||
scrollArea->viewport()->setAcceptDrops(false); | ||||
} | ||||
bool DragDropScroller::eventFilter(QObject *obj, QEvent *event) | ||||
{ | ||||
if (event->type() == QEvent::DragMove) | ||||
{ | ||||
auto w = static_cast<QWidget*>(obj); | ||||
if (impl->m_currentScrollArea && impl->m_currentScrollArea->isAncestorOf(w)) | ||||
{ | ||||
auto moveEvent = static_cast<QDragMoveEvent*>(event); | ||||
auto pos = moveEvent->pos(); | ||||
if (impl->m_currentScrollArea->viewport() != w) | ||||
{ | ||||
auto globalPos = w->mapToGlobal(moveEvent->pos()); | ||||
pos = impl->m_currentScrollArea->viewport()->mapFromGlobal(globalPos); | ||||
} | ||||
auto isInTopZone = pos.y() > impl->m_currentScrollArea->viewport()->size().height() - SCROLL_ZONE_SIZE; | ||||
auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE; | ||||
if (!isInTopZone && !isInBottomZone) | ||||
{ | ||||
impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown; | ||||
impl->m_timer->stop(); | ||||
} | ||||
else if (!impl->m_timer->isActive()) | ||||
{ | ||||
impl->m_direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up : DragDropScrollerPrivate::ScrollDirection::down; | ||||
impl->m_timer->start(); | ||||
} | ||||
} | ||||
} | ||||
else if (event->type() == QEvent::DragEnter) | ||||
{ | ||||
auto w = static_cast<QWidget*>(obj); | ||||
for (auto scrollArea : impl-> m_scrollAreas) | ||||
{ | ||||
if (impl->m_currentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) | ||||
{ | ||||
auto enterEvent = static_cast<QDragEnterEvent*>(event); | ||||
enterEvent->acceptProposedAction(); | ||||
enterEvent->setDropAction(Qt::IgnoreAction); | ||||
impl->m_currentScrollArea = scrollArea; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
else if (event->type() == QEvent::DragLeave) | ||||
{ | ||||
auto w = static_cast<QWidget*>(obj); | ||||
if (impl->m_currentScrollArea) | ||||
{ | ||||
if (!QRect(QPoint(), impl->m_currentScrollArea->size()).contains(impl->m_currentScrollArea->mapFromGlobal(QCursor::pos()))) | ||||
{ | ||||
impl->m_currentScrollArea = nullptr; | ||||
impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown; | ||||
impl->m_timer->stop(); | ||||
} | ||||
} | ||||
} | ||||
else if (event->type() == QEvent::Drop) | ||||
{ | ||||
auto w = static_cast<QWidget*>(obj); | ||||
if (impl->m_currentScrollArea) | ||||
{ | ||||
impl->m_currentScrollArea = nullptr; | ||||
impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown; | ||||
impl->m_timer->stop(); | ||||
} | ||||
} | ||||
return false; | ||||
} | ||||
void DragDropScroller::onTimer() | ||||
{ | ||||
if (impl->m_currentScrollArea) | ||||
{ | ||||
auto mvt = 0; | ||||
switch (impl->m_direction) | ||||
{ | ||||
case DragDropScrollerPrivate::ScrollDirection::up: | ||||
mvt = SCROLL_SPEED; | ||||
break; | ||||
case DragDropScrollerPrivate::ScrollDirection::down: | ||||
mvt = -SCROLL_SPEED; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
impl->m_currentScrollArea->verticalScrollBar()->setValue(impl->m_currentScrollArea->verticalScrollBar()->value() + mvt); | ||||
} | ||||
} | ||||
r837 | ||||
struct DragDropHelper::DragDropHelperPrivate { | ||||
VisualizationDragWidget* m_currentDragWidget = nullptr; | ||||
std::unique_ptr<QWidget> m_placeHolder = nullptr; | ||||
std::unique_ptr<DragDropScroller> m_dragDropScroller = nullptr; | ||||
QString m_imageTempUrl; //Temporary file for image url generated by the drag & drop. Not using QTemporaryFile to have a name which is not generated. | ||||
explicit DragDropHelperPrivate() | ||||
: m_placeHolder{std::make_unique<QWidget>()}, | ||||
m_dragDropScroller{std::make_unique<DragDropScroller>()} | ||||
{ | ||||
m_placeHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4"); | ||||
sqpApp->installEventFilter(m_dragDropScroller.get()); | ||||
m_imageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png"); | ||||
} | ||||
void preparePlaceHolder() const | ||||
{ | ||||
if (m_currentDragWidget) | ||||
{ | ||||
m_placeHolder->setMinimumSize(m_currentDragWidget->size()); | ||||
m_placeHolder->setSizePolicy(m_currentDragWidget->sizePolicy()); | ||||
} | ||||
else | ||||
{ | ||||
m_placeHolder->setMinimumSize(200, 200); | ||||
} | ||||
} | ||||
}; | ||||
DragDropHelper::DragDropHelper() : | ||||
impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} | ||||
{ | ||||
} | ||||
DragDropHelper::~DragDropHelper() | ||||
{ | ||||
QFile::remove(impl->m_imageTempUrl); | ||||
} | ||||
void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget) | ||||
{ | ||||
impl->m_currentDragWidget = dragWidget; | ||||
} | ||||
VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const | ||||
{ | ||||
return impl->m_currentDragWidget; | ||||
} | ||||
QWidget& DragDropHelper::placeHolder() const | ||||
{ | ||||
return *impl->m_placeHolder; | ||||
} | ||||
void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index) | ||||
{ | ||||
removePlaceHolder(); | ||||
impl->preparePlaceHolder(); | ||||
layout->insertWidget(index, impl->m_placeHolder.get()); | ||||
impl->m_placeHolder->show(); | ||||
} | ||||
void DragDropHelper::removePlaceHolder() | ||||
{ | ||||
auto parentWidget = impl->m_placeHolder->parentWidget(); | ||||
if (parentWidget) | ||||
{ | ||||
parentWidget->layout()->removeWidget(impl->m_placeHolder.get()); | ||||
impl->m_placeHolder->setParent(nullptr); | ||||
impl->m_placeHolder->hide(); | ||||
} | ||||
} | ||||
bool DragDropHelper::isPlaceHolderSet() const | ||||
{ | ||||
return impl->m_placeHolder->parentWidget(); | ||||
} | ||||
r840 | void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea) | |||
{ | ||||
impl->m_dragDropScroller->addScrollArea(scrollArea); | ||||
} | ||||
void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea) | ||||
{ | ||||
impl->m_dragDropScroller->removeScrollArea(scrollArea); | ||||
} | ||||
r837 | QUrl DragDropHelper::imageTemporaryUrl(const QImage& image) const | |||
{ | ||||
image.save(impl->m_imageTempUrl); | ||||
return QUrl::fromLocalFile(impl->m_imageTempUrl); | ||||
} | ||||