##// END OF EJS Templates
Add a lambda in SeletionZoneAction to enable or disable the action
trabillard -
r1115:c55ac7376de6
parent child
Show More
@@ -1,49 +1,58
1 #ifndef SCIQLOP_SELECTIONZONEACTION_H
1 #ifndef SCIQLOP_SELECTIONZONEACTION_H
2 #define SCIQLOP_SELECTIONZONEACTION_H
2 #define SCIQLOP_SELECTIONZONEACTION_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QObject>
7 #include <QObject>
8
8
9 #include <functional>
9 #include <functional>
10
10
11 class VisualizationSelectionZoneItem;
11 class VisualizationSelectionZoneItem;
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_SelectionZoneAction)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_SelectionZoneAction)
14
14
15 /**
15 /**
16 * @brief The SelectionZoneAction class represents an action on a selection zone in the
16 * @brief The SelectionZoneAction class represents an action on a selection zone in the
17 * visualization.
17 * visualization.
18 *
18 *
19 * The action is a function that will be executed when the slot execute() is called.
19 * The action is a function that will be executed when the slot execute() is called.
20 */
20 */
21 class SelectionZoneAction : public QObject {
21 class SelectionZoneAction : public QObject {
22
22
23 Q_OBJECT
23 Q_OBJECT
24
24
25 public:
25 public:
26 /// Signature of the function associated to the action
26 /// Signature of the function associated to the action
27 using ExecuteFunction
27 using ExecuteFunction
28 = std::function<void(const QVector<VisualizationSelectionZoneItem *> &item)>;
28 = std::function<void(const QVector<VisualizationSelectionZoneItem *> &item)>;
29
29
30 using EnableFunction
31 = std::function<bool(const QVector<VisualizationSelectionZoneItem *> &item)>;
32
30 /**
33 /**
31 * @param name the name of the action, displayed to the user
34 * @param name the name of the action, displayed to the user
32 * @param fun the function that will be called when the action is executed
35 * @param fun the function that will be called when the action is executed
33 * @sa execute()
36 * @sa execute()
34 */
37 */
35 explicit SelectionZoneAction(const QString &name, ExecuteFunction fun);
38 explicit SelectionZoneAction(const QString &name, ExecuteFunction fun);
36
39
40 /// Sets the function which determine if the action should be enabled or disabled
41 void setEnableFunction(EnableFunction fun);
42
37 /// The name of the action
43 /// The name of the action
38 QString name() const noexcept;
44 QString name() const noexcept;
39
45
40 public slots:
46 public slots:
41 /// Executes the action
47 /// Executes the action
42 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
48 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
43
49
50 /// Returns true if the action is enabled
51 bool isEnabled(const QVector<VisualizationSelectionZoneItem *> &item);
52
44 private:
53 private:
45 class SelectionZoneActionPrivate;
54 class SelectionZoneActionPrivate;
46 spimpl::unique_impl_ptr<SelectionZoneActionPrivate> impl;
55 spimpl::unique_impl_ptr<SelectionZoneActionPrivate> impl;
47 };
56 };
48
57
49 #endif // SCIQLOP_SELECTIONZONEACTION_H
58 #endif // SCIQLOP_SELECTIONZONEACTION_H
@@ -1,30 +1,41
1 #include <Actions/SelectionZoneAction.h>
1 #include <Actions/SelectionZoneAction.h>
2 #include <Visualization/VisualizationSelectionZoneItem.h>
2 #include <Visualization/VisualizationSelectionZoneItem.h>
3
3
4 Q_LOGGING_CATEGORY(LOG_SelectionZoneAction, "SelectionZoneAction")
4 Q_LOGGING_CATEGORY(LOG_SelectionZoneAction, "SelectionZoneAction")
5
5
6 struct SelectionZoneAction::SelectionZoneActionPrivate {
6 struct SelectionZoneAction::SelectionZoneActionPrivate {
7 explicit SelectionZoneActionPrivate(const QString &name,
7 explicit SelectionZoneActionPrivate(const QString &name,
8 SelectionZoneAction::ExecuteFunction fun)
8 SelectionZoneAction::ExecuteFunction fun)
9 : m_Name{name}, m_Fun{std::move(fun)}
9 : m_Name{name}, m_Fun{std::move(fun)}
10 {
10 {
11 }
11 }
12
12
13 QString m_Name;
13 QString m_Name;
14 SelectionZoneAction::ExecuteFunction m_Fun;
14 SelectionZoneAction::ExecuteFunction m_Fun;
15 SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; };
15 };
16 };
16
17
17 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
18 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
18 : impl{spimpl::make_unique_impl<SelectionZoneActionPrivate>(name, std::move(fun))}
19 : impl{spimpl::make_unique_impl<SelectionZoneActionPrivate>(name, std::move(fun))}
19 {
20 {
20 }
21 }
21
22
23 void SelectionZoneAction::setEnableFunction(EnableFunction fun)
24 {
25 impl->m_EnableFun = std::move(fun);
26 }
27
22 QString SelectionZoneAction::name() const noexcept
28 QString SelectionZoneAction::name() const noexcept
23 {
29 {
24 return impl->m_Name;
30 return impl->m_Name;
25 }
31 }
26
32
27 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
33 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
28 {
34 {
29 impl->m_Fun(item);
35 impl->m_Fun(item);
30 }
36 }
37
38 bool SelectionZoneAction::isEnabled(const QVector<VisualizationSelectionZoneItem *> &item)
39 {
40 return impl->m_EnableFun(item);
41 }
@@ -1,22 +1,30
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 actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto &zones) {
14 actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto &zones) {
14 for (auto selectionZone : zones) {
15 for (auto selectionZone : zones) {
15 if (auto graph = selectionZone->parentGraphWidget()) {
16 if (auto graph = selectionZone->parentGraphWidget()) {
16 graph->removeSelectionZone(selectionZone);
17 graph->removeSelectionZone(selectionZone);
17 }
18 }
18 }
19 }
19 });
20 });
20 actionController.addSectionZoneAction("Align Left", [](auto &zones) {});
21
21 actionController.addSectionZoneAction("Align Right", [](auto &zones) {});
22 auto alignEnableFuntion = [](auto &items) { return items.count() > 0; };
23
24 auto alignLeftAction = actionController.addSectionZoneAction("Align Left Vertically", [](auto &zones) {});
25 alignLeftAction->setEnableFunction(alignEnableFuntion);
26
27 auto alignRightAction
28 = actionController.addSectionZoneAction("Align Right vertically", [](auto &zones) {});
29 alignRightAction->setEnableFunction(alignEnableFuntion);
22 }
30 }
@@ -1,901 +1,902
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 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
617 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
618 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
618 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
619 graphMenu.addSeparator();
619 graphMenu.addSeparator();
620 }
620 }
621
621
622 for (auto zoneAction : zoneActions) {
622 for (auto zoneAction : zoneActions) {
623 auto action = graphMenu.addAction(zoneAction->name());
623 auto action = graphMenu.addAction(zoneAction->name());
624 action->setEnabled(zoneAction->isEnabled(selectedItems));
624 QObject::connect(action, &QAction::triggered, [zoneAction, &selectedItems]() {
625 QObject::connect(action, &QAction::triggered, [zoneAction, &selectedItems]() {
625 zoneAction->execute(selectedItems);
626 zoneAction->execute(selectedItems);
626 });
627 });
627 }
628 }
628 }
629 }
629
630
630 if (!graphMenu.isEmpty()) {
631 if (!graphMenu.isEmpty()) {
631 graphMenu.exec(QCursor::pos());
632 graphMenu.exec(QCursor::pos());
632 }
633 }
633 }
634 }
634
635
635 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
636 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
636 {
637 {
637 qCDebug(LOG_VisualizationGraphWidget())
638 qCDebug(LOG_VisualizationGraphWidget())
638 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
639 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
639 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
640 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
640
641
641 auto graphRange = SqpRange{t1.lower, t1.upper};
642 auto graphRange = SqpRange{t1.lower, t1.upper};
642 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
643 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
643
644
644 if (impl->m_DoAcquisition) {
645 if (impl->m_DoAcquisition) {
645 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
646 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
646
647
647 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
648 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
648 end = impl->m_VariableToPlotMultiMap.end();
649 end = impl->m_VariableToPlotMultiMap.end();
649 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
650 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
650 variableUnderGraphVector.push_back(it->first);
651 variableUnderGraphVector.push_back(it->first);
651 }
652 }
652 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
653 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
653 !impl->m_IsCalibration);
654 !impl->m_IsCalibration);
654
655
655 if (!impl->m_IsCalibration) {
656 if (!impl->m_IsCalibration) {
656 qCDebug(LOG_VisualizationGraphWidget())
657 qCDebug(LOG_VisualizationGraphWidget())
657 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
658 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
658 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
659 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
659 emit synchronize(graphRange, oldGraphRange);
660 emit synchronize(graphRange, oldGraphRange);
660 }
661 }
661 }
662 }
662
663
663 auto pos = mapFromGlobal(QCursor::pos());
664 auto pos = mapFromGlobal(QCursor::pos());
664 auto axisPos = impl->posToAxisPos(pos, plot());
665 auto axisPos = impl->posToAxisPos(pos, plot());
665 if (auto parentZone = parentZoneWidget()) {
666 if (auto parentZone = parentZoneWidget()) {
666 if (impl->pointIsInAxisRect(axisPos, plot())) {
667 if (impl->pointIsInAxisRect(axisPos, plot())) {
667 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
668 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
668 }
669 }
669 else {
670 else {
670 parentZone->notifyMouseLeaveGraph(this);
671 parentZone->notifyMouseLeaveGraph(this);
671 }
672 }
672 }
673 }
673 else {
674 else {
674 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
675 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
675 }
676 }
676 }
677 }
677
678
678 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
679 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
679 {
680 {
680 impl->m_RenderingDelegate->onMouseDoubleClick(event);
681 impl->m_RenderingDelegate->onMouseDoubleClick(event);
681 }
682 }
682
683
683 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
684 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
684 {
685 {
685 // Handles plot rendering when mouse is moving
686 // Handles plot rendering when mouse is moving
686 impl->m_RenderingDelegate->onMouseMove(event);
687 impl->m_RenderingDelegate->onMouseMove(event);
687
688
688 auto axisPos = impl->posToAxisPos(event->pos(), plot());
689 auto axisPos = impl->posToAxisPos(event->pos(), plot());
689
690
690 // Zoom box and zone drawing
691 // Zoom box and zone drawing
691 if (impl->m_DrawingZoomRect) {
692 if (impl->m_DrawingZoomRect) {
692 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
693 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
693 }
694 }
694 else if (impl->m_DrawingZone) {
695 else if (impl->m_DrawingZone) {
695 impl->m_DrawingZone->setEnd(axisPos.x());
696 impl->m_DrawingZone->setEnd(axisPos.x());
696 }
697 }
697
698
698 // Cursor
699 // Cursor
699 if (auto parentZone = parentZoneWidget()) {
700 if (auto parentZone = parentZoneWidget()) {
700 if (impl->pointIsInAxisRect(axisPos, plot())) {
701 if (impl->pointIsInAxisRect(axisPos, plot())) {
701 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
702 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
702 }
703 }
703 else {
704 else {
704 parentZone->notifyMouseLeaveGraph(this);
705 parentZone->notifyMouseLeaveGraph(this);
705 }
706 }
706 }
707 }
707 else {
708 else {
708 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
709 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
709 }
710 }
710
711
711 // Search for the selection zone under the mouse
712 // Search for the selection zone under the mouse
712 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
713 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
713 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
714 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
714 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
715 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
715
716
716 // Sets the appropriate cursor shape
717 // Sets the appropriate cursor shape
717 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
718 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
718 setCursor(cursorShape);
719 setCursor(cursorShape);
719
720
720 // Manages the hovered zone
721 // Manages the hovered zone
721 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
722 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
722 if (impl->m_HoveredZone) {
723 if (impl->m_HoveredZone) {
723 impl->m_HoveredZone->setHovered(false);
724 impl->m_HoveredZone->setHovered(false);
724 }
725 }
725 selectionZoneItemUnderCursor->setHovered(true);
726 selectionZoneItemUnderCursor->setHovered(true);
726 impl->m_HoveredZone = selectionZoneItemUnderCursor;
727 impl->m_HoveredZone = selectionZoneItemUnderCursor;
727 plot().replot(QCustomPlot::rpQueuedReplot);
728 plot().replot(QCustomPlot::rpQueuedReplot);
728 }
729 }
729 }
730 }
730 else {
731 else {
731 // There is no zone under the mouse or the interaction mode is not "selection zones"
732 // There is no zone under the mouse or the interaction mode is not "selection zones"
732 if (impl->m_HoveredZone) {
733 if (impl->m_HoveredZone) {
733 impl->m_HoveredZone->setHovered(false);
734 impl->m_HoveredZone->setHovered(false);
734 impl->m_HoveredZone = nullptr;
735 impl->m_HoveredZone = nullptr;
735 }
736 }
736
737
737 setCursor(Qt::ArrowCursor);
738 setCursor(Qt::ArrowCursor);
738 }
739 }
739
740
740 impl->m_HasMovedMouse = true;
741 impl->m_HasMovedMouse = true;
741 VisualizationDragWidget::mouseMoveEvent(event);
742 VisualizationDragWidget::mouseMoveEvent(event);
742 }
743 }
743
744
744 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
745 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
745 {
746 {
746 auto value = event->angleDelta().x() + event->angleDelta().y();
747 auto value = event->angleDelta().x() + event->angleDelta().y();
747 if (value != 0) {
748 if (value != 0) {
748
749
749 auto direction = value > 0 ? 1.0 : -1.0;
750 auto direction = value > 0 ? 1.0 : -1.0;
750 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
751 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
751 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
752 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
752 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
753 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
753
754
754 auto zoomOrientations = QFlags<Qt::Orientation>{};
755 auto zoomOrientations = QFlags<Qt::Orientation>{};
755 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
756 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
756 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
757 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
757
758
758 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
759 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
759
760
760 if (!isZoomX && !isZoomY) {
761 if (!isZoomX && !isZoomY) {
761 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
762 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
762 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
763 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
763
764
764 axis->setRange(axis->range() + diff);
765 axis->setRange(axis->range() + diff);
765
766
766 if (plot().noAntialiasingOnDrag()) {
767 if (plot().noAntialiasingOnDrag()) {
767 plot().setNotAntialiasedElements(QCP::aeAll);
768 plot().setNotAntialiasedElements(QCP::aeAll);
768 }
769 }
769
770
770 plot().replot(QCustomPlot::rpQueuedReplot);
771 plot().replot(QCustomPlot::rpQueuedReplot);
771 }
772 }
772 }
773 }
773 }
774 }
774
775
775 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
776 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
776 {
777 {
777 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
778 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
778 auto isSelectionZoneMode
779 auto isSelectionZoneMode
779 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
780 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
780 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
781 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
781
782
782 if (!isDragDropClick && isLeftClick) {
783 if (!isDragDropClick && isLeftClick) {
783 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
784 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
784 // Starts a zoom box
785 // Starts a zoom box
785 impl->startDrawingRect(event->pos(), plot());
786 impl->startDrawingRect(event->pos(), plot());
786 }
787 }
787 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
788 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
788 // Starts a new selection zone
789 // Starts a new selection zone
789 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
790 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
790 if (!zoneAtPos) {
791 if (!zoneAtPos) {
791 impl->startDrawingZone(event->pos(), this);
792 impl->startDrawingZone(event->pos(), this);
792 }
793 }
793 }
794 }
794 }
795 }
795
796
796 // Allows mouse panning only in default mode
797 // Allows mouse panning only in default mode
797 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
798 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
798 == SqpApplication::PlotsInteractionMode::None
799 == SqpApplication::PlotsInteractionMode::None
799 && !isDragDropClick);
800 && !isDragDropClick);
800
801
801 // Allows zone edition only in selection zone mode without drag&drop
802 // Allows zone edition only in selection zone mode without drag&drop
802 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
803 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
803
804
804 // Selection / Deselection
805 // Selection / Deselection
805 if (isSelectionZoneMode) {
806 if (isSelectionZoneMode) {
806 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
807 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
807 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
808 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
808 if (selectionZoneItemUnderCursor && isLeftClick) {
809 if (selectionZoneItemUnderCursor && isLeftClick) {
809 selectionZoneItemUnderCursor->setAssociatedEditedZones(
810 selectionZoneItemUnderCursor->setAssociatedEditedZones(
810 parentVisualizationWidget()->selectionZoneManager().selectedItems());
811 parentVisualizationWidget()->selectionZoneManager().selectedItems());
811 }
812 }
812 else if (!isMultiSelectionClick && isLeftClick) {
813 else if (!isMultiSelectionClick && isLeftClick) {
813 parentVisualizationWidget()->selectionZoneManager().clearSelection();
814 parentVisualizationWidget()->selectionZoneManager().clearSelection();
814 }
815 }
815 else {
816 else {
816 // No selection change
817 // No selection change
817 }
818 }
818 }
819 }
819
820
820
821
821 impl->m_HasMovedMouse = false;
822 impl->m_HasMovedMouse = false;
822 VisualizationDragWidget::mousePressEvent(event);
823 VisualizationDragWidget::mousePressEvent(event);
823 }
824 }
824
825
825 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
826 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
826 {
827 {
827 if (impl->m_DrawingZoomRect) {
828 if (impl->m_DrawingZoomRect) {
828
829
829 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
830 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
830 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
831 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
831
832
832 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
833 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
833 impl->m_DrawingZoomRect->bottomRight->coords().x()};
834 impl->m_DrawingZoomRect->bottomRight->coords().x()};
834
835
835 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
836 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
836 impl->m_DrawingZoomRect->bottomRight->coords().y()};
837 impl->m_DrawingZoomRect->bottomRight->coords().y()};
837
838
838 impl->removeDrawingRect(plot());
839 impl->removeDrawingRect(plot());
839
840
840 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
841 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
841 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
842 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
842 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
843 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
843 axisX->setRange(newAxisXRange);
844 axisX->setRange(newAxisXRange);
844 axisY->setRange(newAxisYRange);
845 axisY->setRange(newAxisYRange);
845
846
846 plot().replot(QCustomPlot::rpQueuedReplot);
847 plot().replot(QCustomPlot::rpQueuedReplot);
847 }
848 }
848 }
849 }
849
850
850 impl->endDrawingZone(this);
851 impl->endDrawingZone(this);
851
852
852 impl->m_IsCalibration = false;
853 impl->m_IsCalibration = false;
853
854
854 // Selection / Deselection
855 // Selection / Deselection
855 auto isSelectionZoneMode
856 auto isSelectionZoneMode
856 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
857 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
857 if (isSelectionZoneMode) {
858 if (isSelectionZoneMode) {
858 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
859 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
859 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
860 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
860 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
861 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
861 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
862 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
862 parentVisualizationWidget()->selectionZoneManager().select(
863 parentVisualizationWidget()->selectionZoneManager().select(
863 {selectionZoneItemUnderCursor});
864 {selectionZoneItemUnderCursor});
864 }
865 }
865 else if (!impl->m_HasMovedMouse) {
866 else if (!impl->m_HasMovedMouse) {
866 parentVisualizationWidget()->selectionZoneManager().setSelected(
867 parentVisualizationWidget()->selectionZoneManager().setSelected(
867 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
868 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
868 || event->button() == Qt::RightButton);
869 || event->button() == Qt::RightButton);
869 }
870 }
870 }
871 }
871 else {
872 else {
872 // No selection change
873 // No selection change
873 }
874 }
874 }
875 }
875 }
876 }
876
877
877 void VisualizationGraphWidget::onDataCacheVariableUpdated()
878 void VisualizationGraphWidget::onDataCacheVariableUpdated()
878 {
879 {
879 auto graphRange = ui->widget->xAxis->range();
880 auto graphRange = ui->widget->xAxis->range();
880 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
881 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
881
882
882 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
883 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
883 auto variable = variableEntry.first;
884 auto variable = variableEntry.first;
884 qCDebug(LOG_VisualizationGraphWidget())
885 qCDebug(LOG_VisualizationGraphWidget())
885 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
886 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
886 qCDebug(LOG_VisualizationGraphWidget())
887 qCDebug(LOG_VisualizationGraphWidget())
887 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
888 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
888 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
889 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
889 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
890 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
890 }
891 }
891 }
892 }
892 }
893 }
893
894
894 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
895 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
895 const SqpRange &range)
896 const SqpRange &range)
896 {
897 {
897 auto it = impl->m_VariableToPlotMultiMap.find(variable);
898 auto it = impl->m_VariableToPlotMultiMap.find(variable);
898 if (it != impl->m_VariableToPlotMultiMap.end()) {
899 if (it != impl->m_VariableToPlotMultiMap.end()) {
899 impl->updateData(it->second, variable->dataSeries(), range);
900 impl->updateData(it->second, variable->dataSeries(), range);
900 }
901 }
901 }
902 }
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