QtBase  v6.3.1
qabstractanimation.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
144 #include "qabstractanimation.h"
145 #include "qanimationgroup.h"
146 
147 #include <QtCore/qdebug.h>
148 
149 #include "qabstractanimation_p.h"
150 
151 #include <QtCore/qmath.h>
152 #include <QtCore/qthreadstorage.h>
153 #include <QtCore/qcoreevent.h>
154 #include <QtCore/qpointer.h>
155 #include <QtCore/qscopedvaluerollback.h>
156 
157 #define DEFAULT_TIMER_INTERVAL 16
158 #define PAUSE_TIMER_COARSE_THRESHOLD 2000
159 
161 
164 
218 
219 QUnifiedTimer::QUnifiedTimer() :
220  QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
221  currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
222  startTimersPending(false), stopTimerPending(false), allowNegativeDelta(false),
223  slowdownFactor(5.0f), profilerCallback(nullptr),
224  driverStartTime(0), temporalDrift(0)
225 {
226  time.invalidate();
227  driver = &defaultDriver;
228 }
229 
230 
232 {
233  QUnifiedTimer *inst;
234  if (create && !unifiedTimer()->hasLocalData()) {
235  inst = new QUnifiedTimer;
236  unifiedTimer()->setLocalData(inst);
237  } else {
238  inst = unifiedTimer() ? unifiedTimer()->localData() : nullptr;
239  }
240  return inst;
241 }
242 
244 {
245  return instance(true);
246 }
247 
249 {
250  if (elapsed() - lastTick > 50)
252 }
253 
255 {
256  if (driver->isRunning())
257  return driverStartTime + driver->elapsed();
258  else if (time.isValid())
259  return time.elapsed() + temporalDrift;
260 
261  // Reaching here would normally indicate that the function is called
262  // under the wrong circumstances as neither pauses nor actual animations
263  // are running and there should be no need to query for elapsed().
264  return 0;
265 }
266 
268 {
269  if (driver->isRunning()) {
270  qWarning("QUnifiedTimer::startAnimationDriver: driver is already running...");
271  return;
272  }
273  // Set the start time to the currently elapsed() value before starting.
274  // This means we get the animation system time including the temporal drift
275  // which is what we want.
276  driverStartTime = elapsed();
277  driver->start();
278 }
279 
281 {
282  if (!driver->isRunning()) {
283  qWarning("QUnifiedTimer::stopAnimationDriver: driver is not running");
284  return;
285  }
286  // Update temporal drift. Since the driver is running, elapsed() will
287  // return the total animation time in driver-time. Subtract the current
288  // wall time to get the delta.
289  temporalDrift = elapsed() - time.elapsed();
290  driver->stop();
291 }
292 
294 {
295  //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
296  if (insideTick)
297  return;
298 
299  const qint64 totalElapsed = elapsed();
300 
301  // ignore consistentTiming in case the pause timer is active
302  qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
303  timingInterval : totalElapsed - lastTick;
304  if (slowMode) {
305  if (slowdownFactor > 0)
306  delta = qRound(delta / slowdownFactor);
307  else
308  delta = 0;
309  }
310 
311  lastTick = totalElapsed;
312 
313  //we make sure we only call update time if the time has actually advanced
314  //* it might happen in some cases that the time doesn't change because events are delayed
315  // when the CPU load is high
316  //* it might happen in some cases that the delta is negative because the animation driver
317  // advances faster than time.elapsed()
318  if (delta != 0 && (allowNegativeDelta || delta > 0)) {
319  QScopedValueRollback<bool> guard(insideTick, true);
320  if (profilerCallback)
321  profilerCallback(delta);
322  for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.count(); ++currentAnimationIdx) {
323  QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx);
324  animation->updateAnimationsTime(delta);
325  }
326  currentAnimationIdx = 0;
327  }
328 }
329 
331 {
332  int count = 0;
333  for (int i = 0; i < animationTimers.count(); ++i)
334  count += animationTimers.at(i)->runningAnimationCount();
335  return count;
336 }
337 
339 {
340  profilerCallback = cb;
341 }
342 
343 void QUnifiedTimer::localRestart()
344 {
345  if (insideRestart)
346  return;
347 
348  if (!pausedAnimationTimers.isEmpty() && (animationTimers.count() + animationTimersToStart.count() == pausedAnimationTimers.count())) {
349  driver->stop();
350  int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish();
351  // use a precise timer if the pause will be short
352  Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer;
353  pauseTimer.start(closestTimeToFinish, timerType, this);
354  } else if (!driver->isRunning()) {
355  if (pauseTimer.isActive())
356  pauseTimer.stop();
358  }
359 
360 }
361 
363 {
364  {
365  QScopedValueRollback<bool> guard(insideRestart, true);
366  for (int i = 0; i < animationTimers.count(); ++i)
367  animationTimers.at(i)->restartAnimationTimer();
368  }
369 
370  localRestart();
371 }
372 
374 {
375  timingInterval = interval;
376 
377  if (driver->isRunning() && !pauseTimer.isActive()) {
378  //we changed the timing interval
381  }
382 }
383 
384 void QUnifiedTimer::startTimers()
385 {
386  startTimersPending = false;
387 
388  //we transfer the waiting animations into the "really running" state
389  animationTimers += animationTimersToStart;
390  animationTimersToStart.clear();
391  if (!animationTimers.isEmpty()) {
392  if (!time.isValid()) {
393  lastTick = 0;
394  time.start();
395  temporalDrift = 0;
396  driverStartTime = 0;
397  }
398  localRestart();
399  }
400 }
401 
402 void QUnifiedTimer::stopTimer()
403 {
404  stopTimerPending = false;
405  if (animationTimers.isEmpty()) {
407  pauseTimer.stop();
408  // invalidate the start reference time
409  time.invalidate();
410  }
411 }
412 
414 {
415  //in the case of consistent timing we make sure the order in which events come is always the same
416  //for that purpose we do as if the startstoptimer would always fire before the animation timer
417  if (consistentTiming) {
418  if (stopTimerPending)
419  stopTimer();
420  if (startTimersPending)
421  startTimers();
422  }
423 
424  if (event->timerId() == pauseTimer.timerId()) {
425  // update current time on all timers
427  restart();
428  }
429 }
430 
432 {
433  if (timer->isRegistered)
434  return;
435  timer->isRegistered = true;
436 
437  QUnifiedTimer *inst = instance(true); //we create the instance if needed
438  inst->animationTimersToStart << timer;
439  if (!inst->startTimersPending) {
440  inst->startTimersPending = true;
441  QMetaObject::invokeMethod(inst, "startTimers", Qt::QueuedConnection);
442  }
443 }
444 
446 {
447  QUnifiedTimer *inst = QUnifiedTimer::instance(false);
448  if (inst) {
449  //at this point the unified timer should have been created
450  //but it might also have been already destroyed in case the application is shutting down
451 
452  if (!timer->isRegistered)
453  return;
454  timer->isRegistered = false;
455 
456  int idx = inst->animationTimers.indexOf(timer);
457  if (idx != -1) {
458  inst->animationTimers.removeAt(idx);
459  // this is needed if we unregister an animation while its running
460  if (idx <= inst->currentAnimationIdx)
461  --inst->currentAnimationIdx;
462 
463  if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) {
464  inst->stopTimerPending = true;
466  }
467  } else {
468  inst->animationTimersToStart.removeOne(timer);
469  }
470  }
471 }
472 
474 {
476  if (!timer->isRegistered)
477  inst->startAnimationTimer(timer);
478 
479  bool timerWasPaused = timer->isPaused;
480  timer->isPaused = true;
481  timer->pauseDuration = duration;
482  if (!timerWasPaused)
483  inst->pausedAnimationTimers << timer;
484  inst->localRestart();
485 }
486 
488 {
489  if (!timer->isPaused)
490  return;
491 
492  timer->isPaused = false;
494  inst->pausedAnimationTimers.removeOne(timer);
495  inst->localRestart();
496 }
497 
498 int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish()
499 {
500  int closestTimeToFinish = INT_MAX;
501  for (TimerListConstIt it = pausedAnimationTimers.constBegin(), cend = pausedAnimationTimers.constEnd(); it != cend; ++it) {
502  const int timeToFinish = (*it)->pauseDuration;
503  if (timeToFinish < closestTimeToFinish)
504  closestTimeToFinish = timeToFinish;
505  }
506  return closestTimeToFinish;
507 }
508 
510 {
511  if (driver != &defaultDriver) {
512  qWarning("QUnifiedTimer: animation driver already installed...");
513  return;
514  }
515 
516  bool running = driver->isRunning();
517  if (running)
519  driver = d;
520  if (driver)
521  allowNegativeDelta = driver->property("allowNegativeDelta").toBool();
522  if (running)
524 }
525 
527 {
528  if (driver != d) {
529  qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
530  return;
531  }
532 
533  bool running = driver->isRunning();
534  if (running)
536  driver = &defaultDriver;
537  allowNegativeDelta = false;
538  if (running)
540 }
541 
547 {
548  return d == driver && driver != &defaultDriver;
549 }
550 
551 #if QT_CONFIG(thread)
553 #endif
554 
555 QAnimationTimer::QAnimationTimer() :
556  QAbstractAnimationTimer(), lastTick(0),
557  currentAnimationIdx(0), insideTick(false),
558  startAnimationPending(false), stopTimerPending(false),
559  runningLeafAnimations(0)
560 {
561 }
562 
564 {
565  QAnimationTimer *inst;
566 #if QT_CONFIG(thread)
567  if (create && !animationTimer()->hasLocalData()) {
568  inst = new QAnimationTimer;
569  animationTimer()->setLocalData(inst);
570  } else {
571  inst = animationTimer() ? animationTimer()->localData() : nullptr;
572  }
573 #else
574  Q_UNUSED(create);
575  static QAnimationTimer animationTimer;
576  inst = &animationTimer;
577 #endif
578  return inst;
579 }
580 
582 {
583  return instance(true);
584 }
585 
587 {
589  QUnifiedTimer *instU = QUnifiedTimer::instance(false);
590  if (instU && inst && inst->isPaused)
591  instU->updateAnimationTimers();
592 }
593 
595 {
596  //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
597  if (insideTick)
598  return;
599 
600  lastTick += delta;
601 
602  //we make sure we only call update time if the time has actually changed
603  //it might happen in some cases that the time doesn't change because events are delayed
604  //when the CPU load is high
605  if (delta) {
606  QScopedValueRollback<bool> guard(insideTick, true);
607  for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
608  QAbstractAnimation *animation = animations.at(currentAnimationIdx);
609  int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
610  + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
611  animation->setCurrentTime(elapsed);
612  }
613  currentAnimationIdx = 0;
614  }
615 }
616 
618 {
620  if (inst)
621  inst->restartAnimationTimer();
622 }
623 
625 {
626  if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
627  QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
628  else if (isPaused)
630  else if (!isRegistered)
632 }
633 
634 void QAnimationTimer::startAnimations()
635 {
636  if (!startAnimationPending)
637  return;
638  startAnimationPending = false;
639 
640  //force timer to update, which prevents large deltas for our newly added animations
642 
643  //we transfer the waiting animations into the "really running" state
644  animations += animationsToStart;
645  animationsToStart.clear();
646  if (!animations.isEmpty())
648 }
649 
650 void QAnimationTimer::stopTimer()
651 {
652  stopTimerPending = false;
653  bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
654  if (animations.isEmpty() && !pendingStart) {
657  // invalidate the start reference time
658  lastTick = 0;
659  }
660 }
661 
663 {
664  QAnimationTimer *inst = instance(true); //we create the instance if needed
665  inst->registerRunningAnimation(animation);
666  if (isTopLevel) {
667  Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
669  inst->animationsToStart << animation;
670  if (!inst->startAnimationPending) {
671  inst->startAnimationPending = true;
672  QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
673  }
674  }
675 }
676 
678 {
680  if (inst) {
681  //at this point the unified timer should have been created
682  //but it might also have been already destroyed in case the application is shutting down
683 
684  inst->unregisterRunningAnimation(animation);
685 
686  if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
687  return;
688 
689  int idx = inst->animations.indexOf(animation);
690  if (idx != -1) {
691  inst->animations.removeAt(idx);
692  // this is needed if we unregister an animation while its running
693  if (idx <= inst->currentAnimationIdx)
694  --inst->currentAnimationIdx;
695 
696  if (inst->animations.isEmpty() && !inst->stopTimerPending) {
697  inst->stopTimerPending = true;
699  }
700  } else {
701  inst->animationsToStart.removeOne(animation);
702  }
703  }
705 }
706 
707 void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation)
708 {
710  return;
711 
713  runningPauseAnimations << animation;
714  } else
715  runningLeafAnimations++;
716 }
717 
718 void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
719 {
721  return;
722 
724  runningPauseAnimations.removeOne(animation);
725  else
726  runningLeafAnimations--;
727  Q_ASSERT(runningLeafAnimations >= 0);
728 }
729 
730 int QAnimationTimer::closestPauseAnimationTimeToFinish()
731 {
732  int closestTimeToFinish = INT_MAX;
733  for (AnimationListConstIt it = runningPauseAnimations.constBegin(), cend = runningPauseAnimations.constEnd(); it != cend; ++it) {
734  const QAbstractAnimation *animation = *it;
735  int timeToFinish;
736 
738  timeToFinish = animation->duration() - animation->currentLoopTime();
739  else
740  timeToFinish = animation->currentLoopTime();
741 
742  if (timeToFinish < closestTimeToFinish)
743  closestTimeToFinish = timeToFinish;
744  }
745  return closestTimeToFinish;
746 }
747 
763 {
764 }
765 
767  : QObject(dd, parent)
768 {
769 }
770 
772 {
774  if (timer && timer->canUninstallAnimationDriver(this))
775  uninstall();
776 }
777 
787 {
789 
790  // update current time on all top level animations
791  instance->updateAnimationTimers();
792  instance->restart();
793 }
794 
795 
796 
803 {
805 }
806 
807 
808 
815 {
817  timer->installAnimationDriver(this);
818 }
819 
820 
821 
827 {
829  timer->uninstallAnimationDriver(this);
830 }
831 
833 {
834  return d_func()->running;
835 }
836 
837 
839 {
840  Q_D(QAnimationDriver);
841  if (!d->running) {
842  d->running = true;
843  d->timer.start();
844  emit started();
845  }
846 }
847 
848 
850 {
851  Q_D(QAnimationDriver);
852  if (d->running) {
853  d->running = false;
854  emit stopped();
855  }
856 }
857 
858 
866 {
867  Q_D(const QAnimationDriver);
868  return d->running ? d->timer.elapsed() : 0;
869 }
870 
893  : QAnimationDriver(nullptr), m_unified_timer(timer)
894 {
895  connect(this, SIGNAL(started()), this, SLOT(startTimer()));
896  connect(this, SIGNAL(stopped()), this, SLOT(stopTimer()));
897 }
898 
900 {
901  Q_ASSERT(e->timerId() == m_timer.timerId());
902  Q_UNUSED(e); // if the assertions are disabled
903  advance();
904 }
905 
906 void QDefaultAnimationDriver::startTimer()
907 {
908  // always use a precise timer to drive animations
909  m_timer.start(m_unified_timer->timingInterval, Qt::PreciseTimer, this);
910 }
911 
912 void QDefaultAnimationDriver::stopTimer()
913 {
914  m_timer.stop();
915 }
916 
918 
919 void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
920 {
921  Q_Q(QAbstractAnimation);
922  if (state == newState)
923  return;
924 
925  if (loopCount == 0)
926  return;
927 
928  QAbstractAnimation::State oldState = state;
929  int oldCurrentTime = currentTime;
930  int oldCurrentLoop = currentLoop;
932 
933  // check if we should Rewind
935  && oldState == QAbstractAnimation::Stopped) {
936  const int oldTotalCurrentTime = totalCurrentTime;
937  //here we reset the time if needed
938  //we don't call setCurrentTime because this might change the way the animation
939  //behaves: changing the state or changing the current value
940  totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
941  0 : (loopCount == -1 ? q->duration() : q->totalDuration());
942  if (totalCurrentTime != oldTotalCurrentTime)
943  totalCurrentTime.notify();
944  }
945 
946  state.setValueBypassingBindings(newState);
948 
949  //(un)registration of the animation must always happen before calls to
950  //virtual function (updateState) to ensure a correct state of the timer
951  bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
952  if (oldState == QAbstractAnimation::Running) {
955  //the animation, is not running any more
957  } else if (newState == QAbstractAnimation::Running) {
959  }
960 
961  q->updateState(newState, oldState);
962  if (!guard || newState != state) //this is to be safe if updateState changes the state
963  return;
964 
965  // Notify state change
966  state.notify();
967  emit q->stateChanged(newState, oldState);
968  if (!guard || newState != state) //this is to be safe if updateState changes the state
969  return;
970 
971  switch (state) {
973  break;
975  {
976 
977  // this ensures that the value is updated now that the animation is running
978  if (oldState == QAbstractAnimation::Stopped) {
979  if (isTopLevel) {
980  // currentTime needs to be updated if pauseTimer is active
982  q->setCurrentTime(totalCurrentTime);
983  }
984  }
985  }
986  break;
988  // Leave running state.
989  int dura = q->duration();
990 
991  if (deleteWhenStopped)
992  q->deleteLater();
993 
994  if (dura == -1 || loopCount < 0
995  || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
996  || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
997  emit q->finished();
998  }
999  break;
1000  }
1001 }
1002 
1011 {
1012  // Allow auto-add on reparent
1013  setParent(parent);
1014 }
1015 
1020  : QObject(dd, nullptr)
1021 {
1022  // Allow auto-add on reparent
1023  setParent(parent);
1024 }
1025 
1032 {
1033  Q_D(QAbstractAnimation);
1034  //we can't call stop here. Otherwise we get pure virtual calls
1035  if (d->state != Stopped) {
1036  QAbstractAnimation::State oldState = d->state;
1037  d->state = Stopped;
1038  d->state.notify();
1039  emit stateChanged(d->state, oldState);
1040  if (oldState == QAbstractAnimation::Running)
1042  }
1043  if (d->group)
1044  d->group->removeAnimation(this);
1045 }
1046 
1061 {
1062  Q_D(const QAbstractAnimation);
1063  return d->state;
1064 }
1065 
1067 {
1068  Q_D(const QAbstractAnimation);
1069  return &d->state;
1070 }
1071 
1079 {
1080  Q_D(const QAbstractAnimation);
1081  return d->group;
1082 }
1083 
1130 {
1131  Q_D(const QAbstractAnimation);
1132  return d->direction;
1133 }
1135 {
1136  Q_D(QAbstractAnimation);
1137  if (d->direction == direction) {
1138  d->direction.removeBindingUnlessInWrapper();
1139  return;
1140  }
1141 
1143  const int oldCurrentLoop = d->currentLoop;
1144  if (state() == Stopped) {
1145  if (direction == Backward) {
1146  d->currentTime = duration();
1147  d->currentLoop = d->loopCount - 1;
1148  } else {
1149  d->currentTime = 0;
1150  d->currentLoop = 0;
1151  }
1152  }
1153 
1154  // the commands order below is important: first we need to setCurrentTime with the old direction,
1155  // then update the direction on this and all children and finally restart the pauseTimer if needed
1156  if (d->hasRegisteredTimer)
1158 
1159  d->direction = direction;
1161 
1162  if (d->hasRegisteredTimer)
1163  // needed to update the timer interval in case of a pause animation
1165 
1166  if (d->currentLoop != oldCurrentLoop)
1167  d->currentLoop.notify();
1168  d->direction.notify();
1170 }
1171 
1173 {
1174  Q_D(QAbstractAnimation);
1175  return &d->direction;
1176 }
1177 
1200 {
1201  Q_D(const QAbstractAnimation);
1202  return d->loopCount;
1203 }
1205 {
1206  Q_D(QAbstractAnimation);
1207  d->loopCount = loopCount;
1208 }
1209 
1211 {
1212  Q_D(QAbstractAnimation);
1213  return &d->loopCount;
1214 }
1215 
1230 {
1231  Q_D(const QAbstractAnimation);
1232  return d->currentLoop;
1233 }
1234 
1236 {
1237  Q_D(const QAbstractAnimation);
1238  return &d->currentLoop;
1239 }
1240 
1266 {
1267  int dura = duration();
1268  if (dura <= 0)
1269  return dura;
1270  int loopcount = loopCount();
1271  if (loopcount < 0)
1272  return -1;
1273  return dura * loopcount;
1274 }
1275 
1283 {
1284  Q_D(const QAbstractAnimation);
1285  return d->currentTime;
1286 }
1287 
1306 {
1307  Q_D(const QAbstractAnimation);
1308  return d->totalCurrentTime;
1309 }
1310 
1312 {
1313  Q_D(QAbstractAnimation);
1314  return &d->totalCurrentTime;
1315 }
1316 
1318 {
1319  Q_D(QAbstractAnimation);
1320  msecs = qMax(msecs, 0);
1321 
1322  // Calculate new time and loop.
1323  int dura = duration();
1324  int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
1325  if (totalDura != -1)
1326  msecs = qMin(totalDura, msecs);
1327 
1328  const int oldCurrentTime = d->totalCurrentTime;
1329  d->totalCurrentTime = msecs;
1330 
1331  // Update new values.
1332  int oldLoop = d->currentLoop;
1333  d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
1334  if (d->currentLoop == d->loopCount) {
1335  //we're at the end
1336  d->currentTime = qMax(0, dura);
1337  d->currentLoop = qMax(0, d->loopCount - 1);
1338  } else {
1339  if (d->direction == Forward) {
1340  d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
1341  } else {
1342  d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
1343  if (d->currentTime == dura)
1344  d->currentLoop = d->currentLoop - 1;
1345  }
1346  }
1347 
1348  updateCurrentTime(d->currentTime);
1349  if (d->currentLoop != oldLoop)
1350  d->currentLoop.notify();
1351 
1352  /* Notify before calling stop: As seen in tst_QSequentialAnimationGroup::clear
1353  * we might delete the animation when stop is called. Thus after stop no member
1354  * of the object must be used anymore.
1355  */
1356  if (oldCurrentTime != d->totalCurrentTime)
1357  d->totalCurrentTime.notify();
1358  // All animations are responsible for stopping the animation when their
1359  // own end state is reached; in this case the animation is time driven,
1360  // and has reached the end.
1361  if ((d->direction == Forward && d->totalCurrentTime == totalDura)
1362  || (d->direction == Backward && d->totalCurrentTime == 0)) {
1363  stop();
1364  }
1365 }
1366 
1384 {
1385  Q_D(QAbstractAnimation);
1386  if (d->state == Running)
1387  return;
1388  d->deleteWhenStopped = policy;
1389  d->setState(Running);
1390 }
1391 
1403 {
1404  Q_D(QAbstractAnimation);
1405 
1406  if (d->state == Stopped)
1407  return;
1408 
1409  d->setState(Stopped);
1410 }
1411 
1420 {
1421  Q_D(QAbstractAnimation);
1422  if (d->state == Stopped) {
1423  qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
1424  return;
1425  }
1426 
1427  d->setState(Paused);
1428 }
1429 
1438 {
1439  Q_D(QAbstractAnimation);
1440  if (d->state != Paused) {
1441  qWarning("QAbstractAnimation::resume: "
1442  "Cannot resume an animation that is not paused");
1443  return;
1444  }
1445 
1446  d->setState(Running);
1447 }
1448 
1456 {
1457  if (paused)
1458  pause();
1459  else
1460  resume();
1461 }
1462 
1463 
1468 {
1469  return QObject::event(event);
1470 }
1471 
1488  QAbstractAnimation::State oldState)
1489 {
1490  Q_UNUSED(oldState);
1491  Q_UNUSED(newState);
1492 }
1493 
1501 {
1503 }
1504 
1505 
1507 
1508 #include "moc_qabstractanimation.cpp"
1509 #include "moc_qabstractanimation_p.cpp"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
FT_UInt idx
Definition: cffcmap.c:135
The QAbstractAnimation class is the base of all animations.
State state
state of the animation.
Direction direction
the direction of the animation when it is in \l Running state.
QBindable< Direction > bindableDirection()
virtual void updateCurrentTime(int currentTime)=0
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
bool event(QEvent *event) override
int loopCount
the loop count of the animation
QAbstractAnimation(QObject *parent=nullptr)
void setLoopCount(int loopCount)
QBindable< int > bindableCurrentLoop() const
void setDirection(Direction direction)
int currentLoop
the current loop of the animation
virtual void updateDirection(QAbstractAnimation::Direction direction)
int currentTime
the current time and progress of the animation
void setCurrentTime(int msecs)
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
QBindable< QAbstractAnimation::State > bindableState() const
QBindable< int > bindableCurrentTime()
void stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
QBindable< int > bindableLoopCount()
QAnimationGroup * group() const
int duration
the duration of the animation.
static QAbstractAnimationPrivate * get(QAbstractAnimation *q)
QAbstractAnimationTimer is the base class for animation timers.
virtual void restartAnimationTimer()=0
virtual int runningAnimationCount()=0
The QAnimationDriver class is used to exchange the mechanism that drives animations.
virtual qint64 elapsed() const
virtual void advance()
QAnimationDriver(QObject *parent=nullptr)
The QAnimationGroup class is an abstract base class for groups of animations.
static void unregisterAnimation(QAbstractAnimation *animation)
static void updateAnimationTimer()
void updateAnimationsTime(qint64 delta) override
void restartAnimationTimer() override
static void ensureTimerUpdate()
static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
static QAnimationTimer * instance()
void start(int msec, QObject *obj)
int timerId() const noexcept
Definition: qbasictimer.h:69
bool isActive() const noexcept
Definition: qbasictimer.h:68
QBindable is a wrapper class around binding-enabled properties. It allows type-safe operations while ...
Definition: qproperty.h:753
QDefaultAnimationDriver(QUnifiedTimer *timer)
void timerEvent(QTimerEvent *e) override
void invalidate() noexcept
qint64 elapsed() const noexcept
void start() noexcept
bool isValid() const noexcept
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
void removeAt(qsizetype i)
Definition: qlist.h:588
bool removeOne(const AT &t)
Definition: qlist.h:596
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
const_iterator constBegin() const noexcept
Definition: qlist.h:630
qsizetype count() const noexcept
Definition: qlist.h:415
const_iterator constEnd() const noexcept
Definition: qlist.h:631
void clear()
Definition: qlist.h:445
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
void setParent(QObject *parent)
Definition: qobject.cpp:2108
QVariant property(const char *name) const
Definition: qobject.cpp:4118
The QPointer class is a template class that provides guarded pointers to QObject.
Definition: qpointer.h:54
The QScopedValueRollback class resets a variable to its previous value on destruction.
The QThreadStorage class provides per-thread data storage.
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:367
QUnifiedTimer provides a unified timing mechanism for animations in Qt C++ and QML.
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)
void timerEvent(QTimerEvent *) 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
Definition: qvariant.cpp:1906
#define this
Definition: dialogs.cpp:56
double e
direction
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
const PluginKeyMapConstIterator cend
TimerType
Definition: qnamespace.h:1689
@ CoarseTimer
Definition: qnamespace.h:1691
@ PreciseTimer
Definition: qnamespace.h:1690
Q_CORE_EXPORT void beginPropertyUpdateGroup()
@ QueuedConnection
Definition: qnamespace.h:1307
Q_CORE_EXPORT void endPropertyUpdateGroup()
#define DEFAULT_TIMER_INTERVAL
QT_BEGIN_NAMESPACE typedef QList< QAbstractAnimationTimer * >::ConstIterator TimerListConstIt
QList< QAbstractAnimation * >::ConstIterator AnimationListConstIt
#define PAUSE_TIMER_COARSE_THRESHOLD
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
long long qint64
Definition: qglobal.h:298
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition: qlogging.h:179
#define SLOT(a)
Definition: qobjectdefs.h:87
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLenum GLenum GLsizei count
GLboolean GLuint group
struct _cl_event * event
Definition: qopenglext.h:2998
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define emit
Definition: qtmetamacros.h:85
Q_UNUSED(salary)
[21]
QPropertyAnimation * animation
[0]
QObject::connect nullptr
QTimer * timer
[3]
QTime time
[5]
QSizePolicy policy
view create()
QStringList::Iterator it
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition: qlist.h:966
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())
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent