##// END OF EJS Templates
Visual display when dropping on top of a existing graph
trabillard -
r857:8c8decf98df7
parent child
Show More
@@ -1,85 +1,87
1 1 #ifndef SCIQLOP_DRAGDROPHELPER_H
2 2 #define SCIQLOP_DRAGDROPHELPER_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QLoggingCategory>
6 6 #include <QWidget>
7 7
8 8 class QVBoxLayout;
9 9 class QScrollArea;
10 10 class VisualizationDragWidget;
11 11 class VisualizationDragDropContainer;
12 12 class QMimeData;
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
15 15
16 16 /**
17 17 * @brief Helper class for drag&drop operations.
18 18 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
19 19 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
20 20 * can interect with the gui.
21 21 * @see SqpApplication
22 22 */
23 23 class DragDropHelper {
24 24 public:
25 25 static const QString MIME_TYPE_GRAPH;
26 26 static const QString MIME_TYPE_ZONE;
27 27
28 28 DragDropHelper();
29 29 virtual ~DragDropHelper();
30 30
31 31 /// Resets some internal variables. Must be called before any new drag&drop operation.
32 32 void resetDragAndDrop();
33 33
34 34 /// Sets the visualization widget currently being drag on the visualization.
35 35 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
36 36
37 37 /// Returns the visualization widget currently being drag on the visualization.
38 38 /// Can be null if a new visualization widget is intended to be created by the drag&drop
39 39 /// operation.
40 40 VisualizationDragWidget *getCurrentDragWidget() const;
41 41
42 42 QWidget &placeHolder() const;
43 43 void insertPlaceHolder(QVBoxLayout *layout, int index);
44 44 void removePlaceHolder();
45 45 bool isPlaceHolderSet() const;
46 46
47 47 /// Checks if the specified mime data is valid for a drop in the visualization
48 48 bool checkMimeDataForVisualization(const QMimeData *mimeData,
49 49 VisualizationDragDropContainer *dropContainer);
50 50
51 51 void addDragDropScrollArea(QScrollArea *scrollArea);
52 52 void removeDragDropScrollArea(QScrollArea *scrollArea);
53 53
54 54 QUrl imageTemporaryUrl(const QImage &image) const;
55 55
56 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
57
56 58 private:
57 59 class DragDropHelperPrivate;
58 60 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
59 61 };
60 62
61 63 /**
62 64 * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation.
63 65 * @note A QScrollArea inside an other QScrollArea is not fully supported.
64 66 */
65 67 class DragDropScroller : public QObject {
66 68 Q_OBJECT
67 69
68 70 public:
69 71 DragDropScroller(QObject *parent = nullptr);
70 72
71 73 void addScrollArea(QScrollArea *scrollArea);
72 74 void removeScrollArea(QScrollArea *scrollArea);
73 75
74 76 protected:
75 77 bool eventFilter(QObject *obj, QEvent *event);
76 78
77 79 private:
78 80 class DragDropScrollerPrivate;
79 81 spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl;
80 82
81 83 private slots:
82 84 void onTimer();
83 85 };
84 86
85 87 #endif // SCIQLOP_DRAGDROPHELPER_H
@@ -1,29 +1,30
1 1 #ifndef SCIQLOP_VISUALIZATIONDRAGWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONDRAGWIDGET_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QMimeData>
6 6 #include <QWidget>
7 7
8 8 class VisualizationDragWidget : public QWidget {
9 9 Q_OBJECT
10 10
11 11 public:
12 12 VisualizationDragWidget(QWidget *parent = nullptr);
13 13
14 14 virtual QMimeData *mimeData() const = 0;
15 15 virtual bool isDragAllowed() const = 0;
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); };
16 17
17 18 protected:
18 19 virtual void mousePressEvent(QMouseEvent *event) override;
19 20 virtual void mouseMoveEvent(QMouseEvent *event) override;
20 21
21 22 private:
22 23 class VisualizationDragWidgetPrivate;
23 24 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
24 25
25 26 signals:
26 27 void dragDetected(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
27 28 };
28 29
29 30 #endif // SCIQLOP_VISUALIZATIONDRAGWIDGET_H
@@ -1,107 +1,108
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5 #include "Visualization/VisualizationDragWidget.h"
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QWidget>
9 9
10 10 #include <memory>
11 11
12 12 #include <Common/spimpl.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15 15
16 16 class QCPRange;
17 17 class QCustomPlot;
18 18 class SqpRange;
19 19 class Variable;
20 20 class VisualizationZoneWidget;
21 21
22 22 namespace Ui {
23 23 class VisualizationGraphWidget;
24 24 } // namespace Ui
25 25
26 26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
27 27 Q_OBJECT
28 28
29 29 friend class QCustomPlotSynchronizer;
30 30 friend class VisualizationGraphRenderingDelegate;
31 31
32 32 public:
33 33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 34 virtual ~VisualizationGraphWidget();
35 35
36 36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
37 37
38 38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
39 39 void enableAcquisition(bool enable);
40 40
41 41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
42 42
43 43 /// Removes a variable from the graph
44 44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
45 45
46 46 /// Returns the list of all variables used in the graph
47 47 QList<std::shared_ptr<Variable> > variables() const;
48 48
49 49 void setYRange(const SqpRange &range);
50 50 SqpRange graphRange() const noexcept;
51 51 void setGraphRange(const SqpRange &range);
52 52
53 53 // IVisualizationWidget interface
54 54 void accept(IVisualizationWidgetVisitor *visitor) override;
55 55 bool canDrop(const Variable &variable) const override;
56 56 bool contains(const Variable &variable) const override;
57 57 QString name() const override;
58 58
59 59 // VisualisationDragWidget
60 60 QMimeData *mimeData() const override;
61 61 bool isDragAllowed() const override;
62 void highlightForMerge(bool highlighted) override;
62 63
63 64 signals:
64 65 void synchronize(const SqpRange &range, const SqpRange &oldRange);
65 66 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
66 67 bool synchronise);
67 68
68 69 /// Signal emitted when the variable is about to be removed from the graph
69 70 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
70 71 /// Signal emitted when the variable has been added to the graph
71 72 void variableAdded(std::shared_ptr<Variable> var);
72 73
73 74 protected:
74 75 void closeEvent(QCloseEvent *event) override;
75 76 void enterEvent(QEvent *event) override;
76 77 void leaveEvent(QEvent *event) override;
77 78
78 79 QCustomPlot &plot() noexcept;
79 80
80 81 private:
81 82 Ui::VisualizationGraphWidget *ui;
82 83
83 84 class VisualizationGraphWidgetPrivate;
84 85 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
85 86
86 87 private slots:
87 88 /// Slot called when right clicking on the graph (displays a menu)
88 89 void onGraphMenuRequested(const QPoint &pos) noexcept;
89 90
90 91 /// Rescale the X axe to range parameter
91 92 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
92 93
93 94 /// Slot called when a mouse move was made
94 95 void onMouseMove(QMouseEvent *event) noexcept;
95 96 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
96 97 void onMouseWheel(QWheelEvent *event) noexcept;
97 98 /// Slot called when a mouse press was made, to activate the calibration of a graph
98 99 void onMousePress(QMouseEvent *event) noexcept;
99 100 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
100 101 void onMouseRelease(QMouseEvent *event) noexcept;
101 102
102 103 void onDataCacheVariableUpdated();
103 104
104 105 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
105 106 };
106 107
107 108 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,289 +1,301
1 1 #include "DragDropHelper.h"
2 2 #include "SqpApplication.h"
3 3 #include "Visualization/VisualizationDragDropContainer.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5 #include "Visualization/VisualizationWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7
8 8 #include "Variable/VariableController.h"
9 9
10 10 #include "Common/MimeTypesDef.h"
11 11 #include "Common/VisualizationDef.h"
12 12
13 13 #include <QDir>
14 14 #include <QDragEnterEvent>
15 15 #include <QDragMoveEvent>
16 16 #include <QScrollArea>
17 17 #include <QScrollBar>
18 18 #include <QTimer>
19 19 #include <QVBoxLayout>
20 20
21 21 const int SCROLL_SPEED = 5;
22 22 const int SCROLL_ZONE_SIZE = 50;
23 23
24 24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25 25
26 26 struct DragDropScroller::DragDropScrollerPrivate {
27 27
28 28 QList<QScrollArea *> m_ScrollAreas;
29 29 QScrollArea *m_CurrentScrollArea = nullptr;
30 30 std::unique_ptr<QTimer> m_Timer = nullptr;
31 31
32
33 32 enum class ScrollDirection { up, down, unknown };
34 33 ScrollDirection m_Direction = ScrollDirection::unknown;
35 34
36 35 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 36 {
38 37 m_Timer->setInterval(0);
39 38 }
40 39 };
41 40
42 41 DragDropScroller::DragDropScroller(QObject *parent)
43 42 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 43 {
45 44 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 45 }
47 46
48 47 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 48 {
50 49 impl->m_ScrollAreas << scrollArea;
51 50 scrollArea->viewport()->setAcceptDrops(true);
52 51 }
53 52
54 53 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 54 {
56 55 impl->m_ScrollAreas.removeAll(scrollArea);
57 56 scrollArea->viewport()->setAcceptDrops(false);
58 57 }
59 58
60 59 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 60 {
62 61 if (event->type() == QEvent::DragMove) {
63 62 auto w = static_cast<QWidget *>(obj);
64 63
65 64 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 65 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67 66
68 67 auto pos = moveEvent->pos();
69 68 if (impl->m_CurrentScrollArea->viewport() != w) {
70 69 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 70 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 71 }
73 72
74 73 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 74 - SCROLL_ZONE_SIZE;
76 75 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77 76
78 77 if (!isInTopZone && !isInBottomZone) {
79 78 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 79 impl->m_Timer->stop();
81 80 }
82 81 else if (!impl->m_Timer->isActive()) {
83 82 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 83 : DragDropScrollerPrivate::ScrollDirection::down;
85 84 impl->m_Timer->start();
86 85 }
87 86 }
88 87 }
89 88 else if (event->type() == QEvent::DragEnter) {
90 89 auto w = static_cast<QWidget *>(obj);
91 90
92 91 for (auto scrollArea : impl->m_ScrollAreas) {
93 92 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 93 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 94 enterEvent->acceptProposedAction();
96 95 enterEvent->setDropAction(Qt::IgnoreAction);
97 96 impl->m_CurrentScrollArea = scrollArea;
98 97 break;
99 98 }
100 99 }
101 100 }
102 101 else if (event->type() == QEvent::DragLeave) {
103 102 if (impl->m_CurrentScrollArea) {
104 103 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 104 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 105 impl->m_CurrentScrollArea = nullptr;
107 106 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 107 impl->m_Timer->stop();
109 108 }
110 109 }
111 110 }
112 111 else if (event->type() == QEvent::Drop) {
113 112 if (impl->m_CurrentScrollArea) {
114 113 impl->m_CurrentScrollArea = nullptr;
115 114 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 115 impl->m_Timer->stop();
117 116 }
118 117 }
119 118
120 119 return false;
121 120 }
122 121
123 122 void DragDropScroller::onTimer()
124 123 {
125 124 if (impl->m_CurrentScrollArea) {
126 125 auto mvt = 0;
127 126 switch (impl->m_Direction) {
128 127 case DragDropScrollerPrivate::ScrollDirection::up:
129 128 mvt = SCROLL_SPEED;
130 129 break;
131 130 case DragDropScrollerPrivate::ScrollDirection::down:
132 131 mvt = -SCROLL_SPEED;
133 132 break;
134 133 default:
135 134 break;
136 135 }
137 136
138 137 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 138 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 139 }
141 140 }
142 141
143 142 struct DragDropHelper::DragDropHelperPrivate {
144 143
145 144 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 145 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 146 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
148 147 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
149 148 // QTemporaryFile to have a name which is not generated.
150 149
150 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
151
151 152 explicit DragDropHelperPrivate()
152 153 : m_PlaceHolder{std::make_unique<QWidget>()},
153 154 m_DragDropScroller{std::make_unique<DragDropScroller>()}
154 155 {
155 156 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
156 157 sqpApp->installEventFilter(m_DragDropScroller.get());
157 158
158 159
159 160 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
160 161 }
161 162
162 163 void preparePlaceHolder() const
163 164 {
164 165 if (m_CurrentDragWidget) {
165 166 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
166 167 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
167 168 }
168 169 else {
169 170 // Configuration of the placeHolder when there is no dragWidget
170 171 // (for instance with a drag from a variable)
171 172
172 173 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
173 174 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 175 }
175 176 }
176 177 };
177 178
178 179
179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
180 {
181 }
180 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
182 181
183 182 DragDropHelper::~DragDropHelper()
184 183 {
185 184 QFile::remove(impl->m_ImageTempUrl);
186 185 }
187 186
188 187 void DragDropHelper::resetDragAndDrop()
189 188 {
190 189 setCurrentDragWidget(nullptr);
190 impl->m_HighlightedDragWidget = nullptr;
191 191 }
192 192
193 193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
194 194 {
195 195 impl->m_CurrentDragWidget = dragWidget;
196 196 }
197 197
198 198 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
199 199 {
200 200 return impl->m_CurrentDragWidget;
201 201 }
202 202
203 203
204 204 QWidget &DragDropHelper::placeHolder() const
205 205 {
206 206 return *impl->m_PlaceHolder;
207 207 }
208 208
209 209 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
210 210 {
211 211 removePlaceHolder();
212 212 impl->preparePlaceHolder();
213 213 layout->insertWidget(index, impl->m_PlaceHolder.get());
214 214 impl->m_PlaceHolder->show();
215 215 }
216 216
217 217 void DragDropHelper::removePlaceHolder()
218 218 {
219 219 auto parentWidget = impl->m_PlaceHolder->parentWidget();
220 220 if (parentWidget) {
221 221 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
222 222 impl->m_PlaceHolder->setParent(nullptr);
223 223 impl->m_PlaceHolder->hide();
224 224 }
225 225 }
226 226
227 227 bool DragDropHelper::isPlaceHolderSet() const
228 228 {
229 229 return impl->m_PlaceHolder->parentWidget();
230 230 }
231 231
232 232 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
233 233 {
234 234 impl->m_DragDropScroller->addScrollArea(scrollArea);
235 235 }
236 236
237 237 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
238 238 {
239 239 impl->m_DragDropScroller->removeScrollArea(scrollArea);
240 240 }
241 241
242 242 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
243 243 {
244 244 image.save(impl->m_ImageTempUrl);
245 245 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
246 246 }
247 247
248 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
249 {
250 if (impl->m_HighlightedDragWidget) {
251 impl->m_HighlightedDragWidget->highlightForMerge(false);
252 }
253
254 if (dragWidget) {
255 impl->m_HighlightedDragWidget = dragWidget;
256 impl->m_HighlightedDragWidget->highlightForMerge(true);
257 }
258 }
259
248 260 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
249 261 VisualizationDragDropContainer *dropContainer)
250 262 {
251 263 auto result = true;
252 264
253 265 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
254 266 auto variables = sqpApp->variableController().variablesForMimeData(
255 267 mimeData->data(MIME_TYPE_VARIABLE_LIST));
256 268
257 269 if (variables.count() == 1) {
258 270 // Check that the viariable is not already in a graph
259 271
260 272 // Search for the top level VisualizationWidget
261 273 auto parent = dropContainer->parentWidget();
262 274 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
263 275 parent = parent->parentWidget();
264 276 }
265 277
266 278 if (parent) {
267 279 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
268 280
269 281 FindVariableOperation findVariableOperation{variables.first()};
270 282 visualizationWidget->accept(&findVariableOperation);
271 283 auto variableContainers = findVariableOperation.result();
272 284 if (!variableContainers.empty()) {
273 285 result = false;
274 286 }
275 287 }
276 288 else {
277 289 qCWarning(LOG_DragDropHelper()) << QObject::tr(
278 290 "DragDropHelper::checkMimeDataForVisualization, the parent "
279 291 "VisualizationWidget cannot be found.");
280 292 result = false;
281 293 }
282 294 }
283 295 else {
284 296 result = false;
285 297 }
286 298 }
287 299
288 300 return result;
289 301 }
@@ -1,362 +1,368
1 1 #include "Visualization/VisualizationDragDropContainer.h"
2 2 #include "DragDropHelper.h"
3 3 #include "SqpApplication.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5
6 6 #include "Common/VisualizationDef.h"
7 7
8 8 #include <QDrag>
9 9 #include <QDragEnterEvent>
10 10 #include <QVBoxLayout>
11 11
12 12 #include <cmath>
13 13 #include <memory>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16 16
17 17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
18 18
19 19 QVBoxLayout *m_Layout;
20 20 QStringList m_AcceptedMimeTypes;
21 21 QStringList m_MergeAllowedMimeTypes;
22 22 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
23 23 = [](auto mimeData) { return true; };
24 24
25 25 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
26 26 {
27 27 m_Layout = new QVBoxLayout(widget);
28 28 m_Layout->setContentsMargins(0, 0, 0, 0);
29 29 }
30 30
31 31 bool acceptMimeData(const QMimeData *data) const
32 32 {
33 33 for (const auto &type : m_AcceptedMimeTypes) {
34 34 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
35 35 return true;
36 36 }
37 37 }
38 38
39 39 return false;
40 40 }
41 41
42 42 bool allowMergeMimeData(const QMimeData *data) const
43 43 {
44 44 for (const auto &type : m_MergeAllowedMimeTypes) {
45 45 if (data->hasFormat(type)) {
46 46 return true;
47 47 }
48 48 }
49 49
50 50 return false;
51 51 }
52 52
53 53 bool hasPlaceHolder() const
54 54 {
55 55 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
56 56 }
57 57
58 58 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
59 59 {
60 60 VisualizationDragWidget *dragWidget = nullptr;
61 61
62 62 for (auto child : parent->children()) {
63 63 auto widget = qobject_cast<VisualizationDragWidget *>(child);
64 64 if (widget && widget->isVisible()) {
65 65 if (widget->frameGeometry().contains(pos)) {
66 66 dragWidget = widget;
67 67 break;
68 68 }
69 69 }
70 70 }
71 71
72 72 return dragWidget;
73 73 }
74 74
75 75 bool cursorIsInContainer(QWidget *container) const
76 76 {
77 77 auto adustNum = 18; // to be safe, in case of scrollbar on the side
78 78 auto containerRect = QRect(QPoint(), container->contentsRect().size())
79 79 .adjusted(adustNum, adustNum, -adustNum, -adustNum);
80 80 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
81 81 }
82 82 };
83 83
84 84 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
85 85 : QWidget{parent},
86 86 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
87 87 {
88 88 setAcceptDrops(true);
89 89 }
90 90
91 91 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
92 92 {
93 93 impl->m_Layout->addWidget(dragWidget);
94 94 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
95 95 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
96 96 &VisualizationDragDropContainer::startDrag);
97 97 }
98 98
99 99 void VisualizationDragDropContainer::insertDragWidget(int index,
100 100 VisualizationDragWidget *dragWidget)
101 101 {
102 102 impl->m_Layout->insertWidget(index, dragWidget);
103 103 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
104 104 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
105 105 &VisualizationDragDropContainer::startDrag);
106 106 }
107 107
108 108 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
109 109 {
110 110 impl->m_AcceptedMimeTypes = mimeTypes;
111 111 }
112 112
113 113 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
114 114 {
115 115 impl->m_MergeAllowedMimeTypes = mimeTypes;
116 116 }
117 117
118 118 int VisualizationDragDropContainer::countDragWidget() const
119 119 {
120 120 auto nbGraph = 0;
121 121 for (auto child : children()) {
122 122 if (qobject_cast<VisualizationDragWidget *>(child)) {
123 123 nbGraph += 1;
124 124 }
125 125 }
126 126
127 127 return nbGraph;
128 128 }
129 129
130 130 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
131 131 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
132 132 {
133 133 impl->m_AcceptMimeDataFun = fun;
134 134 }
135 135
136 136 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
137 137 const QPoint &dragPosition)
138 138 {
139 139 auto &helper = sqpApp->dragDropHelper();
140 140 helper.resetDragAndDrop();
141 141
142 142 // Note: The management of the drag object is done by Qt
143 143 auto drag = new QDrag{dragWidget};
144 144 drag->setHotSpot(dragPosition);
145 145
146 146 auto mimeData = dragWidget->mimeData();
147 147 drag->setMimeData(mimeData);
148 148
149 149 auto pixmap = QPixmap(dragWidget->size());
150 150 dragWidget->render(&pixmap);
151 151 drag->setPixmap(pixmap);
152 152
153 153 auto image = pixmap.toImage();
154 154 mimeData->setImageData(image);
155 155 mimeData->setUrls({helper.imageTemporaryUrl(image)});
156 156
157 157 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
158 158 helper.setCurrentDragWidget(dragWidget);
159 159
160 160 if (impl->cursorIsInContainer(this)) {
161 161 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
162 162 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
163 163 dragWidget->setVisible(false);
164 164 }
165 165
166 166 // Note: The exec() is blocking on windows but not on linux and macOS
167 167 drag->exec(Qt::MoveAction | Qt::CopyAction);
168 168 }
169 169 else {
170 170 qCWarning(LOG_VisualizationDragDropContainer())
171 171 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
172 172 "VisualizationDragWidget is not found in this container.");
173 173 }
174 174 }
175 175
176 176 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
177 177 {
178 178 if (impl->acceptMimeData(event->mimeData())) {
179 179 event->acceptProposedAction();
180 180
181 181 auto &helper = sqpApp->dragDropHelper();
182 182
183 183 if (!impl->hasPlaceHolder()) {
184 184 auto dragWidget = helper.getCurrentDragWidget();
185 185
186 186 if (dragWidget) {
187 187 // If the drag&drop is internal to the visualization, entering the container hide
188 188 // the dragWidget which was hidden by the dragLeaveEvent
189 189 auto parentWidget
190 190 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
191 191 if (parentWidget) {
192 192 dragWidget->setVisible(false);
193 193 }
194 194 }
195 195
196 196 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
197 197
198 198 if (dragWidgetHovered) {
199 199 auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
200 200
201 201 if (dragWidget) {
202 202 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
203 203 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
204 204 // Correction of the index if the drop occurs in the same container
205 205 // and if the drag is started from the visualization (in that case, the
206 206 // dragWidget is hidden)
207 207 hoveredWidgetIndex += 1;
208 208 }
209 209 }
210 210
211 211 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
212 212 }
213 213 else {
214 214 helper.insertPlaceHolder(impl->m_Layout, 0);
215 215 }
216 216 }
217 217 else {
218 218 // do nothing
219 219 }
220 220 }
221 221 else {
222 222 event->ignore();
223 223 }
224 224
225 225 QWidget::dragEnterEvent(event);
226 226 }
227 227
228 228 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
229 229 {
230 230 Q_UNUSED(event);
231 231
232 232 auto &helper = sqpApp->dragDropHelper();
233 233
234 234 if (!impl->cursorIsInContainer(this)) {
235 235 helper.removePlaceHolder();
236 236
237 237 auto dragWidget = helper.getCurrentDragWidget();
238 238 if (dragWidget) {
239 239 // dragWidget has a value only if the drag is started from the visualization
240 240 // In that case, shows the drag widget at its original place
241 241 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
242 242 // drop zone (It is not possible to catch a drop event outside of the application)
243 243
244 244 if (dragWidget) {
245 245 dragWidget->setVisible(true);
246 246 }
247 247 }
248 248 }
249 249 else {
250 250 // Leave event probably received for a child widget.
251 251 // Do nothing.
252 252 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
253 253 }
254 254
255 255 QWidget::dragLeaveEvent(event);
256 256 }
257 257
258 258 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
259 259 {
260 260 if (impl->acceptMimeData(event->mimeData())) {
261 261 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
262 262 if (dragWidgetHovered) {
263 263 auto canMerge = impl->allowMergeMimeData(event->mimeData());
264 264
265 265 auto nbDragWidget = countDragWidget();
266 266 if (nbDragWidget > 0) {
267 267 auto graphHeight = qMax(size().height() / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
268 268
269 269 auto dropIndex = floor(event->pos().y() / graphHeight);
270 270 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
271 271
272 272 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
273 273 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
274 274
275 275 auto &helper = sqpApp->dragDropHelper();
276 276 auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
277 277
278 278 if (isOnTop || isOnBottom) {
279 279 if (isOnBottom) {
280 280 dropIndex += 1;
281 281 }
282 282
283 283 if (helper.getCurrentDragWidget()) {
284 284 auto dragWidgetIndex
285 285 = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
286 286 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
287 287 // Correction of the index if the drop occurs in the same container
288 288 // and if the drag is started from the visualization (in that case, the
289 289 // dragWidget is hidden)
290 290 dropIndex += 1;
291 291 }
292 292 }
293 293
294 294 if (dropIndex != placeHolderIndex) {
295 295 helper.insertPlaceHolder(impl->m_Layout, dropIndex);
296 296 }
297
298 helper.setHightlightedDragWidget(nullptr);
297 299 }
298 300 else if (canMerge) {
299 301 // drop on the middle -> merge
300 302 if (impl->hasPlaceHolder()) {
301 303 helper.removePlaceHolder();
302 304 }
305
306 helper.setHightlightedDragWidget(dragWidgetHovered);
303 307 }
304 308 }
305 309 else {
306 310 qCWarning(LOG_VisualizationDragDropContainer())
307 311 << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the "
308 312 "container");
309 313 }
310 314 }
311 315 else {
312 316 // No hovered drag widget, the mouse is probably hover the placeHolder
313 317 // Do nothing
314 318 }
315 319 }
316 320 else {
317 321 event->ignore();
318 322 }
319 323
320 324 QWidget::dragMoveEvent(event);
321 325 }
322 326
323 327 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
324 328 {
325 329 if (impl->acceptMimeData(event->mimeData())) {
326 330 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
327 331 if (impl->hasPlaceHolder()) {
328 332 auto &helper = sqpApp->dragDropHelper();
329 333
330 334 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
331 335
332 336 if (dragWidget) {
333 337 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
334 338 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
335 339 // Correction of the index if the drop occurs in the same container
336 340 // and if the drag is started from the visualization (in that case, the
337 341 // dragWidget is hidden)
338 342 droppedIndex -= 1;
339 343 }
340 344
341 345 dragWidget->setVisible(true);
342 346 }
343 347
344 348 event->acceptProposedAction();
345 349
346 350 helper.removePlaceHolder();
351 helper.setHightlightedDragWidget(nullptr);
347 352
348 353 emit dropOccured(droppedIndex, event->mimeData());
349 354 }
350 355 else {
351 356 qCWarning(LOG_VisualizationDragDropContainer())
352 357 << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the "
353 358 "placeHolder is not found.");
354 Q_ASSERT(false);
359 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
360 // Q_ASSERT(false);
355 361 }
356 362 }
357 363 else {
358 364 event->ignore();
359 365 }
360 366
361 367 QWidget::dropEvent(event);
362 368 }
@@ -1,385 +1,396
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7 #include "ui_VisualizationGraphWidget.h"
8 8
9 9 #include <Common/MimeTypesDef.h>
10 10 #include <Data/ArrayData.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <DragDropHelper.h>
13 13 #include <Settings/SqpSettingsDefs.h>
14 14 #include <SqpApplication.h>
15 15 #include <Variable/Variable.h>
16 16 #include <Variable/VariableController.h>
17 17
18 18 #include <unordered_map>
19 19
20 20 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
21 21
22 22 namespace {
23 23
24 24 /// Key pressed to enable zoom on horizontal axis
25 25 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
26 26
27 27 /// Key pressed to enable zoom on vertical axis
28 28 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 29
30 30 } // namespace
31 31
32 32 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
33 33
34 34 explicit VisualizationGraphWidgetPrivate(const QString &name)
35 35 : m_Name{name},
36 36 m_DoAcquisition{true},
37 37 m_IsCalibration{false},
38 38 m_RenderingDelegate{nullptr}
39 39 {
40 40 }
41 41
42 42 QString m_Name;
43 43 // 1 variable -> n qcpplot
44 44 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
45 45 bool m_DoAcquisition;
46 46 bool m_IsCalibration;
47 47 QCPItemTracer *m_TextTracer;
48 48 /// Delegate used to attach rendering features to the plot
49 49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
50 50 };
51 51
52 52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
53 53 : VisualizationDragWidget{parent},
54 54 ui{new Ui::VisualizationGraphWidget},
55 55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
56 56 {
57 57 ui->setupUi(this);
58 58
59 59 // 'Close' options : widget is deleted when closed
60 60 setAttribute(Qt::WA_DeleteOnClose);
61 61
62 62 // Set qcpplot properties :
63 63 // - Drag (on x-axis) and zoom are enabled
64 64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67 67
68 68 // The delegate must be initialized after the ui as it uses the plot
69 69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
70 70
71 71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
72 72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
73 73 &VisualizationGraphWidget::onMouseRelease);
74 74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
75 75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
77 &QCPAxis::rangeChanged),
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76 connect(
77 ui->widget->xAxis,
78 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
79 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
79 80
80 81 // Activates menu when right clicking on the graph
81 82 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
82 83 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
83 84 &VisualizationGraphWidget::onGraphMenuRequested);
84 85
85 86 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
86 87 &VariableController::onRequestDataLoading);
87 88
88 89 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
89 90 &VisualizationGraphWidget::onUpdateVarDisplaying);
90 91 }
91 92
92 93
93 94 VisualizationGraphWidget::~VisualizationGraphWidget()
94 95 {
95 96 delete ui;
96 97 }
97 98
98 99 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
99 100 {
100 101 auto parent = parentWidget();
101 102 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
102 103 parent = parent->parentWidget();
103 104 }
104 105
105 106 return qobject_cast<VisualizationZoneWidget *>(parent);
106 107 }
107 108
108 109 void VisualizationGraphWidget::enableAcquisition(bool enable)
109 110 {
110 111 impl->m_DoAcquisition = enable;
111 112 }
112 113
113 114 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
114 115 {
115 116 // Uses delegate to create the qcpplot components according to the variable
116 117 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
117 118 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
118 119
119 120 // Set axes properties according to the units of the data series
120 121 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
121 122 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
122 123 auto xAxisUnit = Unit{};
123 124 auto valuesUnit = Unit{};
124 125
125 126 if (auto dataSeries = variable->dataSeries()) {
126 127 dataSeries->lockRead();
127 128 xAxisUnit = dataSeries->xAxisUnit();
128 129 valuesUnit = dataSeries->valuesUnit();
129 130 dataSeries->unlock();
130 131 }
131 132 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
132 133
133 134 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
134 135
135 136 this->enableAcquisition(false);
136 137 this->setGraphRange(range);
137 138 this->enableAcquisition(true);
138 139
139 140 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
140 141
141 142 emit variableAdded(variable);
142 143 }
143 144
144 145 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
145 146 {
146 147 // Each component associated to the variable :
147 148 // - is removed from qcpplot (which deletes it)
148 149 // - is no longer referenced in the map
149 150 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
150 151 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
151 152 emit variableAboutToBeRemoved(variable);
152 153
153 154 auto &plottablesMap = variableIt->second;
154 155
155 156 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
156 157 plottableIt != plottableEnd;) {
157 158 ui->widget->removePlottable(plottableIt->second);
158 159 plottableIt = plottablesMap.erase(plottableIt);
159 160 }
160 161
161 162 impl->m_VariableToPlotMultiMap.erase(variableIt);
162 163 }
163 164
164 165 // Updates graph
165 166 ui->widget->replot();
166 167 }
167 168
168 169 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
169 170 {
170 171 auto variables = QList<std::shared_ptr<Variable> >{};
171 172 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
172 173 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
173 174 variables << it->first;
174 175 }
175 176
176 177 return variables;
177 178 }
178 179
179 180 void VisualizationGraphWidget::setYRange(const SqpRange &range)
180 181 {
181 182 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
182 183 }
183 184
184 185 SqpRange VisualizationGraphWidget::graphRange() const noexcept
185 186 {
186 187 auto graphRange = ui->widget->xAxis->range();
187 188 return SqpRange{graphRange.lower, graphRange.upper};
188 189 }
189 190
190 191 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
191 192 {
192 193 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
193 194 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
194 195 ui->widget->replot();
195 196 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
196 197 }
197 198
198 199 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
199 200 {
200 201 if (visitor) {
201 202 visitor->visit(this);
202 203 }
203 204 else {
204 205 qCCritical(LOG_VisualizationGraphWidget())
205 206 << tr("Can't visit widget : the visitor is null");
206 207 }
207 208 }
208 209
209 210 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
210 211 {
211 212 /// @todo : for the moment, a graph can always accomodate a variable
212 213 Q_UNUSED(variable);
213 214 return true;
214 215 }
215 216
216 217 bool VisualizationGraphWidget::contains(const Variable &variable) const
217 218 {
218 219 // Finds the variable among the keys of the map
219 220 auto variablePtr = &variable;
220 221 auto findVariable
221 222 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
222 223
223 224 auto end = impl->m_VariableToPlotMultiMap.cend();
224 225 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
225 226 return it != end;
226 227 }
227 228
228 229 QString VisualizationGraphWidget::name() const
229 230 {
230 231 return impl->m_Name;
231 232 }
232 233
233 234 QMimeData *VisualizationGraphWidget::mimeData() const
234 235 {
235 236 auto mimeData = new QMimeData;
236 237 mimeData->setData(MIME_TYPE_GRAPH, QByteArray());
237 238
238 239 return mimeData;
239 240 }
240 241
241 242 bool VisualizationGraphWidget::isDragAllowed() const
242 243 {
243 244 return true;
244 245 }
245 246
247 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
248 {
249 if (highlighted) {
250 plot().setBackground(QBrush(QColor("#BBD5EE")));
251 }
252 else {
253 plot().setBackground(QBrush(Qt::white));
254 }
255 }
256
246 257 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
247 258 {
248 259 Q_UNUSED(event);
249 260
250 261 // Prevents that all variables will be removed from graph when it will be closed
251 262 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
252 263 emit variableAboutToBeRemoved(variableEntry.first);
253 264 }
254 265 }
255 266
256 267 void VisualizationGraphWidget::enterEvent(QEvent *event)
257 268 {
258 269 Q_UNUSED(event);
259 270 impl->m_RenderingDelegate->showGraphOverlay(true);
260 271 }
261 272
262 273 void VisualizationGraphWidget::leaveEvent(QEvent *event)
263 274 {
264 275 Q_UNUSED(event);
265 276 impl->m_RenderingDelegate->showGraphOverlay(false);
266 277 }
267 278
268 279 QCustomPlot &VisualizationGraphWidget::plot() noexcept
269 280 {
270 281 return *ui->widget;
271 282 }
272 283
273 284 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
274 285 {
275 286 QMenu graphMenu{};
276 287
277 288 // Iterates on variables (unique keys)
278 289 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
279 290 end = impl->m_VariableToPlotMultiMap.cend();
280 291 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
281 292 // 'Remove variable' action
282 293 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
283 294 [ this, var = it->first ]() { removeVariable(var); });
284 295 }
285 296
286 297 if (!graphMenu.isEmpty()) {
287 298 graphMenu.exec(QCursor::pos());
288 299 }
289 300 }
290 301
291 302 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
292 303 {
293 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
294 << QThread::currentThread()->objectName() << "DoAcqui"
295 << impl->m_DoAcquisition;
304 qCDebug(LOG_VisualizationGraphWidget())
305 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
306 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
296 307
297 308 auto graphRange = SqpRange{t1.lower, t1.upper};
298 309 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
299 310
300 311 if (impl->m_DoAcquisition) {
301 312 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
302 313
303 314 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
304 315 end = impl->m_VariableToPlotMultiMap.end();
305 316 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
306 317 variableUnderGraphVector.push_back(it->first);
307 318 }
308 319 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
309 320 !impl->m_IsCalibration);
310 321
311 322 if (!impl->m_IsCalibration) {
312 323 qCDebug(LOG_VisualizationGraphWidget())
313 324 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
314 325 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
315 326 emit synchronize(graphRange, oldGraphRange);
316 327 }
317 328 }
318 329 }
319 330
320 331 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
321 332 {
322 333 // Handles plot rendering when mouse is moving
323 334 impl->m_RenderingDelegate->onMouseMove(event);
324 335
325 336 VisualizationDragWidget::mouseMoveEvent(event);
326 337 }
327 338
328 339 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
329 340 {
330 341 auto zoomOrientations = QFlags<Qt::Orientation>{};
331 342
332 343 // Lambda that enables a zoom orientation if the key modifier related to this orientation
333 344 // has
334 345 // been pressed
335 346 auto enableOrientation
336 347 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
337 348 auto orientationEnabled = event->modifiers().testFlag(modifier);
338 349 zoomOrientations.setFlag(orientation, orientationEnabled);
339 350 };
340 351 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
341 352 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
342 353
343 354 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
344 355 }
345 356
346 357 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
347 358 {
348 359 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
349 360
350 361 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
351 362
352 363 VisualizationDragWidget::mousePressEvent(event);
353 364 }
354 365
355 366 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
356 367 {
357 368 impl->m_IsCalibration = false;
358 369 }
359 370
360 371 void VisualizationGraphWidget::onDataCacheVariableUpdated()
361 372 {
362 373 auto graphRange = ui->widget->xAxis->range();
363 374 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
364 375
365 376 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
366 377 auto variable = variableEntry.first;
367 378 qCDebug(LOG_VisualizationGraphWidget())
368 379 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
369 380 qCDebug(LOG_VisualizationGraphWidget())
370 381 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
371 382 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
372 383 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
373 384 variable->range());
374 385 }
375 386 }
376 387 }
377 388
378 389 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
379 390 const SqpRange &range)
380 391 {
381 392 auto it = impl->m_VariableToPlotMultiMap.find(variable);
382 393 if (it != impl->m_VariableToPlotMultiMap.end()) {
383 394 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
384 395 }
385 396 }
General Comments 0
You need to be logged in to leave comments. Login now