source: trunk/src/corelib/animation/qparallelanimationgroup.cpp@ 641

Last change on this file since 641 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
78QT_BEGIN_NAMESPACE
79
80/*!
81 Constructs a QParallelAnimationGroup.
82 \a parent is passed to QObject's constructor.
83*/
84QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
85 : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
86{
87}
88
89/*!
90 \internal
91*/
92QParallelAnimationGroup::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*/
101QParallelAnimationGroup::~QParallelAnimationGroup()
102{
103}
104
105/*!
106 \reimp
107*/
108int 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*/
128void 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*/
185void QParallelAnimationGroup::updateState(QAbstractAnimation::State newState,
186 QAbstractAnimation::State oldState)
187{
188 Q_D(QParallelAnimationGroup);
189 QAnimationGroup::updateState(newState, oldState);
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
216void 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
247void 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
260void 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
273bool 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
286void 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
303bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
304{
305 return uncontrolledFinishTime.value(anim, -1) >= 0;
306}
307
308/*!
309 \reimp
310*/
311void 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*/
335bool QParallelAnimationGroup::event(QEvent *event)
336{
337 return QAnimationGroup::event(event);
338}
339
340QT_END_NAMESPACE
341
342#include "moc_qparallelanimationgroup.cpp"
343
344#endif //QT_NO_ANIMATION
Note: See TracBrowser for help on using the repository browser.