diff --git a/doc/index.docbook b/doc/index.docbook index 61ac18e4..4a0e7813 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -1,719 +1,720 @@ ]> Gwenview User Manual Aurélien Gâteau
agateau@kde.org
ChristopherMartin
chrsmrtn@debian.org
Henry de Valence
hdevalence@gmail.com
2005 Aurélien Gâteau 2008 Henry de Valence &FDLNotice; 2015-08-04 Applications 15.08 &gwenview; is an image and video viewer. KDE image viewer artist photo picture
Introduction What is &gwenview; &gwenview; is a fast and easy to use image and video viewer. &gwenview; features two main modes: Browse and View. Both modes can be used in a normal application window and Full Screen. Browse Mode lets you navigate through your computer showing thumbnails of your images, View Mode lets you view images one at a time, and Full Screen lets you make quick slideshows. There is also a start screen that displays a list of recently opened folders and &URL;s as well as your places and tags. Image loading is handled by the &Qt; library, so &gwenview; supports all image formats your &Qt; installation supports. &gwenview; correctly displays images with an alpha channel (transparency) as well as animations. &gwenview; supports the displaying and editing of EXIF comments in JPEG images. Lossless JPEG transforms such as rotations and mirroring are also supported. &gwenview; can read embedded color profiles from PNG and JPEG files. It can use the image color profile together with the display color profile to output correct colors on the screen. The Interface Start Page The start page lists recently opened folders and &URL;s on the left side, and your places and tags on the right side. Start Page Screenshot Image Operations &gwenview; has a few features which are available in both Browse, View, and Full Screen view. &gwenview; has the capability to do basic alteration of your images. Rotate: A rotate operation will rotate the image either to the left or to the right, depending on whether you do &Ctrl;R Edit Rotate Right or &Ctrl;L Edit Rotate Left Edit Mirror : This operation will reflect the image along the vertical axis, as if you were seeing it in a mirror. Edit Flip : This operation will reflect the image upside-down (a reflection along the horizontal axis) &Shift;R Edit Resize : This operation will allow you to shrink or expand the image. Note that if you increase the size of an image, it may appear blurry and/or pixelated. These actions are also available on the Operations tab of the sidebar. If you have edited one or more images a bar with additional actions is displayed at the top of the image. You can undo or redo your changes, go to the previous or next modified image and there are three options to save the changed images. Actions bar for modified images If you have installed the Kipi Plugins, a Plugins menu will be available that will allow you to perform many additional operations on your images. For more information, see the Kipi Plugins documentation. Browse Mode When in Browse Mode, you can easily navigate through your files and folders. The preview window shows thumbnails of the images in the current folder, as well as subfolders. Browse Mode Screenshot Moving the mouse over an image shows buttons to select or rotate the image as well as a button to enter Fullscreen Mode. Modified images are indicated by an icon down right, click it to save the changed image. Clicking on an image takes you into View Mode. You may select multiple images and switch to View Mode to view them side-by-side. The slider at the bottom right allows you to change the size of the images. You can also filter the images by filename, date, tag or rating using the box on the lower left. The toolbar appears in both Browse mode as well as View mode and contains the most commonly used actions. Start Page: Open the start page. Browse: Switches to Browse Mode. View: Switches to View Mode. Full Screen: Switches to Full Screen Mode. Previous: Clicking this icon will go to the previous image in the folder. Next: Clicking this button will go to the next image in the folder. Rotate Left/Right: Same as discussed in Image Operations View Mode View Mode displays full-size images. The same sidebar available in Browse Mode is displayed on the left. At the bottom, there is the Thumbnail Bar, which allows you to scroll through the images in the current folder. The Thumbnail Bar can be minimized by clicking on the Thumbnail Bar button. Clicking again will restore it. To change the size of the thumbnails move the splitter with the &LMB;. View Mode supports viewing multiple images side-by-side. You may select multiple images in Browse Mode before switching to View Mode, or you may click the + button that appears when hovering over images in the Thumbnail Bar to add a pane displaying that image. A - will then appear that will permit you to remove its pane. When multiple images are displayed, a small toolbar appears below each image that permits you to delete the image or remove its pane. You may perform zoom operations independently for each image, or synchronize them. Toggle this by checking the Synchronize to the left of the zoom slider or by pressing &Ctrl;Y. You can switch images by clicking on their pane, or using your keyboard. To switch to the image on the right, press . To switch to the image on the left, press &Shift; . View Mode Screenshot The slider at the bottom right controls the zoom of the image. The -Fit button and the 100% -button are next to the zoom slider and are two preset zoom levels. The +Fit, Fill and 100% +buttons are next to the zoom slider and are three preset zoom levels. The Fit button zooms the current image to fit the size -of the window, and the 100% button zooms the image to -the actual pixel size. The shortcut F toggles between both view modes. +of the window, the Fill button zooms the image to fill the window +by fitting width or height and the 100% button zooms the image to +the actual pixel size. The shortcut F switches to fit mode. When an image is in zoom-to-fit mode, you can go to the previous and next image with the arrow keys. When you zoom in, arrow keys are used to scroll the image. This is very similar to the behavior provided by phones or digital cameras. When an image is zoomed in, a bird-eye view appears and lets you scroll the image using the mouse and the arrow keys. The bird-eye view automatically hides itself after a short delay, showing back only while zooming or scrolling. You can define what happens when going to image B after having zoomed in on an area of image A using the options in the Zoom mode group on the Image View page of the &gwenview; configuration window which can be reached using the SettingsConfigure &gwenview;.... If set to Autofit each image, image B is zoomed out to fit the screen. If set to Keep same zoom and position, all images share the same zoom and position: image B is set to the same zoom parameters as image A (and if these are changed, image A will then be displayed with the updated zoom and position). If set to Per image zoom and position, all images remember their own zoom and position: image B is initially set to the same zoom parameters as image A, but will then remember its own zoom and position (if these are changed, image A will not be displayed with the updated zoom and position). You can start directly in View mode by starting &gwenview; from a context menu like Open With in another program or by launching it from the command line with an image as an argument. The following additional image operations are available only in View Mode: &Shift;C Edit Crop : This operation lets you discard parts of the image you don't want. You can access the advanced cropping parameters by ticking Advanced settings check box on the bottom popup pane. Use the corresponding fields to tune up the cropping operation. It is also possible to adjust the cropped area by dragging the gray square handles on the borders of the image. You can move the cropped area by clicking and holding the &LMB; and drag it with the mouse pointer. Press the Crop button to see the results when you are ready. Use the upper popup pane to save the results or undo/redo the operation. Edit Red Eye Reduction : This operation reduces the "red eye" effect commonly found in photographs taken with a flash camera. Full Screen Modes Access Full Screen by pressing the Full Screen button on the toolbar, or by &Ctrl;&Shift;F View Full Screen Mode . To leave this mode press the &Esc; key. Browse Mode Full Screen In Browse Mode you can switch to fullscreen also by clicking on the button that appears when you move the mouse over the thumbnails. Full Screen View Mode Screenshot Going fullscreen while browsing gives you a more immersive experience while you go through your pictures. It is quite nice on your regular computer, but makes even more sense when you connect your laptop to the big TV in the living room to show pictures to your guests. View Mode Full Screen The full screen View Mode shows a slideshow of your images. Access Full Screen Mode by clicking on the button that appears when you move the mouse over the thumbnails in Browse Mode, by pressing the Full Screen button on the taskbar. Full Screen Browse Mode Screenshot The top bar will hide itself automatically; to show it simply move the mouse to the top of the screen. If the mouse cursor is over the top bar, it will not autohide. Most of the buttons on the bar are the same as the ones on the toolbar in Browse or View Modes, except for the Exit Full Screen Mode button which returns you to the &gwenview; window, the Start/Stop Slideshow button, and the Configure Full Screen Mode button which shows a small settings dialog that allows you to easily and quickly configure the slideshow. The slideshow controls there are: The Interval slider controls how long &gwenview; will show an image before it move to the next one. If the Loop check box is checked, when the end of the slideshow is reached, it will continue from the beginning instead of stopping. If the Random check box is checked, instead of progressing through the folder alphabetically, images will be shown in random order. Select Image Information to Display allows you to define what metadata is displayed under the buttons on the toolbar. If the Show thumbnails check box is checked, thumbnails for all images in the current folder will be displayed to the right of the toolbar. The Height slider changes the size of the thumbnails displayed. If enabled, an area that shows you the other images in the current folder will be shown on the top bar. Clicking on one will display it. Sidebar The sidebar on the left is available in the Browse and View modes, but does not appear by default in Browse Mode. Its appearance can be toggled using F4 View Sidebar or using the ▮← / ▮→ button at the left side of the statusbar. When clicked it collapses or expands the sidebar. The sidebar contains several tabs: Folders Displays a list of all folders on your system permitting you to switch between them. In Browse Mode thumbnails from the folder will be displayed, while in View Mode the first image in the folder will appear, from which you can browse through the folder using the Previous and Next buttons or shortcuts. Clicking on a folder multiple times toggles between View Mode and Browse Mode. Information Displays Meta Information like the filename and size. The More... link permits you to view all available metadata and select which data appear in the sidebar. Operations This permits you to perform the previously described global image operations as well as those specific to View Mode. It also permits common file operations like copying, renaming, deleting, and creating new folders. Tips Using the mouse Panning with the mouse Holding down the left mouse button on an image allows you to scroll the image. The mouse wheel will scroll the image up and down. Zooming with the mouse Clicking the middle mouse button will toggle the auto zoom on/off. Hold down the &Ctrl; key, then either use the mouse wheel to zoom in and out or left click to zoom in and right click to zoom out. The mouse wheel, used while holding down the &Alt; key, will scroll the image horizontally. Browsing with the mouse When in Browse mode, clicking an image switches into View mode and shows that image. When in Browse mode, scrolling the mouse wheel will scroll up or down the thumbnail view area. If the Mouse wheel behavior option in SettingsConfigure &gwenview; is set to Browse, scrolling the mouse wheel while in View Mode will move you through the images in the folder. Key bindings &gwenview; comes with a range of keyboard shortcuts, all of which can be viewed and remapped by selecting SettingsConfigure Shortcuts.... Note that in the Files and Folders windows, all the normal KDE shortcuts are functional, unless otherwise remapped. A few of the most useful default bindings are: Space: Displays the next image in the directory. &Backspace;: Displays the previous image in the directory. &Alt;Up: Moves to the parent folder of the current folder. &Ctrl;&Shift;F: Switches into Full Screen Mode. &Esc;: Switches back to Browse Mode. &Ctrl;M: Show or hide the menubar. &Ctrl;B: Show or hide the Thumbnail bar. F4: Show or hide the Sidebar. F6: Make the Location bar editable so that you can directly type in a file path. You can return to the standard Location Bar by pressing the arrow at the right. &Ctrl;R: Rotate the current image to the right. &Ctrl;L: Rotate the current image to the left. &Shift;R: Resize the current image. &Shift;C: Crop the current image. &Ctrl;Y: When multiple images are displayed in View Mode, this synchronizes their views. &Ctrl;S: Save any changes made to the image. Del: Move the current image to the trash. &Shift;Del: Permanently delete the image from the disk. Note that this operation is irreversible and cannot be undone. &Ctrl;P: Print the current image. &Ctrl;O: Open an image using the standard file selection dialog. F: Pressing this shortcut toggles zoom-to-fit on and off. P: Viewing a video this shortcut toggles playback on and off. &Ctrl;T: Edit tags. F2: Rename an image inline. Del: Move an image to the trash. &Shift;Del: Delete an image. &Ctrl;F7: Copy an image. &Ctrl;F8: Move an image. &Ctrl;F9: Link an image. Advanced Configuration Options Some notes on hidden &gwenview; options can be found on this page. The options described on the above-mentioned page may help you tune &gwenview; for specific needs, but please keep in mind there is no warranty they will continue working from one version to another. Credits and Copyright &gwenview; is currently maintained by Aurélien Gâteau This document was written by Christopher Martin This document was updated for &kde; 4 by Henry de Valence &underFDL; &underGPL;
diff --git a/lib/documentview/abstractdocumentviewadapter.h b/lib/documentview/abstractdocumentviewadapter.h index 13bc74ea..75c79093 100644 --- a/lib/documentview/abstractdocumentviewadapter.h +++ b/lib/documentview/abstractdocumentviewadapter.h @@ -1,203 +1,203 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef ABSTRACTDOCUMENTVIEWADAPTER_H #define ABSTRACTDOCUMENTVIEWADAPTER_H #include // Qt #include #include // KDE // Local #include class QCursor; class QGraphicsWidget; class QRectF; namespace Gwenview { class ImageView; class RasterImageView; /** * Classes inherit from this class so that they can be used inside the * DocumentPanel. */ class GWENVIEWLIB_EXPORT AbstractDocumentViewAdapter : public QObject { Q_OBJECT public: AbstractDocumentViewAdapter(); virtual ~AbstractDocumentViewAdapter(); QGraphicsWidget* widget() const { return mWidget; } virtual MimeTypeUtils::Kind kind() const = 0; virtual ImageView* imageView() const { return 0; } virtual RasterImageView* rasterImageView() const { return 0; } virtual QCursor cursor() const; virtual void setCursor(const QCursor&); /** * @defgroup zooming functions * @{ */ virtual bool canZoom() const { return false; } // Implementation must emit zoomToFitChanged() virtual void setZoomToFit(bool) {} virtual bool zoomToFit() const { return false; } - // Implementation must emit zoomToFitWidthChanged() - virtual void setZoomToFitWidth(bool) + // Implementation must emit zoomToFillChanged() + virtual void setZoomToFill(bool) {} - virtual bool zoomToFitWidth() const + virtual bool zoomToFill() const { return false; } virtual qreal zoom() const { return 0; } virtual void setZoom(qreal /*zoom*/, const QPointF& /*center*/ = QPointF(-1, -1)) {} virtual qreal computeZoomToFit() const { return 1.; } - virtual qreal computeZoomToFitWidth() const + virtual qreal computeZoomToFill() const { return 1.; } /** @} */ virtual Document::Ptr document() const = 0; virtual void setDocument(Document::Ptr) = 0; virtual void loadConfig() {} virtual QPointF scrollPos() const { return QPointF(0, 0); } virtual void setScrollPos(const QPointF& /*pos*/) {} /** * Rectangle within the item which is actually used to show the document. * In item coordinates. */ virtual QRectF visibleDocumentRect() const; protected: void setWidget(QGraphicsWidget* widget) { mWidget = widget; } Q_SIGNALS: /** * @addgroup zooming functions * @{ */ void zoomChanged(qreal); void zoomToFitChanged(bool); - void zoomToFitWidthChanged(bool); + void zoomToFillChanged(bool); void zoomInRequested(const QPointF&); void zoomOutRequested(const QPointF&); /** @} */ void scrollPosChanged(); /** * Emitted when the adapter is done showing the document for the first time */ void completed(); void previousImageRequested(); void nextImageRequested(); void toggleFullScreenRequested(); private: QGraphicsWidget* mWidget; }; /** * An empty adapter, used when no document is displayed */ class EmptyAdapter : public AbstractDocumentViewAdapter { Q_OBJECT public: EmptyAdapter(); virtual MimeTypeUtils::Kind kind() const Q_DECL_OVERRIDE { return MimeTypeUtils::KIND_UNKNOWN; } virtual Document::Ptr document() const Q_DECL_OVERRIDE { return Document::Ptr(); } virtual void setDocument(Document::Ptr) Q_DECL_OVERRIDE {} }; } // namespace #endif /* ABSTRACTDOCUMENTVIEWADAPTER_H */ diff --git a/lib/documentview/abstractimageview.cpp b/lib/documentview/abstractimageview.cpp index 7a2501fa..370c7d40 100644 --- a/lib/documentview/abstractimageview.cpp +++ b/lib/documentview/abstractimageview.cpp @@ -1,573 +1,575 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "abstractimageview.h" // Local // KDE // Qt #include #include #include #include namespace Gwenview { static const int UNIT_STEP = 16; struct AbstractImageViewPrivate { enum Verbosity { Silent, Notify }; AbstractImageView* q; QCursor mZoomCursor; Document::Ptr mDocument; bool mControlKeyIsDown; bool mEnlargeSmallerImages; qreal mZoom; bool mZoomToFit; - bool mZoomToFitWidth; + bool mZoomToFill; QPointF mImageOffset; QPointF mScrollPos; QPointF mLastDragPos; void adjustImageOffset(Verbosity verbosity = Notify) { QSizeF zoomedDocSize = q->documentSize() * mZoom; QSizeF viewSize = q->boundingRect().size(); QPointF offset( qMax((viewSize.width() - zoomedDocSize.width()) / 2, qreal(0.)), qMax((viewSize.height() - zoomedDocSize.height()) / 2, qreal(0.)) ); if (offset != mImageOffset) { mImageOffset = offset; if (verbosity == Notify) { q->onImageOffsetChanged(); } } } void adjustScrollPos(Verbosity verbosity = Notify) { setScrollPos(mScrollPos, verbosity); } void setScrollPos(const QPointF& _newPos, Verbosity verbosity = Notify) { if (!mDocument) { mScrollPos = _newPos; return; } QSizeF zoomedDocSize = q->documentSize() * mZoom; QSizeF viewSize = q->boundingRect().size(); QPointF newPos( qBound(qreal(0.), _newPos.x(), zoomedDocSize.width() - viewSize.width()), qBound(qreal(0.), _newPos.y(), zoomedDocSize.height() - viewSize.height()) ); if (newPos != mScrollPos) { QPointF oldPos = mScrollPos; mScrollPos = newPos; if (verbosity == Notify) { q->onScrollPosChanged(oldPos); } // No verbosity test: we always notify the outside world about // scrollPos changes QMetaObject::invokeMethod(q, "scrollPosChanged"); } } void setupZoomCursor() { // We do not use "appdata" here because that does not work when this // code is called from a KPart. const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("gwenview/cursors/zoom.png")); QPixmap cursorPixmap = QPixmap(path); mZoomCursor = QCursor(cursorPixmap, 11, 11); } }; AbstractImageView::AbstractImageView(QGraphicsItem* parent) : QGraphicsWidget(parent) , d(new AbstractImageViewPrivate) { d->q = this; d->mControlKeyIsDown = false; d->mEnlargeSmallerImages = false; d->mZoom = 1; d->mZoomToFit = true; - d->mZoomToFitWidth = false; + d->mZoomToFill = false; d->mImageOffset = QPointF(0, 0); d->mScrollPos = QPointF(0, 0); setFocusPolicy(Qt::WheelFocus); setFlag(ItemIsSelectable); setAcceptHoverEvents(true); d->setupZoomCursor(); updateCursor(); } AbstractImageView::~AbstractImageView() { if (d->mDocument) { d->mDocument->stopAnimation(); } delete d; } Document::Ptr AbstractImageView::document() const { return d->mDocument; } void AbstractImageView::setDocument(Document::Ptr doc) { if (d->mDocument) { disconnect(d->mDocument.data(), 0, this, 0); } d->mDocument = doc; loadFromDocument(); } QSizeF AbstractImageView::documentSize() const { return d->mDocument ? d->mDocument->size() : QSizeF(); } qreal AbstractImageView::zoom() const { return d->mZoom; } void AbstractImageView::setZoom(qreal zoom, const QPointF& _center, AbstractImageView::UpdateType updateType) { if (!d->mDocument) { d->mZoom = zoom; return; } if (updateType == UpdateIfNecessary && qFuzzyCompare(zoom, d->mZoom)) { return; } qreal oldZoom = d->mZoom; d->mZoom = zoom; QPointF center; if (_center == QPointF(-1, -1)) { center = boundingRect().center(); } else { center = _center; } /* We want to keep the point at viewport coordinates "center" at the same position after zooming. The coordinates of this point in image coordinates can be expressed like this: oldScroll + center imagePointAtOldZoom = ------------------ oldZoom scroll + center imagePointAtZoom = --------------- zoom So we want: imagePointAtOldZoom = imagePointAtZoom oldScroll + center scroll + center <=> ------------------ = --------------- oldZoom zoom zoom <=> scroll = ------- (oldScroll + center) - center oldZoom */ /* Compute oldScroll It's useless to take the new offset in consideration because if a direction of the new offset is not 0, we won't be able to center on a specific point in that direction. */ QPointF oldScroll = scrollPos() - imageOffset(); QPointF scroll = (zoom / oldZoom) * (oldScroll + center) - center; d->adjustImageOffset(AbstractImageViewPrivate::Silent); d->setScrollPos(scroll, AbstractImageViewPrivate::Silent); onZoomChanged(); zoomChanged(d->mZoom); } bool AbstractImageView::zoomToFit() const { return d->mZoomToFit; } -bool AbstractImageView::zoomToFitWidth() const +bool AbstractImageView::zoomToFill() const { - return d->mZoomToFitWidth; + return d->mZoomToFill; } void AbstractImageView::setZoomToFit(bool on) { d->mZoomToFit = on; if (on) { setZoom(computeZoomToFit()); } // We do not set zoom to 1 if zoomToFit is off, this is up to the code // calling us. It may went to zoom to some other level and/or to zoom on // a particular position zoomToFitChanged(d->mZoomToFit); } -void AbstractImageView::setZoomToFitWidth(bool on) +void AbstractImageView::setZoomToFill(bool on) { - d->mZoomToFitWidth = on; + d->mZoomToFill = on; if (on) { - setZoom(computeZoomToFitWidth()); + setZoom(computeZoomToFill()); } // We do not set zoom to 1 if zoomToFit is off, this is up to the code // calling us. It may went to zoom to some other level and/or to zoom on // a particular position - zoomToFitWidthChanged(d->mZoomToFitWidth); + zoomToFillChanged(d->mZoomToFill); } void AbstractImageView::resizeEvent(QGraphicsSceneResizeEvent* event) { QGraphicsWidget::resizeEvent(event); if (d->mZoomToFit) { // setZoom() calls adjustImageOffset(), but only if the zoom changes. // If the view is resized but does not cause a zoom change, we call // adjustImageOffset() ourself. const qreal newZoom = computeZoomToFit(); if (qFuzzyCompare(zoom(), newZoom)) { d->adjustImageOffset(AbstractImageViewPrivate::Notify); } else { setZoom(newZoom); } - } else if (d->mZoomToFitWidth) { - const qreal newZoom = computeZoomToFitWidth(); + } else if (d->mZoomToFill) { + const qreal newZoom = computeZoomToFill(); if (qFuzzyCompare(zoom(), newZoom)) { d->adjustImageOffset(AbstractImageViewPrivate::Notify); } else { setZoom(newZoom); } } else { d->adjustImageOffset(); d->adjustScrollPos(); } } qreal AbstractImageView::computeZoomToFit() const { QSizeF docSize = documentSize(); if (docSize.isEmpty()) { return 1; } QSizeF viewSize = boundingRect().size(); qreal fitWidth = viewSize.width() / docSize.width(); qreal fitHeight = viewSize.height() / docSize.height(); qreal fit = qMin(fitWidth, fitHeight); if (!d->mEnlargeSmallerImages) { fit = qMin(fit, qreal(1.)); } return fit; } -qreal AbstractImageView::computeZoomToFitWidth() const +qreal AbstractImageView::computeZoomToFill() const { QSizeF docSize = documentSize(); if (docSize.isEmpty()) { return 1; } QSizeF viewSize = boundingRect().size(); qreal fitWidth = viewSize.width() / docSize.width(); + qreal fitHeight = viewSize.height() / docSize.height(); + qreal fill = qMax(fitWidth, fitHeight); if (!d->mEnlargeSmallerImages) { - fitWidth = qMin(fitWidth, qreal(1.)); + fill = qMin(fill, qreal(1.)); } - return fitWidth; + return fill; } void AbstractImageView::mousePressEvent(QGraphicsSceneMouseEvent* event) { QGraphicsItem::mousePressEvent(event); if (event->button() == Qt::MiddleButton) { bool value = !zoomToFit(); setZoomToFit(value); if (!value) { setZoom(1.); } return; } if (event->modifiers() & Qt::ControlModifier) { if (event->button() == Qt::LeftButton) { zoomInRequested(event->pos()); return; } else if (event->button() == Qt::RightButton) { zoomOutRequested(event->pos()); return; } } d->mLastDragPos = event->pos(); updateCursor(); } void AbstractImageView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { QGraphicsItem::mouseMoveEvent(event); QPointF mousePos = event->pos(); QPointF newScrollPos = d->mScrollPos + d->mLastDragPos - mousePos; #if 0 // commented out due to mouse pointer warping around, bug in Qt? // Wrap mouse pos qreal maxWidth = boundingRect().width(); qreal maxHeight = boundingRect().height(); // We need a margin because if the window is maximized, the mouse may not // be able to go past the bounding rect. // The mouse get placed 1 pixel before/after the margin to avoid getting // considered as needing to wrap the other way in next mouseMoveEvent // (because we don't check the move vector) const int margin = 5; if (mousePos.x() <= margin) { mousePos.setX(maxWidth - margin - 1); } else if (mousePos.x() >= maxWidth - margin) { mousePos.setX(margin + 1); } if (mousePos.y() <= margin) { mousePos.setY(maxHeight - margin - 1); } else if (mousePos.y() >= maxHeight - margin) { mousePos.setY(margin + 1); } // Set mouse pos (Hackish translation to screen coords!) QPointF screenDelta = event->screenPos() - event->pos(); QCursor::setPos((mousePos + screenDelta).toPoint()); #endif d->mLastDragPos = mousePos; d->setScrollPos(newScrollPos); } void AbstractImageView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { QGraphicsItem::mouseReleaseEvent(event); if (!d->mLastDragPos.isNull()) { d->mLastDragPos = QPointF(); } updateCursor(); } void AbstractImageView::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Control) { d->mControlKeyIsDown = true; updateCursor(); return; } if (zoomToFit() || qFuzzyCompare(computeZoomToFit(), zoom())) { if (event->modifiers() != Qt::NoModifier) { return; } switch (event->key()) { case Qt::Key_Left: case Qt::Key_Up: previousImageRequested(); break; case Qt::Key_Right: case Qt::Key_Down: nextImageRequested(); break; default: break; } return; } QPointF delta(0, 0); qreal pageStep = boundingRect().height(); qreal unitStep; if (event->modifiers() & Qt::ShiftModifier) { unitStep = pageStep / 2; } else { unitStep = UNIT_STEP; } switch (event->key()) { case Qt::Key_Left: delta.setX(-unitStep); break; case Qt::Key_Right: delta.setX(unitStep); break; case Qt::Key_Up: delta.setY(-unitStep); break; case Qt::Key_Down: delta.setY(unitStep); break; case Qt::Key_PageUp: delta.setY(-pageStep); break; case Qt::Key_PageDown: delta.setY(pageStep); break; case Qt::Key_Home: d->setScrollPos(QPointF(d->mScrollPos.x(), 0)); return; case Qt::Key_End: d->setScrollPos(QPointF(d->mScrollPos.x(), documentSize().height() * zoom())); return; default: return; } d->setScrollPos(d->mScrollPos + delta); } void AbstractImageView::keyReleaseEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Control) { d->mControlKeyIsDown = false; updateCursor(); } } void AbstractImageView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { if (event->modifiers() == Qt::NoModifier) { toggleFullScreenRequested(); } } QPointF AbstractImageView::imageOffset() const { return d->mImageOffset; } QPointF AbstractImageView::scrollPos() const { return d->mScrollPos; } void AbstractImageView::setScrollPos(const QPointF& pos) { d->setScrollPos(pos); } QPointF AbstractImageView::mapToView(const QPointF& imagePos) const { return imagePos * d->mZoom + d->mImageOffset - d->mScrollPos; } QPoint AbstractImageView::mapToView(const QPoint& imagePos) const { return mapToView(QPointF(imagePos)).toPoint(); } QRectF AbstractImageView::mapToView(const QRectF& imageRect) const { return QRectF( mapToView(imageRect.topLeft()), imageRect.size() * zoom() ); } QRect AbstractImageView::mapToView(const QRect& imageRect) const { return QRect( mapToView(imageRect.topLeft()), imageRect.size() * zoom() ); } QPointF AbstractImageView::mapToImage(const QPointF& viewPos) const { return (viewPos - d->mImageOffset + d->mScrollPos) / d->mZoom; } QPoint AbstractImageView::mapToImage(const QPoint& viewPos) const { return mapToImage(QPointF(viewPos)).toPoint(); } QRectF AbstractImageView::mapToImage(const QRectF& viewRect) const { return QRectF( mapToImage(viewRect.topLeft()), viewRect.size() / zoom() ); } QRect AbstractImageView::mapToImage(const QRect& viewRect) const { return QRect( mapToImage(viewRect.topLeft()), viewRect.size() / zoom() ); } void AbstractImageView::setEnlargeSmallerImages(bool value) { d->mEnlargeSmallerImages = value; if (zoomToFit()) { setZoom(computeZoomToFit()); } } void AbstractImageView::updateCursor() { if (d->mControlKeyIsDown) { setCursor(d->mZoomCursor); } else { if (d->mLastDragPos.isNull()) { setCursor(Qt::OpenHandCursor); } else { setCursor(Qt::ClosedHandCursor); } } } QSizeF AbstractImageView::visibleImageSize() const { if (!document()) { return QSizeF(); } QSizeF size = documentSize() * zoom(); return size.boundedTo(boundingRect().size()); } void AbstractImageView::applyPendingScrollPos() { d->adjustImageOffset(); d->adjustScrollPos(); } } // namespace diff --git a/lib/documentview/abstractimageview.h b/lib/documentview/abstractimageview.h index a84433f1..e1c0e0b2 100644 --- a/lib/documentview/abstractimageview.h +++ b/lib/documentview/abstractimageview.h @@ -1,147 +1,147 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef ABSTRACTIMAGEVIEW_H #define ABSTRACTIMAGEVIEW_H // Local #include // KDE // Qt #include namespace Gwenview { struct AbstractImageViewPrivate; /** * */ class AbstractImageView : public QGraphicsWidget { Q_OBJECT public: enum UpdateType { UpdateIfNecessary, ForceUpdate }; AbstractImageView(QGraphicsItem* parent); ~AbstractImageView(); qreal zoom() const; virtual void setZoom(qreal zoom, const QPointF& center = QPointF(-1, -1), UpdateType updateType = UpdateIfNecessary); bool zoomToFit() const; - bool zoomToFitWidth() const; + bool zoomToFill() const; virtual void setZoomToFit(bool value); - virtual void setZoomToFitWidth(bool value); + virtual void setZoomToFill(bool value); virtual void setDocument(Document::Ptr doc); Document::Ptr document() const; qreal computeZoomToFit() const; - qreal computeZoomToFitWidth() const; + qreal computeZoomToFill() const; QSizeF documentSize() const; QSizeF visibleImageSize() const; /** * If the image is smaller than the view, imageOffset is the distance from * the topleft corner of the view to the topleft corner of the image. * Neither x nor y can be negative. */ QPointF imageOffset() const; /** * The scroll position, in zoomed image coordinates. * x and y are always between 0 and (docsize * zoom - viewsize) */ QPointF scrollPos() const; void setScrollPos(const QPointF& pos); QPointF mapToView(const QPointF& imagePos) const; QPoint mapToView(const QPoint& imagePos) const; QRectF mapToView(const QRectF& imageRect) const; QRect mapToView(const QRect& imageRect) const; QPointF mapToImage(const QPointF& viewPos) const; QPoint mapToImage(const QPoint& viewPos) const; QRectF mapToImage(const QRectF& viewRect) const; QRect mapToImage(const QRect& viewRect) const; void setEnlargeSmallerImages(bool value); void applyPendingScrollPos(); public Q_SLOTS: void updateCursor(); Q_SIGNALS: void zoomToFitChanged(bool); - void zoomToFitWidthChanged(bool); + void zoomToFillChanged(bool); void zoomChanged(qreal); void zoomInRequested(const QPointF&); void zoomOutRequested(const QPointF&); void scrollPosChanged(); void completed(); void previousImageRequested(); void nextImageRequested(); void toggleFullScreenRequested(); protected: virtual void loadFromDocument() = 0; virtual void onZoomChanged() = 0; /** * Called when the offset changes. * Note: to avoid multiple adjustments, this is not called if zoom changes! */ virtual void onImageOffsetChanged() = 0; /** * Called when the scrollPos changes. * Note: to avoid multiple adjustments, this is not called if zoom changes! */ virtual void onScrollPosChanged(const QPointF& oldPos) = 0; void resizeEvent(QGraphicsSceneResizeEvent* event) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE; void keyReleaseEvent(QKeyEvent* event) Q_DECL_OVERRIDE; void mousePressEvent(QGraphicsSceneMouseEvent* event) Q_DECL_OVERRIDE; void mouseMoveEvent(QGraphicsSceneMouseEvent* event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) Q_DECL_OVERRIDE; void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) Q_DECL_OVERRIDE; private: friend struct AbstractImageViewPrivate; AbstractImageViewPrivate* const d; }; } // namespace #endif /* ABSTRACTIMAGEVIEW_H */ diff --git a/lib/documentview/documentview.cpp b/lib/documentview/documentview.cpp index 29c6367b..b321cd29 100644 --- a/lib/documentview/documentview.cpp +++ b/lib/documentview/documentview.cpp @@ -1,817 +1,812 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "documentview.h" // C++ Standard library #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include // KDE #include // Local #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Gwenview { #undef ENABLE_LOG #undef LOG //#define ENABLE_LOG #ifdef ENABLE_LOG #define LOG(x) //qDebug() << x #else #define LOG(x) ; #endif static const qreal REAL_DELTA = 0.001; static const qreal MAXIMUM_ZOOM_VALUE = qreal(DocumentView::MaximumZoom); static const auto MINSTEP = sqrt(0.5); static const auto MAXSTEP = sqrt(2.0); static const int COMPARE_MARGIN = 4; const int DocumentView::MaximumZoom = 16; const int DocumentView::AnimDuration = 250; struct DocumentViewPrivate { DocumentView* q; int mSortKey; // Used to sort views when displayed in compare mode HudWidget* mHud; BirdEyeView* mBirdEyeView; QPointer mMoveAnimation; QPointer mFadeAnimation; LoadingIndicator* mLoadingIndicator; QScopedPointer mAdapter; QList mZoomSnapValues; Document::Ptr mDocument; DocumentView::Setup mSetup; bool mCurrent; bool mCompareMode; bool mEraseBorders; int controlWheelAccumulatedDelta; void setCurrentAdapter(AbstractDocumentViewAdapter* adapter) { Q_ASSERT(adapter); mAdapter.reset(adapter); adapter->widget()->setParentItem(q); resizeAdapterWidget(); if (adapter->canZoom()) { QObject::connect(adapter, SIGNAL(zoomChanged(qreal)), q, SLOT(slotZoomChanged(qreal))); QObject::connect(adapter, SIGNAL(zoomInRequested(QPointF)), q, SLOT(zoomIn(QPointF))); QObject::connect(adapter, SIGNAL(zoomOutRequested(QPointF)), q, SLOT(zoomOut(QPointF))); QObject::connect(adapter, SIGNAL(zoomToFitChanged(bool)), q, SIGNAL(zoomToFitChanged(bool))); - QObject::connect(adapter, SIGNAL(zoomToFitWidthChanged(bool)), - q, SIGNAL(zoomToFitWidthChanged(bool))); + QObject::connect(adapter, SIGNAL(zoomToFillChanged(bool)), + q, SIGNAL(zoomToFillChanged(bool))); } QObject::connect(adapter, SIGNAL(scrollPosChanged()), q, SIGNAL(positionChanged())); QObject::connect(adapter, SIGNAL(previousImageRequested()), q, SIGNAL(previousImageRequested())); QObject::connect(adapter, SIGNAL(nextImageRequested()), q, SIGNAL(nextImageRequested())); QObject::connect(adapter, SIGNAL(toggleFullScreenRequested()), q, SIGNAL(toggleFullScreenRequested())); QObject::connect(adapter, SIGNAL(completed()), q, SLOT(slotCompleted())); adapter->loadConfig(); adapter->widget()->installSceneEventFilter(q); if (mCurrent) { adapter->widget()->setFocus(); } if (mSetup.valid && adapter->canZoom()) { adapter->setZoomToFit(mSetup.zoomToFit); - adapter->setZoomToFitWidth(mSetup.zoomToFitWidth); - if (!mSetup.zoomToFit && !mSetup.zoomToFitWidth) { + adapter->setZoomToFill(mSetup.zoomToFill); + if (!mSetup.zoomToFit && !mSetup.zoomToFill) { adapter->setZoom(mSetup.zoom); adapter->setScrollPos(mSetup.position); } } q->adapterChanged(); q->positionChanged(); if (adapter->canZoom()) { if (adapter->zoomToFit()) { q->zoomToFitChanged(true); - } else if (adapter->zoomToFitWidth()) { - q->zoomToFitWidthChanged(true); + } else if (adapter->zoomToFill()) { + q->zoomToFillChanged(true); } else { q->zoomChanged(adapter->zoom()); } } if (adapter->rasterImageView()) { QObject::connect(adapter->rasterImageView(), SIGNAL(currentToolChanged(AbstractRasterImageViewTool*)), q, SIGNAL(currentToolChanged(AbstractRasterImageViewTool*))); } } void setupLoadingIndicator() { mLoadingIndicator = new LoadingIndicator(q); GraphicsWidgetFloater* floater = new GraphicsWidgetFloater(q); floater->setChildWidget(mLoadingIndicator); } HudButton* createHudButton(const QString& text, const char* iconName, bool showText) { HudButton* button = new HudButton; if (showText) { button->setText(text); } else { button->setToolTip(text); } button->setIcon(QIcon::fromTheme(iconName)); return button; } void setupHud() { HudButton* trashButton = createHudButton(i18nc("@info:tooltip", "Trash"), "user-trash", false); HudButton* deselectButton = createHudButton(i18nc("@action:button", "Deselect"), "list-remove", true); QGraphicsWidget* content = new QGraphicsWidget; QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(content); layout->addItem(trashButton); layout->addItem(deselectButton); mHud = new HudWidget(q); mHud->init(content, HudWidget::OptionNone); GraphicsWidgetFloater* floater = new GraphicsWidgetFloater(q); floater->setChildWidget(mHud); floater->setAlignment(Qt::AlignBottom | Qt::AlignHCenter); QObject::connect(trashButton, SIGNAL(clicked()), q, SLOT(emitHudTrashClicked())); QObject::connect(deselectButton, SIGNAL(clicked()), q, SLOT(emitHudDeselectClicked())); mHud->hide(); } void setupBirdEyeView() { if (mBirdEyeView) { delete mBirdEyeView; } mBirdEyeView = new BirdEyeView(q); mBirdEyeView->setZValue(1); } void updateCaption() { QString caption; Document::Ptr doc = mAdapter->document(); if (!doc) { emit q->captionUpdateRequested(caption); return; } caption = doc->url().fileName(); QSize size = doc->size(); if (size.isValid()) { caption += QString(" - %1x%2") .arg(size.width()) .arg(size.height()); if (mAdapter->canZoom()) { int intZoom = qRound(mAdapter->zoom() * 100); caption += QString(" - %1%") .arg(intZoom); } } emit q->captionUpdateRequested(caption); } void uncheckZoomToFit() { if (mAdapter->zoomToFit()) { mAdapter->setZoomToFit(false); } } - void uncheckZoomToFitWidth() + void uncheckZoomToFill() { - if (mAdapter->zoomToFitWidth()) { - mAdapter->setZoomToFitWidth(false); + if (mAdapter->zoomToFill()) { + mAdapter->setZoomToFill(false); } } void setZoom(qreal zoom, const QPointF& center = QPointF(-1, -1)) { uncheckZoomToFit(); - uncheckZoomToFitWidth(); + uncheckZoomToFill(); zoom = qBound(q->minimumZoom(), zoom, MAXIMUM_ZOOM_VALUE); mAdapter->setZoom(zoom, center); } void updateZoomSnapValues() { qreal min = q->minimumZoom(); mZoomSnapValues.clear(); for (qreal zoom = MINSTEP; zoom > min; zoom *= MINSTEP) { mZoomSnapValues << zoom; } mZoomSnapValues << min; std::reverse(mZoomSnapValues.begin(), mZoomSnapValues.end()); for (qreal zoom = 1; zoom < MAXIMUM_ZOOM_VALUE; zoom *= MAXSTEP) { mZoomSnapValues << zoom; } mZoomSnapValues << MAXIMUM_ZOOM_VALUE; q->minimumZoomChanged(min); } void showLoadingIndicator() { if (!mLoadingIndicator) { setupLoadingIndicator(); } mLoadingIndicator->show(); mLoadingIndicator->setZValue(1); } void hideLoadingIndicator() { if (!mLoadingIndicator) { return; } mLoadingIndicator->hide(); } void resizeAdapterWidget() { QRectF rect = QRectF(QPointF(0, 0), q->boundingRect().size()); if (mCompareMode) { rect.adjust(COMPARE_MARGIN, COMPARE_MARGIN, -COMPARE_MARGIN, -COMPARE_MARGIN); } mAdapter->widget()->setGeometry(rect); } void fadeTo(qreal value) { if (mFadeAnimation.data()) { qreal endValue = mFadeAnimation.data()->endValue().toReal(); if (qFuzzyCompare(value, endValue)) { // Same end value, don't change the actual animation return; } } // Create a new fade animation QPropertyAnimation* anim = new QPropertyAnimation(q, "opacity"); anim->setStartValue(q->opacity()); anim->setEndValue(value); if (qFuzzyCompare(value, 1)) { QObject::connect(anim, SIGNAL(finished()), q, SLOT(slotFadeInFinished())); } QObject::connect(anim, SIGNAL(finished()), q, SIGNAL(isAnimatedChanged())); anim->setDuration(DocumentView::AnimDuration); mFadeAnimation = anim; q->isAnimatedChanged(); anim->start(QAbstractAnimation::DeleteWhenStopped); } }; DocumentView::DocumentView(QGraphicsScene* scene) : d(new DocumentViewPrivate) { setFlag(ItemIsFocusable); setFlag(ItemIsSelectable); setFlag(ItemClipsChildrenToShape); d->q = this; d->mLoadingIndicator = 0; d->mBirdEyeView = 0; d->mCurrent = false; d->mCompareMode = false; d->mEraseBorders = false; d->controlWheelAccumulatedDelta = 0; setOpacity(0); scene->addItem(this); d->setupHud(); d->setCurrentAdapter(new EmptyAdapter); } DocumentView::~DocumentView() { delete d; } void DocumentView::createAdapterForDocument() { const MimeTypeUtils::Kind documentKind = d->mDocument->kind(); if (d->mAdapter && documentKind == d->mAdapter->kind() && documentKind != MimeTypeUtils::KIND_UNKNOWN) { // Do not reuse for KIND_UNKNOWN: we may need to change the message LOG("Reusing current adapter"); return; } AbstractDocumentViewAdapter* adapter = 0; switch (documentKind) { case MimeTypeUtils::KIND_RASTER_IMAGE: adapter = new RasterImageViewAdapter; break; case MimeTypeUtils::KIND_SVG_IMAGE: adapter = new SvgViewAdapter; break; case MimeTypeUtils::KIND_VIDEO: adapter = new VideoViewAdapter; connect(adapter, SIGNAL(videoFinished()), SIGNAL(videoFinished())); break; case MimeTypeUtils::KIND_UNKNOWN: adapter = new MessageViewAdapter; static_cast(adapter)->setErrorMessage(i18n("Gwenview does not know how to display this kind of document")); break; default: qWarning() << "should not be called for documentKind=" << documentKind; adapter = new MessageViewAdapter; break; } d->setCurrentAdapter(adapter); } void DocumentView::openUrl(const QUrl &url, const DocumentView::Setup& setup) { if (d->mDocument) { if (url == d->mDocument->url()) { return; } disconnect(d->mDocument.data(), 0, this, 0); } d->mSetup = setup; d->mDocument = DocumentFactory::instance()->load(url); connect(d->mDocument.data(), SIGNAL(busyChanged(QUrl,bool)), SLOT(slotBusyChanged(QUrl,bool))); if (d->mDocument->loadingState() < Document::KindDetermined) { MessageViewAdapter* messageViewAdapter = qobject_cast(d->mAdapter.data()); if (messageViewAdapter) { messageViewAdapter->setInfoMessage(QString()); } d->showLoadingIndicator(); connect(d->mDocument.data(), SIGNAL(kindDetermined(QUrl)), SLOT(finishOpenUrl())); } else { QMetaObject::invokeMethod(this, "finishOpenUrl", Qt::QueuedConnection); } d->setupBirdEyeView(); } void DocumentView::finishOpenUrl() { disconnect(d->mDocument.data(), SIGNAL(kindDetermined(QUrl)), this, SLOT(finishOpenUrl())); GV_RETURN_IF_FAIL(d->mDocument->loadingState() >= Document::KindDetermined); if (d->mDocument->loadingState() == Document::LoadingFailed) { slotLoadingFailed(); return; } createAdapterForDocument(); connect(d->mDocument.data(), SIGNAL(loadingFailed(QUrl)), SLOT(slotLoadingFailed())); d->mAdapter->setDocument(d->mDocument); d->updateCaption(); } void DocumentView::loadAdapterConfig() { d->mAdapter->loadConfig(); } RasterImageView* DocumentView::imageView() const { return d->mAdapter->rasterImageView(); } void DocumentView::slotCompleted() { d->hideLoadingIndicator(); d->updateCaption(); d->updateZoomSnapValues(); - if (!d->mAdapter->zoomToFit()) { - qreal min = minimumZoom(); - if (d->mAdapter->zoom() < min) { - d->mAdapter->setZoom(min); - } - } else if (!d->mAdapter->zoomToFitWidth()) { + if (!d->mAdapter->zoomToFit() || !d->mAdapter->zoomToFill()) { qreal min = minimumZoom(); if (d->mAdapter->zoom() < min) { d->mAdapter->setZoom(min); } } emit completed(); } DocumentView::Setup DocumentView::setup() const { Setup setup; if (d->mAdapter->canZoom()) { setup.valid = true; setup.zoomToFit = zoomToFit(); - setup.zoomToFitWidth = zoomToFitWidth(); - if (!setup.zoomToFit && !setup.zoomToFitWidth) { + setup.zoomToFill = zoomToFill(); + if (!setup.zoomToFit && !setup.zoomToFill) { setup.zoom = zoom(); setup.position = position(); } } return setup; } void DocumentView::slotLoadingFailed() { d->hideLoadingIndicator(); MessageViewAdapter* adapter = new MessageViewAdapter; adapter->setDocument(d->mDocument); QString message = xi18n("Loading %1 failed", d->mDocument->url().fileName()); adapter->setErrorMessage(message, d->mDocument->errorString()); d->setCurrentAdapter(adapter); emit completed(); } bool DocumentView::canZoom() const { return d->mAdapter->canZoom(); } void DocumentView::setZoomToFit(bool on) { if (on == d->mAdapter->zoomToFit()) { return; } d->mAdapter->setZoomToFit(on); } -void DocumentView::setZoomToFitWidth(bool on) +void DocumentView::setZoomToFill(bool on) { - if (on == d->mAdapter->zoomToFitWidth()) { + if (on == d->mAdapter->zoomToFill()) { return; } - d->mAdapter->setZoomToFitWidth(on); + d->mAdapter->setZoomToFill(on); } bool DocumentView::zoomToFit() const { return d->mAdapter->zoomToFit(); } -bool DocumentView::zoomToFitWidth() const +bool DocumentView::zoomToFill() const { - return d->mAdapter->zoomToFitWidth(); + return d->mAdapter->zoomToFill(); } void DocumentView::zoomActualSize() { d->uncheckZoomToFit(); - d->uncheckZoomToFitWidth(); + d->uncheckZoomToFill(); d->mAdapter->setZoom(1.); } void DocumentView::zoomIn(const QPointF& center) { qreal currentZoom = d->mAdapter->zoom(); Q_FOREACH(qreal zoom, d->mZoomSnapValues) { if (zoom > currentZoom + REAL_DELTA) { d->setZoom(zoom, center); return; } } } void DocumentView::zoomOut(const QPointF& center) { qreal currentZoom = d->mAdapter->zoom(); QListIterator it(d->mZoomSnapValues); it.toBack(); while (it.hasPrevious()) { qreal zoom = it.previous(); if (zoom < currentZoom - REAL_DELTA) { d->setZoom(zoom, center); return; } } } void DocumentView::slotZoomChanged(qreal zoom) { d->updateCaption(); zoomChanged(zoom); } void DocumentView::setZoom(qreal zoom) { d->setZoom(zoom); } qreal DocumentView::zoom() const { return d->mAdapter->zoom(); } void DocumentView::resizeEvent(QGraphicsSceneResizeEvent *event) { d->resizeAdapterWidget(); d->updateZoomSnapValues(); QGraphicsWidget::resizeEvent(event); } void DocumentView::wheelEvent(QGraphicsSceneWheelEvent* event) { if (d->mAdapter->canZoom() && event->modifiers() & Qt::ControlModifier) { d->controlWheelAccumulatedDelta += event->delta(); // Ctrl + wheel => zoom in or out if (d->controlWheelAccumulatedDelta >= QWheelEvent::DefaultDeltasPerStep) { zoomIn(event->pos()); d->controlWheelAccumulatedDelta = 0; } else if (d->controlWheelAccumulatedDelta <= -QWheelEvent::DefaultDeltasPerStep) { zoomOut(event->pos()); d->controlWheelAccumulatedDelta = 0; } return; } if (GwenviewConfig::mouseWheelBehavior() == MouseWheelBehavior::Browse && event->modifiers() == Qt::NoModifier) { // Browse with mouse wheel if (event->delta() > 0) { previousImageRequested(); } else { nextImageRequested(); } return; } // Scroll qreal dx = 0; // 16 = pixels for one line // 120: see QWheelEvent::delta() doc qreal dy = -qApp->wheelScrollLines() * 16 * event->delta() / 120; if (event->orientation() == Qt::Horizontal) { qSwap(dx, dy); } d->mAdapter->setScrollPos(d->mAdapter->scrollPos() + QPointF(dx, dy)); } void DocumentView::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { // Filter out context menu if Ctrl is down to avoid showing it when // zooming out with Ctrl + Right button if (event->modifiers() != Qt::ControlModifier) { contextMenuRequested(); } } void DocumentView::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) { QRectF visibleRect = mapRectFromItem(d->mAdapter->widget(), d->mAdapter->visibleDocumentRect()); if (d->mEraseBorders) { QRegion borders = QRegion(boundingRect().toRect()) - QRegion(visibleRect.toRect()); Q_FOREACH(const QRect& rect, borders.rects()) { painter->eraseRect(rect); } } if (d->mCompareMode && d->mCurrent) { painter->save(); painter->setBrush(Qt::NoBrush); painter->setPen(QPen(palette().highlight().color(), 2)); painter->setRenderHint(QPainter::Antialiasing); QRectF selectionRect = visibleRect.adjusted(-2, -2, 2, 2); painter->drawRoundedRect(selectionRect, 3, 3); painter->restore(); } } void DocumentView::slotBusyChanged(const QUrl&, bool busy) { if (busy) { d->showLoadingIndicator(); } else { d->hideLoadingIndicator(); } } qreal DocumentView::minimumZoom() const { // There is no point zooming out less than zoomToFit, but make sure it does // not get too small either return qBound(qreal(0.001), d->mAdapter->computeZoomToFit(), qreal(1.)); } void DocumentView::setCompareMode(bool compare) { d->mCompareMode = compare; if (compare) { d->mHud->show(); d->mHud->setZValue(1); } else { d->mHud->hide(); } } void DocumentView::setCurrent(bool value) { d->mCurrent = value; if (value) { d->mAdapter->widget()->setFocus(); } update(); } bool DocumentView::isCurrent() const { return d->mCurrent; } QPoint DocumentView::position() const { return d->mAdapter->scrollPos().toPoint(); } void DocumentView::setPosition(const QPoint& pos) { d->mAdapter->setScrollPos(pos); } Document::Ptr DocumentView::document() const { return d->mDocument; } QUrl DocumentView::url() const { Document::Ptr doc = d->mDocument; return doc ? doc->url() : QUrl(); } void DocumentView::emitHudDeselectClicked() { hudDeselectClicked(this); } void DocumentView::emitHudTrashClicked() { hudTrashClicked(this); } void DocumentView::emitFocused() { focused(this); } void DocumentView::setGeometry(const QRectF& rect) { QGraphicsWidget::setGeometry(rect); if (d->mBirdEyeView) { d->mBirdEyeView->slotZoomOrSizeChanged(); } } void DocumentView::moveTo(const QRect& rect) { if (d->mMoveAnimation) { d->mMoveAnimation.data()->setEndValue(rect); } else { setGeometry(rect); } } void DocumentView::moveToAnimated(const QRect& rect) { QPropertyAnimation* anim = new QPropertyAnimation(this, "geometry"); anim->setStartValue(geometry()); anim->setEndValue(rect); anim->setDuration(DocumentView::AnimDuration); connect(anim, SIGNAL(finished()), SIGNAL(isAnimatedChanged())); d->mMoveAnimation = anim; isAnimatedChanged(); anim->start(QAbstractAnimation::DeleteWhenStopped); } QPropertyAnimation* DocumentView::fadeIn() { d->fadeTo(1); return d->mFadeAnimation.data(); } void DocumentView::fadeOut() { d->fadeTo(0); } void DocumentView::slotFadeInFinished() { fadeInFinished(this); } bool DocumentView::isAnimated() const { return d->mMoveAnimation || d->mFadeAnimation; } bool DocumentView::sceneEventFilter(QGraphicsItem*, QEvent* event) { if (event->type() == QEvent::GraphicsSceneMousePress) { QMetaObject::invokeMethod(this, "emitFocused", Qt::QueuedConnection); } else if (event->type() == QEvent::GraphicsSceneHoverMove) { if (d->mBirdEyeView) { d->mBirdEyeView->onMouseMoved(); } } return false; } AbstractRasterImageViewTool* DocumentView::currentTool() const { return imageView() ? imageView()->currentTool() : 0; } int DocumentView::sortKey() const { return d->mSortKey; } void DocumentView::setSortKey(int sortKey) { d->mSortKey = sortKey; } void DocumentView::setEraseBorders(bool value) { d->mEraseBorders = value; } void DocumentView::hideAndDeleteLater() { hide(); deleteLater(); } } // namespace diff --git a/lib/documentview/documentview.h b/lib/documentview/documentview.h index c6bac4cb..c8d1e996 100644 --- a/lib/documentview/documentview.h +++ b/lib/documentview/documentview.h @@ -1,234 +1,234 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef DOCUMENTVIEW_H #define DOCUMENTVIEW_H #include // Qt #include // KDE // Local #include class QPropertyAnimation; class QUrl; namespace Gwenview { class AbstractRasterImageViewTool; class RasterImageView; struct DocumentViewPrivate; /** * This widget can display various documents, using an instance of * AbstractDocumentViewAdapter */ class GWENVIEWLIB_EXPORT DocumentView : public QGraphicsWidget { Q_OBJECT Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged) Q_PROPERTY(bool zoomToFit READ zoomToFit WRITE setZoomToFit NOTIFY zoomToFitChanged) - Q_PROPERTY(bool zoomToFitWidth READ zoomToFitWidth WRITE setZoomToFitWidth NOTIFY zoomToFitWidthChanged) + Q_PROPERTY(bool zoomToFill READ zoomToFill WRITE setZoomToFill NOTIFY zoomToFillChanged) Q_PROPERTY(QPoint position READ position WRITE setPosition NOTIFY positionChanged) public: static const int MaximumZoom; static const int AnimDuration; struct Setup { Setup() : valid(false) , zoomToFit(true) - , zoomToFitWidth(false) + , zoomToFill(false) , zoom(0) {} bool valid:1; bool zoomToFit:1; - bool zoomToFitWidth:1; + bool zoomToFill:1; qreal zoom; QPointF position; }; enum AnimationMethod { NoAnimation, SoftwareAnimation, GLAnimation }; /** * Create a new view attached to scene. We need the scene to be able to * install scene event filters. */ DocumentView(QGraphicsScene* scene); ~DocumentView(); Document::Ptr document() const; QUrl url() const; void openUrl(const QUrl&, const Setup&); Setup setup() const; /** * Tells the current adapter to load its config. Used when the user changed * the config while the view was visible. */ void loadAdapterConfig(); bool canZoom() const; qreal minimumZoom() const; qreal zoom() const; bool isCurrent() const; void setCurrent(bool); void setCompareMode(bool); bool zoomToFit() const; - bool zoomToFitWidth() const; + bool zoomToFill() const; QPoint position() const; /** * Returns the RasterImageView of the current adapter, if it has one */ RasterImageView* imageView() const; AbstractRasterImageViewTool* currentTool() const; void moveTo(const QRect&); void moveToAnimated(const QRect&); QPropertyAnimation* fadeIn(); void fadeOut(); void fakeFadeOut(); void setGeometry(const QRectF& rect) Q_DECL_OVERRIDE; int sortKey() const; void setSortKey(int sortKey); /** * If true, areas around the document will be painted with the default brush. * If false they will be kept transparent. */ void setEraseBorders(bool); bool isAnimated() const; public Q_SLOTS: void setZoom(qreal); void setZoomToFit(bool); - void setZoomToFitWidth(bool); + void setZoomToFill(bool); void setPosition(const QPoint&); void hideAndDeleteLater(); Q_SIGNALS: /** * Emitted when the part has finished loading */ void completed(); void previousImageRequested(); void nextImageRequested(); void captionUpdateRequested(const QString&); void toggleFullScreenRequested(); void videoFinished(); void minimumZoomChanged(qreal); void zoomChanged(qreal); void adapterChanged(); void focused(DocumentView*); void zoomToFitChanged(bool); - void zoomToFitWidthChanged(bool); + void zoomToFillChanged(bool); void positionChanged(); void hudTrashClicked(DocumentView*); void hudDeselectClicked(DocumentView*); void fadeInFinished(DocumentView*); void contextMenuRequested(); void currentToolChanged(AbstractRasterImageViewTool*); void isAnimatedChanged(); protected: void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0) Q_DECL_OVERRIDE; void resizeEvent(QGraphicsSceneResizeEvent* event) Q_DECL_OVERRIDE; void wheelEvent(QGraphicsSceneWheelEvent* event) Q_DECL_OVERRIDE; void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) Q_DECL_OVERRIDE; bool sceneEventFilter(QGraphicsItem*, QEvent*) Q_DECL_OVERRIDE; private Q_SLOTS: void finishOpenUrl(); void slotCompleted(); void slotLoadingFailed(); void zoomActualSize(); void zoomIn(const QPointF& center = QPointF(-1, -1)); void zoomOut(const QPointF& center = QPointF(-1, -1)); void slotZoomChanged(qreal); void slotBusyChanged(const QUrl&, bool); void emitHudTrashClicked(); void emitHudDeselectClicked(); void emitFocused(); void slotFadeInFinished(); private: friend struct DocumentViewPrivate; DocumentViewPrivate* const d; void createAdapterForDocument(); }; } // namespace #endif /* DOCUMENTVIEW_H */ diff --git a/lib/documentview/documentviewcontroller.cpp b/lib/documentview/documentviewcontroller.cpp index baf2d222..4f17041b 100644 --- a/lib/documentview/documentviewcontroller.cpp +++ b/lib/documentview/documentviewcontroller.cpp @@ -1,282 +1,282 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "documentviewcontroller.h" // Local #include "abstractdocumentviewadapter.h" #include "documentview.h" #include #include #include #include // KDE #include #include // Qt #include #include #include #include namespace Gwenview { /** * A simple container which: * - Horizontally center the tool widget * - Provide a darker background */ class ToolContainerContent : public QWidget { public: ToolContainerContent(QWidget* parent = 0) : QWidget(parent) , mLayout(new QHBoxLayout(this)) { mLayout->setMargin(0); setAutoFillBackground(true); setBackgroundRole(QPalette::Mid); } void setToolWidget(QWidget* widget) { mLayout->addWidget(widget, 0, Qt::AlignCenter); setFixedHeight(widget->sizeHint().height()); } private: QHBoxLayout* mLayout; }; struct DocumentViewControllerPrivate { DocumentViewController* q; KActionCollection* mActionCollection; DocumentView* mView; ZoomWidget* mZoomWidget; SlideContainer* mToolContainer; ToolContainerContent* mToolContainerContent; QAction * mZoomToFitAction; - QAction * mZoomToFitWidthAction; + QAction * mZoomToFillAction; QAction * mActualSizeAction; QAction * mZoomInAction; QAction * mZoomOutAction; QList mActions; void setupActions() { KActionCategory* view = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface", "View"), mActionCollection); mZoomToFitAction = view->addAction("view_zoom_to_fit"); view->collection()->setDefaultShortcut(mZoomToFitAction, Qt::Key_F); mZoomToFitAction->setCheckable(true); mZoomToFitAction->setChecked(true); - mZoomToFitAction->setText(i18n("Zoom to Fit")); + mZoomToFitAction->setText(i18n("Zoom to fit")); mZoomToFitAction->setIcon(QIcon::fromTheme("zoom-fit-best")); mZoomToFitAction->setIconText(i18nc("@action:button Zoom to fit, shown in status bar, keep it short please", "Fit")); - mZoomToFitWidthAction = view->addAction("view_zoom_to_fit_width"); - //view->collection()->setDefaultShortcuts(mZoomToFitWidthAction, Qt::Key_W); ?? - mZoomToFitWidthAction->setCheckable(true); - mZoomToFitWidthAction->setChecked(false); - mZoomToFitWidthAction->setText(i18n("Zoom to Fit Width")); - mZoomToFitWidthAction->setIcon(QIcon::fromTheme("zoom-fit-best")); - mZoomToFitWidthAction->setIconText(i18nc("@action:button Zoom to fit width, shown in status bar, keep it short please", "Fit Width")); + mZoomToFillAction = view->addAction("view_zoom_to_fill"); + //view->collection()->setDefaultShortcuts(mZoomToFillAction, Qt::Key_W); ?? + mZoomToFillAction->setCheckable(true); + mZoomToFillAction->setChecked(false); + mZoomToFillAction->setText(i18n("Zoom to fill window by fitting to width or height")); + mZoomToFillAction->setIcon(QIcon::fromTheme("zoom-fit-best")); + mZoomToFillAction->setIconText(i18nc("@action:button Zoom to fill (fit width or height), shown in status bar, keep it short please", "Fill")); mActualSizeAction = view->addAction(KStandardAction::ActualSize); mActualSizeAction->setCheckable(true); - mZoomToFitWidthAction->setChecked(false); + mZoomToFillAction->setChecked(false); mActualSizeAction->setIcon(QIcon::fromTheme("zoom-original")); mActualSizeAction->setIconText(i18nc("@action:button Zoom to original size, shown in status bar, keep it short please", "100%")); mZoomInAction = view->addAction(KStandardAction::ZoomIn); mZoomOutAction = view->addAction(KStandardAction::ZoomOut); - mActions << mZoomToFitAction << mActualSizeAction << mZoomInAction << mZoomOutAction << mZoomToFitWidthAction; + mActions << mZoomToFitAction << mActualSizeAction << mZoomInAction << mZoomOutAction << mZoomToFillAction; } void connectZoomWidget() { if (!mZoomWidget || !mView) { return; } QObject::connect(mZoomWidget, &ZoomWidget::zoomChanged, mView, &DocumentView::setZoom); QObject::connect(mView, &DocumentView::minimumZoomChanged, mZoomWidget, &ZoomWidget::setMinimumZoom); QObject::connect(mView, &DocumentView::zoomChanged, mZoomWidget, &ZoomWidget::setZoom); mZoomWidget->setMinimumZoom(mView->minimumZoom()); mZoomWidget->setZoom(mView->zoom()); } void updateZoomWidgetVisibility() { if (!mZoomWidget) { return; } mZoomWidget->setVisible(mView && mView->canZoom()); } void updateActions() { const bool enabled = mView && mView->isVisible() && mView->canZoom(); Q_FOREACH(QAction * action, mActions) { action->setEnabled(enabled); } } }; DocumentViewController::DocumentViewController(KActionCollection* actionCollection, QObject* parent) : QObject(parent) , d(new DocumentViewControllerPrivate) { d->q = this; d->mActionCollection = actionCollection; d->mView = 0; d->mZoomWidget = 0; d->mToolContainer = 0; d->mToolContainerContent = new ToolContainerContent; d->setupActions(); } DocumentViewController::~DocumentViewController() { delete d; } void DocumentViewController::setView(DocumentView* view) { // Forget old view if (d->mView) { disconnect(d->mView, 0, this, 0); Q_FOREACH(QAction * action, d->mActions) { disconnect(action, 0, d->mView, 0); } disconnect(d->mZoomWidget, 0, d->mView, 0); } // Connect new view d->mView = view; if (!d->mView) { return; } connect(d->mView, &DocumentView::adapterChanged, this, &DocumentViewController::slotAdapterChanged); connect(d->mView, &DocumentView::zoomToFitChanged, this, &DocumentViewController::updateZoomToFitActionFromView); - connect(d->mView, &DocumentView::zoomToFitWidthChanged, this, &DocumentViewController::updateZoomToFitWidthActionFromView); + connect(d->mView, &DocumentView::zoomToFillChanged, this, &DocumentViewController::updateZoomToFillActionFromView); connect(d->mView, &DocumentView::currentToolChanged, this, &DocumentViewController::updateTool); connect(d->mZoomToFitAction, SIGNAL(toggled(bool)), d->mView, SLOT(setZoomToFit(bool))); - connect(d->mZoomToFitWidthAction, SIGNAL(toggled(bool)), - d->mView, SLOT(setZoomToFitWidth(bool))); + connect(d->mZoomToFillAction, SIGNAL(toggled(bool)), + d->mView, SLOT(setZoomToFill(bool))); connect(d->mActualSizeAction, SIGNAL(triggered()), d->mView, SLOT(zoomActualSize())); connect(d->mZoomInAction, SIGNAL(triggered()), d->mView, SLOT(zoomIn())); connect(d->mZoomOutAction, SIGNAL(triggered()), d->mView, SLOT(zoomOut())); d->updateActions(); updateZoomToFitActionFromView(); - updateZoomToFitWidthActionFromView(); + updateZoomToFillActionFromView(); updateTool(); // Sync zoom widget d->connectZoomWidget(); d->updateZoomWidgetVisibility(); } DocumentView* DocumentViewController::view() const { return d->mView; } void DocumentViewController::setZoomWidget(ZoomWidget* widget) { d->mZoomWidget = widget; d->mZoomWidget->setActions( d->mZoomToFitAction, d->mActualSizeAction, d->mZoomInAction, d->mZoomOutAction, - d->mZoomToFitWidthAction + d->mZoomToFillAction ); d->mZoomWidget->setMaximumZoom(qreal(DocumentView::MaximumZoom)); d->connectZoomWidget(); d->updateZoomWidgetVisibility(); } ZoomWidget* DocumentViewController::zoomWidget() const { return d->mZoomWidget; } void DocumentViewController::slotAdapterChanged() { d->updateActions(); d->updateZoomWidgetVisibility(); } void DocumentViewController::updateZoomToFitActionFromView() { SignalBlocker blocker(d->mZoomToFitAction); d->mZoomToFitAction->setChecked(d->mView->zoomToFit()); } -void DocumentViewController::updateZoomToFitWidthActionFromView() +void DocumentViewController::updateZoomToFillActionFromView() { - SignalBlocker blocker(d->mZoomToFitWidthAction); - d->mZoomToFitWidthAction->setChecked(d->mView->zoomToFitWidth()); + SignalBlocker blocker(d->mZoomToFillAction); + d->mZoomToFillAction->setChecked(d->mView->zoomToFill()); } void DocumentViewController::updateTool() { if (!d->mToolContainer) { return; } AbstractRasterImageViewTool* tool = d->mView->currentTool(); if (tool && tool->widget()) { // Use a QueuedConnection to ensure the size of the view has been // updated by the time the slot is called. connect(d->mToolContainer, &SlideContainer::slidedIn, tool, &AbstractRasterImageViewTool::onWidgetSlidedIn, Qt::QueuedConnection); d->mToolContainerContent->setToolWidget(tool->widget()); d->mToolContainer->slideIn(); } else { d->mToolContainer->slideOut(); } } void DocumentViewController::setToolContainer(SlideContainer* container) { d->mToolContainer = container; container->setContent(d->mToolContainerContent); } } // namespace diff --git a/lib/documentview/documentviewcontroller.h b/lib/documentview/documentviewcontroller.h index c12f294d..2a9b4a9e 100644 --- a/lib/documentview/documentviewcontroller.h +++ b/lib/documentview/documentviewcontroller.h @@ -1,75 +1,75 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef DOCUMENTVIEWCONTROLLER_H #define DOCUMENTVIEWCONTROLLER_H #include // Local // KDE // Qt #include class KActionCollection; namespace Gwenview { class DocumentView; class SlideContainer; class ZoomWidget; struct DocumentViewControllerPrivate; /** * Handles all DocumentView specific actions like zooming. Calls the * corresponding code on its view, if any. */ class GWENVIEWLIB_EXPORT DocumentViewController : public QObject { Q_OBJECT public: explicit DocumentViewController(KActionCollection*, QObject* parent = 0); ~DocumentViewController(); DocumentView* view() const; ZoomWidget* zoomWidget() const; void setView(DocumentView*); void setZoomWidget(ZoomWidget* widget); void setToolContainer(SlideContainer* container); private Q_SLOTS: void slotAdapterChanged(); void updateZoomToFitActionFromView(); - void updateZoomToFitWidthActionFromView(); + void updateZoomToFillActionFromView(); void updateTool(); private: DocumentViewControllerPrivate* const d; }; } // namespace #endif /* DOCUMENTVIEWCONTROLLER_H */ diff --git a/lib/documentview/documentviewsynchronizer.cpp b/lib/documentview/documentviewsynchronizer.cpp index cea6391d..7f780e12 100644 --- a/lib/documentview/documentviewsynchronizer.cpp +++ b/lib/documentview/documentviewsynchronizer.cpp @@ -1,157 +1,157 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "documentviewsynchronizer.h" // Local #include // KDE // Qt #include namespace Gwenview { struct DocumentViewSynchronizerPrivate { DocumentViewSynchronizer* q; const QList* mViews; QPointer mCurrentView; bool mActive; QPoint mOldPosition; DocumentViewSynchronizerPrivate(const QList* views) : mViews(views) {} void updateConnections() { if (!mCurrentView || !mActive) { return; } QObject::connect(mCurrentView.data(), SIGNAL(zoomChanged(qreal)), q, SLOT(setZoom(qreal))); QObject::connect(mCurrentView.data(), SIGNAL(zoomToFitChanged(bool)), q, SLOT(setZoomToFit(bool))); - QObject::connect(mCurrentView.data(), SIGNAL(zoomToFitWidthChanged(bool)), - q, SLOT(setZoomToFitWidth(bool))); + QObject::connect(mCurrentView.data(), SIGNAL(zoomToFillChanged(bool)), + q, SLOT(setZoomToFill(bool))); QObject::connect(mCurrentView.data(), SIGNAL(positionChanged()), q, SLOT(updatePosition())); Q_FOREACH(DocumentView* view, *mViews) { if (view == mCurrentView.data()) { continue; } view->setZoom(mCurrentView.data()->zoom()); view->setZoomToFit(mCurrentView.data()->zoomToFit()); - view->setZoomToFitWidth(mCurrentView.data()->zoomToFitWidth()); + view->setZoomToFill(mCurrentView.data()->zoomToFill()); } } void updateOldPosition() { if (!mCurrentView || !mActive) { return; } mOldPosition = mCurrentView.data()->position(); } }; DocumentViewSynchronizer::DocumentViewSynchronizer(const QList* views, QObject* parent) : QObject(parent) , d(new DocumentViewSynchronizerPrivate(views)) { d->q = this; d->mActive = false; } DocumentViewSynchronizer::~DocumentViewSynchronizer() { delete d; } void DocumentViewSynchronizer::setCurrentView(DocumentView* view) { if (d->mCurrentView) { disconnect(d->mCurrentView.data(), 0, this, 0); } d->mCurrentView = view; d->updateOldPosition(); d->updateConnections(); } void DocumentViewSynchronizer::setActive(bool active) { d->mActive = active; d->updateOldPosition(); d->updateConnections(); } void DocumentViewSynchronizer::setZoom(qreal zoom) { Q_FOREACH(DocumentView* view, *d->mViews) { if (view == d->mCurrentView.data()) { continue; } view->setZoom(zoom); } d->updateOldPosition(); } void DocumentViewSynchronizer::setZoomToFit(bool fit) { Q_FOREACH(DocumentView* view, *d->mViews) { if (view == d->mCurrentView.data()) { continue; } view->setZoomToFit(fit); } d->updateOldPosition(); } -void DocumentViewSynchronizer::setZoomToFitWidth(bool fit) +void DocumentViewSynchronizer::setZoomToFill(bool fit) { Q_FOREACH(DocumentView* view, *d->mViews) { if (view == d->mCurrentView.data()) { continue; } - view->setZoomToFitWidth(fit); + view->setZoomToFill(fit); } d->updateOldPosition(); } void DocumentViewSynchronizer::updatePosition() { QPoint pos = d->mCurrentView.data()->position(); QPoint delta = pos - d->mOldPosition; d->mOldPosition = pos; Q_FOREACH(DocumentView* view, *d->mViews) { if (view == d->mCurrentView.data()) { continue; } view->setPosition(view->position() + delta); } } } // namespace diff --git a/lib/documentview/documentviewsynchronizer.h b/lib/documentview/documentviewsynchronizer.h index 291318f1..9eb92901 100644 --- a/lib/documentview/documentviewsynchronizer.h +++ b/lib/documentview/documentviewsynchronizer.h @@ -1,69 +1,69 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef DOCUMENTVIEWSYNCHRONIZER_H #define DOCUMENTVIEWSYNCHRONIZER_H #include // Local // KDE // Qt #include namespace Gwenview { class DocumentView; struct DocumentViewSynchronizerPrivate; /** * A class to synchronize zoom and scroll of DocumentViews */ class GWENVIEWLIB_EXPORT DocumentViewSynchronizer : public QObject { Q_OBJECT public: // We pass a pointer to the view list because we don't want to maintain // a copy of the list itself explicit DocumentViewSynchronizer(const QList* views, QObject* parent = 0); ~DocumentViewSynchronizer(); void setCurrentView(DocumentView* view); public Q_SLOTS: void setActive(bool); private Q_SLOTS: void setZoom(qreal zoom); void setZoomToFit(bool); - void setZoomToFitWidth(bool); + void setZoomToFill(bool); void updatePosition(); private: DocumentViewSynchronizerPrivate* const d; }; } // namespace #endif /* DOCUMENTVIEWSYNCHRONIZER_H */ diff --git a/lib/documentview/rasterimageview.cpp b/lib/documentview/rasterimageview.cpp index ec6efb42..d3f28e45 100644 --- a/lib/documentview/rasterimageview.cpp +++ b/lib/documentview/rasterimageview.cpp @@ -1,561 +1,561 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2011 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "rasterimageview.h" // Local #include #include #include #include // KDE // Qt #include #include #include #include #include namespace Gwenview { struct RasterImageViewPrivate { RasterImageView* q; ImageScaler* mScaler; QPixmap mBackgroundTexture; bool mEmittedCompleted; // Config RasterImageView::AlphaBackgroundMode mAlphaBackgroundMode; QColor mAlphaBackgroundColor; cmsUInt32Number mRenderingIntent; bool mEnlargeSmallerImages; // /Config bool mBufferIsEmpty; QPixmap mCurrentBuffer; // The alternate buffer is useful when scrolling: existing content is copied // to mAlternateBuffer and buffers are swapped. This avoids allocating a new // QPixmap every time the image is scrolled. QPixmap mAlternateBuffer; QTimer* mUpdateTimer; QPointer mTool; bool mApplyDisplayTransform; // Defaults to true. Can be set to false if there is no need or no way to apply color profile cmsHTRANSFORM mDisplayTransform; void updateDisplayTransform(QImage::Format format) { GV_RETURN_IF_FAIL(format != QImage::Format_Invalid); mApplyDisplayTransform = false; if (mDisplayTransform) { cmsDeleteTransform(mDisplayTransform); } mDisplayTransform = 0; Cms::Profile::Ptr profile = q->document()->cmsProfile(); if (!profile) { // The assumption that something unmarked is *probably* sRGB is better than failing to apply any transform when one // has a wide-gamut screen. profile = Cms::Profile::getSRgbProfile(); } Cms::Profile::Ptr monitorProfile = Cms::Profile::getMonitorProfile(); if (!monitorProfile) { qWarning() << "Could not get monitor color profile"; return; } cmsUInt32Number cmsFormat = 0; switch (format) { case QImage::Format_RGB32: case QImage::Format_ARGB32: cmsFormat = TYPE_BGRA_8; break; #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) case QImage::Format_Grayscale8: cmsFormat = TYPE_GRAY_8; break; #endif default: qWarning() << "Gwenview can only apply color profile on RGB32 or ARGB32 images"; return; } mDisplayTransform = cmsCreateTransform(profile->handle(), cmsFormat, monitorProfile->handle(), cmsFormat, mRenderingIntent, cmsFLAGS_BLACKPOINTCOMPENSATION); mApplyDisplayTransform = true; } void createBackgroundTexture() { mBackgroundTexture = QPixmap(32, 32); QPainter painter(&mBackgroundTexture); painter.fillRect(mBackgroundTexture.rect(), QColor(128, 128, 128)); QColor light = QColor(192, 192, 192); painter.fillRect(0, 0, 16, 16, light); painter.fillRect(16, 16, 16, 16, light); } void setupUpdateTimer() { mUpdateTimer = new QTimer(q); mUpdateTimer->setInterval(500); mUpdateTimer->setSingleShot(true); QObject::connect(mUpdateTimer, SIGNAL(timeout()), q, SLOT(updateBuffer())); } void startAnimationIfNecessary() { if (q->document() && q->isVisible()) { q->document()->startAnimation(); } } QRectF mapViewportToZoomedImage(const QRectF& viewportRect) const { return QRectF( viewportRect.topLeft() - q->imageOffset() + q->scrollPos(), viewportRect.size() ); } void setScalerRegionToVisibleRect() { QRectF rect = mapViewportToZoomedImage(q->boundingRect()); mScaler->setDestinationRegion(QRegion(rect.toRect())); } void resizeBuffer() { QSize size = q->visibleImageSize().toSize(); if (size == mCurrentBuffer.size()) { return; } if (!size.isValid()) { mAlternateBuffer = QPixmap(); mCurrentBuffer = QPixmap(); return; } mAlternateBuffer = QPixmap(size); mAlternateBuffer.fill(Qt::transparent); { QPainter painter(&mAlternateBuffer); painter.drawPixmap(0, 0, mCurrentBuffer); } qSwap(mAlternateBuffer, mCurrentBuffer); mAlternateBuffer = QPixmap(); } void drawAlphaBackground(QPainter* painter, const QRect& viewportRect, const QPoint& zoomedImageTopLeft) { if (mAlphaBackgroundMode == RasterImageView::AlphaBackgroundCheckBoard) { QPoint textureOffset( zoomedImageTopLeft.x() % mBackgroundTexture.width(), zoomedImageTopLeft.y() % mBackgroundTexture.height() ); painter->drawTiledPixmap( viewportRect, mBackgroundTexture, textureOffset); } else { painter->fillRect(viewportRect, mAlphaBackgroundColor); } } }; RasterImageView::RasterImageView(QGraphicsItem* parent) : AbstractImageView(parent) , d(new RasterImageViewPrivate) { d->q = this; d->mEmittedCompleted = false; d->mApplyDisplayTransform = true; d->mDisplayTransform = 0; d->mAlphaBackgroundMode = AlphaBackgroundCheckBoard; d->mAlphaBackgroundColor = Qt::black; d->mRenderingIntent = INTENT_PERCEPTUAL; d->mEnlargeSmallerImages = false; d->mBufferIsEmpty = true; d->mScaler = new ImageScaler(this); connect(d->mScaler, &ImageScaler::scaledRect, this, &RasterImageView::updateFromScaler); d->createBackgroundTexture(); d->setupUpdateTimer(); } RasterImageView::~RasterImageView() { if (d->mDisplayTransform) { cmsDeleteTransform(d->mDisplayTransform); } delete d; } void RasterImageView::setAlphaBackgroundMode(AlphaBackgroundMode mode) { d->mAlphaBackgroundMode = mode; if (document() && document()->hasAlphaChannel()) { d->mCurrentBuffer = QPixmap(); updateBuffer(); } } void RasterImageView::setAlphaBackgroundColor(const QColor& color) { d->mAlphaBackgroundColor = color; if (document() && document()->hasAlphaChannel()) { d->mCurrentBuffer = QPixmap(); updateBuffer(); } } void RasterImageView::setRenderingIntent(const RenderingIntent::Enum& renderingIntent) { if (d->mRenderingIntent != renderingIntent) { d->mRenderingIntent = renderingIntent; updateBuffer(); } } void RasterImageView::loadFromDocument() { Document::Ptr doc = document(); if (!doc) { return; } connect(doc.data(), SIGNAL(metaInfoLoaded(QUrl)), SLOT(slotDocumentMetaInfoLoaded())); connect(doc.data(), SIGNAL(isAnimatedUpdated()), SLOT(slotDocumentIsAnimatedUpdated())); const Document::LoadingState state = doc->loadingState(); if (state == Document::MetaInfoLoaded || state == Document::Loaded) { slotDocumentMetaInfoLoaded(); } } void RasterImageView::slotDocumentMetaInfoLoaded() { if (document()->size().isValid()) { QMetaObject::invokeMethod(this, "finishSetDocument", Qt::QueuedConnection); } else { // Could not retrieve image size from meta info, we need to load the // full image now. connect(document().data(), SIGNAL(loaded(QUrl)), SLOT(finishSetDocument())); document()->startLoadingFullImage(); } } void RasterImageView::finishSetDocument() { GV_RETURN_IF_FAIL(document()->size().isValid()); d->mScaler->setDocument(document()); d->resizeBuffer(); applyPendingScrollPos(); connect(document().data(), SIGNAL(imageRectUpdated(QRect)), SLOT(updateImageRect(QRect))); if (zoomToFit()) { // Force the update otherwise if computeZoomToFit() returns 1, setZoom() // will think zoom has not changed and won't update the image setZoom(computeZoomToFit(), QPointF(-1, -1), ForceUpdate); - } else if (zoomToFitWidth()) { - setZoom(computeZoomToFitWidth(), QPointF(-1, -1), ForceUpdate); + } else if (zoomToFill()) { + setZoom(computeZoomToFill(), QPointF(-1, -1), ForceUpdate); } else { updateBuffer(); } d->startAnimationIfNecessary(); update(); } void RasterImageView::updateImageRect(const QRect& imageRect) { QRectF viewRect = mapToView(imageRect); if (!viewRect.intersects(boundingRect())) { return; } if (zoomToFit()) { setZoom(computeZoomToFit()); - } else if (zoomToFitWidth()) { - setZoom(computeZoomToFitWidth()); + } else if (zoomToFill()) { + setZoom(computeZoomToFill()); } d->setScalerRegionToVisibleRect(); update(); } void RasterImageView::slotDocumentIsAnimatedUpdated() { d->startAnimationIfNecessary(); } void RasterImageView::updateFromScaler(int zoomedImageLeft, int zoomedImageTop, const QImage& image) { if (d->mApplyDisplayTransform) { d->updateDisplayTransform(image.format()); if (d->mDisplayTransform) { quint8 *bytes = const_cast(image.bits()); cmsDoTransform(d->mDisplayTransform, bytes, bytes, image.width() * image.height()); } } d->resizeBuffer(); int viewportLeft = zoomedImageLeft - scrollPos().x(); int viewportTop = zoomedImageTop - scrollPos().y(); d->mBufferIsEmpty = false; { QPainter painter(&d->mCurrentBuffer); if (document()->hasAlphaChannel()) { d->drawAlphaBackground( &painter, QRect(viewportLeft, viewportTop, image.width(), image.height()), QPoint(zoomedImageLeft, zoomedImageTop) ); } else { painter.setCompositionMode(QPainter::CompositionMode_Source); } painter.drawImage(viewportLeft, viewportTop, image); } update(); if (!d->mEmittedCompleted) { d->mEmittedCompleted = true; completed(); } } void RasterImageView::onZoomChanged() { // If we zoom more than twice, then assume the user wants to see the real // pixels, for example to fine tune a crop operation if (zoom() < 2.) { d->mScaler->setTransformationMode(Qt::SmoothTransformation); } else { d->mScaler->setTransformationMode(Qt::FastTransformation); } if (!d->mUpdateTimer->isActive()) { updateBuffer(); } } void RasterImageView::onImageOffsetChanged() { update(); } void RasterImageView::onScrollPosChanged(const QPointF& oldPos) { QPointF delta = scrollPos() - oldPos; // Scroll existing { if (d->mAlternateBuffer.size() != d->mCurrentBuffer.size()) { d->mAlternateBuffer = QPixmap(d->mCurrentBuffer.size()); } QPainter painter(&d->mAlternateBuffer); painter.drawPixmap(-delta, d->mCurrentBuffer); } qSwap(d->mCurrentBuffer, d->mAlternateBuffer); // Scale missing parts QRegion bufferRegion = QRegion(d->mCurrentBuffer.rect().translated(scrollPos().toPoint())); QRegion updateRegion = bufferRegion - bufferRegion.translated(-delta.toPoint()); updateBuffer(updateRegion); update(); } void RasterImageView::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) { QPointF topLeft = imageOffset(); if (zoomToFit()) { // In zoomToFit mode, scale crudely the buffer to fit the screen. This // provide an approximate rendered which will be replaced when the scheduled // proper scale is ready. QSizeF size = documentSize() * zoom(); painter->drawPixmap(topLeft.x(), topLeft.y(), size.width(), size.height(), d->mCurrentBuffer); } else { painter->drawPixmap(topLeft, d->mCurrentBuffer); } if (d->mTool) { d->mTool.data()->paint(painter); } // Debug #if 0 QSizeF visibleSize = documentSize() * zoom(); painter->setPen(Qt::red); painter->drawRect(topLeft.x(), topLeft.y(), visibleSize.width() - 1, visibleSize.height() - 1); painter->setPen(Qt::blue); painter->drawRect(topLeft.x(), topLeft.y(), d->mCurrentBuffer.width() - 1, d->mCurrentBuffer.height() - 1); #endif } void RasterImageView::resizeEvent(QGraphicsSceneResizeEvent* event) { // If we are in zoomToFit mode and have something in our buffer, delay the // update: paint() will paint a scaled version of the buffer until resizing // is done. This is much faster than rescaling the whole image for each // resize event we receive. // mUpdateTimer must be started before calling AbstractImageView::resizeEvent() // because AbstractImageView::resizeEvent() will call onZoomChanged(), which // will trigger an immediate update unless the mUpdateTimer is active. if (zoomToFit() && !d->mBufferIsEmpty) { d->mUpdateTimer->start(); - } else if (zoomToFitWidth() && !d->mBufferIsEmpty) { + } else if (zoomToFill() && !d->mBufferIsEmpty) { d->mUpdateTimer->start(); } AbstractImageView::resizeEvent(event); if (!zoomToFit()) { // Only update buffer if we are not in zoomToFit mode: if we are // onZoomChanged() will have already updated the buffer. updateBuffer(); - } else if (!zoomToFitWidth()) { + } else if (!zoomToFill()) { updateBuffer(); } } void RasterImageView::updateBuffer(const QRegion& region) { d->mUpdateTimer->stop(); d->mScaler->setZoom(zoom()); if (region.isEmpty()) { d->setScalerRegionToVisibleRect(); } else { d->mScaler->setDestinationRegion(region); } } void RasterImageView::setCurrentTool(AbstractRasterImageViewTool* tool) { if (d->mTool) { d->mTool.data()->toolDeactivated(); d->mTool.data()->deleteLater(); } d->mTool = tool; if (d->mTool) { d->mTool.data()->toolActivated(); } updateCursor(); currentToolChanged(tool); update(); } AbstractRasterImageViewTool* RasterImageView::currentTool() const { return d->mTool.data(); } void RasterImageView::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (d->mTool) { d->mTool.data()->mousePressEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::mousePressEvent(event); } void RasterImageView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { if (d->mTool) { d->mTool.data()->mouseMoveEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::mouseMoveEvent(event); } void RasterImageView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { if (d->mTool) { d->mTool.data()->mouseReleaseEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::mouseReleaseEvent(event); } void RasterImageView::wheelEvent(QGraphicsSceneWheelEvent* event) { if (d->mTool) { d->mTool.data()->wheelEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::wheelEvent(event); } void RasterImageView::keyPressEvent(QKeyEvent* event) { if (d->mTool) { d->mTool.data()->keyPressEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::keyPressEvent(event); } void RasterImageView::keyReleaseEvent(QKeyEvent* event) { if (d->mTool) { d->mTool.data()->keyReleaseEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::keyReleaseEvent(event); } void RasterImageView::hoverMoveEvent(QGraphicsSceneHoverEvent* event) { if (d->mTool) { d->mTool.data()->hoverMoveEvent(event); if (event->isAccepted()) { return; } } AbstractImageView::hoverMoveEvent(event); } } // namespace diff --git a/lib/documentview/rasterimageviewadapter.cpp b/lib/documentview/rasterimageviewadapter.cpp index d0e66cc7..d2154db9 100644 --- a/lib/documentview/rasterimageviewadapter.cpp +++ b/lib/documentview/rasterimageviewadapter.cpp @@ -1,166 +1,166 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "rasterimageviewadapter.h" // Local #include #include #include // KDE // Qt #include namespace Gwenview { //// RasterImageViewAdapter //// struct RasterImageViewAdapterPrivate { RasterImageViewAdapter* q; RasterImageView* mView; }; RasterImageViewAdapter::RasterImageViewAdapter() : d(new RasterImageViewAdapterPrivate) { d->q = this; d->mView = new RasterImageView; connect(d->mView, &RasterImageView::zoomChanged, this, &RasterImageViewAdapter::zoomChanged); connect(d->mView, &RasterImageView::zoomToFitChanged, this, &RasterImageViewAdapter::zoomToFitChanged); - connect(d->mView, &RasterImageView::zoomToFitWidthChanged, this, &RasterImageViewAdapter::zoomToFitWidthChanged); + connect(d->mView, &RasterImageView::zoomToFillChanged, this, &RasterImageViewAdapter::zoomToFillChanged); connect(d->mView, &RasterImageView::zoomInRequested, this, &RasterImageViewAdapter::zoomInRequested); connect(d->mView, &RasterImageView::zoomOutRequested, this, &RasterImageViewAdapter::zoomOutRequested); connect(d->mView, &RasterImageView::scrollPosChanged, this, &RasterImageViewAdapter::scrollPosChanged); connect(d->mView, &RasterImageView::completed, this, &RasterImageViewAdapter::completed); connect(d->mView, &RasterImageView::previousImageRequested, this, &RasterImageViewAdapter::previousImageRequested); connect(d->mView, &RasterImageView::nextImageRequested, this, &RasterImageViewAdapter::nextImageRequested); connect(d->mView, &RasterImageView::toggleFullScreenRequested, this, &RasterImageViewAdapter::toggleFullScreenRequested); setWidget(d->mView); } RasterImageViewAdapter::~RasterImageViewAdapter() { delete d; } QCursor RasterImageViewAdapter::cursor() const { return d->mView->cursor(); } void RasterImageViewAdapter::setCursor(const QCursor& cursor) { d->mView->setCursor(cursor); } void RasterImageViewAdapter::setDocument(Document::Ptr doc) { d->mView->setDocument(doc); connect(doc.data(), SIGNAL(loadingFailed(QUrl)), SLOT(slotLoadingFailed())); if (doc->loadingState() == Document::LoadingFailed) { slotLoadingFailed(); } } qreal RasterImageViewAdapter::zoom() const { return d->mView->zoom(); } void RasterImageViewAdapter::setZoomToFit(bool on) { d->mView->setZoomToFit(on); } -void RasterImageViewAdapter::setZoomToFitWidth(bool on) +void RasterImageViewAdapter::setZoomToFill(bool on) { - d->mView->setZoomToFitWidth(on); + d->mView->setZoomToFill(on); } bool RasterImageViewAdapter::zoomToFit() const { return d->mView->zoomToFit(); } -bool RasterImageViewAdapter::zoomToFitWidth() const +bool RasterImageViewAdapter::zoomToFill() const { - return d->mView->zoomToFitWidth(); + return d->mView->zoomToFill(); } void RasterImageViewAdapter::setZoom(qreal zoom, const QPointF& center) { d->mView->setZoom(zoom, center); } qreal RasterImageViewAdapter::computeZoomToFit() const { return d->mView->computeZoomToFit(); } -qreal RasterImageViewAdapter::computeZoomToFitWidth() const +qreal RasterImageViewAdapter::computeZoomToFill() const { - return d->mView->computeZoomToFitWidth(); + return d->mView->computeZoomToFill(); } Document::Ptr RasterImageViewAdapter::document() const { return d->mView->document(); } void RasterImageViewAdapter::slotLoadingFailed() { d->mView->setDocument(Document::Ptr()); } void RasterImageViewAdapter::loadConfig() { d->mView->setAlphaBackgroundMode(GwenviewConfig::alphaBackgroundMode()); d->mView->setAlphaBackgroundColor(GwenviewConfig::alphaBackgroundColor()); d->mView->setRenderingIntent(GwenviewConfig::renderingIntent()); d->mView->setEnlargeSmallerImages(GwenviewConfig::enlargeSmallerImages()); } RasterImageView* RasterImageViewAdapter::rasterImageView() const { return d->mView; } QPointF RasterImageViewAdapter::scrollPos() const { return d->mView->scrollPos(); } void RasterImageViewAdapter::setScrollPos(const QPointF& pos) { d->mView->setScrollPos(pos); } QRectF RasterImageViewAdapter::visibleDocumentRect() const { return QRectF(d->mView->imageOffset(), d->mView->visibleImageSize()); } } // namespace diff --git a/lib/documentview/rasterimageviewadapter.h b/lib/documentview/rasterimageviewadapter.h index 1c5a2714..36943a41 100644 --- a/lib/documentview/rasterimageviewadapter.h +++ b/lib/documentview/rasterimageviewadapter.h @@ -1,96 +1,96 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef RASTERIMAGEVIEWADAPTER_H #define RASTERIMAGEVIEWADAPTER_H #include // Qt // KDE // Local #include namespace Gwenview { struct RasterImageViewAdapterPrivate; class GWENVIEWLIB_EXPORT RasterImageViewAdapter : public AbstractDocumentViewAdapter { Q_OBJECT public: RasterImageViewAdapter(); ~RasterImageViewAdapter(); virtual QCursor cursor() const Q_DECL_OVERRIDE; virtual void setCursor(const QCursor&) Q_DECL_OVERRIDE; virtual MimeTypeUtils::Kind kind() const Q_DECL_OVERRIDE { return MimeTypeUtils::KIND_RASTER_IMAGE; } virtual bool canZoom() const Q_DECL_OVERRIDE { return true; } virtual void setZoomToFit(bool) Q_DECL_OVERRIDE; - virtual void setZoomToFitWidth(bool) Q_DECL_OVERRIDE; + virtual void setZoomToFill(bool) Q_DECL_OVERRIDE; virtual bool zoomToFit() const Q_DECL_OVERRIDE; - virtual bool zoomToFitWidth() const Q_DECL_OVERRIDE; + virtual bool zoomToFill() const Q_DECL_OVERRIDE; virtual qreal zoom() const Q_DECL_OVERRIDE; virtual void setZoom(qreal zoom, const QPointF& center) Q_DECL_OVERRIDE; virtual qreal computeZoomToFit() const Q_DECL_OVERRIDE; - virtual qreal computeZoomToFitWidth() const Q_DECL_OVERRIDE; + virtual qreal computeZoomToFill() const Q_DECL_OVERRIDE; virtual Document::Ptr document() const Q_DECL_OVERRIDE; virtual void setDocument(Document::Ptr) Q_DECL_OVERRIDE; virtual void loadConfig() Q_DECL_OVERRIDE; virtual RasterImageView* rasterImageView() const Q_DECL_OVERRIDE; virtual QPointF scrollPos() const Q_DECL_OVERRIDE; virtual void setScrollPos(const QPointF& pos) Q_DECL_OVERRIDE; virtual QRectF visibleDocumentRect() const Q_DECL_OVERRIDE; private Q_SLOTS: void slotLoadingFailed(); private: RasterImageViewAdapterPrivate* const d; }; } // namespace #endif /* RASTERIMAGEVIEWADAPTER_H */ diff --git a/lib/documentview/svgviewadapter.cpp b/lib/documentview/svgviewadapter.cpp index 73950849..e1315b25 100644 --- a/lib/documentview/svgviewadapter.cpp +++ b/lib/documentview/svgviewadapter.cpp @@ -1,197 +1,197 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "svgviewadapter.h" // Qt #include #include #include #include #include #include // KDE // Local #include "document/documentfactory.h" #include #include namespace Gwenview { /// SvgImageView //// SvgImageView::SvgImageView(QGraphicsItem* parent) : AbstractImageView(parent) , mSvgItem(new QGraphicsSvgItem(this)) { } void SvgImageView::loadFromDocument() { Document::Ptr doc = document(); GV_RETURN_IF_FAIL(doc); if (doc->loadingState() < Document::Loaded) { connect(doc.data(), SIGNAL(loaded(QUrl)), SLOT(finishLoadFromDocument())); } else { QMetaObject::invokeMethod(this, "finishLoadFromDocument", Qt::QueuedConnection); } } void SvgImageView::finishLoadFromDocument() { QSvgRenderer* renderer = document()->svgRenderer(); GV_RETURN_IF_FAIL(renderer); mSvgItem->setSharedRenderer(renderer); if (zoomToFit()) { setZoom(computeZoomToFit(), QPointF(-1, -1), ForceUpdate); - } else if (zoomToFitWidth()) { - setZoom(computeZoomToFitWidth(), QPointF(-1, -1), ForceUpdate); + } else if (zoomToFill()) { + setZoom(computeZoomToFill(), QPointF(-1, -1), ForceUpdate); } else { mSvgItem->setScale(zoom()); } applyPendingScrollPos(); completed(); } void SvgImageView::onZoomChanged() { mSvgItem->setScale(zoom()); adjustItemPos(); } void SvgImageView::onImageOffsetChanged() { adjustItemPos(); } void SvgImageView::onScrollPosChanged(const QPointF& /* oldPos */) { adjustItemPos(); } void SvgImageView::adjustItemPos() { mSvgItem->setPos(imageOffset() - scrollPos()); } //// SvgViewAdapter //// struct SvgViewAdapterPrivate { SvgImageView* mView; }; SvgViewAdapter::SvgViewAdapter() : d(new SvgViewAdapterPrivate) { d->mView = new SvgImageView; setWidget(d->mView); connect(d->mView, &SvgImageView::zoomChanged, this, &SvgViewAdapter::zoomChanged); connect(d->mView, &SvgImageView::zoomToFitChanged, this, &SvgViewAdapter::zoomToFitChanged); - connect(d->mView, &SvgImageView::zoomToFitWidthChanged, this, &SvgViewAdapter::zoomToFitWidthChanged); + connect(d->mView, &SvgImageView::zoomToFillChanged, this, &SvgViewAdapter::zoomToFillChanged); connect(d->mView, &SvgImageView::zoomInRequested, this, &SvgViewAdapter::zoomInRequested); connect(d->mView, &SvgImageView::zoomOutRequested, this, &SvgViewAdapter::zoomOutRequested); connect(d->mView, &SvgImageView::scrollPosChanged, this, &SvgViewAdapter::scrollPosChanged); connect(d->mView, &SvgImageView::completed, this, &SvgViewAdapter::completed); connect(d->mView, &SvgImageView::previousImageRequested, this, &SvgViewAdapter::previousImageRequested); connect(d->mView, &SvgImageView::nextImageRequested, this, &SvgViewAdapter::nextImageRequested); connect(d->mView, &SvgImageView::toggleFullScreenRequested, this, &SvgViewAdapter::toggleFullScreenRequested); } SvgViewAdapter::~SvgViewAdapter() { delete d; } QCursor SvgViewAdapter::cursor() const { return widget()->cursor(); } void SvgViewAdapter::setCursor(const QCursor& cursor) { widget()->setCursor(cursor); } void SvgViewAdapter::setDocument(Document::Ptr doc) { d->mView->setDocument(doc); } Document::Ptr SvgViewAdapter::document() const { return d->mView->document(); } void SvgViewAdapter::setZoomToFit(bool on) { d->mView->setZoomToFit(on); } -void SvgViewAdapter::setZoomToFitWidth(bool on) +void SvgViewAdapter::setZoomToFill(bool on) { - d->mView->setZoomToFitWidth(on); + d->mView->setZoomToFill(on); } bool SvgViewAdapter::zoomToFit() const { return d->mView->zoomToFit(); } -bool SvgViewAdapter::zoomToFitWidth() const +bool SvgViewAdapter::zoomToFill() const { - return d->mView->zoomToFitWidth(); + return d->mView->zoomToFill(); } qreal SvgViewAdapter::zoom() const { return d->mView->zoom(); } void SvgViewAdapter::setZoom(qreal zoom, const QPointF& center) { d->mView->setZoom(zoom, center); } qreal SvgViewAdapter::computeZoomToFit() const { return d->mView->computeZoomToFit(); } -qreal SvgViewAdapter::computeZoomToFitWidth() const +qreal SvgViewAdapter::computeZoomToFill() const { - return d->mView->computeZoomToFitWidth(); + return d->mView->computeZoomToFill(); } QPointF SvgViewAdapter::scrollPos() const { return d->mView->scrollPos(); } void SvgViewAdapter::setScrollPos(const QPointF& pos) { d->mView->setScrollPos(pos); } } // namespace diff --git a/lib/documentview/svgviewadapter.h b/lib/documentview/svgviewadapter.h index 695cdc18..8ec7a223 100644 --- a/lib/documentview/svgviewadapter.h +++ b/lib/documentview/svgviewadapter.h @@ -1,111 +1,111 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef SVGVIEWADAPTER_H #define SVGVIEWADAPTER_H #include // Qt #include // KDE // Local #include #include class QGraphicsSvgItem; namespace Gwenview { class SvgImageView : public AbstractImageView { Q_OBJECT public: SvgImageView(QGraphicsItem* parent = 0); protected: void loadFromDocument() Q_DECL_OVERRIDE; void onZoomChanged() Q_DECL_OVERRIDE; void onImageOffsetChanged() Q_DECL_OVERRIDE; void onScrollPosChanged(const QPointF& oldPos) Q_DECL_OVERRIDE; private Q_SLOTS: void finishLoadFromDocument(); private: QGraphicsSvgItem* mSvgItem; void adjustItemPos(); }; struct SvgViewAdapterPrivate; class GWENVIEWLIB_EXPORT SvgViewAdapter : public AbstractDocumentViewAdapter { Q_OBJECT public: SvgViewAdapter(); ~SvgViewAdapter(); virtual QCursor cursor() const Q_DECL_OVERRIDE; virtual void setCursor(const QCursor&) Q_DECL_OVERRIDE; virtual void setDocument(Document::Ptr) Q_DECL_OVERRIDE; virtual Document::Ptr document() const Q_DECL_OVERRIDE; virtual MimeTypeUtils::Kind kind() const Q_DECL_OVERRIDE { return MimeTypeUtils::KIND_SVG_IMAGE; } virtual bool canZoom() const Q_DECL_OVERRIDE { return true; } virtual void setZoomToFit(bool) Q_DECL_OVERRIDE; - virtual void setZoomToFitWidth(bool) Q_DECL_OVERRIDE; + virtual void setZoomToFill(bool) Q_DECL_OVERRIDE; virtual bool zoomToFit() const Q_DECL_OVERRIDE; - virtual bool zoomToFitWidth() const Q_DECL_OVERRIDE; + virtual bool zoomToFill() const Q_DECL_OVERRIDE; virtual qreal zoom() const Q_DECL_OVERRIDE; virtual void setZoom(qreal /*zoom*/, const QPointF& /*center*/ = QPointF(-1, -1)) Q_DECL_OVERRIDE; virtual qreal computeZoomToFit() const Q_DECL_OVERRIDE; - virtual qreal computeZoomToFitWidth() const Q_DECL_OVERRIDE; + virtual qreal computeZoomToFill() const Q_DECL_OVERRIDE; virtual QPointF scrollPos() const Q_DECL_OVERRIDE; virtual void setScrollPos(const QPointF& pos) Q_DECL_OVERRIDE; private: SvgViewAdapterPrivate* const d; }; } // namespace #endif /* SVGVIEWADAPTER_H */ diff --git a/lib/zoomwidget.cpp b/lib/zoomwidget.cpp index 9aca642b..6b9102f0 100644 --- a/lib/zoomwidget.cpp +++ b/lib/zoomwidget.cpp @@ -1,200 +1,201 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ // Self #include "zoomwidget.h" // stdc++ #include // Qt #include #include #include #include #include // KDE // Local #include "zoomslider.h" #include "signalblocker.h" #include "statusbartoolbutton.h" namespace Gwenview { static const qreal MAGIC_K = 1.04; static const qreal MAGIC_OFFSET = 16.; static const qreal PRECISION = 100.; inline int sliderValueForZoom(qreal zoom) { return int(PRECISION * (log(zoom) / log(MAGIC_K) + MAGIC_OFFSET)); } inline qreal zoomForSliderValue(int sliderValue) { return pow(MAGIC_K, sliderValue / PRECISION - MAGIC_OFFSET); } struct ZoomWidgetPrivate { ZoomWidget* q; StatusBarToolButton* mZoomToFitButton; StatusBarToolButton* mActualSizeButton; - StatusBarToolButton* mZoomToFitWidthButton; + StatusBarToolButton* mZoomToFillButton; QLabel* mZoomLabel; ZoomSlider* mZoomSlider; QAction* mZoomToFitAction; QAction* mActualSizeAction; - QAction* mZoomToFitWidthAction; + QAction* mZoomToFillAction; bool mZoomUpdatedBySlider; void emitZoomChanged() { // Use QSlider::sliderPosition(), not QSlider::value() because when we are // called from slotZoomSliderActionTriggered(), QSlider::value() has not // been updated yet. qreal zoom = zoomForSliderValue(mZoomSlider->slider()->sliderPosition()); mZoomUpdatedBySlider = true; emit q->zoomChanged(zoom); mZoomUpdatedBySlider = false; } }; ZoomWidget::ZoomWidget(QWidget* parent) : QFrame(parent) , d(new ZoomWidgetPrivate) { d->q = this; d->mZoomUpdatedBySlider = false; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); d->mZoomToFitButton = new StatusBarToolButton; d->mActualSizeButton = new StatusBarToolButton; - d->mZoomToFitWidthButton = new StatusBarToolButton; + d->mZoomToFillButton = new StatusBarToolButton; d->mZoomToFitButton->setCheckable(true); d->mActualSizeButton->setCheckable(true); - d->mZoomToFitWidthButton->setCheckable(true); + d->mZoomToFillButton->setCheckable(true); d->mZoomToFitButton->setChecked(true); if (QApplication::isLeftToRight()) { d->mZoomToFitButton->setGroupPosition(StatusBarToolButton::GroupLeft); - d->mZoomToFitWidthButton->setGroupPosition(StatusBarToolButton::GroupCenter); + d->mZoomToFillButton->setGroupPosition(StatusBarToolButton::GroupCenter); d->mActualSizeButton->setGroupPosition(StatusBarToolButton::GroupRight); } else { d->mActualSizeButton->setGroupPosition(StatusBarToolButton::GroupLeft); - d->mZoomToFitWidthButton->setGroupPosition(StatusBarToolButton::GroupCenter); + d->mZoomToFillButton->setGroupPosition(StatusBarToolButton::GroupCenter); d->mZoomToFitButton->setGroupPosition(StatusBarToolButton::GroupRight); } d->mZoomLabel = new QLabel; d->mZoomLabel->setFixedWidth(d->mZoomLabel->fontMetrics().width(" 1000% ")); d->mZoomLabel->setAlignment(Qt::AlignCenter); d->mZoomSlider = new ZoomSlider; d->mZoomSlider->setMinimumWidth(150); d->mZoomSlider->slider()->setSingleStep(int(PRECISION)); d->mZoomSlider->slider()->setPageStep(3 * int(PRECISION)); connect(d->mZoomSlider->slider(), SIGNAL(actionTriggered(int)), SLOT(slotZoomSliderActionTriggered())); // Layout QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(d->mZoomToFitButton); - layout->addWidget(d->mZoomToFitWidthButton); + layout->addWidget(d->mZoomToFillButton); layout->addWidget(d->mActualSizeButton); layout->addWidget(d->mZoomSlider); layout->addWidget(d->mZoomLabel); } ZoomWidget::~ZoomWidget() { delete d; } -void ZoomWidget::setActions(QAction* zoomToFitAction, QAction* actualSizeAction, QAction* zoomInAction, QAction* zoomOutAction, QAction* zoomToFitWidthAction) +void ZoomWidget::setActions(QAction* zoomToFitAction, QAction* actualSizeAction, QAction* zoomInAction, QAction* zoomOutAction, QAction* zoomToFillAction) { d->mZoomToFitAction = zoomToFitAction; d->mActualSizeAction = actualSizeAction; - d->mZoomToFitWidthAction = zoomToFitWidthAction; + d->mZoomToFillAction = zoomToFillAction; d->mZoomToFitButton->setDefaultAction(zoomToFitAction); d->mActualSizeButton->setDefaultAction(actualSizeAction); - d->mZoomToFitWidthButton->setDefaultAction(zoomToFitWidthAction); + d->mZoomToFillButton->setDefaultAction(zoomToFillAction); d->mZoomSlider->setZoomInAction(zoomInAction); d->mZoomSlider->setZoomOutAction(zoomOutAction); QActionGroup *actionGroup = new QActionGroup(d->q); actionGroup->addAction(d->mZoomToFitAction); - actionGroup->addAction(d->mZoomToFitWidthAction); + actionGroup->addAction(d->mZoomToFillAction); actionGroup->addAction(d->mActualSizeAction); actionGroup->setExclusive(true); // Adjust sizes - int width = qMax(d->mZoomToFitButton->sizeHint().width(), d->mActualSizeButton->sizeHint().width()); + int width = std::max({d->mZoomToFitButton->sizeHint().width(), d->mActualSizeButton->sizeHint().width(), d->mZoomToFillButton->sizeHint().width()}); d->mZoomToFitButton->setFixedWidth(width); d->mActualSizeButton->setFixedWidth(width); + d->mZoomToFillButton->setFixedWidth(width); } void ZoomWidget::slotZoomSliderActionTriggered() { // The slider value changed because of the user (not because of range // changes). In this case disable zoom and apply slider value. d->emitZoomChanged(); } void ZoomWidget::setZoom(qreal zoom) { int intZoom = qRound(zoom * 100); d->mZoomLabel->setText(QString("%1%").arg(intZoom)); // Don't change slider value if we come here because the slider change, // avoids choppy sliding scroll. if (!d->mZoomUpdatedBySlider) { QSlider* slider = d->mZoomSlider->slider(); SignalBlocker blocker(slider); int value = sliderValueForZoom(zoom); if (value < slider->minimum()) { // It is possible that we are called *before* setMinimumZoom() as // been called. In this case, define the minimum ourself. d->mZoomSlider->setMinimum(value); } d->mZoomSlider->setValue(value); } } void ZoomWidget::setMinimumZoom(qreal minimumZoom) { d->mZoomSlider->setMinimum(sliderValueForZoom(minimumZoom)); } void ZoomWidget::setMaximumZoom(qreal zoom) { d->mZoomSlider->setMaximum(sliderValueForZoom(zoom)); } } // namespace diff --git a/lib/zoomwidget.h b/lib/zoomwidget.h index 7bdceb0b..535614cf 100644 --- a/lib/zoomwidget.h +++ b/lib/zoomwidget.h @@ -1,67 +1,67 @@ // vim: set tabstop=4 shiftwidth=4 expandtab: /* Gwenview: an image viewer Copyright 2008 Aurélien Gâteau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA. */ #ifndef ZOOMWIDGET_H #define ZOOMWIDGET_H #include // Qt #include // KDE // Local class QAction; namespace Gwenview { struct ZoomWidgetPrivate; class GWENVIEWLIB_EXPORT ZoomWidget : public QFrame { Q_OBJECT public: ZoomWidget(QWidget* parent = 0); ~ZoomWidget(); - void setActions(QAction* zoomToFitAction, QAction* actualSizeAction, QAction* zoomInAction, QAction* zoomOutAction, QAction* zoomToFitWidthAction); + void setActions(QAction* zoomToFitAction, QAction* actualSizeAction, QAction* zoomInAction, QAction* zoomOutAction, QAction* zoomToFillAction); public Q_SLOTS: void setZoom(qreal zoom); void setMinimumZoom(qreal zoom); void setMaximumZoom(qreal zoom); Q_SIGNALS: void zoomChanged(qreal); private Q_SLOTS: void slotZoomSliderActionTriggered(); private: friend struct ZoomWidgetPrivate; ZoomWidgetPrivate* const d; }; } // namespace #endif /* ZOOMWIDGET_H */