9#include <private/qqmlproperty_p.h>
10#if QT_CONFIG(quick_path)
11#include <private/qquickpath_p.h>
13#include "private/qparallelanimationgroupjob_p.h"
14#include "private/qsequentialanimationgroupjob_p.h"
16#include <QtCore/qmath.h>
17#include <QtGui/qtransform.h>
18#include <QtQml/qqmlinfo.h>
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56QQuickParentAnimation::QQuickParentAnimation(QObject *parent)
57 : QQuickAnimationGroup(*(
new QQuickParentAnimationPrivate), parent)
62
63
64
65
66
67
68QQuickItem *QQuickParentAnimation::target()
const
70 Q_D(
const QQuickParentAnimation);
74void QQuickParentAnimation::setTargetObject(QQuickItem *target)
76 Q_D(QQuickParentAnimation);
77 if (target == d->target)
85
86
87
88
89
90
91
92QQuickItem *QQuickParentAnimation::newParent()
const
94 Q_D(
const QQuickParentAnimation);
98void QQuickParentAnimation::setNewParent(QQuickItem *newParent)
100 Q_D(QQuickParentAnimation);
101 if (newParent == d->newParent)
104 d->newParent = newParent;
105 emit newParentChanged();
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124QQuickItem *QQuickParentAnimation::via()
const
126 Q_D(
const QQuickParentAnimation);
130void QQuickParentAnimation::setVia(QQuickItem *via)
132 Q_D(QQuickParentAnimation);
145 case QQuickItem::TopLeft:
146 return QPointF(0, 0);
147 case QQuickItem::Top:
148 return QPointF(width / 2., 0);
149 case QQuickItem::TopRight:
150 return QPointF(width, 0);
151 case QQuickItem::Left:
152 return QPointF(0, height / 2.);
153 case QQuickItem::Center:
154 return QPointF(width / 2., height / 2.);
155 case QQuickItem::Right:
156 return QPointF(width, height / 2.);
157 case QQuickItem::BottomLeft:
158 return QPointF(0, height);
159 case QQuickItem::Bottom:
160 return QPointF(width / 2., height);
161 case QQuickItem::BottomRight:
162 return QPointF(width, height);
177 for (
int ii = 0; ii < actions.size(); ++ii) {
178 const QQuickStateAction &action = actions.at(ii);
180 action.event->reverse();
182 action.event->execute();
187QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions,
188 QQmlProperties &modified,
189 TransitionDirection direction,
190 QObject *defaultTarget)
192 Q_D(QQuickParentAnimation);
194 std::unique_ptr<QQuickParentAnimationData> data(
new QQuickParentAnimationData);
195 std::unique_ptr<QQuickParentAnimationData> viaData(
new QQuickParentAnimationData);
197 bool hasExplicit =
false;
198 if (d->target && d->newParent) {
199 data->reverse =
false;
200 QQuickStateAction myAction;
201 QQuickParentChange *pc =
new QQuickParentChange;
202 pc->setObject(d->target);
203 pc->setParent(d->newParent);
206 data->actions << myAction;
209 viaData->reverse =
false;
210 QQuickStateAction myVAction;
211 QQuickParentChange *vpc =
new QQuickParentChange;
212 vpc->setObject(d->target);
213 vpc->setParent(d->via);
214 myVAction.event = vpc;
216 viaData->actions << myVAction;
223 for (
int i = 0; i < actions.size(); ++i) {
224 QQuickStateAction &action = actions[i];
225 if (action.event && action.event->type() == QQuickStateActionEvent::ParentChange
226 && (!d->target ||
static_cast<QQuickParentChange*>(action.event)->object() == d->target)) {
228 QQuickParentChange *pc =
static_cast<QQuickParentChange*>(action.event);
229 QQuickStateAction myAction = action;
230 data->reverse = action.reverseEvent;
235 QQuickParentChange *epc =
new QQuickParentChange;
236 epc->setObject(
static_cast<QQuickParentChange*>(action.event)->object());
237 epc->setParent(d->newParent);
238 myAction.event = epc;
240 data->actions << myAction;
243 action.actionDone =
true;
244 data->actions << myAction;
248 viaData->reverse =
false;
249 QQuickStateAction myAction;
250 QQuickParentChange *vpc =
new QQuickParentChange;
251 vpc->setObject(pc->object());
252 vpc->setParent(d->via);
253 myAction.event = vpc;
255 viaData->actions << myAction;
256 QQuickStateAction dummyAction;
257 QQuickStateAction &xAction = pc->xIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
258 QQuickStateAction &yAction = pc->yIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
259 QQuickStateAction &sAction = pc->scaleIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
260 QQuickStateAction &rAction = pc->rotationIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
261 QQuickItem *target = pc->object();
262 QQuickItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent();
266 const QTransform &transform = targetParent->itemTransform(d->via, &ok);
267 if (transform.type() >= QTransform::TxShear || !ok) {
268 qmlWarning(
this) << QQuickParentAnimation::tr(
"Unable to preserve appearance under complex transform");
274 bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
275 if (ok && !isRotate) {
276 if (transform.m11() == transform.m22())
277 scale = transform.m11();
279 qmlWarning(
this) << QQuickParentAnimation::tr(
"Unable to preserve appearance under non-uniform scale");
282 }
else if (ok && isRotate) {
283 if (transform.m11() == transform.m22())
284 scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
286 qmlWarning(
this) << QQuickParentAnimation::tr(
"Unable to preserve appearance under non-uniform scale");
291 rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale));
293 qmlWarning(
this) << QQuickParentAnimation::tr(
"Unable to preserve appearance under scale of 0");
298 const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal()));
301 if (ok && target->transformOrigin() != QQuickItem::TopLeft) {
302 qreal w = target->width();
303 qreal h = target->height();
304 if (pc->widthIsSet() && i < actions.size() - 1)
305 w = actions.at(++i).toValue.toReal();
306 if (pc->heightIsSet() && i < actions.size() - 1)
307 h = actions.at(++i).toValue.toReal();
308 const QPointF &transformOrigin
309 = d->computeTransformOrigin(target->transformOrigin(), w,h);
310 qreal tempxt = transformOrigin.x();
311 qreal tempyt = transformOrigin.y();
313 t.translate(-tempxt, -tempyt);
315 t.scale(scale, scale);
316 t.translate(tempxt, tempyt);
317 const QPointF &offset = t.map(QPointF(0,0));
326 sAction.toValue = sAction.toValue.toReal() * scale;
327 rAction.toValue = rAction.toValue.toReal() + rotation;
333 if (data->actions.size()) {
334 QSequentialAnimationGroupJob *topLevelGroup =
new QSequentialAnimationGroupJob;
335 QActionAnimation *viaAction = d->via ?
new QActionAnimation :
nullptr;
336 QActionAnimation *targetAction =
new QActionAnimation;
338 QParallelAnimationGroupJob *ag =
new QParallelAnimationGroupJob;
341 viaAction->setAnimAction(viaData.release());
342 targetAction->setAnimAction(data.release());
345 bool valid = d->defaultProperty.isValid();
346 QAbstractAnimationJob* anim;
347 for (
int ii = 0; ii < d->animations.size(); ++ii) {
349 d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
350 anim = d->animations.at(ii)->transition(actions, modified, direction, defaultTarget);
352 ag->appendAnimation(anim);
356 bool forwards = direction == QQuickAbstractAnimation::Forward;
358 topLevelGroup->appendAnimation(d->via ? viaAction : targetAction);
359 topLevelGroup->appendAnimation(ag);
361 topLevelGroup->appendAnimation(targetAction);
364 topLevelGroup->appendAnimation(targetAction);
365 topLevelGroup->appendAnimation(ag);
366 topLevelGroup->appendAnimation(d->via ? viaAction : targetAction);
368 return initInstance(topLevelGroup);
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398QQuickAnchorAnimation::QQuickAnchorAnimation(QObject *parent)
399: QQuickAbstractAnimation(*(
new QQuickAnchorAnimationPrivate), parent)
404
405
406
407
408
409
410QQmlListProperty<QQuickItem> QQuickAnchorAnimation::targets()
412 Q_D(QQuickAnchorAnimation);
413 return QQmlListProperty<QQuickItem>(
this, &(d->targets));
417
418
419
420
421
422int QQuickAnchorAnimation::duration()
const
424 Q_D(
const QQuickAnchorAnimation);
428void QQuickAnchorAnimation::setDuration(
int duration)
431 qmlWarning(
this) << tr(
"Cannot set a duration of < 0");
435 Q_D(QQuickAnchorAnimation);
436 if (d->duration == duration)
438 d->duration = duration;
439 emit durationChanged(duration);
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461QEasingCurve QQuickAnchorAnimation::easing()
const
463 Q_D(
const QQuickAnchorAnimation);
467void QQuickAnchorAnimation::setEasing(
const QEasingCurve &e)
469 Q_D(QQuickAnchorAnimation);
474 emit easingChanged(e);
477QAbstractAnimationJob* QQuickAnchorAnimation::transition(QQuickStateActions &actions,
478 QQmlProperties &modified,
479 TransitionDirection direction,
480 QObject *defaultTarget)
483 Q_UNUSED(defaultTarget);
484 Q_D(QQuickAnchorAnimation);
485 QQuickAnimationPropertyUpdater *data =
new QQuickAnimationPropertyUpdater;
486 data->interpolatorType = QMetaType::QReal;
487 data->interpolator = d->interpolator;
488 data->reverse = direction == Backward ?
true :
false;
489 data->fromIsSourced =
false;
490 data->fromIsDefined =
false;
492 for (
int ii = 0; ii < actions.size(); ++ii) {
493 QQuickStateAction &action = actions[ii];
494 if (action.event && action.event->type() == QQuickStateActionEvent::AnchorChanges
495 && (d->targets.isEmpty() || d->targets.contains(
static_cast<QQuickAnchorChanges*>(action.event)->object()))) {
496 data->actions <<
static_cast<QQuickAnchorChanges*>(action.event)->additionalActions();
500 QQuickBulkValueAnimator *animator =
new QQuickBulkValueAnimator;
501 if (data->actions.size()) {
502 animator->setAnimValue(data);
503 animator->setFromIsSourcedValue(&data->fromIsSourced);
508 animator->setDuration(d->duration);
509 animator->setEasingCurve(d->easing);
510 return initInstance(animator);
514#if QT_CONFIG(quick_path)
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541QQuickPathAnimation::QQuickPathAnimation(QObject *parent)
542: QQuickAbstractAnimation(*(
new QQuickPathAnimationPrivate), parent)
546QQuickPathAnimation::~QQuickPathAnimation()
548 typedef QHash<QQuickItem*, QQuickPathAnimationAnimator* >::iterator ActiveAnimationsIt;
550 Q_D(QQuickPathAnimation);
551 for (ActiveAnimationsIt it = d->activeAnimations.begin(), end = d->activeAnimations.end(); it != end; ++it)
552 it.value()->clearTemplate();
556
557
558
559
560
561int QQuickPathAnimation::duration()
const
563 Q_D(
const QQuickPathAnimation);
567void QQuickPathAnimation::setDuration(
int duration)
570 qmlWarning(
this) << tr(
"Cannot set a duration of < 0");
574 Q_D(QQuickPathAnimation);
575 if (d->duration == duration)
577 d->duration = duration;
578 emit durationChanged(duration);
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596QEasingCurve QQuickPathAnimation::easing()
const
598 Q_D(
const QQuickPathAnimation);
599 return d->easingCurve;
602void QQuickPathAnimation::setEasing(
const QEasingCurve &e)
604 Q_D(QQuickPathAnimation);
605 if (d->easingCurve == e)
609 emit easingChanged(e);
613
614
615
616
617
618QQuickPath *QQuickPathAnimation::path()
const
620 Q_D(
const QQuickPathAnimation);
624void QQuickPathAnimation::setPath(QQuickPath *path)
626 Q_D(QQuickPathAnimation);
635
636
637
638QQuickItem *QQuickPathAnimation::target()
const
640 Q_D(
const QQuickPathAnimation);
644void QQuickPathAnimation::setTargetObject(QQuickItem *target)
646 Q_D(QQuickPathAnimation);
647 if (d->target == target)
651 emit targetChanged();
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670QQuickPathAnimation::Orientation QQuickPathAnimation::orientation()
const
672 Q_D(
const QQuickPathAnimation);
673 return d->orientation;
676void QQuickPathAnimation::setOrientation(Orientation orientation)
678 Q_D(QQuickPathAnimation);
679 if (d->orientation == orientation)
682 d->orientation = orientation;
683 emit orientationChanged(d->orientation);
687
688
689
690
691
692
693
694
695QPointF QQuickPathAnimation::anchorPoint()
const
697 Q_D(
const QQuickPathAnimation);
698 return d->anchorPoint;
701void QQuickPathAnimation::setAnchorPoint(
const QPointF &point)
703 Q_D(QQuickPathAnimation);
704 if (d->anchorPoint == point)
707 d->anchorPoint = point;
708 emit anchorPointChanged(point);
712
713
714
715
716
717
718
719
720int QQuickPathAnimation::orientationEntryDuration()
const
722 Q_D(
const QQuickPathAnimation);
723 return d->entryDuration;
726void QQuickPathAnimation::setOrientationEntryDuration(
int duration)
728 Q_D(QQuickPathAnimation);
729 if (d->entryDuration == duration)
731 d->entryDuration = duration;
732 emit orientationEntryDurationChanged(duration);
736
737
738
739
740
741
742
743int QQuickPathAnimation::orientationExitDuration()
const
745 Q_D(
const QQuickPathAnimation);
746 return d->exitDuration;
749void QQuickPathAnimation::setOrientationExitDuration(
int duration)
751 Q_D(QQuickPathAnimation);
752 if (d->exitDuration == duration)
754 d->exitDuration = duration;
755 emit orientationExitDurationChanged(duration);
759
760
761
762
763
764
765
766
767
768
769
770
771qreal QQuickPathAnimation::endRotation()
const
773 Q_D(
const QQuickPathAnimation);
774 return d->endRotation.isValid() ? d->endRotation.value() : qreal(0);
777void QQuickPathAnimation::setEndRotation(qreal rotation)
779 Q_D(QQuickPathAnimation);
780 if (d->endRotation.isValid() && d->endRotation == rotation)
783 d->endRotation = rotation;
784 emit endRotationChanged(d->endRotation);
787QAbstractAnimationJob* QQuickPathAnimation::transition(QQuickStateActions &actions,
788 QQmlProperties &modified,
789 TransitionDirection direction,
790 QObject *defaultTarget)
792 Q_D(QQuickPathAnimation);
794 QQuickItem *target = d->target ? d->target : qobject_cast<QQuickItem*>(defaultTarget);
796 QQuickPathAnimationUpdater prevData;
797 bool havePrevData =
false;
798 if (d->activeAnimations.contains(target)) {
800 prevData = *d->activeAnimations[target]->pathUpdater();
803 for (
auto it = d->activeAnimations.begin(); it != d->activeAnimations.end();) {
804 QQuickPathAnimationAnimator *anim = it.value();
805 if (anim->state() == QAbstractAnimationJob::Stopped) {
806 anim->clearTemplate();
807 it = d->activeAnimations.erase(it);
813 QQuickPathAnimationUpdater *data =
new QQuickPathAnimationUpdater();
814 QQuickPathAnimationAnimator *pa =
new QQuickPathAnimationAnimator(d);
816 d->activeAnimations[target] = pa;
818 data->orientation = d->orientation;
819 data->anchorPoint = d->anchorPoint;
820 data->entryInterval = d->duration ? qreal(d->entryDuration) / d->duration : qreal(0);
821 data->exitInterval = d->duration ? qreal(d->exitDuration) / d->duration : qreal(0);
822 data->endRotation = d->endRotation;
823 data->reverse = direction == Backward ?
true :
false;
824 data->fromIsSourced =
false;
825 data->fromIsDefined = (d->path && d->path->hasStartX() && d->path->hasStartY()) ?
true :
false;
826 data->toIsDefined = d->path ?
true :
false;
827 int origModifiedSize = modified.size();
829 for (
int i = 0; i < actions.size(); ++i) {
830 QQuickStateAction &action = actions[i];
833 if (action.specifiedObject == target && action.property.name() == QLatin1String(
"x")) {
834 data->toX = action.toValue.toReal();
835 modified << action.property;
836 action.fromValue = action.toValue;
838 if (action.specifiedObject == target && action.property.name() == QLatin1String(
"y")) {
839 data->toY = action.toValue.toReal();
840 modified << action.property;
841 action.fromValue = action.toValue;
845 if (target && d->path && (modified.size() > origModifiedSize || data->toIsDefined)) {
846 data->target = target;
847 data->path = d->path;
848 data->path->invalidateSequentialHistory();
852 data->startRotation = prevData.startRotation;
855 if ((data->reverse || prevData.reverse) && prevData.currentV > 0 && prevData.currentV < 1) {
856 if (!data->fromIsDefined && !data->toIsDefined && !prevData.painterPath.isEmpty()) {
857 QPointF pathPos = QQuickPath::sequentialPointAt(prevData.painterPath, prevData.pathLength, prevData.attributePoints, prevData.prevBez, prevData.currentV);
858 if (!prevData.anchorPoint.isNull())
859 pathPos -= prevData.anchorPoint;
860 if (pathPos == data->target->position()) {
861 data->painterPath = prevData.painterPath;
862 data->toIsDefined = data->fromIsDefined = data->fromIsSourced =
true;
863 data->prevBez.isValid =
false;
864 data->interruptStart = prevData.currentV;
865 data->startRotation = prevData.startRotation;
866 data->pathLength = prevData.pathLength;
867 data->attributePoints = prevData.attributePoints;
872 pa->setFromIsSourcedValue(&data->fromIsSourced);
873 pa->setAnimValue(data);
874 pa->setDuration(d->duration);
875 pa->setEasingCurve(d->easingCurve);
876 return initInstance(pa);
878 pa->setFromIsSourcedValue(
nullptr);
879 pa->setAnimValue(
nullptr);
886void QQuickPathAnimationUpdater::setValue(qreal v)
888 v = qMin(qMax(v, (qreal)0.0), (qreal)1.0);;
890 if (interruptStart.isValid()) {
893 qreal end = reverse ? 0.0 : 1.0;
894 v = interruptStart + v * (end-interruptStart);
897 bool atStart = ((reverse && v == 1.0) || (!reverse && v == 0.0));
898 if (!fromIsSourced && (!fromIsDefined || !toIsDefined)) {
899 qreal startX = reverse ? toX + anchorPoint.x() : target->x() + anchorPoint.x();
900 qreal startY = reverse ? toY + anchorPoint.y() : target->y() + anchorPoint.y();
901 qreal endX = reverse ? target->x() + anchorPoint.x() : toX + anchorPoint.x();
902 qreal endY = reverse ? target->y() + anchorPoint.y() : toY + anchorPoint.y();
904 prevBez.isValid =
false;
905 painterPath = path->createPath(QPointF(startX, startY), QPointF(endX, endY), QStringList(), pathLength, attributePoints);
906 fromIsSourced =
true;
910 bool fixed = orientation == QQuickPathAnimation::Fixed;
911 QPointF currentPos = !painterPath.isEmpty() ? path->sequentialPointAt(painterPath, pathLength, attributePoints, prevBez, v, fixed ?
nullptr : &angle) : path->sequentialPointAt(v, fixed ?
nullptr : &angle);
914 if (!anchorPoint.isNull()) {
915 currentPos -= anchorPoint;
917 if (!anchorPoint.isNull() && !fixed)
918 target->setTransformOriginPoint(anchorPoint);
922 target->setPosition(currentPos);
926 switch (orientation) {
927 case QQuickPathAnimation::RightFirst:
930 case QQuickPathAnimation::TopFirst:
933 case QQuickPathAnimation::LeftFirst:
934 angle = -angle + 180;
936 case QQuickPathAnimation::BottomFirst:
937 angle = -angle + 270;
944 if (atStart && !reverse) {
945 startRotation = target->rotation();
948 qreal diff = angle - startRotation;
949 while (diff > 180.0) {
950 startRotation = startRotation.value() + 360.0;
953 while (diff < -180.0) {
954 startRotation = startRotation.value() - 360.0;
961 if (startRotation.isValid()) {
962 if (reverse && v == 0.0)
963 angle = startRotation;
964 else if (v < entryInterval)
965 angle = angle * v / entryInterval + startRotation * (entryInterval - v) / entryInterval;
967 if (endRotation.isValid()) {
968 qreal exitStart = 1 - entryInterval;
969 if (!reverse && v == 1.0)
971 else if (v > exitStart)
972 angle = endRotation * (v - exitStart) / exitInterval + angle * (exitInterval - (v - exitStart)) / exitInterval;
974 target->setRotation(angle);
978
979
980
981
982
983 if ((reverse && v == 0.0) || (!reverse && v == 1.0)) {
984 if (!anchorPoint.isNull() && !fixed && qFuzzyIsNull(angle))
985 target->setTransformOriginPoint(QPointF());
989QQuickPathAnimationAnimator::QQuickPathAnimationAnimator(QQuickPathAnimationPrivate *priv)
990 : animationTemplate(priv)
994QQuickPathAnimationAnimator::~QQuickPathAnimationAnimator()
996 if (animationTemplate && pathUpdater()) {
997 auto it = animationTemplate->activeAnimations.constFind(pathUpdater()->target);
998 if (it != animationTemplate->activeAnimations.cend() && it.value() ==
this)
999 animationTemplate->activeAnimations.erase(it);
1007#include "moc_qquickitemanimation_p.cpp"
QPointF computeTransformOrigin(QQuickItem::TransformOrigin origin, qreal width, qreal height) const
QList< QQuickParentChange * > pc
QQuickStateActions actions
~QQuickParentAnimationData()
QQuickParentAnimationData()