ganeswidgets/src/hgmediawallrenderer.cpp
changeset 0 89c329efa980
child 1 e48454f237ca
equal deleted inserted replaced
-1:000000000000 0:89c329efa980
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:    
       
    15 *
       
    16 */
       
    17 #include "HgMediaWallRenderer.h"
       
    18 #include "hgmediawalldataprovider.h"
       
    19 #include "hgquadrenderer.h"
       
    20 #include "hgquad.h"
       
    21 #include "hgimage.h"
       
    22 #include "HgImageFader.h"
       
    23 #include "hgvgquadrenderer.h"
       
    24 #include <qvector3d>
       
    25 #include <qtimer>
       
    26 #include <qpropertyanimation>
       
    27 #include <qstate.h>
       
    28 #include <qabstracttransition>
       
    29 #include <qstatemachine>
       
    30 #include <qsignaltransition>
       
    31 #include <qsequentialanimationgroup>
       
    32 #include <qparallelanimationgroup>
       
    33 #include <qvariantanimation>
       
    34 #include <qpolygon>
       
    35 #include <qpainter>
       
    36 #include <qpaintengine>
       
    37 
       
    38 const Qt::Orientation KDefaultOrientation(Qt::Vertical);
       
    39 const qreal KPi = 3.1415926535897932384626433832795;
       
    40 
       
    41 static qreal lerp(qreal start, qreal end, qreal t)
       
    42 {
       
    43     return start * (1.0f - t) + end * t;
       
    44 }
       
    45 
       
    46 class MyVectorAnimation : public QVariantAnimation
       
    47 {
       
    48 public:
       
    49     virtual void updateCurrentValue(const QVariant& value)
       
    50     {
       
    51         mValue = value.value<QVector3D>();
       
    52     }
       
    53     QVector3D getValue() const
       
    54     {
       
    55         return mValue;
       
    56     }
       
    57 private:
       
    58     QVector3D mValue;
       
    59 };
       
    60 
       
    61 class HgAnimatedQuad
       
    62 {
       
    63 public:
       
    64     
       
    65     HgAnimatedQuad(HgQuad* start, HgQuad* end, 
       
    66         int duration) : mQuad(start)
       
    67     {        
       
    68         mPositionAnimation.setDuration(duration);
       
    69         mPositionAnimation.setKeyValueAt(0, start->position());
       
    70         mPositionAnimation.setKeyValueAt(1.0, end->position());
       
    71         mPositionAnimation.setEasingCurve(QEasingCurve::Linear);
       
    72 
       
    73         mScaleAnimation.setDuration(duration);
       
    74         mScaleAnimation.setKeyValueAt(0, QVector3D(start->scale().x(), start->scale().y(), 0));
       
    75         mScaleAnimation.setKeyValueAt(1, QVector3D(end->scale().x(), end->scale().y(), 0));
       
    76         mScaleAnimation.setEasingCurve(QEasingCurve::Linear);
       
    77     
       
    78     }
       
    79     
       
    80     ~HgAnimatedQuad()
       
    81     {
       
    82     }
       
    83     
       
    84     void start()
       
    85     {
       
    86         mPositionAnimation.start();
       
    87         mScaleAnimation.start();
       
    88     }
       
    89            
       
    90     void update()
       
    91     {
       
    92         mQuad->setPosition(mPositionAnimation.currentValue().value<QVector3D>());
       
    93         QVector3D scale = mScaleAnimation.currentValue().value<QVector3D>();
       
    94         mQuad->setScale(QVector2D(scale.x(), scale.y()));
       
    95     }
       
    96     
       
    97     HgQuad* mQuad;
       
    98     MyVectorAnimation mPositionAnimation;
       
    99     MyVectorAnimation mScaleAnimation;
       
   100 };
       
   101 
       
   102 HgMediaWallRenderer::HgMediaWallRenderer(HgMediaWallDataProvider* provider) :
       
   103     mDataProvider(provider),
       
   104     mRenderer(NULL),
       
   105     mIndicatorRenderer(NULL),
       
   106     mRendererInitialized(false),
       
   107     mOrientation(KDefaultOrientation),
       
   108     mNextOrientation(KDefaultOrientation),
       
   109     mStateAnimationAlpha(0),
       
   110     mStateAnimationOnGoing(false),
       
   111     mAnimationAlpha(0),
       
   112     mOpeningAnimationDuration(500),
       
   113     mOpenedItem(-1),
       
   114     mFlipAngle(qreal(360)),
       
   115     mZoomAmount(qreal(0.5)),
       
   116     mCoverflowMode(false),
       
   117     mRowCount(1),
       
   118     mNextRowCount(1),
       
   119     mStateAnimationDuration(300),
       
   120     mStep(1.1),
       
   121     mZfar(-2),
       
   122     mSpacing2D(10,10),
       
   123     mImageSize2D(100, 60),
       
   124     mCameraDistance(0),
       
   125     mCameraRotationY(0),
       
   126     mCameraRotationZ(0),
       
   127     mFrontCoverElevation(0.4),
       
   128     mReflectionsEnabled(true),
       
   129     mItemCountChanged(false),
       
   130     mOpenedItemState(ItemClosed)
       
   131 {
       
   132     createStateMachine();
       
   133     mImageFader = new HgImageFader();    
       
   134     mRenderer = new HgVgQuadRenderer(256);
       
   135     mRendererInitialized = true;
       
   136 }
       
   137 
       
   138 HgMediaWallRenderer::~HgMediaWallRenderer()
       
   139 {
       
   140     delete mRenderer;
       
   141     delete mImageFader;
       
   142     delete mStateMachine;
       
   143 }
       
   144 
       
   145 
       
   146 void HgMediaWallRenderer::setCameraDistance(qreal distance)
       
   147 {
       
   148     mCameraDistance = distance;
       
   149 }
       
   150 
       
   151 void HgMediaWallRenderer::setCameraRotationY(qreal angle)
       
   152 {
       
   153     mCameraRotationY = angle;
       
   154 }
       
   155 
       
   156 void HgMediaWallRenderer::setCameraRotationZ(qreal angle)
       
   157 {
       
   158     mCameraRotationZ = angle;
       
   159 }
       
   160 
       
   161 qreal HgMediaWallRenderer::getCameraDistance() const
       
   162 {
       
   163     return mCameraDistance;
       
   164 }
       
   165 
       
   166 qreal HgMediaWallRenderer::getCameraRotationY() const
       
   167 {
       
   168     return mCameraRotationY;
       
   169 }
       
   170 
       
   171 qreal HgMediaWallRenderer::getCameraRotationZ() const
       
   172 {
       
   173     return mCameraRotationZ;
       
   174 }
       
   175 
       
   176 void HgMediaWallRenderer::draw(
       
   177     const QPointF& startPosition,
       
   178     const QPointF& position, 
       
   179     const QPointF& targetPosition, 
       
   180     qreal springVelocity,
       
   181     QPainter* painter)
       
   182 {
       
   183     // if still not initialized we cant draw anything
       
   184     if (!mRendererInitialized)
       
   185         return;
       
   186         
       
   187     if (mOrientation != mNextOrientation ||
       
   188         mRowCount != mNextRowCount)
       
   189     {
       
   190                 
       
   191         // save old state of the quads         
       
   192         recordState(mOldState);
       
   193         
       
   194         // goto wanted orientation / rowcount
       
   195         mOrientation = mNextOrientation;
       
   196         mRowCount = mNextRowCount;
       
   197         setImageSize(mNextImageSize);
       
   198         
       
   199         // setup quads to new state
       
   200         setupRows(startPosition, position, targetPosition, springVelocity, painter);
       
   201 
       
   202         // record state for animation
       
   203         recordState(mNextState);
       
   204 
       
   205         startStateAnimation(painter);
       
   206     }
       
   207     else
       
   208     {
       
   209         if (!mStateAnimationOnGoing)
       
   210         {
       
   211             setupRows(startPosition, position, targetPosition, springVelocity, painter);
       
   212         }
       
   213         else
       
   214         {
       
   215             setupStateAnimation(painter);
       
   216         }    
       
   217     }
       
   218     
       
   219     updateCameraMatrices();
       
   220     drawQuads(painter);
       
   221 }
       
   222 
       
   223 void HgMediaWallRenderer::setupRows(const QPointF& startPosition,
       
   224     const QPointF& position, 
       
   225     const QPointF& targetPosition, 
       
   226     qreal springVelocity,
       
   227     QPainter* painter)
       
   228 {
       
   229     // draw the state for it 
       
   230     resetQuads();
       
   231     updateSpacingAndImageSize();
       
   232     
       
   233     if (mCoverflowMode)
       
   234     {
       
   235         //setupRow(startPosition, position, targetPosition, springVelocity, painter, 0);
       
   236         setupCoverflow(startPosition, position, targetPosition, springVelocity, painter);
       
   237     }
       
   238     else
       
   239     {
       
   240         if (mOrientation == Qt::Vertical)
       
   241         {
       
   242             setupGridPortrait(startPosition, position, targetPosition, 
       
   243               springVelocity, painter);            
       
   244         }
       
   245         else
       
   246         {
       
   247             setupGridLandscape(startPosition, position, targetPosition, 
       
   248                 springVelocity, painter);
       
   249         }
       
   250     }        
       
   251 }
       
   252 
       
   253 void HgMediaWallRenderer::setFlipAnimationAngle(qreal angleInDegrees)
       
   254 {
       
   255     mFlipAngle = angleInDegrees;
       
   256 }
       
   257     
       
   258 void HgMediaWallRenderer::setOpeningAnimationType(HgMediaWallRenderer::OpeningAnimationType type)
       
   259 {
       
   260     mOpeningAnimationType = type;
       
   261 }
       
   262 
       
   263 void HgMediaWallRenderer::setOpeningAnimationDuration(int msecs)
       
   264 {
       
   265     mOpeningAnimationDuration = msecs;
       
   266 }
       
   267 
       
   268 qreal HgMediaWallRenderer::animationAlpha() const
       
   269 {
       
   270     return mAnimationAlpha;
       
   271 }
       
   272 
       
   273 void HgMediaWallRenderer::setAnimationAlpha(qreal alpha)
       
   274 {
       
   275     mAnimationAlpha = alpha;
       
   276     
       
   277     if (mOpenedItemState == ItemClosing && alpha == 0.0f)
       
   278         mOpenedItemState = ItemClosed;
       
   279     
       
   280     if (mOpenedItemState == ItemOpening && alpha == 1.0f)
       
   281         mOpenedItemState = ItemOpened;
       
   282     
       
   283     emit renderingNeeded();
       
   284 }
       
   285 
       
   286 qreal HgMediaWallRenderer::stateAnimationAlpha() const
       
   287 {
       
   288     return mStateAnimationAlpha;
       
   289 }
       
   290 
       
   291 void HgMediaWallRenderer::setStateAnimationAlpha(qreal alpha)
       
   292 {
       
   293     mStateAnimationAlpha = alpha;
       
   294     if (alpha == 1 && mStateAnimationOnGoing)
       
   295     {
       
   296         mStateAnimationOnGoing = false;
       
   297     }
       
   298     emit renderingNeeded();
       
   299 }
       
   300 
       
   301 void HgMediaWallRenderer::createStateMachine()
       
   302 {
       
   303     mStateMachine = new QStateMachine(this);
       
   304     mStateMachine->setAnimated(true);
       
   305     
       
   306     QState* root = new QState(QState::ParallelStates);
       
   307     QState* p1 = new QState(root);
       
   308     QState* p2 = new QState(root);
       
   309     
       
   310     // create idle/opened states
       
   311     {            
       
   312         QState* idle = new QState(p1);
       
   313         QState* opened = new QState(p1);
       
   314 
       
   315         idle->assignProperty(this, "animationAlpha", qreal(0));                                
       
   316         opened->assignProperty(this, "animationAlpha", qreal(1));
       
   317 
       
   318         // add opening animation
       
   319         QPropertyAnimation* anim1 = new QPropertyAnimation(this, "animationAlpha");
       
   320         anim1->setDuration(mOpeningAnimationDuration);
       
   321         idle->addTransition(this, SIGNAL(toggleItem()), opened)->addAnimation(anim1);
       
   322             
       
   323         // add closing animation
       
   324         QPropertyAnimation* anim2 = new QPropertyAnimation(this, "animationAlpha");
       
   325         anim2->setDuration(mOpeningAnimationDuration);
       
   326         opened->addTransition(this, SIGNAL(toggleItem()), idle)->addAnimation(anim2);
       
   327 
       
   328         QObject::connect(idle, SIGNAL(entered()), this, SLOT(onIdleState()));
       
   329         QObject::connect(opened, SIGNAL(entered()), this, SLOT(onOpenedState()));
       
   330     
       
   331         p1->setInitialState(idle);
       
   332     }
       
   333     
       
   334     // create two states to animate between
       
   335     {
       
   336         QState* s1 = new QState(p2);
       
   337         QState* s2 = new QState(p2);
       
   338 
       
   339         s1->assignProperty(this, "stateAnimationAlpha", qreal(0));
       
   340         s2->assignProperty(this, "stateAnimationAlpha", qreal(0));
       
   341         
       
   342         QPropertyAnimation* anim = new QPropertyAnimation(this, "stateAnimationAlpha");
       
   343         anim->setStartValue(qreal(0));
       
   344         anim->setEndValue(qreal(1));
       
   345         anim->setDuration(mStateAnimationDuration);
       
   346         
       
   347         s1->addTransition(this, SIGNAL(toggleState()), s2)->addAnimation(anim);
       
   348         s2->addTransition(this, SIGNAL(toggleState()), s1)->addAnimation(anim);        
       
   349 
       
   350         p2->setInitialState(s1);        
       
   351     }
       
   352 
       
   353     root->setInitialState(p1);
       
   354     mStateMachine->addState(root);    
       
   355     mStateMachine->setInitialState(root);
       
   356     mStateMachine->start();
       
   357 
       
   358 }
       
   359 
       
   360 void HgMediaWallRenderer::onIdleState()
       
   361 {
       
   362     emit itemClosed(mOpenedItem);
       
   363 }
       
   364 
       
   365 void HgMediaWallRenderer::onOpenedState()
       
   366 {
       
   367     emit itemOpened(mOpenedItem);
       
   368 }
       
   369 
       
   370 void HgMediaWallRenderer::setOrientation(Qt::Orientation orientation, bool animate)
       
   371 {
       
   372     if (mOrientation != orientation)
       
   373     {
       
   374         mStateMachine->setAnimated(animate);
       
   375         mNextOrientation = orientation;
       
   376 
       
   377         if (!animate)
       
   378             mOrientation = orientation;
       
   379         else
       
   380         {
       
   381             emit renderingNeeded();            
       
   382         }
       
   383     }
       
   384 }
       
   385 
       
   386 Qt::Orientation HgMediaWallRenderer::getOrientation() const
       
   387 {
       
   388     return mOrientation;
       
   389 }
       
   390 
       
   391 void HgMediaWallRenderer::drawQuads(QPainter* painter)
       
   392 {
       
   393     mRenderer->transformQuads(mViewMatrix, mProjMatrix, mRect);
       
   394 
       
   395     mRenderer->drawQuads(mRect, painter);    
       
   396 }
       
   397 
       
   398 
       
   399 void HgMediaWallRenderer::enableCoverflowMode(bool enabled)
       
   400 {
       
   401     mCoverflowMode = enabled;
       
   402 }
       
   403 
       
   404 bool HgMediaWallRenderer::coverflowModeEnabled() const
       
   405 {
       
   406     return mCoverflowMode;
       
   407 }
       
   408 
       
   409 void HgMediaWallRenderer::setRowCount(int rowCount, const QSizeF& newImageSize, bool animate)
       
   410 {
       
   411     if (rowCount != mRowCount)
       
   412     {
       
   413         mStateMachine->setAnimated(animate);
       
   414 
       
   415         mNextRowCount = rowCount;
       
   416         mNextImageSize = newImageSize;
       
   417 
       
   418         mColumnCount = rowCount;
       
   419         
       
   420         if (!animate)
       
   421         {
       
   422             mRowCount = rowCount;
       
   423         }
       
   424         else
       
   425         {
       
   426             emit renderingNeeded();            
       
   427         }
       
   428          
       
   429     }
       
   430 
       
   431 }
       
   432 
       
   433 int HgMediaWallRenderer::getRowCount() const
       
   434 {
       
   435     return mRowCount;
       
   436 }
       
   437 
       
   438 void HgMediaWallRenderer::recordState(HgMediaWallRenderer::State& state)
       
   439 {
       
   440     // cleanup old quads
       
   441     for (int i = 0; i < state.mQuads.size(); i++)
       
   442     {
       
   443         delete state.mQuads[i];
       
   444     }
       
   445     
       
   446     state.mQuads.clear();
       
   447     
       
   448     // record new quads
       
   449     for (int i = 0; i < mRenderer->quadCount(); i++)
       
   450     {
       
   451         HgQuad* quad = mRenderer->quad(i);
       
   452         if (!quad->visible())
       
   453             continue;
       
   454         
       
   455         state.mQuads.append(quad->copy());
       
   456     }    
       
   457 }
       
   458 
       
   459 void HgMediaWallRenderer::setupStateAnimation(QPainter* painter)
       
   460 {
       
   461     Q_UNUSED(painter)
       
   462     
       
   463     resetQuads();
       
   464     // setup quads from animated state
       
   465     for (int i = 0; i < mOldState.mQuads.size(); i++)
       
   466     {
       
   467         mAnimatedQuads[i]->update();
       
   468         mRenderer->quad(i)->copyFrom(*mOldState.mQuads[i]);
       
   469     }
       
   470 }
       
   471 
       
   472 void HgMediaWallRenderer::resetQuads()
       
   473 {
       
   474     for (int i = 0; i < mRenderer->quadCount(); i++)
       
   475         mRenderer->quad(i)->setVisible(false);    
       
   476 }
       
   477 
       
   478 HgQuad* HgMediaWallRenderer::getQuadAt(const QPointF& position) const
       
   479 {
       
   480     if (!mRendererInitialized)
       
   481         return NULL;
       
   482         
       
   483     return mRenderer->getQuadAt(position);//mapFromWindow(position));
       
   484 }
       
   485 
       
   486 bool HgMediaWallRenderer::isItemOpen() const
       
   487 {
       
   488     return (mOpenedItem != -1 && mAnimationAlpha > 0);
       
   489 }
       
   490 
       
   491 void HgMediaWallRenderer::setRect(const QRectF& windowRect)
       
   492 {
       
   493     mRect = windowRect;
       
   494 }
       
   495 
       
   496 const QRectF& HgMediaWallRenderer::getRect() const
       
   497 {
       
   498     return mRect;
       
   499 }
       
   500 
       
   501 void HgMediaWallRenderer::updateCameraMatrices()
       
   502 {    
       
   503     QMatrix4x4 view;
       
   504         
       
   505     view.setToIdentity();
       
   506     
       
   507     view.lookAt(QVector3D(0.0, 0.0, 1.0f  + mCameraDistance), 
       
   508         QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f));
       
   509 
       
   510     QMatrix4x4 rot;
       
   511     rot.rotate(mCameraRotationZ, QVector3D(0,0,1));
       
   512     rot.rotate(mCameraRotationY, QVector3D(0,1,0));
       
   513     view *= rot;
       
   514         
       
   515     qreal aspect = mRect.width() / mRect.height();
       
   516     
       
   517     QMatrix4x4 proj;
       
   518     proj.setToIdentity();
       
   519     
       
   520     if (mRect.width() <= mRect.height())
       
   521     {
       
   522         qreal aspect = mRect.height() / mRect.width();
       
   523         proj.frustum(-0.5f, 0.5f, -0.5f*aspect, 0.5f*aspect, 1.0f, 1000.0f);
       
   524     }
       
   525     else
       
   526     {
       
   527         qreal aspect = mRect.width() / mRect.height();
       
   528         proj.frustum(-0.5f*aspect, 0.5f*aspect, -0.5f, 0.5f, 1.0f, 1000.0f);
       
   529     }
       
   530 
       
   531     mViewMatrix = view;
       
   532     mProjMatrix = proj;
       
   533     
       
   534     qreal mirrorPlaneY = getRowPosY(mRowCount-1)-mImageSize3D.height()/2;
       
   535     mRenderer->setMirroringPlaneY(mirrorPlaneY);
       
   536 }
       
   537 
       
   538 void HgMediaWallRenderer::updateSpacingAndImageSize()
       
   539 {
       
   540     qreal div = mRect.width() <= mRect.height() ? mRect.width() : mRect.height();
       
   541     
       
   542     mSpacing3D = mSpacing2D / div;
       
   543     mImageSize3D = mImageSize2D / div;
       
   544 }
       
   545 
       
   546 void HgMediaWallRenderer::setSpacing(const QSizeF& spacing)
       
   547 {
       
   548     mSpacing2D = spacing;
       
   549 }
       
   550 
       
   551 void HgMediaWallRenderer::setImageSize(const QSizeF& imageSize)
       
   552 {
       
   553     mImageSize2D = imageSize;
       
   554     mNextImageSize = imageSize;
       
   555 }
       
   556 
       
   557 const QSizeF& HgMediaWallRenderer::getSpacing() const
       
   558 {
       
   559     return mSpacing2D;
       
   560 }
       
   561 
       
   562 const QSizeF& HgMediaWallRenderer::getImageSize() const
       
   563 {
       
   564     return mImageSize2D;
       
   565 }
       
   566 
       
   567 void HgMediaWallRenderer::setFrontCoverElevationFactor(qreal elevation)
       
   568 {
       
   569     mFrontCoverElevation = elevation;
       
   570 }
       
   571 
       
   572 qreal HgMediaWallRenderer::getFrontCoverElevationFactor() const
       
   573 {
       
   574     return mFrontCoverElevation;
       
   575 }
       
   576 
       
   577 void HgMediaWallRenderer::openItem(int index, bool animate)
       
   578 {
       
   579     if (isItemOpen())
       
   580         return;
       
   581     
       
   582     mOpenedItem = index;
       
   583     mOpenedItemState = animate ? ItemOpening : ItemOpened;
       
   584 
       
   585     mStateMachine->setAnimated(animate);
       
   586     emit toggleItem();
       
   587     
       
   588 }
       
   589 
       
   590 void HgMediaWallRenderer::closeItem(bool animate)
       
   591 {
       
   592     if (!isItemOpen())
       
   593         return;
       
   594 
       
   595     mOpenedItemState = animate ? ItemClosing : ItemClosed;
       
   596     if (!animate)
       
   597         mOpenedItem = -1;
       
   598 
       
   599     mStateMachine->setAnimated(animate);
       
   600     emit toggleItem();
       
   601 }
       
   602 
       
   603 qreal HgMediaWallRenderer::getRowPosY(int row)
       
   604 {
       
   605     qreal step = mSpacing3D.height() + mImageSize3D.height();            
       
   606     return mRowCount == 1 ? qreal(0) : (((qreal)mRowCount/qreal(2)-qreal(0.5)) - (qreal)row) * step; 
       
   607 }
       
   608 
       
   609 qreal HgMediaWallRenderer::getColumnPosX(int col)
       
   610 {
       
   611     qreal step = -(mSpacing3D.width() + mImageSize3D.width());                
       
   612     return mColumnCount == 1 ? qreal(0) : (((qreal)mColumnCount/qreal(2)-qreal(0.5)) - (qreal)col) * step; 
       
   613 }
       
   614 
       
   615 
       
   616 void HgMediaWallRenderer::enableReflections(bool enabled)
       
   617 {
       
   618     mReflectionsEnabled = enabled;
       
   619 }
       
   620 
       
   621 bool HgMediaWallRenderer::reflectionsEnabled() const
       
   622 {
       
   623     return mReflectionsEnabled;
       
   624 }
       
   625     
       
   626 QPointF HgMediaWallRenderer::mapFromWindow(const QPointF& point) const
       
   627 {
       
   628     return QPointF(point.x(), mRect.height() - point.y());
       
   629 }
       
   630 
       
   631 void HgMediaWallRenderer::emitUpdate()
       
   632 {
       
   633     emit renderingNeeded();
       
   634 }
       
   635 
       
   636 void HgMediaWallRenderer::applyOpeningAnimation(HgQuad* quad)
       
   637 {
       
   638     QQuaternion rot(0,0,0,1);
       
   639     qreal rotAngle = mAnimationAlpha * mFlipAngle;
       
   640     rot = QQuaternion::fromAxisAndAngle(QVector3D(0,1,0), rotAngle);
       
   641     quad->setRotation(rot);
       
   642     quad->setPosition(quad->position() + QVector3D(0,0,mAnimationAlpha * mZoomAmount));    
       
   643 }
       
   644 
       
   645 
       
   646 qreal HgMediaWallRenderer::getWorldWidth() const
       
   647 {   
       
   648     qreal width = (qreal)mDataProvider->imageCount() / (qreal)mRowCount - 1.0f;
       
   649     
       
   650     if (mOrientation == Qt::Vertical)
       
   651     {
       
   652         qreal step = mSpacing2D.height() + mImageSize2D.height(); 
       
   653         width -= (mRect.height() / step - 1.0f);
       
   654     }
       
   655    
       
   656     return width;
       
   657 }
       
   658 
       
   659 void HgMediaWallRenderer::beginRemoveRows(int start, int end)
       
   660 {
       
   661     mRemoveStart = start;
       
   662     mRemoveEnd = end;
       
   663     mItemCountChanged = true;
       
   664     
       
   665     recordState(mOldState);
       
   666 
       
   667 }
       
   668 
       
   669 void HgMediaWallRenderer::endRemoveRows()
       
   670 {
       
   671         
       
   672     mStateMachine->setAnimated(true);
       
   673 
       
   674     emit renderingNeeded();            
       
   675     
       
   676 }
       
   677 
       
   678 void HgMediaWallRenderer::startStateAnimation(QPainter* painter)
       
   679 {
       
   680     
       
   681     // clear previous animation quads
       
   682     for (int i = 0; i < mAnimatedQuads.size(); i++)
       
   683     {
       
   684         delete mAnimatedQuads[i];
       
   685     }        
       
   686     mAnimatedQuads.clear();
       
   687     
       
   688     // setup animated quads
       
   689     HgQuad* defaultQuad = new HgQuad();
       
   690     defaultQuad->setPosition(QVector3D(100,100,-100));
       
   691     int n = mOldState.mQuads.count() < mNextState.mQuads.count() ? mNextState.mQuads.count() : mOldState.mQuads.count();
       
   692     for (int i = 0; i < n; i++)
       
   693     {
       
   694         HgQuad* qA = (i >= mOldState.mQuads.count()) ? defaultQuad : mOldState.mQuads[i];
       
   695         HgQuad* qB = (i >= mNextState.mQuads.count()) ? defaultQuad : mNextState.mQuads[i];
       
   696         
       
   697         HgAnimatedQuad* q = new HgAnimatedQuad(qA, qB, mStateAnimationDuration);
       
   698         mAnimatedQuads.append(q);
       
   699         q->start();
       
   700     }
       
   701     
       
   702     mStateAnimationOnGoing = true;
       
   703     
       
   704     // setup first frame of the animation
       
   705     setupStateAnimation(painter);        
       
   706 
       
   707     // toggle state animation on
       
   708     toggleState();
       
   709 
       
   710 }
       
   711 
       
   712 void HgMediaWallRenderer::setupCoverflow(const QPointF& startPosition,
       
   713     const QPointF& position, 
       
   714     const QPointF& targetPosition, 
       
   715     qreal springVelocity,
       
   716     QPainter* painter)
       
   717 {   
       
   718     Q_UNUSED(startPosition)
       
   719     Q_UNUSED(targetPosition)
       
   720     Q_UNUSED(springVelocity)
       
   721     Q_UNUSED(painter)
       
   722     
       
   723     // save selected item for coverflow
       
   724     mSelectedItem = ceil(position.x());
       
   725     
       
   726     int quadsVisible = (mRect.width() / mImageSize2D.width() + 1) * 4;
       
   727     int selectedItemIndex = quadsVisible / 2;
       
   728 
       
   729     qreal step = mSpacing3D.width() + mImageSize3D.width();                
       
   730     qreal ipos = floorf(position.x());
       
   731     qreal frac = (position.x() - ipos) * step;
       
   732     qreal posX = -(qreal)(selectedItemIndex + 0) * step - frac;
       
   733     qreal zFar = -mFrontCoverElevation;
       
   734     qreal posY = 0;    
       
   735     
       
   736     int count = mDataProvider->imageCount();
       
   737     int quadIndex = 0;
       
   738     int itemIndex = ((int)(ipos - (qreal)selectedItemIndex));
       
   739     int index = 0;
       
   740     
       
   741     while (1)
       
   742     {
       
   743         if (itemIndex < 0)
       
   744         {
       
   745             itemIndex++;
       
   746             posX += step;
       
   747             index++;
       
   748             continue;
       
   749         }
       
   750         else if (itemIndex >= count || index >= quadsVisible || quadIndex >= mRenderer->quadCount())
       
   751         {
       
   752             break;
       
   753         }
       
   754                         
       
   755         qreal posZ = zFar;
       
   756 
       
   757         // if this is center item modify its z
       
   758         qreal p = posX / step;
       
   759         if (p > -1.0f && p < 1.0f)
       
   760         {
       
   761             qreal d = lerp(-zFar, 0, qBound(qreal(0), qAbs(springVelocity)/6.0f, qreal(1)));
       
   762             posZ = zFar + sin((p+1.0f) * KPi / 2) * d;                
       
   763         }
       
   764 
       
   765         // modify z also for sorting
       
   766         posZ -= 0.001f * abs(posX/step);
       
   767                 
       
   768         // setup quad for this item
       
   769         HgQuad* quad = mRenderer->quad(quadIndex);
       
   770         setupDefaultQuad(QVector3D(posX, posY, posZ), itemIndex, mReflectionsEnabled, quadIndex);
       
   771                          
       
   772         // step to next item                    
       
   773         posX += step;        
       
   774         itemIndex++;
       
   775         index++;
       
   776     }
       
   777     
       
   778 }
       
   779 
       
   780 
       
   781 void HgMediaWallRenderer::setupGridPortrait(const QPointF& startPosition,
       
   782     const QPointF& position, 
       
   783     const QPointF& targetPosition, 
       
   784     qreal springVelocity,
       
   785     QPainter* painter)
       
   786 {
       
   787     Q_UNUSED(startPosition)
       
   788     Q_UNUSED(targetPosition)
       
   789     Q_UNUSED(springVelocity)
       
   790     Q_UNUSED(painter)
       
   791     
       
   792     int rowCount = (mRect.height() / mImageSize2D.height() + 1) * 4;
       
   793     int rowsUp = rowCount/2;
       
   794         
       
   795     qreal stepY = mSpacing3D.height() + mImageSize3D.height();
       
   796     qreal ipos = floorf(position.x());
       
   797     qreal frac = (position.x() - ipos) * stepY;
       
   798     qreal posY = -(qreal)rowsUp * stepY - frac;
       
   799         
       
   800     // adjust height so that we begin from top
       
   801     qreal div = mRect.width() <= mRect.height() ? mRect.width() : mRect.height();
       
   802     posY -= mRect.height() / div / 2.0 - stepY / 2.0;
       
   803     
       
   804     int count = mDataProvider->imageCount();
       
   805     int itemIndex = ((int)(ipos - (qreal)rowsUp)) * mColumnCount;
       
   806     int row = 0;
       
   807     int quadIndex = 0;
       
   808     
       
   809     while (1)
       
   810     {
       
   811         if (itemIndex < 0)
       
   812         {
       
   813             itemIndex+=mColumnCount;
       
   814             posY += stepY;
       
   815             row++;
       
   816             continue;
       
   817         }
       
   818         else if (itemIndex >= count || quadIndex >= mRenderer->quadCount() || row >= rowCount)
       
   819         {
       
   820             break;
       
   821         }
       
   822         
       
   823         setupGridRow(-posY, itemIndex, quadIndex);
       
   824                         
       
   825         posY += stepY;
       
   826         row++;
       
   827         itemIndex+=mColumnCount;
       
   828     }
       
   829     
       
   830 }
       
   831 
       
   832 void HgMediaWallRenderer::setupGridLandscape(const QPointF& startPosition,
       
   833     const QPointF& position, 
       
   834     const QPointF& targetPosition, 
       
   835     qreal springVelocity,
       
   836     QPainter* painter)
       
   837 {
       
   838     Q_UNUSED(startPosition)
       
   839     Q_UNUSED(targetPosition)
       
   840     Q_UNUSED(springVelocity)
       
   841     Q_UNUSED(painter)
       
   842     
       
   843     int colCount = (mRect.width() / mImageSize2D.width() + 1) * 3;
       
   844     int colsLeft = colCount/2;
       
   845 
       
   846     qreal stepX = mSpacing3D.width() + mImageSize3D.width();
       
   847     qreal ipos = floorf(position.x());
       
   848     qreal frac = (position.x() - ipos) * stepX;
       
   849     qreal posX = -(qreal)colsLeft * stepX - frac;    
       
   850     
       
   851     int count = mDataProvider->imageCount();
       
   852     int itemIndex = ((int)(ipos - (qreal)colsLeft)) * mRowCount;
       
   853     int col = 0;
       
   854     int quadIndex = 0;
       
   855     
       
   856     while (1)
       
   857     {
       
   858         if (itemIndex < 0)
       
   859         {
       
   860             itemIndex+=mColumnCount;
       
   861             posX += stepX;
       
   862             col++;
       
   863             continue;
       
   864         }
       
   865         else if (itemIndex >= count || col >= colCount || quadIndex >= mRenderer->quadCount())
       
   866         {
       
   867             break;
       
   868         }
       
   869         
       
   870         setupGridColumn(posX, itemIndex, quadIndex);
       
   871                         
       
   872         posX += stepX;
       
   873         col++;
       
   874         itemIndex+=mRowCount;
       
   875     }
       
   876 }
       
   877 
       
   878 void HgMediaWallRenderer::setupGridColumn(qreal posX, int itemIndex, int& quadIndex)
       
   879 {
       
   880     for (int i = 0; i < mRowCount; i++)
       
   881     {
       
   882         qreal posY = getRowPosY(i);
       
   883         
       
   884         // enable reflections for the last row needed
       
   885         bool reflections = (i == (mRowCount-1) && mReflectionsEnabled);
       
   886 
       
   887         setupDefaultQuad(QVector3D(posX, posY, 0), itemIndex++, reflections, quadIndex);
       
   888         
       
   889         if (itemIndex >= mDataProvider->imageCount())
       
   890             return;    
       
   891     }    
       
   892 }
       
   893 
       
   894 void HgMediaWallRenderer::setupGridRow(qreal posY, int itemIndex, int& quadIndex)
       
   895 {
       
   896     for (int i = 0; i < mColumnCount; i++)
       
   897     {
       
   898         qreal posX = getColumnPosX(i);
       
   899         setupDefaultQuad(QVector3D(posX, posY, 0), itemIndex++, false, quadIndex);
       
   900         if (itemIndex >= mDataProvider->imageCount())
       
   901             return;     
       
   902     }    
       
   903 }
       
   904 
       
   905 void HgMediaWallRenderer::setupDefaultQuad(const QVector3D& pos, int itemIndex, bool reflectionsEnabled, int& quadIndex)
       
   906 {
       
   907     HgQuad* quad = mRenderer->quad(quadIndex++);
       
   908     quad->setPosition(pos);
       
   909     quad->setImage(mDataProvider->image(itemIndex));
       
   910     quad->setVisible(true);
       
   911     quad->setScale(QVector2D(mImageSize3D.width(),mImageSize3D.height()));
       
   912     quad->setPivot(QVector2D(0,0));
       
   913     quad->setUserData(QVariant(itemIndex));
       
   914     quad->setRotation(QQuaternion(1,0,0,0));
       
   915     quad->setOuterRotation(QQuaternion(1,0,0,0));
       
   916     quad->enableMirrorImage(reflectionsEnabled);
       
   917     quad->setAlpha(1.0f);
       
   918     
       
   919     // apply opening animation if needed
       
   920  /*   if (itemIndex == mOpenedItem)
       
   921         applyOpeningAnimation(quad);
       
   922 */
       
   923     // setup indicator/decorator for the item if needed 
       
   924     int flags = mDataProvider->flags(itemIndex);
       
   925     const HgImage* indicatorImage = mDataProvider->indicator(flags);
       
   926     if (flags != 0 && indicatorImage)
       
   927     {
       
   928         HgQuad* indicator = mRenderer->quad(quadIndex++);
       
   929         setupIndicator(quad, indicator, indicatorImage, 
       
   930             itemIndex);
       
   931         indicator->enableMirrorImage(reflectionsEnabled);
       
   932     }
       
   933 
       
   934 
       
   935 }
       
   936 
       
   937 void HgMediaWallRenderer::setupIndicator(HgQuad* parent, 
       
   938     HgQuad* indicator, const HgImage* indicatorImage, int itemIndex)
       
   939 {
       
   940     indicator->setPosition(parent->position()+
       
   941         QVector3D(0.25*mImageSize3D.width(), -0.25*mImageSize3D.height(), 0.0001f));
       
   942     indicator->setImage(indicatorImage);
       
   943     indicator->setVisible(true);
       
   944     indicator->setScale(QVector2D(0.25f*mImageSize3D.width(), 0.25f*mImageSize3D.height()));
       
   945     indicator->setPivot(QVector2D(0.0, 0.0));
       
   946     indicator->setUserData(QVariant(itemIndex));
       
   947     indicator->setRotation(parent->rotation());
       
   948     indicator->setOuterRotation(parent->outerRotation());
       
   949     indicator->enableMirrorImage(false);
       
   950     indicator->setAlpha(parent->alpha());
       
   951 
       
   952     // apply opening animation to indicator if needed
       
   953     if (itemIndex == mOpenedItem)
       
   954         applyOpeningAnimation(indicator);
       
   955 }
       
   956 
       
   957 HgQuadRenderer* HgMediaWallRenderer::getRenderer()
       
   958 {
       
   959     return mRenderer;
       
   960 }
       
   961 
       
   962 bool HgMediaWallRenderer::getItemPoints(int index, QPolygonF& points) const
       
   963 {
       
   964     QPolygonF poly;
       
   965     if (!mRenderer->getQuadTranformedPoints(poly, index))
       
   966         return false;
       
   967     
       
   968     points = poly;
       
   969     return true;
       
   970 }
       
   971 
       
   972 QList<HgQuad*> HgMediaWallRenderer::getVisibleQuads() const
       
   973 {
       
   974     return mRenderer->getVisibleQuads(QRectF(0, 0, mRect.width(), mRect.height()));
       
   975 }
       
   976 
       
   977