summaryrefslogtreecommitdiffstats
path: root/src/corelib/animation/qparallelanimationgroup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/animation/qparallelanimationgroup.cpp')
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp347
1 files changed, 347 insertions, 0 deletions
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
new file mode 100644
index 0000000000..414cdde23e
--- /dev/null
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QParallelAnimationGroup
+ \brief The QParallelAnimationGroup class provides a parallel group of animations.
+ \since 4.6
+ \ingroup animation
+
+ QParallelAnimationGroup--a \l{QAnimationGroup}{container for
+ animations}--starts all its animations when it is
+ \l{QAbstractAnimation::start()}{started} itself, i.e., runs all
+ animations in parallel. The animation group finishes when the
+ longest lasting animation has finished.
+
+ You can treat QParallelAnimation as any other QAbstractAnimation,
+ e.g., pause, resume, or add it to other animation groups.
+
+ \code
+ QParallelAnimationGroup *group = new QParallelAnimationGroup;
+ group->addAnimation(anim1);
+ group->addAnimation(anim2);
+
+ group->start();
+ \endcode
+
+ In this example, \c anim1 and \c anim2 are two
+ \l{QPropertyAnimation}s that have already been set up.
+
+ \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework}
+*/
+
+
+#include "qparallelanimationgroup.h"
+#include "qparallelanimationgroup_p.h"
+//#define QANIMATION_DEBUG
+
+#ifndef QT_NO_ANIMATION
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs a QParallelAnimationGroup.
+ \a parent is passed to QObject's constructor.
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
+ : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd,
+ QObject *parent)
+ : QAnimationGroup(dd, parent)
+{
+}
+
+/*!
+ Destroys the animation group. It will also destroy all its animations.
+*/
+QParallelAnimationGroup::~QParallelAnimationGroup()
+{
+}
+
+/*!
+ \reimp
+*/
+int QParallelAnimationGroup::duration() const
+{
+ Q_D(const QParallelAnimationGroup);
+ int ret = 0;
+
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int currentDuration = animation->totalDuration();
+ if (currentDuration == -1)
+ return -1; // Undetermined length
+
+ ret = qMax(ret, currentDuration);
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateCurrentTime(int currentTime)
+{
+ Q_D(QParallelAnimationGroup);
+ if (d->animations.isEmpty())
+ return;
+
+ if (d->currentLoop > d->lastLoop) {
+ // simulate completion of the loop
+ int dura = duration();
+ if (dura > 0) {
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ if (animation->state() != QAbstractAnimation::Stopped)
+ d->animations.at(i)->setCurrentTime(dura); // will stop
+ }
+ }
+ } else if (d->currentLoop < d->lastLoop) {
+ // simulate completion of the loop seeking backwards
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ //we need to make sure the animation is in the right state
+ //and then rewind it
+ d->applyGroupState(animation);
+ animation->setCurrentTime(0);
+ animation->stop();
+ }
+ }
+
+#ifdef QANIMATION_DEBUG
+ qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d",
+ __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state());
+#endif
+ // finally move into the actual time of the current loop
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ const int dura = animation->totalDuration();
+ //if the loopcount is bigger we should always start all animations
+ if (d->currentLoop > d->lastLoop
+ //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
+ //this happens in Backward direction where not all animations are started at the same time
+ || d->shouldAnimationStart(animation, d->lastCurrentTime > dura /*startIfAtEnd*/)) {
+ d->applyGroupState(animation);
+ }
+
+ if (animation->state() == state()) {
+ animation->setCurrentTime(currentTime);
+ if (dura > 0 && currentTime > dura)
+ animation->stop();
+ }
+ }
+ d->lastLoop = d->currentLoop;
+ d->lastCurrentTime = currentTime;
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateState(QAbstractAnimation::State newState,
+ QAbstractAnimation::State oldState)
+{
+ Q_D(QParallelAnimationGroup);
+ QAnimationGroup::updateState(newState, oldState);
+
+ switch (newState) {
+ case Stopped:
+ for (int i = 0; i < d->animations.size(); ++i)
+ d->animations.at(i)->stop();
+ d->disconnectUncontrolledAnimations();
+ break;
+ case Paused:
+ for (int i = 0; i < d->animations.size(); ++i)
+ if (d->animations.at(i)->state() == Running)
+ d->animations.at(i)->pause();
+ break;
+ case Running:
+ d->connectUncontrolledAnimations();
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ if (oldState == Stopped)
+ animation->stop();
+ animation->setDirection(d->direction);
+ if (d->shouldAnimationStart(animation, oldState == Stopped))
+ animation->start();
+ }
+ break;
+ }
+}
+
+void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
+{
+ Q_Q(QParallelAnimationGroup);
+
+ QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender());
+ Q_ASSERT(animation);
+
+ int uncontrolledRunningCount = 0;
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ if (it.key() == animation) {
+ *it = animation->currentTime();
+ }
+ if (it.value() == -1)
+ ++uncontrolledRunningCount;
+ ++it;
+ }
+ }
+
+ if (uncontrolledRunningCount > 0)
+ return;
+
+ int maxDuration = 0;
+ for (int i = 0; i < animations.size(); ++i)
+ maxDuration = qMax(maxDuration, animations.at(i)->totalDuration());
+
+ if (currentTime >= maxDuration)
+ q->stop();
+}
+
+void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations()
+{
+ QHash<QAbstractAnimation *, int>::iterator it = uncontrolledFinishTime.begin();
+ while (it != uncontrolledFinishTime.end()) {
+ disconnectUncontrolledAnimation(it.key());
+ ++it;
+ }
+
+ uncontrolledFinishTime.clear();
+}
+
+void QParallelAnimationGroupPrivate::connectUncontrolledAnimations()
+{
+ for (int i = 0; i < animations.size(); ++i) {
+ QAbstractAnimation *animation = animations.at(i);
+ if (animation->duration() == -1 || animation->loopCount() < 0) {
+ uncontrolledFinishTime[animation] = -1;
+ connectUncontrolledAnimation(animation);
+ }
+ }
+}
+
+bool QParallelAnimationGroupPrivate::shouldAnimationStart(QAbstractAnimation *animation, bool startIfAtEnd) const
+{
+ const int dura = animation->totalDuration();
+ if (dura == -1)
+ return !isUncontrolledAnimationFinished(animation);
+ if (startIfAtEnd)
+ return currentTime <= dura;
+ if (direction == QAbstractAnimation::Forward)
+ return currentTime < dura;
+ else //direction == QAbstractAnimation::Backward
+ return currentTime && currentTime <= dura;
+}
+
+void QParallelAnimationGroupPrivate::applyGroupState(QAbstractAnimation *animation)
+{
+ switch (state)
+ {
+ case QAbstractAnimation::Running:
+ animation->start();
+ break;
+ case QAbstractAnimation::Paused:
+ animation->pause();
+ break;
+ case QAbstractAnimation::Stopped:
+ default:
+ break;
+ }
+}
+
+
+bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
+{
+ return uncontrolledFinishTime.value(anim, -1) >= 0;
+}
+
+void QParallelAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *anim)
+{
+ QAnimationGroupPrivate::animationRemoved(index, anim);
+ disconnectUncontrolledAnimation(anim);
+ uncontrolledFinishTime.remove(anim);
+}
+
+/*!
+ \reimp
+*/
+void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
+{
+ Q_D(QParallelAnimationGroup);
+ //we need to update the direction of the current animation
+ if (state() != Stopped) {
+ for (int i = 0; i < d->animations.size(); ++i) {
+ QAbstractAnimation *animation = d->animations.at(i);
+ animation->setDirection(direction);
+ }
+ } else {
+ if (direction == Forward) {
+ d->lastLoop = 0;
+ d->lastCurrentTime = 0;
+ } else {
+ // Looping backwards with loopCount == -1 does not really work well...
+ d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1);
+ d->lastCurrentTime = duration();
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+bool QParallelAnimationGroup::event(QEvent *event)
+{
+ return QAnimationGroup::event(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qparallelanimationgroup.cpp"
+
+#endif //QT_NO_ANIMATION