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