24 Q_DISABLE_COPY(QSpringAnimation)
26 QSpringAnimation(QQuickSpringAnimationPrivate * =
nullptr);
29 int duration()
const override;
59 typedef QHash<QQmlProperty, QSpringAnimation*> ActiveAnimationHash;
60 typedef ActiveAnimationHash::Iterator ActiveAnimationHashIt;
62 void clearTemplate() { animationTemplate =
nullptr; }
65 void updateCurrentTime(
int time) override;
66 void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State) override;
67 void debugAnimation(QDebug d)
const override;
70 QQuickSpringAnimationPrivate *animationTemplate;
132QSpringAnimation::~QSpringAnimation()
134 if (animationTemplate) {
135 if (target.object()) {
136 auto it = animationTemplate->activeAnimations.constFind(target);
137 if (it != animationTemplate->activeAnimations.cend() && it.value() ==
this)
138 animationTemplate->activeAnimations.erase(it);
141 for (
auto it = animationTemplate->activeAnimations.cbegin(); it != animationTemplate->activeAnimations.cend(); ++it) {
142 if (it.value() ==
this) {
143 animationTemplate->activeAnimations.erase(it);
173void QSpringAnimation::updateCurrentTime(
int time)
185 int elapsed = time - lastTime;
190 int count = elapsed / 16;
192 if (mode == Spring) {
195 lastTime = time - (elapsed - count * 16);
202 bool stopped =
false;
205 currentValue = fmod(currentValue, modulus);
206 srcVal = fmod(srcVal, modulus);
208 if (mode == Spring) {
211 for (
int i = 0; i < count; ++i) {
212 qreal diff = srcVal - currentValue;
213 if (haveModulus && qAbs(diff) > modulus / 2) {
220 velocity = velocity + (spring * diff - damping * velocity) / mass;
222 velocity = velocity + spring * diff - damping * velocity;
223 if (maxVelocity > 0.) {
225 if (velocity > maxVelocity)
226 velocity = maxVelocity;
227 else if (velocity < -maxVelocity)
228 velocity = -maxVelocity;
230 currentValue += velocity * 16.0 / 1000.0;
232 currentValue = fmod(currentValue, modulus);
233 if (currentValue < 0.0)
234 currentValue += modulus;
237 if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) {
239 currentValue = srcVal;
243 qreal moveBy = elapsed * velocityms;
244 qreal diff = srcVal - currentValue;
245 if (haveModulus && qAbs(diff) > modulus / 2) {
252 currentValue += moveBy;
254 currentValue = std::fmod(currentValue, modulus);
256 currentValue -= moveBy;
257 if (haveModulus && currentValue < 0.0)
258 currentValue = std::fmod(currentValue, modulus) + modulus;
260 if (lastTime - startTime >= dura) {
268 QQmlPropertyPrivate::write(target, currentValue,
269 QQmlPropertyData::BypassInterceptor |
270 QQmlPropertyData::DontRemoveBinding);
272 if (stopped && old_to == to) {
273 if (animationTemplate)
274 stopTime = animationTemplate->elapsed.elapsed();
296 if (spring == 0. && maxVelocity == 0.)
297 mode = QSpringAnimation::Track;
298 else if (spring > 0.)
299 mode = QSpringAnimation::Spring;
301 mode = QSpringAnimation::Velocity;
302 for (QSpringAnimation::ActiveAnimationHashIt it = activeAnimations.begin(), end = activeAnimations.end(); it != end; ++it) {
303 QSpringAnimation *animation = *it;
304 animation->startTime = animation->lastTime;
305 qreal dist = qAbs(animation->currentValue - animation->to);
306 if (haveModulus && dist > modulus / 2)
307 dist = modulus - fmod(dist, modulus);
308 animation->dura = dist / velocityms;
497QAbstractAnimationJob* QQuickSpringAnimation::transition(QQuickStateActions &actions,
498 QQmlProperties &modified,
499 TransitionDirection direction,
500 QObject *defaultTarget)
502 Q_D(QQuickSpringAnimation);
505 QContinuingAnimationGroupJob *wrapperGroup =
new QContinuingAnimationGroupJob();
507 QQuickStateActions dataActions = QQuickNumberAnimation::createTransitionActions(actions, modified, defaultTarget);
508 if (!dataActions.isEmpty()) {
509 QSet<QAbstractAnimationJob*> anims;
510 for (
int i = 0; i < dataActions.size(); ++i) {
511 QSpringAnimation *animation;
512 bool needsRestart =
false;
513 const QQmlProperty &property = dataActions.at(i).property;
514 if (d->activeAnimations.contains(property)) {
515 animation = d->activeAnimations[property];
518 animation =
new QSpringAnimation(d);
519 d->activeAnimations.insert(property, animation);
520 animation->target = property;
522 wrapperGroup->appendAnimation(initInstance(animation));
524 animation->to = dataActions.at(i).toValue.toReal();
525 animation->startTime = 0;
526 animation->velocityms = d->velocityms;
527 animation->mass = d->mass;
528 animation->spring = d->spring;
529 animation->damping = d->damping;
530 animation->epsilon = d->epsilon;
531 animation->modulus = d->modulus;
532 animation->useMass = d->useMass;
533 animation->haveModulus = d->haveModulus;
534 animation->mode = d->mode;
535 animation->dura = -1;
536 animation->maxVelocity = d->maxVelocity;
538 if (d->fromIsDefined)
539 animation->currentValue = dataActions.at(i).fromValue.toReal();
541 animation->currentValue = property.read().toReal();
542 if (animation->mode == QSpringAnimation::Velocity) {
543 qreal dist = qAbs(animation->currentValue - animation->to);
544 if (d->haveModulus && dist > d->modulus / 2)
545 dist = d->modulus - fmod(dist, d->modulus);
546 animation->dura = dist / animation->velocityms;
550 animation->restart();
551 anims.insert(animation);
553 const auto copy = d->activeAnimations;
554 for (QSpringAnimation *anim : copy) {
555 if (!anims.contains(anim)) {
556 anim->clearTemplate();
557 d->activeAnimations.remove(anim->target);