summaryrefslogtreecommitdiffstats
path: root/examples/animation/photobrowser
diff options
context:
space:
mode:
Diffstat (limited to 'examples/animation/photobrowser')
-rw-r--r--examples/animation/photobrowser/main.cpp52
-rw-r--r--examples/animation/photobrowser/menu.cpp125
-rw-r--r--examples/animation/photobrowser/menu.h50
-rw-r--r--examples/animation/photobrowser/photobrowser.pro17
-rw-r--r--examples/animation/photobrowser/river.cpp561
-rw-r--r--examples/animation/photobrowser/river.h81
-rw-r--r--examples/animation/photobrowser/riveritem.cpp95
-rw-r--r--examples/animation/photobrowser/riveritem.h36
8 files changed, 1017 insertions, 0 deletions
diff --git a/examples/animation/photobrowser/main.cpp b/examples/animation/photobrowser/main.cpp
new file mode 100644
index 0000000..98f2a9e
--- /dev/null
+++ b/examples/animation/photobrowser/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "river.h"
+#include "menu.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ if (app.arguments().size() == 1) {
+ qWarning("you have to specifiy a path to look for the photos");
+ return 0;
+ }
+
+
+ QGraphicsScene scene;
+ scene.setSceneRect(QRectF(QPointF(), River::fixedSize()));
+
+ QGraphicsView view(&scene);
+ view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ const int fw = view.frameWidth() * 2;
+ view.setFixedSize(River::fixedSize() + QSize(fw,fw));
+
+ River river(app.arguments()[1]);
+ scene.addItem(&river);
+
+ Menu menu(&river);
+ menu.addAction(QLatin1String("River Mode"), &river, SLOT(setRiverMode()));
+ menu.addAction(QLatin1String("Grid Mode"), &river, SLOT(setGridMode()));
+ menu.addAction(QLatin1String("Cover Flow"), &river, SLOT(setCoverMode()));
+ menu.addAction(QLatin1String("Hide Menu"), &menu, SLOT(hide()));
+ menu.addAction(QLatin1String("Exit"), &app, SLOT(quit()));
+ menu.setZValue(2);
+ menu.setFocus();
+
+ river.menu = &menu;
+ view.show();
+
+ return app.exec();
+}
diff --git a/examples/animation/photobrowser/menu.cpp b/examples/animation/photobrowser/menu.cpp
new file mode 100644
index 0000000..d4efe9c
--- /dev/null
+++ b/examples/animation/photobrowser/menu.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "menu.h"
+
+Menu::Menu(QGraphicsItem *parent) : QGraphicsWidget(parent), m_selected(0)
+{
+ setFlag(QGraphicsItem::ItemIsFocusable);
+ m_selection = new QGraphicsRectItem(this);
+ QLinearGradient linearGrad(QPointF(0, 0), QPointF(0,50));
+ linearGrad.setColorAt(0, QColor(255,255,255,128));
+ linearGrad.setColorAt(1, QColor(255,255,255,16));
+ m_selection->setBrush(linearGrad);
+ m_selection->setPen(QPen(Qt::transparent));
+}
+
+Menu::~Menu()
+{
+}
+
+
+MenuAction *Menu::addAction(const QString &text, QObject *receiver, const char* slot)
+{
+ MenuAction *action = new MenuAction(text, this);
+ if (!m_actions.isEmpty()) {
+ MenuAction *last = m_actions.last();
+ action->setPos(last->pos() + last->boundingRect().bottomLeft());
+ }
+ m_actions.append(action);
+ if (m_selection->boundingRect().width() < action->boundingRect().width())
+ m_selection->setRect(action->boundingRect());
+
+ QObject::connect(action, SIGNAL(triggered()), receiver, slot);
+ return action;
+}
+
+QRectF Menu::boundingRect() const
+{
+ QRectF res;
+ foreach (MenuAction *a, m_actions)
+ res |= a->boundingRect();
+ return res;
+}
+
+void Menu::keyPressEvent (QKeyEvent * event)
+{
+ switch (event->key()) {
+ case Qt::Key_Escape:
+ hide();
+ break;
+ case Qt::Key_Up:
+ m_selected -= 2;
+ case Qt::Key_Down:
+ if (!m_actions.isEmpty()) {
+ m_selected = (m_selected + 1 + m_actions.count()) % m_actions.count();
+ QItemAnimation *anim = new QItemAnimation(m_selection, QItemAnimation::Position);
+ anim->setEndValue(m_actions.at(m_selected)->pos());
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+ break;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (!m_actions.isEmpty()) {
+ QItemAnimation *anim = new QItemAnimation(m_selection, QItemAnimation::RotationX);
+ anim->setEndValue(m_selection->xRotation() < 180 ? qreal(360) : qreal(0));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ m_actions.at(m_selected)->trigger();
+ hide();
+ }
+ break;
+ default:
+ QGraphicsItem::keyPressEvent(event);
+ }
+}
+
+void Menu::show()
+{
+ QItemAnimation *anim = new QItemAnimation(this, QItemAnimation::Opacity);
+ anim->setEndValue(qreal(1.));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(m_selection, QItemAnimation::ScaleFactorX);
+ anim->setEndValue(qreal(1));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(m_selection, QItemAnimation::ScaleFactorY);
+ anim->setEndValue(qreal(1));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ setFocus();
+}
+
+void Menu::hide()
+{
+ QItemAnimation *anim = new QItemAnimation(m_selection, QItemAnimation::ScaleFactorX);
+ anim->setEndValue(qreal(.1));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(m_selection, QItemAnimation::ScaleFactorY);
+ anim->setEndValue(qreal(.1));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(this, QItemAnimation::Opacity);
+ anim->setEndValue(qreal(0));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ parentItem()->setFocus();
+}
+
+
+MenuAction::MenuAction(const QString &text, Menu * parent)
+ : QGraphicsTextItem(text,parent)
+{
+ QFont f = font();
+ f.setPointSize(18);
+ setFont(f);
+ setDefaultTextColor(Qt::white);
+}
+
+void MenuAction::trigger()
+{
+ emit triggered();
+}
diff --git a/examples/animation/photobrowser/menu.h b/examples/animation/photobrowser/menu.h
new file mode 100644
index 0000000..9514cfe
--- /dev/null
+++ b/examples/animation/photobrowser/menu.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef __MENU__H__
+#define __MENU__H__
+
+#include <QtGui>
+
+class MenuAction;
+
+class Menu : public QGraphicsWidget
+{
+ Q_OBJECT
+public:
+ Menu(QGraphicsItem *parent);
+ ~Menu();
+
+ MenuAction *addAction(const QString&, QObject *receiver = 0, const char* slot = 0 );
+
+ QRectF boundingRect() const;
+ void keyPressEvent ( QKeyEvent * event );
+public slots:
+ void show();
+ void hide();
+private:
+ QList<MenuAction*> m_actions;
+ QGraphicsRectItem *m_selection;
+ int m_selected;
+};
+
+class MenuAction : public QGraphicsTextItem
+{
+ Q_OBJECT
+public:
+ MenuAction(const QString &text, Menu * parent);
+ void trigger();
+signals:
+ void triggered();
+};
+
+
+#endif //__RIVERITEM__H__
diff --git a/examples/animation/photobrowser/photobrowser.pro b/examples/animation/photobrowser/photobrowser.pro
new file mode 100644
index 0000000..21f03d6
--- /dev/null
+++ b/examples/animation/photobrowser/photobrowser.pro
@@ -0,0 +1,17 @@
+######################################################################
+# Automatically generated by qmake (2.01a) ven. 22. août 13:09:33 2008
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+SOURCES += main.cpp \
+ river.cpp \
+ riveritem.cpp \
+ menu.cpp
+HEADERS += river.h \
+ riveritem.h \
+ menu.h
diff --git a/examples/animation/photobrowser/river.cpp b/examples/animation/photobrowser/river.cpp
new file mode 100644
index 0000000..f3dd0746
--- /dev/null
+++ b/examples/animation/photobrowser/river.cpp
@@ -0,0 +1,561 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "river.h"
+#include "riveritem.h"
+
+#include "qvariantanimation.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QGraphicsScene>
+#include <QtGui/QPainter>
+
+
+#define GRID_ROW_COUNT 3
+#define GRID_COLUMN_COUNT 2
+#define GRID_DIMENSIONS (GRID_ROW_COUNT * GRID_COLUMN_COUNT)
+#define ITEM_COUNT 12
+
+#define RIVER_MAGNIFY(ITEM) (qreal(0.50) + (ITEM)->zValue()*2 )
+#define GRID_MAGNIFY qreal(1.5)
+#define GRID_CURRENT_MAGNIFY 2
+
+River::River(const QString &path) :
+m_images(QDir(path).entryInfoList(QStringList() << QLatin1String("*.jpg") << QLatin1String("*.png"))),
+m_currentImage(0), m_mode(RiverMode), m_selectedItem(-1) , m_topLeftIndex(-1)
+{
+ setFocusPolicy(Qt::StrongFocus);
+ setGeometry(QRectF( QPointF(), fixedSize()));
+
+
+ for (int i = 0; i < ITEM_COUNT; ++i) {
+ RiverItem * item = new RiverItem(this);
+
+ //here we also randomize the x position (not when looping)
+ const int x = qrand() % fixedSize().width();
+ item->setPos(x, -1);
+
+ m_items.insert(m_currentImage, item);
+ addUnusedRiverItem(item);
+ }
+
+}
+
+QPointF River::gridItemPosition(int row, int col) const
+{
+ if (col < 0) {
+ col += GRID_COLUMN_COUNT;
+ row --;
+ }
+ return QPointF(rect().width()*(col*2 + 1)/(GRID_COLUMN_COUNT*2),
+ rect().height()*(row*2 + 1)/(GRID_ROW_COUNT*2));
+}
+
+QPixmap River::pixmap(int index) const
+{
+ if (index < 0 || index >= m_images.size())
+ return QPixmap();
+
+ if (m_pixmaps.size() <= index) {
+ m_pixmaps.resize(index+1);
+ }
+
+ if (m_pixmaps.at(index).isNull()) {
+ m_pixmaps[index] = QPixmap(m_images.at(index).absoluteFilePath());
+ }
+
+ return m_pixmaps.at(index);
+}
+
+void River::addUnusedRiverItem(RiverItem * item)
+{
+ if (m_images.isEmpty())
+ return;
+
+ QRectF realItemRect = item->mapToParent(item->boundingRect()).boundingRect();
+
+ int y = item->pos().y();
+ int x = item->pos().x();
+ if (x >= fixedSize().width() || x < -realItemRect.width() || y < 0) {
+ //we set the new pixmap
+
+ m_items.remove(m_items.key(item));
+
+ while (m_items.contains(m_currentImage))
+ m_currentImage = (m_currentImage + 1 ) % m_images.size();
+
+ item->setPixmap(pixmap(m_currentImage));
+
+ m_items.insert(m_currentImage, item);
+ //this manages looping as well
+ m_currentImage = (m_currentImage + 1 ) % m_images.size();
+
+ item->setZValue(qreal(qrand()%100)/200.0);
+
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(RIVER_MAGNIFY(item));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(RIVER_MAGNIFY(item));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+
+ realItemRect = item->mapToParent(item->boundingRect()).boundingRect();
+
+ y = -realItemRect.y() + qrand() % (fixedSize().height() - int(realItemRect.height()));
+ if (x >= fixedSize().width()) {
+ x = -realItemRect.width()/2;
+ }
+ }
+
+ item->setPos(x, y);
+
+ const QPointF target(QPointF(fixedSize().width() + realItemRect.width()/2, y));
+
+ const int distance = target.x() - x;
+
+ const int duration = (40 - 50*item->zValue() ) * distance;
+ QItemAnimation *a = new QItemAnimation(item, QItemAnimation::Position, scene());
+ a->setEndValue(target);
+ a->setDuration(duration);
+ a->start(QAbstractAnimation::DeleteWhenStopped);
+ connect(a, SIGNAL(finished()), SLOT(animationFinished()));
+}
+
+void River::animationFinished()
+{
+ QItemAnimation *anim = qobject_cast<QItemAnimation*>(sender());
+ if (!anim || anim->propertyName() != QItemAnimation::Position)
+ return;
+
+ /*RiverItem *item = static_cast<RiverItem*>(anim->graphicsItem());
+ if (m_mode != RiverMode) {*/
+ /*int key = m_items.key(item);
+ if (key < m_topLeftIndex || key >= m_topLeftIndex + GRID_DIMENSIONS) {
+ delete item;
+ m_items.remove(key);
+ }*/
+ //return;
+
+ //}
+
+ addUnusedRiverItem(static_cast<RiverItem*>(anim->targetItem()));
+}
+
+void River::switchPaused()
+{
+ const bool paused = m_pausedAnimations.isEmpty();
+ if (paused)
+ m_pausedAnimations = scene()->findChildren<QItemAnimation*>();
+
+ foreach(QItemAnimation *anim, m_pausedAnimations) {
+ if (paused)
+ anim->pause();
+ else
+ anim->resume();
+ }
+
+ if (!paused)
+ m_pausedAnimations.clear();
+}
+
+void River::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
+{
+ painter->fillRect(option->rect, Qt::black);
+}
+
+void River::setMode(Mode m)
+{
+ if (m_mode == m)
+ return;
+
+ Mode oldMode = m_mode;
+ m_mode = m;
+ switch(m)
+ {
+ case RiverMode:
+ m_mode = oldMode; //some animation may be stopt, and we don't want that animationFinished we were in that mode yet
+ foreach (RiverItem *item, m_items) {
+ const int x = qrand() % fixedSize().width();
+ const int y = qrand() % fixedSize().width();
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(RIVER_MAGNIFY(item));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(RIVER_MAGNIFY(item));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::Position, scene());
+ anim->setEndValue(QPointF(x, y));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ connect(anim, SIGNAL(finished()), SLOT(animationFinished()));
+ }
+ m_mode = m;
+ break;
+
+ case GridMode:
+
+ if (oldMode == GridFullScreenMode) {
+ currentItem()->setFullScreen(false, GRID_CURRENT_MAGNIFY);
+ } else {
+ m_topLeftIndex = -GRID_DIMENSIONS;
+ foreach (RiverItem *item, m_items) {
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+ adjustGrid(m_currentImage - GRID_DIMENSIONS + 1);
+ setCurrentItem(m_topLeftIndex);
+ }
+ break;
+ case GridFullScreenMode:
+ //let's put the current item fullscreen
+ currentItem()->setFullScreen(true, GRID_CURRENT_MAGNIFY);
+ break;
+ case CoverMode:
+ m_gridItem = m_items.values();
+ setCurrentItem(m_gridItem.count()/2);
+ default:
+ break;
+ }
+}
+
+River::Mode River::mode() const
+{
+ return m_mode;
+}
+
+QSize River::fixedSize()
+{
+ return QSize(352, 416);
+}
+
+//the name of this method is not that good...
+void River::makeCenterAvailable(qreal size)
+{
+ QRectF center(QPointF(), QSizeF(size, size));
+ center.moveCenter(rect().center());
+
+ const QList<QGraphicsItem*> list = scene()->items(center);
+
+ foreach(QGraphicsItem *item, m_items) {
+
+ if (!list.contains(item))
+ continue;
+
+ QPointF pos = item->pos();
+
+ if (pos.y() < rect().center().y()) {
+ //item is above center
+ pos.ry() = center.top() - item->boundingRect().height() - 1;
+ } else {
+ //item is below the center
+ pos.ry() = center.bottom() + 1;
+ }
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::Position, scene());
+ anim->setEndValue(pos);
+ anim->setDuration(150);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+}
+
+
+//this is there just to test small interaction
+void River::keyPressEvent ( QKeyEvent * keyEvent )
+{
+ switch(keyEvent->key())
+ {
+ case Qt::Key_O:
+ {
+ QItemAnimation *anim = new QItemAnimation(this, QItemAnimation::Opacity, scene());
+ anim->setDuration(2000);
+ anim->setEndValue(qreal(.5));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+ break;
+ case Qt::Key_N:
+ //that's a test
+ makeCenterAvailable(60);
+ break;
+ case Qt::Key_P:
+ switchPaused();
+ break;
+ case Qt::Key_V:
+ setMode(GridMode);
+ break;
+ case Qt::Key_R:
+ setMode(RiverMode);
+ break;
+ case Qt::Key_C:
+ setMode(CoverMode);
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if (m_mode == RiverMode) {
+ setMode(GridMode);
+ } else if (m_mode == GridMode) {
+ setMode(GridFullScreenMode);
+ } else if (m_mode == GridFullScreenMode) {
+ setMode(GridMode);
+ }
+ break;
+ case Qt::Key_Escape:
+ if (m_mode == GridFullScreenMode) {
+ setMode(GridMode);
+ } else if (m_mode == GridMode || m_mode == CoverMode) {
+ setMode(RiverMode);
+ } else if (m_mode == RiverMode) {
+ menu->show();
+ }
+ break;
+ case Qt::Key_Right:
+ if (m_mode == GridMode) {
+ navigateBy(+1);
+ } else if (m_mode == CoverMode) {
+ setCurrentItem(m_selectedItem + 1);
+ }
+ break;
+ case Qt::Key_Left:
+ if (m_mode == GridMode) {
+ navigateBy(-1);
+ } else if (m_mode == CoverMode) {
+ setCurrentItem(m_selectedItem - 1);
+ }
+ break;
+ case Qt::Key_Down:
+ if (m_mode == GridMode) {
+ navigateBy(GRID_COLUMN_COUNT);
+ }
+ break;
+ case Qt::Key_Up:
+ if (m_mode == GridMode) {
+ navigateBy(-GRID_COLUMN_COUNT);
+ }
+ break;
+// case Qt::Key_PageUp:
+ case Qt::Key_M:
+ menu->show();
+ break;
+ case Qt::Key_Space:
+ if (m_mode == GridMode) {
+ RiverItem *item = currentItem();
+ if(!item)
+ break;
+
+ //stupid sequence.
+ QPointF pos = item->pos();
+ QAnimationGroup *group = new QSequentialAnimationGroup();
+ //item->animator()->beginSequence();
+
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::Position, scene());
+ anim->setEndValue(pos);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(qreal(1.));
+ anim->setDuration(500);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(qreal(1.));
+ anim->setDuration(500);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(item, QItemAnimation::RotationX, scene());
+ anim->setEndValue(qreal(0));
+ group->addAnimation(anim);
+ group->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+ default:
+ break;
+ }
+
+ QGraphicsItem::keyPressEvent(keyEvent);
+}
+
+
+void River::setGridMode()
+{
+ setMode(GridMode);
+}
+
+void River::setRiverMode()
+{
+ setMode(RiverMode);
+}
+
+void River::setCoverMode()
+{
+ setMode(CoverMode);
+}
+
+
+void River::adjustGrid(int newTopLeft)
+{
+ for (int i = newTopLeft ; i < newTopLeft + GRID_DIMENSIONS; i++) {
+ if (!m_items.contains(i)) {
+ RiverItem *item = createItem(i);
+ int row = (i - m_topLeftIndex) / GRID_COLUMN_COUNT;
+ int col = (i - m_topLeftIndex) % GRID_COLUMN_COUNT;
+ item->setPos(gridItemPosition(row, col));
+ item->setXScale(0);
+ item->setYScale(0);
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+ }
+ newTopLeft = newTopLeft - newTopLeft % GRID_COLUMN_COUNT;
+
+ QHash<int, RiverItem *>::iterator it = m_items.begin();
+ while (it != m_items.constEnd()) {
+ const int imageIdx = it.key();
+ RiverItem *item = *it;
+ QSizeF itemSize = item->boundingRect().size();
+ if ((imageIdx >= newTopLeft && imageIdx < newTopLeft + GRID_DIMENSIONS)
+ || boundingRect().adjusted(-itemSize.width()/2, -itemSize.height()/2, itemSize.width()/2, itemSize.height()/2)
+ .contains(item->pos())) {
+ int row = (imageIdx-newTopLeft) / GRID_COLUMN_COUNT;
+ int col = (imageIdx-newTopLeft) % GRID_COLUMN_COUNT;
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::Position, scene());
+ anim->setEndValue(gridItemPosition(row, col));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ ++it;
+ } else {
+ ++it; /* ### ideally we should remove the items, but this cause the photobrowser to crash
+ because the QItemAnimations are not notified the item is deleted
+ delete item;
+ it = m_items.erase(it);
+ */
+ }
+ }
+
+ m_topLeftIndex = newTopLeft;
+}
+
+
+RiverItem *River::createItem(int imageIndex)
+{
+ Q_ASSERT(!m_items.contains(imageIndex));
+ RiverItem * item = new RiverItem(this);
+ item->setPixmap(pixmap(imageIndex));
+ m_items.insert(imageIndex,item);
+ return item;
+}
+
+void River::setCurrentItem(int newCurrentItem)
+{
+ if (m_mode == CoverMode)
+ {
+ m_selectedItem = newCurrentItem;
+ for (int i = 0; i < m_gridItem.count(); i++) {
+ QVariantAnimation *anim;
+ RiverItem *item = m_gridItem.at(i);
+
+ qreal rotation = 0;
+ qreal width = boundingRect().width() / 2;
+ qreal x = width;
+ qreal scale = 3;
+ qreal z = 1;
+ qreal y = boundingRect().height()/2;
+
+ if (i < newCurrentItem - 4) {
+ item->setVisible(false);
+ item->setPos(QPointF(0, y));
+ continue;
+ } else if(i > newCurrentItem + 4) {
+ item->setVisible(false);
+ item->setPos(QPointF(boundingRect().width(), y));
+ continue;
+ } else if (i < newCurrentItem) {
+ x = (i - newCurrentItem + 4) * width/7;
+ rotation = -75;
+ scale = 2;
+ z = 1.+qreal(i-newCurrentItem)/10.;
+ } else if (i > newCurrentItem) {
+ x = width + (i - newCurrentItem + 3) * width/7;
+ rotation = 75;
+ scale = 2;
+ z = 1.-qreal(i-newCurrentItem)/8.;
+ }
+
+ item->setVisible(true);
+ item->setZValue(z);
+
+ anim = new QItemAnimation(item, QItemAnimation::RotationY, scene());
+ anim->setEndValue(rotation);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(scale);
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(scale);
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+
+ anim = new QItemAnimation(item, QItemAnimation::Position, scene());
+ anim->setEndValue(QPointF(x,y));
+ anim->start(QVariantAnimation::DeleteWhenStopped);
+ }
+ return;
+ }
+
+
+ //deselect the current item
+ if (m_selectedItem >= 0 && m_items.contains(m_selectedItem)) {
+ RiverItem *item = m_items.value(m_selectedItem);
+ item->setZValue(qreal(qrand()%100)/200.0);
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(GRID_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+
+ if (newCurrentItem < 0) {
+ m_selectedItem = newCurrentItem;
+ return;
+ }
+
+ //ensure visible;
+ if (newCurrentItem < m_topLeftIndex) {
+ adjustGrid(newCurrentItem);
+ } else if (newCurrentItem >= m_topLeftIndex + GRID_DIMENSIONS) {
+ adjustGrid(newCurrentItem - GRID_DIMENSIONS + GRID_COLUMN_COUNT);
+ }
+
+ //select the new one
+ m_selectedItem = newCurrentItem;
+ RiverItem *item = currentItem();
+ Q_ASSERT(item);
+ item->setZValue(1);
+
+ QItemAnimation *anim = new QItemAnimation(item, QItemAnimation::ScaleFactorX, scene());
+ anim->setEndValue(GRID_CURRENT_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ anim = new QItemAnimation(item, QItemAnimation::ScaleFactorY, scene());
+ anim->setEndValue(GRID_CURRENT_MAGNIFY);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+void River::navigateBy(int offset)
+{
+ int newSelection = m_selectedItem + offset;
+ const int imageCount = m_images.size();
+ while (newSelection < 0)
+ newSelection += imageCount;
+ newSelection %= imageCount;
+ setCurrentItem(newSelection);
+}
diff --git a/examples/animation/photobrowser/river.h b/examples/animation/photobrowser/river.h
new file mode 100644
index 0000000..25bf62a
--- /dev/null
+++ b/examples/animation/photobrowser/river.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef __RIVER__H__
+#define __RIVER__H__
+
+#include <QtCore/QDirIterator>
+#include <QtGui/QGraphicsWidget>
+
+#include "menu.h"
+
+class RiverItem;
+
+class River : public QGraphicsWidget
+{
+ Q_OBJECT
+public:
+ enum Mode
+ {
+ RiverMode,
+ GridMode,
+ GridFullScreenMode,
+ CoverMode
+ };
+
+ River(const QString &path);
+ void addUnusedRiverItem(RiverItem * item);
+
+ static QSize fixedSize();
+
+ void switchPaused();
+
+ void setMode(Mode m);
+ Mode mode() const;
+
+ Menu *menu;
+
+protected:
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+ void keyPressEvent ( QKeyEvent * keyEvent );
+ void makeCenterAvailable(qreal size);
+ QPointF gridItemPosition(int row, int col) const;
+ QPixmap pixmap(int index) const;
+
+protected slots:
+ void animationFinished();
+public slots:
+ void setRiverMode();
+ void setGridMode();
+ void setCoverMode();
+
+private:
+ const QFileInfoList m_images;
+ int m_currentImage;
+ mutable QVector<QPixmap> m_pixmaps;
+ QHash<int, RiverItem*> m_items;
+ QList<RiverItem*> m_gridItem;
+ QList<QItemAnimation*> m_pausedAnimations;
+ Mode m_mode;
+
+ void adjustGrid(int topRight);
+ RiverItem *currentItem() { return m_items.value(m_selectedItem); }
+ RiverItem *createItem(int imageIndex);
+ void setCurrentItem(int currentItem);
+ void navigateBy(int offset);
+
+ int m_selectedItem;
+ int m_topLeftIndex;
+
+};
+
+
+#endif //__RIVERITEM__H__
diff --git a/examples/animation/photobrowser/riveritem.cpp b/examples/animation/photobrowser/riveritem.cpp
new file mode 100644
index 0000000..f6523a7
--- /dev/null
+++ b/examples/animation/photobrowser/riveritem.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#include "riveritem.h"
+#include "river.h"
+
+RiverItem::RiverItem(QGraphicsItem *parent) : QGraphicsPixmapItem(parent), m_fullscreen(false)
+{
+ setCacheMode(DeviceCoordinateCache);
+}
+
+RiverItem::~RiverItem()
+{
+}
+
+void RiverItem::setPixmap(const QPixmap &pix)
+{
+ const QSize oldSize = pixmap().size();
+ const QSize newSize = pix.size();
+ QGraphicsPixmapItem::setPixmap(pix);
+
+ if (newSize != oldSize) {
+ setOffset(-newSize.width()/2, -newSize.height()/2);
+ const qreal scaleFactor = qreal(River::fixedSize().height())/(qreal(pix.height()*7));
+ setTransform(QTransform().scale(scaleFactor, scaleFactor));
+ prepareGeometryChange();
+ }
+}
+
+
+void RiverItem::setFullScreen(bool b, qreal originScaleFactor)
+{
+ if (m_fullscreen == b)
+ return;
+
+ m_fullscreen = b;
+
+ QPointF newPos;
+ qreal rotationZ;
+ qreal scaleX, scaleY;
+
+ if (b) {
+ const QSizeF basePixmapSize = transform().map(boundingRect()).boundingRect().size();
+
+ newPos = parentItem()->boundingRect().center();
+ rotationZ = 90;
+ scaleY = qreal(River::fixedSize().width()) / basePixmapSize.height() * yScale();
+ scaleX = qreal(River::fixedSize().height()) / basePixmapSize.width() * xScale();
+
+ if (m_nonFSPos.isNull()) {
+ m_nonFSPos = pos(); //let's save our current (non fullscreen) position
+ }
+
+ } else {
+ Q_ASSERT(!m_nonFSPos.isNull());
+ rotationZ = 0;
+ scaleX = originScaleFactor;
+ scaleY = originScaleFactor;
+ newPos = m_nonFSPos;
+ }
+
+ QAnimationGroup *group = new QParallelAnimationGroup(scene());
+ QItemAnimation *anim = new QItemAnimation(this, QItemAnimation::Position);
+ anim->setEndValue(newPos);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(this, QItemAnimation::RotationZ);
+ anim->setEndValue(rotationZ);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(this, QItemAnimation::ScaleFactorX);
+ anim->setEndValue(scaleX);
+ group->addAnimation(anim);
+ anim = new QItemAnimation(this, QItemAnimation::ScaleFactorY);
+ anim->setEndValue(scaleY);
+ group->addAnimation(anim);
+ group->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+void RiverItem::mousePressEvent(QGraphicsSceneMouseEvent*)
+{
+ //just let it rotate on itself
+ QItemAnimation *anim = new QItemAnimation(this, QItemAnimation::RotationY);
+ anim->setEndValue(yRotation() < 180 ? 360 : 0);
+ anim->setDuration(500);
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+
diff --git a/examples/animation/photobrowser/riveritem.h b/examples/animation/photobrowser/riveritem.h
new file mode 100644
index 0000000..39fdcc2
--- /dev/null
+++ b/examples/animation/photobrowser/riveritem.h
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_LICENSE$
+**
+****************************************************************************/
+
+#ifndef __RIVERITEM__H__
+#define __RIVERITEM__H__
+
+#include <QtGui/QGraphicsPixmapItem>
+
+class RiverItemAnimator;
+
+class RiverItem : public QGraphicsPixmapItem
+{
+public:
+ RiverItem(QGraphicsItem *parent);
+ ~RiverItem();
+
+ void setPixmap(const QPixmap &);
+ void setFullScreen(bool b, qreal originScaleFactor);
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent*);
+
+private:
+ QPointF m_nonFSPos; //to save the position when not in fullscreen
+ bool m_fullscreen;
+};
+
+#endif //__RIVERITEM__H__