browsercore/appfw/Common/PictureFlow.cpp
changeset 16 3c88a81ff781
parent 14 6aeb7a756187
equal deleted inserted replaced
14:6aeb7a756187 16:3c88a81ff781
     1 /*
       
     2   PictureFlow - animated image show widget
       
     3   http://pictureflow.googlecode.com
       
     4   
       
     5   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     6   Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
       
     7   Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
       
     8 
       
     9   Permission is hereby granted, free of charge, to any person obtaining a copy
       
    10   of this software and associated documentation files (the "Software"), to deal
       
    11   in the Software without restriction, including without limitation the rights
       
    12   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    13   copies of the Software, and to permit persons to whom the Software is
       
    14   furnished to do so, subject to the following conditions:
       
    15 
       
    16   The above copyright notice and this permission notice shall be included in
       
    17   all copies or substantial portions of the Software.
       
    18 
       
    19   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    20   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    21   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       
    22   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    23   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    24   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    25   THE SOFTWARE.
       
    26 */
       
    27 
       
    28 #include "PictureFlow.h"
       
    29 
       
    30 // detect Qt version
       
    31 #if QT_VERSION >= 0x040000
       
    32 #define PICTUREFLOW_QT4
       
    33 #elif QT_VERSION >= 0x030000
       
    34 #define PICTUREFLOW_QT3
       
    35 #elif QT_VERSION >= 235
       
    36 #define PICTUREFLOW_QT2
       
    37 #else
       
    38 #error PictureFlow widgets need Qt 2, Qt 3 or Qt 4
       
    39 #endif
       
    40 
       
    41 #include <QGraphicsSceneResizeEvent>
       
    42 #include <QGraphicsSceneMouseEvent>
       
    43 #include <QGraphicsSceneMoveEvent>
       
    44 
       
    45 #ifdef PICTUREFLOW_QT4
       
    46 #include <QApplication>
       
    47 #include <QCache>
       
    48 #include <QHash>
       
    49 #include <QImage>
       
    50 #include <QKeyEvent>
       
    51 #include <QPainter>
       
    52 #include <QPixmap>
       
    53 #include <QTimer>
       
    54 #include <QVector>
       
    55 #include <QWidget>
       
    56 #endif
       
    57 
       
    58 #include <QDebug>
       
    59 
       
    60 #ifdef PICTUREFLOW_QT3
       
    61 #include <qapplication.h>
       
    62 #include <qcache.h>
       
    63 #include <qimage.h>
       
    64 #include <qpainter.h>
       
    65 #include <qpixmap.h>
       
    66 #include <qdatetime.h>
       
    67 #include <qtimer.h>
       
    68 #include <qvaluevector.h>
       
    69 #include <qwidget.h>
       
    70 
       
    71 #define qMax(x,y) ((x) > (y)) ? (x) : (y)
       
    72 #define qMin(x,y) ((x) < (y)) ? (x) : (y)
       
    73 
       
    74 #define QVector QValueVector
       
    75 
       
    76 #define toImage convertToImage
       
    77 #define contains find
       
    78 #define modifiers state
       
    79 #define ControlModifier ControlButton
       
    80 #endif
       
    81 
       
    82 #ifdef PICTUREFLOW_QT2
       
    83 #include <qapplication.h>
       
    84 #include <qarray.h>
       
    85 #include <qcache.h>
       
    86 #include <qimage.h>
       
    87 #include <qintdict.h>
       
    88 #include <qpainter.h>
       
    89 #include <qpixmap.h>
       
    90 #include <qdatetime.h>
       
    91 #include <qtimer.h>
       
    92 #include <qwidget.h>
       
    93 
       
    94 #define qMax(x,y) ((x) > (y)) ? (x) : (y)
       
    95 #define qMin(x,y) ((x) < (y)) ? (x) : (y)
       
    96 
       
    97 #define QVector QArray
       
    98 
       
    99 #define toImage convertToImage
       
   100 #define contains find
       
   101 #define modifiers state
       
   102 #define ControlModifier ControlButton
       
   103 #define flush flushX
       
   104 #endif
       
   105 
       
   106 // for fixed-point arithmetic, we need minimum 32-bit long
       
   107 // long long (64-bit) might be useful for multiplication and division
       
   108 typedef long PFreal;
       
   109 #define PFREAL_SHIFT 10
       
   110 #define PFREAL_ONE (1 << PFREAL_SHIFT)
       
   111 
       
   112 #define IANGLE_MAX 1024
       
   113 #define IANGLE_MASK 1023
       
   114 
       
   115 namespace WRT {
       
   116 
       
   117 const int slideRatio1 = 2;
       
   118 const int slideRatio2 = 5;
       
   119 const int KScrollTimeout = 250;
       
   120 
       
   121 inline PFreal fmul(PFreal a, PFreal b)
       
   122 {
       
   123   return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
       
   124 }
       
   125 
       
   126 inline PFreal fdiv(PFreal num, PFreal den)
       
   127 {
       
   128   long long p = (long long)(num) << (PFREAL_SHIFT*2);
       
   129   long long q = p / (long long)den;
       
   130   long long r = q >> PFREAL_SHIFT;
       
   131 
       
   132   return r;
       
   133 }
       
   134 
       
   135 inline PFreal fsin(int iangle)
       
   136 {
       
   137   // warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed!
       
   138   static const PFreal tab[] = {
       
   139      3,    103,    202,    300,    394,    485,    571,    652,
       
   140    726,    793,    853,    904,    947,    980,   1004,   1019,
       
   141   1023,   1018,   1003,    978,    944,    901,    849,    789,
       
   142    721,    647,    566,    479,    388,    294,    196,     97,
       
   143     -4,   -104,   -203,   -301,   -395,   -486,   -572,   -653,
       
   144   -727,   -794,   -854,   -905,   -948,   -981,  -1005,  -1020,
       
   145  -1024,  -1019,  -1004,   -979,   -945,   -902,   -850,   -790,
       
   146   -722,   -648,   -567,   -480,   -389,   -295,   -197,    -98,
       
   147   3
       
   148   };
       
   149 
       
   150   while(iangle < 0)
       
   151     iangle += IANGLE_MAX;
       
   152   iangle &= IANGLE_MASK;
       
   153 
       
   154   int i = (iangle >> 4);
       
   155   PFreal p = tab[i];
       
   156   PFreal q = tab[(i+1)];
       
   157   PFreal g = (q - p);
       
   158   return p + g * (iangle-i*16)/16;
       
   159 }
       
   160 
       
   161 inline PFreal fcos(int iangle)
       
   162 {
       
   163   return fsin(iangle + (IANGLE_MAX >> 2));
       
   164 }
       
   165 
       
   166 /* ----------------------------------------------------------
       
   167 
       
   168 PictureFlowState stores the state of all slides, i.e. all the necessary
       
   169 information to be able to render them.
       
   170 
       
   171 PictureFlowAnimator is responsible to move the slides during the
       
   172 transition between slides, to achieve the effect similar to Cover Flow,
       
   173 by changing the state.
       
   174 
       
   175 PictureFlowSoftwareRenderer (or PictureFlowOpenGLRenderer) is
       
   176 the actual 3-d renderer. It should render all slides given the state
       
   177 (an instance of PictureFlowState).
       
   178 
       
   179 Instances of all the above three classes are stored in
       
   180 PictureFlowPrivate.
       
   181 
       
   182 ------------------------------------------------------- */
       
   183 
       
   184 struct SlideInfo
       
   185 {
       
   186   int slideIndex;
       
   187   int angle;
       
   188   PFreal cx;
       
   189   PFreal cy;
       
   190   int blend;
       
   191 };
       
   192 
       
   193 class PictureFlowState
       
   194 {
       
   195 public:
       
   196   PictureFlowState();
       
   197   ~PictureFlowState();
       
   198 
       
   199   void reposition();
       
   200   void reset();
       
   201 
       
   202   QRgb backgroundColor;
       
   203   int slideWidth;
       
   204   int slideHeight;
       
   205   ReflectionEffect reflectionEffect;
       
   206   QVector<QImage*> slideImages;
       
   207 
       
   208   int angle;
       
   209   int spacing;
       
   210   PFreal offsetX;
       
   211   PFreal offsetY;
       
   212 
       
   213   SlideInfo centerSlide;
       
   214   QVector<SlideInfo> leftSlides;
       
   215   QVector<SlideInfo> rightSlides;
       
   216   int centerIndex;
       
   217 };
       
   218 
       
   219 class PictureFlowAnimator
       
   220 {
       
   221 public:
       
   222   PictureFlowAnimator();
       
   223   PictureFlowState* state;
       
   224 
       
   225   void start(int slide);
       
   226   void stop(int slide);
       
   227   void update();
       
   228 
       
   229   int target;
       
   230   int step;
       
   231   int frame;
       
   232   QTimer animateTimer;
       
   233 };
       
   234 
       
   235 class PictureFlowAbstractRenderer
       
   236 {
       
   237 public:
       
   238   PictureFlowAbstractRenderer(): state(0), dirty(false), widget(0), gWidget(0), gPainter(0) {}
       
   239   virtual ~PictureFlowAbstractRenderer() {}
       
   240 
       
   241   PictureFlowState* state;
       
   242   bool dirty;
       
   243   QWidget* widget;
       
   244   QGraphicsWidget* gWidget;
       
   245   QPainter* gPainter;
       
   246   QRect cRect; // central rect
       
   247 
       
   248   virtual void init() = 0;
       
   249   virtual void paint() = 0;
       
   250 };
       
   251 
       
   252 class PictureFlowSoftwareRenderer: public PictureFlowAbstractRenderer
       
   253 {
       
   254 public:
       
   255   PictureFlowSoftwareRenderer();
       
   256   ~PictureFlowSoftwareRenderer();
       
   257 
       
   258   virtual void init();
       
   259   virtual void paint();
       
   260 
       
   261   QRect renderSlide(const SlideInfo &slide, int col1 = -1, int col2 = -1);
       
   262 private:
       
   263   QSize size;
       
   264   QRgb bgcolor;
       
   265   int effect;
       
   266   QImage buffer;
       
   267   QVector<PFreal> rays;
       
   268   QImage* blankSurface;
       
   269 #ifdef PICTUREFLOW_QT4
       
   270   QCache<int,QImage> surfaceCache;
       
   271   QHash<int,QImage*> imageHash;
       
   272 #endif
       
   273 #ifdef PICTUREFLOW_QT3
       
   274   QCache<QImage> surfaceCache;
       
   275   QMap<int,QImage*> imageHash;
       
   276 #endif
       
   277 #ifdef PICTUREFLOW_QT2
       
   278   QCache<QImage> surfaceCache;
       
   279   QIntDict<QImage> imageHash;
       
   280 #endif
       
   281 
       
   282   void render();
       
   283   void renderSlides();
       
   284   QImage* surface(int slideIndex);
       
   285 };
       
   286 
       
   287 // ------------- PictureFlowState ---------------------------------------
       
   288 
       
   289 PictureFlowState::PictureFlowState():
       
   290 backgroundColor(0), slideWidth(150), slideHeight(200),
       
   291 reflectionEffect(BlurredReflection), centerIndex(0)
       
   292 {
       
   293 }
       
   294 
       
   295 PictureFlowState::~PictureFlowState()
       
   296 {
       
   297   for(int i = 0; i < (int)slideImages.count(); i++)
       
   298     delete slideImages[i];
       
   299 }
       
   300 
       
   301 // readjust the settings, call this when slide dimension is changed
       
   302 void PictureFlowState::reposition()
       
   303 {
       
   304   angle = 60*IANGLE_MAX / 360;
       
   305 
       
   306   offsetX = slideWidth/2 * (PFREAL_ONE-fcos(angle));
       
   307   offsetY = slideWidth/2 * fsin(angle);
       
   308   offsetX += slideWidth * PFREAL_ONE;
       
   309   offsetY += slideWidth * PFREAL_ONE / 4;
       
   310   spacing = 20;
       
   311 }
       
   312 
       
   313 // adjust slides so that they are in "steady state" position
       
   314 void PictureFlowState::reset()
       
   315 {
       
   316   centerSlide.angle = 0;
       
   317   centerSlide.cx = 0;
       
   318   centerSlide.cy = 0;
       
   319   centerSlide.slideIndex = centerIndex;
       
   320   centerSlide.blend = 256;
       
   321 
       
   322   leftSlides.resize(6);
       
   323   for(int i = 0; i < (int)leftSlides.count(); i++)
       
   324   {
       
   325     SlideInfo& si = leftSlides[i];
       
   326     si.angle = angle;
       
   327     si.cx = -(offsetX + spacing*i*PFREAL_ONE);
       
   328     si.cy = offsetY;
       
   329     si.slideIndex = centerIndex-1-i;
       
   330     si.blend = 256;
       
   331     if(i == (int)leftSlides.count()-2)
       
   332       si.blend = 128;
       
   333     if(i == (int)leftSlides.count()-1)
       
   334       si.blend = 0;
       
   335   }
       
   336 
       
   337   rightSlides.resize(6);
       
   338   for(int i = 0; i < (int)rightSlides.count(); i++)
       
   339   {
       
   340     SlideInfo& si = rightSlides[i];
       
   341     si.angle = -angle;
       
   342     si.cx = offsetX + spacing*i*PFREAL_ONE;
       
   343     si.cy = offsetY;
       
   344     si.slideIndex = centerIndex+1+i;
       
   345     si.blend = 256;
       
   346     if(i == (int)rightSlides.count()-2)
       
   347       si.blend = 128;
       
   348     if(i == (int)rightSlides.count()-1)
       
   349       si.blend = 0;
       
   350   }
       
   351 }
       
   352 
       
   353 // ------------- PictureFlowAnimator  ---------------------------------------
       
   354 
       
   355 PictureFlowAnimator::PictureFlowAnimator():
       
   356 state(0), target(0), step(0), frame(0)
       
   357 {
       
   358 }
       
   359 
       
   360 void PictureFlowAnimator::start(int slide)
       
   361 {
       
   362   target = slide;
       
   363   if(!animateTimer.isActive() && state)
       
   364   {
       
   365     step = (target < state->centerSlide.slideIndex) ? -1 : 1;
       
   366     animateTimer.start(30);
       
   367   }
       
   368 }
       
   369 
       
   370 void PictureFlowAnimator::stop(int slide)
       
   371 {
       
   372   step = 0;
       
   373   target = slide;
       
   374   frame = slide << 16;
       
   375   animateTimer.stop();
       
   376 }
       
   377 
       
   378 void PictureFlowAnimator::update()
       
   379 {
       
   380   if(!animateTimer.isActive())
       
   381     return;
       
   382   if(step == 0)
       
   383     return;
       
   384   if(!state)
       
   385     return;
       
   386 
       
   387   int speed = 16384/4;
       
   388 
       
   389 #if 1
       
   390   // deaccelerate when approaching the target
       
   391   // we disabled clicking until the animation is done so this has to be fast enough to not annoy users
       
   392   const int max = 65536 + 16384; // was 65536*2 but that was too slow when we disabled clicks
       
   393 
       
   394   int fi = frame;
       
   395   fi -= (target << 16);
       
   396   if(fi < 0)
       
   397     fi = -fi;
       
   398   fi = qMin(fi, max);
       
   399 
       
   400   int ia = IANGLE_MAX * (fi-max/2) / (max*2);
       
   401   speed = 512 + 16384 * (PFREAL_ONE+fsin(ia))/PFREAL_ONE;
       
   402 #endif
       
   403 
       
   404   frame += speed*step;
       
   405 
       
   406   int index = frame >> 16;
       
   407   int pos = frame & 0xffff;
       
   408   int neg = 65536 - pos;
       
   409   int tick = (step < 0) ? neg : pos;
       
   410   PFreal ftick = (tick * PFREAL_ONE) >> 16;
       
   411 
       
   412   if(step < 0)
       
   413     index++;
       
   414 
       
   415   if(state->centerIndex != index)
       
   416   {
       
   417     state->centerIndex = index;
       
   418     frame = index << 16;
       
   419     state->centerSlide.slideIndex = state->centerIndex;
       
   420     for(int i = 0; i < (int)state->leftSlides.count(); i++)
       
   421       state->leftSlides[i].slideIndex = state->centerIndex-1-i;
       
   422     for(int i = 0; i < (int)state->rightSlides.count(); i++)
       
   423       state->rightSlides[i].slideIndex = state->centerIndex+1+i;
       
   424   }
       
   425 
       
   426   state->centerSlide.angle = (step * tick * state->angle) >> 16;
       
   427   state->centerSlide.cx = -step * fmul(state->offsetX, ftick);
       
   428   state->centerSlide.cy = fmul(state->offsetY, ftick);
       
   429 
       
   430   if(state->centerIndex == target)
       
   431   {
       
   432     stop(target);
       
   433     state->reset();
       
   434     return;
       
   435   }
       
   436 
       
   437   for(int i = 0; i < (int)state->leftSlides.count(); i++)
       
   438   {
       
   439     SlideInfo& si = state->leftSlides[i];
       
   440     si.angle = state->angle;
       
   441     si.cx = -(state->offsetX + state->spacing*i*PFREAL_ONE + step*state->spacing*ftick);
       
   442     si.cy = state->offsetY;
       
   443   }
       
   444 
       
   445   for(int i = 0; i < (int)state->rightSlides.count(); i++)
       
   446   {
       
   447     SlideInfo& si = state->rightSlides[i];
       
   448     si.angle = -state->angle;
       
   449     si.cx = state->offsetX + state->spacing*i*PFREAL_ONE - step*state->spacing*ftick;
       
   450     si.cy = state->offsetY;
       
   451   }
       
   452 
       
   453   if(step > 0)
       
   454   {
       
   455     PFreal ftick = (neg * PFREAL_ONE) >> 16;
       
   456     state->rightSlides[0].angle = -(neg * state->angle) >> 16;
       
   457     state->rightSlides[0].cx = fmul(state->offsetX, ftick);
       
   458     state->rightSlides[0].cy = fmul(state->offsetY, ftick);
       
   459   }
       
   460   else
       
   461   {
       
   462     PFreal ftick = (pos * PFREAL_ONE) >> 16;
       
   463     state->leftSlides[0].angle = (pos * state->angle) >> 16;
       
   464     state->leftSlides[0].cx = -fmul(state->offsetX, ftick);
       
   465     state->leftSlides[0].cy = fmul(state->offsetY, ftick);
       
   466   }
       
   467 
       
   468   // must change direction ?
       
   469   if(target < index) if(step > 0)
       
   470     step = -1;
       
   471   if(target > index) if(step < 0)
       
   472     step = 1;
       
   473 
       
   474   // the first and last slide must fade in/fade out
       
   475   int nleft = state->leftSlides.count();
       
   476   int nright = state->rightSlides.count();
       
   477   int fade = pos / 256;
       
   478 
       
   479   for(int index = 0; index < nleft; index++)
       
   480   {
       
   481     int blend = 256;
       
   482     if(index == nleft-1)
       
   483       blend = (step > 0) ? 0 : 128-fade/2;
       
   484     if(index == nleft-2)
       
   485       blend = (step > 0) ? 128-fade/2 : 256-fade/2;
       
   486     if(index == nleft-3)
       
   487       blend = (step > 0) ? 256-fade/2 : 256;
       
   488     state->leftSlides[index].blend = blend;
       
   489   }
       
   490   for(int index = 0; index < nright; index++)
       
   491   {
       
   492     int blend = (index < nright-2) ? 256 : 128;
       
   493     if(index == nright-1)
       
   494       blend = (step > 0) ? fade/2 : 0;
       
   495     if(index == nright-2)
       
   496       blend = (step > 0) ? 128+fade/2 : fade/2;
       
   497     if(index == nright-3)
       
   498       blend = (step > 0) ? 256 : 128+fade/2;
       
   499     state->rightSlides[index].blend = blend;
       
   500   }
       
   501 }
       
   502 
       
   503 // ------------- PictureFlowSoftwareRenderer ---------------------------------------
       
   504 
       
   505 PictureFlowSoftwareRenderer::PictureFlowSoftwareRenderer():
       
   506 PictureFlowAbstractRenderer(), size(0,0), bgcolor(0), effect(-1), blankSurface(0)
       
   507 {
       
   508 #ifdef PICTUREFLOW_QT3
       
   509   surfaceCache.setAutoDelete(true);
       
   510 #endif
       
   511 }
       
   512 
       
   513 PictureFlowSoftwareRenderer::~PictureFlowSoftwareRenderer()
       
   514 {
       
   515   surfaceCache.clear();
       
   516   buffer = QImage();
       
   517   delete blankSurface;
       
   518 }
       
   519 
       
   520 void PictureFlowSoftwareRenderer::paint()
       
   521 {
       
   522   if(!widget && !gWidget)
       
   523     return;
       
   524 
       
   525   if(widget && widget->size() != size)
       
   526     init();
       
   527   else if (gWidget && gWidget->size().toSize() != size)
       
   528     init();
       
   529 
       
   530   if(state->backgroundColor != bgcolor)
       
   531   {
       
   532     bgcolor = state->backgroundColor;
       
   533     surfaceCache.clear();
       
   534   }
       
   535 
       
   536   if((int)(state->reflectionEffect) != effect)
       
   537   {
       
   538     effect = (int)state->reflectionEffect;
       
   539     surfaceCache.clear();
       
   540   }
       
   541 
       
   542   if(dirty)
       
   543     render();
       
   544 
       
   545   if (widget) {
       
   546       QPainter painter(widget);
       
   547       painter.drawImage(QPoint(0,0), buffer);
       
   548   } else if (gWidget && gPainter) {
       
   549       gPainter->drawImage(QPoint(0,0), buffer);
       
   550   }
       
   551 }
       
   552 
       
   553 void PictureFlowSoftwareRenderer::init()
       
   554 {
       
   555   if(!widget && !gWidget)
       
   556     return;
       
   557 
       
   558   surfaceCache.clear();
       
   559   blankSurface = 0;
       
   560 
       
   561   if (widget)
       
   562     size = widget->size();
       
   563   else
       
   564     size = gWidget->size().toSize();
       
   565   
       
   566   int ww = size.width();
       
   567   int wh = size.height();
       
   568   int w = (ww+1)/2;
       
   569   int h = (wh+1)/2;
       
   570 
       
   571 #ifdef PICTUREFLOW_QT4
       
   572   buffer = QImage(ww, wh, QImage::Format_RGB32);
       
   573 #endif
       
   574 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
   575   buffer.create(ww, wh, 32);
       
   576 #endif
       
   577   buffer.fill(bgcolor);
       
   578 
       
   579   rays.resize(w*2);
       
   580   for(int i = 0; i < w; i++)
       
   581   {
       
   582     PFreal gg = ((PFREAL_ONE >> 1) + i * PFREAL_ONE) / (2*h);
       
   583     rays[w-i-1] = -gg;
       
   584     rays[w+i] = gg;
       
   585   }
       
   586 
       
   587   dirty = true;
       
   588 }
       
   589 
       
   590 // TODO: optimize this with lookup tables
       
   591 static QRgb blendColor(QRgb c1, QRgb c2, int blend)
       
   592 {
       
   593   int r = qRed(c1) * blend/256 + qRed(c2)*(256-blend)/256;
       
   594   int g = qGreen(c1) * blend/256 + qGreen(c2)*(256-blend)/256;
       
   595   int b = qBlue(c1) * blend/256 + qBlue(c2)*(256-blend)/256;
       
   596   return qRgb(r, g, b);
       
   597 }
       
   598 
       
   599 
       
   600 static QImage* prepareSurface(const QImage* slideImage, int w, int h, QRgb bgcolor,
       
   601 ReflectionEffect reflectionEffect)
       
   602 {
       
   603 #ifdef PICTUREFLOW_QT4
       
   604   Qt::TransformationMode mode = Qt::SmoothTransformation;
       
   605   QImage img = slideImage->scaled(w, h, Qt::IgnoreAspectRatio, mode);
       
   606 #endif
       
   607 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
   608   QImage img = slideImage->smoothScale(w, h);
       
   609 #endif
       
   610 
       
   611   // slightly larger, to accomodate for the reflection
       
   612   int hs = h * 2;
       
   613   int hofs = h / 3;
       
   614 
       
   615   // offscreen buffer: black is sweet
       
   616 #ifdef PICTUREFLOW_QT4
       
   617   QImage* result = new QImage(hs, w, QImage::Format_RGB32);
       
   618 #endif
       
   619 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
   620   QImage* result = new QImage;
       
   621   result->create(hs, w, 32);
       
   622 #endif
       
   623   result->fill(bgcolor);
       
   624 
       
   625   // transpose the image, this is to speed-up the rendering
       
   626   // because we process one column at a time
       
   627   // (and much better and faster to work row-wise, i.e in one scanline)
       
   628   for(int x = 0; x < w; x++)
       
   629     for(int y = 0; y < h; y++)
       
   630       result->setPixel(hofs + y, x, img.pixel(x, y));
       
   631 
       
   632   if(reflectionEffect != NoReflection)
       
   633   {
       
   634     // create the reflection
       
   635     int ht = hs - h - hofs;
       
   636     int hte = ht;
       
   637     for(int x = 0; x < w; x++)
       
   638       for(int y = 0; y < ht; y++)
       
   639       {
       
   640         QRgb color = img.pixel(x, img.height()-y-1);
       
   641         result->setPixel(h+hofs+y, x, blendColor(color,bgcolor,128*(hte-y)/hte));
       
   642       }
       
   643 
       
   644     if(reflectionEffect == BlurredReflection)
       
   645     {
       
   646       // blur the reflection everything first
       
   647       // Based on exponential blur algorithm by Jani Huhtanen
       
   648       QRect rect(hs/2, 0, hs/2, w);
       
   649       rect &= result->rect();
       
   650 
       
   651       int r1 = rect.top();
       
   652       int r2 = rect.bottom();
       
   653       int c1 = rect.left();
       
   654       int c2 = rect.right();
       
   655 
       
   656       int bpl = result->bytesPerLine();
       
   657       int rgba[4];
       
   658       unsigned char* p;
       
   659 
       
   660       // how many times blur is applied?
       
   661       // for low-end system, limit this to only 1 loop
       
   662       for(int loop = 0; loop < 2; loop++)
       
   663       {
       
   664         for(int col = c1; col <= c2; col++)
       
   665         {
       
   666           p = result->scanLine(r1) + col*4;
       
   667           for(int i = 0; i < 3; i++)
       
   668             rgba[i] = p[i] << 4;
       
   669 
       
   670           p += bpl;
       
   671           for(int j = r1; j < r2; j++, p += bpl)
       
   672             for(int i = 0; i < 3; i++)
       
   673               p[i] = (rgba[i] += (((p[i]<<4)-rgba[i])) >> 1) >> 4;
       
   674         }
       
   675 
       
   676         for(int row = r1; row <= r2; row++)
       
   677         {
       
   678           p = result->scanLine(row) + c1*4;
       
   679           for(int i = 0; i < 3; i++)
       
   680             rgba[i] = p[i] << 4;
       
   681 
       
   682           p += 4;
       
   683           for(int j = c1; j < c2; j++, p+=4)
       
   684             for(int i = 0; i < 3; i++)
       
   685               p[i] = (rgba[i] += (((p[i]<<4)-rgba[i])) >> 1) >> 4;
       
   686         }
       
   687 
       
   688         for(int col = c1; col <= c2; col++)
       
   689         {
       
   690           p = result->scanLine(r2) + col*4;
       
   691           for(int i = 0; i < 3; i++)
       
   692             rgba[i] = p[i] << 4;
       
   693 
       
   694           p -= bpl;
       
   695           for(int j = r1; j < r2; j++, p -= bpl)
       
   696             for(int i = 0; i < 3; i++)
       
   697               p[i] = (rgba[i] += (((p[i]<<4)-rgba[i])) >> 1) >> 4;
       
   698         }
       
   699 
       
   700         for(int row = r1; row <= r2; row++)
       
   701         {
       
   702           p = result->scanLine(row) + c2*4;
       
   703           for(int i = 0; i < 3; i++)
       
   704             rgba[i] = p[i] << 4;
       
   705 
       
   706           p -= 4;
       
   707           for(int j = c1; j < c2; j++, p-=4)
       
   708             for(int i = 0; i < 3; i++)
       
   709               p[i] = (rgba[i] += (((p[i]<<4)-rgba[i])) >> 1) >> 4;
       
   710         }
       
   711       }
       
   712 
       
   713       // overdraw to leave only the reflection blurred (but not the actual image)
       
   714       for(int x = 0; x < w; x++)
       
   715         for(int y = 0; y < h; y++)
       
   716           result->setPixel(hofs + y, x, img.pixel(x, y));
       
   717     }
       
   718   }
       
   719 
       
   720   return result;
       
   721 }
       
   722 
       
   723 QImage* PictureFlowSoftwareRenderer::surface(int slideIndex)
       
   724 {
       
   725   if(!state)
       
   726     return 0;
       
   727   if(slideIndex < 0)
       
   728     return 0;
       
   729   if(slideIndex >= (int)state->slideImages.count())
       
   730     return 0;
       
   731 
       
   732 #ifdef PICTUREFLOW_QT4
       
   733   int key = slideIndex;
       
   734 #endif
       
   735 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
   736   QString key = QString::number(slideIndex);
       
   737 #endif
       
   738 
       
   739   QImage* img = state->slideImages.at(slideIndex);
       
   740   bool empty = img ? img->isNull() : true;
       
   741   if(empty)
       
   742   {
       
   743     surfaceCache.remove(key);
       
   744     imageHash.remove(slideIndex);
       
   745     if(!blankSurface)
       
   746     {
       
   747       int sw = state->slideWidth;
       
   748       int sh = state->slideHeight;
       
   749 
       
   750 #ifdef PICTUREFLOW_QT4
       
   751       QImage img = QImage(sw, sh, QImage::Format_RGB32);
       
   752 
       
   753       QPainter painter(&img);
       
   754       QPoint p1(sw*4/10, 0);
       
   755       QPoint p2(sw*6/10, sh);
       
   756       QLinearGradient linearGrad(p1, p2);
       
   757       linearGrad.setColorAt(0, Qt::black);
       
   758       linearGrad.setColorAt(1, Qt::white);
       
   759       painter.setBrush(linearGrad);
       
   760       painter.fillRect(0, 0, sw, sh, QBrush(linearGrad));
       
   761 
       
   762       painter.setPen(QPen(QColor(64,64,64), 4));
       
   763       painter.setBrush(QBrush());
       
   764       painter.drawRect(2, 2, sw-3, sh-3);
       
   765       painter.end();
       
   766 #endif
       
   767 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
   768       QPixmap pixmap(sw, sh, 32);
       
   769       QPainter painter(&pixmap);
       
   770       painter.fillRect(pixmap.rect(), QColor(192,192,192));
       
   771       painter.fillRect(5, 5, sw-10, sh-10, QColor(64,64,64));
       
   772       painter.end();
       
   773       QImage img = pixmap.convertToImage();
       
   774 #endif
       
   775 
       
   776       blankSurface = prepareSurface(&img, sw, sh, bgcolor, state->reflectionEffect);
       
   777     }
       
   778     return blankSurface;
       
   779   }
       
   780 
       
   781 #ifdef PICTUREFLOW_QT4
       
   782   bool exist = imageHash.contains(slideIndex);
       
   783   if(exist)
       
   784   if(img == imageHash.find(slideIndex).value())
       
   785 #endif
       
   786 #ifdef PICTUREFLOW_QT3
       
   787   bool exist = imageHash.find(slideIndex) != imageHash.end();
       
   788   if(exist)
       
   789   if(img == imageHash.find(slideIndex).data())
       
   790 #endif
       
   791 #ifdef PICTUREFLOW_QT2
       
   792   if(img == imageHash[slideIndex])
       
   793 #endif
       
   794     if(surfaceCache.contains(key))
       
   795         return surfaceCache[key];
       
   796 
       
   797   QImage* sr = prepareSurface(img, state->slideWidth, state->slideHeight, bgcolor, state->reflectionEffect);
       
   798   surfaceCache.insert(key, sr);
       
   799   imageHash.insert(slideIndex, img);
       
   800 
       
   801   return sr;
       
   802 }
       
   803 
       
   804 // Renders a slide to offscreen buffer. Returns a rect of the rendered area.
       
   805 // col1 and col2 limit the column for rendering.
       
   806 QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, int col2)
       
   807 {
       
   808   int blend = slide.blend;
       
   809   if(!blend)
       
   810     return QRect();
       
   811 
       
   812   QImage* src = surface(slide.slideIndex);
       
   813   if(!src)
       
   814     return QRect();
       
   815 
       
   816   QRect rect(0, 0, 0, 0);
       
   817 
       
   818   int sw = src->height();
       
   819   int sh = src->width();
       
   820   int h = buffer.height();
       
   821   int w = buffer.width();
       
   822 
       
   823   if(col1 > col2)
       
   824   {
       
   825     int c = col2;
       
   826     col2 = col1;
       
   827     col1 = c;
       
   828   }
       
   829 
       
   830   col1 = (col1 >= 0) ? col1 : 0;
       
   831   col2 = (col2 >= 0) ? col2 : w-1;
       
   832   col1 = qMin(col1, w-1);
       
   833   col2 = qMin(col2, w-1);
       
   834 
       
   835   int zoom = 100;
       
   836   int distance = h * 100 / zoom;
       
   837   PFreal sdx = fcos(slide.angle);
       
   838   PFreal sdy = fsin(slide.angle);
       
   839   PFreal xs = slide.cx - state->slideWidth * sdx/2;
       
   840   PFreal ys = slide.cy - state->slideWidth * sdy/2;
       
   841   PFreal dist = distance * PFREAL_ONE;
       
   842   int xi = qMax((PFreal)0, (w*PFREAL_ONE/2) + fdiv(xs*h, dist+ys) >> PFREAL_SHIFT);
       
   843   if(xi >= w)
       
   844     return rect;
       
   845 
       
   846   bool flag = false;
       
   847   rect.setLeft(xi);
       
   848   
       
   849   int centerY = 0;
       
   850   for(int x = qMax(xi, col1); x <= col2; x++)
       
   851   {
       
   852     PFreal hity = 0;
       
   853     PFreal fk = rays[x];
       
   854     if(sdy)
       
   855     {
       
   856       fk = fk - fdiv(sdx,sdy);
       
   857       hity = -fdiv((rays[x]*distance - slide.cx + slide.cy*sdx/sdy), fk);
       
   858     }
       
   859 
       
   860     dist = distance*PFREAL_ONE + hity;
       
   861     if(dist < 0)
       
   862       continue;
       
   863 
       
   864     PFreal hitx = fmul(dist, rays[x]);
       
   865     PFreal hitdist = fdiv(hitx - slide.cx, sdx);
       
   866 
       
   867     int column = sw/2 + (hitdist >> PFREAL_SHIFT);
       
   868     if(column >= sw)
       
   869       break;
       
   870     if(column < 0)
       
   871       continue;
       
   872 
       
   873     rect.setRight(x);
       
   874     if(!flag)
       
   875       rect.setLeft(x);
       
   876     flag = true;
       
   877 
       
   878     int y1 = h/2;
       
   879     int y2 = y1+ 1;
       
   880     centerY = y1;
       
   881     QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x;
       
   882     QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x;
       
   883     QRgb pixelstep = pixel2 - pixel1;
       
   884 
       
   885     int center = (sh/2);
       
   886     int dy = dist / h;
       
   887     int p1 = center*PFREAL_ONE - dy/2;
       
   888     int p2 = center*PFREAL_ONE + dy/2;
       
   889 
       
   890     const QRgb *ptr = (const QRgb*)(src->scanLine(column));
       
   891     if(blend == 256)
       
   892       while((y1 >= 0) && (y2 < h) && (p1 >= 0))
       
   893       {
       
   894         *pixel1 = ptr[p1 >> PFREAL_SHIFT];
       
   895         *pixel2 = ptr[p2 >> PFREAL_SHIFT];
       
   896         p1 -= dy;
       
   897         p2 += dy;
       
   898         y1--;
       
   899         y2++;
       
   900         pixel1 -= pixelstep;
       
   901         pixel2 += pixelstep;
       
   902       }
       
   903     else
       
   904       while((y1 >= 0) && (y2 < h) && (p1 >= 0))
       
   905       {
       
   906         QRgb c1 = ptr[p1 >> PFREAL_SHIFT];
       
   907         QRgb c2 = ptr[p2 >> PFREAL_SHIFT];
       
   908         *pixel1 = blendColor(c1, bgcolor, blend);
       
   909         *pixel2 = blendColor(c2, bgcolor, blend);
       
   910         p1 -= dy;
       
   911         p2 += dy;
       
   912         y1--;
       
   913         y2++;
       
   914         pixel1 -= pixelstep;
       
   915         pixel2 += pixelstep;
       
   916      }
       
   917    }
       
   918 
       
   919    int yTop = (3 * centerY - 2 * state->slideHeight) / 3;
       
   920    rect.setTop(yTop);
       
   921    rect.setBottom(state->slideHeight + yTop);
       
   922    return rect;
       
   923 }
       
   924 
       
   925 void PictureFlowSoftwareRenderer::renderSlides()
       
   926 {
       
   927   int nleft = state->leftSlides.count();
       
   928   int nright = state->rightSlides.count();
       
   929 
       
   930   QRect r = renderSlide(state->centerSlide);
       
   931   int c1 = r.left();
       
   932   int c2 = r.right();
       
   933   cRect = r;
       
   934   for(int index = 0; index < nleft; index++)
       
   935   {
       
   936     QRect rs = renderSlide(state->leftSlides[index], 0, c1-1);
       
   937     if(!rs.isEmpty())
       
   938       c1 = rs.left();
       
   939   }
       
   940   for(int index = 0; index < nright; index++)
       
   941   {
       
   942     QRect rs = renderSlide(state->rightSlides[index], c2+1, buffer.width());
       
   943     if(!rs.isEmpty())
       
   944       c2 = rs.right();
       
   945   }
       
   946 }
       
   947 
       
   948 // Render the slides. Updates only the offscreen buffer.
       
   949 void PictureFlowSoftwareRenderer::render()
       
   950 {
       
   951   buffer.fill(state->backgroundColor);
       
   952   renderSlides();
       
   953   dirty = false;
       
   954 }
       
   955 
       
   956 // -----------------------------------------
       
   957 
       
   958 class PictureFlowPrivate
       
   959 {
       
   960 public:
       
   961   PictureFlowState* state;
       
   962   PictureFlowAnimator* animator;
       
   963   PictureFlowAbstractRenderer* renderer;
       
   964   QTimer triggerTimer;
       
   965   QTimer scrollTimer;
       
   966 };
       
   967 
       
   968 
       
   969 PictureFlow::PictureFlow(QWidget* parent): FlowInterface(parent)
       
   970 {
       
   971   d = new PictureFlowPrivate;
       
   972 
       
   973   d->state = new PictureFlowState;
       
   974   d->state->reset();
       
   975   d->state->reposition();
       
   976 
       
   977   d->renderer = new PictureFlowSoftwareRenderer;
       
   978   d->renderer->state = d->state;
       
   979   d->renderer->widget = this;
       
   980   d->renderer->init();
       
   981 
       
   982   d->animator = new PictureFlowAnimator;
       
   983   d->animator->state = d->state;
       
   984   QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
       
   985 
       
   986   QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));
       
   987   QObject::connect(&d->scrollTimer, SIGNAL(timeout()), this, SLOT(scroll()));
       
   988 
       
   989 #ifdef PICTUREFLOW_QT4
       
   990   setAttribute(Qt::WA_StaticContents, true);
       
   991   setAttribute(Qt::WA_OpaquePaintEvent, true);
       
   992   setAttribute(Qt::WA_NoSystemBackground, true);
       
   993 #endif
       
   994 #ifdef PICTUREFLOW_QT3
       
   995   setWFlags(getWFlags() | Qt::WStaticContents);
       
   996   setWFlags(getWFlags() | Qt::WNoAutoErase);
       
   997 #endif
       
   998 #ifdef PICTUREFLOW_QT2
       
   999   setWFlags(getWFlags() | Qt::WPaintClever);
       
  1000   setWFlags(getWFlags() | Qt::WRepaintNoErase);
       
  1001   setWFlags(getWFlags() | Qt::WResizeNoErase);
       
  1002 #endif
       
  1003 }
       
  1004 
       
  1005 PictureFlow::~PictureFlow()
       
  1006 {
       
  1007   delete d->renderer;
       
  1008   delete d->animator;
       
  1009   delete d->state;
       
  1010   delete d;
       
  1011 }
       
  1012 
       
  1013 int PictureFlow::slideCount() const
       
  1014 {
       
  1015   return d->state->slideImages.count();
       
  1016 }
       
  1017 
       
  1018 QColor PictureFlow::backgroundColor() const
       
  1019 {
       
  1020   return QColor(d->state->backgroundColor);
       
  1021 }
       
  1022 
       
  1023 void PictureFlow::setBackgroundColor(const QColor& c)
       
  1024 {
       
  1025   d->state->backgroundColor = c.rgb();
       
  1026   triggerRender();
       
  1027 }
       
  1028 
       
  1029 QSize PictureFlow::slideSize() const
       
  1030 {
       
  1031   return QSize(d->state->slideWidth, d->state->slideHeight);
       
  1032 }
       
  1033 
       
  1034 void PictureFlow::setSlideSize(QSize size)
       
  1035 {
       
  1036   d->state->slideWidth = size.width();
       
  1037   d->state->slideHeight = size.height();
       
  1038   d->state->reposition();
       
  1039   triggerRender();
       
  1040 }
       
  1041 
       
  1042 ReflectionEffect PictureFlow::reflectionEffect() const
       
  1043 {
       
  1044   return d->state->reflectionEffect;
       
  1045 }
       
  1046 
       
  1047 void PictureFlow::setReflectionEffect(ReflectionEffect effect)
       
  1048 {
       
  1049   d->state->reflectionEffect = effect;
       
  1050   triggerRender();
       
  1051 }
       
  1052 
       
  1053 QImage PictureFlow::slide(int index) const
       
  1054 {
       
  1055   QImage* i = 0;
       
  1056   if((index >= 0) && (index < slideCount()))
       
  1057     i = d->state->slideImages[index];
       
  1058   return i ? QImage(*i) : QImage();
       
  1059 }
       
  1060 
       
  1061 void PictureFlow::addSlide(const QImage& image)
       
  1062 {
       
  1063   int c = d->state->slideImages.count();
       
  1064   d->state->slideImages.resize(c+1);
       
  1065   d->state->slideImages[c] = new QImage(image);
       
  1066   triggerRender();
       
  1067 }
       
  1068 
       
  1069 void PictureFlow::addSlide(const QPixmap& pixmap)
       
  1070 {
       
  1071   addSlide(pixmap.toImage());
       
  1072 }
       
  1073 
       
  1074 void PictureFlow::setSlide(int index, const QImage& image)
       
  1075 {
       
  1076   if((index >= 0) && (index < slideCount()))
       
  1077   {
       
  1078     QImage* i = image.isNull() ? 0 : new QImage(image);
       
  1079     delete d->state->slideImages[index];
       
  1080     d->state->slideImages[index] = i;
       
  1081     triggerRender();
       
  1082   }
       
  1083 }
       
  1084 
       
  1085 void PictureFlow::setSlide(int index, const QPixmap& pixmap)
       
  1086 {
       
  1087   setSlide(index, pixmap.toImage());
       
  1088 }
       
  1089 
       
  1090 int PictureFlow::centerIndex() const
       
  1091 {
       
  1092   return d->state->centerIndex;
       
  1093 }
       
  1094 
       
  1095 bool PictureFlow::slideAnimationOngoing() const
       
  1096 {
       
  1097     return d->animator->animateTimer.isActive();
       
  1098 }
       
  1099 
       
  1100 void PictureFlow::setCenterIndex(int index)
       
  1101 {
       
  1102   index = qMin(index, slideCount()-1);
       
  1103   index = qMax(index, 0);
       
  1104   d->state->centerIndex = index;
       
  1105   d->state->reset();
       
  1106   d->animator->stop(index);
       
  1107   triggerRender();
       
  1108 }
       
  1109 
       
  1110 void PictureFlow::clear()
       
  1111 {
       
  1112   int c = d->state->slideImages.count();
       
  1113   for(int i = 0; i < c; i++)
       
  1114     delete d->state->slideImages[i];
       
  1115   d->state->slideImages.resize(0);
       
  1116 
       
  1117   d->state->reset();
       
  1118   triggerRender();
       
  1119 }
       
  1120 
       
  1121 void PictureFlow::render()
       
  1122 {
       
  1123   d->renderer->dirty = true;
       
  1124   update();
       
  1125 }
       
  1126 
       
  1127 void PictureFlow::triggerRender()
       
  1128 {
       
  1129 #ifdef PICTUREFLOW_QT4
       
  1130   d->triggerTimer.setSingleShot(true);
       
  1131   d->triggerTimer.start(0);
       
  1132 #endif
       
  1133 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
  1134   d->triggerTimer.start(0, true);
       
  1135 #endif
       
  1136 }
       
  1137 
       
  1138 void PictureFlow::showPrevious()
       
  1139 {
       
  1140   int step = d->animator->step;
       
  1141   int center = d->state->centerIndex;
       
  1142 
       
  1143   if(step > 0)
       
  1144     d->animator->start(center);
       
  1145 
       
  1146   if(step == 0)
       
  1147     if(center > 0)
       
  1148       d->animator->start(center - 1);
       
  1149 
       
  1150   if(step < 0)
       
  1151     d->animator->target = qMax(0, center - 2);
       
  1152 }
       
  1153 
       
  1154 void PictureFlow::showNext()
       
  1155 {
       
  1156   int step = d->animator->step;
       
  1157   int center = d->state->centerIndex;
       
  1158 
       
  1159   if(step < 0)
       
  1160     d->animator->start(center);
       
  1161 
       
  1162   if(step == 0)
       
  1163     if(center < slideCount()-1)
       
  1164       d->animator->start(center + 1);
       
  1165 
       
  1166   if(step > 0)
       
  1167     d->animator->target = qMin(center + 2, slideCount()-1);
       
  1168 }
       
  1169 
       
  1170 void PictureFlow::showSlide(int index)
       
  1171 {
       
  1172   index = qMax(index, 0);
       
  1173   index = qMin(slideCount()-1, index);
       
  1174   if(index == d->state->centerSlide.slideIndex)
       
  1175     return;
       
  1176 
       
  1177   d->animator->start(index);
       
  1178 }
       
  1179 
       
  1180 void PictureFlow::keyPressEvent(QKeyEvent* event)
       
  1181 {
       
  1182     switch (event->key()) {
       
  1183         case Qt::Key_Escape:
       
  1184             emit cancel();
       
  1185             return;
       
  1186 
       
  1187         case Qt::Key_Enter:
       
  1188         case Qt::Key_Return:
       
  1189         case Qt::Key_Select:
       
  1190             emit ok(centerIndex());
       
  1191             return;
       
  1192         case Qt::Key_Left:
       
  1193             if(event->modifiers() == Qt::ControlModifier)
       
  1194                 showSlide(centerIndex()-10);
       
  1195             else
       
  1196                 showPrevious();
       
  1197             event->accept();
       
  1198             return;
       
  1199         case Qt::Key_Right:
       
  1200             if(event->modifiers() == Qt::ControlModifier)
       
  1201                 showSlide(centerIndex()+10);
       
  1202             else
       
  1203                 showNext();
       
  1204             event->accept();
       
  1205             return;
       
  1206     }
       
  1207     event->ignore();
       
  1208 }
       
  1209 
       
  1210 void PictureFlow::mousePressEvent(QMouseEvent* event)
       
  1211 {
       
  1212     m_lastMoveEventPos = event->pos();
       
  1213     if (d->scrollTimer.isActive())
       
  1214         d->scrollTimer.stop();
       
  1215 	d->scrollTimer.start(KScrollTimeout);
       
  1216     scroll();
       
  1217 }
       
  1218 
       
  1219 void PictureFlow::mouseMoveEvent(QMouseEvent* event)
       
  1220 {
       
  1221     m_lastMoveEventPos = event->pos();
       
  1222 }
       
  1223 
       
  1224 void PictureFlow::mouseReleaseEvent(QMouseEvent* event)
       
  1225 {
       
  1226     d->scrollTimer.stop();        
       
  1227 	if (slideAnimationOngoing()) {
       
  1228 //		qDebug() << "pf:mouseReleaseEvent slideanimation running, ignoring click";
       
  1229 		return;
       
  1230 	}
       
  1231     if(event->x() > ((width() * (slideRatio2 - slideRatio1)) / (2 * slideRatio2)) && event->x() < ((width() * (slideRatio2 + slideRatio1)) / (2 * slideRatio2))) {
       
  1232         emit ok(centerIndex());
       
  1233         return;
       
  1234     }
       
  1235 }
       
  1236 
       
  1237 void PictureFlow::scroll()
       
  1238 {
       
  1239     if(m_lastMoveEventPos.x() < ((width() * (slideRatio2 - slideRatio1)) / (2 * slideRatio2))) {
       
  1240         showPrevious();
       
  1241     }
       
  1242     else if (m_lastMoveEventPos.x() > ((width() * (slideRatio2 + slideRatio1)) / (2 * slideRatio2))) {
       
  1243         showNext();
       
  1244     }
       
  1245 }
       
  1246 
       
  1247 
       
  1248 void PictureFlow::paintEvent(QPaintEvent* event)
       
  1249 {
       
  1250   Q_UNUSED(event);
       
  1251   d->renderer->paint();
       
  1252 }
       
  1253 
       
  1254 void PictureFlow::resizeEvent(QResizeEvent* event)
       
  1255 {
       
  1256     QWidget::resizeEvent(event);
       
  1257 
       
  1258     QSize s = event->size(); //parentWidget()->rect().size();
       
  1259     setSlideSize(QSize((s.width() * slideRatio1) / slideRatio2, (s.height() * slideRatio1) / slideRatio2));
       
  1260 }
       
  1261 
       
  1262 void PictureFlow::updateAnimation()
       
  1263 {
       
  1264   int old_center = d->state->centerIndex;
       
  1265   d->animator->update();
       
  1266   triggerRender();
       
  1267   if(d->state->centerIndex != old_center)
       
  1268     emit centerIndexChanged(d->state->centerIndex);
       
  1269 }
       
  1270 
       
  1271 void PictureFlow::init()
       
  1272 {   
       
  1273     QSize s = size(); //parentWidget()->rect().size();
       
  1274  
       
  1275     setSlideSize(QSize((s.width() * slideRatio1) / slideRatio2, (s.height() * slideRatio1) / slideRatio2));
       
  1276     //resize(s);
       
  1277 //TODO: Disable refrection ?
       
  1278 //    setReflectionEffect(PictureFlow::NoReflection); 
       
  1279     setBackgroundColor(Qt::black);
       
  1280     // ensure that system cursor is an arrow, not a random icon
       
  1281     // This is not an issue if the platform does not have a system cursor
       
  1282 #ifndef __SYMBIAN32__
       
  1283     setCursor(Qt::ArrowCursor);
       
  1284 #endif
       
  1285     setFocusPolicy(Qt::WheelFocus);
       
  1286     setFocus(Qt::OtherFocusReason);
       
  1287 }
       
  1288 
       
  1289 QRect PictureFlow::centralRect() const 
       
  1290 {
       
  1291     if (d->renderer) {
       
  1292         /* Render the slide to get the rectangle */
       
  1293         SlideInfo s = d->state->centerSlide;
       
  1294         QRect r = ((PictureFlowSoftwareRenderer*)d->renderer)->renderSlide(s);
       
  1295         return r;
       
  1296     }
       
  1297     else
       
  1298         return QRect();
       
  1299 }
       
  1300 
       
  1301 //-----------------------------------------------
       
  1302 // GraphicsPictureFlow class
       
  1303 
       
  1304 GraphicsPictureFlow::GraphicsPictureFlow(QObject* parent): GraphicsFlowInterface(NULL)
       
  1305 {
       
  1306   setParent(parent);
       
  1307 
       
  1308   d = new PictureFlowPrivate;
       
  1309 
       
  1310   d->state = new PictureFlowState;
       
  1311   d->state->reset();
       
  1312   d->state->reposition();
       
  1313 
       
  1314   d->renderer = new PictureFlowSoftwareRenderer;
       
  1315   d->renderer->state = d->state;
       
  1316   d->renderer->gWidget = this;
       
  1317   d->renderer->init();
       
  1318 
       
  1319   d->animator = new PictureFlowAnimator;
       
  1320   d->animator->state = d->state;
       
  1321   QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
       
  1322 
       
  1323   QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));
       
  1324   QObject::connect(&d->scrollTimer, SIGNAL(timeout()), this, SLOT(scroll()));
       
  1325 
       
  1326 #ifdef PICTUREFLOW_QT4
       
  1327   setAttribute(Qt::WA_StaticContents, true);
       
  1328   setAttribute(Qt::WA_OpaquePaintEvent, true);
       
  1329   setAttribute(Qt::WA_NoSystemBackground, true);
       
  1330 #endif
       
  1331 #ifdef PICTUREFLOW_QT3
       
  1332   setWFlags(getWFlags() | Qt::WStaticContents);
       
  1333   setWFlags(getWFlags() | Qt::WNoAutoErase);
       
  1334 #endif
       
  1335 #ifdef PICTUREFLOW_QT2
       
  1336   setWFlags(getWFlags() | Qt::WPaintClever);
       
  1337   setWFlags(getWFlags() | Qt::WRepaintNoErase);
       
  1338   setWFlags(getWFlags() | Qt::WResizeNoErase);
       
  1339 #endif
       
  1340 }
       
  1341 
       
  1342 GraphicsPictureFlow::~GraphicsPictureFlow()
       
  1343 {
       
  1344   delete d->renderer;
       
  1345   delete d->animator;
       
  1346   delete d->state;
       
  1347   delete d;
       
  1348 }
       
  1349 
       
  1350 int GraphicsPictureFlow::slideCount() const
       
  1351 {
       
  1352   return d->state->slideImages.count();
       
  1353 }
       
  1354 
       
  1355 QColor GraphicsPictureFlow::backgroundColor() const
       
  1356 {
       
  1357   return QColor(d->state->backgroundColor);
       
  1358 }
       
  1359 
       
  1360 void GraphicsPictureFlow::setBackgroundColor(const QColor& c)
       
  1361 {
       
  1362   d->state->backgroundColor = c.rgb();
       
  1363   triggerRender();
       
  1364 }
       
  1365 
       
  1366 QSize GraphicsPictureFlow::slideSize() const
       
  1367 {
       
  1368   return QSize(d->state->slideWidth, d->state->slideHeight);
       
  1369 }
       
  1370 
       
  1371 void GraphicsPictureFlow::setSlideSize(QSize size)
       
  1372 {
       
  1373   d->state->slideWidth = size.width();
       
  1374   d->state->slideHeight = size.height();
       
  1375   d->state->reposition();
       
  1376   triggerRender();
       
  1377 }
       
  1378 
       
  1379 ReflectionEffect GraphicsPictureFlow::reflectionEffect() const
       
  1380 {
       
  1381   return d->state->reflectionEffect;
       
  1382 }
       
  1383 
       
  1384 void GraphicsPictureFlow::setReflectionEffect(ReflectionEffect effect)
       
  1385 {
       
  1386   d->state->reflectionEffect = effect;
       
  1387   triggerRender();
       
  1388 }
       
  1389 
       
  1390 QImage GraphicsPictureFlow::slide(int index) const
       
  1391 {
       
  1392   QImage* i = 0;
       
  1393   if((index >= 0) && (index < slideCount()))
       
  1394     i = d->state->slideImages[index];
       
  1395   return i ? QImage(*i) : QImage();
       
  1396 }
       
  1397 
       
  1398 void GraphicsPictureFlow::addSlide(const QImage& image)
       
  1399 {
       
  1400   int c = d->state->slideImages.count();
       
  1401   d->state->slideImages.resize(c+1);
       
  1402   d->state->slideImages[c] = new QImage(image);
       
  1403   triggerRender();
       
  1404 }
       
  1405 
       
  1406 void GraphicsPictureFlow::addSlide(const QPixmap& pixmap)
       
  1407 {
       
  1408   addSlide(pixmap.toImage());
       
  1409 }
       
  1410 
       
  1411 void GraphicsPictureFlow::setSlide(int index, const QImage& image)
       
  1412 {
       
  1413   if((index >= 0) && (index < slideCount()))
       
  1414   {
       
  1415     QImage* i = image.isNull() ? 0 : new QImage(image);
       
  1416     delete d->state->slideImages[index];
       
  1417     d->state->slideImages[index] = i;
       
  1418     triggerRender();
       
  1419   }
       
  1420 }
       
  1421 
       
  1422 void GraphicsPictureFlow::setSlide(int index, const QPixmap& pixmap)
       
  1423 {
       
  1424   setSlide(index, pixmap.toImage());
       
  1425 }
       
  1426 
       
  1427 int GraphicsPictureFlow::centerIndex() const
       
  1428 {
       
  1429   return d->state->centerIndex;
       
  1430 }
       
  1431 
       
  1432 bool GraphicsPictureFlow::slideAnimationOngoing() const
       
  1433 {
       
  1434     return d->animator->animateTimer.isActive();
       
  1435 }
       
  1436 
       
  1437 void GraphicsPictureFlow::setCenterIndex(int index)
       
  1438 {
       
  1439   index = qMin(index, slideCount()-1);
       
  1440   index = qMax(index, 0);
       
  1441   d->state->centerIndex = index;
       
  1442   d->state->reset();
       
  1443   d->animator->stop(index);
       
  1444   triggerRender();
       
  1445 }
       
  1446 
       
  1447 void GraphicsPictureFlow::clear()
       
  1448 {
       
  1449   int c = d->state->slideImages.count();
       
  1450   for(int i = 0; i < c; i++)
       
  1451     delete d->state->slideImages[i];
       
  1452   d->state->slideImages.resize(0);
       
  1453 
       
  1454   d->state->reset();
       
  1455   triggerRender();
       
  1456 }
       
  1457 
       
  1458 void GraphicsPictureFlow::render()
       
  1459 {
       
  1460   d->renderer->dirty = true;
       
  1461   update();
       
  1462 }
       
  1463 
       
  1464 void GraphicsPictureFlow::triggerRender()
       
  1465 {
       
  1466 #ifdef PICTUREFLOW_QT4
       
  1467   d->triggerTimer.setSingleShot(true);
       
  1468   d->triggerTimer.start(0);
       
  1469 #endif
       
  1470 #if defined(PICTUREFLOW_QT3) || defined(PICTUREFLOW_QT2)
       
  1471   d->triggerTimer.start(0, true);
       
  1472 #endif
       
  1473 }
       
  1474 
       
  1475 void GraphicsPictureFlow::showPrevious()
       
  1476 {
       
  1477   int step = d->animator->step;
       
  1478   int center = d->state->centerIndex;
       
  1479 
       
  1480   if(step > 0)
       
  1481     d->animator->start(center);
       
  1482 
       
  1483   if(step == 0)
       
  1484     if(center > 0)
       
  1485       d->animator->start(center - 1);
       
  1486 
       
  1487   if(step < 0)
       
  1488     d->animator->target = qMax(0, center - 2);
       
  1489 }
       
  1490 
       
  1491 void GraphicsPictureFlow::showNext()
       
  1492 {
       
  1493   int step = d->animator->step;
       
  1494   int center = d->state->centerIndex;
       
  1495 
       
  1496   if(step < 0)
       
  1497     d->animator->start(center);
       
  1498 
       
  1499   if(step == 0)
       
  1500     if(center < slideCount()-1)
       
  1501       d->animator->start(center + 1);
       
  1502 
       
  1503   if(step > 0)
       
  1504     d->animator->target = qMin(center + 2, slideCount()-1);
       
  1505 }
       
  1506 
       
  1507 void GraphicsPictureFlow::showSlide(int index)
       
  1508 {
       
  1509   index = qMax(index, 0);
       
  1510   index = qMin(slideCount()-1, index);
       
  1511   if(index == d->state->centerSlide.slideIndex)
       
  1512     return;
       
  1513 
       
  1514   d->animator->start(index);
       
  1515 }
       
  1516 
       
  1517 void GraphicsPictureFlow::keyPressEvent(QKeyEvent* event)
       
  1518 {
       
  1519     switch (event->key()) {
       
  1520         case Qt::Key_Escape:
       
  1521             emit cancel();
       
  1522             return;
       
  1523 
       
  1524         case Qt::Key_Enter:
       
  1525         case Qt::Key_Return:
       
  1526         case Qt::Key_Select:
       
  1527             emit ok(centerIndex());
       
  1528             return;
       
  1529         case Qt::Key_Left:
       
  1530             if(event->modifiers() == Qt::ControlModifier)
       
  1531                 showSlide(centerIndex()-10);
       
  1532             else
       
  1533                 showPrevious();
       
  1534             event->accept();
       
  1535             return;
       
  1536         case Qt::Key_Right:
       
  1537             if(event->modifiers() == Qt::ControlModifier)
       
  1538                 showSlide(centerIndex()+10);
       
  1539             else
       
  1540                 showNext();
       
  1541             event->accept();
       
  1542             return;
       
  1543     }
       
  1544     event->ignore();
       
  1545 }
       
  1546 
       
  1547 void GraphicsPictureFlow::mousePressEvent(QGraphicsSceneMouseEvent* event)
       
  1548 {
       
  1549     m_lastMoveEventPos = event->pos().toPoint();
       
  1550     if (d->scrollTimer.isActive())
       
  1551         d->scrollTimer.stop();
       
  1552 	d->scrollTimer.start(KScrollTimeout);
       
  1553     scroll();
       
  1554 }
       
  1555 
       
  1556 void GraphicsPictureFlow::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
       
  1557 {
       
  1558     m_lastMoveEventPos = event->pos().toPoint();
       
  1559 }
       
  1560 
       
  1561 void GraphicsPictureFlow::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
       
  1562 {
       
  1563     d->scrollTimer.stop();        
       
  1564 	if (slideAnimationOngoing()) {
       
  1565 //		qDebug() << "pf:mouseReleaseEvent slideanimation running, ignoring click";
       
  1566 		return;
       
  1567 	}
       
  1568     if(event->pos().x() > ((size().width() * (slideRatio2 - slideRatio1)) / (2 * slideRatio2)) && event->pos().x() < ((size().width() * (slideRatio2 + slideRatio1)) / (2 * slideRatio2))) {
       
  1569         emit ok(centerIndex());
       
  1570         return;
       
  1571     }
       
  1572 }
       
  1573 
       
  1574 void GraphicsPictureFlow::scroll()
       
  1575 {
       
  1576     if(m_lastMoveEventPos.x() < ((size().width() * (slideRatio2 - slideRatio1)) / (2 * slideRatio2))) {
       
  1577         showPrevious();
       
  1578     }
       
  1579     else if (m_lastMoveEventPos.x() > ((size().width() * (slideRatio2 + slideRatio1)) / (2 * slideRatio2))) {
       
  1580         showNext();
       
  1581     }
       
  1582 }
       
  1583 
       
  1584 void GraphicsPictureFlow::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
       
  1585 {
       
  1586     d->renderer->gPainter = painter;
       
  1587     d->renderer->paint();
       
  1588     d->renderer->gPainter = NULL;
       
  1589 }
       
  1590 
       
  1591 void GraphicsPictureFlow::resizeEvent(QGraphicsSceneResizeEvent* event)
       
  1592 {
       
  1593     QGraphicsWidget::resizeEvent(event);
       
  1594 
       
  1595     QSize s = event->newSize().toSize();
       
  1596     setSlideSize(QSize((s.width() * slideRatio1) / slideRatio2, (s.height() * slideRatio1) / slideRatio2));
       
  1597 }
       
  1598 
       
  1599 void GraphicsPictureFlow::updateAnimation()
       
  1600 {
       
  1601   int old_center = d->state->centerIndex;
       
  1602   d->animator->update();
       
  1603   triggerRender();
       
  1604   if(d->state->centerIndex != old_center)
       
  1605     emit centerIndexChanged(d->state->centerIndex);
       
  1606 }
       
  1607 
       
  1608 void GraphicsPictureFlow::init()
       
  1609 {   
       
  1610     QSize s = size().toSize(); //parentWidget()->rect().size();
       
  1611  
       
  1612     setSlideSize(QSize((s.width() * slideRatio1) / slideRatio2, (s.height() * slideRatio1) / slideRatio2));
       
  1613     //resize(s);
       
  1614 //TODO: Disable refrection ?
       
  1615 //    setReflectionEffect(PictureFlow::NoReflection); 
       
  1616     setBackgroundColor(Qt::black);
       
  1617     // ensure that system cursor is an arrow, not a random icon
       
  1618     // This is not an issue if the platform does not have a system cursor
       
  1619 #ifndef __SYMBIAN32__
       
  1620     setCursor(Qt::ArrowCursor);
       
  1621 #endif
       
  1622     setFocusPolicy(Qt::WheelFocus);
       
  1623     setFocus(Qt::OtherFocusReason);
       
  1624 }
       
  1625 
       
  1626 QRect GraphicsPictureFlow::centralRect() const 
       
  1627 {
       
  1628     if (d->renderer) {
       
  1629         /* Render the slide to get the rectangle */
       
  1630         SlideInfo s = d->state->centerSlide;
       
  1631         QRect r = ((PictureFlowSoftwareRenderer*)d->renderer)->renderSlide(s);
       
  1632         return r;
       
  1633     }
       
  1634     else
       
  1635         return QRect();
       
  1636 }
       
  1637 }