@@ -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); | |||
|
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 0
You need to be logged in to leave comments.
Login now