From 2228d2f72778bc3939954380820b16d05dfbad92 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Sun, 22 Dec 2024 18:06:41 -0500 Subject: [PATCH] Make some calculations more robust * getContentRect now returns QRect because in practice, GraphicsView always snaps to whole pixels when displaying. This also prevents use of getContentRect().size().toSize() which can in theory round differently than getContentRect().toRect().size() (probably not in practice since we don't translate by fractional amounts), so this forces rounding to happen the same way it will end up getting displayed. * isExpensiveScalingRequested shouldn't use getContentRect because the current pixmap may already have been scaled expensively and have some rounding errors built in. We only want to take the the future pixmap into account, the size of which will be recalculated from ideal values. * Increase the error tolerance slightly for expensive scaling (even though it probably doesn't need it now?) because there's no downside if the threshold is a tad high, but if it's too low we'll miss scaling a fitted image. --- src/qvgraphicsview.cpp | 26 +++++++++++++------------- src/qvgraphicsview.h | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/qvgraphicsview.cpp b/src/qvgraphicsview.cpp index daee31e4..60031ce3 100644 --- a/src/qvgraphicsview.cpp +++ b/src/qvgraphicsview.cpp @@ -30,7 +30,7 @@ QVGraphicsView::QVGraphicsView(QWidget *parent) : QGraphicsView(parent) scrollHelper = new ScrollHelper(this, [this](ScrollHelper::Parameters &p) { - p.contentRect = getContentRect().toRect(); + p.contentRect = getContentRect(); p.usableViewportRect = getUsableViewportRect(); p.shouldConstrain = isConstrainedPositioningEnabled; p.shouldCenter = isConstrainedSmallCenteringEnabled; @@ -766,7 +766,7 @@ void QVGraphicsView::recalculateZoom() void QVGraphicsView::centerImage() { const QRect viewRect = getUsableViewportRect(); - const QRect contentRect = getContentRect().toRect(); + const QRect contentRect = getContentRect(); const int hOffset = isRightToLeft() ? horizontalScrollBar()->minimum() + horizontalScrollBar()->maximum() - contentRect.left() : contentRect.left(); @@ -892,9 +892,9 @@ bool QVGraphicsView::isExpensiveScalingRequested() const if (!isSmoothScalingRequested() || smoothScalingMode != Qv::SmoothScalingMode::Expensive || !getCurrentFileDetails().isPixmapLoaded) return false; - // If we are above maximum scaling size - const QSize contentSize = getContentRect().size().toSize(); - const QSize maxSize = getUsableViewportRect(true).size() * (expensiveScalingAboveWindowSize ? 3 : 1) + QSize(1, 1); + // Don't go over the maximum scaling size (a small tolerance is added to cover rounding errors) + const QSize contentSize = (getEffectiveOriginalSize() * zoomLevel).toSize(); + const QSize maxSize = getUsableViewportRect(true).size() * (expensiveScalingAboveWindowSize ? 3 : 1) + QSize(2, 2); return contentSize.width() <= maxSize.width() && contentSize.height() <= maxSize.height(); } @@ -903,15 +903,15 @@ QSizeF QVGraphicsView::getEffectiveOriginalSize() const return getTransformWithNoScaling().mapRect(QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize)).size() * getDpiAdjustment(); } -void QVGraphicsView::matchContentCenter(const QRectF target) +void QVGraphicsView::matchContentCenter(const QRect target) { - const QPointF delta = getContentRect().center() - target.center(); + const QPointF delta = QRectF(getContentRect()).center() - QRectF(target).center(); scrollHelper->move(QPointF(delta.x() * (isRightToLeft() ? -1 : 1), delta.y())); } -QRectF QVGraphicsView::getContentRect() const +QRect QVGraphicsView::getContentRect() const { - return transform().mapRect(loadedPixmapItem->boundingRect()); + return transform().mapRect(loadedPixmapItem->boundingRect()).toRect(); } QRect QVGraphicsView::getUsableViewportRect(const bool addOverscan) const @@ -1090,7 +1090,7 @@ void QVGraphicsView::setSpeed(const int &desiredSpeed) void QVGraphicsView::rotateImage(const int relativeAngle) { - const QRectF oldRect = getContentRect(); + const QRect oldRect = getContentRect(); const QTransform t = transform(); const bool isMirroredOrFlipped = t.isRotating() ? (t.m12() < 0 == t.m21() < 0) : (t.m11() < 0 != t.m22() < 0); rotate(relativeAngle * (isMirroredOrFlipped ? -1 : 1)); @@ -1099,7 +1099,7 @@ void QVGraphicsView::rotateImage(const int relativeAngle) void QVGraphicsView::mirrorImage() { - const QRectF oldRect = getContentRect(); + const QRect oldRect = getContentRect(); const int rotateCorrection = transform().isRotating() ? -1 : 1; scale(-1 * rotateCorrection, 1 * rotateCorrection); matchContentCenter(oldRect); @@ -1107,7 +1107,7 @@ void QVGraphicsView::mirrorImage() void QVGraphicsView::flipImage() { - const QRectF oldRect = getContentRect(); + const QRect oldRect = getContentRect(); const int rotateCorrection = transform().isRotating() ? -1 : 1; scale(1 * rotateCorrection, -1 * rotateCorrection); matchContentCenter(oldRect); @@ -1115,7 +1115,7 @@ void QVGraphicsView::flipImage() void QVGraphicsView::resetTransformation() { - const QRectF oldRect = getContentRect(); + const QRect oldRect = getContentRect(); const QTransform t = transform(); const qreal scale = qFabs(t.isRotating() ? t.m21() : t.m11()); setTransform(QTransform::fromScale(scale, scale)); diff --git a/src/qvgraphicsview.h b/src/qvgraphicsview.h index 170cbb13..a685c1dd 100644 --- a/src/qvgraphicsview.h +++ b/src/qvgraphicsview.h @@ -135,9 +135,9 @@ class QVGraphicsView : public QGraphicsView bool isExpensiveScalingRequested() const; - void matchContentCenter(const QRectF target); + void matchContentCenter(const QRect target); - QRectF getContentRect() const; + QRect getContentRect() const; QRect getUsableViewportRect(const bool addOverscan = false) const; @@ -200,7 +200,7 @@ private slots: QPointF lastZoomRoundingError; bool isCursorAutoHideFullscreenEnabled {true}; bool isCursorVisible {true}; - QRectF lastImageContentRect; + QRect lastImageContentRect; QVImageCore imageCore {this};