##// END OF EJS Templates
New visualization classes for the drag&drop
trabillard -
r838:7a8534096878
parent child
Show More
@@ -0,0 +1,45
1 #ifndef VISUALIZATIONDRAGDROPCONTAINER_H
2 #define VISUALIZATIONDRAGDROPCONTAINER_H
3
4 #include <QWidget>
5 #include <QVBoxLayout>
6 #include <QMimeData>
7 #include <Common/spimpl.h>
8
9 class VisualizationDragWidget;
10
11 class VisualizationDragDropContainer : public QWidget
12 {
13 Q_OBJECT
14
15 signals:
16 void dropOccured(int dropIndex, const QMimeData* mimeData);
17
18 public:
19 VisualizationDragDropContainer(QWidget* parent = nullptr);
20
21 void addDragWidget(VisualizationDragWidget* dragWidget);
22 void insertDragWidget(int index, VisualizationDragWidget* dragWidget);
23
24 void setAcceptedMimeTypes(const QStringList& mimeTypes);
25 void setMergeAllowedMimeTypes(const QStringList& mimeTypes);
26
27 int countDragWidget() const;
28
29 protected:
30 void dragEnterEvent(QDragEnterEvent *event);
31 void dragLeaveEvent(QDragLeaveEvent *event);
32 void dragMoveEvent(QDragMoveEvent *event);
33 void dropEvent(QDropEvent *event);
34
35 private:
36
37
38 class VisualizationDragDropContainerPrivate;
39 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
40
41 private slots:
42 void startDrag(VisualizationDragWidget* dragWidget, const QPoint& dragPosition);
43 };
44
45 #endif // VISUALIZATIONDRAGDROPCONTAINER_H
@@ -0,0 +1,30
1 #ifndef VISUALIZATIONDRAGWIDGET_H
2 #define VISUALIZATIONDRAGWIDGET_H
3
4 #include <QWidget>
5 #include <QMimeData>
6 #include <Common/spimpl.h>
7
8 class VisualizationDragWidget : public QWidget
9 {
10 Q_OBJECT
11
12 public:
13 VisualizationDragWidget(QWidget* parent = nullptr);
14
15 virtual QMimeData* mimeData() const = 0;
16 virtual bool isDragAllowed() const = 0;
17
18 protected:
19 virtual void mousePressEvent(QMouseEvent *event) override;
20 virtual void mouseMoveEvent(QMouseEvent *event) override;
21
22 private:
23 class VisualizationDragWidgetPrivate;
24 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
25
26 signals:
27 void dragDetected(VisualizationDragWidget* dragWidget, const QPoint& dragPosition);
28 };
29
30 #endif // VISUALIZATIONDRAGWIDGET_H
@@ -0,0 +1,312
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "Visualization/VisualizationDragWidget.h"
3 #include "SqpApplication.h"
4 #include "DragDropHelper.h"
5
6 #include <QDrag>
7 #include <QVBoxLayout>
8 #include <QDragEnterEvent>
9
10 #include <memory>
11
12 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
13
14 QVBoxLayout* m_layout;
15 QStringList m_acceptedMimeTypes;
16 QStringList m_mergeAllowedMimeTypes;
17
18 explicit VisualizationDragDropContainerPrivate(QWidget* widget)
19 {
20 m_layout = new QVBoxLayout(widget);
21 m_layout->setContentsMargins(0,0,0,0);
22 }
23
24 bool acceptMimeData(const QMimeData* data) const
25 {
26 for (const auto& type : m_acceptedMimeTypes)
27 {
28 if (data->hasFormat(type))
29 return true;
30 }
31
32 return false;
33 }
34
35 bool allowMergeMimeData(const QMimeData* data) const
36 {
37 for (const auto& type : m_mergeAllowedMimeTypes)
38 {
39 if (data->hasFormat(type))
40 return true;
41 }
42
43 return false;
44 }
45
46 bool hasPlaceHolder() const
47 {
48 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_layout->parentWidget();
49 }
50
51 VisualizationDragWidget* getChildDragWidgetAt(QWidget* parent, const QPoint &pos) const
52 {
53 VisualizationDragWidget* dragWidget = nullptr;
54
55 for (auto child : parent->children())
56 {
57 auto widget = qobject_cast<VisualizationDragWidget*>(child);
58 if (widget && widget->isVisible())
59 {
60 if (widget->frameGeometry().contains(pos))
61 {
62 dragWidget = widget;
63 break;
64 }
65 }
66 }
67
68 return dragWidget;
69 }
70
71 bool cursorIsInContainer(QWidget* container) const
72 {
73 auto adustNum = 18; //to be safe, in case of scrollbar on the side
74 auto containerRect = QRect(QPoint(), container->contentsRect().size()).adjusted(adustNum, adustNum, -adustNum, -adustNum);
75 qDebug() << containerRect << container->mapFromGlobal(QCursor::pos());
76 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
77 }
78
79 };
80
81 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
82 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
83 {
84 setAcceptDrops(true);
85 }
86
87 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
88 {
89 impl->m_layout->addWidget(dragWidget);
90 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
91 connect(dragWidget, &VisualizationDragWidget::dragDetected, this, &VisualizationDragDropContainer::startDrag);
92 }
93
94 void VisualizationDragDropContainer::insertDragWidget(int index, VisualizationDragWidget *dragWidget)
95 {
96 impl->m_layout->insertWidget(index, dragWidget);
97 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
98 connect(dragWidget, &VisualizationDragWidget::dragDetected, this, &VisualizationDragDropContainer::startDrag);
99 }
100
101 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
102 {
103 impl->m_acceptedMimeTypes = mimeTypes;
104 }
105
106 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
107 {
108 impl->m_mergeAllowedMimeTypes = mimeTypes;
109 }
110
111 int VisualizationDragDropContainer::countDragWidget() const
112 {
113 auto nbGraph = 0;
114 for (auto child : children())
115 {
116 auto widget = qobject_cast<VisualizationDragWidget*>(child);
117 if (widget)
118 {
119 nbGraph += 1;
120 }
121 }
122
123 return nbGraph;
124 }
125
126 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition)
127 {
128 auto& helper = sqpApp->dragDropHelper();
129
130 //Note: The management of the drag object is done by Qt
131 auto *drag = new QDrag{dragWidget};
132 drag->setHotSpot(dragPosition);
133
134 auto mimeData = dragWidget->mimeData();
135 drag->setMimeData(mimeData);
136
137 auto pixmap = QPixmap(dragWidget->size());
138 dragWidget->render(&pixmap);
139 drag->setPixmap(pixmap);
140
141 auto image = pixmap.toImage();
142 mimeData->setImageData(image);
143 mimeData->setUrls({helper.imageTemporaryUrl(image)});
144
145 if (impl->m_layout->indexOf(dragWidget) >= 0)
146 {
147 helper.setCurrentDragWidget(dragWidget);
148
149 if (impl->cursorIsInContainer(this))
150 {
151 auto dragWidgetIndex = impl->m_layout->indexOf(dragWidget);
152 helper.insertPlaceHolder(impl->m_layout, dragWidgetIndex);
153 dragWidget->setVisible(false);
154 }
155 }
156
157 //Note: The exec() is blocking on windows but not on linux and macOS
158 drag->exec(Qt::MoveAction | Qt::CopyAction);
159 }
160
161 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
162 {
163 if (impl->acceptMimeData(event->mimeData()))
164 {
165 event->acceptProposedAction();
166
167 auto& helper = sqpApp->dragDropHelper();
168
169 if (!impl->hasPlaceHolder())
170 {
171 auto dragWidget = helper.getCurrentDragWidget();
172 auto parentWidget = qobject_cast<VisualizationDragDropContainer*>(dragWidget->parentWidget());
173 if (parentWidget)
174 {
175 dragWidget->setVisible(false);
176 }
177
178 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
179
180 if (dragWidgetHovered)
181 {
182 auto hoveredWidgetIndex = impl->m_layout->indexOf(dragWidgetHovered);
183 auto dragWidgetIndex = impl->m_layout->indexOf(helper.getCurrentDragWidget());
184 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex)
185 hoveredWidgetIndex += 1; //Correction of the index if the drop occurs in the same container
186
187 helper.insertPlaceHolder(impl->m_layout, hoveredWidgetIndex);
188 }
189 else
190 {
191 helper.insertPlaceHolder(impl->m_layout, 0);
192 }
193 }
194 }
195 else
196 event->ignore();
197
198 QWidget::dragEnterEvent(event);
199 }
200
201 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
202 {
203 Q_UNUSED(event);
204
205 auto& helper = sqpApp->dragDropHelper();
206
207 if (!impl->cursorIsInContainer(this))
208 {
209 helper.removePlaceHolder();
210
211 bool isInternal = true;
212 if (isInternal)
213 {
214 //Only if the drag is strated from the visualization
215 //Show the drag widget at its original place
216 //So the drag widget doesn't stay hidden if the drop occurs outside the visualization drop zone
217 //(It is not possible to catch a drop event outside of the application)
218
219 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
220 if (dragWidget)
221 {
222 dragWidget->setVisible(true);
223 }
224 }
225 }
226
227 QWidget::dragLeaveEvent(event);
228 }
229
230 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
231 {
232 if (impl->acceptMimeData(event->mimeData()))
233 {
234 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
235 if (dragWidgetHovered)
236 {
237 auto canMerge = impl->allowMergeMimeData(event->mimeData());
238
239 auto nbDragWidget = countDragWidget();
240 if (nbDragWidget > 0)
241 {
242 auto graphHeight = size().height() / nbDragWidget;
243 auto dropIndex = floor(event->pos().y() / graphHeight);
244 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
245
246 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
247 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
248
249 auto& helper = sqpApp->dragDropHelper();
250 auto placeHolderIndex = impl->m_layout->indexOf(&(helper.placeHolder()));
251
252 if (isOnTop || isOnBottom)
253 {
254 if (isOnBottom)
255 dropIndex += 1;
256
257 auto dragWidgetIndex = impl->m_layout->indexOf(helper.getCurrentDragWidget());
258 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex)
259 dropIndex += 1; //Correction of the index if the drop occurs in the same container
260
261 if (dropIndex != placeHolderIndex)
262 {
263 helper.insertPlaceHolder(impl->m_layout, dropIndex);
264 }
265 }
266 else if (canMerge)
267 {
268 //drop on the middle -> merge
269 if (impl->hasPlaceHolder())
270 {
271 helper.removePlaceHolder();
272 }
273 }
274 }
275 }
276 }
277 else
278 event->ignore();
279
280 QWidget::dragMoveEvent(event);
281 }
282
283 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
284 {
285 if (impl->acceptMimeData(event->mimeData()))
286 {
287 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
288 if (impl->hasPlaceHolder() && dragWidget)
289 {
290 auto& helper = sqpApp->dragDropHelper();
291
292 auto droppedIndex = impl->m_layout->indexOf(&helper.placeHolder());
293
294 auto dragWidgetIndex = impl->m_layout->indexOf(dragWidget);
295 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex)
296 droppedIndex -= 1; //Correction of the index if the drop occurs in the same container
297
298 dragWidget->setVisible(true);
299 dragWidget->setStyleSheet("");
300
301 event->acceptProposedAction();
302
303 helper.removePlaceHolder();
304
305 emit dropOccured(droppedIndex, event->mimeData());
306 }
307 }
308 else
309 event->ignore();
310
311 QWidget::dropEvent(event);
312 }
@@ -0,0 +1,50
1 #include "Visualization/VisualizationDragWidget.h"
2 #include "Visualization/VisualizationDragDropContainer.h"
3
4 #include <QMouseEvent>
5 #include <QApplication>
6
7 struct VisualizationDragWidget::VisualizationDragWidgetPrivate {
8
9 QPoint m_dragStartPosition;
10 bool m_dragStartPositionValid = false;
11
12 explicit VisualizationDragWidgetPrivate()
13 {
14 }
15 };
16
17 VisualizationDragWidget::VisualizationDragWidget(QWidget* parent)
18 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragWidgetPrivate>()}
19 {
20
21 }
22
23 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
24 {
25 if (event->button() == Qt::LeftButton)
26 impl->m_dragStartPosition = event->pos();
27
28 impl->m_dragStartPositionValid = isDragAllowed();
29
30 QWidget::mousePressEvent(event);
31 }
32
33 void VisualizationDragWidget::mouseMoveEvent(QMouseEvent *event)
34 {
35 if (!impl->m_dragStartPositionValid || !isDragAllowed())
36 return;
37
38 if (!(event->buttons() & Qt::LeftButton))
39 return;
40
41 if (!event->modifiers().testFlag(Qt::AltModifier))
42 return;
43
44 if ((event->pos() - impl->m_dragStartPosition).manhattanLength() < QApplication::startDragDistance())
45 return;
46
47 emit dragDetected(this, impl->m_dragStartPosition);
48
49 QWidget::mouseMoveEvent(event);
50 }
General Comments 0
You need to be logged in to leave comments. Login now