##// END OF EJS Templates
Merge branch 'feature/SelectionZones' into develop
trabillard -
r1095:ca242dcb639e merge
parent child
Show More
@@ -0,0 +1,47
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
7
8 class VisualizationSelectionZoneItem : public QCPItemRect {
9
10 public:
11 VisualizationSelectionZoneItem(QCustomPlot *plot);
12 virtual ~VisualizationSelectionZoneItem();
13
14 void setName(const QString &name);
15 QString name() const;
16
17 SqpRange range() const;
18 void setRange(double tstart, double tend);
19 void setStart(double tstart);
20 void setEnd(double tend);
21
22 void setColor(const QColor &color);
23
24 void setEditionEnabled(bool value);
25 bool isEditionEnabled() const;
26
27 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
28 void setHovered(bool value);
29
30 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
31
32 protected:
33 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
34 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
35 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
36
37 void resizeLeft(double pixelDiff);
38 void resizeRight(double pixelDiff);
39 void move(double pixelDiff);
40
41
42 private:
43 class VisualizationSelectionZoneItemPrivate;
44 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
45 };
46
47 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -0,0 +1,26
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
3
4 #include <Common/spimpl.h>
5
6 #include <QVector>
7
8 class VisualizationSelectionZoneItem;
9
10 class VisualizationSelectionZoneManager {
11 public:
12 VisualizationSelectionZoneManager();
13
14 void select(const QVector<VisualizationSelectionZoneItem *> &items);
15 void setSelected(VisualizationSelectionZoneItem *item, bool value);
16
17 void clearSelection();
18
19 QVector<VisualizationSelectionZoneItem *> selectedItems() const;
20
21 private:
22 class VisualizationSelectionZoneManagerPrivate;
23 spimpl::unique_impl_ptr<VisualizationSelectionZoneManagerPrivate> impl;
24 };
25
26 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEMANAGER_H
@@ -0,0 +1,343
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2
3 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
4
5 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
6
7 QCustomPlot *m_Plot;
8 double m_T1 = 0;
9 double m_T2 = 0;
10 QColor m_Color;
11
12 bool m_IsEditionEnabled = true;
13 double m_MovedOrinalT1 = 0;
14 double m_MovedOrinalT2 = 0;
15
16 QCPItemStraightLine *m_LeftLine;
17 QCPItemStraightLine *m_RightLine;
18 QCPItemText *m_NameLabelItem = nullptr;
19
20 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
21 EditionMode m_CurrentEditionMode;
22
23 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
24
25 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
26 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
27 {
28 }
29
30 void updatePosition(VisualizationSelectionZoneItem *item)
31 {
32 item->topLeft->setCoords(m_T1, 0);
33 item->bottomRight->setCoords(m_T2, 1);
34 }
35
36 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
37 {
38 auto distanceLeft = m_LeftLine->selectTest(pos, false);
39 auto distanceRight = m_RightLine->selectTest(pos, false);
40 auto distance = zoneItem->selectTest(pos, false);
41
42 if (distanceRight <= distance) {
43 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
44 }
45 else if (distanceLeft <= distance) {
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
47 }
48
49 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
50 }
51
52 double pixelSizeToAxisXSize(double pixels)
53 {
54 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
55 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
56 }
57 };
58
59 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
60 : QCPItemRect(plot),
61 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
62 {
63 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
64 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
65 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
66 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
67 setSelectable(false);
68
69 impl->m_RightLine = new QCPItemStraightLine(plot);
70 impl->m_RightLine->point1->setParentAnchor(topRight);
71 impl->m_RightLine->point2->setParentAnchor(bottomRight);
72 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
73 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
74 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
75 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
76 impl->m_RightLine->setSelectable(false);
77
78 impl->m_LeftLine = new QCPItemStraightLine(plot);
79 impl->m_LeftLine->point1->setParentAnchor(topLeft);
80 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
81 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
82 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
83 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
84 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
85 impl->m_LeftLine->setSelectable(false);
86
87 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
88 &QCPItemStraightLine::setSelected);
89 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
90 &QCPItemStraightLine::setSelected);
91
92 setColor(QColor(DEFAULT_COLOR));
93 }
94
95 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
96 {
97 impl->m_Plot->removeItem(impl->m_RightLine);
98 impl->m_Plot->removeItem(impl->m_LeftLine);
99 }
100
101 void VisualizationSelectionZoneItem::setName(const QString &name)
102 {
103 if (name.isEmpty() && impl->m_NameLabelItem) {
104 impl->m_Plot->removeItem(impl->m_NameLabelItem);
105 impl->m_NameLabelItem = nullptr;
106 }
107 else if (!impl->m_NameLabelItem) {
108 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
109 impl->m_NameLabelItem->setText(name);
110 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
111 impl->m_NameLabelItem->setColor(impl->m_Color);
112 impl->m_NameLabelItem->position->setParentAnchor(top);
113 }
114 }
115
116 QString VisualizationSelectionZoneItem::name() const
117 {
118 if (!impl->m_NameLabelItem) {
119 return QString();
120 }
121
122 return impl->m_NameLabelItem->text();
123 }
124
125 SqpRange VisualizationSelectionZoneItem::range() const
126 {
127 SqpRange range;
128 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
129 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
130 return range;
131 }
132
133 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
134 {
135 impl->m_T1 = tstart;
136 impl->m_T2 = tend;
137 impl->updatePosition(this);
138 }
139
140 void VisualizationSelectionZoneItem::setStart(double tstart)
141 {
142 impl->m_T1 = tstart;
143 impl->updatePosition(this);
144 }
145
146 void VisualizationSelectionZoneItem::setEnd(double tend)
147 {
148 impl->m_T2 = tend;
149 impl->updatePosition(this);
150 }
151
152 void VisualizationSelectionZoneItem::setColor(const QColor &color)
153 {
154 impl->m_Color = color;
155
156 auto brushColor = color;
157 brushColor.setAlpha(80);
158 setBrush(QBrush(brushColor));
159 setPen(QPen(Qt::NoPen));
160
161 auto selectedBrushColor = brushColor;
162 selectedBrushColor.setAlpha(150);
163 setSelectedBrush(QBrush(selectedBrushColor));
164 setSelectedPen(QPen(Qt::NoPen));
165
166 auto linePen = QPen(color);
167 linePen.setStyle(Qt::SolidLine);
168 linePen.setWidth(4);
169
170 auto selectedLinePen = linePen;
171 selectedLinePen.setColor(color.darker(120));
172 selectedLinePen.setWidth(4);
173
174 impl->m_LeftLine->setPen(linePen);
175 impl->m_RightLine->setPen(linePen);
176
177 impl->m_LeftLine->setSelectedPen(selectedLinePen);
178 impl->m_RightLine->setSelectedPen(selectedLinePen);
179 }
180
181 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
182 {
183 impl->m_IsEditionEnabled = value;
184 setSelectable(value);
185 if (!value) {
186 setSelected(false);
187 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
188 }
189 }
190
191 bool VisualizationSelectionZoneItem::isEditionEnabled() const
192 {
193 return impl->m_IsEditionEnabled;
194 }
195
196 Qt::CursorShape
197 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
198 {
199 auto mode = impl->m_CurrentEditionMode
200 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
201 ? impl->getEditionMode(position, this)
202 : impl->m_CurrentEditionMode;
203 switch (mode) {
204 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
205 return Qt::SizeAllCursor;
206 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
207 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
208 return Qt::SizeHorCursor;
209 default:
210 return Qt::ArrowCursor;
211 }
212 }
213
214 void VisualizationSelectionZoneItem::setHovered(bool value)
215 {
216 if (value) {
217 auto linePen = impl->m_LeftLine->pen();
218 linePen.setStyle(Qt::DotLine);
219 linePen.setWidth(3);
220
221 auto selectedLinePen = impl->m_LeftLine->selectedPen();
222 ;
223 selectedLinePen.setStyle(Qt::DotLine);
224 selectedLinePen.setWidth(3);
225
226 impl->m_LeftLine->setPen(linePen);
227 impl->m_RightLine->setPen(linePen);
228
229 impl->m_LeftLine->setSelectedPen(selectedLinePen);
230 impl->m_RightLine->setSelectedPen(selectedLinePen);
231 }
232 else {
233 setColor(impl->m_Color);
234 }
235 }
236
237 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
238 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
239 {
240 impl->m_AssociatedEditedZones = associatedZones;
241 impl->m_AssociatedEditedZones.removeAll(this);
242 }
243
244 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
245 {
246 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
247 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
248
249 impl->m_MovedOrinalT1 = impl->m_T1;
250 impl->m_MovedOrinalT2 = impl->m_T2;
251 for (auto associatedZone : impl->m_AssociatedEditedZones) {
252 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
253 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
254 }
255 }
256 else {
257 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
258 event->ignore();
259 }
260 }
261
262 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
263 {
264 if (isEditionEnabled()) {
265 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
266 auto pixelDiff = event->pos().x() - startPos.x();
267 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
268
269 switch (impl->m_CurrentEditionMode) {
270 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
271 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
272 for (auto associatedZone : impl->m_AssociatedEditedZones) {
273 associatedZone->move(pixelDiff);
274 }
275 break;
276 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
277 setStart(impl->m_MovedOrinalT1 + diff);
278 for (auto associatedZone : impl->m_AssociatedEditedZones) {
279 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
280 ? associatedZone->resizeLeft(pixelDiff)
281 : associatedZone->resizeRight(pixelDiff);
282 }
283 break;
284 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
285 setEnd(impl->m_MovedOrinalT2 + diff);
286 for (auto associatedZone : impl->m_AssociatedEditedZones) {
287 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
288 ? associatedZone->resizeRight(pixelDiff)
289 : associatedZone->resizeLeft(pixelDiff);
290 }
291 break;
292 default:
293 break;
294 }
295
296 for (auto associatedZone : impl->m_AssociatedEditedZones) {
297 associatedZone->parentPlot()->replot();
298 }
299 }
300 else {
301 event->ignore();
302 }
303 }
304
305 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
306 {
307 if (isEditionEnabled()) {
308 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
309 }
310 else {
311 event->ignore();
312 }
313
314 impl->m_AssociatedEditedZones.clear();
315 }
316
317 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
318 {
319 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
320 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
321 setStart(impl->m_MovedOrinalT1 + diff);
322 }
323 else {
324 setEnd(impl->m_MovedOrinalT2 + diff);
325 }
326 }
327
328 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
329 {
330 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
331 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
332 setStart(impl->m_MovedOrinalT1 + diff);
333 }
334 else {
335 setEnd(impl->m_MovedOrinalT2 + diff);
336 }
337 }
338
339 void VisualizationSelectionZoneItem::move(double pixelDiff)
340 {
341 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
342 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
343 }
@@ -0,0 +1,51
1 #include "Visualization/VisualizationSelectionZoneManager.h"
2 #include "Visualization/VisualizationSelectionZoneItem.h"
3
4 struct VisualizationSelectionZoneManager::VisualizationSelectionZoneManagerPrivate {
5 QVector<VisualizationSelectionZoneItem *> m_SelectedItems;
6 };
7
8 VisualizationSelectionZoneManager::VisualizationSelectionZoneManager()
9 : impl{spimpl::make_unique_impl<VisualizationSelectionZoneManagerPrivate>()}
10 {
11 }
12
13 void VisualizationSelectionZoneManager::select(
14 const QVector<VisualizationSelectionZoneItem *> &items)
15 {
16 clearSelection();
17 for (auto item : items) {
18 setSelected(item, true);
19 }
20 }
21
22 void VisualizationSelectionZoneManager::setSelected(VisualizationSelectionZoneItem *item,
23 bool value)
24 {
25 if (value != item->selected()) {
26 item->setSelected(value);
27 item->parentPlot()->replot();
28 }
29
30 if (!value && impl->m_SelectedItems.contains(item)) {
31 impl->m_SelectedItems.removeAll(item);
32 }
33 else if (value) {
34 impl->m_SelectedItems << item;
35 }
36 }
37
38 void VisualizationSelectionZoneManager::clearSelection()
39 {
40 for (auto item : impl->m_SelectedItems) {
41 item->setSelected(false);
42 item->parentPlot()->replot();
43 }
44
45 impl->m_SelectedItems.clear();
46 }
47
48 QVector<VisualizationSelectionZoneItem *> VisualizationSelectionZoneManager::selectedItems() const
49 {
50 return impl->m_SelectedItems;
51 }
@@ -189,7 +189,7 MainWindow::MainWindow(QWidget *parent)
189 auto timeWidget = new TimeWidget{};
189 auto timeWidget = new TimeWidget{};
190 mainToolBar->addWidget(timeWidget);
190 mainToolBar->addWidget(timeWidget);
191
191
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Pointer", this};
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
193 actionPointerMode->setCheckable(true);
193 actionPointerMode->setCheckable(true);
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
195 == SqpApplication::PlotsInteractionMode::None);
195 == SqpApplication::PlotsInteractionMode::None);
@@ -14,6 +14,7 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
17
18
18
19
19 #endif // SCIQLOP_MIMETYPESDEF_H
20 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -5,3 +5,4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
@@ -11,9 +11,13 class VisualizationDragWidget : public QWidget {
11 public:
11 public:
12 VisualizationDragWidget(QWidget *parent = nullptr);
12 VisualizationDragWidget(QWidget *parent = nullptr);
13
13
14 virtual QMimeData *mimeData() const = 0;
14 virtual QMimeData *mimeData(const QPoint &position) const = 0;
15 virtual bool isDragAllowed() const = 0;
15 virtual bool isDragAllowed() const = 0;
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); };
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); }
17
18 /// Custom pixmap to display during a drag operation.
19 /// If the provided pixmap is null, a pixmap of the entire widget is used.
20 virtual QPixmap customDragPixmap(const QPoint &dragPosition);
17
21
18 protected:
22 protected:
19 virtual void mousePressEvent(QMouseEvent *event) override;
23 virtual void mousePressEvent(QMouseEvent *event) override;
@@ -17,6 +17,7 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationWidget;
20 class VisualizationZoneWidget;
21 class VisualizationZoneWidget;
21
22
22 namespace Ui {
23 namespace Ui {
@@ -33,8 +34,12 public:
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 virtual ~VisualizationGraphWidget();
35 virtual ~VisualizationGraphWidget();
35
36
37 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
38 VisualizationZoneWidget *parentZoneWidget() const noexcept;
37
39
40 /// Returns the main VisualizationWidget which contains the graph or nullptr
41 VisualizationWidget *parentVisualizationWidget() const;
42
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
43 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
39 void enableAcquisition(bool enable);
44 void enableAcquisition(bool enable);
40
45
@@ -51,6 +56,15 public:
51 SqpRange graphRange() const noexcept;
56 SqpRange graphRange() const noexcept;
52 void setGraphRange(const SqpRange &range);
57 void setGraphRange(const SqpRange &range);
53
58
59 /// Returns the ranges of all the selection zones on the graph
60 QVector<SqpRange> selectionZoneRanges() const;
61
62 /// Adds new selection zones in the graph
63 void addSelectionZones(const QVector<SqpRange> &ranges);
64
65 /// Undo the last zoom done with a zoom box
66 void undoZoom();
67
54 // IVisualizationWidget interface
68 // IVisualizationWidget interface
55 void accept(IVisualizationWidgetVisitor *visitor) override;
69 void accept(IVisualizationWidgetVisitor *visitor) override;
56 bool canDrop(const Variable &variable) const override;
70 bool canDrop(const Variable &variable) const override;
@@ -58,7 +72,8 public:
58 QString name() const override;
72 QString name() const override;
59
73
60 // VisualisationDragWidget
74 // VisualisationDragWidget
61 QMimeData *mimeData() const override;
75 QMimeData *mimeData(const QPoint &position) const override;
76 QPixmap customDragPixmap(const QPoint &dragPosition) override;
62 bool isDragAllowed() const override;
77 bool isDragAllowed() const override;
63 void highlightForMerge(bool highlighted) override;
78 void highlightForMerge(bool highlighted) override;
64
79
@@ -89,7 +104,7 protected:
89 void enterEvent(QEvent *event) override;
104 void enterEvent(QEvent *event) override;
90 void leaveEvent(QEvent *event) override;
105 void leaveEvent(QEvent *event) override;
91
106
92 QCustomPlot &plot() noexcept;
107 QCustomPlot &plot() const noexcept;
93
108
94 private:
109 private:
95 Ui::VisualizationGraphWidget *ui;
110 Ui::VisualizationGraphWidget *ui;
@@ -7,11 +7,14
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <Common/spimpl.h>
11
10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
11
13
12 class QMenu;
14 class QMenu;
13 class Variable;
15 class Variable;
14 class VisualizationTabWidget;
16 class VisualizationTabWidget;
17 class VisualizationSelectionZoneManager;
15
18
16 namespace Ui {
19 namespace Ui {
17 class VisualizationWidget;
20 class VisualizationWidget;
@@ -24,6 +27,9 public:
24 explicit VisualizationWidget(QWidget *parent = 0);
27 explicit VisualizationWidget(QWidget *parent = 0);
25 virtual ~VisualizationWidget();
28 virtual ~VisualizationWidget();
26
29
30 /// Returns the class which manage the selection of selection zone across the visualization
31 VisualizationSelectionZoneManager &selectionZoneManager() const;
32
27 // IVisualizationWidget interface
33 // IVisualizationWidget interface
28 void accept(IVisualizationWidgetVisitor *visitor) override;
34 void accept(IVisualizationWidgetVisitor *visitor) override;
29 bool canDrop(const Variable &variable) const override;
35 bool canDrop(const Variable &variable) const override;
@@ -49,6 +55,9 protected:
49
55
50 private:
56 private:
51 Ui::VisualizationWidget *ui;
57 Ui::VisualizationWidget *ui;
58
59 class VisualizationWidgetPrivate;
60 spimpl::unique_impl_ptr<VisualizationWidgetPrivate> impl;
52 };
61 };
53
62
54 #endif // VISUALIZATIONWIDGET_H
63 #endif // VISUALIZATIONWIDGET_H
@@ -60,6 +60,9 public:
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
61 int index);
61 int index);
62
62
63 /// Returns the first graph in the zone or nullptr if there is no graph inside
64 VisualizationGraphWidget *firstGraph() const;
65
63 // IVisualizationWidget interface
66 // IVisualizationWidget interface
64 void accept(IVisualizationWidgetVisitor *visitor) override;
67 void accept(IVisualizationWidgetVisitor *visitor) override;
65 bool canDrop(const Variable &variable) const override;
68 bool canDrop(const Variable &variable) const override;
@@ -67,7 +70,7 public:
67 QString name() const override;
70 QString name() const override;
68
71
69 // VisualisationDragWidget
72 // VisualisationDragWidget
70 QMimeData *mimeData() const override;
73 QMimeData *mimeData(const QPoint &position) const override;
71 bool isDragAllowed() const override;
74 bool isDragAllowed() const override;
72
75
73 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
76 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
@@ -82,7 +82,9 gui_sources = [
82 'src/Visualization/VisualizationCursorItem.cpp',
82 'src/Visualization/VisualizationCursorItem.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
83 'src/Visualization/ColorScaleEditor.cpp',
84 'src/Visualization/SqpColorScale.cpp',
84 'src/Visualization/SqpColorScale.cpp',
85 'src/Visualization/QCPColorMapIterator.cpp'
85 'src/Visualization/QCPColorMapIterator.cpp',
86 'src/Visualization/VisualizationSelectionZoneItem.cpp',
87 'src/Visualization/VisualizationSelectionZoneManager.cpp'
86 ]
88 ]
87
89
88 gui_inc = include_directories(['include'])
90 gui_inc = include_directories(['include'])
@@ -212,11 +212,15 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidg
212 // Note: The management of the drag object is done by Qt
212 // Note: The management of the drag object is done by Qt
213 auto drag = new QDrag{dragWidget};
213 auto drag = new QDrag{dragWidget};
214
214
215 auto mimeData = dragWidget->mimeData();
215 auto mimeData = dragWidget->mimeData(dragPosition);
216 drag->setMimeData(mimeData);
216 drag->setMimeData(mimeData);
217
217
218 auto pixmap = QPixmap(dragWidget->size());
218 auto pixmap = dragWidget->customDragPixmap(dragPosition);
219 dragWidget->render(&pixmap);
219 if (pixmap.isNull()) {
220 pixmap = QPixmap{dragWidget->size()};
221 dragWidget->render(&pixmap);
222 }
223
220 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
224 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
221 Qt::KeepAspectRatio, Qt::SmoothTransformation));
225 Qt::KeepAspectRatio, Qt::SmoothTransformation));
222
226
@@ -225,17 +229,20 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidg
225 mimeData->setUrls({helper.imageTemporaryUrl(image)});
229 mimeData->setUrls({helper.imageTemporaryUrl(image)});
226
230
227 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
231 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
228 helper.setCurrentDragWidget(dragWidget);
229
232
230 if (impl->cursorIsInContainer(this)) {
233 if (impl->acceptMimeData(mimeData) && impl->allowInsertForMimeData(mimeData)) {
231 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
234 helper.setCurrentDragWidget(dragWidget);
232 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
235
233 impl->m_PlaceHolderText);
236 if (impl->cursorIsInContainer(this)) {
234 dragWidget->setVisible(false);
237 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
235 }
238 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
236 else {
239 impl->m_PlaceHolderText);
237 // The drag starts directly outside the drop zone
240 dragWidget->setVisible(false);
238 // do not add the placeHolder
241 }
242 else {
243 // The drag starts directly outside the drop zone
244 // do not add the placeHolder
245 }
239 }
246 }
240
247
241 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
248 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
@@ -19,6 +19,12 VisualizationDragWidget::VisualizationDragWidget(QWidget *parent)
19 {
19 {
20 }
20 }
21
21
22 QPixmap VisualizationDragWidget::customDragPixmap(const QPoint &dragPosition)
23 {
24 Q_UNUSED(dragPosition);
25 return QPixmap();
26 }
27
22 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
28 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
23 {
29 {
24 if (event->button() == Qt::LeftButton) {
30 if (event->button() == Qt::LeftButton) {
@@ -48,6 +48,7 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
48 tracer.setSize(3);
48 tracer.setSize(3);
49 tracer.setPen(QPen(Qt::black));
49 tracer.setPen(QPen(Qt::black));
50 tracer.setBrush(Qt::black);
50 tracer.setBrush(Qt::black);
51 tracer.setSelectable(false);
51 }
52 }
52
53
53 QPixmap pixmap(const QString &iconPath) noexcept
54 QPixmap pixmap(const QString &iconPath) noexcept
@@ -94,6 +95,7 void initTitleTextStyle(QCPItemText &text) noexcept
94 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
95 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setType(QCPItemPosition::ptAxisRectRatio);
96 text.position->setCoords(0.5, 0);
97 text.position->setCoords(0.5, 0);
98 text.setSelectable(false);
97 }
99 }
98
100
99 /**
101 /**
@@ -162,9 +164,9 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP
162 initClosePixmapStyle(*m_ClosePixmap);
164 initClosePixmapStyle(*m_ClosePixmap);
163
165
164 // Connects pixmap selection to graph widget closing
166 // Connects pixmap selection to graph widget closing
165 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
167 QObject::connect(&m_Plot, &QCustomPlot::itemClick,
166 [&graphWidget](bool selected) {
168 [&graphWidget, this](auto item, auto mouseEvent) {
167 if (selected) {
169 if (item == m_ClosePixmap) {
168 graphWidget.close();
170 graphWidget.close();
169 }
171 }
170 });
172 });
@@ -179,15 +181,14 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP
179 initXAxisPixmapStyle(*m_XAxisPixmap);
181 initXAxisPixmapStyle(*m_XAxisPixmap);
180
182
181 // Connects pixmap selection to graph x-axis showing/hiding
183 // Connects pixmap selection to graph x-axis showing/hiding
182 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
184 QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) {
183 if (m_XAxisPixmap->selected()) {
185 if (m_XAxisPixmap == item) {
184 // Changes the selection state and refreshes the x-axis
186 // Changes the selection state and refreshes the x-axis
185 m_ShowXAxis = !m_ShowXAxis;
187 m_ShowXAxis = !m_ShowXAxis;
186 updateXAxisState();
188 this->updateXAxisState();
187 m_Plot.layer(AXES_LAYER)->replot();
189 m_Plot.layer(AXES_LAYER)->replot();
188
190
189 // Deselects the x-axis pixmap and updates icon
191 // Deselects the x-axis pixmap and updates icon
190 m_XAxisPixmap->setSelected(false);
191 m_XAxisPixmap->setPixmap(
192 m_XAxisPixmap->setPixmap(
192 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
193 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
193 m_Plot.layer(OVERLAY_LAYER)->replot();
194 m_Plot.layer(OVERLAY_LAYER)->replot();
@@ -4,6 +4,9
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
7 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
8 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
9
12
@@ -24,6 +27,9 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24
27
25 namespace {
28 namespace {
26
29
30 /// Key pressed to enable drag&drop in all modes
31 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32
27 /// Key pressed to enable zoom on horizontal axis
33 /// Key pressed to enable zoom on horizontal axis
28 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
34 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
29
35
@@ -36,6 +42,9 const auto PAN_SPEED = 5;
36 /// Key pressed to enable a calibration pan
42 /// Key pressed to enable a calibration pan
37 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
43 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
38
44
45 /// Key pressed to enable multi selection of selection zones
46 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47
39 /// Minimum size for the zoom box, in percentage of the axis range
48 /// Minimum size for the zoom box, in percentage of the axis range
40 const auto ZOOM_BOX_MIN_SIZE = 0.8;
49 const auto ZOOM_BOX_MIN_SIZE = 0.8;
41
50
@@ -71,18 +80,17 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
71 /// Delegate used to attach rendering features to the plot
80 /// Delegate used to attach rendering features to the plot
72 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
81 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
73
82
74 QCPItemRect *m_DrawingRect = nullptr;
83 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85
75 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
86 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
76 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
77
88
78 void configureDrawingRect()
89 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
79 {
90 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
80 if (m_DrawingRect) {
91 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
81 QPen p;
92
82 p.setWidth(2);
93 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
83 m_DrawingRect->setPen(p);
84 }
85 }
86
94
87 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
95 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
88 {
96 {
@@ -90,22 +98,77 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
90
98
91 auto axisPos = posToAxisPos(pos, plot);
99 auto axisPos = posToAxisPos(pos, plot);
92
100
93 m_DrawingRect = new QCPItemRect{&plot};
101 m_DrawingZoomRect = new QCPItemRect{&plot};
94 configureDrawingRect();
102 QPen p;
103 p.setWidth(2);
104 m_DrawingZoomRect->setPen(p);
95
105
96 m_DrawingRect->topLeft->setCoords(axisPos);
106 m_DrawingZoomRect->topLeft->setCoords(axisPos);
97 m_DrawingRect->bottomRight->setCoords(axisPos);
107 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
98 }
108 }
99
109
100 void removeDrawingRect(QCustomPlot &plot)
110 void removeDrawingRect(QCustomPlot &plot)
101 {
111 {
102 if (m_DrawingRect) {
112 if (m_DrawingZoomRect) {
103 plot.removeItem(m_DrawingRect); // the item is deleted by QCustomPlot
113 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
104 m_DrawingRect = nullptr;
114 m_DrawingZoomRect = nullptr;
105 plot.replot(QCustomPlot::rpQueuedReplot);
115 plot.replot(QCustomPlot::rpQueuedReplot);
106 }
116 }
107 }
117 }
108
118
119 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 {
121 endDrawingZone(graph);
122
123 auto axisPos = posToAxisPos(pos, graph->plot());
124
125 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setEditionEnabled(false);
128 }
129
130 void endDrawingZone(VisualizationGraphWidget *graph)
131 {
132 if (m_DrawingZone) {
133 auto drawingZoneRange = m_DrawingZone->range();
134 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 m_DrawingZone->setEditionEnabled(true);
136 addSelectionZone(m_DrawingZone);
137 }
138 else {
139 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 }
141
142 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 m_DrawingZone = nullptr;
144 }
145 }
146
147 void setSelectionZonesEditionEnabled(bool value)
148 {
149 for (auto s : m_SelectionZones) {
150 s->setEditionEnabled(value);
151 }
152 }
153
154 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155
156 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 const QCustomPlot &plot) const
158 {
159 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 auto minDistanceToZone = -1;
161 for (auto zone : m_SelectionZones) {
162 auto distanceToZone = zone->selectTest(pos, false);
163 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 selectionZoneItemUnderCursor = zone;
166 }
167 }
168
169 return selectionZoneItemUnderCursor;
170 }
171
109 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
172 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
110 {
173 {
111 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
174 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
@@ -117,7 +180,6 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
117 {
180 {
118 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
181 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
119 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
182 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
120
121 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
183 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
122 }
184 }
123 };
185 };
@@ -133,9 +195,10 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
133 setAttribute(Qt::WA_DeleteOnClose);
195 setAttribute(Qt::WA_DeleteOnClose);
134
196
135 // Set qcpplot properties :
197 // Set qcpplot properties :
136 // - Drag (on x-axis) and zoom are enabled
198 // - zoom is enabled
137 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
199 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
138 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
200 ui->widget->setInteractions(QCP::iRangeZoom);
201 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
139
202
140 // The delegate must be initialized after the ui as it uses the plot
203 // The delegate must be initialized after the ui as it uses the plot
141 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
204 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
@@ -153,9 +216,10 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
153 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
216 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
154 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
217 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
155 &VisualizationGraphWidget::onMouseDoubleClick);
218 &VisualizationGraphWidget::onMouseDoubleClick);
156 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
219 connect(
157 &QCPAxis::rangeChanged),
220 ui->widget->xAxis,
158 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
221 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
222 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
159
223
160 // Activates menu when right clicking on the graph
224 // Activates menu when right clicking on the graph
161 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
225 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -189,6 +253,16 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noex
189 return qobject_cast<VisualizationZoneWidget *>(parent);
253 return qobject_cast<VisualizationZoneWidget *>(parent);
190 }
254 }
191
255
256 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 {
258 auto parent = parentWidget();
259 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 parent = parent->parentWidget();
261 }
262
263 return qobject_cast<VisualizationWidget *>(parent);
264 }
265
192 void VisualizationGraphWidget::enableAcquisition(bool enable)
266 void VisualizationGraphWidget::enableAcquisition(bool enable)
193 {
267 {
194 impl->m_DoAcquisition = enable;
268 impl->m_DoAcquisition = enable;
@@ -281,6 +355,40 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
281 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
355 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
282 }
356 }
283
357
358 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 {
360 QVector<SqpRange> ranges;
361 for (auto zone : impl->m_SelectionZones) {
362 ranges << zone->range();
363 }
364
365 return ranges;
366 }
367
368 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 {
370 for (const auto &range : ranges) {
371 // note: ownership is transfered to QCustomPlot
372 auto zone = new VisualizationSelectionZoneItem(&plot());
373 zone->setRange(range.m_TStart, range.m_TEnd);
374 impl->addSelectionZone(zone);
375 }
376
377 plot().replot(QCustomPlot::rpQueuedReplot);
378 }
379
380 void VisualizationGraphWidget::undoZoom()
381 {
382 auto zoom = impl->m_ZoomStack.pop();
383 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
384 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
385
386 axisX->setRange(zoom.first);
387 axisY->setRange(zoom.second);
388
389 plot().replot(QCustomPlot::rpQueuedReplot);
390 }
391
284 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
392 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
285 {
393 {
286 if (visitor) {
394 if (visitor) {
@@ -324,17 +432,50 QString VisualizationGraphWidget::name() const
324 return impl->m_Name;
432 return impl->m_Name;
325 }
433 }
326
434
327 QMimeData *VisualizationGraphWidget::mimeData() const
435 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
328 {
436 {
329 auto mimeData = new QMimeData;
437 auto mimeData = new QMimeData;
330 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
331
438
332 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
439 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
333 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
440 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
441 && selectionZoneItemUnderCursor) {
442 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
443 selectionZoneItemUnderCursor->range()));
444 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
445 selectionZoneItemUnderCursor->range()));
446 }
447 else {
448 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
449
450 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
451 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
452 }
334
453
335 return mimeData;
454 return mimeData;
336 }
455 }
337
456
457 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
458 {
459 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
460 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
461 && selectionZoneItemUnderCursor) {
462
463 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
464 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
465
466 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
467 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
468 .toSize();
469
470 auto pixmap = QPixmap(zoneSize);
471 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
472
473 return pixmap;
474 }
475
476 return QPixmap();
477 }
478
338 bool VisualizationGraphWidget::isDragAllowed() const
479 bool VisualizationGraphWidget::isDragAllowed() const
339 {
480 {
340 return true;
481 return true;
@@ -428,9 +569,14 void VisualizationGraphWidget::leaveEvent(QEvent *event)
428 else {
569 else {
429 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
570 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
430 }
571 }
572
573 if (impl->m_HoveredZone) {
574 impl->m_HoveredZone->setHovered(false);
575 impl->m_HoveredZone = nullptr;
576 }
431 }
577 }
432
578
433 QCustomPlot &VisualizationGraphWidget::plot() noexcept
579 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
434 {
580 {
435 return *ui->widget;
581 return *ui->widget;
436 }
582 }
@@ -448,6 +594,14 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
448 [ this, var = it->first ]() { removeVariable(var); });
594 [ this, var = it->first ]() { removeVariable(var); });
449 }
595 }
450
596
597 if (!impl->m_ZoomStack.isEmpty()) {
598 if (!graphMenu.isEmpty()) {
599 graphMenu.addSeparator();
600 }
601
602 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
603 }
604
451 if (!graphMenu.isEmpty()) {
605 if (!graphMenu.isEmpty()) {
452 graphMenu.exec(QCursor::pos());
606 graphMenu.exec(QCursor::pos());
453 }
607 }
@@ -455,9 +609,9 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
455
609
456 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
610 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
457 {
611 {
458 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
612 qCDebug(LOG_VisualizationGraphWidget())
459 << QThread::currentThread()->objectName() << "DoAcqui"
613 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
460 << impl->m_DoAcquisition;
614 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
461
615
462 auto graphRange = SqpRange{t1.lower, t1.upper};
616 auto graphRange = SqpRange{t1.lower, t1.upper};
463 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
617 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
@@ -508,10 +662,15 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
508
662
509 auto axisPos = impl->posToAxisPos(event->pos(), plot());
663 auto axisPos = impl->posToAxisPos(event->pos(), plot());
510
664
511 if (impl->m_DrawingRect) {
665 // Zoom box and zone drawing
512 impl->m_DrawingRect->bottomRight->setCoords(axisPos);
666 if (impl->m_DrawingZoomRect) {
667 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
668 }
669 else if (impl->m_DrawingZone) {
670 impl->m_DrawingZone->setEnd(axisPos.x());
513 }
671 }
514
672
673 // Cursor
515 if (auto parentZone = parentZoneWidget()) {
674 if (auto parentZone = parentZoneWidget()) {
516 if (impl->pointIsInAxisRect(axisPos, plot())) {
675 if (impl->pointIsInAxisRect(axisPos, plot())) {
517 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
676 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
@@ -524,6 +683,36 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
524 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
683 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
525 }
684 }
526
685
686 // Search for the selection zone under the mouse
687 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
688 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
689 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
690
691 // Sets the appropriate cursor shape
692 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
693 setCursor(cursorShape);
694
695 // Manages the hovered zone
696 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
697 if (impl->m_HoveredZone) {
698 impl->m_HoveredZone->setHovered(false);
699 }
700 selectionZoneItemUnderCursor->setHovered(true);
701 impl->m_HoveredZone = selectionZoneItemUnderCursor;
702 plot().replot(QCustomPlot::rpQueuedReplot);
703 }
704 }
705 else {
706 // There is no zone under the mouse or the interaction mode is not "selection zones"
707 if (impl->m_HoveredZone) {
708 impl->m_HoveredZone->setHovered(false);
709 impl->m_HoveredZone = nullptr;
710 }
711
712 setCursor(Qt::ArrowCursor);
713 }
714
715 impl->m_HasMovedMouse = true;
527 VisualizationDragWidget::mouseMoveEvent(event);
716 VisualizationDragWidget::mouseMoveEvent(event);
528 }
717 }
529
718
@@ -560,30 +749,72 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
560
749
561 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
750 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
562 {
751 {
563 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
752 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
564 impl->startDrawingRect(event->pos(), plot());
753 auto isSelectionZoneMode
754 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
755 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
756
757 if (!isDragDropClick && isLeftClick) {
758 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
759 // Starts a zoom box
760 impl->startDrawingRect(event->pos(), plot());
761 }
762 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
763 // Starts a new selection zone
764 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
765 if (!zoneAtPos) {
766 impl->startDrawingZone(event->pos(), this);
767 }
768 }
769 }
770
771 // Allows mouse panning only in default mode
772 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
773 == SqpApplication::PlotsInteractionMode::None
774 && !isDragDropClick);
775
776 // Allows zone edition only in selection zone mode without drag&drop
777 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
778
779 // Selection / Deselection
780 if (isSelectionZoneMode) {
781 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
782 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
783 if (selectionZoneItemUnderCursor && isLeftClick) {
784 selectionZoneItemUnderCursor->setAssociatedEditedZones(
785 parentVisualizationWidget()->selectionZoneManager().selectedItems());
786 }
787 else if (!isMultiSelectionClick && isLeftClick) {
788 parentVisualizationWidget()->selectionZoneManager().clearSelection();
789 }
790 else {
791 // No selection change
792 }
565 }
793 }
566
794
795
796 impl->m_HasMovedMouse = false;
567 VisualizationDragWidget::mousePressEvent(event);
797 VisualizationDragWidget::mousePressEvent(event);
568 }
798 }
569
799
570 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
800 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
571 {
801 {
572 if (impl->m_DrawingRect) {
802 if (impl->m_DrawingZoomRect) {
573
803
574 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
804 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
575 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
805 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
576
806
577 auto newAxisXRange = QCPRange{impl->m_DrawingRect->topLeft->coords().x(),
807 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
578 impl->m_DrawingRect->bottomRight->coords().x()};
808 impl->m_DrawingZoomRect->bottomRight->coords().x()};
579
809
580 auto newAxisYRange = QCPRange{impl->m_DrawingRect->topLeft->coords().y(),
810 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
581 impl->m_DrawingRect->bottomRight->coords().y()};
811 impl->m_DrawingZoomRect->bottomRight->coords().y()};
582
812
583 impl->removeDrawingRect(plot());
813 impl->removeDrawingRect(plot());
584
814
585 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
815 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
586 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
816 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
817 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
587 axisX->setRange(newAxisXRange);
818 axisX->setRange(newAxisXRange);
588 axisY->setRange(newAxisYRange);
819 axisY->setRange(newAxisYRange);
589
820
@@ -591,7 +822,31 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
591 }
822 }
592 }
823 }
593
824
825 impl->endDrawingZone(this);
826
594 impl->m_IsCalibration = false;
827 impl->m_IsCalibration = false;
828
829 // Selection / Deselection
830 auto isSelectionZoneMode
831 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
832 if (isSelectionZoneMode) {
833 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
834 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
835 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
836 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
837 parentVisualizationWidget()->selectionZoneManager().select(
838 {selectionZoneItemUnderCursor});
839 }
840 else if (!impl->m_HasMovedMouse) {
841 parentVisualizationWidget()->selectionZoneManager().setSelected(
842 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
843 || event->button() == Qt::RightButton);
844 }
845 }
846 else {
847 // No selection change
848 }
849 }
595 }
850 }
596
851
597 void VisualizationGraphWidget::onDataCacheVariableUpdated()
852 void VisualizationGraphWidget::onDataCacheVariableUpdated()
@@ -255,7 +255,16 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
255 helper.delayedCloseWidget(graphWidget);
255 helper.delayedCloseWidget(graphWidget);
256 }
256 }
257
257
258 tabWidget->createZone(variables, index);
258 auto zoneWidget = tabWidget->createZone(variables, index);
259 auto firstGraph = zoneWidget->firstGraph();
260 if (firstGraph) {
261 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
262 }
263 else {
264 qCWarning(LOG_VisualizationZoneWidget())
265 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
266 Q_ASSERT(false);
267 }
259 }
268 }
260 else {
269 else {
261 // The graph is empty, create an empty zone and move the graph inside
270 // The graph is empty, create an empty zone and move the graph inside
@@ -1,6 +1,7
1 #include "Visualization/VisualizationWidget.h"
1 #include "Visualization/VisualizationWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationSelectionZoneManager.h"
4 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/operations/FindVariableOperation.h"
7 #include "Visualization/operations/FindVariableOperation.h"
@@ -16,10 +17,23
16
17
17 #include <QToolButton>
18 #include <QToolButton>
18
19
20 #include <memory>
21
19 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
22 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
20
23
24 struct VisualizationWidget::VisualizationWidgetPrivate {
25 std::unique_ptr<VisualizationSelectionZoneManager> m_ZoneSelectionManager = nullptr;
26
27 VisualizationWidgetPrivate()
28 : m_ZoneSelectionManager(std::make_unique<VisualizationSelectionZoneManager>())
29 {
30 }
31 };
32
21 VisualizationWidget::VisualizationWidget(QWidget *parent)
33 VisualizationWidget::VisualizationWidget(QWidget *parent)
22 : QWidget{parent}, ui{new Ui::VisualizationWidget}
34 : QWidget{parent},
35 ui{new Ui::VisualizationWidget},
36 impl{spimpl::make_unique_impl<VisualizationWidgetPrivate>()}
23 {
37 {
24 ui->setupUi(this);
38 ui->setupUi(this);
25
39
@@ -82,6 +96,11 VisualizationWidget::~VisualizationWidget()
82 delete ui;
96 delete ui;
83 }
97 }
84
98
99 VisualizationSelectionZoneManager &VisualizationWidget::selectionZoneManager() const
100 {
101 return *impl->m_ZoneSelectionManager.get();
102 }
103
85 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
104 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
86 {
105 {
87 if (visitor) {
106 if (visitor) {
@@ -72,21 +72,6 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
72 QUuid m_SynchronisationGroupId;
72 QUuid m_SynchronisationGroupId;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74
74
75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 {
78 VisualizationGraphWidget *firstGraph = nullptr;
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 if (layout->count() > 0) {
81 if (auto visualizationGraphWidget
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 firstGraph = visualizationGraphWidget;
84 }
85 }
86
87 return firstGraph;
88 }
89
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
75 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
76 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 VisualizationZoneWidget *zoneWidget);
77 VisualizationZoneWidget *zoneWidget);
@@ -110,6 +95,8 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p
110 VisualizationDragDropContainer::DropBehavior::Merged);
95 VisualizationDragDropContainer::DropBehavior::Merged);
111 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
96 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
112 VisualizationDragDropContainer::DropBehavior::Forbidden);
97 VisualizationDragDropContainer::DropBehavior::Forbidden);
98 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
99 VisualizationDragDropContainer::DropBehavior::Forbidden);
113 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
114 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
101 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
115 ui->dragDropContainer);
102 ui->dragDropContainer);
@@ -284,7 +271,7 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<V
284 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
271 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
285
272
286 auto range = SqpRange{};
273 auto range = SqpRange{};
287 if (auto firstGraph = impl->firstGraph(this)) {
274 if (auto firstGraph = this->firstGraph()) {
288 // Case of a new graph in a existant zone
275 // Case of a new graph in a existant zone
289 range = firstGraph->graphRange();
276 range = firstGraph->graphRange();
290 }
277 }
@@ -316,6 +303,20 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > var
316 return graphWidget;
303 return graphWidget;
317 }
304 }
318
305
306 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
307 {
308 VisualizationGraphWidget *firstGraph = nullptr;
309 auto layout = ui->dragDropContainer->layout();
310 if (layout->count() > 0) {
311 if (auto visualizationGraphWidget
312 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
313 firstGraph = visualizationGraphWidget;
314 }
315 }
316
317 return firstGraph;
318 }
319
319 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 {
321 {
321 if (visitor) {
322 if (visitor) {
@@ -352,12 +353,14 QString VisualizationZoneWidget::name() const
352 return ui->zoneNameLabel->text();
353 return ui->zoneNameLabel->text();
353 }
354 }
354
355
355 QMimeData *VisualizationZoneWidget::mimeData() const
356 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
356 {
357 {
358 Q_UNUSED(position);
359
357 auto mimeData = new QMimeData;
360 auto mimeData = new QMimeData;
358 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
361 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
359
362
360 if (auto firstGraph = impl->firstGraph(this)) {
363 if (auto firstGraph = this->firstGraph()) {
361 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
364 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
362 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
365 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
363 }
366 }
@@ -543,7 +546,8 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
543 }
546 }
544
547
545 // Creates the new graph in the zone
548 // Creates the new graph in the zone
546 zoneWidget->createGraph(variables, index);
549 auto newGraphWidget = zoneWidget->createGraph(variables, index);
550 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
547 }
551 }
548 else {
552 else {
549 // The drop occurred in the same zone or the graph is empty
553 // The drop occurred in the same zone or the graph is empty
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

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