##// END OF EJS Templates
Alignment actions for zone selections
trabillard -
r1116:13a66582f6e0
parent child
Show More
@@ -1,51 +1,64
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
6 #include <Visualization/qcustomplot.h>
7
7
8 class VisualizationGraphWidget;
8 class VisualizationGraphWidget;
9
9
10 class VisualizationSelectionZoneItem : public QCPItemRect {
10 class VisualizationSelectionZoneItem : public QCPItemRect {
11
11
12 public:
12 public:
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
14 virtual ~VisualizationSelectionZoneItem();
14 virtual ~VisualizationSelectionZoneItem();
15
15
16 VisualizationGraphWidget *parentGraphWidget() const noexcept;
16 VisualizationGraphWidget *parentGraphWidget() const noexcept;
17
17
18 void setName(const QString &name);
18 void setName(const QString &name);
19 QString name() const;
19 QString name() const;
20
20
21 SqpRange range() const;
21 SqpRange range() const;
22 void setRange(double tstart, double tend);
22 void setRange(double tstart, double tend);
23 void setStart(double tstart);
23 void setStart(double tstart);
24 void setEnd(double tend);
24 void setEnd(double tend);
25
25
26 void setColor(const QColor &color);
26 void setColor(const QColor &color);
27
27
28 void setEditionEnabled(bool value);
28 void setEditionEnabled(bool value);
29 bool isEditionEnabled() const;
29 bool isEditionEnabled() const;
30
30
31 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
31 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
32 void setHovered(bool value);
32 void setHovered(bool value);
33
33
34 /// Sets the zones which should be moved or reisized together with this zone
34 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
35 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
35
36
37 /// Align the specified zones with this one, vertically with the left border
38 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
39 bool allowResize);
40 /// Align the specified zones with this one, vertically with the right border
41 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
42 bool allowResize);
43 /// Align the specified zones with this one, temporally with the left border
44 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
45 bool allowResize);
46 /// Align the specified zones with this one, temporally with the right border
47 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
48 bool allowResize);
49
36 protected:
50 protected:
37 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
51 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
38 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
52 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
39 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
53 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
40
54
41 void resizeLeft(double pixelDiff);
55 void resizeLeft(double pixelDiff);
42 void resizeRight(double pixelDiff);
56 void resizeRight(double pixelDiff);
43 void move(double pixelDiff);
57 void move(double pixelDiff);
44
58
45
46 private:
59 private:
47 class VisualizationSelectionZoneItemPrivate;
60 class VisualizationSelectionZoneItemPrivate;
48 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
61 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
49 };
62 };
50
63
51 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
64 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -1,30 +1,107
1 #include "Visualization/VisualizationActionManager.h"
1 #include "Visualization/VisualizationActionManager.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationSelectionZoneItem.h"
3 #include "Visualization/VisualizationSelectionZoneItem.h"
4
4
5 #include <Actions/ActionsGuiController.h>
5 #include <Actions/ActionsGuiController.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7
7
8 VisualizationActionManager::VisualizationActionManager() {}
8 VisualizationActionManager::VisualizationActionManager() {}
9
9
10 void VisualizationActionManager::installSelectionZoneActions()
10 void VisualizationActionManager::installSelectionZoneActions()
11 {
11 {
12 auto &actionController = sqpApp->actionsGuiController();
12 auto &actionController = sqpApp->actionsGuiController();
13
13
14 actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto &zones) {
14 actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto zones) {
15 for (auto selectionZone : zones) {
15 for (auto selectionZone : zones) {
16 if (auto graph = selectionZone->parentGraphWidget()) {
16 if (auto graph = selectionZone->parentGraphWidget()) {
17 graph->removeSelectionZone(selectionZone);
17 graph->removeSelectionZone(selectionZone);
18 }
18 }
19 }
19 }
20 });
20 });
21
21
22 auto alignEnableFuntion = [](auto &items) { return items.count() > 0; };
22 auto alignEnableFuntion = [](auto items) { return items.count() > 1; };
23
23
24 auto alignLeftAction = actionController.addSectionZoneAction("Align Left Vertically", [](auto &zones) {});
24 // Vertical alignment actions
25 auto alignLeftAction
26 = actionController.addSectionZoneAction("Align Vertically / Left", [](auto zones) {
27 Q_ASSERT(zones.count() > 1);
28 auto ref = zones.takeFirst();
29 ref->alignZonesVerticallyOnLeft(zones, false);
30 });
25 alignLeftAction->setEnableFunction(alignEnableFuntion);
31 alignLeftAction->setEnableFunction(alignEnableFuntion);
26
32
33 auto alignLeftBorderAction
34 = actionController.addSectionZoneAction("Align Vertically / Left Borders", [](auto zones) {
35 Q_ASSERT(zones.count() > 1);
36 auto ref = zones.takeFirst();
37 ref->alignZonesVerticallyOnLeft(zones, true);
38 });
39 alignLeftBorderAction->setEnableFunction(alignEnableFuntion);
40
27 auto alignRightAction
41 auto alignRightAction
28 = actionController.addSectionZoneAction("Align Right vertically", [](auto &zones) {});
42 = actionController.addSectionZoneAction("Align Vertically / Right", [](auto zones) {
43 Q_ASSERT(zones.count() > 1);
44 auto ref = zones.takeFirst();
45 ref->alignZonesVerticallyOnRight(zones, false);
46 });
29 alignRightAction->setEnableFunction(alignEnableFuntion);
47 alignRightAction->setEnableFunction(alignEnableFuntion);
48
49 auto alignRightBorderAction
50 = actionController.addSectionZoneAction("Align Vertically / Right Borders", [](auto zones) {
51 Q_ASSERT(zones.count() > 1);
52 auto ref = zones.takeFirst();
53 ref->alignZonesVerticallyOnRight(zones, true);
54 });
55 alignRightBorderAction->setEnableFunction(alignEnableFuntion);
56
57 auto alignLeftAndRightAction = actionController.addSectionZoneAction(
58 "Align Vertically / Left and Right", [](auto zones) {
59 Q_ASSERT(zones.count() > 1);
60 auto ref = zones.takeFirst();
61 ref->alignZonesVerticallyOnLeft(zones, false);
62 ref->alignZonesVerticallyOnRight(zones, true);
63 });
64 alignLeftAndRightAction->setEnableFunction(alignEnableFuntion);
65
66 // Temporal alignment actions
67 auto alignLeftTemporallyAction
68 = actionController.addSectionZoneAction("Align Temporally / Left", [](auto zones) {
69 Q_ASSERT(zones.count() > 1);
70 auto ref = zones.takeFirst();
71 ref->alignZonesTemporallyOnLeft(zones, false);
72 });
73 alignLeftTemporallyAction->setEnableFunction(alignEnableFuntion);
74
75 auto alignLeftBorderTemporallyAction
76 = actionController.addSectionZoneAction("Align Temporally / Left Borders", [](auto zones) {
77 Q_ASSERT(zones.count() > 1);
78 auto ref = zones.takeFirst();
79 ref->alignZonesTemporallyOnLeft(zones, true);
80 });
81 alignLeftBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
82
83 auto alignRightTemporallyAction
84 = actionController.addSectionZoneAction("Align Temporally / Right", [](auto zones) {
85 Q_ASSERT(zones.count() > 1);
86 auto ref = zones.takeFirst();
87 ref->alignZonesTemporallyOnRight(zones, false);
88 });
89 alignRightTemporallyAction->setEnableFunction(alignEnableFuntion);
90
91 auto alignRightBorderTemporallyAction
92 = actionController.addSectionZoneAction("Align Temporally / Right Borders", [](auto zones) {
93 Q_ASSERT(zones.count() > 1);
94 auto ref = zones.takeFirst();
95 ref->alignZonesTemporallyOnRight(zones, true);
96 });
97 alignRightBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
98
99 auto alignLeftAndRightTemporallyAction = actionController.addSectionZoneAction(
100 "Align Temporally / Left and Right", [](auto zones) {
101 Q_ASSERT(zones.count() > 1);
102 auto ref = zones.takeFirst();
103 ref->alignZonesTemporallyOnLeft(zones, false);
104 ref->alignZonesTemporallyOnRight(zones, true);
105 });
106 alignLeftAndRightTemporallyAction->setEnableFunction(alignEnableFuntion);
30 }
107 }
@@ -1,902 +1,904
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
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"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
9 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
12
12
13 #include <Actions/ActionsGuiController.h>
13 #include <Actions/ActionsGuiController.h>
14 #include <Common/MimeTypesDef.h>
14 #include <Common/MimeTypesDef.h>
15 #include <Data/ArrayData.h>
15 #include <Data/ArrayData.h>
16 #include <Data/IDataSeries.h>
16 #include <Data/IDataSeries.h>
17 #include <Data/SpectrogramSeries.h>
17 #include <Data/SpectrogramSeries.h>
18 #include <DragAndDrop/DragDropGuiController.h>
18 #include <DragAndDrop/DragDropGuiController.h>
19 #include <Settings/SqpSettingsDefs.h>
19 #include <Settings/SqpSettingsDefs.h>
20 #include <SqpApplication.h>
20 #include <SqpApplication.h>
21 #include <Time/TimeController.h>
21 #include <Time/TimeController.h>
22 #include <Variable/Variable.h>
22 #include <Variable/Variable.h>
23 #include <Variable/VariableController.h>
23 #include <Variable/VariableController.h>
24
24
25 #include <unordered_map>
25 #include <unordered_map>
26
26
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28
28
29 namespace {
29 namespace {
30
30
31 /// Key pressed to enable drag&drop in all modes
31 /// Key pressed to enable drag&drop in all modes
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33
33
34 /// Key pressed to enable zoom on horizontal axis
34 /// Key pressed to enable zoom on horizontal axis
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36
36
37 /// Key pressed to enable zoom on vertical axis
37 /// Key pressed to enable zoom on vertical axis
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39
39
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 const auto PAN_SPEED = 5;
41 const auto PAN_SPEED = 5;
42
42
43 /// Key pressed to enable a calibration pan
43 /// Key pressed to enable a calibration pan
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45
45
46 /// Key pressed to enable multi selection of selection zones
46 /// Key pressed to enable multi selection of selection zones
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48
48
49 /// Minimum size for the zoom box, in percentage of the axis range
49 /// Minimum size for the zoom box, in percentage of the axis range
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51
51
52 /// Format of the dates appearing in the label of a cursor
52 /// Format of the dates appearing in the label of a cursor
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54
54
55 } // namespace
55 } // namespace
56
56
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58
58
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 : m_Name{name},
60 : m_Name{name},
61 m_DoAcquisition{true},
61 m_DoAcquisition{true},
62 m_IsCalibration{false},
62 m_IsCalibration{false},
63 m_RenderingDelegate{nullptr}
63 m_RenderingDelegate{nullptr}
64 {
64 {
65 }
65 }
66
66
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 const SqpRange &range)
68 const SqpRange &range)
69 {
69 {
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71
71
72 // Prevents that data has changed to update rendering
72 // Prevents that data has changed to update rendering
73 m_RenderingDelegate->onPlotUpdated();
73 m_RenderingDelegate->onPlotUpdated();
74 }
74 }
75
75
76 QString m_Name;
76 QString m_Name;
77 // 1 variable -> n qcpplot
77 // 1 variable -> n qcpplot
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 bool m_DoAcquisition;
79 bool m_DoAcquisition;
80 bool m_IsCalibration;
80 bool m_IsCalibration;
81 /// Delegate used to attach rendering features to the plot
81 /// Delegate used to attach rendering features to the plot
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83
83
84 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86
86
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89
89
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93
93
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95
95
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 {
97 {
98 removeDrawingRect(plot);
98 removeDrawingRect(plot);
99
99
100 auto axisPos = posToAxisPos(pos, plot);
100 auto axisPos = posToAxisPos(pos, plot);
101
101
102 m_DrawingZoomRect = new QCPItemRect{&plot};
102 m_DrawingZoomRect = new QCPItemRect{&plot};
103 QPen p;
103 QPen p;
104 p.setWidth(2);
104 p.setWidth(2);
105 m_DrawingZoomRect->setPen(p);
105 m_DrawingZoomRect->setPen(p);
106
106
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 }
109 }
110
110
111 void removeDrawingRect(QCustomPlot &plot)
111 void removeDrawingRect(QCustomPlot &plot)
112 {
112 {
113 if (m_DrawingZoomRect) {
113 if (m_DrawingZoomRect) {
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 m_DrawingZoomRect = nullptr;
115 m_DrawingZoomRect = nullptr;
116 plot.replot(QCustomPlot::rpQueuedReplot);
116 plot.replot(QCustomPlot::rpQueuedReplot);
117 }
117 }
118 }
118 }
119
119
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 {
121 {
122 endDrawingZone(graph);
122 endDrawingZone(graph);
123
123
124 auto axisPos = posToAxisPos(pos, graph->plot());
124 auto axisPos = posToAxisPos(pos, graph->plot());
125
125
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setEditionEnabled(false);
128 m_DrawingZone->setEditionEnabled(false);
129 }
129 }
130
130
131 void endDrawingZone(VisualizationGraphWidget *graph)
131 void endDrawingZone(VisualizationGraphWidget *graph)
132 {
132 {
133 if (m_DrawingZone) {
133 if (m_DrawingZone) {
134 auto drawingZoneRange = m_DrawingZone->range();
134 auto drawingZoneRange = m_DrawingZone->range();
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 m_DrawingZone->setEditionEnabled(true);
136 m_DrawingZone->setEditionEnabled(true);
137 addSelectionZone(m_DrawingZone);
137 addSelectionZone(m_DrawingZone);
138 }
138 }
139 else {
139 else {
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 }
141 }
142
142
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 m_DrawingZone = nullptr;
144 m_DrawingZone = nullptr;
145 }
145 }
146 }
146 }
147
147
148 void setSelectionZonesEditionEnabled(bool value)
148 void setSelectionZonesEditionEnabled(bool value)
149 {
149 {
150 for (auto s : m_SelectionZones) {
150 for (auto s : m_SelectionZones) {
151 s->setEditionEnabled(value);
151 s->setEditionEnabled(value);
152 }
152 }
153 }
153 }
154
154
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156
156
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 const QCustomPlot &plot) const
158 const QCustomPlot &plot) const
159 {
159 {
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 auto minDistanceToZone = -1;
161 auto minDistanceToZone = -1;
162 for (auto zone : m_SelectionZones) {
162 for (auto zone : m_SelectionZones) {
163 auto distanceToZone = zone->selectTest(pos, false);
163 auto distanceToZone = zone->selectTest(pos, false);
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 selectionZoneItemUnderCursor = zone;
166 selectionZoneItemUnderCursor = zone;
167 }
167 }
168 }
168 }
169
169
170 return selectionZoneItemUnderCursor;
170 return selectionZoneItemUnderCursor;
171 }
171 }
172
172
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
174 {
174 {
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
178 }
178 }
179
179
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
181 {
181 {
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
185 }
185 }
186 };
186 };
187
187
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
189 : VisualizationDragWidget{parent},
189 : VisualizationDragWidget{parent},
190 ui{new Ui::VisualizationGraphWidget},
190 ui{new Ui::VisualizationGraphWidget},
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
192 {
192 {
193 ui->setupUi(this);
193 ui->setupUi(this);
194
194
195 // 'Close' options : widget is deleted when closed
195 // 'Close' options : widget is deleted when closed
196 setAttribute(Qt::WA_DeleteOnClose);
196 setAttribute(Qt::WA_DeleteOnClose);
197
197
198 // Set qcpplot properties :
198 // Set qcpplot properties :
199 // - zoom is enabled
199 // - zoom is enabled
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
201 ui->widget->setInteractions(QCP::iRangeZoom);
201 ui->widget->setInteractions(QCP::iRangeZoom);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
203
203
204 // The delegate must be initialized after the ui as it uses the plot
204 // The delegate must be initialized after the ui as it uses the plot
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
206
206
207 // Init the cursors
207 // Init the cursors
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
212
212
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
215 &VisualizationGraphWidget::onMouseRelease);
215 &VisualizationGraphWidget::onMouseRelease);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
219 &VisualizationGraphWidget::onMouseDoubleClick);
219 &VisualizationGraphWidget::onMouseDoubleClick);
220 connect(
220 connect(
221 ui->widget->xAxis,
221 ui->widget->xAxis,
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
224
224
225 // Activates menu when right clicking on the graph
225 // Activates menu when right clicking on the graph
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
228 &VisualizationGraphWidget::onGraphMenuRequested);
228 &VisualizationGraphWidget::onGraphMenuRequested);
229
229
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
231 &VariableController::onRequestDataLoading);
231 &VariableController::onRequestDataLoading);
232
232
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
235
235
236 #ifdef Q_OS_MAC
236 #ifdef Q_OS_MAC
237 plot().setPlottingHint(QCP::phFastPolylines, true);
237 plot().setPlottingHint(QCP::phFastPolylines, true);
238 #endif
238 #endif
239 }
239 }
240
240
241
241
242 VisualizationGraphWidget::~VisualizationGraphWidget()
242 VisualizationGraphWidget::~VisualizationGraphWidget()
243 {
243 {
244 delete ui;
244 delete ui;
245 }
245 }
246
246
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
248 {
248 {
249 auto parent = parentWidget();
249 auto parent = parentWidget();
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
251 parent = parent->parentWidget();
251 parent = parent->parentWidget();
252 }
252 }
253
253
254 return qobject_cast<VisualizationZoneWidget *>(parent);
254 return qobject_cast<VisualizationZoneWidget *>(parent);
255 }
255 }
256
256
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
258 {
258 {
259 auto parent = parentWidget();
259 auto parent = parentWidget();
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
261 parent = parent->parentWidget();
261 parent = parent->parentWidget();
262 }
262 }
263
263
264 return qobject_cast<VisualizationWidget *>(parent);
264 return qobject_cast<VisualizationWidget *>(parent);
265 }
265 }
266
266
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
268 {
268 {
269 impl->m_DoAcquisition = enable;
269 impl->m_DoAcquisition = enable;
270 }
270 }
271
271
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
273 {
273 {
274 // Uses delegate to create the qcpplot components according to the variable
274 // Uses delegate to create the qcpplot components according to the variable
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
276
276
277 if (auto dataSeries = variable->dataSeries()) {
277 if (auto dataSeries = variable->dataSeries()) {
278 // Set axes properties according to the units of the data series
278 // Set axes properties according to the units of the data series
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
280
280
281 // Sets rendering properties for the new plottables
281 // Sets rendering properties for the new plottables
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
283 // axes properties that have to be initialized
283 // axes properties that have to be initialized
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
285 }
285 }
286
286
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
288
288
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
290
290
291 this->enableAcquisition(false);
291 this->enableAcquisition(false);
292 this->setGraphRange(range);
292 this->setGraphRange(range);
293 this->enableAcquisition(true);
293 this->enableAcquisition(true);
294
294
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
296
296
297 emit variableAdded(variable);
297 emit variableAdded(variable);
298 }
298 }
299
299
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
301 {
301 {
302 // Each component associated to the variable :
302 // Each component associated to the variable :
303 // - is removed from qcpplot (which deletes it)
303 // - is removed from qcpplot (which deletes it)
304 // - is no longer referenced in the map
304 // - is no longer referenced in the map
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
307 emit variableAboutToBeRemoved(variable);
307 emit variableAboutToBeRemoved(variable);
308
308
309 auto &plottablesMap = variableIt->second;
309 auto &plottablesMap = variableIt->second;
310
310
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
312 plottableIt != plottableEnd;) {
312 plottableIt != plottableEnd;) {
313 ui->widget->removePlottable(plottableIt->second);
313 ui->widget->removePlottable(plottableIt->second);
314 plottableIt = plottablesMap.erase(plottableIt);
314 plottableIt = plottablesMap.erase(plottableIt);
315 }
315 }
316
316
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
318 }
318 }
319
319
320 // Updates graph
320 // Updates graph
321 ui->widget->replot();
321 ui->widget->replot();
322 }
322 }
323
323
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
325 {
325 {
326 auto variables = QList<std::shared_ptr<Variable> >{};
326 auto variables = QList<std::shared_ptr<Variable> >{};
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
329 variables << it->first;
329 variables << it->first;
330 }
330 }
331
331
332 return variables;
332 return variables;
333 }
333 }
334
334
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
336 {
336 {
337 if (!variable) {
337 if (!variable) {
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
339 return;
339 return;
340 }
340 }
341
341
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
343 }
343 }
344
344
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
346 {
346 {
347 auto graphRange = ui->widget->xAxis->range();
347 auto graphRange = ui->widget->xAxis->range();
348 return SqpRange{graphRange.lower, graphRange.upper};
348 return SqpRange{graphRange.lower, graphRange.upper};
349 }
349 }
350
350
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
352 {
352 {
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
355 ui->widget->replot();
355 ui->widget->replot();
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
357 }
357 }
358
358
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
360 {
360 {
361 QVector<SqpRange> ranges;
361 QVector<SqpRange> ranges;
362 for (auto zone : impl->m_SelectionZones) {
362 for (auto zone : impl->m_SelectionZones) {
363 ranges << zone->range();
363 ranges << zone->range();
364 }
364 }
365
365
366 return ranges;
366 return ranges;
367 }
367 }
368
368
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
370 {
370 {
371 for (const auto &range : ranges) {
371 for (const auto &range : ranges) {
372 // note: ownership is transfered to QCustomPlot
372 // note: ownership is transfered to QCustomPlot
373 auto zone = new VisualizationSelectionZoneItem(&plot());
373 auto zone = new VisualizationSelectionZoneItem(&plot());
374 zone->setRange(range.m_TStart, range.m_TEnd);
374 zone->setRange(range.m_TStart, range.m_TEnd);
375 impl->addSelectionZone(zone);
375 impl->addSelectionZone(zone);
376 }
376 }
377
377
378 plot().replot(QCustomPlot::rpQueuedReplot);
378 plot().replot(QCustomPlot::rpQueuedReplot);
379 }
379 }
380
380
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
382 {
382 {
383 impl->m_SelectionZones.removeAll(selectionZone);
383 impl->m_SelectionZones.removeAll(selectionZone);
384 plot().removeItem(selectionZone);
384 plot().removeItem(selectionZone);
385 plot().replot(QCustomPlot::rpQueuedReplot);
385 plot().replot(QCustomPlot::rpQueuedReplot);
386 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
386 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
387 }
387 }
388
388
389 void VisualizationGraphWidget::undoZoom()
389 void VisualizationGraphWidget::undoZoom()
390 {
390 {
391 auto zoom = impl->m_ZoomStack.pop();
391 auto zoom = impl->m_ZoomStack.pop();
392 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
392 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
393 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
393 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
394
394
395 axisX->setRange(zoom.first);
395 axisX->setRange(zoom.first);
396 axisY->setRange(zoom.second);
396 axisY->setRange(zoom.second);
397
397
398 plot().replot(QCustomPlot::rpQueuedReplot);
398 plot().replot(QCustomPlot::rpQueuedReplot);
399 }
399 }
400
400
401 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
401 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
402 {
402 {
403 if (visitor) {
403 if (visitor) {
404 visitor->visit(this);
404 visitor->visit(this);
405 }
405 }
406 else {
406 else {
407 qCCritical(LOG_VisualizationGraphWidget())
407 qCCritical(LOG_VisualizationGraphWidget())
408 << tr("Can't visit widget : the visitor is null");
408 << tr("Can't visit widget : the visitor is null");
409 }
409 }
410 }
410 }
411
411
412 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
412 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
413 {
413 {
414 auto isSpectrogram = [](const auto &variable) {
414 auto isSpectrogram = [](const auto &variable) {
415 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
415 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
416 };
416 };
417
417
418 // - A spectrogram series can't be dropped on graph with existing plottables
418 // - A spectrogram series can't be dropped on graph with existing plottables
419 // - No data series can be dropped on graph with existing spectrogram series
419 // - No data series can be dropped on graph with existing spectrogram series
420 return isSpectrogram(variable)
420 return isSpectrogram(variable)
421 ? impl->m_VariableToPlotMultiMap.empty()
421 ? impl->m_VariableToPlotMultiMap.empty()
422 : std::none_of(
422 : std::none_of(
423 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
423 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
424 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
424 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
425 }
425 }
426
426
427 bool VisualizationGraphWidget::contains(const Variable &variable) const
427 bool VisualizationGraphWidget::contains(const Variable &variable) const
428 {
428 {
429 // Finds the variable among the keys of the map
429 // Finds the variable among the keys of the map
430 auto variablePtr = &variable;
430 auto variablePtr = &variable;
431 auto findVariable
431 auto findVariable
432 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
432 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
433
433
434 auto end = impl->m_VariableToPlotMultiMap.cend();
434 auto end = impl->m_VariableToPlotMultiMap.cend();
435 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
435 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
436 return it != end;
436 return it != end;
437 }
437 }
438
438
439 QString VisualizationGraphWidget::name() const
439 QString VisualizationGraphWidget::name() const
440 {
440 {
441 return impl->m_Name;
441 return impl->m_Name;
442 }
442 }
443
443
444 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
444 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
445 {
445 {
446 auto mimeData = new QMimeData;
446 auto mimeData = new QMimeData;
447
447
448 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
448 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
449 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
449 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
450 && selectionZoneItemUnderCursor) {
450 && selectionZoneItemUnderCursor) {
451 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
451 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
452 selectionZoneItemUnderCursor->range()));
452 selectionZoneItemUnderCursor->range()));
453 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
453 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
454 selectionZoneItemUnderCursor->range()));
454 selectionZoneItemUnderCursor->range()));
455 }
455 }
456 else {
456 else {
457 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
457 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
458
458
459 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
459 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
460 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
460 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
461 }
461 }
462
462
463 return mimeData;
463 return mimeData;
464 }
464 }
465
465
466 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
466 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
467 {
467 {
468 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
468 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
469 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
469 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
470 && selectionZoneItemUnderCursor) {
470 && selectionZoneItemUnderCursor) {
471
471
472 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
472 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
473 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
473 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
474
474
475 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
475 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
476 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
476 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
477 .toSize();
477 .toSize();
478
478
479 auto pixmap = QPixmap(zoneSize);
479 auto pixmap = QPixmap(zoneSize);
480 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
480 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
481
481
482 return pixmap;
482 return pixmap;
483 }
483 }
484
484
485 return QPixmap();
485 return QPixmap();
486 }
486 }
487
487
488 bool VisualizationGraphWidget::isDragAllowed() const
488 bool VisualizationGraphWidget::isDragAllowed() const
489 {
489 {
490 return true;
490 return true;
491 }
491 }
492
492
493 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
493 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
494 {
494 {
495 if (highlighted) {
495 if (highlighted) {
496 plot().setBackground(QBrush(QColor("#BBD5EE")));
496 plot().setBackground(QBrush(QColor("#BBD5EE")));
497 }
497 }
498 else {
498 else {
499 plot().setBackground(QBrush(Qt::white));
499 plot().setBackground(QBrush(Qt::white));
500 }
500 }
501
501
502 plot().update();
502 plot().update();
503 }
503 }
504
504
505 void VisualizationGraphWidget::addVerticalCursor(double time)
505 void VisualizationGraphWidget::addVerticalCursor(double time)
506 {
506 {
507 impl->m_VerticalCursor->setPosition(time);
507 impl->m_VerticalCursor->setPosition(time);
508 impl->m_VerticalCursor->setVisible(true);
508 impl->m_VerticalCursor->setVisible(true);
509
509
510 auto text
510 auto text
511 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
511 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
512 impl->m_VerticalCursor->setLabelText(text);
512 impl->m_VerticalCursor->setLabelText(text);
513 }
513 }
514
514
515 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
515 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
516 {
516 {
517 impl->m_VerticalCursor->setAbsolutePosition(position);
517 impl->m_VerticalCursor->setAbsolutePosition(position);
518 impl->m_VerticalCursor->setVisible(true);
518 impl->m_VerticalCursor->setVisible(true);
519
519
520 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
520 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
521 auto text
521 auto text
522 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
522 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
523 impl->m_VerticalCursor->setLabelText(text);
523 impl->m_VerticalCursor->setLabelText(text);
524 }
524 }
525
525
526 void VisualizationGraphWidget::removeVerticalCursor()
526 void VisualizationGraphWidget::removeVerticalCursor()
527 {
527 {
528 impl->m_VerticalCursor->setVisible(false);
528 impl->m_VerticalCursor->setVisible(false);
529 plot().replot(QCustomPlot::rpQueuedReplot);
529 plot().replot(QCustomPlot::rpQueuedReplot);
530 }
530 }
531
531
532 void VisualizationGraphWidget::addHorizontalCursor(double value)
532 void VisualizationGraphWidget::addHorizontalCursor(double value)
533 {
533 {
534 impl->m_HorizontalCursor->setPosition(value);
534 impl->m_HorizontalCursor->setPosition(value);
535 impl->m_HorizontalCursor->setVisible(true);
535 impl->m_HorizontalCursor->setVisible(true);
536 impl->m_HorizontalCursor->setLabelText(QString::number(value));
536 impl->m_HorizontalCursor->setLabelText(QString::number(value));
537 }
537 }
538
538
539 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
539 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
540 {
540 {
541 impl->m_HorizontalCursor->setAbsolutePosition(position);
541 impl->m_HorizontalCursor->setAbsolutePosition(position);
542 impl->m_HorizontalCursor->setVisible(true);
542 impl->m_HorizontalCursor->setVisible(true);
543
543
544 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
544 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
545 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
545 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
546 }
546 }
547
547
548 void VisualizationGraphWidget::removeHorizontalCursor()
548 void VisualizationGraphWidget::removeHorizontalCursor()
549 {
549 {
550 impl->m_HorizontalCursor->setVisible(false);
550 impl->m_HorizontalCursor->setVisible(false);
551 plot().replot(QCustomPlot::rpQueuedReplot);
551 plot().replot(QCustomPlot::rpQueuedReplot);
552 }
552 }
553
553
554 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
554 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
555 {
555 {
556 Q_UNUSED(event);
556 Q_UNUSED(event);
557
557
558 // Prevents that all variables will be removed from graph when it will be closed
558 // Prevents that all variables will be removed from graph when it will be closed
559 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
559 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
560 emit variableAboutToBeRemoved(variableEntry.first);
560 emit variableAboutToBeRemoved(variableEntry.first);
561 }
561 }
562 }
562 }
563
563
564 void VisualizationGraphWidget::enterEvent(QEvent *event)
564 void VisualizationGraphWidget::enterEvent(QEvent *event)
565 {
565 {
566 Q_UNUSED(event);
566 Q_UNUSED(event);
567 impl->m_RenderingDelegate->showGraphOverlay(true);
567 impl->m_RenderingDelegate->showGraphOverlay(true);
568 }
568 }
569
569
570 void VisualizationGraphWidget::leaveEvent(QEvent *event)
570 void VisualizationGraphWidget::leaveEvent(QEvent *event)
571 {
571 {
572 Q_UNUSED(event);
572 Q_UNUSED(event);
573 impl->m_RenderingDelegate->showGraphOverlay(false);
573 impl->m_RenderingDelegate->showGraphOverlay(false);
574
574
575 if (auto parentZone = parentZoneWidget()) {
575 if (auto parentZone = parentZoneWidget()) {
576 parentZone->notifyMouseLeaveGraph(this);
576 parentZone->notifyMouseLeaveGraph(this);
577 }
577 }
578 else {
578 else {
579 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
579 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
580 }
580 }
581
581
582 if (impl->m_HoveredZone) {
582 if (impl->m_HoveredZone) {
583 impl->m_HoveredZone->setHovered(false);
583 impl->m_HoveredZone->setHovered(false);
584 impl->m_HoveredZone = nullptr;
584 impl->m_HoveredZone = nullptr;
585 }
585 }
586 }
586 }
587
587
588 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
588 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
589 {
589 {
590 return *ui->widget;
590 return *ui->widget;
591 }
591 }
592
592
593 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
593 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
594 {
594 {
595 QMenu graphMenu{};
595 QMenu graphMenu{};
596
596
597 // Iterates on variables (unique keys)
597 // Iterates on variables (unique keys)
598 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
598 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
599 end = impl->m_VariableToPlotMultiMap.cend();
599 end = impl->m_VariableToPlotMultiMap.cend();
600 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
600 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
601 // 'Remove variable' action
601 // 'Remove variable' action
602 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
602 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
603 [ this, var = it->first ]() { removeVariable(var); });
603 [ this, var = it->first ]() { removeVariable(var); });
604 }
604 }
605
605
606 if (!impl->m_ZoomStack.isEmpty()) {
606 if (!impl->m_ZoomStack.isEmpty()) {
607 if (!graphMenu.isEmpty()) {
607 if (!graphMenu.isEmpty()) {
608 graphMenu.addSeparator();
608 graphMenu.addSeparator();
609 }
609 }
610
610
611 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
611 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
612 }
612 }
613
613
614 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
614 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
615 if (selectionZoneItem) {
615 if (selectionZoneItem) {
616 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
616 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
617 selectedItems.removeAll(selectionZoneItem);
618 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
619
617 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
620 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
618 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
621 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
619 graphMenu.addSeparator();
622 graphMenu.addSeparator();
620 }
623 }
621
624
622 for (auto zoneAction : zoneActions) {
625 for (auto zoneAction : zoneActions) {
623 auto action = graphMenu.addAction(zoneAction->name());
626 auto action = graphMenu.addAction(zoneAction->name());
624 action->setEnabled(zoneAction->isEnabled(selectedItems));
627 action->setEnabled(zoneAction->isEnabled(selectedItems));
625 QObject::connect(action, &QAction::triggered, [zoneAction, &selectedItems]() {
628 QObject::connect(action, &QAction::triggered,
626 zoneAction->execute(selectedItems);
629 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
627 });
628 }
630 }
629 }
631 }
630
632
631 if (!graphMenu.isEmpty()) {
633 if (!graphMenu.isEmpty()) {
632 graphMenu.exec(QCursor::pos());
634 graphMenu.exec(QCursor::pos());
633 }
635 }
634 }
636 }
635
637
636 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
638 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
637 {
639 {
638 qCDebug(LOG_VisualizationGraphWidget())
640 qCDebug(LOG_VisualizationGraphWidget())
639 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
641 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
640 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
642 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
641
643
642 auto graphRange = SqpRange{t1.lower, t1.upper};
644 auto graphRange = SqpRange{t1.lower, t1.upper};
643 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
645 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
644
646
645 if (impl->m_DoAcquisition) {
647 if (impl->m_DoAcquisition) {
646 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
648 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
647
649
648 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
650 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
649 end = impl->m_VariableToPlotMultiMap.end();
651 end = impl->m_VariableToPlotMultiMap.end();
650 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
652 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
651 variableUnderGraphVector.push_back(it->first);
653 variableUnderGraphVector.push_back(it->first);
652 }
654 }
653 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
655 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
654 !impl->m_IsCalibration);
656 !impl->m_IsCalibration);
655
657
656 if (!impl->m_IsCalibration) {
658 if (!impl->m_IsCalibration) {
657 qCDebug(LOG_VisualizationGraphWidget())
659 qCDebug(LOG_VisualizationGraphWidget())
658 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
660 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
659 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
661 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
660 emit synchronize(graphRange, oldGraphRange);
662 emit synchronize(graphRange, oldGraphRange);
661 }
663 }
662 }
664 }
663
665
664 auto pos = mapFromGlobal(QCursor::pos());
666 auto pos = mapFromGlobal(QCursor::pos());
665 auto axisPos = impl->posToAxisPos(pos, plot());
667 auto axisPos = impl->posToAxisPos(pos, plot());
666 if (auto parentZone = parentZoneWidget()) {
668 if (auto parentZone = parentZoneWidget()) {
667 if (impl->pointIsInAxisRect(axisPos, plot())) {
669 if (impl->pointIsInAxisRect(axisPos, plot())) {
668 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
670 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
669 }
671 }
670 else {
672 else {
671 parentZone->notifyMouseLeaveGraph(this);
673 parentZone->notifyMouseLeaveGraph(this);
672 }
674 }
673 }
675 }
674 else {
676 else {
675 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
677 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
676 }
678 }
677 }
679 }
678
680
679 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
681 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
680 {
682 {
681 impl->m_RenderingDelegate->onMouseDoubleClick(event);
683 impl->m_RenderingDelegate->onMouseDoubleClick(event);
682 }
684 }
683
685
684 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
686 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
685 {
687 {
686 // Handles plot rendering when mouse is moving
688 // Handles plot rendering when mouse is moving
687 impl->m_RenderingDelegate->onMouseMove(event);
689 impl->m_RenderingDelegate->onMouseMove(event);
688
690
689 auto axisPos = impl->posToAxisPos(event->pos(), plot());
691 auto axisPos = impl->posToAxisPos(event->pos(), plot());
690
692
691 // Zoom box and zone drawing
693 // Zoom box and zone drawing
692 if (impl->m_DrawingZoomRect) {
694 if (impl->m_DrawingZoomRect) {
693 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
695 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
694 }
696 }
695 else if (impl->m_DrawingZone) {
697 else if (impl->m_DrawingZone) {
696 impl->m_DrawingZone->setEnd(axisPos.x());
698 impl->m_DrawingZone->setEnd(axisPos.x());
697 }
699 }
698
700
699 // Cursor
701 // Cursor
700 if (auto parentZone = parentZoneWidget()) {
702 if (auto parentZone = parentZoneWidget()) {
701 if (impl->pointIsInAxisRect(axisPos, plot())) {
703 if (impl->pointIsInAxisRect(axisPos, plot())) {
702 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
704 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
703 }
705 }
704 else {
706 else {
705 parentZone->notifyMouseLeaveGraph(this);
707 parentZone->notifyMouseLeaveGraph(this);
706 }
708 }
707 }
709 }
708 else {
710 else {
709 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
711 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
710 }
712 }
711
713
712 // Search for the selection zone under the mouse
714 // Search for the selection zone under the mouse
713 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
715 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
714 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
716 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
715 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
717 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
716
718
717 // Sets the appropriate cursor shape
719 // Sets the appropriate cursor shape
718 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
720 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
719 setCursor(cursorShape);
721 setCursor(cursorShape);
720
722
721 // Manages the hovered zone
723 // Manages the hovered zone
722 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
724 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
723 if (impl->m_HoveredZone) {
725 if (impl->m_HoveredZone) {
724 impl->m_HoveredZone->setHovered(false);
726 impl->m_HoveredZone->setHovered(false);
725 }
727 }
726 selectionZoneItemUnderCursor->setHovered(true);
728 selectionZoneItemUnderCursor->setHovered(true);
727 impl->m_HoveredZone = selectionZoneItemUnderCursor;
729 impl->m_HoveredZone = selectionZoneItemUnderCursor;
728 plot().replot(QCustomPlot::rpQueuedReplot);
730 plot().replot(QCustomPlot::rpQueuedReplot);
729 }
731 }
730 }
732 }
731 else {
733 else {
732 // There is no zone under the mouse or the interaction mode is not "selection zones"
734 // There is no zone under the mouse or the interaction mode is not "selection zones"
733 if (impl->m_HoveredZone) {
735 if (impl->m_HoveredZone) {
734 impl->m_HoveredZone->setHovered(false);
736 impl->m_HoveredZone->setHovered(false);
735 impl->m_HoveredZone = nullptr;
737 impl->m_HoveredZone = nullptr;
736 }
738 }
737
739
738 setCursor(Qt::ArrowCursor);
740 setCursor(Qt::ArrowCursor);
739 }
741 }
740
742
741 impl->m_HasMovedMouse = true;
743 impl->m_HasMovedMouse = true;
742 VisualizationDragWidget::mouseMoveEvent(event);
744 VisualizationDragWidget::mouseMoveEvent(event);
743 }
745 }
744
746
745 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
747 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
746 {
748 {
747 auto value = event->angleDelta().x() + event->angleDelta().y();
749 auto value = event->angleDelta().x() + event->angleDelta().y();
748 if (value != 0) {
750 if (value != 0) {
749
751
750 auto direction = value > 0 ? 1.0 : -1.0;
752 auto direction = value > 0 ? 1.0 : -1.0;
751 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
753 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
752 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
754 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
753 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
755 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
754
756
755 auto zoomOrientations = QFlags<Qt::Orientation>{};
757 auto zoomOrientations = QFlags<Qt::Orientation>{};
756 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
758 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
757 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
759 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
758
760
759 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
761 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
760
762
761 if (!isZoomX && !isZoomY) {
763 if (!isZoomX && !isZoomY) {
762 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
764 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
763 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
765 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
764
766
765 axis->setRange(axis->range() + diff);
767 axis->setRange(axis->range() + diff);
766
768
767 if (plot().noAntialiasingOnDrag()) {
769 if (plot().noAntialiasingOnDrag()) {
768 plot().setNotAntialiasedElements(QCP::aeAll);
770 plot().setNotAntialiasedElements(QCP::aeAll);
769 }
771 }
770
772
771 plot().replot(QCustomPlot::rpQueuedReplot);
773 plot().replot(QCustomPlot::rpQueuedReplot);
772 }
774 }
773 }
775 }
774 }
776 }
775
777
776 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
778 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
777 {
779 {
778 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
780 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
779 auto isSelectionZoneMode
781 auto isSelectionZoneMode
780 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
782 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
781 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
783 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
782
784
783 if (!isDragDropClick && isLeftClick) {
785 if (!isDragDropClick && isLeftClick) {
784 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
786 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
785 // Starts a zoom box
787 // Starts a zoom box
786 impl->startDrawingRect(event->pos(), plot());
788 impl->startDrawingRect(event->pos(), plot());
787 }
789 }
788 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
790 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
789 // Starts a new selection zone
791 // Starts a new selection zone
790 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
792 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
791 if (!zoneAtPos) {
793 if (!zoneAtPos) {
792 impl->startDrawingZone(event->pos(), this);
794 impl->startDrawingZone(event->pos(), this);
793 }
795 }
794 }
796 }
795 }
797 }
796
798
797 // Allows mouse panning only in default mode
799 // Allows mouse panning only in default mode
798 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
800 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
799 == SqpApplication::PlotsInteractionMode::None
801 == SqpApplication::PlotsInteractionMode::None
800 && !isDragDropClick);
802 && !isDragDropClick);
801
803
802 // Allows zone edition only in selection zone mode without drag&drop
804 // Allows zone edition only in selection zone mode without drag&drop
803 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
805 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
804
806
805 // Selection / Deselection
807 // Selection / Deselection
806 if (isSelectionZoneMode) {
808 if (isSelectionZoneMode) {
807 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
809 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
808 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
810 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
809 if (selectionZoneItemUnderCursor && isLeftClick) {
811 if (selectionZoneItemUnderCursor && isLeftClick) {
810 selectionZoneItemUnderCursor->setAssociatedEditedZones(
812 selectionZoneItemUnderCursor->setAssociatedEditedZones(
811 parentVisualizationWidget()->selectionZoneManager().selectedItems());
813 parentVisualizationWidget()->selectionZoneManager().selectedItems());
812 }
814 }
813 else if (!isMultiSelectionClick && isLeftClick) {
815 else if (!isMultiSelectionClick && isLeftClick) {
814 parentVisualizationWidget()->selectionZoneManager().clearSelection();
816 parentVisualizationWidget()->selectionZoneManager().clearSelection();
815 }
817 }
816 else {
818 else {
817 // No selection change
819 // No selection change
818 }
820 }
819 }
821 }
820
822
821
823
822 impl->m_HasMovedMouse = false;
824 impl->m_HasMovedMouse = false;
823 VisualizationDragWidget::mousePressEvent(event);
825 VisualizationDragWidget::mousePressEvent(event);
824 }
826 }
825
827
826 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
828 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
827 {
829 {
828 if (impl->m_DrawingZoomRect) {
830 if (impl->m_DrawingZoomRect) {
829
831
830 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
832 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
831 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
833 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
832
834
833 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
835 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
834 impl->m_DrawingZoomRect->bottomRight->coords().x()};
836 impl->m_DrawingZoomRect->bottomRight->coords().x()};
835
837
836 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
838 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
837 impl->m_DrawingZoomRect->bottomRight->coords().y()};
839 impl->m_DrawingZoomRect->bottomRight->coords().y()};
838
840
839 impl->removeDrawingRect(plot());
841 impl->removeDrawingRect(plot());
840
842
841 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
843 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
842 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
844 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
843 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
845 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
844 axisX->setRange(newAxisXRange);
846 axisX->setRange(newAxisXRange);
845 axisY->setRange(newAxisYRange);
847 axisY->setRange(newAxisYRange);
846
848
847 plot().replot(QCustomPlot::rpQueuedReplot);
849 plot().replot(QCustomPlot::rpQueuedReplot);
848 }
850 }
849 }
851 }
850
852
851 impl->endDrawingZone(this);
853 impl->endDrawingZone(this);
852
854
853 impl->m_IsCalibration = false;
855 impl->m_IsCalibration = false;
854
856
855 // Selection / Deselection
857 // Selection / Deselection
856 auto isSelectionZoneMode
858 auto isSelectionZoneMode
857 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
859 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
858 if (isSelectionZoneMode) {
860 if (isSelectionZoneMode) {
859 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
861 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
860 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
862 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
861 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
863 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
862 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
864 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
863 parentVisualizationWidget()->selectionZoneManager().select(
865 parentVisualizationWidget()->selectionZoneManager().select(
864 {selectionZoneItemUnderCursor});
866 {selectionZoneItemUnderCursor});
865 }
867 }
866 else if (!impl->m_HasMovedMouse) {
868 else if (!impl->m_HasMovedMouse) {
867 parentVisualizationWidget()->selectionZoneManager().setSelected(
869 parentVisualizationWidget()->selectionZoneManager().setSelected(
868 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
870 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
869 || event->button() == Qt::RightButton);
871 || event->button() == Qt::RightButton);
870 }
872 }
871 }
873 }
872 else {
874 else {
873 // No selection change
875 // No selection change
874 }
876 }
875 }
877 }
876 }
878 }
877
879
878 void VisualizationGraphWidget::onDataCacheVariableUpdated()
880 void VisualizationGraphWidget::onDataCacheVariableUpdated()
879 {
881 {
880 auto graphRange = ui->widget->xAxis->range();
882 auto graphRange = ui->widget->xAxis->range();
881 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
883 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
882
884
883 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
885 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
884 auto variable = variableEntry.first;
886 auto variable = variableEntry.first;
885 qCDebug(LOG_VisualizationGraphWidget())
887 qCDebug(LOG_VisualizationGraphWidget())
886 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
888 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
887 qCDebug(LOG_VisualizationGraphWidget())
889 qCDebug(LOG_VisualizationGraphWidget())
888 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
890 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
889 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
891 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
890 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
892 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
891 }
893 }
892 }
894 }
893 }
895 }
894
896
895 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
897 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
896 const SqpRange &range)
898 const SqpRange &range)
897 {
899 {
898 auto it = impl->m_VariableToPlotMultiMap.find(variable);
900 auto it = impl->m_VariableToPlotMultiMap.find(variable);
899 if (it != impl->m_VariableToPlotMultiMap.end()) {
901 if (it != impl->m_VariableToPlotMultiMap.end()) {
900 impl->updateData(it->second, variable->dataSeries(), range);
902 impl->updateData(it->second, variable->dataSeries(), range);
901 }
903 }
902 }
904 }
@@ -1,354 +1,425
1 #include "Visualization/VisualizationSelectionZoneItem.h"
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
3
4 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
4 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
5
5
6 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
6 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
7
7
8 QCustomPlot *m_Plot;
8 QCustomPlot *m_Plot;
9 double m_T1 = 0;
9 double m_T1 = 0;
10 double m_T2 = 0;
10 double m_T2 = 0;
11 QColor m_Color;
11 QColor m_Color;
12
12
13 bool m_IsEditionEnabled = true;
13 bool m_IsEditionEnabled = true;
14 double m_MovedOrinalT1 = 0;
14 double m_MovedOrinalT1 = 0;
15 double m_MovedOrinalT2 = 0;
15 double m_MovedOrinalT2 = 0;
16
16
17 QCPItemStraightLine *m_LeftLine;
17 QCPItemStraightLine *m_LeftLine;
18 QCPItemStraightLine *m_RightLine;
18 QCPItemStraightLine *m_RightLine;
19 QCPItemText *m_NameLabelItem = nullptr;
19 QCPItemText *m_NameLabelItem = nullptr;
20
20
21 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
21 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
22 EditionMode m_CurrentEditionMode;
22 EditionMode m_CurrentEditionMode;
23
23
24 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
24 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
25
25
26 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
26 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
27 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
27 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
28 {
28 {
29 }
29 }
30
30
31 void updatePosition(VisualizationSelectionZoneItem *item)
31 void updatePosition(VisualizationSelectionZoneItem *item)
32 {
32 {
33 item->topLeft->setCoords(m_T1, 0);
33 item->topLeft->setCoords(m_T1, 0);
34 item->bottomRight->setCoords(m_T2, 1);
34 item->bottomRight->setCoords(m_T2, 1);
35 }
35 }
36
36
37 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
37 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
38 {
38 {
39 auto distanceLeft = m_LeftLine->selectTest(pos, false);
39 auto distanceLeft = m_LeftLine->selectTest(pos, false);
40 auto distanceRight = m_RightLine->selectTest(pos, false);
40 auto distanceRight = m_RightLine->selectTest(pos, false);
41 auto distance = zoneItem->selectTest(pos, false);
41 auto distance = zoneItem->selectTest(pos, false);
42
42
43 if (distanceRight <= distance) {
43 if (distanceRight <= distance) {
44 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
44 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
45 }
45 }
46 else if (distanceLeft <= distance) {
46 else if (distanceLeft <= distance) {
47 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
47 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
48 }
48 }
49
49
50 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
50 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
51 }
51 }
52
52
53 double pixelSizeToAxisXSize(double pixels)
53 double pixelSizeToAxisXSize(double pixels)
54 {
54 {
55 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
55 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
56 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
56 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
57 }
57 }
58
59 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
60 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
61 bool allowResize, bool vertically)
62 {
63 auto result = false;
64
65 auto referenceTime
66 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
67
68 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
69 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
70
71 for (auto otherZone : zonesToAlign) {
72
73 auto otherZoneRange = otherZone->range();
74 auto newZoneStart = otherZoneRange.m_TStart;
75 auto newZoneEnd = otherZoneRange.m_TEnd;
76
77 auto alignedTime = referenceTime;
78 if (vertically) {
79 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
80 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
81 }
82
83 if (alignOnLeft) {
84 newZoneStart = alignedTime;
85 if (!allowResize) {
86 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
87 }
88 }
89 else { // align on right
90 newZoneEnd = alignedTime;
91 if (!allowResize) {
92 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
93 }
94 }
95
96 if (newZoneStart < newZoneEnd) {
97 result = true;
98 otherZone->setRange(newZoneStart, newZoneEnd);
99 otherZone->parentPlot()->replot();
100 }
101 }
102
103 return result;
104 }
58 };
105 };
59
106
60 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
107 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
61 : QCPItemRect(plot),
108 : QCPItemRect(plot),
62 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
109 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
63 {
110 {
64 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
111 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
65 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
112 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
66 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
113 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
67 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
114 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
68 setSelectable(false);
115 setSelectable(false);
69
116
70 impl->m_RightLine = new QCPItemStraightLine(plot);
117 impl->m_RightLine = new QCPItemStraightLine(plot);
71 impl->m_RightLine->point1->setParentAnchor(topRight);
118 impl->m_RightLine->point1->setParentAnchor(topRight);
72 impl->m_RightLine->point2->setParentAnchor(bottomRight);
119 impl->m_RightLine->point2->setParentAnchor(bottomRight);
73 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
120 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
74 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
121 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
75 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
122 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
76 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
77 impl->m_RightLine->setSelectable(false);
124 impl->m_RightLine->setSelectable(false);
78
125
79 impl->m_LeftLine = new QCPItemStraightLine(plot);
126 impl->m_LeftLine = new QCPItemStraightLine(plot);
80 impl->m_LeftLine->point1->setParentAnchor(topLeft);
127 impl->m_LeftLine->point1->setParentAnchor(topLeft);
81 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
128 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
82 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
129 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
83 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
130 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
84 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
131 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
85 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
86 impl->m_LeftLine->setSelectable(false);
133 impl->m_LeftLine->setSelectable(false);
87
134
88 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
135 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
89 &QCPItemStraightLine::setSelected);
136 &QCPItemStraightLine::setSelected);
90 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
91 &QCPItemStraightLine::setSelected);
138 &QCPItemStraightLine::setSelected);
92
139
93 setColor(QColor(DEFAULT_COLOR));
140 setColor(QColor(DEFAULT_COLOR));
94 }
141 }
95
142
96 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
143 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
97 {
144 {
98 impl->m_Plot->removeItem(impl->m_RightLine);
145 impl->m_Plot->removeItem(impl->m_RightLine);
99 impl->m_Plot->removeItem(impl->m_LeftLine);
146 impl->m_Plot->removeItem(impl->m_LeftLine);
100 }
147 }
101
148
102 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
149 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
103 {
150 {
104 auto parent = impl->m_Plot->parentWidget();
151 auto parent = impl->m_Plot->parentWidget();
105 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
152 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
106 parent = parent->parentWidget();
153 parent = parent->parentWidget();
107 }
154 }
108
155
109 return qobject_cast<VisualizationGraphWidget *>(parent);
156 return qobject_cast<VisualizationGraphWidget *>(parent);
110 }
157 }
111
158
112 void VisualizationSelectionZoneItem::setName(const QString &name)
159 void VisualizationSelectionZoneItem::setName(const QString &name)
113 {
160 {
114 if (name.isEmpty() && impl->m_NameLabelItem) {
161 if (name.isEmpty() && impl->m_NameLabelItem) {
115 impl->m_Plot->removeItem(impl->m_NameLabelItem);
162 impl->m_Plot->removeItem(impl->m_NameLabelItem);
116 impl->m_NameLabelItem = nullptr;
163 impl->m_NameLabelItem = nullptr;
117 }
164 }
118 else if (!impl->m_NameLabelItem) {
165 else if (!impl->m_NameLabelItem) {
119 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
166 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
120 impl->m_NameLabelItem->setText(name);
167 impl->m_NameLabelItem->setText(name);
121 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
168 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
122 impl->m_NameLabelItem->setColor(impl->m_Color);
169 impl->m_NameLabelItem->setColor(impl->m_Color);
123 impl->m_NameLabelItem->position->setParentAnchor(top);
170 impl->m_NameLabelItem->position->setParentAnchor(top);
124 }
171 }
125 }
172 }
126
173
127 QString VisualizationSelectionZoneItem::name() const
174 QString VisualizationSelectionZoneItem::name() const
128 {
175 {
129 if (!impl->m_NameLabelItem) {
176 if (!impl->m_NameLabelItem) {
130 return QString();
177 return QString();
131 }
178 }
132
179
133 return impl->m_NameLabelItem->text();
180 return impl->m_NameLabelItem->text();
134 }
181 }
135
182
136 SqpRange VisualizationSelectionZoneItem::range() const
183 SqpRange VisualizationSelectionZoneItem::range() const
137 {
184 {
138 SqpRange range;
185 SqpRange range;
139 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
186 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
140 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
187 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
141 return range;
188 return range;
142 }
189 }
143
190
144 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
191 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
145 {
192 {
146 impl->m_T1 = tstart;
193 impl->m_T1 = tstart;
147 impl->m_T2 = tend;
194 impl->m_T2 = tend;
148 impl->updatePosition(this);
195 impl->updatePosition(this);
149 }
196 }
150
197
151 void VisualizationSelectionZoneItem::setStart(double tstart)
198 void VisualizationSelectionZoneItem::setStart(double tstart)
152 {
199 {
153 impl->m_T1 = tstart;
200 impl->m_T1 = tstart;
154 impl->updatePosition(this);
201 impl->updatePosition(this);
155 }
202 }
156
203
157 void VisualizationSelectionZoneItem::setEnd(double tend)
204 void VisualizationSelectionZoneItem::setEnd(double tend)
158 {
205 {
159 impl->m_T2 = tend;
206 impl->m_T2 = tend;
160 impl->updatePosition(this);
207 impl->updatePosition(this);
161 }
208 }
162
209
163 void VisualizationSelectionZoneItem::setColor(const QColor &color)
210 void VisualizationSelectionZoneItem::setColor(const QColor &color)
164 {
211 {
165 impl->m_Color = color;
212 impl->m_Color = color;
166
213
167 auto brushColor = color;
214 auto brushColor = color;
168 brushColor.setAlpha(80);
215 brushColor.setAlpha(80);
169 setBrush(QBrush(brushColor));
216 setBrush(QBrush(brushColor));
170 setPen(QPen(Qt::NoPen));
217 setPen(QPen(Qt::NoPen));
171
218
172 auto selectedBrushColor = brushColor;
219 auto selectedBrushColor = brushColor;
173 selectedBrushColor.setAlpha(150);
220 selectedBrushColor.setAlpha(150);
174 setSelectedBrush(QBrush(selectedBrushColor));
221 setSelectedBrush(QBrush(selectedBrushColor));
175 setSelectedPen(QPen(Qt::NoPen));
222 setSelectedPen(QPen(Qt::NoPen));
176
223
177 auto linePen = QPen(color);
224 auto linePen = QPen(color);
178 linePen.setStyle(Qt::SolidLine);
225 linePen.setStyle(Qt::SolidLine);
179 linePen.setWidth(4);
226 linePen.setWidth(4);
180
227
181 auto selectedLinePen = linePen;
228 auto selectedLinePen = linePen;
182 selectedLinePen.setColor(color.darker(120));
229 selectedLinePen.setColor(color.darker(120));
183 selectedLinePen.setWidth(4);
230 selectedLinePen.setWidth(4);
184
231
185 impl->m_LeftLine->setPen(linePen);
232 impl->m_LeftLine->setPen(linePen);
186 impl->m_RightLine->setPen(linePen);
233 impl->m_RightLine->setPen(linePen);
187
234
188 impl->m_LeftLine->setSelectedPen(selectedLinePen);
235 impl->m_LeftLine->setSelectedPen(selectedLinePen);
189 impl->m_RightLine->setSelectedPen(selectedLinePen);
236 impl->m_RightLine->setSelectedPen(selectedLinePen);
190 }
237 }
191
238
192 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
239 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
193 {
240 {
194 impl->m_IsEditionEnabled = value;
241 impl->m_IsEditionEnabled = value;
195 setSelectable(value);
242 setSelectable(value);
196 if (!value) {
243 if (!value) {
197 setSelected(false);
244 setSelected(false);
198 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
245 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
199 }
246 }
200 }
247 }
201
248
202 bool VisualizationSelectionZoneItem::isEditionEnabled() const
249 bool VisualizationSelectionZoneItem::isEditionEnabled() const
203 {
250 {
204 return impl->m_IsEditionEnabled;
251 return impl->m_IsEditionEnabled;
205 }
252 }
206
253
207 Qt::CursorShape
254 Qt::CursorShape
208 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
255 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
209 {
256 {
210 auto mode = impl->m_CurrentEditionMode
257 auto mode = impl->m_CurrentEditionMode
211 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
258 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
212 ? impl->getEditionMode(position, this)
259 ? impl->getEditionMode(position, this)
213 : impl->m_CurrentEditionMode;
260 : impl->m_CurrentEditionMode;
214 switch (mode) {
261 switch (mode) {
215 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
262 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
216 return Qt::SizeAllCursor;
263 return Qt::SizeAllCursor;
217 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
264 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
218 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
265 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
219 return Qt::SizeHorCursor;
266 return Qt::SizeHorCursor;
220 default:
267 default:
221 return Qt::ArrowCursor;
268 return Qt::ArrowCursor;
222 }
269 }
223 }
270 }
224
271
225 void VisualizationSelectionZoneItem::setHovered(bool value)
272 void VisualizationSelectionZoneItem::setHovered(bool value)
226 {
273 {
227 if (value) {
274 if (value) {
228 auto linePen = impl->m_LeftLine->pen();
275 auto linePen = impl->m_LeftLine->pen();
229 linePen.setStyle(Qt::DotLine);
276 linePen.setStyle(Qt::DotLine);
230 linePen.setWidth(3);
277 linePen.setWidth(3);
231
278
232 auto selectedLinePen = impl->m_LeftLine->selectedPen();
279 auto selectedLinePen = impl->m_LeftLine->selectedPen();
233 ;
280 ;
234 selectedLinePen.setStyle(Qt::DotLine);
281 selectedLinePen.setStyle(Qt::DotLine);
235 selectedLinePen.setWidth(3);
282 selectedLinePen.setWidth(3);
236
283
237 impl->m_LeftLine->setPen(linePen);
284 impl->m_LeftLine->setPen(linePen);
238 impl->m_RightLine->setPen(linePen);
285 impl->m_RightLine->setPen(linePen);
239
286
240 impl->m_LeftLine->setSelectedPen(selectedLinePen);
287 impl->m_LeftLine->setSelectedPen(selectedLinePen);
241 impl->m_RightLine->setSelectedPen(selectedLinePen);
288 impl->m_RightLine->setSelectedPen(selectedLinePen);
242 }
289 }
243 else {
290 else {
244 setColor(impl->m_Color);
291 setColor(impl->m_Color);
245 }
292 }
246 }
293 }
247
294
248 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
295 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
249 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
296 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
250 {
297 {
251 impl->m_AssociatedEditedZones = associatedZones;
298 impl->m_AssociatedEditedZones = associatedZones;
252 impl->m_AssociatedEditedZones.removeAll(this);
299 impl->m_AssociatedEditedZones.removeAll(this);
253 }
300 }
254
301
302 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
303 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
304 {
305 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
306 }
307
308 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
309 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
310 {
311 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
312 }
313
314 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
315 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
316 {
317 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
318 }
319
320 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
321 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
322 {
323 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
324 }
325
255 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
326 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
256 {
327 {
257 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
328 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
258 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
329 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
259
330
260 impl->m_MovedOrinalT1 = impl->m_T1;
331 impl->m_MovedOrinalT1 = impl->m_T1;
261 impl->m_MovedOrinalT2 = impl->m_T2;
332 impl->m_MovedOrinalT2 = impl->m_T2;
262 for (auto associatedZone : impl->m_AssociatedEditedZones) {
333 for (auto associatedZone : impl->m_AssociatedEditedZones) {
263 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
334 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
264 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
335 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
265 }
336 }
266 }
337 }
267 else {
338 else {
268 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
339 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
269 event->ignore();
340 event->ignore();
270 }
341 }
271 }
342 }
272
343
273 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
344 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
274 {
345 {
275 if (isEditionEnabled()) {
346 if (isEditionEnabled()) {
276 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
347 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
277 auto pixelDiff = event->pos().x() - startPos.x();
348 auto pixelDiff = event->pos().x() - startPos.x();
278 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
349 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
279
350
280 switch (impl->m_CurrentEditionMode) {
351 switch (impl->m_CurrentEditionMode) {
281 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
352 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
282 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
353 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
283 for (auto associatedZone : impl->m_AssociatedEditedZones) {
354 for (auto associatedZone : impl->m_AssociatedEditedZones) {
284 associatedZone->move(pixelDiff);
355 associatedZone->move(pixelDiff);
285 }
356 }
286 break;
357 break;
287 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
358 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
288 setStart(impl->m_MovedOrinalT1 + diff);
359 setStart(impl->m_MovedOrinalT1 + diff);
289 for (auto associatedZone : impl->m_AssociatedEditedZones) {
360 for (auto associatedZone : impl->m_AssociatedEditedZones) {
290 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
361 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
291 ? associatedZone->resizeLeft(pixelDiff)
362 ? associatedZone->resizeLeft(pixelDiff)
292 : associatedZone->resizeRight(pixelDiff);
363 : associatedZone->resizeRight(pixelDiff);
293 }
364 }
294 break;
365 break;
295 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
366 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
296 setEnd(impl->m_MovedOrinalT2 + diff);
367 setEnd(impl->m_MovedOrinalT2 + diff);
297 for (auto associatedZone : impl->m_AssociatedEditedZones) {
368 for (auto associatedZone : impl->m_AssociatedEditedZones) {
298 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
369 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
299 ? associatedZone->resizeRight(pixelDiff)
370 ? associatedZone->resizeRight(pixelDiff)
300 : associatedZone->resizeLeft(pixelDiff);
371 : associatedZone->resizeLeft(pixelDiff);
301 }
372 }
302 break;
373 break;
303 default:
374 default:
304 break;
375 break;
305 }
376 }
306
377
307 for (auto associatedZone : impl->m_AssociatedEditedZones) {
378 for (auto associatedZone : impl->m_AssociatedEditedZones) {
308 associatedZone->parentPlot()->replot();
379 associatedZone->parentPlot()->replot();
309 }
380 }
310 }
381 }
311 else {
382 else {
312 event->ignore();
383 event->ignore();
313 }
384 }
314 }
385 }
315
386
316 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
387 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
317 {
388 {
318 if (isEditionEnabled()) {
389 if (isEditionEnabled()) {
319 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
390 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
320 }
391 }
321 else {
392 else {
322 event->ignore();
393 event->ignore();
323 }
394 }
324
395
325 impl->m_AssociatedEditedZones.clear();
396 impl->m_AssociatedEditedZones.clear();
326 }
397 }
327
398
328 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
399 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
329 {
400 {
330 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
401 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
331 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
402 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
332 setStart(impl->m_MovedOrinalT1 + diff);
403 setStart(impl->m_MovedOrinalT1 + diff);
333 }
404 }
334 else {
405 else {
335 setEnd(impl->m_MovedOrinalT2 + diff);
406 setEnd(impl->m_MovedOrinalT2 + diff);
336 }
407 }
337 }
408 }
338
409
339 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
410 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
340 {
411 {
341 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
412 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
342 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
413 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
343 setStart(impl->m_MovedOrinalT1 + diff);
414 setStart(impl->m_MovedOrinalT1 + diff);
344 }
415 }
345 else {
416 else {
346 setEnd(impl->m_MovedOrinalT2 + diff);
417 setEnd(impl->m_MovedOrinalT2 + diff);
347 }
418 }
348 }
419 }
349
420
350 void VisualizationSelectionZoneItem::move(double pixelDiff)
421 void VisualizationSelectionZoneItem::move(double pixelDiff)
351 {
422 {
352 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
423 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
353 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
424 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
354 }
425 }
General Comments 4
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

Approved

Status change > Approved

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