File indexing completed on 2025-04-27 03:58:25
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-04-30 0007 * Description : Layout for an item on image preview 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 "previewlayout.h" 0016 0017 // Qt includes 0018 0019 #include <QGraphicsView> 0020 #include <QGraphicsScene> 0021 0022 // Local includes 0023 0024 #include "graphicsdimgitem.h" 0025 #include "graphicsdimgview.h" 0026 #include "imagezoomsettings.h" 0027 0028 namespace Digikam 0029 { 0030 0031 class Q_DECL_HIDDEN SinglePhotoPreviewLayout::Private 0032 { 0033 public: 0034 0035 explicit Private() 0036 : view (nullptr), 0037 item (nullptr), 0038 fitToSizeMode (ImageZoomSettings::OnlyScaleDown), 0039 isFitToWindow (true), 0040 previousZoom (1.0), 0041 zoomMultiplier(1.2), 0042 maxZoom (12.0), 0043 minZoom (0.1) 0044 { 0045 } 0046 0047 ImageZoomSettings* zoomSettings() const 0048 { 0049 return item->zoomSettings(); 0050 } 0051 0052 QSizeF frameSize() const 0053 { 0054 return view->maximumViewportSize(); 0055 } 0056 0057 public: 0058 0059 GraphicsDImgView* view; 0060 GraphicsDImgItem* item; 0061 0062 ImageZoomSettings::FitToSizeMode fitToSizeMode; 0063 0064 bool isFitToWindow; 0065 double previousZoom; 0066 0067 double zoomMultiplier; 0068 double maxZoom; 0069 double minZoom; 0070 }; 0071 0072 SinglePhotoPreviewLayout::SinglePhotoPreviewLayout(QObject* const parent) 0073 : QObject(parent), 0074 d(new Private) 0075 { 0076 } 0077 0078 SinglePhotoPreviewLayout::~SinglePhotoPreviewLayout() 0079 { 0080 delete d; 0081 } 0082 0083 void SinglePhotoPreviewLayout::setGraphicsView(GraphicsDImgView* const view) 0084 { 0085 d->view = view; 0086 } 0087 0088 void SinglePhotoPreviewLayout::setScaleFitToWindow(bool value) 0089 { 0090 if (value) 0091 { 0092 d->fitToSizeMode = ImageZoomSettings::AlwaysFit; 0093 } 0094 else 0095 { 0096 d->fitToSizeMode = ImageZoomSettings::OnlyScaleDown; 0097 } 0098 } 0099 0100 void SinglePhotoPreviewLayout::addItem(GraphicsDImgItem* const item) 0101 { 0102 if (d->item) 0103 { 0104 disconnect(d->item, SIGNAL(imageChanged()), 0105 this, SLOT(updateZoomAndSize())); 0106 } 0107 0108 d->item = item; 0109 0110 if (d->item) 0111 { 0112 connect(d->item, SIGNAL(imageChanged()), 0113 this, SLOT(updateZoomAndSize())); 0114 } 0115 } 0116 0117 bool SinglePhotoPreviewLayout::isFitToWindow() const 0118 { 0119 return d->isFitToWindow; 0120 } 0121 0122 double SinglePhotoPreviewLayout::zoomFactor() const 0123 { 0124 if (!d->item || !d->view) 0125 { 0126 return 1.0; 0127 } 0128 0129 return d->zoomSettings()->zoomFactor(); 0130 } 0131 0132 double SinglePhotoPreviewLayout::realZoomFactor() const 0133 { 0134 if (!d->item || !d->view) 0135 { 0136 return 1.0; 0137 } 0138 0139 return d->zoomSettings()->realZoomFactor(); 0140 } 0141 0142 double SinglePhotoPreviewLayout::maxZoomFactor() const 0143 { 0144 return d->maxZoom; 0145 } 0146 0147 double SinglePhotoPreviewLayout::minZoomFactor() const 0148 { 0149 return d->minZoom; 0150 } 0151 0152 bool SinglePhotoPreviewLayout::atMaxZoom() const 0153 { 0154 return (zoomFactor() >= d->maxZoom); 0155 } 0156 0157 bool SinglePhotoPreviewLayout::atMinZoom() const 0158 { 0159 return (zoomFactor() <= d->minZoom); 0160 } 0161 0162 void SinglePhotoPreviewLayout::setMaxZoomFactor(double z) 0163 { 0164 d->maxZoom = z; 0165 } 0166 0167 void SinglePhotoPreviewLayout::setMinZoomFactor(double z) 0168 { 0169 d->minZoom = z; 0170 } 0171 0172 void SinglePhotoPreviewLayout::increaseZoom(const QPoint& viewportAnchor) 0173 { 0174 if (!d->item || !d->view) 0175 { 0176 return; 0177 } 0178 0179 double zoom = d->zoomSettings()->zoomFactor() * d->zoomMultiplier; 0180 zoom = qMin(zoom, d->maxZoom); 0181 zoom = d->zoomSettings()->snappedZoomStep(zoom, d->frameSize()); 0182 setZoomFactor(zoom, viewportAnchor); 0183 } 0184 0185 void SinglePhotoPreviewLayout::decreaseZoom(const QPoint& viewportAnchor) 0186 { 0187 if (!d->item || !d->view) 0188 { 0189 return; 0190 } 0191 0192 double zoom = d->zoomSettings()->zoomFactor() / d->zoomMultiplier; 0193 zoom = qMax(zoom, d->minZoom); 0194 zoom = d->zoomSettings()->snappedZoomStep(zoom, d->frameSize()); 0195 setZoomFactor(zoom, viewportAnchor); 0196 } 0197 0198 void SinglePhotoPreviewLayout::setZoomFactorSnapped(double z) 0199 { 0200 setZoomFactor(z, SnapZoomFactor); 0201 } 0202 0203 void SinglePhotoPreviewLayout::setZoomFactor(double z, const QPoint& givenAnchor, SetZoomFlags flags) 0204 { 0205 if (!d->item || !d->view) 0206 { 0207 return; 0208 } 0209 0210 QPoint viewportAnchor = givenAnchor.isNull() ? d->view->viewport()->rect().center() : givenAnchor; 0211 QPointF sceneAnchor = d->view->mapToScene(viewportAnchor); 0212 QPointF imageAnchor = d->zoomSettings()->mapZoomToImage(sceneAnchor); 0213 0214 if (flags & SnapZoomFactor) 0215 { 0216 z = d->zoomSettings()->snappedZoomFactor(z, d->frameSize()); 0217 } 0218 0219 d->isFitToWindow = false; 0220 double minZoom = qMin(z, 0.1); 0221 double maxZoom = qMax(z, maxZoomFactor()); 0222 minZoom = qMin(minZoom, minZoomFactor()); 0223 0224 setMinZoomFactor(minZoom); 0225 setMaxZoomFactor(maxZoom); 0226 0227 d->zoomSettings()->setZoomFactor(z); 0228 d->item->sizeHasChanged(); 0229 0230 updateLayout(); 0231 d->item->update(); 0232 0233 Q_EMIT fitToWindowToggled(d->isFitToWindow); 0234 Q_EMIT zoomFactorChanged(d->zoomSettings()->zoomFactor()); 0235 0236 if (flags & CenterView) 0237 { 0238 d->view->centerOn(d->view->scene()->sceneRect().width() / 2.0, 0239 d->view->scene()->sceneRect().height() / 2.0); 0240 } 0241 0242 d->view->scrollPointOnPoint(d->zoomSettings()->mapImageToZoom(imageAnchor), viewportAnchor); 0243 } 0244 0245 void SinglePhotoPreviewLayout::setZoomFactor(double z, SetZoomFlags flags) 0246 { 0247 if (!d->item || !d->view) 0248 { 0249 return; 0250 } 0251 0252 setZoomFactor(z, QPoint(), flags); 0253 } 0254 0255 void SinglePhotoPreviewLayout::fitToWindow() 0256 { 0257 if (!d->item || !d->view) 0258 { 0259 return; 0260 } 0261 0262 if (!d->isFitToWindow) 0263 { 0264 d->previousZoom = d->zoomSettings()->zoomFactor(); 0265 } 0266 0267 d->isFitToWindow = true; 0268 0269 d->zoomSettings()->fitToSize(d->frameSize(), d->fitToSizeMode); 0270 d->item->sizeHasChanged(); 0271 0272 updateLayout(); 0273 d->item->update(); 0274 0275 Q_EMIT fitToWindowToggled(d->isFitToWindow); 0276 Q_EMIT zoomFactorChanged(d->zoomSettings()->zoomFactor()); 0277 } 0278 0279 void SinglePhotoPreviewLayout::toggleFitToWindow() 0280 { 0281 if (!d->item || !d->view) 0282 { 0283 return; 0284 } 0285 0286 if (d->isFitToWindow) 0287 { 0288 setZoomFactor(d->previousZoom); 0289 } 0290 else 0291 { 0292 fitToWindow(); 0293 } 0294 } 0295 0296 void SinglePhotoPreviewLayout::toggleFitToWindowOr100() 0297 { 0298 if (!d->item || !d->view) 0299 { 0300 return; 0301 } 0302 0303 if (d->isFitToWindow || ((qRound(zoomFactor() * 1000) / 1000.0) != 1.0)) 0304 { 0305 setZoomFactor(1.0); 0306 } 0307 else 0308 { 0309 fitToWindow(); 0310 } 0311 } 0312 0313 void SinglePhotoPreviewLayout::updateLayout() 0314 { 0315 if (!d->item || !d->view) 0316 { 0317 return; 0318 } 0319 0320 d->view->scene()->setSceneRect(d->item->boundingRect()); 0321 d->item->setPos(0, 0); 0322 } 0323 0324 void SinglePhotoPreviewLayout::updateZoomAndSize() 0325 { 0326 if (!d->item || !d->view) 0327 { 0328 return; 0329 } 0330 0331 double fitZoom = d->zoomSettings()->fitToSizeZoomFactor(d->frameSize(), d->fitToSizeMode); 0332 double minZoom = qBound(0.01, fitZoom - 0.01, 0.1); 0333 0334 setMinZoomFactor(minZoom); 0335 setMaxZoomFactor(12.0); 0336 0337 // Is currently the zoom factor set to fit to window? Then set it again to fit the new size. 0338 0339 if (!d->zoomSettings()->imageSize().isNull() && d->isFitToWindow) 0340 { 0341 fitToWindow(); 0342 } 0343 0344 updateLayout(); 0345 } 0346 0347 } // namespace Digikam 0348 0349 #include "moc_previewlayout.cpp"