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