1 
2 /****************************************************************************
3 **
4 ** Copyright (C) 2015 The Qt Company Ltd.
5 ** Contact: http://www.qt.io/licensing/
6 **
7 ** This file is part of the examples of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 **   * Redistributions of source code must retain the above copyright
16 **     notice, this list of conditions and the following disclaimer.
17 **   * Redistributions in binary form must reproduce the above copyright
18 **     notice, this list of conditions and the following disclaimer in
19 **     the documentation and/or other materials provided with the
20 **     distribution.
21 **   * Neither the name of The Qt Company Ltd nor the names of its
22 **     contributors may be used to endorse or promote products derived
23 **     from this software without specific prior written permission.
24 **
25 **
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "imagewidget.h"
43 
44 #include <QtGui>
45 
46 bool ImageWidget::verbose = false;
47 
48 //! [constructor]
ImageWidget(QWidget * parent)49 ImageWidget::ImageWidget(QWidget *parent)
50     : QWidget(parent),
51     position(0),
52     horizontalOffset(0),
53     verticalOffset(0),
54     rotationAngle(0),
55     scaleFactor(1),
56     currentStepScaleFactor(1)
57 
58 {
59     setMinimumSize(QSize(100,100));
60 }
61 //! [constructor]
62 
grabGestures(const QList<Qt::GestureType> & gestures)63 void ImageWidget::grabGestures(const QList<Qt::GestureType> &gestures)
64 {
65     //! [enable gestures]
66     foreach (Qt::GestureType gesture, gestures)
67         grabGesture(gesture);
68     //! [enable gestures]
69 }
70 
71 //! [event handler]
event(QEvent * event)72 bool ImageWidget::event(QEvent *event)
73 {
74     if (event->type() == QEvent::Gesture)
75         return gestureEvent(static_cast<QGestureEvent*>(event));
76     return QWidget::event(event);
77 }
78 //! [event handler]
79 
paintEvent(QPaintEvent *)80 void ImageWidget::paintEvent(QPaintEvent*)
81 {
82     QPainter p(this);
83 
84     const qreal iw = currentImage.width();
85     const qreal ih = currentImage.height();
86     const qreal wh = height();
87     const qreal ww = width();
88 
89     p.translate(ww/2, wh/2);
90     p.translate(horizontalOffset, verticalOffset);
91     p.rotate(rotationAngle);
92     p.scale(currentStepScaleFactor * scaleFactor, currentStepScaleFactor * scaleFactor);
93     p.translate(-iw/2, -ih/2);
94     p.drawImage(0, 0, currentImage);
95 }
96 
mouseDoubleClickEvent(QMouseEvent *)97 void ImageWidget::mouseDoubleClickEvent(QMouseEvent *)
98 {
99     rotationAngle = 0;
100     scaleFactor = 1;
101     currentStepScaleFactor = 1;
102     verticalOffset = 0;
103     horizontalOffset = 0;
104     update();
105     if (ImageWidget::verbose)
106         qDebug() << "reset on mouse double click";
107 }
108 
109 //! [gesture event handler]
gestureEvent(QGestureEvent * event)110 bool ImageWidget::gestureEvent(QGestureEvent *event)
111 {
112     if (ImageWidget::verbose)
113         qDebug() << "gestureEvent():" << event->gestures().size();
114     if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
115         swipeTriggered(static_cast<QSwipeGesture *>(swipe));
116     else if (QGesture *pan = event->gesture(Qt::PanGesture))
117         panTriggered(static_cast<QPanGesture *>(pan));
118     if (QGesture *pinch = event->gesture(Qt::PinchGesture))
119         pinchTriggered(static_cast<QPinchGesture *>(pinch));
120     return true;
121 }
122 //! [gesture event handler]
123 
panTriggered(QPanGesture * gesture)124 void ImageWidget::panTriggered(QPanGesture *gesture)
125 {
126 #ifndef QT_NO_CURSOR
127     switch (gesture->state()) {
128         case Qt::GestureStarted:
129         case Qt::GestureUpdated:
130             setCursor(Qt::SizeAllCursor);
131             break;
132         default:
133             setCursor(Qt::ArrowCursor);
134     }
135 #endif
136     QPointF delta = gesture->delta();
137     if (ImageWidget::verbose)
138         qDebug() << "panTriggered():" << delta;
139     horizontalOffset += delta.x();
140     verticalOffset += delta.y();
141     update();
142 }
143 
pinchTriggered(QPinchGesture * gesture)144 void ImageWidget::pinchTriggered(QPinchGesture *gesture)
145 {
146     QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
147     if (changeFlags & QPinchGesture::RotationAngleChanged) {
148         const qreal value = gesture->property("rotationAngle").toReal();
149         const qreal lastValue = gesture->property("lastRotationAngle").toReal();
150         const qreal rotationAngleDelta = value - lastValue;
151         rotationAngle += rotationAngleDelta;
152         if (ImageWidget::verbose)
153             qDebug() << "pinchTriggered(): rotation by" << rotationAngleDelta << rotationAngle;
154     }
155     if (changeFlags & QPinchGesture::ScaleFactorChanged) {
156         qreal value = gesture->property("scaleFactor").toReal();
157         currentStepScaleFactor = value;
158         if (ImageWidget::verbose)
159             qDebug() << "pinchTriggered(): " << currentStepScaleFactor;
160     }
161     if (gesture->state() == Qt::GestureFinished) {
162         scaleFactor *= currentStepScaleFactor;
163         currentStepScaleFactor = 1;
164     }
165     update();
166 }
167 
168 //! [swipe function]
swipeTriggered(QSwipeGesture * gesture)169 void ImageWidget::swipeTriggered(QSwipeGesture *gesture)
170 {
171     if (gesture->state() == Qt::GestureFinished) {
172         if (gesture->horizontalDirection() == QSwipeGesture::Left
173             || gesture->verticalDirection() == QSwipeGesture::Up) {
174             if (ImageWidget::verbose)
175                 qDebug() << "swipeTriggered(): swipe to previous";
176             goPrevImage();
177         } else {
178             if (ImageWidget::verbose)
179                 qDebug() << "swipeTriggered(): swipe to next";
180             goNextImage();
181         }
182         update();
183     }
184 }
185 //! [swipe function]
186 
resizeEvent(QResizeEvent *)187 void ImageWidget::resizeEvent(QResizeEvent*)
188 {
189     update();
190 }
191 
openDirectory(const QString & path)192 void ImageWidget::openDirectory(const QString &path)
193 {
194     this->path = path;
195     QDir dir(path);
196     QStringList nameFilters;
197     nameFilters << "*.jpg" << "*.png";
198     files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
199 
200     position = 0;
201     goToImage(0);
202     update();
203 }
204 
loadImage(const QString & fileName)205 QImage ImageWidget::loadImage(const QString &fileName)
206 {
207     qDebug() << position << files << fileName;
208     QImageReader reader(fileName);
209     if (ImageWidget::verbose)
210         qDebug() << "loading" << QDir::toNativeSeparators(fileName) << position << '/' << files.size();
211     if (!reader.canRead()) {
212         qWarning() << QDir::toNativeSeparators(fileName) << ": can't load image";
213         return QImage();
214     }
215 
216     QImage image;
217     if (!reader.read(&image)) {
218         qWarning() << QDir::toNativeSeparators(fileName) << ": corrupted image: " << reader.errorString();
219         return QImage();
220     }
221     const QSize maximumSize(2000, 2000); // Reduce in case someone has large photo images.
222     if (image.size().width() > maximumSize.width() || image.height() > maximumSize.height())
223         image = image.scaled(maximumSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
224     return image;
225 }
226 
goNextImage()227 void ImageWidget::goNextImage()
228 {
229     if (files.isEmpty())
230         return;
231 
232     if (position < files.size()-1) {
233         ++position;
234         prevImage = currentImage;
235         currentImage = nextImage;
236         if (position+1 < files.size())
237             nextImage = loadImage(path+QLatin1String("/")+files.at(position+1));
238         else
239             nextImage = QImage();
240     }
241     update();
242 }
243 
goPrevImage()244 void ImageWidget::goPrevImage()
245 {
246     if (files.isEmpty())
247         return;
248 
249     if (position > 0) {
250         --position;
251         nextImage = currentImage;
252         currentImage = prevImage;
253         if (position > 0)
254             prevImage = loadImage(path+QLatin1String("/")+files.at(position-1));
255         else
256             prevImage = QImage();
257     }
258     update();
259 }
260 
goToImage(int index)261 void ImageWidget::goToImage(int index)
262 {
263     if (files.isEmpty())
264         return;
265 
266     if (index < 0 || index >= files.size()) {
267         qWarning() << "goToImage: invalid index: " << index;
268         return;
269     }
270 
271     if (index == position+1) {
272         goNextImage();
273         return;
274     }
275 
276     if (position > 0 && index == position-1) {
277         goPrevImage();
278         return;
279     }
280 
281     position = index;
282 
283     if (index > 0)
284         prevImage = loadImage(path+QLatin1String("/")+files.at(position-1));
285     else
286         prevImage = QImage();
287     currentImage = loadImage(path+QLatin1String("/")+files.at(position));
288     if (position+1 < files.size())
289         nextImage = loadImage(path+QLatin1String("/")+files.at(position+1));
290     else
291         nextImage = QImage();
292     update();
293 }
294