source: trunk/demos/embedded/fluidlauncher/pictureflow.cpp@ 858

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 38.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the ActiveQt framework 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 Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
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** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41/*
42 ORIGINAL COPYRIGHT HEADER
43 PictureFlow - animated image show widget
44 http://pictureflow.googlecode.com
45
46 Copyright (C) 2007 Ariya Hidayat ([email protected])
47
48 Permission is hereby granted, free of charge, to any person obtaining a copy
49 of this software and associated documentation files (the "Software"), to deal
50 in the Software without restriction, including without limitation the rights
51 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52 copies of the Software, and to permit persons to whom the Software is
53 furnished to do so, subject to the following conditions:
54
55 The above copyright notice and this permission notice shall be included in
56 all copies or substantial portions of the Software.
57
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64 THE SOFTWARE.
65*/
66
67#include "pictureflow.h"
68
69#include <QBasicTimer>
70#include <QCache>
71#include <QImage>
72#include <QKeyEvent>
73#include <QPainter>
74#include <QPixmap>
75#include <QTimer>
76#include <QVector>
77#include <QWidget>
78#include <QTime>
79
80#ifdef Q_WS_QWS
81#include <QScreen>
82#endif
83
84#include <QDebug>
85
86static const int captionFontSize =
87#ifdef Q_WS_S60
88 8;
89#else
90 14;
91#endif
92
93
94// uncomment this to enable bilinear filtering for texture mapping
95// gives much better rendering, at the cost of memory space
96// #define PICTUREFLOW_BILINEAR_FILTER
97
98// for fixed-point arithmetic, we need minimum 32-bit long
99// long long (64-bit) might be useful for multiplication and division
100typedef long PFreal;
101
102typedef unsigned short QRgb565;
103
104#define RGB565_RED_MASK 0xF800
105#define RGB565_GREEN_MASK 0x07E0
106#define RGB565_BLUE_MASK 0x001F
107
108#define RGB565_RED(col) ((col&RGB565_RED_MASK)>>11)
109#define RGB565_GREEN(col) ((col&RGB565_GREEN_MASK)>>5)
110#define RGB565_BLUE(col) (col&RGB565_BLUE_MASK)
111
112#define PFREAL_SHIFT 10
113#define PFREAL_FACTOR (1 << PFREAL_SHIFT)
114#define PFREAL_ONE (1 << PFREAL_SHIFT)
115#define PFREAL_HALF (PFREAL_ONE >> 1)
116
117inline PFreal fmul(PFreal a, PFreal b)
118{
119 return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
120}
121
122inline PFreal fdiv(PFreal num, PFreal den)
123{
124 long long p = (long long)(num) << (PFREAL_SHIFT*2);
125 long long q = p / (long long)den;
126 long long r = q >> PFREAL_SHIFT;
127
128 return r;
129}
130
131inline float fixedToFloat(PFreal val)
132{
133 return ((float)val) / (float)PFREAL_ONE;
134}
135
136inline PFreal floatToFixed(float val)
137{
138 return (PFreal)(val*PFREAL_ONE);
139}
140
141#define IANGLE_MAX 1024
142#define IANGLE_MASK 1023
143
144// warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed!
145static const PFreal sinTable[IANGLE_MAX] = {
146 3, 9, 15, 21, 28, 34, 40, 47,
147 53, 59, 65, 72, 78, 84, 90, 97,
148 103, 109, 115, 122, 128, 134, 140, 147,
149 153, 159, 165, 171, 178, 184, 190, 196,
150 202, 209, 215, 221, 227, 233, 239, 245,
151 251, 257, 264, 270, 276, 282, 288, 294,
152 300, 306, 312, 318, 324, 330, 336, 342,
153 347, 353, 359, 365, 371, 377, 383, 388,
154 394, 400, 406, 412, 417, 423, 429, 434,
155 440, 446, 451, 457, 463, 468, 474, 479,
156 485, 491, 496, 501, 507, 512, 518, 523,
157 529, 534, 539, 545, 550, 555, 561, 566,
158 571, 576, 581, 587, 592, 597, 602, 607,
159 612, 617, 622, 627, 632, 637, 642, 647,
160 652, 656, 661, 666, 671, 675, 680, 685,
161 690, 694, 699, 703, 708, 712, 717, 721,
162 726, 730, 735, 739, 743, 748, 752, 756,
163 760, 765, 769, 773, 777, 781, 785, 789,
164 793, 797, 801, 805, 809, 813, 816, 820,
165 824, 828, 831, 835, 839, 842, 846, 849,
166 853, 856, 860, 863, 866, 870, 873, 876,
167 879, 883, 886, 889, 892, 895, 898, 901,
168 904, 907, 910, 913, 916, 918, 921, 924,
169 927, 929, 932, 934, 937, 939, 942, 944,
170 947, 949, 951, 954, 956, 958, 960, 963,
171 965, 967, 969, 971, 973, 975, 977, 978,
172 980, 982, 984, 986, 987, 989, 990, 992,
173 994, 995, 997, 998, 999, 1001, 1002, 1003,
174 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
175 1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018,
176 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
177 1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
178 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022,
179 1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019,
180 1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013,
181 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004,
182 1003, 1002, 1001, 999, 998, 997, 995, 994,
183 992, 990, 989, 987, 986, 984, 982, 980,
184 978, 977, 975, 973, 971, 969, 967, 965,
185 963, 960, 958, 956, 954, 951, 949, 947,
186 944, 942, 939, 937, 934, 932, 929, 927,
187 924, 921, 918, 916, 913, 910, 907, 904,
188 901, 898, 895, 892, 889, 886, 883, 879,
189 876, 873, 870, 866, 863, 860, 856, 853,
190 849, 846, 842, 839, 835, 831, 828, 824,
191 820, 816, 813, 809, 805, 801, 797, 793,
192 789, 785, 781, 777, 773, 769, 765, 760,
193 756, 752, 748, 743, 739, 735, 730, 726,
194 721, 717, 712, 708, 703, 699, 694, 690,
195 685, 680, 675, 671, 666, 661, 656, 652,
196 647, 642, 637, 632, 627, 622, 617, 612,
197 607, 602, 597, 592, 587, 581, 576, 571,
198 566, 561, 555, 550, 545, 539, 534, 529,
199 523, 518, 512, 507, 501, 496, 491, 485,
200 479, 474, 468, 463, 457, 451, 446, 440,
201 434, 429, 423, 417, 412, 406, 400, 394,
202 388, 383, 377, 371, 365, 359, 353, 347,
203 342, 336, 330, 324, 318, 312, 306, 300,
204 294, 288, 282, 276, 270, 264, 257, 251,
205 245, 239, 233, 227, 221, 215, 209, 202,
206 196, 190, 184, 178, 171, 165, 159, 153,
207 147, 140, 134, 128, 122, 115, 109, 103,
208 97, 90, 84, 78, 72, 65, 59, 53,
209 47, 40, 34, 28, 21, 15, 9, 3,
210 -4, -10, -16, -22, -29, -35, -41, -48,
211 -54, -60, -66, -73, -79, -85, -91, -98,
212 -104, -110, -116, -123, -129, -135, -141, -148,
213 -154, -160, -166, -172, -179, -185, -191, -197,
214 -203, -210, -216, -222, -228, -234, -240, -246,
215 -252, -258, -265, -271, -277, -283, -289, -295,
216 -301, -307, -313, -319, -325, -331, -337, -343,
217 -348, -354, -360, -366, -372, -378, -384, -389,
218 -395, -401, -407, -413, -418, -424, -430, -435,
219 -441, -447, -452, -458, -464, -469, -475, -480,
220 -486, -492, -497, -502, -508, -513, -519, -524,
221 -530, -535, -540, -546, -551, -556, -562, -567,
222 -572, -577, -582, -588, -593, -598, -603, -608,
223 -613, -618, -623, -628, -633, -638, -643, -648,
224 -653, -657, -662, -667, -672, -676, -681, -686,
225 -691, -695, -700, -704, -709, -713, -718, -722,
226 -727, -731, -736, -740, -744, -749, -753, -757,
227 -761, -766, -770, -774, -778, -782, -786, -790,
228 -794, -798, -802, -806, -810, -814, -817, -821,
229 -825, -829, -832, -836, -840, -843, -847, -850,
230 -854, -857, -861, -864, -867, -871, -874, -877,
231 -880, -884, -887, -890, -893, -896, -899, -902,
232 -905, -908, -911, -914, -917, -919, -922, -925,
233 -928, -930, -933, -935, -938, -940, -943, -945,
234 -948, -950, -952, -955, -957, -959, -961, -964,
235 -966, -968, -970, -972, -974, -976, -978, -979,
236 -981, -983, -985, -987, -988, -990, -991, -993,
237 -995, -996, -998, -999, -1000, -1002, -1003, -1004,
238 -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013,
239 -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019,
240 -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023,
241 -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024,
242 -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023,
243 -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020,
244 -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014,
245 -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005,
246 -1004, -1003, -1002, -1000, -999, -998, -996, -995,
247 -993, -991, -990, -988, -987, -985, -983, -981,
248 -979, -978, -976, -974, -972, -970, -968, -966,
249 -964, -961, -959, -957, -955, -952, -950, -948,
250 -945, -943, -940, -938, -935, -933, -930, -928,
251 -925, -922, -919, -917, -914, -911, -908, -905,
252 -902, -899, -896, -893, -890, -887, -884, -880,
253 -877, -874, -871, -867, -864, -861, -857, -854,
254 -850, -847, -843, -840, -836, -832, -829, -825,
255 -821, -817, -814, -810, -806, -802, -798, -794,
256 -790, -786, -782, -778, -774, -770, -766, -761,
257 -757, -753, -749, -744, -740, -736, -731, -727,
258 -722, -718, -713, -709, -704, -700, -695, -691,
259 -686, -681, -676, -672, -667, -662, -657, -653,
260 -648, -643, -638, -633, -628, -623, -618, -613,
261 -608, -603, -598, -593, -588, -582, -577, -572,
262 -567, -562, -556, -551, -546, -540, -535, -530,
263 -524, -519, -513, -508, -502, -497, -492, -486,
264 -480, -475, -469, -464, -458, -452, -447, -441,
265 -435, -430, -424, -418, -413, -407, -401, -395,
266 -389, -384, -378, -372, -366, -360, -354, -348,
267 -343, -337, -331, -325, -319, -313, -307, -301,
268 -295, -289, -283, -277, -271, -265, -258, -252,
269 -246, -240, -234, -228, -222, -216, -210, -203,
270 -197, -191, -185, -179, -172, -166, -160, -154,
271 -148, -141, -135, -129, -123, -116, -110, -104,
272 -98, -91, -85, -79, -73, -66, -60, -54,
273 -48, -41, -35, -29, -22, -16, -10, -4
274};
275
276// this is the program the generate the above table
277#if 0
278#include <stdio.h>
279#include <math.h>
280
281#ifndef M_PI
282#define M_PI 3.14159265358979323846
283#endif
284
285#define PFREAL_ONE 1024
286#define IANGLE_MAX 1024
287
288int main(int, char**)
289{
290 FILE*f = fopen("table.c","wt");
291 fprintf(f,"PFreal sinTable[] = {\n");
292 for(int i = 0; i < 128; i++)
293 {
294 for(int j = 0; j < 8; j++)
295 {
296 int iang = j+i*8;
297 double ii = (double)iang + 0.5;
298 double angle = ii * 2 * M_PI / IANGLE_MAX;
299 double sinAngle = sin(angle);
300 fprintf(f,"%6d, ", (int)(floor(PFREAL_ONE*sinAngle)));
301 }
302 fprintf(f,"\n");
303 }
304 fprintf(f,"};\n");
305 fclose(f);
306
307 return 0;
308}
309#endif
310
311inline PFreal fsin(int iangle)
312{
313 while(iangle < 0)
314 iangle += IANGLE_MAX;
315 return sinTable[iangle & IANGLE_MASK];
316}
317
318inline PFreal fcos(int iangle)
319{
320 // quarter phase shift
321 return fsin(iangle + (IANGLE_MAX >> 2));
322}
323
324struct SlideInfo
325{
326 int slideIndex;
327 int angle;
328 PFreal cx;
329 PFreal cy;
330};
331
332class PictureFlowPrivate
333{
334public:
335 PictureFlowPrivate(PictureFlow* widget);
336
337 int slideCount() const;
338 void setSlideCount(int count);
339
340 QSize slideSize() const;
341 void setSlideSize(QSize size);
342
343 int zoomFactor() const;
344 void setZoomFactor(int z);
345
346 QImage slide(int index) const;
347 void setSlide(int index, const QImage& image);
348
349 int currentSlide() const;
350 void setCurrentSlide(int index);
351
352 int getTarget() const;
353
354 void showPrevious();
355 void showNext();
356 void showSlide(int index);
357
358 void resize(int w, int h);
359
360 void render();
361 void startAnimation();
362 void updateAnimation();
363
364 void clearSurfaceCache();
365
366 QImage buffer;
367 QBasicTimer animateTimer;
368
369 bool singlePress;
370 int singlePressThreshold;
371 QPoint firstPress;
372 QPoint previousPos;
373 QTime previousPosTimestamp;
374 int pixelDistanceMoved;
375 int pixelsToMovePerSlide;
376
377 QVector<QString> captions;
378
379private:
380 PictureFlow* widget;
381
382 int slideWidth;
383 int slideHeight;
384 int zoom;
385
386 QVector<QImage> slideImages;
387 int centerIndex;
388 SlideInfo centerSlide;
389 QVector<SlideInfo> leftSlides;
390 QVector<SlideInfo> rightSlides;
391
392 QVector<PFreal> rays;
393 int itilt;
394 int spacing;
395 PFreal offsetX;
396 PFreal offsetY;
397
398 QImage blankSurface;
399 QCache<int, QImage> surfaceCache;
400 QTimer triggerTimer;
401
402 int slideFrame;
403 int step;
404 int target;
405 int fade;
406
407 void recalc(int w, int h);
408 QRect renderSlide(const SlideInfo &slide, int alpha=256, int col1=-1, int col=-1);
409 QImage* surface(int slideIndex);
410 void triggerRender();
411 void resetSlides();
412};
413
414PictureFlowPrivate::PictureFlowPrivate(PictureFlow* w)
415{
416 widget = w;
417
418 slideWidth = 200;
419 slideHeight = 200;
420 zoom = 100;
421
422 centerIndex = 0;
423
424 slideFrame = 0;
425 step = 0;
426 target = 0;
427 fade = 256;
428
429 triggerTimer.setSingleShot(true);
430 triggerTimer.setInterval(0);
431 QObject::connect(&triggerTimer, SIGNAL(timeout()), widget, SLOT(render()));
432
433 recalc(200, 200);
434 resetSlides();
435}
436
437int PictureFlowPrivate::slideCount() const
438{
439 return slideImages.count();
440}
441
442void PictureFlowPrivate::setSlideCount(int count)
443{
444 slideImages.resize(count);
445 captions.resize(count);
446 surfaceCache.clear();
447 resetSlides();
448 triggerRender();
449}
450
451QSize PictureFlowPrivate::slideSize() const
452{
453 return QSize(slideWidth, slideHeight);
454}
455
456void PictureFlowPrivate::setSlideSize(QSize size)
457{
458 slideWidth = size.width();
459 slideHeight = size.height();
460 recalc(buffer.width(), buffer.height());
461 triggerRender();
462}
463
464int PictureFlowPrivate::zoomFactor() const
465{
466 return zoom;
467}
468
469void PictureFlowPrivate::setZoomFactor(int z)
470{
471 if(z <= 0)
472 return;
473
474 zoom = z;
475 recalc(buffer.width(), buffer.height());
476 triggerRender();
477}
478
479QImage PictureFlowPrivate::slide(int index) const
480{
481 return slideImages[index];
482}
483
484void PictureFlowPrivate::setSlide(int index, const QImage& image)
485{
486 if((index >= 0) && (index < slideImages.count()))
487 {
488 slideImages[index] = image;
489 surfaceCache.remove(index);
490 triggerRender();
491 }
492}
493
494int PictureFlowPrivate::getTarget() const
495{
496 return target;
497}
498
499int PictureFlowPrivate::currentSlide() const
500{
501 return centerIndex;
502}
503
504void PictureFlowPrivate::setCurrentSlide(int index)
505{
506 step = 0;
507 centerIndex = qBound(index, 0, slideImages.count()-1);
508 target = centerIndex;
509 slideFrame = index << 16;
510 resetSlides();
511 triggerRender();
512}
513
514void PictureFlowPrivate::showPrevious()
515{
516 if(step >= 0)
517 {
518 if(centerIndex > 0)
519 {
520 target--;
521 startAnimation();
522 }
523 }
524 else
525 {
526 target = qMax(0, centerIndex - 2);
527 }
528}
529
530void PictureFlowPrivate::showNext()
531{
532 if(step <= 0)
533 {
534 if(centerIndex < slideImages.count()-1)
535 {
536 target++;
537 startAnimation();
538 }
539 }
540 else
541 {
542 target = qMin(centerIndex + 2, slideImages.count()-1);
543 }
544}
545
546void PictureFlowPrivate::showSlide(int index)
547{
548 index = qMax(index, 0);
549 index = qMin(slideImages.count()-1, index);
550 if(index == centerSlide.slideIndex)
551 return;
552
553 target = index;
554 startAnimation();
555}
556
557void PictureFlowPrivate::resize(int w, int h)
558{
559 recalc(w, h);
560 resetSlides();
561 triggerRender();
562}
563
564
565// adjust slides so that they are in "steady state" position
566void PictureFlowPrivate::resetSlides()
567{
568 centerSlide.angle = 0;
569 centerSlide.cx = 0;
570 centerSlide.cy = 0;
571 centerSlide.slideIndex = centerIndex;
572
573 leftSlides.clear();
574 leftSlides.resize(3);
575 for(int i = 0; i < leftSlides.count(); i++)
576 {
577 SlideInfo& si = leftSlides[i];
578 si.angle = itilt;
579 si.cx = -(offsetX + spacing*i*PFREAL_ONE);
580 si.cy = offsetY;
581 si.slideIndex = centerIndex-1-i;
582 //qDebug() << "Left[" << i << "] x=" << fixedToFloat(si.cx) << ", y=" << fixedToFloat(si.cy) ;
583 }
584
585 rightSlides.clear();
586 rightSlides.resize(3);
587 for(int i = 0; i < rightSlides.count(); i++)
588 {
589 SlideInfo& si = rightSlides[i];
590 si.angle = -itilt;
591 si.cx = offsetX + spacing*i*PFREAL_ONE;
592 si.cy = offsetY;
593 si.slideIndex = centerIndex+1+i;
594 //qDebug() << "Right[" << i << "] x=" << fixedToFloat(si.cx) << ", y=" << fixedToFloat(si.cy) ;
595 }
596}
597
598#define BILINEAR_STRETCH_HOR 4
599#define BILINEAR_STRETCH_VER 4
600
601static QImage prepareSurface(QImage img, int w, int h)
602{
603 Qt::TransformationMode mode = Qt::SmoothTransformation;
604 img = img.scaled(w, h, Qt::IgnoreAspectRatio, mode);
605
606 // slightly larger, to accommodate for the reflection
607 int hs = h * 2;
608 int hofs = h / 3;
609
610 // offscreen buffer: black is sweet
611 QImage result(hs, w, QImage::Format_RGB16);
612 result.fill(0);
613
614 // transpose the image, this is to speed-up the rendering
615 // because we process one column at a time
616 // (and much better and faster to work row-wise, i.e in one scanline)
617 for(int x = 0; x < w; x++)
618 for(int y = 0; y < h; y++)
619 result.setPixel(hofs + y, x, img.pixel(x, y));
620
621 // create the reflection
622 int ht = hs - h - hofs;
623 int hte = ht;
624 for(int x = 0; x < w; x++)
625 for(int y = 0; y < ht; y++)
626 {
627 QRgb color = img.pixel(x, img.height()-y-1);
628 //QRgb565 color = img.scanLine(img.height()-y-1) + x*sizeof(QRgb565); //img.pixel(x, img.height()-y-1);
629 int a = qAlpha(color);
630 int r = qRed(color) * a / 256 * (hte - y) / hte * 3/5;
631 int g = qGreen(color) * a / 256 * (hte - y) / hte * 3/5;
632 int b = qBlue(color) * a / 256 * (hte - y) / hte * 3/5;
633 result.setPixel(h+hofs+y, x, qRgb(r, g, b));
634 }
635
636#ifdef PICTUREFLOW_BILINEAR_FILTER
637 int hh = BILINEAR_STRETCH_VER*hs;
638 int ww = BILINEAR_STRETCH_HOR*w;
639 result = result.scaled(hh, ww, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
640#endif
641
642 return result;
643}
644
645
646// get transformed image for specified slide
647// if it does not exist, create it and place it in the cache
648QImage* PictureFlowPrivate::surface(int slideIndex)
649{
650 if(slideIndex < 0)
651 return 0;
652 if(slideIndex >= slideImages.count())
653 return 0;
654
655 if(surfaceCache.contains(slideIndex))
656 return surfaceCache[slideIndex];
657
658 QImage img = widget->slide(slideIndex);
659 if(img.isNull())
660 {
661 if(blankSurface.isNull())
662 {
663 blankSurface = QImage(slideWidth, slideHeight, QImage::Format_RGB16);
664
665 QPainter painter(&blankSurface);
666 QPoint p1(slideWidth*4/10, 0);
667 QPoint p2(slideWidth*6/10, slideHeight);
668 QLinearGradient linearGrad(p1, p2);
669 linearGrad.setColorAt(0, Qt::black);
670 linearGrad.setColorAt(1, Qt::white);
671 painter.setBrush(linearGrad);
672 painter.fillRect(0, 0, slideWidth, slideHeight, QBrush(linearGrad));
673
674 painter.setPen(QPen(QColor(64,64,64), 4));
675 painter.setBrush(QBrush());
676 painter.drawRect(2, 2, slideWidth-3, slideHeight-3);
677 painter.end();
678 blankSurface = prepareSurface(blankSurface, slideWidth, slideHeight);
679 }
680 return &blankSurface;
681 }
682
683 surfaceCache.insert(slideIndex, new QImage(prepareSurface(img, slideWidth, slideHeight)));
684 return surfaceCache[slideIndex];
685}
686
687
688// Schedules rendering the slides. Call this function to avoid immediate
689// render and thus cause less flicker.
690void PictureFlowPrivate::triggerRender()
691{
692 triggerTimer.start();
693}
694
695// Render the slides. Updates only the offscreen buffer.
696void PictureFlowPrivate::render()
697{
698 buffer.fill(0);
699
700 int nleft = leftSlides.count();
701 int nright = rightSlides.count();
702
703 QRect r = renderSlide(centerSlide);
704 int c1 = r.left();
705 int c2 = r.right();
706
707 if(step == 0)
708 {
709 // no animation, boring plain rendering
710 for(int index = 0; index < nleft-1; index++)
711 {
712 int alpha = (index < nleft-2) ? 256 : 128;
713 QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1);
714 if(!rs.isEmpty())
715 c1 = rs.left();
716 }
717 for(int index = 0; index < nright-1; index++)
718 {
719 int alpha = (index < nright-2) ? 256 : 128;
720 QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width());
721 if(!rs.isEmpty())
722 c2 = rs.right();
723 }
724
725 QPainter painter;
726 painter.begin(&buffer);
727
728 QFont font("Arial", captionFontSize);
729 font.setBold(true);
730 painter.setFont(font);
731 painter.setPen(Qt::white);
732 //painter.setPen(QColor(255,255,255,127));
733
734 if (!captions.isEmpty())
735 painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
736 Qt::AlignCenter, captions[centerIndex]);
737
738 painter.end();
739
740 }
741 else
742 {
743 // the first and last slide must fade in/fade out
744 for(int index = 0; index < nleft; index++)
745 {
746 int alpha = 256;
747 if(index == nleft-1)
748 alpha = (step > 0) ? 0 : 128-fade/2;
749 if(index == nleft-2)
750 alpha = (step > 0) ? 128-fade/2 : 256-fade/2;
751 if(index == nleft-3)
752 alpha = (step > 0) ? 256-fade/2 : 256;
753 QRect rs = renderSlide(leftSlides[index], alpha, 0, c1-1);
754 if(!rs.isEmpty())
755 c1 = rs.left();
756
757 alpha = (step > 0) ? 256-fade/2 : 256;
758 }
759 for(int index = 0; index < nright; index++)
760 {
761 int alpha = (index < nright-2) ? 256 : 128;
762 if(index == nright-1)
763 alpha = (step > 0) ? fade/2 : 0;
764 if(index == nright-2)
765 alpha = (step > 0) ? 128+fade/2 : fade/2;
766 if(index == nright-3)
767 alpha = (step > 0) ? 256 : 128+fade/2;
768 QRect rs = renderSlide(rightSlides[index], alpha, c2+1, buffer.width());
769 if(!rs.isEmpty())
770 c2 = rs.right();
771 }
772
773 QPainter painter;
774 painter.begin(&buffer);
775
776 QFont font("Arial", captionFontSize);
777 font.setBold(true);
778 painter.setFont(font);
779
780 int leftTextIndex = (step>0) ? centerIndex : centerIndex-1;
781
782 painter.setPen(QColor(255,255,255, (255-fade) ));
783 painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
784 Qt::AlignCenter, captions[leftTextIndex]);
785
786 painter.setPen(QColor(255,255,255, fade));
787 painter.drawText( QRect(0,0, buffer.width(), (buffer.height() - slideSize().height())/4),
788 Qt::AlignCenter, captions[leftTextIndex+1]);
789
790 painter.end();
791 }
792}
793
794
795static inline uint BYTE_MUL_RGB16(uint x, uint a) {
796 a += 1;
797 uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0;
798 t |= (((x & 0xf81f)*(a>>2)) >> 6) & 0xf81f;
799 return t;
800}
801
802static inline uint BYTE_MUL_RGB16_32(uint x, uint a) {
803 uint t = (((x & 0xf81f07e0) >> 5)*a) & 0xf81f07e0;
804 t |= (((x & 0x07e0f81f)*a) >> 5) & 0x07e0f81f;
805 return t;
806}
807
808
809// Renders a slide to offscreen buffer. Returns a rect of the rendered area.
810// alpha=256 means normal, alpha=0 is fully black, alpha=128 half transparent
811// col1 and col2 limit the column for rendering.
812QRect PictureFlowPrivate::renderSlide(const SlideInfo &slide, int alpha,
813int col1, int col2)
814{
815 QImage* src = surface(slide.slideIndex);
816 if(!src)
817 return QRect();
818
819 QRect rect(0, 0, 0, 0);
820
821#ifdef PICTUREFLOW_BILINEAR_FILTER
822 int sw = src->height() / BILINEAR_STRETCH_HOR;
823 int sh = src->width() / BILINEAR_STRETCH_VER;
824#else
825 int sw = src->height();
826 int sh = src->width();
827#endif
828 int h = buffer.height();
829 int w = buffer.width();
830
831 if(col1 > col2)
832 {
833 int c = col2;
834 col2 = col1;
835 col1 = c;
836 }
837
838 col1 = (col1 >= 0) ? col1 : 0;
839 col2 = (col2 >= 0) ? col2 : w-1;
840 col1 = qMin(col1, w-1);
841 col2 = qMin(col2, w-1);
842
843 int distance = h * 100 / zoom;
844 PFreal sdx = fcos(slide.angle);
845 PFreal sdy = fsin(slide.angle);
846 PFreal xs = slide.cx - slideWidth * sdx/2;
847 PFreal ys = slide.cy - slideWidth * sdy/2;
848 PFreal dist = distance * PFREAL_ONE;
849
850 int xi = qMax((PFreal)0, ((w*PFREAL_ONE/2) + fdiv(xs*h, dist+ys)) >> PFREAL_SHIFT);
851 if(xi >= w)
852 return rect;
853
854 bool flag = false;
855 rect.setLeft(xi);
856 for(int x = qMax(xi, col1); x <= col2; x++)
857 {
858 PFreal hity = 0;
859 PFreal fk = rays[x];
860 if(sdy)
861 {
862 fk = fk - fdiv(sdx,sdy);
863 hity = -fdiv((rays[x]*distance - slide.cx + slide.cy*sdx/sdy), fk);
864 }
865
866 dist = distance*PFREAL_ONE + hity;
867 if(dist < 0)
868 continue;
869
870 PFreal hitx = fmul(dist, rays[x]);
871 PFreal hitdist = fdiv(hitx - slide.cx, sdx);
872
873#ifdef PICTUREFLOW_BILINEAR_FILTER
874 int column = sw*BILINEAR_STRETCH_HOR/2 + (hitdist*BILINEAR_STRETCH_HOR >> PFREAL_SHIFT);
875 if(column >= sw*BILINEAR_STRETCH_HOR)
876 break;
877#else
878 int column = sw/2 + (hitdist >> PFREAL_SHIFT);
879 if(column >= sw)
880 break;
881#endif
882 if(column < 0)
883 continue;
884
885 rect.setRight(x);
886 if(!flag)
887 rect.setLeft(x);
888 flag = true;
889
890 int y1 = h/2;
891 int y2 = y1+ 1;
892 QRgb565* pixel1 = (QRgb565*)(buffer.scanLine(y1)) + x;
893 QRgb565* pixel2 = (QRgb565*)(buffer.scanLine(y2)) + x;
894 int pixelstep = pixel2 - pixel1;
895
896#ifdef PICTUREFLOW_BILINEAR_FILTER
897 int center = (sh*BILINEAR_STRETCH_VER/2);
898 int dy = dist*BILINEAR_STRETCH_VER / h;
899#else
900 int center = (sh/2);
901 int dy = dist / h;
902#endif
903 int p1 = center*PFREAL_ONE - dy/2;
904 int p2 = center*PFREAL_ONE + dy/2;
905
906 const QRgb565 *ptr = (const QRgb565*)(src->scanLine(column));
907 if(alpha == 256)
908 while((y1 >= 0) && (y2 < h) && (p1 >= 0))
909 {
910 *pixel1 = ptr[p1 >> PFREAL_SHIFT];
911 *pixel2 = ptr[p2 >> PFREAL_SHIFT];
912 p1 -= dy;
913 p2 += dy;
914 y1--;
915 y2++;
916 pixel1 -= pixelstep;
917 pixel2 += pixelstep;
918 }
919 else
920 while((y1 >= 0) && (y2 < h) && (p1 >= 0))
921 {
922 QRgb565 c1 = ptr[p1 >> PFREAL_SHIFT];
923 QRgb565 c2 = ptr[p2 >> PFREAL_SHIFT];
924
925 *pixel1 = BYTE_MUL_RGB16(c1, alpha);
926 *pixel2 = BYTE_MUL_RGB16(c2, alpha);
927
928/*
929 int r1 = qRed(c1) * alpha/256;
930 int g1 = qGreen(c1) * alpha/256;
931 int b1 = qBlue(c1) * alpha/256;
932 int r2 = qRed(c2) * alpha/256;
933 int g2 = qGreen(c2) * alpha/256;
934 int b2 = qBlue(c2) * alpha/256;
935 *pixel1 = qRgb(r1, g1, b1);
936 *pixel2 = qRgb(r2, g2, b2);
937*/
938 p1 -= dy;
939 p2 += dy;
940 y1--;
941 y2++;
942 pixel1 -= pixelstep;
943 pixel2 += pixelstep;
944 }
945 }
946
947 rect.setTop(0);
948 rect.setBottom(h-1);
949 return rect;
950}
951
952// Updates look-up table and other stuff necessary for the rendering.
953// Call this when the viewport size or slide dimension is changed.
954void PictureFlowPrivate::recalc(int ww, int wh)
955{
956 int w = (ww+1)/2;
957 int h = (wh+1)/2;
958 buffer = QImage(ww, wh, QImage::Format_RGB16);
959 buffer.fill(0);
960
961 rays.resize(w*2);
962
963 for(int i = 0; i < w; i++)
964 {
965 PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2*h);
966 rays[w-i-1] = -gg;
967 rays[w+i] = gg;
968 }
969
970 // pointer must move more than 1/15 of the window to enter drag mode
971 singlePressThreshold = ww / 15;
972// qDebug() << "singlePressThreshold now set to " << singlePressThreshold;
973
974 pixelsToMovePerSlide = ww / 3;
975// qDebug() << "pixelsToMovePerSlide now set to " << pixelsToMovePerSlide;
976
977 itilt = 80 * IANGLE_MAX / 360; // approx. 80 degrees tilted
978
979 offsetY = slideWidth/2 * fsin(itilt);
980 offsetY += slideWidth * PFREAL_ONE / 4;
981
982// offsetX = slideWidth/2 * (PFREAL_ONE-fcos(itilt));
983// offsetX += slideWidth * PFREAL_ONE;
984
985 // center slide + side slide
986 offsetX = slideWidth*PFREAL_ONE;
987// offsetX = 150*PFREAL_ONE;//(slideWidth/2)*PFREAL_ONE + ( slideWidth*fcos(itilt) )/2;
988// qDebug() << "center width = " << slideWidth;
989// qDebug() << "side width = " << fixedToFloat(slideWidth/2 * (PFREAL_ONE-fcos(itilt)));
990// qDebug() << "offsetX now " << fixedToFloat(offsetX);
991
992 spacing = slideWidth/5;
993
994 surfaceCache.clear();
995 blankSurface = QImage();
996}
997
998void PictureFlowPrivate::startAnimation()
999{
1000 if(!animateTimer.isActive())
1001 {
1002 step = (target < centerSlide.slideIndex) ? -1 : 1;
1003 animateTimer.start(30, widget);
1004 }
1005}
1006
1007// Updates the animation effect. Call this periodically from a timer.
1008void PictureFlowPrivate::updateAnimation()
1009{
1010 if(!animateTimer.isActive())
1011 return;
1012 if(step == 0)
1013 return;
1014
1015 int speed = 16384;
1016
1017 // deaccelerate when approaching the target
1018 if(true)
1019 {
1020 const int max = 2 * 65536;
1021
1022 int fi = slideFrame;
1023 fi -= (target << 16);
1024 if(fi < 0)
1025 fi = -fi;
1026 fi = qMin(fi, max);
1027
1028 int ia = IANGLE_MAX * (fi-max/2) / (max*2);
1029 speed = 512 + 16384 * (PFREAL_ONE+fsin(ia))/PFREAL_ONE;
1030 }
1031
1032 slideFrame += speed*step;
1033
1034 int index = slideFrame >> 16;
1035 int pos = slideFrame & 0xffff;
1036 int neg = 65536 - pos;
1037 int tick = (step < 0) ? neg : pos;
1038 PFreal ftick = (tick * PFREAL_ONE) >> 16;
1039
1040 // the leftmost and rightmost slide must fade away
1041 fade = pos / 256;
1042
1043 if(step < 0)
1044 index++;
1045 if(centerIndex != index)
1046 {
1047 centerIndex = index;
1048 slideFrame = index << 16;
1049 centerSlide.slideIndex = centerIndex;
1050 for(int i = 0; i < leftSlides.count(); i++)
1051 leftSlides[i].slideIndex = centerIndex-1-i;
1052 for(int i = 0; i < rightSlides.count(); i++)
1053 rightSlides[i].slideIndex = centerIndex+1+i;
1054 }
1055
1056 centerSlide.angle = (step * tick * itilt) >> 16;
1057 centerSlide.cx = -step * fmul(offsetX, ftick);
1058 centerSlide.cy = fmul(offsetY, ftick);
1059
1060 if(centerIndex == target)
1061 {
1062 resetSlides();
1063 animateTimer.stop();
1064 triggerRender();
1065 step = 0;
1066 fade = 256;
1067 return;
1068 }
1069
1070 for(int i = 0; i < leftSlides.count(); i++)
1071 {
1072 SlideInfo& si = leftSlides[i];
1073 si.angle = itilt;
1074 si.cx = -(offsetX + spacing*i*PFREAL_ONE + step*spacing*ftick);
1075 si.cy = offsetY;
1076 }
1077
1078 for(int i = 0; i < rightSlides.count(); i++)
1079 {
1080 SlideInfo& si = rightSlides[i];
1081 si.angle = -itilt;
1082 si.cx = offsetX + spacing*i*PFREAL_ONE - step*spacing*ftick;
1083 si.cy = offsetY;
1084 }
1085
1086 if(step > 0)
1087 {
1088 PFreal ftick = (neg * PFREAL_ONE) >> 16;
1089 rightSlides[0].angle = -(neg * itilt) >> 16;
1090 rightSlides[0].cx = fmul(offsetX, ftick);
1091 rightSlides[0].cy = fmul(offsetY, ftick);
1092 }
1093 else
1094 {
1095 PFreal ftick = (pos * PFREAL_ONE) >> 16;
1096 leftSlides[0].angle = (pos * itilt) >> 16;
1097 leftSlides[0].cx = -fmul(offsetX, ftick);
1098 leftSlides[0].cy = fmul(offsetY, ftick);
1099 }
1100
1101 // must change direction ?
1102 if(target < index) if(step > 0)
1103 step = -1;
1104 if(target > index) if(step < 0)
1105 step = 1;
1106
1107 triggerRender();
1108}
1109
1110
1111void PictureFlowPrivate::clearSurfaceCache()
1112{
1113 surfaceCache.clear();
1114}
1115
1116// -----------------------------------------
1117
1118PictureFlow::PictureFlow(QWidget* parent): QWidget(parent)
1119{
1120 d = new PictureFlowPrivate(this);
1121
1122 setAttribute(Qt::WA_StaticContents, true);
1123 setAttribute(Qt::WA_OpaquePaintEvent, true);
1124 setAttribute(Qt::WA_NoSystemBackground, true);
1125
1126#ifdef Q_WS_QWS
1127 if (QScreen::instance()->pixelFormat() != QImage::Format_Invalid)
1128 setAttribute(Qt::WA_PaintOnScreen, true);
1129#endif
1130}
1131
1132PictureFlow::~PictureFlow()
1133{
1134 delete d;
1135}
1136
1137int PictureFlow::slideCount() const
1138{
1139 return d->slideCount();
1140}
1141
1142void PictureFlow::setSlideCount(int count)
1143{
1144 d->setSlideCount(count);
1145}
1146
1147QSize PictureFlow::slideSize() const
1148{
1149 return d->slideSize();
1150}
1151
1152void PictureFlow::setSlideSize(QSize size)
1153{
1154 d->setSlideSize(size);
1155}
1156
1157int PictureFlow::zoomFactor() const
1158{
1159 return d->zoomFactor();
1160}
1161
1162void PictureFlow::setZoomFactor(int z)
1163{
1164 d->setZoomFactor(z);
1165}
1166
1167QImage PictureFlow::slide(int index) const
1168{
1169 return d->slide(index);
1170}
1171
1172void PictureFlow::setSlide(int index, const QImage& image)
1173{
1174 d->setSlide(index, image);
1175}
1176
1177void PictureFlow::setSlide(int index, const QPixmap& pixmap)
1178{
1179 d->setSlide(index, pixmap.toImage());
1180}
1181
1182void PictureFlow::setSlideCaption(int index, QString caption)
1183{
1184 d->captions[index] = caption;
1185}
1186
1187
1188int PictureFlow::currentSlide() const
1189{
1190 return d->currentSlide();
1191}
1192
1193void PictureFlow::setCurrentSlide(int index)
1194{
1195 d->setCurrentSlide(index);
1196}
1197
1198void PictureFlow::clear()
1199{
1200 d->setSlideCount(0);
1201}
1202
1203void PictureFlow::clearCaches()
1204{
1205 d->clearSurfaceCache();
1206}
1207
1208void PictureFlow::render()
1209{
1210 d->render();
1211 update();
1212}
1213
1214void PictureFlow::showPrevious()
1215{
1216 d->showPrevious();
1217}
1218
1219void PictureFlow::showNext()
1220{
1221 d->showNext();
1222}
1223
1224void PictureFlow::showSlide(int index)
1225{
1226 d->showSlide(index);
1227}
1228
1229void PictureFlow::keyPressEvent(QKeyEvent* event)
1230{
1231 if(event->key() == Qt::Key_Left)
1232 {
1233 if(event->modifiers() == Qt::ControlModifier)
1234 showSlide(currentSlide()-10);
1235 else
1236 showPrevious();
1237 event->accept();
1238 return;
1239 }
1240
1241 if(event->key() == Qt::Key_Right)
1242 {
1243 if(event->modifiers() == Qt::ControlModifier)
1244 showSlide(currentSlide()+10);
1245 else
1246 showNext();
1247 event->accept();
1248 return;
1249 }
1250
1251 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Select) {
1252 emit itemActivated(d->getTarget());
1253 event->accept();
1254 return;
1255 }
1256
1257 event->ignore();
1258}
1259
1260#define SPEED_LOWER_THRESHOLD 10
1261#define SPEED_UPPER_LIMIT 40
1262
1263void PictureFlow::mouseMoveEvent(QMouseEvent* event)
1264{
1265 int distanceMovedSinceLastEvent = event->pos().x() - d->previousPos.x();
1266
1267 // Check to see if we need to switch from single press mode to a drag mode
1268 if (d->singlePress)
1269 {
1270 // Increment the distance moved for this event
1271 d->pixelDistanceMoved += distanceMovedSinceLastEvent;
1272
1273 // Check against threshold
1274 if (qAbs(d->pixelDistanceMoved) > d->singlePressThreshold)
1275 {
1276 d->singlePress = false;
1277// qDebug() << "DRAG MODE ON";
1278 }
1279 }
1280
1281 if (!d->singlePress)
1282 {
1283 int speed;
1284 // Calculate velocity in a 10th of a window width per second
1285 if (d->previousPosTimestamp.elapsed() == 0)
1286 speed = SPEED_LOWER_THRESHOLD;
1287 else
1288 {
1289 speed = ((qAbs(event->pos().x()-d->previousPos.x())*1000) / d->previousPosTimestamp.elapsed())
1290 / (d->buffer.width() / 10);
1291
1292 if (speed < SPEED_LOWER_THRESHOLD)
1293 speed = SPEED_LOWER_THRESHOLD;
1294 else if (speed > SPEED_UPPER_LIMIT)
1295 speed = SPEED_UPPER_LIMIT;
1296 else {
1297 speed = SPEED_LOWER_THRESHOLD + (speed / 3);
1298// qDebug() << "ACCELERATION ENABLED Speed = " << speed << ", Distance = " << distanceMovedSinceLastEvent;
1299 }
1300 }
1301
1302// qDebug() << "Speed = " << speed;
1303
1304// int incr = ((event->pos().x() - d->previousPos.x())/10) * speed;
1305
1306// qDebug() << "Incremented by " << incr;
1307
1308 int incr = (distanceMovedSinceLastEvent * speed);
1309
1310 //qDebug() << "(distanceMovedSinceLastEvent * speed) = " << incr;
1311
1312 if (incr > d->pixelsToMovePerSlide*2) {
1313 incr = d->pixelsToMovePerSlide*2;
1314 //qDebug() << "Limiting incr to " << incr;
1315 }
1316
1317
1318 d->pixelDistanceMoved += (distanceMovedSinceLastEvent * speed);
1319 // qDebug() << "distance: " << d->pixelDistanceMoved;
1320
1321 int slideInc;
1322
1323 slideInc = d->pixelDistanceMoved / (d->pixelsToMovePerSlide * 10);
1324
1325 if (slideInc != 0) {
1326 int targetSlide = d->getTarget() - slideInc;
1327 showSlide(targetSlide);
1328// qDebug() << "TargetSlide = " << targetSlide;
1329
1330 //qDebug() << "Decrementing pixelDistanceMoved by " << (d->pixelsToMovePerSlide *10) * slideInc;
1331
1332 d->pixelDistanceMoved -= (d->pixelsToMovePerSlide *10) * slideInc;
1333
1334/*
1335 if ( (targetSlide <= 0) || (targetSlide >= d->slideCount()-1) )
1336 d->pixelDistanceMoved = 0;
1337*/
1338 }
1339 }
1340
1341 d->previousPos = event->pos();
1342 d->previousPosTimestamp.restart();
1343
1344 emit inputReceived();
1345}
1346
1347void PictureFlow::mousePressEvent(QMouseEvent* event)
1348{
1349 d->firstPress = event->pos();
1350 d->previousPos = event->pos();
1351 d->previousPosTimestamp.start();
1352 d->singlePress = true; // Initially assume a single press
1353// d->dragStartSlide = d->getTarget();
1354 d->pixelDistanceMoved = 0;
1355
1356 emit inputReceived();
1357}
1358
1359void PictureFlow::mouseReleaseEvent(QMouseEvent* event)
1360{
1361 int sideWidth = (d->buffer.width() - slideSize().width()) /2;
1362
1363 if (d->singlePress)
1364 {
1365 if (event->x() < sideWidth )
1366 {
1367 showPrevious();
1368 } else if ( event->x() > sideWidth + slideSize().width() ) {
1369 showNext();
1370 } else {
1371 emit itemActivated(d->getTarget());
1372 }
1373
1374 event->accept();
1375 }
1376
1377 emit inputReceived();
1378}
1379
1380
1381void PictureFlow::paintEvent(QPaintEvent* event)
1382{
1383 Q_UNUSED(event);
1384 QPainter painter(this);
1385 painter.setRenderHint(QPainter::Antialiasing, false);
1386 painter.drawImage(QPoint(0,0), d->buffer);
1387}
1388
1389void PictureFlow::resizeEvent(QResizeEvent* event)
1390{
1391 d->resize(width(), height());
1392 QWidget::resizeEvent(event);
1393}
1394
1395void PictureFlow::timerEvent(QTimerEvent* event)
1396{
1397 if(event->timerId() == d->animateTimer.timerId())
1398 {
1399// QTime now = QTime::currentTime();
1400 d->updateAnimation();
1401// d->animateTimer.start(qMax(0, 30-now.elapsed() ), this);
1402 }
1403 else
1404 QWidget::timerEvent(event);
1405}
Note: See TracBrowser for help on using the repository browser.