##// END OF EJS Templates
Manage the scroll of the tab QScrollArea during a drag&drop operation
trabillard -
r843:8d32ce09be20
parent child
Show More
@@ -10,6 +10,31 class VisualizationDragWidget;
10 class QMimeData;
10 class QMimeData;
11
11
12 /**
12 /**
13 * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation.
14 * @note A QScrollArea inside an other QScrollArea is not fully supported.
15 */
16 class DragDropScroller : public QObject
17 {
18 Q_OBJECT
19
20 public:
21 DragDropScroller(QObject* parent = nullptr);
22
23 void addScrollArea(QScrollArea* scrollArea);
24 void removeScrollArea(QScrollArea* scrollArea);
25
26 protected:
27 bool eventFilter(QObject *obj, QEvent *event);
28
29 private:
30 class DragDropScrollerPrivate;
31 spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl;
32
33 private slots:
34 void onTimer();
35 };
36
37 /**
13 * @brief Helper class for drag&drop operations.
38 * @brief Helper class for drag&drop operations.
14 */
39 */
15 class DragDropHelper
40 class DragDropHelper
@@ -13,6 +13,139
13 const QString DragDropHelper::MIME_TYPE_GRAPH = "scqlop/graph";
13 const QString DragDropHelper::MIME_TYPE_GRAPH = "scqlop/graph";
14 const QString DragDropHelper::MIME_TYPE_ZONE = "scqlop/zone";
14 const QString DragDropHelper::MIME_TYPE_ZONE = "scqlop/zone";
15
15
16 const int SCROLL_SPEED = 5;
17 const int SCROLL_ZONE_SIZE = 50;
18
19 struct DragDropScroller::DragDropScrollerPrivate {
20
21 QList<QScrollArea*> m_scrollAreas;
22 QScrollArea* m_currentScrollArea = nullptr;
23 std::unique_ptr<QTimer> m_timer = nullptr;
24
25
26 enum class ScrollDirection {up, down, unknown};
27 ScrollDirection m_direction = ScrollDirection::unknown;
28
29 explicit DragDropScrollerPrivate()
30 : m_timer{std::make_unique<QTimer>()}
31 {
32 m_timer->setInterval(0);
33 }
34 };
35
36 DragDropScroller::DragDropScroller(QObject* parent)
37 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
38 {
39 connect(impl->m_timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
40 }
41
42 void DragDropScroller::addScrollArea(QScrollArea* scrollArea)
43 {
44 impl->m_scrollAreas << scrollArea;
45 scrollArea->viewport()->setAcceptDrops(true);
46 }
47
48 void DragDropScroller::removeScrollArea(QScrollArea* scrollArea)
49 {
50 impl->m_scrollAreas.removeAll(scrollArea);
51 scrollArea->viewport()->setAcceptDrops(false);
52 }
53
54 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
55 {
56 if (event->type() == QEvent::DragMove)
57 {
58 auto w = static_cast<QWidget*>(obj);
note

I think it's better to test if the cast success. For that you need a dynamic_cast

note

In case of a DragMove, Qt ensure the object will always be a QWidget.

59
60 if (impl->m_currentScrollArea && impl->m_currentScrollArea->isAncestorOf(w))
61 {
62 auto moveEvent = static_cast<QDragMoveEvent*>(event);
63
64 auto pos = moveEvent->pos();
65 if (impl->m_currentScrollArea->viewport() != w)
66 {
67 auto globalPos = w->mapToGlobal(moveEvent->pos());
68 pos = impl->m_currentScrollArea->viewport()->mapFromGlobal(globalPos);
69 }
70
71 auto isInTopZone = pos.y() > impl->m_currentScrollArea->viewport()->size().height() - SCROLL_ZONE_SIZE;
72 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
73
74 if (!isInTopZone && !isInBottomZone)
75 {
76 impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown;
77 impl->m_timer->stop();
78 }
79 else if (!impl->m_timer->isActive())
80 {
81 impl->m_direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up : DragDropScrollerPrivate::ScrollDirection::down;
82 impl->m_timer->start();
83 }
84 }
85 }
86 else if (event->type() == QEvent::DragEnter)
87 {
88 auto w = static_cast<QWidget*>(obj);
89
90 for (auto scrollArea : impl-> m_scrollAreas)
91 {
92 if (impl->m_currentScrollArea != scrollArea && scrollArea->isAncestorOf(w))
93 {
94 auto enterEvent = static_cast<QDragEnterEvent*>(event);
95 enterEvent->acceptProposedAction();
96 enterEvent->setDropAction(Qt::IgnoreAction);
97 impl->m_currentScrollArea = scrollArea;
98 break;
99 }
100 }
101 }
102 else if (event->type() == QEvent::DragLeave)
103 {
104 auto w = static_cast<QWidget*>(obj);
105 if (impl->m_currentScrollArea)
106 {
107 if (!QRect(QPoint(), impl->m_currentScrollArea->size()).contains(impl->m_currentScrollArea->mapFromGlobal(QCursor::pos())))
108 {
109 impl->m_currentScrollArea = nullptr;
110 impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown;
111 impl->m_timer->stop();
112 }
113 }
114 }
115 else if (event->type() == QEvent::Drop)
116 {
117 auto w = static_cast<QWidget*>(obj);
118 if (impl->m_currentScrollArea)
119 {
120 impl->m_currentScrollArea = nullptr;
121 impl->m_direction = DragDropScrollerPrivate::ScrollDirection::unknown;
122 impl->m_timer->stop();
123 }
124 }
125
126 return false;
127 }
128
129 void DragDropScroller::onTimer()
130 {
131 if (impl->m_currentScrollArea)
132 {
133 auto mvt = 0;
134 switch (impl->m_direction)
135 {
136 case DragDropScrollerPrivate::ScrollDirection::up:
137 mvt = SCROLL_SPEED;
138 break;
139 case DragDropScrollerPrivate::ScrollDirection::down:
140 mvt = -SCROLL_SPEED;
141 break;
142 default:
143 break;
144 }
145
146 impl->m_currentScrollArea->verticalScrollBar()->setValue(impl->m_currentScrollArea->verticalScrollBar()->value() + mvt);
147 }
148 }
16
149
17 struct DragDropHelper::DragDropHelperPrivate {
150 struct DragDropHelper::DragDropHelperPrivate {
18
151
@@ -97,6 +230,16 bool DragDropHelper::isPlaceHolderSet() const
97 return impl->m_placeHolder->parentWidget();
230 return impl->m_placeHolder->parentWidget();
98 }
231 }
99
232
233 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
234 {
235 impl->m_dragDropScroller->addScrollArea(scrollArea);
236 }
237
238 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
239 {
240 impl->m_dragDropScroller->removeScrollArea(scrollArea);
241 }
242
100 QUrl DragDropHelper::imageTemporaryUrl(const QImage& image) const
243 QUrl DragDropHelper::imageTemporaryUrl(const QImage& image) const
101 {
244 {
102 image.save(impl->m_imageTempUrl);
245 image.save(impl->m_imageTempUrl);
@@ -61,6 +61,7 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par
61
61
62 ui->dragDropContainer->setAcceptedMimeTypes({DragDropHelper::MIME_TYPE_GRAPH, DragDropHelper::MIME_TYPE_ZONE});
62 ui->dragDropContainer->setAcceptedMimeTypes({DragDropHelper::MIME_TYPE_GRAPH, DragDropHelper::MIME_TYPE_ZONE});
63 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this, &VisualizationTabWidget::dropMimeData);
63 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this, &VisualizationTabWidget::dropMimeData);
64 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
64
65
65 // Widget is deleted when closed
66 // Widget is deleted when closed
66 setAttribute(Qt::WA_DeleteOnClose);
67 setAttribute(Qt::WA_DeleteOnClose);
@@ -68,6 +69,7 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par
68
69
69 VisualizationTabWidget::~VisualizationTabWidget()
70 VisualizationTabWidget::~VisualizationTabWidget()
70 {
71 {
72 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
71 delete ui;
73 delete ui;
72 }
74 }
73
75
General Comments 6
Approved

Status change > Approved

You need to be logged in to leave comments. Login now