File indexing completed on 2024-05-12 16:02:13

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2007 C. Boemann <cbo@boemann.dk>
0003  * SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org>
0004  * SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net>
0005  * SPDX-FileCopyrightText: 2010 Boudewijn Rempt <boud@valdyas.org>
0006  * SPDX-FileCopyrightText: 2011 Arjen Hiemstra <ahiemstra@heimr.nl>
0007  *
0008  * SPDX-License-Identifier: LGPL-2.0-or-later
0009  */
0010 #include <KoZoomController.h>
0011 #include <KoZoomController_p.h>
0012 
0013 #include <kactioncollection.h>
0014 #include <klocalizedstring.h>
0015 #include <WidgetsDebug.h>
0016 
0017 #include <KoZoomHandler.h>
0018 #include <KoCanvasBase.h>
0019 #include <KoCanvasController.h>
0020 
0021 #include <QtMath>
0022 
0023 void KoZoomController::Private::init(KoCanvasController *co,
0024                                      KoZoomHandler *zh,
0025                                      KisKActionCollection *actionCollection)
0026 {
0027     canvasController = co;
0028     fitMargin = co->margin();
0029     zoomHandler = zh;
0030     connect(action, SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)),
0031             parent, SLOT(setZoom(KoZoomMode::Mode,qreal)));
0032     connect(action, SIGNAL(canvasMappingModeChanged(bool)),
0033             parent, SIGNAL(canvasMappingModeChanged(bool)));
0034     connect(action, SIGNAL(zoomedToSelection()),
0035             parent, SIGNAL(zoomedToSelection()));
0036     connect(action, SIGNAL(zoomedToAll()),
0037             parent, SIGNAL(zoomedToAll()));
0038 
0039     actionCollection->addAction("view_zoom", action);
0040 
0041     connect(canvasController->proxyObject, SIGNAL(sizeChanged(QSize)), parent, SLOT(setAvailableSize()) );
0042 
0043     connect(canvasController->proxyObject, SIGNAL(zoomRelative(qreal,QPointF)), parent, SLOT(requestZoomRelative(qreal,QPointF)) );
0044 }
0045 
0046 KoZoomController::KoZoomController(KoCanvasController *co, KoZoomHandler *zh, KisKActionCollection *actionCollection, QObject *parent)
0047     : QObject(parent),
0048       d(new Private(this))
0049 {
0050     d->init(co, zh, actionCollection);
0051 }
0052 
0053 KoZoomController::~KoZoomController()
0054 {
0055     delete d;
0056 }
0057 
0058 KoZoomAction *KoZoomController::zoomAction() const
0059 {
0060     return d->action;
0061 }
0062 
0063 void KoZoomController::setZoomMode(KoZoomMode::Mode mode)
0064 {
0065     setZoom(mode, 1.0);
0066 }
0067 
0068 KoZoomMode::Mode KoZoomController::zoomMode() const
0069 {
0070     return d->zoomHandler->zoomMode();
0071 }
0072 
0073 void KoZoomController::setPageSize(const QSizeF &pageSize)
0074 {
0075     if(d->pageSize == pageSize) return;
0076     d->pageSize = pageSize;
0077 
0078     if(d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_WIDTH)
0079         setZoom(KoZoomMode::ZOOM_WIDTH, 0);
0080     if(d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_PAGE)
0081         setZoom(KoZoomMode::ZOOM_PAGE, 0);
0082     if(d->zoomHandler->zoomMode() == KoZoomMode::ZOOM_HEIGHT)
0083         setZoom(KoZoomMode::ZOOM_HEIGHT, 0);
0084 }
0085 
0086 QSizeF KoZoomController::pageSize() const
0087 {
0088     return d->pageSize;
0089 }
0090 
0091 void KoZoomController::setDocumentSize(const QSizeF &documentSize, bool recalculateCenter)
0092 {
0093     d->documentSize = documentSize;
0094     d->canvasController->updateDocumentSize(documentToViewport(d->documentSize), recalculateCenter);
0095 
0096     // Finally ask the canvasController to recenter
0097     d->canvasController->recenterPreferred();
0098 }
0099 
0100 QSizeF KoZoomController::documentSize() const
0101 {
0102     return d->documentSize;
0103 }
0104 
0105 void KoZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom)
0106 {
0107     setZoom(mode, zoom, d->canvasController->preferredCenter());
0108 }
0109 
0110 void KoZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom, const QPointF &stillPoint)
0111 {
0112     setZoom(mode, zoom, d->zoomHandler->resolutionX(), d->zoomHandler->resolutionY(), stillPoint);
0113 }
0114 
0115 void KoZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY)
0116 {
0117     setZoom(mode, zoom, resolutionX, resolutionY, d->canvasController->preferredCenter());
0118 }
0119 
0120 void KoZoomController::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY, const QPointF &stillPoint)
0121 {
0122     if (d->zoomHandler->zoomMode() == mode &&
0123             qFuzzyCompare(d->zoomHandler->zoom(), zoom) &&
0124             qFuzzyCompare(d->zoomHandler->resolutionX(), resolutionX) &&
0125             qFuzzyCompare(d->zoomHandler->resolutionY(), resolutionY)) {
0126         return; // no change
0127     }
0128 
0129     qreal oldEffectiveZoom = d->action->effectiveZoom();
0130     QSizeF oldPageViewportSize = documentToViewport(d->pageSize);
0131 
0132     if(!qFuzzyCompare(d->zoomHandler->resolutionX(), resolutionX) ||
0133             !qFuzzyCompare(d->zoomHandler->resolutionY(), resolutionY)) {
0134 
0135         d->zoomHandler->setResolution(resolutionX, resolutionY);
0136     }
0137 
0138     int cfgMargin = d->zoomHandler->zoomMarginSize();
0139     if(mode == KoZoomMode::ZOOM_CONSTANT) {
0140         if(zoom == 0.0) return;
0141         d->action->setZoom(zoom);
0142     }
0143     else if(mode == KoZoomMode::ZOOM_WIDTH) {
0144         zoom = (d->canvasController->viewportSize().width() - cfgMargin - 2 * d->fitMargin)
0145                 / (oldPageViewportSize.width() / d->zoomHandler->zoom());
0146         d->action->setSelectedZoomMode(mode);
0147         d->action->setEffectiveZoom(zoom);
0148     }
0149     else if(mode == KoZoomMode::ZOOM_PAGE) {
0150         zoom = (d->canvasController->viewportSize().width() - cfgMargin - 2 * d->fitMargin)
0151                 / (oldPageViewportSize.width() / d->zoomHandler->zoom());
0152         zoom = qMin(zoom, (d->canvasController->viewportSize().height() - cfgMargin - 2 * d->fitMargin)
0153                     / (oldPageViewportSize.height() / d->zoomHandler->zoom()));
0154 
0155         d->action->setSelectedZoomMode(mode);
0156         d->action->setEffectiveZoom(zoom);
0157     }
0158     else if(mode == KoZoomMode::ZOOM_HEIGHT) {
0159         zoom = (d->canvasController->viewportSize().height() - cfgMargin - 2 * d->fitMargin)
0160                 / (oldPageViewportSize.height() / d->zoomHandler->zoom());
0161 
0162         d->action->setSelectedZoomMode(mode);
0163         d->action->setEffectiveZoom(zoom);
0164     }
0165 
0166     d->zoomHandler->setZoomMode(mode);
0167     d->zoomHandler->setZoom(d->action->effectiveZoom());
0168 
0169 #ifdef DEBUG
0170     if(! d->documentSize.isValid())
0171         warnWidgets << "Setting zoom while there is no document size set, this will fail";
0172     else if (d->pageSize.width() > d->documentSize.width() || d->pageSize.height() > d->documentSize.height())
0173         warnWidgets << "ZoomController; Your page size is larger than your document size (" <<
0174                        d->pageSize << " > " << d->documentSize << ")\n";
0175 #endif
0176 
0177     QSizeF documentViewportSize = documentToViewport(d->documentSize);
0178 
0179     // Tell the canvasController that the zoom has changed
0180     // Actually canvasController doesn't know about zoom, but the document in pixels
0181     // has changed as a result of the zoom change
0182     // To allow listeners of offset changes to react on the real new offset and not on the
0183     // intermediate offsets, we block the signals here, and emit by ourselves later.
0184     d->canvasController->proxyObject->blockSignals(true);
0185     d->canvasController->updateDocumentSize(documentViewportSize, true);
0186     d->canvasController->proxyObject->blockSignals(false);
0187 
0188     // Finally ask the canvasController to recenter
0189     QPointF documentCenter;
0190     if (mode == KoZoomMode::ZOOM_WIDTH || mode == KoZoomMode::ZOOM_PAGE || mode == KoZoomMode::ZOOM_HEIGHT) {
0191         documentCenter = QRectF(QPointF(), documentViewportSize).center();
0192     }
0193     else {
0194         qreal zoomCoeff = d->action->effectiveZoom() / oldEffectiveZoom;
0195         QPointF oldCenter = d->canvasController->preferredCenter();
0196         documentCenter = stillPoint * zoomCoeff - (stillPoint - 1.0 / zoomCoeff * oldCenter);
0197     }
0198     d->canvasController->setPreferredCenter(documentCenter);
0199     emit zoomChanged(mode, d->action->effectiveZoom());
0200 }
0201 
0202 QSizeF KoZoomController::documentToViewport(const QSizeF &size)
0203 {
0204     return d->zoomHandler->documentToView(size).toSize();
0205 }
0206 
0207 QSize KoZoomController::documentToViewportCeil(const QSizeF &size)
0208 {
0209     QSizeF viewport = documentToViewport(size);
0210     return QSize(qCeil(viewport.width()), qCeil(viewport.height()));
0211 }
0212 
0213 void KoZoomController::setCanvasMappingMode(bool status)
0214 {
0215     if (d->action) {
0216         d->action->setCanvasMappingMode(status);
0217     }
0218 }
0219 
0220 void KoZoomController::setZoomMarginSize(int size)
0221 {
0222     d->zoomHandler->setZoomMarginSize(size);
0223 }
0224 
0225 //have to include this because of Q_PRIVATE_SLOT
0226 #include <moc_KoZoomController.cpp>