File indexing completed on 2025-04-27 03:58:24
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-04-30 0007 * Description : Image zoom settings 0008 * 0009 * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "imagezoomsettings.h" 0016 0017 // C++ includes 0018 0019 #include <cmath> 0020 0021 // Qt includes 0022 0023 #include <QList> 0024 0025 // Local includes 0026 0027 #include "digikam_debug.h" 0028 0029 namespace Digikam 0030 { 0031 0032 ImageZoomSettings::ImageZoomSettings() 0033 : m_zoom (1.0), 0034 m_zoomConst (1.0), 0035 m_displayWidget(nullptr) 0036 { 0037 } 0038 0039 ImageZoomSettings::ImageZoomSettings(const QSize& imageSize, const QSize& originalSize) 0040 : m_zoom (1.0), 0041 m_zoomConst (1.0), 0042 m_displayWidget(nullptr) 0043 { 0044 setImageSize(imageSize, originalSize); 0045 } 0046 0047 void ImageZoomSettings::setImageSize(const QSize& size, const QSize& originalSize) 0048 { 0049 m_size = size; 0050 0051 if (!originalSize.isNull() && originalSize.isValid()) 0052 { 0053 m_zoomConst = m_size.width() / double(originalSize.width()); 0054 } 0055 else 0056 { 0057 m_zoomConst = 1.0; 0058 } 0059 } 0060 0061 void ImageZoomSettings::setDisplayWidget(QWidget* const widget) 0062 { 0063 m_displayWidget = widget; 0064 } 0065 0066 double ImageZoomSettings::zoomFactor() const 0067 { 0068 return m_zoom; 0069 } 0070 0071 double ImageZoomSettings::realZoomFactor() const 0072 { 0073 return (m_zoom / displayRatio()); 0074 } 0075 0076 QSizeF ImageZoomSettings::imageSize() const 0077 { 0078 return m_size; 0079 } 0080 0081 QSizeF ImageZoomSettings::originalImageSize() const 0082 { 0083 return (m_size / m_zoomConst); 0084 } 0085 0086 QSizeF ImageZoomSettings::zoomedSize() const 0087 { 0088 return (m_size / (m_zoomConst * displayRatio()) * m_zoom); 0089 } 0090 0091 QRectF ImageZoomSettings::sourceRect(const QRectF& imageRect) const 0092 { 0093 return mapZoomToImage(imageRect); 0094 } 0095 0096 bool ImageZoomSettings::isFitToSize(const QSizeF& frameSize) const 0097 { 0098 return (zoomFactor() == fitToSizeZoomFactor(frameSize)); 0099 } 0100 0101 void ImageZoomSettings::setZoomFactor(double zoom) 0102 { 0103 m_zoom = zoom; 0104 } 0105 0106 void ImageZoomSettings::fitToSize(const QSizeF& frameSize, FitToSizeMode mode) 0107 { 0108 setZoomFactor(fitToSizeZoomFactor(frameSize, mode)); 0109 } 0110 0111 double ImageZoomSettings::fitToSizeZoomFactor(const QSizeF& frameSize, FitToSizeMode mode) const 0112 { 0113 if (!frameSize.isValid() || !m_size.isValid()) 0114 { 0115 return 1.0; 0116 } 0117 0118 double zoom; 0119 0120 if ((frameSize.width() / frameSize.height()) < (m_size.width() / m_size.height())) 0121 { 0122 zoom = m_zoomConst * displayRatio() * frameSize.width() / m_size.width(); 0123 } 0124 else 0125 { 0126 zoom = m_zoomConst * displayRatio() * frameSize.height() / m_size.height(); 0127 } 0128 0129 // Zoom rounding down and scroll bars are never activated. 0130 0131 zoom = floor(zoom * 100000 - 0.1) / 100000.0; 0132 0133 if (mode == OnlyScaleDown) 0134 { 0135 // OnlyScaleDown: accept that an image is smaller than available space, don't scale up 0136 0137 if ((frameSize.width() > originalImageSize().width()) && (frameSize.height() > originalImageSize().height())) 0138 { 0139 zoom = 1.0; 0140 } 0141 } 0142 0143 return zoom; 0144 } 0145 0146 QRectF ImageZoomSettings::mapZoomToImage(const QRectF& zoomedRect) const 0147 { 0148 return QRectF(zoomedRect.topLeft() / (m_zoom / (m_zoomConst * displayRatio())), 0149 zoomedRect.size() / (m_zoom / (m_zoomConst * displayRatio()))); 0150 } 0151 0152 QRectF ImageZoomSettings::mapImageToZoom(const QRectF& imageRect) const 0153 { 0154 return QRectF(imageRect.topLeft() * (m_zoom / (m_zoomConst * displayRatio())), 0155 imageRect.size() * (m_zoom / (m_zoomConst * displayRatio()))); 0156 } 0157 0158 QPointF ImageZoomSettings::mapZoomToImage(const QPointF& zoomedPoint) const 0159 { 0160 return (zoomedPoint / (m_zoom / (m_zoomConst * displayRatio()))); 0161 } 0162 0163 QPointF ImageZoomSettings::mapImageToZoom(const QPointF& imagePoint) const 0164 { 0165 return (imagePoint * (m_zoom / (m_zoomConst * displayRatio()))); 0166 } 0167 0168 inline static bool lessThanLimitedPrecision(double a, double b) 0169 { 0170 return lround(a * 100000) < lround(b * 100000); 0171 } 0172 0173 double ImageZoomSettings::snappedZoomStep(double nextZoom, const QSizeF& frameSize) const 0174 { 0175 // If the zoom value gets changed from d->zoom to zoom 0176 // across 50%, 100% or fit-to-window, then return the 0177 // the corresponding special value. Otherwise zoom is returned unchanged. 0178 0179 QList<double> snapValues; 0180 snapValues << 0.5; 0181 snapValues << 1.0; 0182 0183 if (frameSize.isValid()) 0184 { 0185 snapValues << fitToSizeZoomFactor(frameSize); 0186 } 0187 0188 double currentZoom = zoomFactor(); 0189 0190 if (currentZoom < nextZoom) 0191 { 0192 Q_FOREACH (double z, snapValues) 0193 { 0194 if (lessThanLimitedPrecision(currentZoom, z) && lessThanLimitedPrecision(z, nextZoom)) 0195 { // cppcheck-suppress useStlAlgorithm 0196 return z; 0197 } 0198 } 0199 } 0200 else 0201 { 0202 Q_FOREACH (double z, snapValues) 0203 { 0204 if (lessThanLimitedPrecision(z, currentZoom) && lessThanLimitedPrecision(nextZoom, z)) 0205 { // cppcheck-suppress useStlAlgorithm 0206 return z; 0207 } 0208 } 0209 } 0210 0211 return nextZoom; 0212 } 0213 0214 double ImageZoomSettings::snappedZoomFactor(double zoom, const QSizeF& frameSize) const 0215 { 0216 QList<double> snapValues; 0217 snapValues << 0.5; 0218 snapValues << 1.0; 0219 0220 if (frameSize.isValid()) 0221 { 0222 snapValues << fitToSizeZoomFactor(frameSize); 0223 } 0224 0225 Q_FOREACH (double z, snapValues) 0226 { 0227 if (fabs(zoom - z) < 0.05) 0228 { // cppcheck-suppress useStlAlgorithm 0229 return z; 0230 } 0231 } 0232 0233 return zoom; 0234 } 0235 0236 double ImageZoomSettings::displayRatio() const 0237 { 0238 if (m_displayWidget) 0239 { 0240 return m_displayWidget->devicePixelRatio(); 0241 } 0242 0243 qCWarning(DIGIKAM_GENERAL_LOG) << "ImageZoomSettings: display widget not set"; 0244 0245 return 1.0; 0246 } 0247 0248 } // namespace Digikam