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