From 68eccfc970a49367f2d3e57e9c5dc6d450003929 Mon Sep 17 00:00:00 2001 From: "J.D. Purcell" Date: Tue, 31 Dec 2024 22:25:56 -0500 Subject: [PATCH] WIP --- src/qvgraphicsview.cpp | 57 +++++++++++++++++++++++++++--------------- src/qvgraphicsview.h | 6 ++++- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/qvgraphicsview.cpp b/src/qvgraphicsview.cpp index e68372a0..08a7f9aa 100644 --- a/src/qvgraphicsview.cpp +++ b/src/qvgraphicsview.cpp @@ -834,7 +834,7 @@ const QJsonObject QVGraphicsView::getSessionState() const { QJsonObject state; - const QTransform transform = getTransformWithNoScaling(); + const QTransform transform = getUnspecializedTransform(); const QJsonArray transformValues { static_cast(transform.m11()), static_cast(transform.m22()), @@ -924,7 +924,7 @@ bool QVGraphicsView::isExpensiveScalingRequested() const QSizeF QVGraphicsView::getEffectiveOriginalSize() const { - return getTransformWithNoScaling().mapRect(QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize)).size() * getDpiAdjustment(); + return getUnspecializedTransform().mapRect(QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize)).size() * getDpiAdjustment(); } LogicalPixelFitter QVGraphicsView::getPixelFitter() const @@ -941,22 +941,19 @@ void QVGraphicsView::matchContentCenter(const QRect target) QRect QVGraphicsView::getContentRect() const { + if (!getCurrentFileDetails().isPixmapLoaded) + return {}; + // Avoid using loadedPixmapItem and the active transform because the pixmap may have expensive scaling applied // which introduces a rounding error to begin with, and even worse, the error will be magnified if we're in the // the process of zooming in and haven't re-applied the expensive scaling yet. If that's the case, callers need // to know what the content rect will be once the dust settles rather than what's being temporarily displayed. - const QRectF loadedPixmapBoundingRect = QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize); - const qreal effectiveTransformScale = zoomLevel * appliedDpiAdjustment; - const QTransform effectiveTransform = getTransformWithNoScaling().scale(effectiveTransformScale, effectiveTransformScale); - const QRectF contentRect = effectiveTransform.mapRect(loadedPixmapBoundingRect); - const QSize snappedSize = getPixelFitter().snapSize(contentRect.size()); - const bool isHorizontalReversed = effectiveTransform.m11() < 0 || effectiveTransform.m21() < 0; - const bool isVerticalReversed = effectiveTransform.m22() < 0 || effectiveTransform.m12() < 0; - const QPointF topLeftCorrection = QPointF( - isHorizontalReversed ? contentRect.width() - snappedSize.width() : 0, - isVerticalReversed ? contentRect.height() - snappedSize.height() : 0 - ); - return QRect((contentRect.topLeft() + topLeftCorrection).toPoint(), snappedSize); + const QSizeF pixmapSize = getCurrentFileDetails().loadedPixmapSize; + const QRectF pixmapBoundingRect = QRectF(QPoint(), pixmapSize); + const qreal pixmapScale = zoomLevel * appliedDpiAdjustment; + const QTransform pixmapTransform = normalizeTransformOrigin(getUnspecializedTransform().scale(pixmapScale, pixmapScale), pixmapSize); + const QRectF contentRect = pixmapTransform.mapRect(pixmapBoundingRect); + return QRect(contentRect.topLeft().toPoint(), getPixelFitter().snapSize(contentRect.size())); } QRect QVGraphicsView::getUsableViewportRect(const bool addOverscan) const @@ -970,10 +967,20 @@ QRect QVGraphicsView::getUsableViewportRect(const bool addOverscan) const void QVGraphicsView::setTransformScale(qreal value) { - setTransform(getTransformWithNoScaling().scale(value, value)); + setTransformWithNormalization(getUnspecializedTransform().scale(value, value)); +} + +void QVGraphicsView::setTransformWithNormalization(QTransform matrix) +{ + if (!loadedPixmapItem->pixmap().isNull()) + { + matrix = normalizeTransformOrigin(matrix, loadedPixmapItem->boundingRect().size()); + } + setTransform(matrix); + qDebug() << getContentRect(); } -QTransform QVGraphicsView::getTransformWithNoScaling() const +QTransform QVGraphicsView::getUnspecializedTransform() const { const QTransform t = transform(); // Only intended to handle combinations of scaling, mirroring, flipping, and rotation @@ -1035,6 +1042,16 @@ MainWindow* QVGraphicsView::getMainWindow() const return qobject_cast(window()); } +QTransform QVGraphicsView::normalizeTransformOrigin(QTransform matrix, const QSizeF pixmapSize) +{ + const bool isXNegative = matrix.m11() < 0 || matrix.m12() < 0; + const bool isYNegative = matrix.m22() < 0 || matrix.m21() < 0; + return matrix.translate( + isXNegative ? -pixmapSize.width() : 0, + isYNegative ? -pixmapSize.height() : 0 + ); +} + void QVGraphicsView::settingsUpdated() { auto &settingsManager = qvApp->getSettingsManager(); @@ -1131,7 +1148,7 @@ void QVGraphicsView::rotateImage(const int relativeAngle) 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)); + setTransformWithNormalization(transform().rotate(relativeAngle * (isMirroredOrFlipped ? -1 : 1))); matchContentCenter(oldRect); } @@ -1139,7 +1156,7 @@ void QVGraphicsView::mirrorImage() { const QRect oldRect = getContentRect(); const int rotateCorrection = transform().isRotating() ? -1 : 1; - scale(-1 * rotateCorrection, 1 * rotateCorrection); + setTransformWithNormalization(transform().scale(-1 * rotateCorrection, 1 * rotateCorrection)); matchContentCenter(oldRect); } @@ -1147,7 +1164,7 @@ void QVGraphicsView::flipImage() { const QRect oldRect = getContentRect(); const int rotateCorrection = transform().isRotating() ? -1 : 1; - scale(1 * rotateCorrection, -1 * rotateCorrection); + setTransformWithNormalization(transform().scale(1 * rotateCorrection, -1 * rotateCorrection)); matchContentCenter(oldRect); } @@ -1156,6 +1173,6 @@ void QVGraphicsView::resetTransformation() const QRect oldRect = getContentRect(); const QTransform t = transform(); const qreal scale = qFabs(t.isRotating() ? t.m21() : t.m11()); - setTransform(QTransform::fromScale(scale, scale)); + setTransformWithNormalization(QTransform::fromScale(scale, scale)); matchContentCenter(oldRect); } diff --git a/src/qvgraphicsview.h b/src/qvgraphicsview.h index fcc8105c..a03f80d1 100644 --- a/src/qvgraphicsview.h +++ b/src/qvgraphicsview.h @@ -146,7 +146,9 @@ class QVGraphicsView : public QGraphicsView void setTransformScale(qreal absoluteScale); - QTransform getTransformWithNoScaling() const; + void setTransformWithNormalization(QTransform matrix); + + QTransform getUnspecializedTransform() const; qreal getDpiAdjustment() const; @@ -158,6 +160,8 @@ class QVGraphicsView : public QGraphicsView MainWindow* getMainWindow() const; + static QTransform normalizeTransformOrigin(QTransform matrix, const QSizeF pixmapSize); + private slots: void animatedFrameChanged(QRect rect);