feat: auto long image mode

This commit is contained in:
2025-07-26 15:33:02 +08:00
parent f0ed9d0ca1
commit f8d3dcc899
8 changed files with 136 additions and 8 deletions

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
//
// SPDX-License-Identifier: MIT
@ -124,6 +124,7 @@ void GraphicsView::resetTransform()
void GraphicsView::zoomView(qreal scaleFactor)
{
m_enableFitInView = false;
m_longImageMode = false;
scale(scaleFactor, scaleFactor);
applyTransformationModeByScaleFactor();
emit navigatorViewRequired(!isThingSmallerThanWindowWith(transform()), transform());
@ -140,6 +141,10 @@ void GraphicsView::rotateView(bool clockwise)
0, 0, 1);
tf = transform() * tf;
setTransform(tf);
// Apply transformation mode but don't emit navigator signal here
// Let displayScene() handle the navigator visibility correctly
applyTransformationModeByScaleFactor();
}
void GraphicsView::flipView(bool horizontal)
@ -261,6 +266,69 @@ void GraphicsView::fitByOrientation(Qt::Orientation ori, bool scaleDownOnly)
emit navigatorViewRequired(!isThingSmallerThanWindowWith(transform()), transform());
}
bool GraphicsView::isLongImage() const
{
// Get the transformed image size (considering rotation and other transforms)
QRectF transformedRect = transform().mapRect(sceneRect());
QSizeF imageSize = transformedRect.size();
if (imageSize.isEmpty()) return false;
qreal aspectRatio = imageSize.width() / imageSize.height();
// Check if aspect ratio exceeds 5:2 (wide) or 2:5 (tall)
return aspectRatio > 2.5 || aspectRatio < 0.4;
}
bool GraphicsView::shouldEnterLongImageMode() const
{
// Check if long image mode is enabled in settings
if (!Settings::instance()->autoLongImageMode()) return false;
// Check if image is a long image
if (!isLongImage()) return false;
// Check if transformed image size is larger than the size of the view
QSizeF imageSize = transform().mapRect(sceneRect()).size();
QSizeF viewSize = viewport()->size();
return imageSize.width() > viewSize.width() || imageSize.height() > viewSize.height();
}
void GraphicsView::applyLongImageMode()
{
if (!shouldEnterLongImageMode()) {
m_longImageMode = false;
return;
}
m_longImageMode = true;
applyLongImageModeDirect();
}
void GraphicsView::applyLongImageModeDirect()
{
// Determine image orientation based on current transform
QRectF transformedRect = transform().mapRect(sceneRect());
qreal aspectRatio = transformedRect.width() / transformedRect.height();
bool isTallImage = aspectRatio < 0.4;
bool isWideImage = aspectRatio > 2.5;
// Use fitByOrientation with the migrated logic
if (isTallImage) {
// Tall image (height >> width): fit by width
fitByOrientation(Qt::Horizontal, true); // scaleDownOnly = true
} else if (isWideImage) {
// Wide image (width >> height): fit by height
fitByOrientation(Qt::Vertical, true); // scaleDownOnly = true
}
}
bool GraphicsView::isInLongImageMode() const
{
return m_longImageMode;
}
void GraphicsView::displayScene()
{
if (shouldAvoidTransform()) {
@ -268,8 +336,23 @@ void GraphicsView::displayScene()
return;
}
// Check if should apply long image mode
if (shouldEnterLongImageMode()) {
applyLongImageMode();
m_firstUserMediaLoaded = true;
return;
}
// Not in long image mode
m_longImageMode = false;
if (isSceneBiggerThanView()) {
fitInView(sceneRect(), Qt::KeepAspectRatio);
// After fitInView, the image should fit the window, so hide navigator
emit navigatorViewRequired(false, transform());
} else {
// Image is already smaller than window, no navigator needed
emit navigatorViewRequired(false, transform());
}
m_enableFitInView = true;
@ -291,6 +374,11 @@ void GraphicsView::setEnableAutoFitInView(bool enable)
m_enableFitInView = enable;
}
void GraphicsView::setLongImageMode(bool enable)
{
m_longImageMode = enable;
}
bool GraphicsView::avoidResetTransform() const
{
return m_avoidResetTransform;
@ -363,7 +451,12 @@ void GraphicsView::wheelEvent(QWheelEvent *event)
void GraphicsView::resizeEvent(QResizeEvent *event)
{
if (m_enableFitInView) {
if (m_longImageMode) {
// In long image mode, reapply long image logic on resize
// We directly apply the long image mode logic without rechecking
// if we should enter long image mode, as the mode is already active
applyLongImageModeDirect();
} else if (m_enableFitInView) {
bool originalSizeSmallerThanWindow = isThingSmallerThanWindowWith(resetScale(transform()));
if (originalSizeSmallerThanWindow && scaleFactor() >= 1) {
// no longer need to do fitInView()