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 rotation.scale(1,-1);
516 rotation.translate( 0, hofs );
517 result->fill(bgcolor);
519 // transpose the image, this is to speed-up the rendering
520 // because we process one column at a time
521 // (and much better and faster to work row-wise, i.e in one scanline)
523 for (int x = 0; x < w; x++)
524 for (int y = 0; y < h; y++)
525 result->setPixel(hofs + y, x, img.pixel(x, y));
527 imagePainter.drawImage( hofs+h, 0, img );
528 if (reflectionEffect != PictureFlow::NoReflection) {
529 // create the reflection
530 int ht = hs - h - hofs;
532 for (int x = 0; x < w; x++)
534 QRgb *line = (QRgb*)(result->scanLine( x ));
535 for (int y = 0; y < ht; y++) {
536 QRgb color = img.pixel(x, img.height() - y - 1);
537 line[h+hofs+y] = blendColor( color, bgcolor, 128*(hte-y)/hte );
538 //result->setPixel(h + hofs + y, x, blendColor(color, bgcolor, 128*(hte - y) / hte));
542 if (reflectionEffect == PictureFlow::BlurredReflection) {
543 // blur the reflection everything first
544 // Based on exponential blur algorithm by Jani Huhtanen
545 QRect rect(hs / 2, 0, hs / 2, w);
546 rect &= result->rect();
549 int r2 = rect.bottom();
550 int c1 = rect.left();
551 int c2 = rect.right();
553 int bpl = result->bytesPerLine();
557 // how many times blur is applied?
558 // for low-end system, limit this to only 1 loop
559 for (int loop = 0; loop < 2; loop++) {
560 for (int col = c1; col <= c2; col++) {
561 p = result->scanLine(r1) + col * 4;
562 for (int i = 0; i < 3; i++)
566 for (int j = r1; j < r2; j++, p += bpl)
567 for (int i = 0; i < 3; i++)
568 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
571 for (int row = r1; row <= r2; row++) {
572 p = result->scanLine(row) + c1 * 4;
573 for (int i = 0; i < 3; i++)
577 for (int j = c1; j < c2; j++, p += 4)
578 for (int i = 0; i < 3; i++)
579 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
582 for (int col = c1; col <= c2; col++) {
583 p = result->scanLine(r2) + col * 4;
584 for (int i = 0; i < 3; i++)
588 for (int j = r1; j < r2; j++, p -= bpl)
589 for (int i = 0; i < 3; i++)
590 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
593 for (int row = r1; row <= r2; row++) {
594 p = result->scanLine(row) + c2 * 4;
595 for (int i = 0; i < 3; i++)
599 for (int j = c1; j < c2; j++, p -= 4)
600 for (int i = 0; i < 3; i++)
601 p[i] = (rgba[i] += (((p[i] << 4) - rgba[i])) >> 1) >> 4;
605 // overdraw to leave only the reflection blurred (but not the actual image)
606 imagePainter.setTransform( rotation );
607 imagePainter.drawImage( 0, 0, img );
609 for (int x = 0; x < w; x++)
610 for (int y = 0; y < h; y++)
611 result->setPixel(hofs + y, x, img.pixel(x, y));
619 QImage* PictureFlowSoftwareRenderer::surface(int slideIndex)
625 if (slideIndex >= state->model->rowCount( state->model->currentIndex().parent() ) )
628 QImage* img = new QImage(PLModel::getArtPixmap( state->model->index( slideIndex, 0, state->model->currentIndex().parent() ),
629 QSize( state->slideWidth, state->slideHeight ) ).toImage());
631 QImage* sr = prepareSurface(img, state->slideWidth, state->slideHeight, bgcolor, state->reflectionEffect);
637 // Renders a slide to offscreen buffer. Returns a rect of the rendered area.
638 // col1 and col2 limit the column for rendering.
639 QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, int col2)
641 int blend = slide.blend;
645 QImage* src = surface(slide.slideIndex);
649 QRect rect(0, 0, 0, 0);
651 int sw = src->height();
652 int sh = src->width();
653 int h = buffer.height();
654 int w = buffer.width();
662 col1 = (col1 >= 0) ? col1 : 0;
663 col2 = (col2 >= 0) ? col2 : w - 1;
664 col1 = qMin(col1, w - 1);
665 col2 = qMin(col2, w - 1);
668 int distance = h * 100 / zoom;
669 PFreal sdx = fcos(slide.angle);
670 PFreal sdy = fsin(slide.angle);
671 PFreal xs = slide.cx - state->slideWidth * sdx / 2;
672 PFreal ys = slide.cy - state->slideWidth * sdy / 2;
673 PFreal dist = distance * PFREAL_ONE;
675 int xi = qMax((PFreal)0, (w * PFREAL_ONE / 2) + fdiv(xs * h, dist + ys) >> PFREAL_SHIFT);
684 for (int x = qMax(xi, col1); x <= col2; x++) {
688 fk = fk - fdiv(sdx, sdy);
689 hity = -fdiv((rays[x] * distance - slide.cx + slide.cy * sdx / sdy), fk);
692 dist = distance * PFREAL_ONE + hity;
696 PFreal hitx = fmul(dist, rays[x]);
697 PFreal hitdist = fdiv(hitx - slide.cx, sdx);
699 int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
712 QRgb* pixel1 = (QRgb*)(buffer.scanLine(y1)) + x;
713 QRgb* pixel2 = (QRgb*)(buffer.scanLine(y2)) + x;
714 QRgb pixelstep = pixel2 - pixel1;
716 int center = (sh / 2);
718 int p1 = center * PFREAL_ONE - dy / 2;
719 int p2 = center * PFREAL_ONE + dy / 2;
721 const QRgb *ptr = (const QRgb*)(src->scanLine(column));
723 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
724 *pixel1 = ptr[p1 >> PFREAL_SHIFT];
725 *pixel2 = ptr[p2 >> PFREAL_SHIFT];
734 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
735 QRgb c1 = ptr[p1 >> PFREAL_SHIFT];
736 QRgb c2 = ptr[p2 >> PFREAL_SHIFT];
737 *pixel1 = blendColor(c1, bgcolor, blend);
738 *pixel2 = blendColor(c2, bgcolor, blend);
749 rect.setBottom(h - 1);
754 void PictureFlowSoftwareRenderer::renderSlides()
756 int nleft = state->leftSlides.count();
757 int nright = state->rightSlides.count();
759 QRect r = renderSlide(state->centerSlide);
763 for (int index = 0; index < nleft; index++) {
764 QRect rs = renderSlide(state->leftSlides[index], 0, c1 - 1);
768 for (int index = 0; index < nright; index++) {
769 QRect rs = renderSlide(state->rightSlides[index], c2 + 1, buffer.width());
775 // Render the slides. Updates only the offscreen buffer.
776 void PictureFlowSoftwareRenderer::render()
778 buffer.fill(state->backgroundColor);
783 // -----------------------------------------
785 class PictureFlowPrivate
788 PictureFlowState* state;
789 PictureFlowAnimator* animator;
790 PictureFlowAbstractRenderer* renderer;
795 PictureFlow::PictureFlow(QWidget* parent, PLModel* _p_model): QWidget(parent)
797 d = new PictureFlowPrivate;
798 d->state = new PictureFlowState;
799 d->state->model = _p_model;
801 d->state->reposition();
803 d->renderer = new PictureFlowSoftwareRenderer;
804 d->renderer->state = d->state;
805 d->renderer->widget = this;
808 d->animator = new PictureFlowAnimator;
809 d->animator->state = d->state;
810 QObject::connect(&d->animator->animateTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
812 QObject::connect(&d->triggerTimer, SIGNAL(timeout()), this, SLOT(render()));
814 setAttribute(Qt::WA_StaticContents, true);
815 setAttribute(Qt::WA_OpaquePaintEvent, true);
816 setAttribute(Qt::WA_NoSystemBackground, true);
819 PictureFlow::~PictureFlow()
827 int PictureFlow::slideCount() const
829 return d->state->model->rowCount( d->state->model->currentIndex().parent() );
832 QColor PictureFlow::backgroundColor() const
834 return QColor(d->state->backgroundColor);
837 void PictureFlow::setBackgroundColor(const QColor& c)
839 d->state->backgroundColor = c.rgb();
843 QSize PictureFlow::slideSize() const
845 return QSize(d->state->slideWidth, d->state->slideHeight);
848 void PictureFlow::setSlideSize(QSize size)
850 d->state->slideWidth = size.width();
851 d->state->slideHeight = size.height();
852 d->state->reposition();
856 PictureFlow::ReflectionEffect PictureFlow::reflectionEffect() const
858 return d->state->reflectionEffect;
861 void PictureFlow::setReflectionEffect(ReflectionEffect effect)
863 d->state->reflectionEffect = effect;
867 int PictureFlow::centerIndex() const
869 return d->state->centerIndex;
872 void PictureFlow::setCenterIndex(int index)
874 index = qMin(index, slideCount() - 1);
875 index = qMax(index, 0);
876 d->state->centerIndex = index;
878 d->animator->stop(index);
882 void PictureFlow::clear()
888 void PictureFlow::render()
890 d->renderer->dirty = true;
894 void PictureFlow::triggerRender()
896 d->triggerTimer.setSingleShot(true);
897 d->triggerTimer.start(0);
900 void PictureFlow::showPrevious()
902 int step = d->animator->step;
903 int center = d->state->centerIndex;
906 d->animator->start(center);
910 d->animator->start(center - 1);
913 d->animator->target = qMax(0, center - 2);
916 void PictureFlow::showNext()
918 int step = d->animator->step;
919 int center = d->state->centerIndex;
922 d->animator->start(center);
925 if (center < slideCount() - 1)
926 d->animator->start(center + 1);
929 d->animator->target = qMin(center + 2, slideCount() - 1);
932 void PictureFlow::showSlide(int index)
934 index = qMax(index, 0);
935 index = qMin(slideCount() - 1, index);
936 if (index == d->state->centerSlide.slideIndex)
939 d->animator->start(index);
942 void PictureFlow::keyPressEvent(QKeyEvent* event)
944 if (event->key() == Qt::Key_Left) {
945 if (event->modifiers() == Qt::ControlModifier)
946 showSlide(centerIndex() - 10);
953 if (event->key() == Qt::Key_Right) {
954 if (event->modifiers() == Qt::ControlModifier)
955 showSlide(centerIndex() + 10);
965 void PictureFlow::mousePressEvent(QMouseEvent* event)
967 if (event->x() > width() / 2 + d->state->slideWidth/2 )
969 else if (event->x() < width() / 2 - d->state->slideWidth/2 )
971 else if ( d->state->model->currentIndex().row() != d->state->centerIndex )
972 d->state->model->activateItem( d->state->model->index( d->state->centerIndex, 0,
973 d->state->model->currentIndex().parent() ) );
976 void PictureFlow::paintEvent(QPaintEvent* event)
979 d->renderer->paint();
982 void PictureFlow::resizeEvent(QResizeEvent* event)
985 QWidget::resizeEvent(event);
988 void PictureFlow::updateAnimation()
990 int old_center = d->state->centerIndex;
991 d->animator->update();
993 if (d->state->centerIndex != old_center)
994 emit centerIndexChanged(d->state->centerIndex);