src/corelib/animation/qparallelanimationgroup.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \class QParallelAnimationGroup
       
    44     \brief The QParallelAnimationGroup class provides a parallel group of animations.
       
    45     \since 4.6
       
    46     \ingroup animation
       
    47 
       
    48     QParallelAnimationGroup--a \l{QAnimationGroup}{container for
       
    49     animations}--starts all its animations when it is
       
    50     \l{QAbstractAnimation::start()}{started} itself, i.e., runs all
       
    51     animations in parallel. The animation group finishes when the
       
    52     longest lasting animation has finished.
       
    53 
       
    54     You can treat QParallelAnimation as any other QAbstractAnimation,
       
    55     e.g., pause, resume, or add it to other animation groups.
       
    56 
       
    57     \code
       
    58         QParallelAnimationGroup *group = new QParallelAnimationGroup;
       
    59         group->addAnimation(anim1);
       
    60         group->addAnimation(anim2);
       
    61 
       
    62         group->start();
       
    63     \endcode
       
    64 
       
    65     In this example, \c anim1 and \c anim2 are two
       
    66     \l{QPropertyAnimation}s that have already been set up.
       
    67 
       
    68     \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework}
       
    69 */
       
    70 
       
    71 
       
    72 #include "qparallelanimationgroup.h"
       
    73 #include "qparallelanimationgroup_p.h"
       
    74 //#define QANIMATION_DEBUG
       
    75 
       
    76 #ifndef QT_NO_ANIMATION
       
    77 
       
    78 QT_BEGIN_NAMESPACE
       
    79 
       
    80 /*!
       
    81     Constructs a QParallelAnimationGroup.
       
    82     \a parent is passed to QObject's constructor.
       
    83 */
       
    84 QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
       
    85     : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
       
    86 {
       
    87 }
       
    88 
       
    89 /*!
       
    90     \internal
       
    91 */
       
    92 QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd,
       
    93                                                  QObject *parent)
       
    94     : QAnimationGroup(dd, parent)
       
    95 {
       
    96 }
       
    97 
       
    98 /*!
       
    99     Destroys the animation group. It will also destroy all its animations.
       
   100 */
       
   101 QParallelAnimationGroup::~QParallelAnimationGroup()
       
   102 {
       
   103 }
       
   104 
       
   105 /*!
       
   106     \reimp
       
   107 */
       
   108 int QParallelAnimationGroup::duration() const
       
   109 {
       
   110     Q_D(const QParallelAnimationGroup);
       
   111     int ret = 0;
       
   112 
       
   113     for (int i = 0; i < d->animations.size(); ++i) {
       
   114         QAbstractAnimation *animation = d->animations.at(i);
       
   115         const int currentDuration = animation->totalDuration();
       
   116         if (currentDuration == -1)
       
   117             return -1; // Undetermined length
       
   118 
       
   119         ret = qMax(ret, currentDuration);
       
   120     }
       
   121 
       
   122     return ret;
       
   123 }
       
   124 
       
   125 /*!
       
   126     \reimp
       
   127 */
       
   128 void QParallelAnimationGroup::updateCurrentTime(int currentTime)
       
   129 {
       
   130     Q_D(QParallelAnimationGroup);
       
   131     if (d->animations.isEmpty())
       
   132         return;
       
   133 
       
   134     if (d->currentLoop > d->lastLoop) {
       
   135         // simulate completion of the loop
       
   136         int dura = duration();
       
   137         if (dura > 0) {
       
   138             for (int i = 0; i < d->animations.size(); ++i) {
       
   139                 QAbstractAnimation *animation = d->animations.at(i);
       
   140                 if (animation->state() != QAbstractAnimation::Stopped)
       
   141                     d->animations.at(i)->setCurrentTime(dura);   // will stop
       
   142             }
       
   143         }
       
   144     } else if (d->currentLoop < d->lastLoop) {
       
   145         // simulate completion of the loop seeking backwards
       
   146         for (int i = 0; i < d->animations.size(); ++i) {
       
   147             QAbstractAnimation *animation = d->animations.at(i);
       
   148             //we need to make sure the animation is in the right state
       
   149             //and then rewind it
       
   150             d->applyGroupState(animation);
       
   151             animation->setCurrentTime(0);
       
   152             animation->stop();
       
   153         }
       
   154     }
       
   155 
       
   156 #ifdef QANIMATION_DEBUG
       
   157     qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d",
       
   158         __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state());
       
   159 #endif
       
   160     // finally move into the actual time of the current loop
       
   161     for (int i = 0; i < d->animations.size(); ++i) {
       
   162         QAbstractAnimation *animation = d->animations.at(i);
       
   163         const int dura = animation->totalDuration();
       
   164         //if the loopcount is bigger we should always start all animations
       
   165         if (d->currentLoop > d->lastLoop
       
   166             //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
       
   167             //this happens in Backward direction where not all animations are started at the same time
       
   168             || d->shouldAnimationStart(animation, d->lastCurrentTime > dura /*startIfAtEnd*/)) {
       
   169             d->applyGroupState(animation);
       
   170         }
       
   171 
       
   172         if (animation->state() == state()) {
       
   173             animation->setCurrentTime(currentTime);
       
   174             if (dura > 0 && currentTime > dura)
       
   175                 animation->stop();
       
   176         }
       
   177     }
       
   178     d->lastLoop = d->currentLoop;
       
   179     d->lastCurrentTime = currentTime;
       
   180 }
       
   181 
       
   182 /*!
       
   183     \reimp
       
   184 */
       
   185 void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState,
       
   186                                           QAbstractAnimation::State newState)
       
   187 {
       
   188     Q_D(QParallelAnimationGroup);
       
   189     QAnimationGroup::updateState(oldState, newState);
       
   190 
       
   191     switch (newState) {
       
   192     case Stopped:
       
   193         for (int i = 0; i < d->animations.size(); ++i)
       
   194             d->animations.at(i)->stop();
       
   195         d->disconnectUncontrolledAnimations();
       
   196         break;
       
   197     case Paused:
       
   198         for (int i = 0; i < d->animations.size(); ++i)
       
   199             if (d->animations.at(i)->state() == Running)
       
   200                 d->animations.at(i)->pause();
       
   201         break;
       
   202     case Running:
       
   203         d->connectUncontrolledAnimations();
       
   204         for (int i = 0; i < d->animations.size(); ++i) {
       
   205             QAbstractAnimation *animation = d->animations.at(i);
       
   206             if (oldState == Stopped)
       
   207                 animation->stop();
       
   208             animation->setDirection(d->direction);
       
   209             if (d->shouldAnimationStart(animation, oldState == Stopped))
       
   210                 animation->start();
       
   211         }
       
   212         break;
       
   213     }
       
   214 }
       
   215 
       
   216 void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
       
   217 {
       
   218     Q_Q(QParallelAnimationGroup);
       
   219 
       
   220     QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender());
       
   221     Q_ASSERT(animation);
       
   222 
       
   223     int uncontrolledRunningCount = 0;
       
   224     if (animation->duration() == -1 || animation->loopCount() < 0) {
       
   225         QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
       
   226         while (it != uncontrolledFinishTime.end()) {
       
   227             if (it.key() == animation) {
       
   228                 *it = animation->currentTime();
       
   229             }
       
   230             if (it.value() == -1)
       
   231                 ++uncontrolledRunningCount;
       
   232             ++it;
       
   233         }
       
   234     }
       
   235 
       
   236     if (uncontrolledRunningCount > 0)
       
   237         return;
       
   238 
       
   239     int maxDuration = 0;
       
   240     for (int i = 0; i < animations.size(); ++i)
       
   241         maxDuration = qMax(maxDuration, animations.at(i)->totalDuration());
       
   242 
       
   243     if (currentTime >= maxDuration)
       
   244         q->stop();
       
   245 }
       
   246 
       
   247 void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations()
       
   248 {
       
   249     Q_Q(QParallelAnimationGroup);
       
   250 
       
   251     QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
       
   252     while (it != uncontrolledFinishTime.end()) {
       
   253         QObject::disconnect(it.key(), SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
       
   254         ++it;
       
   255     }
       
   256 
       
   257     uncontrolledFinishTime.clear();
       
   258 }
       
   259 
       
   260 void QParallelAnimationGroupPrivate::connectUncontrolledAnimations()
       
   261 {
       
   262     Q_Q(QParallelAnimationGroup);
       
   263 
       
   264     for (int i = 0; i < animations.size(); ++i) {
       
   265         QAbstractAnimation *animation = animations.at(i);
       
   266         if (animation->duration() == -1 || animation->loopCount() < 0) {
       
   267             uncontrolledFinishTime[animation] = -1;
       
   268             QObject::connect(animation, SIGNAL(finished()), q, SLOT(_q_uncontrolledAnimationFinished()));
       
   269         }
       
   270     }
       
   271 }
       
   272 
       
   273 bool QParallelAnimationGroupPrivate::shouldAnimationStart(QAbstractAnimation *animation, bool startIfAtEnd) const
       
   274 {
       
   275     const int dura = animation->totalDuration();
       
   276     if (dura == -1)
       
   277         return !isUncontrolledAnimationFinished(animation);
       
   278     if (startIfAtEnd)
       
   279         return currentTime <= dura;
       
   280     if (direction == QAbstractAnimation::Forward)
       
   281         return currentTime < dura;
       
   282     else //direction == QAbstractAnimation::Backward
       
   283         return currentTime && currentTime <= dura;
       
   284 }
       
   285 
       
   286 void QParallelAnimationGroupPrivate::applyGroupState(QAbstractAnimation *animation)
       
   287 {
       
   288     switch (state)
       
   289     {
       
   290     case QAbstractAnimation::Running:
       
   291         animation->start();
       
   292         break;
       
   293     case QAbstractAnimation::Paused:
       
   294         animation->pause();
       
   295         break;
       
   296     case QAbstractAnimation::Stopped:
       
   297     default:
       
   298         break;
       
   299     }
       
   300 }
       
   301 
       
   302 
       
   303 bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
       
   304 {
       
   305     return uncontrolledFinishTime.value(anim, -1) >= 0;
       
   306 }
       
   307 
       
   308 /*!
       
   309     \reimp
       
   310 */
       
   311 void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
       
   312 {
       
   313     Q_D(QParallelAnimationGroup);
       
   314     //we need to update the direction of the current animation
       
   315     if (state() != Stopped) {
       
   316         for (int i = 0; i < d->animations.size(); ++i) {
       
   317             QAbstractAnimation *animation = d->animations.at(i);
       
   318             animation->setDirection(direction);
       
   319         }
       
   320     } else {
       
   321         if (direction == Forward) {
       
   322             d->lastLoop = 0;
       
   323             d->lastCurrentTime = 0;
       
   324         } else {
       
   325             // Looping backwards with loopCount == -1 does not really work well...
       
   326             d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1);
       
   327             d->lastCurrentTime = duration();
       
   328         }
       
   329     }
       
   330 }
       
   331 
       
   332 /*!
       
   333     \reimp
       
   334 */
       
   335 bool QParallelAnimationGroup::event(QEvent *event)
       
   336 {
       
   337     return QAnimationGroup::event(event);
       
   338 }
       
   339 
       
   340 QT_END_NAMESPACE
       
   341 
       
   342 #include "moc_qparallelanimationgroup.cpp"
       
   343 
       
   344 #endif //QT_NO_ANIMATION