Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsequentialanimationgroup.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
38
39#include "qpauseanimation.h"
40
41#include <QtCore/qdebug.h>
42
44
46
48{
49 // we try to detect if we're at the end of the group
50 //this is true if the following conditions are true:
51 // 1. we're in the last loop
52 // 2. the direction is forward
53 // 3. the current animation is the last one
54 // 4. the current animation has reached its end
55 const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
56 return (currentLoop == loopCount - 1
58 && currentAnimation == animations.last()
59 && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex));
60}
61
63{
65 int ret = anim->totalDuration();
66 if (ret == -1 && actualDuration.size() > index)
67 ret = actualDuration.at(index); //we can try the actual duration there
68 return ret;
69}
70
72{
74
76 int duration = 0;
77
78 for (int i = 0; i < animations.size(); ++i) {
80
81 // 'animation' is the current animation if one of these reasons is true:
82 // 1. it's duration is undefined
83 // 2. it ends after msecs
84 // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation)
85 // 4. it ends exactly in msecs and the direction is backwards
86 if (duration == -1 || currentTime < (ret.timeOffset + duration)
87 || (currentTime == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) {
88 ret.index = i;
89 return ret;
90 }
91
92 // 'animation' has a non-null defined duration and is not the one at time 'msecs'.
93 ret.timeOffset += duration;
94 }
95
96 // this can only happen when one of those conditions is true:
97 // 1. the duration of the group is undefined and we passed its actual duration
98 // 2. there are only 0-duration animations in the group
99 ret.timeOffset -= duration;
100 ret.index = animations.size() - 1;
101 return ret;
102}
103
105{
106 // restarting the group by making the first/last animation the current one
108 lastLoop = 0;
109 if (currentAnimationIndex == 0)
111 else
113 } else { // direction == QAbstractAnimation::Backward
114 lastLoop = loopCount - 1;
115 int index = animations.size() - 1;
116 if (currentAnimationIndex == index)
118 else
120 }
121}
122
130{
131 if (lastLoop < currentLoop) {
132 // we need to fast forward to the end
133 for (int i = currentAnimationIndex; i < animations.size(); ++i) {
135 setCurrentAnimation(i, true);
137 }
138 // this will make sure the current animation is reset to the beginning
139 if (animations.size() == 1)
140 // we need to force activation because setCurrentAnimation will have no effect
142 else
143 setCurrentAnimation(0, true);
144 }
145
146 // and now we need to fast forward from the current position to
147 for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG,
149 setCurrentAnimation(i, true);
151 }
152 // setting the new current animation will happen later
153}
154
162{
163 if (lastLoop > currentLoop) {
164 // we need to fast rewind to the beginning
165 for (int i = currentAnimationIndex; i >= 0 ; --i) {
167 setCurrentAnimation(i, true);
168 anim->setCurrentTime(0);
169 }
170 // this will make sure the current animation is reset to the end
171 if (animations.size() == 1)
172 // we need to force activation because setCurrentAnimation will have no effect
174 else
176 }
177
178 // and now we need to fast rewind from the current position to
179 for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) {
181 setCurrentAnimation(i, true);
182 anim->setCurrentTime(0);
183 }
184 // setting the new current animation will happen later
185}
186
205
214
221
236
244{
245 Q_D(const QSequentialAnimationGroup);
246
247 if (index < 0 || index > d->animations.size()) {
248 qWarning("QSequentialAnimationGroup::insertPause: index is out of bounds");
249 return nullptr;
250 }
251
254 return pause;
255}
256
257
263{
264 Q_D(const QSequentialAnimationGroup);
265 return d->currentAnimation;
266}
267
268QBindable<QAbstractAnimation *> QSequentialAnimationGroup::bindableCurrentAnimation() const
269{
270 return &d_func()->currentAnimation;
271}
272
277{
278 Q_D(const QSequentialAnimationGroup);
279 int ret = 0;
280
281 for (AnimationListConstIt it = d->animations.constBegin(), cend = d->animations.constEnd(); it != cend; ++it) {
282 const int currentDuration = (*it)->totalDuration();
283 if (currentDuration == -1)
284 return -1; // Undetermined length
285
286 ret += currentDuration;
287 }
288
289 return ret;
290}
291
296{
298 if (!d->currentAnimation)
299 return;
300
301 const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForCurrentTime();
302
303 // remove unneeded animations from actualDuration list
304 while (newAnimationIndex.index < d->actualDuration.size())
305 d->actualDuration.removeLast();
306
307 // newAnimationIndex.index is the new current animation
308 if (d->lastLoop < d->currentLoop
309 || (d->lastLoop == d->currentLoop && d->currentAnimationIndex < newAnimationIndex.index)) {
310 // advancing with forward direction is the same as rewinding with backwards direction
311 d->advanceForwards(newAnimationIndex);
312 } else if (d->lastLoop > d->currentLoop
313 || (d->lastLoop == d->currentLoop && d->currentAnimationIndex > newAnimationIndex.index)) {
314 // rewinding with forward direction is the same as advancing with backwards direction
315 d->rewindForwards(newAnimationIndex);
316 }
317
318 d->setCurrentAnimation(newAnimationIndex.index);
319
320 const int newCurrentTime = currentTime - newAnimationIndex.timeOffset;
321
322 if (d->currentAnimation) {
323 d->currentAnimation->setCurrentTime(newCurrentTime);
324 if (d->atEnd()) {
325 //we make sure that we don't exceed the duration here
326 d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime;
327 stop();
328 }
329 } else {
330 //the only case where currentAnimation could be null
331 //is when all animations have been removed
332 Q_ASSERT(d->animations.isEmpty());
333 d->currentTime = 0;
334 stop();
335 }
336
337 d->lastLoop = d->currentLoop;
338}
339
345{
348
349 if (!d->currentAnimation)
350 return;
351
352 switch (newState) {
353 case Stopped:
354 d->currentAnimation->stop();
355 break;
356 case Paused:
357 if (oldState == d->currentAnimation->state()
358 && oldState == QSequentialAnimationGroup::Running) {
359 d->currentAnimation->pause();
360 }
361 else
362 d->restart();
363 break;
364 case Running:
365 if (oldState == d->currentAnimation->state()
367 d->currentAnimation->start();
368 else
369 d->restart();
370 break;
371 }
372}
373
378{
380 // we need to update the direction of the current animation
381 if (state() != Stopped && d->currentAnimation)
382 d->currentAnimation->setDirection(direction);
383}
384
392
394{
396 // currentAnimation.removeBindingUnlessInWrapper()
397 // is not necessary here, since it is read only
398
399 index = qMin(index, animations.size() - 1);
400
401 if (index == -1) {
403 currentAnimationIndex = -1;
404 currentAnimation = nullptr;
405 return;
406 }
407
408 // need these two checks below because this func can be called after the current animation
409 // has been removed
410 if (index == currentAnimationIndex && animations.at(index) == currentAnimation)
411 return;
412
413 // stop the old current animation
414 if (currentAnimation)
415 currentAnimation->stop();
416
417 currentAnimationIndex = index;
418 currentAnimation = animations.at(index);
419
420 emit q->currentAnimationChanged(currentAnimation);
421
422 activateCurrentAnimation(intermediate);
423}
424
426{
427 if (!currentAnimation || state == QSequentialAnimationGroup::Stopped)
428 return;
429
430 currentAnimation->stop();
431
432 // we ensure the direction is consistent with the group's direction
433 currentAnimation->setDirection(direction);
434
435 // connects to the finish signal of uncontrolled animations
436 if (currentAnimation->totalDuration() == -1)
437 connectUncontrolledAnimation(currentAnimation);
438
439 currentAnimation->start();
440 if (!intermediate && state == QSequentialAnimationGroup::Paused)
441 currentAnimation->pause();
442}
443
445{
447 Q_ASSERT(qobject_cast<QAbstractAnimation *>(q->sender()) == currentAnimation);
448
449 // we trust the duration returned by the animation
450 while (actualDuration.size() < (currentAnimationIndex + 1))
452 actualDuration[currentAnimationIndex] = currentAnimation->currentTime();
453
454 disconnectUncontrolledAnimation(currentAnimation);
455
456 if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last())
457 || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) {
458 // we don't handle looping of a group with undefined duration
459 q->stop();
461 // set the current animation to be the next one
462 setCurrentAnimation(currentAnimationIndex + 1);
463 } else {
464 // set the current animation to be the previous one
465 setCurrentAnimation(currentAnimationIndex - 1);
466 }
467}
468
476{
477 if (currentAnimation == nullptr) {
478 setCurrentAnimation(0); // initialize the current animation
479 Q_ASSERT(currentAnimation);
480 }
481
482 if (currentAnimationIndex == index
483 && currentAnimation->currentTime() == 0 && currentAnimation->currentLoop() == 0) {
484 //in this case we simply insert an animation before the current one has actually started
486 }
487
488 //we update currentAnimationIndex in case it has changed (the animation pointer is still valid)
489 currentAnimationIndex = animations.indexOf(currentAnimation);
490
491 if (index < currentAnimationIndex || currentLoop != 0) {
492 qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one.");
493 return; //we're not affected because it is added after the current one
494 }
495}
496
504{
507
508 if (!currentAnimation)
509 return;
510
511 if (actualDuration.size() > index)
513
514 const qsizetype currentIndex = animations.indexOf(currentAnimation);
515 if (currentIndex == -1) {
516 //we're removing the current animation
517
518 disconnectUncontrolledAnimation(currentAnimation);
519
520 if (index < animations.size())
521 setCurrentAnimation(index); //let's try to take the next one
522 else if (index > 0)
524 else// case all animations were removed
526 } else if (currentAnimationIndex > index) {
527 currentAnimationIndex--;
528 }
529
530 // duration of the previous animations up to the current animation
531 currentTime = 0;
532 for (qsizetype i = 0; i < currentAnimationIndex; ++i) {
533 const int current = animationActualTotalDuration(i);
534 currentTime += current;
535 }
536
537 if (currentIndex != -1) {
538 //the current animation is not the one being removed
539 //so we add its current time to the current time of this group
540 currentTime += QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime;
541 }
542
543 //let's also update the total current time
544 totalCurrentTime = currentTime + loopCount * q->duration();
545}
546
548
549#include "moc_qsequentialanimationgroup.cpp"
static QAbstractAnimationPrivate * get(QAbstractAnimation *q)
State state
state of the animation.
Direction direction
the direction of the animation when it is in \l Running state.
State
This enum describes the state of the animation.
void stop()
Stops the animation.
int totalDuration() const
Returns the total and effective duration of the animation, including the loop count.
int currentTime
the current time and progress of the animation
void setCurrentTime(int msecs)
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...
Direction
This enum describes the direction of the animation when in \l Running state.
void pause()
Pauses the animation.
QList< QAbstractAnimation * > animations
void disconnectUncontrolledAnimation(QAbstractAnimation *anim)
void connectUncontrolledAnimation(QAbstractAnimation *anim)
virtual void animationRemoved(qsizetype, QAbstractAnimation *)
\inmodule QtCore
void addAnimation(QAbstractAnimation *animation)
Adds animation to this group.
void insertAnimation(int index, QAbstractAnimation *animation)
Inserts animation into this animation group at index.
bool event(QEvent *event) override
\reimp
\inmodule QtCore
Definition qcoreevent.h:45
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & last()
Definition qlist.h:648
void removeAt(qsizetype i)
Definition qlist.h:590
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore
void activateCurrentAnimation(bool intermediate=false)
void advanceForwards(const AnimationIndex &newAnimationIndex)
void animationInsertedAt(qsizetype index) override
void rewindForwards(const AnimationIndex &newAnimationIndex)
void animationRemoved(qsizetype index, QAbstractAnimation *anim) override
void setCurrentAnimation(int index, bool intermediate=false)
QPauseAnimation * addPause(int msecs)
Adds a pause of msecs to this animation group.
QAbstractAnimation * currentAnimation
the animation in the current time.
void updateDirection(QAbstractAnimation::Direction direction) override
\reimp
void updateCurrentTime(int) override
\reimp
bool event(QEvent *event) override
\reimp
int duration() const override
\reimp
QPauseAnimation * insertPause(int index, int msecs)
Inserts a pause of msecs milliseconds at index in this animation group.
~QSequentialAnimationGroup()
Destroys the animation group.
QSequentialAnimationGroup(QObject *parent=nullptr)
Constructs a QSequentialAnimationGroup.
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override
\reimp
QBindable< QAbstractAnimation * > bindableCurrentAnimation() const
const_iterator constBegin() const noexcept
Definition qset.h:139
QSet< QString >::iterator it
direction
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
QList< QAbstractAnimation * >::ConstIterator AnimationListConstIt
#define qWarning
Definition qlogging.h:166
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLuint index
[2]
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef QList< QAbstractAnimation * >::ConstIterator AnimationListConstIt
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
static double currentTime()
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962