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 <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-10-06 21:01:58 +02:00 committed by Dirk Hohndel
parent 7d3e246680
commit c09382036f
4 changed files with 36 additions and 64 deletions

View file

@ -299,7 +299,8 @@ bool ProfileScene::isPointOutOfBoundaries(const QPointF &point) const
ypos < profileYAxis->minimum(); 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; d = dIn;
dc = dcIn; dc = dcIn;
@ -388,8 +389,11 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
percentageAxis->setVisible(false); percentageAxis->setVisible(false);
percentageAxis->updateTicks(animSpeed); percentageAxis->updateTicks(animSpeed);
if (calcMax) if (calcMax) {
timeAxis->setBounds(0.0, maxtime); 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); timeAxis->updateTicks(animSpeed);
cylinderPressureAxis->setBounds(plotInfo.minpressure, plotInfo.maxpressure); cylinderPressureAxis->setBounds(plotInfo.minpressure, plotInfo.maxpressure);

View file

@ -42,7 +42,7 @@ public:
// If a plannerModel is passed, the deco-information is taken from there. // 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, 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, void draw(QPainter *painter, const QRect &pos,
const struct dive *d, int dc, const struct dive *d, int dc,

View file

@ -180,11 +180,8 @@ void ProfileWidget2::setupSceneAndFlags()
void ProfileWidget2::resetZoom() void ProfileWidget2::resetZoom()
{ {
if (!zoomLevel)
return;
const double defScale = 1.0 / pow(zoomFactor, (double)zoomLevel);
scale(defScale, defScale);
zoomLevel = 0; zoomLevel = 0;
zoomedPosition = 0.0;
} }
// Currently just one dive, but the plan is to enable All of the selected dives. // 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; DivePlannerPointsModel *model = currentState == EDIT || currentState == PLAN ? plannerModel : nullptr;
bool inPlanner = currentState == PLAN; 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 #ifndef SUBSURFACE_MOBILE
// reset some item visibility on printMode changes // reset some item visibility on printMode changes
@ -307,19 +305,16 @@ void ProfileWidget2::mouseReleaseEvent(QMouseEvent *event)
} }
#endif #endif
void ProfileWidget2::scale(qreal sx, qreal sy) void ProfileWidget2::setZoom(int level)
{ {
QGraphicsView::scale(sx, sy); zoomLevel = level;
if (zoomLevel == 0) {
#ifndef SUBSURFACE_MOBILE zoomedPosition = 0.0;
// Since the zoom level changed, adjust the duration bars accordingly. } else {
// We want to grow/shrink the length, but not the height and pen. double pos = mapToScene(mapFromGlobal(QCursor::pos())).x();
for (PictureEntry &p: pictures) zoomedPosition = pos / profileScene->width();
updateDurationLine(p); }
replot();
// Since we created new duration lines, we have to update the order in which the thumbnails are painted.
updateThumbnailPaintOrder();
#endif
} }
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
@ -327,23 +322,12 @@ void ProfileWidget2::wheelEvent(QWheelEvent *event)
{ {
if (!d) if (!d)
return; return;
QPoint toolTipPos = mapFromScene(toolTipItem->pos());
if (event->buttons() == Qt::LeftButton) if (event->buttons() == Qt::LeftButton)
return; return;
if (event->angleDelta().y() > 0 && zoomLevel < 20) { if (event->angleDelta().y() > 0 && zoomLevel < 20)
scale(zoomFactor, zoomFactor); setZoom(++zoomLevel);
zoomLevel++; else if (event->angleDelta().y() < 0 && zoomLevel > 0)
} else if (event->angleDelta().y() < 0 && zoomLevel > 0) { setZoom(--zoomLevel);
// 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));
} }
void ProfileWidget2::mouseDoubleClickEvent(QMouseEvent *event) 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) void ProfileWidget2::mouseMoveEvent(QMouseEvent *event)
{ {
QGraphicsView::mouseMoveEvent(event);
QPointF pos = mapToScene(event->pos()); QPointF pos = mapToScene(event->pos());
toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
if (zoomLevel == 0) { if (zoomLevel != 0) {
QGraphicsView::mouseMoveEvent(event); zoomedPosition = pos.x() / profileScene->width();
} else { plotDive(d, dc, false, true); // TODO: animations don't work when scrolling
QPoint toolTipPos = mapFromScene(toolTipItem->pos());
scrollViewTo(event->pos());
toolTipItem->setPos(mapToScene(toolTipPos));
} }
qreal vValue = profileScene->profileYAxis->valueAt(pos); double vValue = profileScene->profileYAxis->valueAt(pos);
qreal hValue = profileScene->timeAxis->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()); 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()); mouseFollowerVertical->setPos(pos.x(), profileScene->profileYAxis->line().y1());
}
} }
bool ProfileWidget2::eventFilter(QObject *object, QEvent *event) bool ProfileWidget2::eventFilter(QObject *object, QEvent *event)

View file

@ -46,7 +46,6 @@ public:
ProfileWidget2(DivePlannerPointsModel *plannerModel, double dpr, QWidget *parent = 0); ProfileWidget2(DivePlannerPointsModel *plannerModel, double dpr, QWidget *parent = 0);
~ProfileWidget2(); ~ProfileWidget2();
void resetZoom(); void resetZoom();
void scale(qreal sx, qreal sy);
void plotDive(const struct dive *d, int dc, bool clearPictures = false, bool instant = false); void plotDive(const struct dive *d, int dc, bool clearPictures = false, bool instant = false);
void setProfileState(const struct dive *d, int dc); void setProfileState(const struct dive *d, int dc);
void setPlanState(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 dragMoveEvent(QDragMoveEvent *event) override;
void replot(); void replot();
void setZoom(int level);
void changeGas(int tank, int seconds); void changeGas(int tank, int seconds);
void scrollViewTo(const QPoint &pos);
void setupSceneAndFlags(); void setupSceneAndFlags();
void addItemsToScene(); void addItemsToScene();
void setupItemOnScene(); void setupItemOnScene();
@ -136,6 +135,7 @@ private:
DivePlannerPointsModel *plannerModel; // If null, no planning supported. DivePlannerPointsModel *plannerModel; // If null, no planning supported.
int zoomLevel; int zoomLevel;
double zoomedPosition; // Position, when zoomed: 0.0 = beginning, 1.0 = end.
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
ToolTipItem *toolTipItem; ToolTipItem *toolTipItem;
#endif #endif