@@ -20,7 +20,7 public: | |||
|
20 | 20 | explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget); |
|
21 | 21 | |
|
22 | 22 | void onMouseDoubleClick(QMouseEvent *event) noexcept; |
|
23 |
void |
|
|
23 | void updateTooltip(QMouseEvent *event) noexcept; | |
|
24 | 24 | /// Updates rendering when data of plot changed |
|
25 | 25 | void onPlotUpdated() noexcept; |
|
26 | 26 |
@@ -130,6 +130,7 protected: | |||
|
130 | 130 | void mouseMoveEvent(QMouseEvent *event) override; |
|
131 | 131 | void mouseReleaseEvent(QMouseEvent *event) override; |
|
132 | 132 | void mousePressEvent(QMouseEvent *event) override; |
|
133 | void mouseDoubleClickEvent(QMouseEvent *event) override; | |
|
133 | 134 | void keyReleaseEvent(QKeyEvent * event) override; |
|
134 | 135 | void keyPressEvent(QKeyEvent * event) override; |
|
135 | 136 | |
@@ -146,7 +147,7 private slots: | |||
|
146 | 147 | void onGraphMenuRequested(const QPoint &pos) noexcept; |
|
147 | 148 | |
|
148 | 149 | /// Rescale the X axe to range parameter |
|
149 | void onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange); | |
|
150 | // void onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange); | |
|
150 | 151 | |
|
151 | 152 | /// Slot called when a mouse double click was made |
|
152 | 153 | void onMouseDoubleClick(QMouseEvent *event) noexcept; |
@@ -233,7 +233,7 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) | |||
|
233 | 233 | } |
|
234 | 234 | } |
|
235 | 235 | |
|
236 |
void VisualizationGraphRenderingDelegate:: |
|
|
236 | void VisualizationGraphRenderingDelegate::updateTooltip(QMouseEvent *event) noexcept | |
|
237 | 237 | { |
|
238 | 238 | // Cancels pending refresh |
|
239 | 239 | impl->m_TracerTimer.disconnect(); |
@@ -210,6 +210,46 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { | |||
|
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 | ||
|
214 | inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis *axis) | |
|
215 | { | |
|
216 | if (axis->scaleType() == QCPAxis::stLinear) | |
|
217 | { | |
|
218 | auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2); | |
|
219 | return QCPRange{axis->range().lower + diff, axis->range().upper + diff}; | |
|
220 | } | |
|
221 | else | |
|
222 | { | |
|
223 | auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2); | |
|
224 | return QCPRange{axis->range().lower * diff, axis->range().upper * diff}; | |
|
225 | } | |
|
226 | } | |
|
227 | ||
|
228 | void setRange(const QCPRange &newRange) | |
|
229 | { | |
|
230 | auto graphRange = DateTimeRange{newRange.lower, newRange.upper}; | |
|
231 | ||
|
232 | if (m_Flags.testFlag(GraphFlag::EnableAcquisition)) | |
|
233 | { | |
|
234 | for (auto it = m_VariableToPlotMultiMap.begin(), | |
|
235 | end = m_VariableToPlotMultiMap.end(); | |
|
236 | it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first)) | |
|
237 | { | |
|
238 | sqpApp->variableController().asyncChangeRange(it->first, graphRange); | |
|
239 | } | |
|
240 | } | |
|
241 | } | |
|
242 | ||
|
243 | void moveGraph(const QPoint& origin, const QPoint& destination, QCustomPlot* plot) | |
|
244 | { | |
|
245 | auto currentPos = destination; | |
|
246 | auto xAxis = plot->axisRect()->rangeDragAxis(Qt::Horizontal); | |
|
247 | auto yAxis = plot->axisRect()->rangeDragAxis(Qt::Vertical); | |
|
248 | xAxis->setRange(_pixDistanceToRange(origin.x(), currentPos.x(), xAxis)); | |
|
249 | yAxis->setRange(_pixDistanceToRange(origin.y(), currentPos.y(), yAxis)); | |
|
250 | setRange(xAxis->range()); | |
|
251 | plot->replot(QCustomPlot::rpQueuedReplot); | |
|
252 | } | |
|
213 | 253 | }; |
|
214 | 254 | |
|
215 | 255 | VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) |
@@ -233,6 +273,7 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget | |||
|
233 | 273 | |
|
234 | 274 | // β swhitch to this ASAP, VisualizationGraphWidget should intercept all UI events |
|
235 | 275 | this->setFocusPolicy(Qt::WheelFocus); |
|
276 | this->setMouseTracking(true); | |
|
236 | 277 | ui->widget->setAttribute(Qt::WA_TransparentForMouseEvents); |
|
237 | 278 | // connect(ui->widget, &QCustomPlot::mousePress, this, |
|
238 | 279 | // &VisualizationGraphWidget::onMousePress); connect(ui->widget, &QCustomPlot::mouseRelease, |
@@ -455,11 +496,10 void VisualizationGraphWidget::undoZoom() | |||
|
455 | 496 | void VisualizationGraphWidget::zoom(double factor, int center, Qt::Orientation orientation) |
|
456 | 497 | |
|
457 | 498 | { |
|
458 | auto oldRange = ui->widget->xAxis->range(); | |
|
459 | 499 | QCPAxis *axis = ui->widget->axisRect()->rangeZoomAxis(orientation); |
|
460 | 500 | axis->scaleRange(factor, axis->pixelToCoord(center)); |
|
461 | 501 | if (orientation == Qt::Horizontal) |
|
462 |
|
|
|
502 | impl->setRange(axis->range()); | |
|
463 | 503 | ui->widget->replot(QCustomPlot::rpQueuedReplot); |
|
464 | 504 | } |
|
465 | 505 | |
@@ -488,7 +528,7 void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation) | |||
|
488 | 528 | ui->widget->axisRect()->rangeDragAxis(orientation)->range().upper * diff); |
|
489 | 529 | } |
|
490 | 530 | if (orientation == Qt::Horizontal) |
|
491 |
|
|
|
531 | impl->setRange(axis->range()); | |
|
492 | 532 | ui->widget->replot(QCustomPlot::rpQueuedReplot); |
|
493 | 533 | } |
|
494 | 534 | |
@@ -709,33 +749,29 void VisualizationGraphWidget::wheelEvent(QWheelEvent *event) | |||
|
709 | 749 | QWidget::wheelEvent(event); |
|
710 | 750 | } |
|
711 | 751 | |
|
712 | inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis *axis) | |
|
752 | ||
|
753 | ||
|
754 | void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent *event) | |
|
713 | 755 | { |
|
714 | if (axis->scaleType() == QCPAxis::stLinear) | |
|
756 | if (event->buttons() == Qt::LeftButton) | |
|
715 | 757 | { |
|
716 | auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2); | |
|
717 | return QCPRange{axis->range().lower + diff, axis->range().upper + diff}; | |
|
758 | impl->moveGraph(_dragLastPos, event->pos(), ui->widget); | |
|
759 | _dragLastPos = event->pos(); | |
|
718 | 760 | } |
|
719 | else | |
|
761 | else if(impl->m_DrawingZoomRect) | |
|
720 | 762 | { |
|
721 | auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2); | |
|
722 | return QCPRange{axis->range().lower * diff, axis->range().upper * diff}; | |
|
763 | QPointF pos{ui->widget->xAxis->pixelToCoord(event->pos().x()), ui->widget->yAxis->pixelToCoord(event->pos().y())}; | |
|
764 | impl->m_DrawingZoomRect->bottomRight->setCoords(pos); | |
|
723 | 765 | } |
|
724 | } | |
|
725 | ||
|
726 | void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent *event) | |
|
727 | { | |
|
728 | if (event->buttons() & Qt::LeftButton) { | |
|
729 | auto currentPos = event->pos(); | |
|
730 | auto xAxis = ui->widget->axisRect()->rangeDragAxis(Qt::Horizontal); | |
|
731 | auto yAxis = ui->widget->axisRect()->rangeDragAxis(Qt::Vertical); | |
|
732 | auto oldXRange = xAxis->range(); | |
|
733 | xAxis->setRange(_pixDistanceToRange(_dragLastPos.x(), currentPos.x(), xAxis)); | |
|
734 | yAxis->setRange(_pixDistanceToRange(_dragLastPos.y(), currentPos.y(), yAxis)); | |
|
735 | onRangeChanged(oldXRange, xAxis->range()); | |
|
736 | ui->widget->replot(QCustomPlot::rpQueuedReplot); | |
|
737 | _dragLastPos = currentPos; | |
|
766 | else if (impl->m_DrawingZone) | |
|
767 | { | |
|
768 | impl->m_DrawingZone->setEnd(ui->widget->xAxis->pixelToCoord(event->pos().x())); | |
|
738 | 769 | } |
|
770 | else | |
|
771 | { | |
|
772 | impl->m_RenderingDelegate->updateTooltip(event); | |
|
773 | } | |
|
774 | event->accept(); | |
|
739 | 775 | QWidget::mouseMoveEvent(event); |
|
740 | 776 | } |
|
741 | 777 | |
@@ -752,12 +788,21 void VisualizationGraphWidget::mousePressEvent(QMouseEvent *event) | |||
|
752 | 788 | } |
|
753 | 789 | else { |
|
754 | 790 | setCursor(Qt::ClosedHandCursor); |
|
755 | this->_dragLastPos= event->pos(); | |
|
791 | this->_dragLastPos = event->pos(); | |
|
756 | 792 | } |
|
757 | 793 | } |
|
794 | else if (event->button()==Qt::RightButton) | |
|
795 | { | |
|
796 | onGraphMenuRequested(event->pos()); | |
|
797 | } | |
|
758 | 798 | QWidget::mousePressEvent(event); |
|
759 | 799 | } |
|
760 | 800 | |
|
801 | void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent *event) | |
|
802 | { | |
|
803 | impl->m_RenderingDelegate->onMouseDoubleClick(event); | |
|
804 | } | |
|
805 | ||
|
761 | 806 | void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent *event) |
|
762 | 807 | { |
|
763 | 808 | switch (event->key()) { |
@@ -921,38 +966,38 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept | |||
|
921 | 966 | } |
|
922 | 967 | } |
|
923 | 968 | |
|
924 | void VisualizationGraphWidget::onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange) | |
|
925 | { | |
|
926 | auto graphRange = DateTimeRange{newRange.lower, newRange.upper}; | |
|
927 | auto oldGraphRange = DateTimeRange{oldRange.lower, oldRange.upper}; | |
|
928 | ||
|
929 | if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) { | |
|
930 | for (auto it = impl->m_VariableToPlotMultiMap.begin(), | |
|
931 | end = impl->m_VariableToPlotMultiMap.end(); | |
|
932 | it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) { | |
|
933 | sqpApp->variableController().asyncChangeRange(it->first, graphRange); | |
|
934 | } | |
|
935 | } | |
|
936 | ||
|
937 | // if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) | |
|
938 | // { | |
|
939 | // emit synchronize(graphRange, oldGraphRange); | |
|
940 | // } | |
|
941 | ||
|
942 | // auto pos = mapFromGlobal(QCursor::pos()); | |
|
943 | // auto axisPos = impl->posToAxisPos(pos, plot()); | |
|
944 | // if (auto parentZone = parentZoneWidget()) { | |
|
945 | // if (impl->pointIsInAxisRect(axisPos, plot())) { | |
|
946 | // parentZone->notifyMouseMoveInGraph(pos, axisPos, this); | |
|
947 | // } | |
|
948 | // else { | |
|
949 | // parentZone->notifyMouseLeaveGraph(this); | |
|
950 | // } | |
|
951 | // } | |
|
952 | ||
|
953 | // Quits calibration | |
|
954 | // impl->m_IsCalibration = false; | |
|
955 | } | |
|
969 | //void VisualizationGraphWidget::onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange) | |
|
970 | //{ | |
|
971 | // auto graphRange = DateTimeRange{newRange.lower, newRange.upper}; | |
|
972 | // auto oldGraphRange = DateTimeRange{oldRange.lower, oldRange.upper}; | |
|
973 | ||
|
974 | // if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) { | |
|
975 | // for (auto it = impl->m_VariableToPlotMultiMap.begin(), | |
|
976 | // end = impl->m_VariableToPlotMultiMap.end(); | |
|
977 | // it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) { | |
|
978 | // sqpApp->variableController().asyncChangeRange(it->first, graphRange); | |
|
979 | // } | |
|
980 | // } | |
|
981 | ||
|
982 | // // if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) | |
|
983 | // // { | |
|
984 | // // emit synchronize(graphRange, oldGraphRange); | |
|
985 | // // } | |
|
986 | ||
|
987 | // // auto pos = mapFromGlobal(QCursor::pos()); | |
|
988 | // // auto axisPos = impl->posToAxisPos(pos, plot()); | |
|
989 | // // if (auto parentZone = parentZoneWidget()) { | |
|
990 | // // if (impl->pointIsInAxisRect(axisPos, plot())) { | |
|
991 | // // parentZone->notifyMouseMoveInGraph(pos, axisPos, this); | |
|
992 | // // } | |
|
993 | // // else { | |
|
994 | // // parentZone->notifyMouseLeaveGraph(this); | |
|
995 | // // } | |
|
996 | // // } | |
|
997 | ||
|
998 | // // Quits calibration | |
|
999 | // // impl->m_IsCalibration = false; | |
|
1000 | //} | |
|
956 | 1001 | |
|
957 | 1002 | void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept |
|
958 | 1003 | { |
@@ -962,7 +1007,7 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept | |||
|
962 | 1007 | void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept |
|
963 | 1008 | { |
|
964 | 1009 | // Handles plot rendering when mouse is moving |
|
965 |
impl->m_RenderingDelegate-> |
|
|
1010 | impl->m_RenderingDelegate->updateTooltip(event); | |
|
966 | 1011 | |
|
967 | 1012 | auto axisPos = impl->posToAxisPos(event->pos(), plot()); |
|
968 | 1013 | |
@@ -1074,11 +1119,6 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept | |||
|
1074 | 1119 | } |
|
1075 | 1120 | } |
|
1076 | 1121 | |
|
1077 | // Allows mouse panning only in default mode | |
|
1078 | // plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode() | |
|
1079 | // == | |
|
1080 | // SqpApplication::PlotsInteractionMode::None | |
|
1081 | // && !isDragDropClick); | |
|
1082 | 1122 | |
|
1083 | 1123 | // Allows zone edition only in selection zone mode without drag&drop |
|
1084 | 1124 | impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick); |
@@ -19,18 +19,19 | |||
|
19 | 19 | ALIAS_TEMPLATE_FUNCTION(isReady, static_cast<SqpApplication *>(qApp)->variableController().isReady) |
|
20 | 20 | |
|
21 | 21 | #define A_SIMPLE_GRAPH_FIXTURE \ |
|
22 |
|
|
|
23 |
|
|
|
24 |
|
|
|
25 |
|
|
|
26 | QTime(16, 00));\ | |
|
27 |
|
|
|
28 |
|
|
|
29 |
|
|
|
30 |
|
|
|
31 |
|
|
|
32 |
|
|
|
33 |
|
|
|
22 | VisualizationGraphWidget w;\ | |
|
23 | PREPARE_GUI_TEST(w);\ | |
|
24 | auto provider = std::make_shared<SimpleRange<10> >();\ | |
|
25 | auto range = DateTimeRange::fromDateTime(QDate(2018, 8, 7), QTime(14, 00), QDate(2018, 8, 7),\ | |
|
26 | QTime(16, 00));\ | |
|
27 | auto var = static_cast<SqpApplication *>(qApp)->variableController().createVariable(\ | |
|
28 | "V1", {{"", "scalar"}}, provider, range);\ | |
|
29 | while (!isReady(var))\ | |
|
30 | QCoreApplication::processEvents();\ | |
|
31 | w.addVariable(var, range);\ | |
|
32 | GET_CHILD_WIDGET_FOR_GUI_TESTS(w, plot, QCustomPlot, "widget");\ | |
|
33 | auto cent = center(&w); | |
|
34 | ||
|
34 | 35 | |
|
35 | 36 | |
|
36 | 37 | class A_SimpleGraph : public QObject { |
@@ -39,19 +40,19 public: | |||
|
39 | 40 | explicit A_SimpleGraph(QObject *parent = Q_NULLPTR) : QObject(parent) {} |
|
40 | 41 | |
|
41 | 42 | private slots: |
|
42 | void scrolls_with_mouse() | |
|
43 | void scrolls_left_with_mouse() | |
|
43 | 44 | { |
|
44 | A_SIMPLE_GRAPH_FIXTURE | |
|
45 | A_SIMPLE_GRAPH_FIXTURE; | |
|
45 | 46 | |
|
46 | for (auto i = 0; i < 10; i++) { | |
|
47 |
QTest::mousePress(&w, Qt::LeftButton, Qt::NoModifier, cent, |
|
|
47 | for (auto i = 0; i < 100; i++) { | |
|
48 | QTest::mousePress(&w, Qt::LeftButton, Qt::NoModifier, cent, 1); | |
|
48 | 49 | mouseMove(&w, {cent.x() + 200, cent.y()}, Qt::LeftButton); |
|
49 | 50 | QTest::mouseRelease(&w, Qt::LeftButton); |
|
50 | 51 | while (!isReady(var)) |
|
51 | 52 | QCoreApplication::processEvents(); |
|
52 | 53 | } |
|
53 | 54 | while (!isReady(var)) |
|
54 |
|
|
|
55 | QCoreApplication::processEvents(); | |
|
55 | 56 | auto r = var->range(); |
|
56 | 57 | /* |
|
57 | 58 | * Scrolling to the left implies going back in time |
@@ -60,6 +61,28 private slots: | |||
|
60 | 61 | QVERIFY(r.m_TEnd < range.m_TEnd); |
|
61 | 62 | QVERIFY(SciQLop::numeric::almost_equal<double>(r.delta(),range.delta(),1)); |
|
62 | 63 | } |
|
64 | ||
|
65 | void scrolls_right_with_mouse() | |
|
66 | { | |
|
67 | A_SIMPLE_GRAPH_FIXTURE; | |
|
68 | ||
|
69 | for (auto i = 0; i < 100; i++) { | |
|
70 | QTest::mousePress(&w, Qt::LeftButton, Qt::NoModifier, cent, 1); | |
|
71 | mouseMove(&w, {cent.x() - 200, cent.y()}, Qt::LeftButton); | |
|
72 | QTest::mouseRelease(&w, Qt::LeftButton); | |
|
73 | while (!isReady(var)) | |
|
74 | QCoreApplication::processEvents(); | |
|
75 | } | |
|
76 | while (!isReady(var)) | |
|
77 | QCoreApplication::processEvents(); | |
|
78 | auto r = var->range(); | |
|
79 | /* | |
|
80 | * Scrolling to the right implies going forward in time | |
|
81 | * Scroll only implies keeping the same delta T -> shit only transformation | |
|
82 | */ | |
|
83 | QVERIFY(r.m_TEnd > range.m_TEnd); | |
|
84 | QVERIFY(SciQLop::numeric::almost_equal<double>(r.delta(),range.delta(),1)); | |
|
85 | } | |
|
63 | 86 | }; |
|
64 | 87 | |
|
65 | 88 | QT_BEGIN_NAMESPACE |
@@ -69,10 +92,10 int main(int argc, char *argv[]) | |||
|
69 | 92 | { |
|
70 | 93 | SqpApplication app{argc, argv}; |
|
71 | 94 | app.setAttribute(Qt::AA_Use96Dpi, true); |
|
72 | QTEST_DISABLE_KEYPAD_NAVIGATION | |
|
73 | QTEST_ADD_GPU_BLACKLIST_SUPPORT | |
|
95 | QTEST_DISABLE_KEYPAD_NAVIGATION; | |
|
96 | QTEST_ADD_GPU_BLACKLIST_SUPPORT; | |
|
74 | 97 | A_SimpleGraph tc; |
|
75 | QTEST_SET_MAIN_SOURCE_PATH | |
|
98 | QTEST_SET_MAIN_SOURCE_PATH; | |
|
76 | 99 | return QTest::qExec(&tc, argc, argv); |
|
77 | 100 | } |
|
78 | 101 |
General Comments 0
You need to be logged in to leave comments.
Login now