2 PictureFlow - animated image show widget
3 http://pictureflow.googlecode.com
5 Copyright (C) 2009 Ariya Hidayat (ariya@kde.org)
6 Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
7 Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
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:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
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
28 #include "pictureflow.hpp"
31 #if QT_VERSION < 0x040300
32 #error PictureFlow widgets need Qt 4.3 or later
35 #include <QApplication>
43 #include "../components/playlist/playlist_model.hpp" /* getArtPixmap etc */
44 #include "../components/playlist/sorting.h" /* Columns List */
46 // for fixed-point arithmetic, we need minimum 32-bit long
47 // long long (64-bit) might be useful for multiplication and division
49 #define PFREAL_SHIFT 10
50 #define PFREAL_ONE (1 << PFREAL_SHIFT)
52 #define IANGLE_MAX 1024
53 #define IANGLE_MASK 1023
55 inline PFreal fmul(PFreal a, PFreal b)
57 return ((long long)(a))*((long long)(b)) >> PFREAL_SHIFT;
60 inline PFreal fdiv(PFreal num, PFreal den)
62 long long p = (long long)(num) << (PFREAL_SHIFT * 2);
63 long long q = p / (long long)den;
64 long long r = q >> PFREAL_SHIFT;
69 inline PFreal fsin(int iangle)
71 // warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed!
72 static const PFreal tab[] = {
73 3, 103, 202, 300, 394, 485, 571, 652,
74 726, 793, 853, 904, 947, 980, 1004, 1019,
75 1023, 1018, 1003, 978, 944, 901, 849, 789,
76 721, 647, 566, 479, 388, 294, 196, 97,
77 -4, -104, -203, -301, -395, -486, -572, -653,
78 -727, -794, -854, -905, -948, -981, -1005, -1020,
79 -1024, -1019, -1004, -979, -945, -902, -850, -790,
80 -722, -648, -567, -480, -389, -295, -197, -98,
86 iangle &= IANGLE_MASK;
88 int i = (iangle >> 4);
90 PFreal q = tab[(i+1)];
92 return p + g *(iangle - i*16) / 16;
95 inline PFreal fcos(int iangle)
97 return fsin(iangle + (IANGLE_MAX >> 2));
100 /* ----------------------------------------------------------
102 PictureFlowState stores the state of all slides, i.e. all the necessary
103 information to be able to render them.
105 PictureFlowAnimator is responsible to move the slides during the
106 transition between slides, to achieve the effect similar to Cover Flow,
107 by changing the state.
109 PictureFlowSoftwareRenderer (or PictureFlowOpenGLRenderer) is
110 the actual 3-d renderer. It should render all slides given the state
111 (an instance of PictureFlowState).
113 Instances of all the above three classes are stored in
116 ------------------------------------------------------- */
126 class PictureFlowState
135 QRgb backgroundColor;
138 PictureFlow::ReflectionEffect reflectionEffect;
146 SlideInfo centerSlide;
147 QVector<SlideInfo> leftSlides;
148 QVector<SlideInfo> rightSlides;
152 class PictureFlowAnimator
155 PictureFlowAnimator();
156 PictureFlowState* state;
158 void start(int slide);
159 void stop(int slide);
168 class PictureFlowAbstractRenderer
171 PictureFlowAbstractRenderer(): state(0), dirty(false), widget(0) {}
172 virtual ~PictureFlowAbstractRenderer() {}
174 PictureFlowState* state;
178 virtual void init() = 0;
179 virtual void paint() = 0;
182 class PictureFlowSoftwareRenderer: public PictureFlowAbstractRenderer
185 PictureFlowSoftwareRenderer();
186 ~PictureFlowSoftwareRenderer();
189 virtual void paint();
196 QVector<PFreal> rays;
197 QImage* blankSurface;
201 QRect renderSlide(const SlideInfo &slide, int col1 = -1, int col2 = -1);
202 QImage* surface(int slideIndex);
205 // ------------- PictureFlowState ---------------------------------------
207 PictureFlowState::PictureFlowState():
208 backgroundColor(0), slideWidth(150), slideHeight(200),
209 reflectionEffect(PictureFlow::BlurredReflection), centerIndex(0)
213 PictureFlowState::~PictureFlowState()
217 // readjust the settings, call this when slide dimension is changed
218 void PictureFlowState::reposition()
220 angle = 70 * IANGLE_MAX / 360; // approx. 70 degrees tilted
222 offsetX = slideWidth / 2 * (PFREAL_ONE - fcos(angle));
223 offsetY = slideWidth / 2 * fsin(angle);
224 offsetX += slideWidth * PFREAL_ONE;
225 offsetY += slideWidth * PFREAL_ONE / 4;
229 // adjust slides so that they are in "steady state" position
230 void PictureFlowState::reset()
232 centerSlide.angle = 0;
235 centerSlide.slideIndex = centerIndex;
236 centerSlide.blend = 256;
238 leftSlides.resize(6);
239 for (int i = 0; i < (int)leftSlides.count(); i++) {
240 SlideInfo& si = leftSlides[i];
242 si.cx = -(offsetX + spacing * i * PFREAL_ONE);
244 si.slideIndex = centerIndex - 1 - i;
246 if (i == (int)leftSlides.count() - 2)
248 if (i == (int)leftSlides.count() - 1)
252 rightSlides.resize(6);
253 for (int i = 0; i < (int)rightSlides.count(); i++) {
254 SlideInfo& si = rightSlides[i];
256 si.cx = offsetX + spacing * i * PFREAL_ONE;
258 si.slideIndex = centerIndex + 1 + i;
260 if (i == (int)rightSlides.count() - 2)
262 if (i == (int)rightSlides.count() - 1)
267 // ------------- PictureFlowAnimator ---------------------------------------
269 PictureFlowAnimator::PictureFlowAnimator():
270 state(0), target(0), step(0), frame(0)
274 void PictureFlowAnimator::start(int slide)
277 if (!animateTimer.isActive() && state) {
278 step = (target < state->centerSlide.slideIndex) ? -1 : 1;
279 animateTimer.start(30);
283 void PictureFlowAnimator::stop(int slide)
291 void PictureFlowAnimator::update()
293 if (!animateTimer.isActive())
303 // deaccelerate when approaching the target
304 const int max = 2 * 65536;
307 fi -= (target << 16);
312 int ia = IANGLE_MAX * (fi - max / 2) / (max * 2);
313 speed = 512 + 16384 * (PFREAL_ONE + fsin(ia)) / PFREAL_ONE;
316 frame += speed * step;
318 int index = frame >> 16;
319 int pos = frame & 0xffff;
320 int neg = 65536 - pos;
321 int tick = (step < 0) ? neg : pos;
322 PFreal ftick = (tick * PFREAL_ONE) >> 16;
327 if (state->centerIndex != index) {
328 state->centerIndex = index;
330 state->centerSlide.slideIndex = state->centerIndex;
331 for (int i = 0; i < (int)state->leftSlides.count(); i++)
332 state->leftSlides[i].slideIndex = state->centerIndex - 1 - i;
333 for (int i = 0; i < (int)state->rightSlides.count(); i++)
334 state->rightSlides[i].slideIndex = state->centerIndex + 1 + i;
337 state->centerSlide.angle = (step * tick * state->angle) >> 16;
338 state->centerSlide.cx = -step * fmul(state->offsetX, ftick);
339 state->centerSlide.cy = fmul(state->offsetY, ftick);
341 if (state->centerIndex == target) {
347 for (int i = 0; i < (int)state->leftSlides.count(); i++) {
348 SlideInfo& si = state->leftSlides[i];
349 si.angle = state->angle;
350 si.cx = -(state->offsetX + state->spacing * i * PFREAL_ONE + step * state->spacing * ftick);
351 si.cy = state->offsetY;
354 for (int i = 0; i < (int)state->rightSlides.count(); i++) {
355 SlideInfo& si = state->rightSlides[i];
356 si.angle = -state->angle;
357 si.cx = state->offsetX + state->spacing * i * PFREAL_ONE - step * state->spacing * ftick;
358 si.cy = state->offsetY;
362 PFreal ftick = (neg * PFREAL_ONE) >> 16;
363 state->rightSlides[0].angle = -(neg * state->angle) >> 16;
364 state->rightSlides[0].cx = fmul(state->offsetX, ftick);
365 state->rightSlides[0].cy = fmul(state->offsetY, ftick);
367 PFreal ftick = (pos * PFREAL_ONE) >> 16;
368 state->leftSlides[0].angle = (pos * state->angle) >> 16;
369 state->leftSlides[0].cx = -fmul(state->offsetX, ftick);
370 state->leftSlides[0].cy = fmul(state->offsetY, ftick);
373 // must change direction ?
374 if (target < index) if (step > 0)
376 if (target > index) if (step < 0)
379 // the first and last slide must fade in/fade out
380 int nleft = state->leftSlides.count();
381 int nright = state->rightSlides.count();
382 int fade = pos / 256;
384 for (int index = 0; index < nleft; index++) {
386 if (index == nleft - 1)
387 blend = (step > 0) ? 0 : 128 - fade / 2;
388 if (index == nleft - 2)
389 blend = (step > 0) ? 128 - fade / 2 : 256 - fade / 2;
390 if (index == nleft - 3)
391 blend = (step > 0) ? 256 - fade / 2 : 256;
392 state->leftSlides[index].blend = blend;
394 for (int index = 0; index < nright; index++) {
395 int blend = (index < nright - 2) ? 256 : 128;
396 if (index == nright - 1)
397 blend = (step > 0) ? fade / 2 : 0;
398 if (index == nright - 2)
399 blend = (step > 0) ? 128 + fade / 2 : fade / 2;
400 if (index == nright - 3)
401 blend = (step > 0) ? 256 : 128 + fade / 2;
402 state->rightSlides[index].blend = blend;
407 // ------------- PictureFlowSoftwareRenderer ---------------------------------------
409 PictureFlowSoftwareRenderer::PictureFlowSoftwareRenderer():
410 PictureFlowAbstractRenderer(), size(0, 0), bgcolor(0), effect(-1), blankSurface(0)
414 PictureFlowSoftwareRenderer::~PictureFlowSoftwareRenderer()
420 void PictureFlowSoftwareRenderer::paint()
425 if (widget->size() != size)
428 if (state->backgroundColor != bgcolor) {
429 bgcolor = state->backgroundColor;
432 if ((int)(state->reflectionEffect) != effect) {
433 effect = (int)state->reflectionEffect;
439 QPainter painter(widget);
440 painter.drawImage(QPoint(0, 0), buffer);
442 QModelIndex index = state->model->index( state->centerIndex, 0, state->model->currentIndex().parent() );
444 if( index.isValid() )
446 QString title = PLModel::getMeta( index, COLUMN_TITLE );
447 QString artist = PLModel::getMeta( index, COLUMN_ARTIST );
448 QFont font( index.data( Qt::FontRole ).value<QFont>() );
449 painter.setFont( font );
450 painter.setBrush( QBrush( Qt::lightGray ) );
451 painter.setPen( QColor( Qt::lightGray ) );
452 QFontMetrics fm = painter.fontMetrics();
454 QPoint textstart( buffer.width() / 2 - state->slideWidth/2 , buffer.height() / 2 + state->slideWidth/2 + 5 );
455 QPoint artiststart( 0, fm.xHeight() * 2 );
457 painter.drawText( textstart, title );
459 textstart += artiststart;
460 painter.drawText( textstart, artist);
464 void PictureFlowSoftwareRenderer::init()
471 size = widget->size();
472 int ww = size.width();
473 int wh = size.height();
474 int w = (ww + 1) / 2;
475 int h = (wh + 1) / 2;
477 buffer = QImage(ww, wh, QImage::Format_RGB32);
478 buffer.fill(bgcolor);
481 for (int i = 0; i < w; i++) {
482 PFreal gg = ((PFREAL_ONE >> 1) + i * PFREAL_ONE) / (2 * h);
490 // TODO: optimize this with lookup tables
491 static QRgb blendColor(QRgb c1, QRgb c2, int blend)
493 int r = qRed(c1) * blend / 256 + qRed(c2) * (256 - blend) / 256;
494 int g = qGreen(c1) * blend / 256 + qGreen(c2) * (256 - blend) / 256;
495 int b = qBlue(c1) * blend / 256 + qBlue(c2) * (256 - blend) / 256;
496 return qRgb(r, g, b);
500 static QImage* prepareSurface(const QImage* slideImage, int w, int h, QRgb bgcolor,
501 PictureFlow::ReflectionEffect reflectionEffect)
503 Qt::TransformationMode mode = Qt::SmoothTransformation;
504 QImage img = slideImage->scaled(w, h, Qt::IgnoreAspectRatio, mode);
506 // slightly larger, to accomodate for the reflection
510 // offscreen buffer: black is sweet
511 QImage* result = new QImage(hs, w, QImage::Format_RGB32);
512 QPainter imagePainter( result );
515 result->fill(bgcolor);
517 // transpose the image, this is to speed-up the rendering
518 // because we process one column at a time
519 // (and much better and faster to work row-wise, i.e in one scanline)
521 for (int x = 0; x < w; x++)
522 for (int y = 0; y < h; y++)
523 result->setPixel(hofs + y, x, img.pixel(x, y));
525 imagePainter.drawImage( hofs+h, 0, img );
526 if (reflectionEffect != PictureFlow::NoReflection) {
527 // create the reflection
528 int ht = hs - h - hofs;
530 for (int x = 0; x < w; x++)
532 QRgb *line = (QRgb*)(result->scanLine( x ));
533 for (int y = 0; y < ht; y++) {
534 QRgb color = img.pixel(x, img.height() - y - 1);
535 line[h+hofs+y] = blendColor( color, bgcolor, 128*(hte-y)/hte );
536 //result->setPixel(h + hofs + y, x, blendColor(color, bgcolor, 128*(hte - y) / hte));
540 if (reflectionEffect == PictureFlow::BlurredReflection) {
541 // blur the reflection everything first
542 // Based on exponential blur algorithm by Jani Huhtanen
543 QRect rect(hs / 2, 0, hs / 2, w);
544 rect &= result->rect();
547 int r2 = rect.bottom();
548 int c1 = rect.left();
549 int c2 = rect.right();
551 int bpl = result->bytesPerLine();
555 // how many times blur is applied?
556 // for low-end system, limit this to only 1 loop
557 for (int loop = 0; loop < 2; loop++) {
558 for (int col = c1; col <= c2; col++) {
559 p = result->scanLine(r1) + col * 4;
560 for (int i = 0; i < 3; i++)
564 for (int j = r1; j < r2; j++, p += bpl)
565 for (int i = 0; i < 3; i++)
566 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
569 for (int row = r1; row <= r2; row++) {
570 p = result->scanLine(row) + c1 * 4;
571 for (int i = 0; i < 3; i++)
575 for (int j = c1; j < c2; j++, p += 4)
576 for (int i = 0; i < 3; i++)
577 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
580 for (int col = c1; col <= c2; col++) {
581 p = result->scanLine(r2) + col * 4;
582 for (int i = 0; i < 3; i++)
586 for (int j = r1; j < r2; j++, p -= bpl)
587 for (int i = 0; i < 3; i++)
588 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
591 for (int row = r1; row <= r2; row++) {
592 p = result->scanLine(row) + c2 * 4;
593 for (int i = 0; i < 3; i++)
597 for (int j = c1; j < c2; j++, p -= 4)
598 for (int i = 0; i < 3; i++)
599 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
603 // overdraw to leave only the reflection blurred (but not the actual image)
604 imagePainter.drawImage( hofs, 0, img.mirrored().transformed( rotation ) );
606 for (int x = 0; x < w; x++)
607 for (int y = 0; y < h; y++)
608 result->setPixel(hofs + y, x, img.pixel(x, y));
616 QImage* PictureFlowSoftwareRenderer::surface(int slideIndex)
622 if (slideIndex >= state->model->rowCount( state->model->currentIndex().parent() ) )
625 QImage* img = new QImage(PLModel::getArtPixmap( state->model->index( slideIndex, 0, state->model->currentIndex().parent() ),
626 QSize( state->slideWidth, state->slideHeight ) ).toImage());
628 QImage* sr = prepareSurface(img, state->slideWidth, state->slideHeight, bgcolor, state->reflectionEffect);
634 // Renders a slide to offscreen buffer. Returns a rect of the rendered area.
635 // col1 and col2 limit the column for rendering.
636 QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, int col2)
638 int blend = slide.blend;
642 QImage* src = surface(slide.slideIndex);
646 QRect rect(0, 0, 0, 0);
648 int sw = src->height();
649 int sh = src->width();
650 int h = buffer.height();
651 int w = buffer.width();
659 col1 = (col1 >= 0) ? col1 : 0;
660 col2 = (col2 >= 0) ? col2 : w - 1;
661 col1 = qMin(col1, w - 1);
662 col2 = qMin(col2, w - 1);
665 int distance = h * 100 / zoom;
666 PFreal sdx = fcos(slide.angle);
667 PFreal sdy = fsin(slide.angle);
668 PFreal xs = slide.cx - state->slideWidth * sdx / 2;
669 PFreal ys = slide.cy - state->slideWidth * sdy / 2;
670 PFreal dist = distance * PFREAL_ONE;
672 int xi = qMax((PFreal)0, (w * PFREAL_ONE / 2) + fdiv(xs * h, dist + ys) >> PFREAL_SHIFT);
681 for (int x = qMax(xi, col1); x <= col2; x++) {
685 fk = fk - fdiv(sdx, sdy);
686 hity = -fdiv((rays[x] * distance - slide.cx + slide.cy * sdx / sdy), fk);
689 dist = distance * PFREAL_ONE + hity;
693 PFreal hitx = fmul(dist, rays[x]);
694 PFreal hitdist = fdiv(hitx - slide.cx, sdx);
696 int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
709 QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x;
710 QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x;
711 QRgb pixelstep = pixel2 - pixel1;
713 int center = (sh / 2);
715 int p1 = center * PFREAL_ONE - dy / 2;
716 int p2 = center * PFREAL_ONE + dy / 2;
718 const QRgb *ptr = (const QRgb*)(src->scanLine(column));
720 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
721 *pixel1 = ptr[p1 >> PFREAL_SHIFT];
722 *pixel2 = ptr[p2 >> PFREAL_SHIFT];
731 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
732 QRgb c1 = ptr[p1 >> PFREAL_SHIFT];
733 QRgb c2 = ptr[p2 >> PFREAL_SHIFT];
734 *pixel1 = blendColor(c1, bgcolor, blend);
735 *pixel2 = blendColor(c2, bgcolor, blend);
746 rect.setBottom(h - 1);
751 void PictureFlowSoftwareRenderer::renderSlides()
753 int nleft = state->leftSlides.count();
754 int nright = state->rightSlides.count();
756 QRect r = renderSlide(state->centerSlide);
760 for (int index = 0; index < nleft; index++) {
761 QRect rs = renderSlide(state->leftSlides[index], 0, c1 - 1);
765 for (int index = 0; index < nright; index++) {
766 QRect rs = renderSlide(state->rightSlides[index], c2 + 1, buffer.width());
772 // Render the slides. Updates only the offscreen buffer.
773 void PictureFlowSoftwareRenderer::render()
775 buffer.fill(state->backgroundColor);
780 // -----------------------------------------
782 class PictureFlowPrivate
785 PictureFlowState* state;
786 PictureFlowAnimator* animator;
787 PictureFlowAbstractRenderer* renderer;
792 PictureFlow::PictureFlow(QWidget* parent, PLModel* _p_model): QWidget(parent)
794 d = new PictureFlowPrivate;
795 d->state = new PictureFlowState;
796 d->state->model = _p_model;
798 d->state->reposition();
800 d->renderer = new PictureFlowSoftwareRenderer;
801 d->renderer->state = d->state;
802 d->renderer->widget = this;
805 d->animator = new PictureFlowAnimator;
806 d->animator->state = d->state;
807 QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
809 QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));
811 setAttribute(Qt::WA_StaticContents, true);
812 setAttribute(Qt::WA_OpaquePaintEvent, true);
813 setAttribute(Qt::WA_NoSystemBackground, true);
816 PictureFlow::~PictureFlow()
824 int PictureFlow::slideCount() const
826 return d->state->model->rowCount( d->state->model->currentIndex().parent() );
829 QColor PictureFlow::backgroundColor() const
831 return QColor(d->state->backgroundColor);
834 void PictureFlow::setBackgroundColor(const QColor& c)
836 d->state->backgroundColor = c.rgb();
840 QSize PictureFlow::slideSize() const
842 return QSize(d->state->slideWidth, d->state->slideHeight);
845 void PictureFlow::setSlideSize(QSize size)
847 d->state->slideWidth = size.width();
848 d->state->slideHeight = size.height();
849 d->state->reposition();
853 PictureFlow::ReflectionEffect PictureFlow::reflectionEffect() const
855 return d->state->reflectionEffect;
858 void PictureFlow::setReflectionEffect(ReflectionEffect effect)
860 d->state->reflectionEffect = effect;
864 int PictureFlow::centerIndex() const
866 return d->state->centerIndex;
869 void PictureFlow::setCenterIndex(int index)
871 index = qMin(index, slideCount() - 1);
872 index = qMax(index, 0);
873 d->state->centerIndex = index;
875 d->animator->stop(index);
879 void PictureFlow::clear()
885 void PictureFlow::render()
887 d->renderer->dirty = true;
891 void PictureFlow::triggerRender()
893 d->triggerTimer.setSingleShot(true);
894 d->triggerTimer.start(0);
897 void PictureFlow::showPrevious()
899 int step = d->animator->step;
900 int center = d->state->centerIndex;
903 d->animator->start(center);
907 d->animator->start(center - 1);
910 d->animator->target = qMax(0, center - 2);
913 void PictureFlow::showNext()
915 int step = d->animator->step;
916 int center = d->state->centerIndex;
919 d->animator->start(center);
922 if (center < slideCount() - 1)
923 d->animator->start(center + 1);
926 d->animator->target = qMin(center + 2, slideCount() - 1);
929 void PictureFlow::showSlide(int index)
931 index = qMax(index, 0);
932 index = qMin(slideCount() - 1, index);
933 if (index == d->state->centerSlide.slideIndex)
936 d->animator->start(index);
939 void PictureFlow::keyPressEvent(QKeyEvent* event)
941 if (event->key() == Qt::Key_Left) {
942 if (event->modifiers() == Qt::ControlModifier)
943 showSlide(centerIndex() - 10);
950 if (event->key() == Qt::Key_Right) {
951 if (event->modifiers() == Qt::ControlModifier)
952 showSlide(centerIndex() + 10);
962 void PictureFlow::mousePressEvent(QMouseEvent* event)
964 if (event->x() > width() / 2 + d->state->slideWidth/2 )
966 else if (event->x() < width() / 2 - d->state->slideWidth/2 )
968 else if ( d->state->model->currentIndex().row() != d->state->centerIndex )
969 d->state->model->activateItem( d->state->model->index( d->state->centerIndex, 0,
970 d->state->model->currentIndex().parent() ) );
973 void PictureFlow::paintEvent(QPaintEvent* event)
976 d->renderer->paint();
979 void PictureFlow::resizeEvent(QResizeEvent* event)
982 QWidget::resizeEvent(event);
985 void PictureFlow::updateAnimation()
987 int old_center = d->state->centerIndex;
988 d->animator->update();
990 if (d->state->centerIndex != old_center)
991 emit centerIndexChanged(d->state->centerIndex);