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