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