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