From c09382036f7c021568b9fe8e58b993e0bd067154 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Wed, 6 Oct 2021 21:01:58 +0200 Subject: [PATCH] profile: don't use scene for zooming We were using the QGraphicsScene machinery to zoom into the plot. This not only zoomed into the dive, but into the whole thing. In general, one couldn't see the axes anymore. Instead, adjust the range of the time-axis according to the zoom-level and position. Of course, the code isn't adapted to that and the result is comical. The chart features will have to be fixed one-by-one. Oh joy. Signed-off-by: Berthold Stoeger --- profile-widget/profilescene.cpp | 10 ++-- profile-widget/profilescene.h | 2 +- profile-widget/profilewidget2.cpp | 84 ++++++++++--------------------- profile-widget/profilewidget2.h | 4 +- 4 files changed, 36 insertions(+), 64 deletions(-) diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index ea7951234..36ff7cb1c 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -299,7 +299,8 @@ bool ProfileScene::isPointOutOfBoundaries(const QPointF &point) const ypos < profileYAxis->minimum(); } -void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsModel *plannerModel, bool inPlanner, bool instant, bool calcMax) +void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsModel *plannerModel, + bool inPlanner, bool instant, bool calcMax, double zoom, double zoomedPosition) { d = dIn; dc = dcIn; @@ -388,8 +389,11 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM percentageAxis->setVisible(false); percentageAxis->updateTicks(animSpeed); - if (calcMax) - timeAxis->setBounds(0.0, maxtime); + if (calcMax) { + double relStart = (1.0 - 1.0/zoom) * zoomedPosition; + double relEnd = relStart + 1.0/zoom; + timeAxis->setBounds(round(relStart * maxtime), round(relEnd * maxtime)); + } timeAxis->updateTicks(animSpeed); cylinderPressureAxis->setBounds(plotInfo.minpressure, plotInfo.maxpressure); diff --git a/profile-widget/profilescene.h b/profile-widget/profilescene.h index 534289b8e..76e4c00de 100644 --- a/profile-widget/profilescene.h +++ b/profile-widget/profilescene.h @@ -42,7 +42,7 @@ public: // If a plannerModel is passed, the deco-information is taken from there. void plotDive(const struct dive *d, int dc, DivePlannerPointsModel *plannerModel = nullptr, bool inPlanner = false, - bool instant = false, bool calcMax = true); + bool instant = false, bool calcMax = true, double zoom = 1.0, double zoomedPosition = 0.0); void draw(QPainter *painter, const QRect &pos, const struct dive *d, int dc, diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 25eb99784..345c7c366 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -180,11 +180,8 @@ void ProfileWidget2::setupSceneAndFlags() void ProfileWidget2::resetZoom() { - if (!zoomLevel) - return; - const double defScale = 1.0 / pow(zoomFactor, (double)zoomLevel); - scale(defScale, defScale); zoomLevel = 0; + zoomedPosition = 0.0; } // Currently just one dive, but the plan is to enable All of the selected dives. @@ -210,7 +207,8 @@ void ProfileWidget2::plotDive(const struct dive *dIn, int dcIn, bool doClearPict DivePlannerPointsModel *model = currentState == EDIT || currentState == PLAN ? plannerModel : nullptr; bool inPlanner = currentState == PLAN; - profileScene->plotDive(d, dc, model, inPlanner, instant, shouldCalculateMax); + double zoom = zoomLevel == 0 ? 1.0 : pow(zoomFactor, zoomLevel); + profileScene->plotDive(d, dc, model, inPlanner, instant, shouldCalculateMax, zoom, zoomedPosition); #ifndef SUBSURFACE_MOBILE // reset some item visibility on printMode changes @@ -307,19 +305,16 @@ void ProfileWidget2::mouseReleaseEvent(QMouseEvent *event) } #endif -void ProfileWidget2::scale(qreal sx, qreal sy) +void ProfileWidget2::setZoom(int level) { - QGraphicsView::scale(sx, sy); - -#ifndef SUBSURFACE_MOBILE - // Since the zoom level changed, adjust the duration bars accordingly. - // We want to grow/shrink the length, but not the height and pen. - for (PictureEntry &p: pictures) - updateDurationLine(p); - - // Since we created new duration lines, we have to update the order in which the thumbnails are painted. - updateThumbnailPaintOrder(); -#endif + zoomLevel = level; + if (zoomLevel == 0) { + zoomedPosition = 0.0; + } else { + double pos = mapToScene(mapFromGlobal(QCursor::pos())).x(); + zoomedPosition = pos / profileScene->width(); + } + replot(); } #ifndef SUBSURFACE_MOBILE @@ -327,23 +322,12 @@ void ProfileWidget2::wheelEvent(QWheelEvent *event) { if (!d) return; - QPoint toolTipPos = mapFromScene(toolTipItem->pos()); if (event->buttons() == Qt::LeftButton) return; - if (event->angleDelta().y() > 0 && zoomLevel < 20) { - scale(zoomFactor, zoomFactor); - zoomLevel++; - } else if (event->angleDelta().y() < 0 && zoomLevel > 0) { - // Zooming out - scale(1.0 / zoomFactor, 1.0 / zoomFactor); - zoomLevel--; - } -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) - scrollViewTo(event->position().toPoint()); -#else - scrollViewTo(event->pos()); -#endif - toolTipItem->setPos(mapToScene(toolTipPos)); + if (event->angleDelta().y() > 0 && zoomLevel < 20) + setZoom(++zoomLevel); + else if (event->angleDelta().y() < 0 && zoomLevel > 0) + setZoom(--zoomLevel); } void ProfileWidget2::mouseDoubleClickEvent(QMouseEvent *event) @@ -359,42 +343,26 @@ void ProfileWidget2::mouseDoubleClickEvent(QMouseEvent *event) } } -void ProfileWidget2::scrollViewTo(const QPoint &pos) -{ - /* since we cannot use translate() directly on the scene we hack on - * the scroll bars (hidden) functionality */ - if (!zoomLevel || !d) - return; - QScrollBar *vs = verticalScrollBar(); - QScrollBar *hs = horizontalScrollBar(); - const qreal yRat = (qreal)pos.y() / viewport()->height(); - const qreal xRat = (qreal)pos.x() / viewport()->width(); - vs->setValue(lrint(yRat * vs->maximum())); - hs->setValue(lrint(xRat * hs->maximum())); -} - void ProfileWidget2::mouseMoveEvent(QMouseEvent *event) { + QGraphicsView::mouseMoveEvent(event); + QPointF pos = mapToScene(event->pos()); toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); - if (zoomLevel == 0) { - QGraphicsView::mouseMoveEvent(event); - } else { - QPoint toolTipPos = mapFromScene(toolTipItem->pos()); - scrollViewTo(event->pos()); - toolTipItem->setPos(mapToScene(toolTipPos)); + if (zoomLevel != 0) { + zoomedPosition = pos.x() / profileScene->width(); + plotDive(d, dc, false, true); // TODO: animations don't work when scrolling } - qreal vValue = profileScene->profileYAxis->valueAt(pos); - qreal hValue = profileScene->timeAxis->valueAt(pos); + double vValue = profileScene->profileYAxis->valueAt(pos); + double hValue = profileScene->timeAxis->valueAt(pos); - if (profileScene->profileYAxis->maximum() >= vValue && profileScene->profileYAxis->minimum() <= vValue) { + if (profileScene->profileYAxis->maximum() >= vValue && profileScene->profileYAxis->minimum() <= vValue) mouseFollowerHorizontal->setPos(profileScene->timeAxis->pos().x(), pos.y()); - } - if (profileScene->timeAxis->maximum() >= hValue && profileScene->timeAxis->minimum() <= hValue) { + + if (profileScene->timeAxis->maximum() >= hValue && profileScene->timeAxis->minimum() <= hValue) mouseFollowerVertical->setPos(pos.x(), profileScene->profileYAxis->line().y1()); - } } bool ProfileWidget2::eventFilter(QObject *object, QEvent *event) diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h index 122065b79..22fe2365d 100644 --- a/profile-widget/profilewidget2.h +++ b/profile-widget/profilewidget2.h @@ -46,7 +46,6 @@ public: ProfileWidget2(DivePlannerPointsModel *plannerModel, double dpr, QWidget *parent = 0); ~ProfileWidget2(); void resetZoom(); - void scale(qreal sx, qreal sy); void plotDive(const struct dive *d, int dc, bool clearPictures = false, bool instant = false); void setProfileState(const struct dive *d, int dc); void setPlanState(const struct dive *d, int dc); @@ -111,8 +110,8 @@ private: void dragMoveEvent(QDragMoveEvent *event) override; void replot(); + void setZoom(int level); void changeGas(int tank, int seconds); - void scrollViewTo(const QPoint &pos); void setupSceneAndFlags(); void addItemsToScene(); void setupItemOnScene(); @@ -136,6 +135,7 @@ private: DivePlannerPointsModel *plannerModel; // If null, no planning supported. int zoomLevel; + double zoomedPosition; // Position, when zoomed: 0.0 = beginning, 1.0 = end. #ifndef SUBSURFACE_MOBILE ToolTipItem *toolTipItem; #endif