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
qabstractanimation.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
108#include "qabstractanimation.h"
109#include "qanimationgroup.h"
110
111#include <QtCore/qdebug.h>
112
113#include "qabstractanimation_p.h"
114
115#include <QtCore/qmath.h>
116#include <QtCore/qcoreevent.h>
117#include <QtCore/qpointer.h>
118#include <QtCore/qscopedvaluerollback.h>
119
120#define DEFAULT_TIMER_INTERVAL 16
121#define PAUSE_TIMER_COARSE_THRESHOLD 2000
122
124
127
180QUnifiedTimer::QUnifiedTimer() :
181 QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
182 currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
183 startTimersPending(false), stopTimerPending(false), allowNegativeDelta(false),
184 slowdownFactor(5.0f), profilerCallback(nullptr),
185 driverStartTime(0), temporalDrift(0)
186{
187 time.invalidate();
188 driver = &defaultDriver;
189}
190
192 = default;
193
195{
196 QUnifiedTimer *inst;
197 static thread_local std::unique_ptr<QUnifiedTimer> unifiedTimer;
198 if (create && !unifiedTimer) {
199 inst = new QUnifiedTimer;
200 unifiedTimer.reset(inst);
201 } else {
202 inst = unifiedTimer.get();
203 }
204 return inst;
205}
206
208{
209 return instance(true);
210}
211
213{
214 if (elapsed() - lastTick > 50)
216}
217
219{
220 if (driver->isRunning())
221 return driverStartTime + driver->elapsed();
222 else if (time.isValid())
223 return time.elapsed() + temporalDrift;
224
225 // Reaching here would normally indicate that the function is called
226 // under the wrong circumstances as neither pauses nor actual animations
227 // are running and there should be no need to query for elapsed().
228 return 0;
229}
230
232{
233 if (driver->isRunning()) {
234 qWarning("QUnifiedTimer::startAnimationDriver: driver is already running...");
235 return;
236 }
237 // Set the start time to the currently elapsed() value before starting.
238 // This means we get the animation system time including the temporal drift
239 // which is what we want.
240 driverStartTime = elapsed();
241 driver->start();
242}
243
245{
246 if (!driver->isRunning()) {
247 qWarning("QUnifiedTimer::stopAnimationDriver: driver is not running");
248 return;
249 }
250 // Update temporal drift. Since the driver is running, elapsed() will
251 // return the total animation time in driver-time. Subtract the current
252 // wall time to get the delta.
253 temporalDrift = elapsed() - time.elapsed();
254 driver->stop();
255}
256
258{
259 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
260 if (insideTick)
261 return;
262
263 const qint64 totalElapsed = elapsed();
264
265 // ignore consistentTiming in case the pause timer is active
266 qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
267 timingInterval : totalElapsed - lastTick;
268 if (slowMode) {
269 if (slowdownFactor > 0)
270 delta = qRound(delta / slowdownFactor);
271 else
272 delta = 0;
273 }
274
275 lastTick = totalElapsed;
276
277 //we make sure we only call update time if the time has actually advanced
278 //* it might happen in some cases that the time doesn't change because events are delayed
279 // when the CPU load is high
280 //* it might happen in some cases that the delta is negative because the animation driver
281 // advances faster than time.elapsed()
282 if (delta != 0 && (allowNegativeDelta || delta > 0)) {
283 QScopedValueRollback<bool> guard(insideTick, true);
284 if (profilerCallback)
285 profilerCallback(delta);
286 for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.size(); ++currentAnimationIdx) {
287 QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx);
288 animation->updateAnimationsTime(delta);
289 }
290 currentAnimationIdx = 0;
291 }
292}
293
295{
296 int count = 0;
297 for (int i = 0; i < animationTimers.size(); ++i)
298 count += animationTimers.at(i)->runningAnimationCount();
299 return count;
300}
301
303{
304 profilerCallback = cb;
305}
306
307void QUnifiedTimer::localRestart()
308{
309 if (insideRestart)
310 return;
311
312 if (!pausedAnimationTimers.isEmpty() && (animationTimers.size() + animationTimersToStart.size() == pausedAnimationTimers.size())) {
313 driver->stop();
314 int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish();
315 // use a precise timer if the pause will be short
317 pauseTimer.start(closestTimeToFinish, timerType, this);
318 } else if (!driver->isRunning()) {
319 if (pauseTimer.isActive())
320 pauseTimer.stop();
322 }
323
324}
325
327{
328 {
329 QScopedValueRollback<bool> guard(insideRestart, true);
330 for (int i = 0; i < animationTimers.size(); ++i)
331 animationTimers.at(i)->restartAnimationTimer();
332 }
333
334 localRestart();
335}
336
338{
339 timingInterval = interval;
340
341 if (driver->isRunning() && !pauseTimer.isActive()) {
342 //we changed the timing interval
345 }
346}
347
348void QUnifiedTimer::startTimers()
349{
350 startTimersPending = false;
351
352 //we transfer the waiting animations into the "really running" state
353 animationTimers += animationTimersToStart;
354 animationTimersToStart.clear();
355 if (!animationTimers.isEmpty()) {
356 if (!time.isValid()) {
357 lastTick = 0;
358 time.start();
359 temporalDrift = 0;
360 driverStartTime = 0;
361 }
362 localRestart();
363 }
364}
365
366void QUnifiedTimer::stopTimer()
367{
368 stopTimerPending = false;
369 if (animationTimers.isEmpty()) {
371 pauseTimer.stop();
372 // invalidate the start reference time
373 time.invalidate();
374 }
375}
376
378{
379 //in the case of consistent timing we make sure the order in which events come is always the same
380 //for that purpose we do as if the startstoptimer would always fire before the animation timer
381 if (consistentTiming) {
382 if (stopTimerPending)
383 stopTimer();
384 if (startTimersPending)
385 startTimers();
386 }
387
388 if (event->timerId() == pauseTimer.timerId()) {
389 // update current time on all timers
391 restart();
392 }
393}
394
396{
397 if (timer->isRegistered)
398 return;
399 timer->isRegistered = true;
400
401 QUnifiedTimer *inst = instance(true); //we create the instance if needed
402 inst->animationTimersToStart << timer;
403 if (!inst->startTimersPending) {
404 inst->startTimersPending = true;
406 }
407}
408
410{
412 if (inst) {
413 //at this point the unified timer should have been created
414 //but it might also have been already destroyed in case the application is shutting down
415
416 if (!timer->isRegistered)
417 return;
418 timer->isRegistered = false;
419
420 int idx = inst->animationTimers.indexOf(timer);
421 if (idx != -1) {
422 inst->animationTimers.removeAt(idx);
423 // this is needed if we unregister an animation while its running
424 if (idx <= inst->currentAnimationIdx)
425 --inst->currentAnimationIdx;
426
427 if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) {
428 inst->stopTimerPending = true;
430 }
431 } else {
432 inst->animationTimersToStart.removeOne(timer);
433 }
434 }
435}
436
438{
440 if (!timer->isRegistered)
442
443 bool timerWasPaused = timer->isPaused;
444 timer->isPaused = true;
445 timer->pauseDuration = duration;
446 if (!timerWasPaused)
447 inst->pausedAnimationTimers << timer;
448 inst->localRestart();
449}
450
452{
453 if (!timer->isPaused)
454 return;
455
456 timer->isPaused = false;
458 inst->pausedAnimationTimers.removeOne(timer);
459 inst->localRestart();
460}
461
462int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish()
463{
464 int closestTimeToFinish = INT_MAX;
465 for (TimerListConstIt it = pausedAnimationTimers.constBegin(), cend = pausedAnimationTimers.constEnd(); it != cend; ++it) {
466 const int timeToFinish = (*it)->pauseDuration;
467 if (timeToFinish < closestTimeToFinish)
468 closestTimeToFinish = timeToFinish;
469 }
470 return closestTimeToFinish;
471}
472
474{
475 if (driver != &defaultDriver) {
476 qWarning("QUnifiedTimer: animation driver already installed...");
477 return;
478 }
479
480 bool running = driver->isRunning();
481 if (running)
483 driver = d;
484 if (driver)
485 allowNegativeDelta = driver->property("allowNegativeDelta").toBool();
486 if (running)
488}
489
491{
492 if (driver != d) {
493 qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
494 return;
495 }
496
497 bool running = driver->isRunning();
498 if (running)
500 driver = &defaultDriver;
501 allowNegativeDelta = false;
502 if (running)
504}
505
511{
512 return d == driver && driver != &defaultDriver;
513}
514
515QAnimationTimer::QAnimationTimer() :
516 QAbstractAnimationTimer(), lastTick(0),
517 currentAnimationIdx(0), insideTick(false),
518 startAnimationPending(false), stopTimerPending(false),
519 runningLeafAnimations(0)
520{
521}
522
524 = default;
525
527{
528 QAnimationTimer *inst;
529#if QT_CONFIG(thread)
530 static thread_local std::unique_ptr<QAnimationTimer> animationTimer;
531 if (create && !animationTimer) {
532 inst = new QAnimationTimer;
533 animationTimer.reset(inst);
534 } else {
535 inst = animationTimer.get();
536 }
537#else
539 static QAnimationTimer animationTimer;
540 inst = &animationTimer;
541#endif
542 return inst;
543}
544
549
551{
554 if (instU && inst && inst->isPaused)
555 instU->updateAnimationTimers();
556}
557
559{
560 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
561 if (insideTick)
562 return;
563
564 lastTick += delta;
565
566 //we make sure we only call update time if the time has actually changed
567 //it might happen in some cases that the time doesn't change because events are delayed
568 //when the CPU load is high
569 if (delta) {
570 QScopedValueRollback<bool> guard(insideTick, true);
571 for (currentAnimationIdx = 0; currentAnimationIdx < animations.size(); ++currentAnimationIdx) {
572 QAbstractAnimation *animation = animations.at(currentAnimationIdx);
573 int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
574 + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
576 }
577 currentAnimationIdx = 0;
578 }
579}
580
582{
584 if (inst)
585 inst->restartAnimationTimer();
586}
587
589{
590 if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
591 QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
592 else if (isPaused)
594 else if (!isRegistered)
596}
597
598void QAnimationTimer::startAnimations()
599{
600 if (!startAnimationPending)
601 return;
602 startAnimationPending = false;
603
604 //force timer to update, which prevents large deltas for our newly added animations
605 QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
606
607 //we transfer the waiting animations into the "really running" state
608 animations += animationsToStart;
609 animationsToStart.clear();
610 if (!animations.isEmpty())
612}
613
614void QAnimationTimer::stopTimer()
615{
616 stopTimerPending = false;
617 bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
618 if (animations.isEmpty() && !pendingStart) {
621 // invalidate the start reference time
622 lastTick = 0;
623 }
624}
625
627{
628 QAnimationTimer *inst = instance(true); //we create the instance if needed
629 inst->registerRunningAnimation(animation);
630 if (isTopLevel) {
632 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
633 inst->animationsToStart << animation;
634 if (!inst->startAnimationPending) {
635 inst->startAnimationPending = true;
636 QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
637 }
638 }
639}
640
642{
644 if (inst) {
645 //at this point the unified timer should have been created
646 //but it might also have been already destroyed in case the application is shutting down
647
648 inst->unregisterRunningAnimation(animation);
649
650 if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
651 return;
652
653 int idx = inst->animations.indexOf(animation);
654 if (idx != -1) {
655 inst->animations.removeAt(idx);
656 // this is needed if we unregister an animation while its running
657 if (idx <= inst->currentAnimationIdx)
658 --inst->currentAnimationIdx;
659
660 if (inst->animations.isEmpty() && !inst->stopTimerPending) {
661 inst->stopTimerPending = true;
663 }
664 } else {
665 inst->animationsToStart.removeOne(animation);
666 }
667 }
668 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
669}
670
671void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation)
672{
674 return;
675
677 runningPauseAnimations << animation;
678 } else
679 runningLeafAnimations++;
680}
681
682void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
683{
685 return;
686
688 runningPauseAnimations.removeOne(animation);
689 else
690 runningLeafAnimations--;
691 Q_ASSERT(runningLeafAnimations >= 0);
692}
693
694int QAnimationTimer::closestPauseAnimationTimeToFinish()
695{
696 int closestTimeToFinish = INT_MAX;
697 for (AnimationListConstIt it = runningPauseAnimations.constBegin(), cend = runningPauseAnimations.constEnd(); it != cend; ++it) {
699 int timeToFinish;
700
702 timeToFinish = animation->duration() - animation->currentLoopTime();
703 else
704 timeToFinish = animation->currentLoopTime();
705
706 if (timeToFinish < closestTimeToFinish)
707 closestTimeToFinish = timeToFinish;
708 }
709 return closestTimeToFinish;
710}
711
729
734
736{
738 if (timer && timer->canUninstallAnimationDriver(this))
739 uninstall();
740}
741
751{
753
754 // update current time on all top level animations
755 instance->updateAnimationTimers();
756 instance->restart();
757}
758
759
760
770
771
772
779{
781 timer->installAnimationDriver(this);
782}
783
784
785
791{
793 timer->uninstallAnimationDriver(this);
794}
795
797{
798 return d_func()->running;
799}
800
801
803{
804 Q_D(QAnimationDriver);
805 if (!d->running) {
806 d->running = true;
807 d->timer.start();
808 emit started();
809 }
810}
811
812
814{
815 Q_D(QAnimationDriver);
816 if (d->running) {
817 d->running = false;
818 emit stopped();
819 }
820}
821
822
830{
831 Q_D(const QAnimationDriver);
832 return d->running ? d->timer.elapsed() : 0;
833}
834
857 : QAnimationDriver(nullptr), m_unified_timer(timer)
858{
859 connect(this, &QAnimationDriver::started, this, &QDefaultAnimationDriver::startTimer);
860 connect(this, &QAnimationDriver::stopped, this, &QDefaultAnimationDriver::stopTimer);
861}
862
864{
865 disconnect(this, &QAnimationDriver::started, this, &QDefaultAnimationDriver::startTimer);
866 disconnect(this, &QAnimationDriver::stopped, this, &QDefaultAnimationDriver::stopTimer);
867}
868
870{
871 Q_ASSERT(e->timerId() == m_timer.timerId());
872 Q_UNUSED(e); // if the assertions are disabled
873 advance();
874}
875
876void QDefaultAnimationDriver::startTimer()
877{
878 // always use a precise timer to drive animations
879 m_timer.start(m_unified_timer->timingInterval, Qt::PreciseTimer, this);
880}
881
882void QDefaultAnimationDriver::stopTimer()
883{
884 m_timer.stop();
885}
886
888 = default;
889
891 = default;
892
894 = default;
895
897 = default;
898
900 = default;
901
903
904void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
905{
907 const QAbstractAnimation::State oldState = state.valueBypassingBindings();
908 if (oldState == newState)
909 return;
910
911 if (loopCount == 0)
912 return;
913
914 int oldCurrentTime = currentTime;
915 int oldCurrentLoop = currentLoop;
917
918 // check if we should Rewind
920 && oldState == QAbstractAnimation::Stopped) {
921 const int oldTotalCurrentTime = totalCurrentTime;
922 //here we reset the time if needed
923 //we don't call setCurrentTime because this might change the way the animation
924 //behaves: changing the state or changing the current value
925 totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
926 0 : (loopCount == -1 ? q->duration() : q->totalDuration());
927 if (totalCurrentTime != oldTotalCurrentTime)
928 totalCurrentTime.notify();
929 }
930
931 state.setValueBypassingBindings(newState);
932 QPointer<QAbstractAnimation> guard(q);
933
934 //(un)registration of the animation must always happen before calls to
935 //virtual function (updateState) to ensure a correct state of the timer
936 bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
937 if (oldState == QAbstractAnimation::Running) {
940 //the animation, is not running any more
944 }
945
946 q->updateState(newState, oldState);
947 //this is to be safe if updateState changes the state
948 if (!guard || newState != state.valueBypassingBindings())
949 return;
950
951 // Notify state change
952 state.notify();
953 emit q->stateChanged(newState, oldState);
954 //this is to be safe if updateState changes the state
955 if (!guard || newState != state.valueBypassingBindings())
956 return;
957
958 switch (state) {
960 break;
962 {
963
964 // this ensures that the value is updated now that the animation is running
965 if (oldState == QAbstractAnimation::Stopped) {
966 if (isTopLevel) {
967 // currentTime needs to be updated if pauseTimer is active
969 q->setCurrentTime(totalCurrentTime);
970 }
971 }
972 }
973 break;
975 // Leave running state.
976 int dura = q->duration();
977
978 if (deleteWhenStopped)
979 q->deleteLater();
980
981 if (dura == -1 || loopCount < 0
982 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
983 || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
984 emit q->finished();
985 }
986 break;
987 }
988}
989
998{
999 // Allow auto-add on reparent
1001}
1002
1007 : QObject(dd, nullptr)
1008{
1009 // Allow auto-add on reparent
1011}
1012
1019{
1020 Q_D(QAbstractAnimation);
1021 //we can't call stop here. Otherwise we get pure virtual calls
1022 if (d->state != Stopped) {
1023 QAbstractAnimation::State oldState = d->state;
1024 d->state = Stopped;
1025 d->state.notify();
1026 emit stateChanged(d->state, oldState);
1027 if (oldState == QAbstractAnimation::Running)
1029 }
1030 if (d->group)
1031 d->group->removeAnimation(this);
1032}
1033
1048{
1049 Q_D(const QAbstractAnimation);
1050 return d->state;
1051}
1052
1053QBindable<QAbstractAnimation::State> QAbstractAnimation::bindableState() const
1054{
1055 Q_D(const QAbstractAnimation);
1056 return &d->state;
1057}
1058
1066{
1067 Q_D(const QAbstractAnimation);
1068 return d->group;
1069}
1070
1117{
1118 Q_D(const QAbstractAnimation);
1119 return d->direction;
1120}
1122{
1123 Q_D(QAbstractAnimation);
1124 if (d->direction == direction) {
1125 d->direction.removeBindingUnlessInWrapper();
1126 return;
1127 }
1128
1129 const QScopedPropertyUpdateGroup guard;
1130 const int oldCurrentLoop = d->currentLoop;
1131 if (state() == Stopped) {
1132 if (direction == Backward) {
1133 d->currentTime = duration();
1134 d->currentLoop = d->loopCount - 1;
1135 } else {
1136 d->currentTime = 0;
1137 d->currentLoop = 0;
1138 }
1139 }
1140
1141 // the commands order below is important: first we need to setCurrentTime with the old direction,
1142 // then update the direction on this and all children and finally restart the pauseTimer if needed
1143 if (d->hasRegisteredTimer)
1145
1146 d->direction = direction;
1148
1149 if (d->hasRegisteredTimer)
1150 // needed to update the timer interval in case of a pause animation
1152
1153 if (d->currentLoop != oldCurrentLoop)
1154 d->currentLoop.notify();
1155 d->direction.notify();
1156}
1157
1158QBindable<QAbstractAnimation::Direction> QAbstractAnimation::bindableDirection()
1159{
1160 Q_D(QAbstractAnimation);
1161 return &d->direction;
1162}
1163
1186{
1187 Q_D(const QAbstractAnimation);
1188 return d->loopCount;
1189}
1191{
1192 Q_D(QAbstractAnimation);
1193 d->loopCount = loopCount;
1194}
1195
1197{
1198 Q_D(QAbstractAnimation);
1199 return &d->loopCount;
1200}
1201
1216{
1217 Q_D(const QAbstractAnimation);
1218 return d->currentLoop;
1219}
1220
1222{
1223 Q_D(const QAbstractAnimation);
1224 return &d->currentLoop;
1225}
1226
1252{
1253 int dura = duration();
1254 if (dura <= 0)
1255 return dura;
1256 int loopcount = loopCount();
1257 if (loopcount < 0)
1258 return -1;
1259 return dura * loopcount;
1260}
1261
1269{
1270 Q_D(const QAbstractAnimation);
1271 return d->currentTime;
1272}
1273
1292{
1293 Q_D(const QAbstractAnimation);
1294 return d->totalCurrentTime;
1295}
1296
1298{
1299 Q_D(QAbstractAnimation);
1300 return &d->totalCurrentTime;
1301}
1302
1304{
1305 Q_D(QAbstractAnimation);
1306 msecs = qMax(msecs, 0);
1307
1308 // Calculate new time and loop.
1309 const int dura = duration();
1310 const int totalLoopCount = d->loopCount;
1311 const int totalDura = dura <= 0 ? dura : ((totalLoopCount < 0) ? -1 : dura * totalLoopCount);
1312 if (totalDura != -1)
1313 msecs = qMin(totalDura, msecs);
1314
1315 d->totalCurrentTime.removeBindingUnlessInWrapper();
1316
1317 const int oldCurrentTime = d->totalCurrentTime.valueBypassingBindings();
1318 d->totalCurrentTime.setValueBypassingBindings(msecs);
1319
1320 QAbstractAnimation::Direction currentDirection = d->direction;
1321
1322 // Update new values.
1323 const int oldLoop = d->currentLoop.valueBypassingBindings();
1324 int newCurrentLoop = (dura <= 0) ? 0 : (msecs / dura);
1325 if (newCurrentLoop == totalLoopCount) {
1326 //we're at the end
1327 d->currentTime = qMax(0, dura);
1328 newCurrentLoop = qMax(0, totalLoopCount - 1);
1329 } else {
1330 if (currentDirection == Forward) {
1331 d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
1332 } else {
1333 d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
1334 if (d->currentTime == dura)
1335 newCurrentLoop = newCurrentLoop - 1;
1336 }
1337 }
1338 d->currentLoop.setValueBypassingBindings(newCurrentLoop);
1339
1340 // this is a virtual function, so it can update the properties as well
1341 updateCurrentTime(d->currentTime);
1342
1343 // read the property values again
1344 newCurrentLoop = d->currentLoop.valueBypassingBindings();
1345 currentDirection = d->direction;
1346 const int newTotalCurrentTime = d->totalCurrentTime.valueBypassingBindings();
1347
1348 if (newCurrentLoop != oldLoop)
1349 d->currentLoop.notify();
1350
1351 /* Notify before calling stop: As seen in tst_QSequentialAnimationGroup::clear
1352 * we might delete the animation when stop is called. Thus after stop no member
1353 * of the object must be used anymore.
1354 */
1355 if (oldCurrentTime != newTotalCurrentTime)
1356 d->totalCurrentTime.notify();
1357 // All animations are responsible for stopping the animation when their
1358 // own end state is reached; in this case the animation is time driven,
1359 // and has reached the end.
1360 if ((currentDirection == Forward && newTotalCurrentTime == totalDura)
1361 || (currentDirection == Backward && newTotalCurrentTime == 0)) {
1362 stop();
1363 }
1364}
1365
1383{
1384 Q_D(QAbstractAnimation);
1385 if (d->state.valueBypassingBindings() == Running)
1386 return;
1387 d->deleteWhenStopped = policy;
1388 d->setState(Running);
1389}
1390
1402{
1403 Q_D(QAbstractAnimation);
1404
1405 if (d->state.valueBypassingBindings() == Stopped)
1406 return;
1407
1408 d->setState(Stopped);
1409}
1410
1419{
1420 Q_D(QAbstractAnimation);
1421 if (d->state.valueBypassingBindings() == Stopped) {
1422 qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
1423 return;
1424 }
1425
1426 d->setState(Paused);
1427}
1428
1437{
1438 Q_D(QAbstractAnimation);
1439 if (d->state.valueBypassingBindings() != Paused) {
1440 qWarning("QAbstractAnimation::resume: "
1441 "Cannot resume an animation that is not paused");
1442 return;
1443 }
1444
1445 d->setState(Running);
1446}
1447
1455{
1456 if (paused)
1457 pause();
1458 else
1459 resume();
1460}
1461
1462
1470
1492
1503
1504
1506
1507#include "moc_qabstractanimation.cpp"
1508#include "moc_qabstractanimation_p.cpp"
static QAbstractAnimationPrivate * get(QAbstractAnimation *q)
virtual void restartAnimationTimer()=0
~QAbstractAnimationTimer() override
virtual int runningAnimationCount()=0
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 resume()
Resumes the animation after it was paused.
QBindable< Direction > bindableDirection()
void setPaused(bool)
If paused is true, the animation is paused.
void stop()
Stops the animation.
DeletionPolicy
\value KeepWhenStopped The animation will not be deleted when stopped.
virtual void updateCurrentTime(int currentTime)=0
This pure virtual function is called every time the animation's currentTime changes.
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
Starts the animation.
bool event(QEvent *event) override
\reimp
int loopCount
the loop count of the animation
QAbstractAnimation(QObject *parent=nullptr)
Constructs the QAbstractAnimation base class, and passes parent to QObject's constructor.
int totalDuration() const
Returns the total and effective duration of the animation, including the loop count.
void setLoopCount(int loopCount)
QBindable< int > bindableCurrentLoop() const
int currentLoopTime() const
Returns the current time inside the current loop.
void setDirection(Direction direction)
int currentLoop
the current loop of the animation
virtual void updateDirection(QAbstractAnimation::Direction direction)
This virtual function is called by QAbstractAnimation when the direction of the animation is changed.
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.
QBindable< QAbstractAnimation::State > bindableState() const
QBindable< int > bindableCurrentTime()
void pause()
Pauses the animation.
void stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
QAbstractAnimation emits this signal whenever the state of the animation has changed from oldState to...
virtual ~QAbstractAnimation()
Stops the animation if it's running, then destroys the QAbstractAnimation.
QBindable< int > bindableLoopCount()
QAnimationGroup * group() const
If this animation is part of a QAnimationGroup, this function returns a pointer to the group; otherwi...
int duration
the duration of the animation.
~QAnimationDriverPrivate() override
\inmodule QtCore
void install()
Installs this animation driver.
virtual qint64 elapsed() const
Returns the number of milliseconds since the animations was started.
void started()
This signal is emitted by the animation framework to notify the driver that continuous animation has ...
virtual void advance()
Advances the animation.
void advanceAnimation()
Advances the animation.
QAnimationDriver(QObject *parent=nullptr)
void stopped()
This signal is emitted by the animation framework to notify the driver that continuous animation has ...
void uninstall()
Uninstalls this animation driver.
\inmodule QtCore
static void unregisterAnimation(QAbstractAnimation *animation)
static void updateAnimationTimer()
void updateAnimationsTime(qint64 delta) override
~QAnimationTimer() override
void restartAnimationTimer() override
static void ensureTimerUpdate()
static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
static QAnimationTimer * instance()
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
int timerId() const noexcept
Returns the timer's ID.
Definition qbasictimer.h:35
void stop()
Stops the timer.
bool isActive() const noexcept
Returns true if the timer is running and has not been stopped; otherwise returns false.
Definition qbasictimer.h:34
QDefaultAnimationDriver(QUnifiedTimer *timer)
The default animation driver just spins the timer...
void timerEvent(QTimerEvent *e) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void invalidate() noexcept
Marks this QElapsedTimer object as invalid.
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
bool isValid() const noexcept
Returns false if the timer has never been started or invalidated by a call to invalidate().
\inmodule QtCore
Definition qcoreevent.h:45
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
void removeAt(qsizetype i)
Definition qlist.h:590
bool removeOne(const AT &t)
Definition qlist.h:598
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator constBegin() const noexcept
Definition qlist.h:632
const_iterator constEnd() const noexcept
Definition qlist.h:633
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
void setParent(QObject *parent)
Makes the object a child of parent.
Definition qobject.cpp:2195
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
RAII class around Qt::beginPropertyUpdateGroup()/Qt::endPropertyUpdateGroup().
Definition qproperty.h:57
\inmodule QtCore
Definition qcoreevent.h:366
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition qcoreevent.h:370
\inmodule QtCore
static void stopAnimationTimer(QAbstractAnimationTimer *timer)
void installAnimationDriver(QAnimationDriver *driver)
void setTimingInterval(int interval)
static void startAnimationTimer(QAbstractAnimationTimer *timer)
qint64 elapsed() const
void maybeUpdateAnimationsToCurrentTime()
void registerProfilerCallback(void(*cb)(qint64))
static void resumeAnimationTimer(QAbstractAnimationTimer *timer)
bool canUninstallAnimationDriver(QAnimationDriver *driver)
Returns true if d is the currently installed animation driver and is not the default animation driver...
void timerEvent(QTimerEvent *) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
~QUnifiedTimer() override
static QUnifiedTimer * instance()
static void pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration)
void uninstallAnimationDriver(QAnimationDriver *driver)
int duration
the duration of the animation
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
direction
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
TimerType
@ CoarseTimer
@ PreciseTimer
@ QueuedConnection
#define DEFAULT_TIMER_INTERVAL
QT_BEGIN_NAMESPACE typedef QList< QAbstractAnimationTimer * >::ConstIterator TimerListConstIt
QList< QAbstractAnimation * >::ConstIterator AnimationListConstIt
#define PAUSE_TIMER_COARSE_THRESHOLD
static Q_CONSTINIT QBasicAtomicInt running
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLenum GLsizei count
GLboolean GLuint group
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
static double elapsed(qint64 after, qint64 before)
#define emit
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
static double currentTime()
QObject::connect nullptr
myObject disconnect()
[26]
QTimer * timer
[3]
QPropertyAnimation animation
[0]
QSizePolicy policy
view create()
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...