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();
}
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);

View file

@ -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,

View file

@ -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)

View file

@ -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