Qt 4.8
qsequentialanimationgroup.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
85 
86 #include "qpauseanimation.h"
87 
88 #include <QtCore/qdebug.h>
89 
90 #ifndef QT_NO_ANIMATION
91 
93 
95 {
96  // we try to detect if we're at the end of the group
97  //this is true if the following conditions are true:
98  // 1. we're in the last loop
99  // 2. the direction is forward
100  // 3. the current animation is the last one
101  // 4. the current animation has reached its end
102  const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
103  return (currentLoop == loopCount - 1
106  && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex));
107 }
108 
110 {
111  QAbstractAnimation *anim = animations.at(index);
112  int ret = anim->totalDuration();
113  if (ret == -1 && actualDuration.size() > index)
114  ret = actualDuration.at(index); //we can try the actual duration there
115  return ret;
116 }
117 
119 {
121 
122  AnimationIndex ret;
123  int duration = 0;
124 
125  for (int i = 0; i < animations.size(); ++i) {
126  duration = animationActualTotalDuration(i);
127 
128  // 'animation' is the current animation if one of these reasons is true:
129  // 1. it's duration is undefined
130  // 2. it ends after msecs
131  // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
132  // 4. it ends exactly in msecs and the direction is backwards
133  if (duration == -1 || currentTime < (ret.timeOffset + duration)
134  || (currentTime == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) {
135  ret.index = i;
136  return ret;
137  }
138 
139  // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
140  ret.timeOffset += duration;
141  }
142 
143  // this can only happen when one of those conditions is true:
144  // 1. the duration of the group is undefined and we passed its actual duration
145  // 2. there are only 0-duration animations in the group
146  ret.timeOffset -= duration;
147  ret.index = animations.size() - 1;
148  return ret;
149 }
150 
152 {
153  // restarting the group by making the first/last animation the current one
155  lastLoop = 0;
156  if (currentAnimationIndex == 0)
158  else
160  } else { // direction == QAbstractAnimation::Backward
161  lastLoop = loopCount - 1;
162  int index = animations.size() - 1;
163  if (currentAnimationIndex == index)
165  else
166  setCurrentAnimation(index);
167  }
168 }
169 
180 {
181  if (lastLoop < currentLoop) {
182  // we need to fast forward to the end
183  for (int i = currentAnimationIndex; i < animations.size(); ++i) {
184  QAbstractAnimation *anim = animations.at(i);
185  setCurrentAnimation(i, true);
187  }
188  // this will make sure the current animation is reset to the beginning
189  if (animations.size() == 1)
190  // we need to force activation because setCurrentAnimation will have no effect
192  else
193  setCurrentAnimation(0, true);
194  }
195 
196  // and now we need to fast forward from the current position to
197  for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG,
198  QAbstractAnimation *anim = animations.at(i);
199  setCurrentAnimation(i, true);
201  }
202  // setting the new current animation will happen later
203 }
204 
215 {
216  if (lastLoop > currentLoop) {
217  // we need to fast rewind to the beginning
218  for (int i = currentAnimationIndex; i >= 0 ; --i) {
219  QAbstractAnimation *anim = animations.at(i);
220  setCurrentAnimation(i, true);
221  anim->setCurrentTime(0);
222  }
223  // this will make sure the current animation is reset to the end
224  if (animations.size() == 1)
225  // we need to force activation because setCurrentAnimation will have no effect
227  else
228  setCurrentAnimation(animations.count() - 1, true);
229  }
230 
231  // and now we need to fast rewind from the current position to
232  for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) {
233  QAbstractAnimation *anim = animations.at(i);
234  setCurrentAnimation(i, true);
235  anim->setCurrentTime(0);
236  }
237  // setting the new current animation will happen later
238 }
239 
256 {
257 }
258 
263  QObject *parent)
264  : QAnimationGroup(dd, parent)
265 {
266 }
267 
272 {
273 }
274 
284 {
285  QPauseAnimation *pause = new QPauseAnimation(msecs);
286  addAnimation(pause);
287  return pause;
288 }
289 
297 {
299 
300  if (index < 0 || index > d->animations.size()) {
301  qWarning("QSequentialAnimationGroup::insertPause: index is out of bounds");
302  return 0;
303  }
304 
305  QPauseAnimation *pause = new QPauseAnimation(msecs);
306  insertAnimation(index, pause);
307  return pause;
308 }
309 
310 
321 {
323  return d->currentAnimation;
324 }
325 
330 {
332  int ret = 0;
333 
334  for (int i = 0; i < d->animations.size(); ++i) {
335  QAbstractAnimation *animation = d->animations.at(i);
336  const int currentDuration = animation->totalDuration();
337  if (currentDuration == -1)
338  return -1; // Undetermined length
339 
340  ret += currentDuration;
341  }
342 
343  return ret;
344 }
345 
350 {
352  if (!d->currentAnimation)
353  return;
354 
355  const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForCurrentTime();
356 
357  // remove unneeded animations from actualDuration list
358  while (newAnimationIndex.index < d->actualDuration.size())
359  d->actualDuration.removeLast();
360 
361  // newAnimationIndex.index is the new current animation
362  if (d->lastLoop < d->currentLoop
363  || (d->lastLoop == d->currentLoop && d->currentAnimationIndex < newAnimationIndex.index)) {
364  // advancing with forward direction is the same as rewinding with backwards direction
365  d->advanceForwards(newAnimationIndex);
366  } else if (d->lastLoop > d->currentLoop
367  || (d->lastLoop == d->currentLoop && d->currentAnimationIndex > newAnimationIndex.index)) {
368  // rewinding with forward direction is the same as advancing with backwards direction
369  d->rewindForwards(newAnimationIndex);
370  }
371 
372  d->setCurrentAnimation(newAnimationIndex.index);
373 
374  const int newCurrentTime = currentTime - newAnimationIndex.timeOffset;
375 
376  if (d->currentAnimation) {
377  d->currentAnimation->setCurrentTime(newCurrentTime);
378  if (d->atEnd()) {
379  //we make sure that we don't exceed the duration here
380  d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime;
381  stop();
382  }
383  } else {
384  //the only case where currentAnimation could be null
385  //is when all animations have been removed
386  Q_ASSERT(d->animations.isEmpty());
387  d->currentTime = 0;
388  stop();
389  }
390 
391  d->lastLoop = d->currentLoop;
392 }
393 
398  QAbstractAnimation::State oldState)
399 {
401  QAnimationGroup::updateState(newState, oldState);
402 
403  if (!d->currentAnimation)
404  return;
405 
406  switch (newState) {
407  case Stopped:
408  d->currentAnimation->stop();
409  break;
410  case Paused:
411  if (oldState == d->currentAnimation->state()
412  && oldState == QSequentialAnimationGroup::Running) {
413  d->currentAnimation->pause();
414  }
415  else
416  d->restart();
417  break;
418  case Running:
419  if (oldState == d->currentAnimation->state()
420  && oldState == QSequentialAnimationGroup::Paused)
421  d->currentAnimation->start();
422  else
423  d->restart();
424  break;
425  }
426 }
427 
432 {
434  // we need to update the direction of the current animation
435  if (state() != Stopped && d->currentAnimation)
436  d->currentAnimation->setDirection(direction);
437 }
438 
443 {
444  return QAnimationGroup::event(event);
445 }
446 
448 {
450 
451  index = qMin(index, animations.count() - 1);
452 
453  if (index == -1) {
454  Q_ASSERT(animations.isEmpty());
455  currentAnimationIndex = -1;
456  currentAnimation = 0;
457  return;
458  }
459 
460  // need these two checks below because this func can be called after the current animation
461  // has been removed
462  if (index == currentAnimationIndex && animations.at(index) == currentAnimation)
463  return;
464 
465  // stop the old current animation
466  if (currentAnimation)
468 
469  currentAnimation = animations.at(index);
470  currentAnimationIndex = index;
471 
472  emit q->currentAnimationChanged(currentAnimation);
473 
474  activateCurrentAnimation(intermediate);
475 }
476 
478 {
480  return;
481 
483 
484  // we ensure the direction is consistent with the group's direction
486 
487  // connects to the finish signal of uncontrolled animations
488  if (currentAnimation->totalDuration() == -1)
489  connectUncontrolledAnimation(currentAnimation);
490 
492  if (!intermediate && state == QSequentialAnimationGroup::Paused)
494 }
495 
497 {
499  Q_ASSERT(qobject_cast<QAbstractAnimation *>(q->sender()) == currentAnimation);
500 
501  // we trust the duration returned by the animation
502  while (actualDuration.size() < (currentAnimationIndex + 1))
503  actualDuration.append(-1);
504  actualDuration[currentAnimationIndex] = currentAnimation->currentTime();
505 
506  disconnectUncontrolledAnimation(currentAnimation);
507 
508  if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last())
509  || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) {
510  // we don't handle looping of a group with undefined duration
511  q->stop();
512  } else if (direction == QAbstractAnimation::Forward) {
513  // set the current animation to be the next one
514  setCurrentAnimation(currentAnimationIndex + 1);
515  } else {
516  // set the current animation to be the previous one
517  setCurrentAnimation(currentAnimationIndex - 1);
518  }
519 }
520 
531 {
532  if (currentAnimation == 0)
533  setCurrentAnimation(0); // initialize the current animation
534 
535  if (currentAnimationIndex == index
537  //in this case we simply insert an animation before the current one has actually started
538  setCurrentAnimation(index);
539  }
540 
541  //we update currentAnimationIndex in case it has changed (the animation pointer is still valid)
542  currentAnimationIndex = animations.indexOf(currentAnimation);
543 
544  if (index < currentAnimationIndex || currentLoop != 0) {
545  qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one.");
546  return; //we're not affected because it is added after the current one
547  }
548 }
549 
560 {
563 
564  Q_ASSERT(currentAnimation); // currentAnimation should always be set
565 
566  if (actualDuration.size() > index)
567  actualDuration.removeAt(index);
568 
569  const int currentIndex = animations.indexOf(currentAnimation);
570  if (currentIndex == -1) {
571  //we're removing the current animation
572 
573  disconnectUncontrolledAnimation(currentAnimation);
574 
575  if (index < animations.count())
576  setCurrentAnimation(index); //let's try to take the next one
577  else if (index > 0)
578  setCurrentAnimation(index - 1);
579  else// case all animations were removed
580  setCurrentAnimation(-1);
581  } else if (currentAnimationIndex > index) {
582  currentAnimationIndex--;
583  }
584 
585  // duration of the previous animations up to the current animation
586  currentTime = 0;
587  for (int i = 0; i < currentAnimationIndex; ++i) {
588  const int current = animationActualTotalDuration(i);
589  currentTime += current;
590  }
591 
592  if (currentIndex != -1) {
593  //the current animation is not the one being removed
594  //so we add its current time to the current time of this group
596  }
597 
598  //let's also update the total current time
599  totalCurrentTime = currentTime + loopCount * q->duration();
600 }
601 
603 
604 #include "moc_qsequentialanimationgroup.cpp"
605 
606 #endif //QT_NO_ANIMATION
double d
Definition: qnumeric_p.h:62
void advanceForwards(const AnimationIndex &newAnimationIndex)
This manages advancing the execution of a group running forwards (time has gone forward), which is the same behaviour for rewinding the execution of a group running backwards (time has gone backward).
void animationRemoved(int index, QAbstractAnimation *anim)
This method is called whenever an animation is removed from the group at index index.
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
void updateCurrentTime(int)
Reimplemented Function
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int totalDuration() const
Returns the total and effective duration of the animation, including the loop count.
void insertAnimation(int index, QAbstractAnimation *animation)
Inserts animation into this animation group at index.
State
This enum describes the state of the animation.
The QSequentialAnimationGroup class provides a sequential group of animations.
State state() const
The QPauseAnimation class provides a pause for QSequentialAnimationGroup.
static QAbstractAnimationPrivate * get(QAbstractAnimation *q)
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
Starts the animation.
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
int currentLoop() const
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
QAbstractAnimation::Direction direction
void stop()
Stops the animation.
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
#define Q_Q(Class)
Definition: qglobal.h:2483
int currentTime() const
int loopCount() const
void updateDirection(QAbstractAnimation::Direction direction)
Reimplemented Function
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Direction
This enum describes the direction of the animation when in Running state.
void animationInsertedAt(int index)
This method is called whenever an animation is added to the group at index index. ...
void addAnimation(QAbstractAnimation *animation)
Adds animation to this group.
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
void setDirection(Direction direction)
Q_CORE_EXPORT void qWarning(const char *,...)
int duration() const
Reimplemented Function
QList< QAbstractAnimation * > animations
The QAbstractAnimation class is the base of all animations.
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
Reimplemented Function
bool event(QEvent *event)
Reimplemented Function
bool event(QEvent *event)
Reimplemented Function
virtual void animationRemoved(int, QAbstractAnimation *)
int currentLoop
the current loop of the animation
void activateCurrentAnimation(bool intermediate=false)
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
T & last()
Returns a reference to the last item in the list.
Definition: qlist.h:284
int currentTime
the current time and progress of the animation
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
This virtual function is called by QAbstractAnimation when the state of the animation is changed from...
void pause()
Pauses the animation.
~QSequentialAnimationGroup()
Destroys the animation group.
QSequentialAnimationGroup(QObject *parent=0)
Constructs a QSequentialAnimationGroup.
quint16 index
QObject * parent
Definition: qobject.h:92
void rewindForwards(const AnimationIndex &newAnimationIndex)
This manages rewinding the execution of a group running forwards (time has gone forward), which is the same behaviour for advancing the execution of a group running backwards (time has gone backward).
Direction direction() const
QAbstractAnimation * currentAnimation() const
QPauseAnimation * addPause(int msecs)
Adds a pause of msecs to this animation group.
The QAnimationGroup class is an abstract base class for groups of animations.
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
void setCurrentTime(int msecs)
QPauseAnimation * insertPause(int index, int msecs)
Inserts a pause of msecs milliseconds at index in this animation group.
void setCurrentAnimation(int index, bool intermediate=false)