demos/embedded/fluidlauncher/pictureflow.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     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 (ariya@kde.org)
       
    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 
       
    86 static 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
       
   100 typedef long PFreal;
       
   101 
       
   102 typedef 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 
       
   117 inline PFreal fmul(PFreal a, PFreal b)
       
   118 {
       
   119   return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
       
   120 }
       
   121 
       
   122 inline 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 
       
   131 inline float fixedToFloat(PFreal val)
       
   132 {
       
   133   return ((float)val) / (float)PFREAL_ONE;
       
   134 }
       
   135 
       
   136 inline 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!
       
   145 static 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 
       
   288 int 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 
       
   311 inline PFreal fsin(int iangle)
       
   312 {
       
   313   while(iangle < 0)
       
   314     iangle += IANGLE_MAX;
       
   315   return sinTable[iangle & IANGLE_MASK];
       
   316 }
       
   317 
       
   318 inline PFreal fcos(int iangle)
       
   319 {
       
   320   // quarter phase shift
       
   321   return fsin(iangle + (IANGLE_MAX >> 2));
       
   322 }
       
   323 
       
   324 struct SlideInfo
       
   325 {
       
   326   int slideIndex;
       
   327   int angle;
       
   328   PFreal cx;
       
   329   PFreal cy;
       
   330 };
       
   331 
       
   332 class PictureFlowPrivate
       
   333 {
       
   334 public:
       
   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 
       
   379 private:
       
   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 
       
   414 PictureFlowPrivate::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 
       
   437 int PictureFlowPrivate::slideCount() const
       
   438 {
       
   439   return slideImages.count();
       
   440 }
       
   441 
       
   442 void PictureFlowPrivate::setSlideCount(int count)
       
   443 {
       
   444   slideImages.resize(count);
       
   445   captions.resize(count);
       
   446   surfaceCache.clear();
       
   447   resetSlides();
       
   448   triggerRender();
       
   449 }
       
   450 
       
   451 QSize PictureFlowPrivate::slideSize() const
       
   452 {
       
   453   return QSize(slideWidth, slideHeight);
       
   454 }
       
   455 
       
   456 void PictureFlowPrivate::setSlideSize(QSize size)
       
   457 {
       
   458   slideWidth = size.width();
       
   459   slideHeight = size.height();
       
   460   recalc(buffer.width(), buffer.height());
       
   461   triggerRender();
       
   462 }
       
   463 
       
   464 int PictureFlowPrivate::zoomFactor() const
       
   465 {
       
   466   return zoom;
       
   467 }
       
   468 
       
   469 void 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 
       
   479 QImage PictureFlowPrivate::slide(int index) const
       
   480 {
       
   481   return slideImages[index];
       
   482 }
       
   483 
       
   484 void 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 
       
   494 int PictureFlowPrivate::getTarget() const
       
   495 {
       
   496   return target;
       
   497 }
       
   498 
       
   499 int PictureFlowPrivate::currentSlide() const
       
   500 {
       
   501   return centerIndex;
       
   502 }
       
   503 
       
   504 void 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 
       
   514 void 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 
       
   530 void 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 
       
   546 void 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 
       
   557 void 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
       
   566 void 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 
       
   601 static 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 accomodate 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
       
   648 QImage* 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.
       
   690 void PictureFlowPrivate::triggerRender()
       
   691 {
       
   692   triggerTimer.start();
       
   693 }
       
   694 
       
   695 // Render the slides. Updates only the offscreen buffer.
       
   696 void 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 
       
   795 static 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 
       
   802 static 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.
       
   812 QRect PictureFlowPrivate::renderSlide(const SlideInfo &slide, int alpha, 
       
   813 int 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.
       
   954 void 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 
       
   998 void 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.
       
  1008 void 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 
       
  1111 void PictureFlowPrivate::clearSurfaceCache()
       
  1112 {
       
  1113   surfaceCache.clear();
       
  1114 }
       
  1115 
       
  1116 // -----------------------------------------
       
  1117 
       
  1118 PictureFlow::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 
       
  1132 PictureFlow::~PictureFlow()
       
  1133 {
       
  1134   delete d;
       
  1135 }
       
  1136 
       
  1137 int PictureFlow::slideCount() const
       
  1138 {
       
  1139   return d->slideCount();
       
  1140 }
       
  1141 
       
  1142 void PictureFlow::setSlideCount(int count)
       
  1143 {
       
  1144   d->setSlideCount(count);
       
  1145 }
       
  1146 
       
  1147 QSize PictureFlow::slideSize() const
       
  1148 {
       
  1149   return d->slideSize();
       
  1150 }
       
  1151 
       
  1152 void PictureFlow::setSlideSize(QSize size)
       
  1153 {
       
  1154   d->setSlideSize(size);
       
  1155 }
       
  1156 
       
  1157 int PictureFlow::zoomFactor() const
       
  1158 {
       
  1159   return d->zoomFactor();
       
  1160 }
       
  1161 
       
  1162 void PictureFlow::setZoomFactor(int z)
       
  1163 {
       
  1164   d->setZoomFactor(z);
       
  1165 }
       
  1166 
       
  1167 QImage PictureFlow::slide(int index) const
       
  1168 {
       
  1169   return d->slide(index);
       
  1170 }
       
  1171 
       
  1172 void PictureFlow::setSlide(int index, const QImage& image)
       
  1173 {
       
  1174   d->setSlide(index, image);
       
  1175 }
       
  1176 
       
  1177 void PictureFlow::setSlide(int index, const QPixmap& pixmap)
       
  1178 {
       
  1179   d->setSlide(index, pixmap.toImage());
       
  1180 }
       
  1181 
       
  1182 void PictureFlow::setSlideCaption(int index, QString caption)
       
  1183 {
       
  1184   d->captions[index] = caption;
       
  1185 }
       
  1186 
       
  1187 
       
  1188 int PictureFlow::currentSlide() const
       
  1189 {
       
  1190   return d->currentSlide();
       
  1191 }
       
  1192 
       
  1193 void PictureFlow::setCurrentSlide(int index)
       
  1194 {
       
  1195   d->setCurrentSlide(index);
       
  1196 }
       
  1197 
       
  1198 void PictureFlow::clear()
       
  1199 {
       
  1200   d->setSlideCount(0);
       
  1201 }
       
  1202 
       
  1203 void PictureFlow::clearCaches()
       
  1204 {
       
  1205   d->clearSurfaceCache();
       
  1206 }
       
  1207 
       
  1208 void PictureFlow::render()
       
  1209 {
       
  1210   d->render();
       
  1211   update();
       
  1212 }
       
  1213 
       
  1214 void PictureFlow::showPrevious()
       
  1215 {
       
  1216   d->showPrevious();
       
  1217 }
       
  1218 
       
  1219 void PictureFlow::showNext()
       
  1220 {
       
  1221   d->showNext();
       
  1222 }
       
  1223 
       
  1224 void PictureFlow::showSlide(int index)
       
  1225 {
       
  1226   d->showSlide(index);
       
  1227 }
       
  1228 
       
  1229 void 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 
       
  1263 void 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 
       
  1347 void 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 
       
  1359 void 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 
       
  1381 void 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 
       
  1389 void PictureFlow::resizeEvent(QResizeEvent* event)
       
  1390 {
       
  1391   d->resize(width(), height());
       
  1392   QWidget::resizeEvent(event);
       
  1393 }
       
  1394 
       
  1395 void 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 }