From 3218d437a13ac82f65abcea0db099f54504c8875 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 22 Feb 2010 17:27:11 +1000 Subject: Add ParentAnimation. ParentAnimation will replace ParentAction. It provides two advantages: * It will animate correctly when reversed. * It allows reparenting via another item, which is useful in the presence of clips, for example. --- src/declarative/util/qdeclarativeanimation.cpp | 242 ++++++++++++++++++++- src/declarative/util/qdeclarativeanimation_p.h | 31 +++ src/declarative/util/qdeclarativeanimation_p_p.h | 28 ++- .../util/qdeclarativestateoperations.cpp | 159 +++++++++++++- .../util/qdeclarativestateoperations_p.h | 32 +++ src/declarative/util/qdeclarativeutilmodule.cpp | 1 + 6 files changed, 486 insertions(+), 7 deletions(-) diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index 264b88c..8af8fc2 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include @@ -360,9 +361,6 @@ void QDeclarativeAbstractAnimation::setGroup(QDeclarativeAnimationGroup *g) if (d->group && !static_cast(d->group->d_func())->animations.contains(this)) static_cast(d->group->d_func())->animations.append(this); - if (d->group) - ((QAnimationGroup*)d->group->qtAnimation())->addAnimation(qtAnimation()); - //if (g) //if removed from a group, then the group should no longer be the parent setParent(g); } @@ -1517,6 +1515,7 @@ void QDeclarativeAnimationGroupPrivate::append_animation(QDeclarativeListPropert if (q) { q->d_func()->animations.append(a); a->setGroup(q); + q->d_func()->ag->addAnimation(a->qtAnimation()); } } @@ -2368,4 +2367,241 @@ void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions +QDeclarativeParentAnimation::QDeclarativeParentAnimation(QObject *parent) + : QDeclarativeAnimationGroup(parent) +{ + Q_D(QDeclarativeParentAnimation); + d->topLevelGroup = new QSequentialAnimationGroup; + QDeclarativeGraphics_setParent_noEvent(d->topLevelGroup, this); + + d->startAction = new QActionAnimation; + d->topLevelGroup->addAnimation(d->startAction); + + d->ag = new QParallelAnimationGroup; + d->topLevelGroup->addAnimation(d->ag); + + d->endAction = new QActionAnimation; + d->topLevelGroup->addAnimation(d->endAction); +} + +QDeclarativeParentAnimation::~QDeclarativeParentAnimation() +{ +} + +QDeclarativeItem *QDeclarativeParentAnimation::target() const +{ + Q_D(const QDeclarativeParentAnimation); + return d->target; +} + +void QDeclarativeParentAnimation::setTarget(QDeclarativeItem *target) +{ + Q_D(QDeclarativeParentAnimation); + d->target = target; +} + +QDeclarativeItem *QDeclarativeParentAnimation::newParent() const +{ + Q_D(const QDeclarativeParentAnimation); + return d->newParent; +} + +void QDeclarativeParentAnimation::setNewParent(QDeclarativeItem *newParent) +{ + Q_D(QDeclarativeParentAnimation); + d->newParent = newParent; +} + +QDeclarativeItem *QDeclarativeParentAnimation::via() const +{ + Q_D(const QDeclarativeParentAnimation); + return d->via; +} + +void QDeclarativeParentAnimation::setVia(QDeclarativeItem *via) +{ + Q_D(QDeclarativeParentAnimation); + d->via = via; +} + +//### mirrors same-named function in QDeclarativeItem +QPointF QDeclarativeParentAnimationPrivate::computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const +{ + switch(origin) { + default: + case QDeclarativeItem::TopLeft: + return QPointF(0, 0); + case QDeclarativeItem::Top: + return QPointF(width / 2., 0); + case QDeclarativeItem::TopRight: + return QPointF(width, 0); + case QDeclarativeItem::Left: + return QPointF(0, height / 2.); + case QDeclarativeItem::Center: + return QPointF(width / 2., height / 2.); + case QDeclarativeItem::Right: + return QPointF(width, height / 2.); + case QDeclarativeItem::BottomLeft: + return QPointF(0, height); + case QDeclarativeItem::Bottom: + return QPointF(width / 2., height); + case QDeclarativeItem::BottomRight: + return QPointF(width, height); + } +} + +void QDeclarativeParentAnimation::transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction) +{ + Q_D(QDeclarativeParentAnimation); + + struct QDeclarativeParentActionData : public QAbstractAnimationAction + { + QDeclarativeParentActionData(): pc(0) {} + ~QDeclarativeParentActionData() { delete pc; } + + QDeclarativeStateActions actions; + bool reverse; + QDeclarativeParentChange *pc; + virtual void doAction() + { + for (int ii = 0; ii < actions.count(); ++ii) { + const QDeclarativeAction &action = actions.at(ii); + if (reverse) + action.event->reverse(); + else + action.event->execute(); + } + } + }; + + QDeclarativeParentActionData *data = new QDeclarativeParentActionData; + QDeclarativeParentActionData *viaData = new QDeclarativeParentActionData; + for (int i = 0; i < actions.size(); ++i) { + QDeclarativeAction &action = actions[i]; + if (action.event && action.event->typeName() == QLatin1String("ParentChange") + && (!d->target || static_cast(action.event)->object() == d->target)) { + + QDeclarativeParentChange *pc = static_cast(action.event); + QDeclarativeAction myAction = action; + data->reverse = action.reverseEvent; + action.actionDone = true; + data->actions << myAction; + + if (d->via) { + viaData->reverse = false; + QDeclarativeAction myAction; + QDeclarativeParentChange *vpc = new QDeclarativeParentChange; + vpc->setObject(pc->object()); + vpc->setParent(d->via); + myAction.event = vpc; + viaData->pc = vpc; + viaData->actions << myAction; + QDeclarativeAction dummyAction; + QDeclarativeAction &xAction = pc->xIsSet() ? actions[++i] : dummyAction; + QDeclarativeAction &yAction = pc->yIsSet() ? actions[++i] : dummyAction; + QDeclarativeAction &sAction = pc->scaleIsSet() ? actions[++i] : dummyAction; + QDeclarativeAction &rAction = pc->rotationIsSet() ? actions[++i] : dummyAction; + bool forward = (direction == QDeclarativeAbstractAnimation::Forward); + QDeclarativeItem *target = pc->object(); + QDeclarativeItem *targetParent = forward ? pc->parent() : pc->originalParent(); + + //### this mirrors the logic in QDeclarativeParentChange. + bool ok; + const QTransform &transform = targetParent->itemTransform(d->via, &ok); + if (transform.type() >= QTransform::TxShear || !ok) { + qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under complex transform"); + ok = false; + } + + qreal scale = 1; + qreal rotation = 0; + if (ok && transform.type() != QTransform::TxRotate) { + if (transform.m11() == transform.m22()) + scale = transform.m11(); + else { + qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under non-uniform scale"); + ok = false; + } + } else if (ok && transform.type() == QTransform::TxRotate) { + if (transform.m11() == transform.m22()) + scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12()); + else { + qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under non-uniform scale"); + ok = false; + } + + if (scale != 0) + rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; + else { + qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under scale of 0"); + ok = false; + } + } + + const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal())); + qreal x = point.x(); + qreal y = point.y(); + if (ok && target->transformOrigin() != QDeclarativeItem::TopLeft) { + qreal w = target->width(); + qreal h = target->height(); + if (pc->widthIsSet()) + w = actions[++i].toValue.toReal(); + if (pc->heightIsSet()) + h = actions[++i].toValue.toReal(); + const QPointF &transformOrigin + = d->computeTransformOrigin(target->transformOrigin(), w,h); + qreal tempxt = transformOrigin.x(); + qreal tempyt = transformOrigin.y(); + QTransform t; + t.translate(-tempxt, -tempyt); + t.rotate(rotation); + t.scale(scale, scale); + t.translate(tempxt, tempyt); + const QPointF &offset = t.map(QPointF(0,0)); + x += offset.x(); + y += offset.y(); + } + + if (ok) { + //qDebug() << x << y << rotation << scale; + xAction.toValue = x; + yAction.toValue = y; + sAction.toValue = sAction.toValue.toReal() * scale; + rAction.toValue = rAction.toValue.toReal() + rotation; + } + } + } + } + + if (data->actions.count()) { + if (direction == QDeclarativeAbstractAnimation::Forward) { + d->startAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped); + d->endAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped); + } else { + d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped); + d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped); + } + } else { + delete data; + delete viaData; + } + + //take care of any child animations + bool valid = d->defaultProperty.isValid(); + for (int ii = 0; ii < d->animations.count(); ++ii) { + if (valid) + d->animations.at(ii)->setDefaultTarget(d->defaultProperty); + d->animations.at(ii)->transition(actions, modified, direction); + } + +} + +QAbstractAnimation *QDeclarativeParentAnimation::qtAnimation() +{ + Q_D(QDeclarativeParentAnimation); + return d->topLevelGroup; +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h index 53afbb5..b57bd9e 100644 --- a/src/declarative/util/qdeclarativeanimation_p.h +++ b/src/declarative/util/qdeclarativeanimation_p.h @@ -447,6 +447,36 @@ protected: virtual QAbstractAnimation *qtAnimation(); }; +class QDeclarativeParentAnimationPrivate; +class QDeclarativeParentAnimation : public QDeclarativeAnimationGroup +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeParentAnimation) + + Q_PROPERTY(QDeclarativeItem *target READ target WRITE setTarget) + //Q_PROPERTY(QDeclarativeItem *newParent READ newParent WRITE setNewParent) + Q_PROPERTY(QDeclarativeItem *via READ via WRITE setVia) + +public: + QDeclarativeParentAnimation(QObject *parent=0); + virtual ~QDeclarativeParentAnimation(); + + QDeclarativeItem *target() const; + void setTarget(QDeclarativeItem *); + + QDeclarativeItem *newParent() const; + void setNewParent(QDeclarativeItem *); + + QDeclarativeItem *via() const; + void setVia(QDeclarativeItem *); + +protected: + virtual void transition(QDeclarativeStateActions &actions, + QDeclarativeProperties &modified, + TransitionDirection direction); + virtual QAbstractAnimation *qtAnimation(); +}; + QT_END_NAMESPACE QML_DECLARE_TYPE(QDeclarativeAbstractAnimation) @@ -461,6 +491,7 @@ QML_DECLARE_TYPE(QDeclarativeSequentialAnimation) QML_DECLARE_TYPE(QDeclarativeParallelAnimation) QML_DECLARE_TYPE(QDeclarativeVector3dAnimation) QML_DECLARE_TYPE(QDeclarativeRotationAnimation) +QML_DECLARE_TYPE(QDeclarativeParentAnimation) QT_END_HEADER diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h index fc4e6e6..e582066 100644 --- a/src/declarative/util/qdeclarativeanimation_p_p.h +++ b/src/declarative/util/qdeclarativeanimation_p_p.h @@ -59,6 +59,7 @@ #include "qdeclarativetimeline_p_p.h" #include +#include #include #include @@ -104,6 +105,12 @@ public: : QAbstractAnimation(parent), animAction(action), policy(KeepWhenStopped), running(false) {} ~QActionAnimation() { if (policy == DeleteWhenStopped) { delete animAction; animAction = 0; } } virtual int duration() const { return 0; } + void clearAnimAction() + { + if (policy == DeleteWhenStopped) + delete animAction; + animAction = 0; + } void setAnimAction(QAbstractAnimationAction *action, DeletionPolicy p) { if (state() == Running) @@ -311,8 +318,6 @@ public: static void append_animation(QDeclarativeListProperty *list, QDeclarativeAbstractAnimation *role); static void clear_animation(QDeclarativeListProperty *list); - static void removeAt_animation(QDeclarativeListProperty *list, int i); - static void insert_animation(QDeclarativeListProperty *list, int i, QDeclarativeAbstractAnimation *role); QList animations; QAnimationGroup *ag; }; @@ -362,6 +367,25 @@ public: QDeclarativeRotationAnimation::RotationDirection direction; }; +class QDeclarativeParentAnimationPrivate : public QDeclarativeAnimationGroupPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeParentAnimation) +public: + QDeclarativeParentAnimationPrivate() + : QDeclarativeAnimationGroupPrivate(), target(0), newParent(0), + via(0), topLevelGroup(0), startAction(0), endAction(0) {} + + QDeclarativeItem *target; + QDeclarativeItem *newParent; + QDeclarativeItem *via; + + QSequentialAnimationGroup *topLevelGroup; + QActionAnimation *startAction; + QActionAnimation *endAction; + + QPointF computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const; +}; + QT_END_NAMESPACE #endif // QDECLARATIVEANIMATION_P_H diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp index 9df8658..cea9ad7 100644 --- a/src/declarative/util/qdeclarativestateoperations.cpp +++ b/src/declarative/util/qdeclarativestateoperations.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ class QDeclarativeParentChangePrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QDeclarativeParentChange) public: QDeclarativeParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0), - rewindParent(0), rewindStackBefore(0) {} + rewindParent(0), rewindStackBefore(0) {} QDeclarativeItem *target; QDeclarativeItem *parent; @@ -71,6 +72,13 @@ public: QDeclarativeItem *rewindParent; QDeclarativeItem *rewindStackBefore; + QDeclarativeNullableValue x; + QDeclarativeNullableValue y; + QDeclarativeNullableValue width; + QDeclarativeNullableValue height; + QDeclarativeNullableValue scale; + QDeclarativeNullableValue rotation; + void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0); }; @@ -173,6 +181,120 @@ QDeclarativeParentChange::~QDeclarativeParentChange() { } +qreal QDeclarativeParentChange::x() const +{ + Q_D(const QDeclarativeParentChange); + return d->x.isNull ? qreal(0.) : d->x.value; +} + +void QDeclarativeParentChange::setX(qreal x) +{ + Q_D(QDeclarativeParentChange); + d->x = x; +} + +bool QDeclarativeParentChange::xIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->x.isValid(); +} + +qreal QDeclarativeParentChange::y() const +{ + Q_D(const QDeclarativeParentChange); + return d->y.isNull ? qreal(0.) : d->y.value; +} + +void QDeclarativeParentChange::setY(qreal y) +{ + Q_D(QDeclarativeParentChange); + d->y = y; +} + +bool QDeclarativeParentChange::yIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->y.isValid(); +} + +qreal QDeclarativeParentChange::width() const +{ + Q_D(const QDeclarativeParentChange); + return d->width.isNull ? qreal(0.) : d->width.value; +} + +void QDeclarativeParentChange::setWidth(qreal width) +{ + Q_D(QDeclarativeParentChange); + d->width = width; +} + +bool QDeclarativeParentChange::widthIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->width.isValid(); +} + +qreal QDeclarativeParentChange::height() const +{ + Q_D(const QDeclarativeParentChange); + return d->height.isNull ? qreal(0.) : d->height.value; +} + +void QDeclarativeParentChange::setHeight(qreal height) +{ + Q_D(QDeclarativeParentChange); + d->height = height; +} + +bool QDeclarativeParentChange::heightIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->height.isValid(); +} + +qreal QDeclarativeParentChange::scale() const +{ + Q_D(const QDeclarativeParentChange); + return d->scale.isNull ? qreal(1.) : d->scale.value; +} + +void QDeclarativeParentChange::setScale(qreal scale) +{ + Q_D(QDeclarativeParentChange); + d->scale = scale; +} + +bool QDeclarativeParentChange::scaleIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->scale.isValid(); +} + +qreal QDeclarativeParentChange::rotation() const +{ + Q_D(const QDeclarativeParentChange); + return d->rotation.isNull ? qreal(0.) : d->rotation.value; +} + +void QDeclarativeParentChange::setRotation(qreal rotation) +{ + Q_D(QDeclarativeParentChange); + d->rotation = rotation; +} + +bool QDeclarativeParentChange::rotationIsSet() const +{ + Q_D(const QDeclarativeParentChange); + return d->rotation.isValid(); +} + +QDeclarativeItem *QDeclarativeParentChange::originalParent() const +{ + Q_D(const QDeclarativeParentChange); + return d->origParent; +} + /*! \qmlproperty Item ParentChange::target This property holds the item to be reparented @@ -213,10 +335,43 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() if (!d->target || !d->parent) return ActionList(); + ActionList actions; + QDeclarativeAction a; a.event = this; + actions << a; - return ActionList() << a; + if (d->x.isValid()) { + QDeclarativeAction xa(d->target, QLatin1String("x"), x()); + actions << xa; + } + + if (d->y.isValid()) { + QDeclarativeAction ya(d->target, QLatin1String("y"), y()); + actions << ya; + } + + if (d->scale.isValid()) { + QDeclarativeAction sa(d->target, QLatin1String("scale"), scale()); + actions << sa; + } + + if (d->rotation.isValid()) { + QDeclarativeAction ra(d->target, QLatin1String("rotation"), rotation()); + actions << ra; + } + + if (d->width.isValid()) { + QDeclarativeAction wa(d->target, QLatin1String("width"), width()); + actions << wa; + } + + if (d->height.isValid()) { + QDeclarativeAction ha(d->target, QLatin1String("height"), height()); + actions << ha; + } + + return actions; } class AccessibleFxItem : public QDeclarativeItem diff --git a/src/declarative/util/qdeclarativestateoperations_p.h b/src/declarative/util/qdeclarativestateoperations_p.h index 9204a58..026a64d 100644 --- a/src/declarative/util/qdeclarativestateoperations_p.h +++ b/src/declarative/util/qdeclarativestateoperations_p.h @@ -62,6 +62,12 @@ class Q_DECLARATIVE_EXPORT QDeclarativeParentChange : public QDeclarativeStateOp Q_PROPERTY(QDeclarativeItem *target READ object WRITE setObject) Q_PROPERTY(QDeclarativeItem *parent READ parent WRITE setParent) + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_PROPERTY(qreal scale READ scale WRITE setScale) + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) public: QDeclarativeParentChange(QObject *parent=0); ~QDeclarativeParentChange(); @@ -72,6 +78,32 @@ public: QDeclarativeItem *parent() const; void setParent(QDeclarativeItem *); + QDeclarativeItem *originalParent() const; + + qreal x() const; + void setX(qreal x); + bool xIsSet() const; + + qreal y() const; + void setY(qreal y); + bool yIsSet() const; + + qreal width() const; + void setWidth(qreal width); + bool widthIsSet() const; + + qreal height() const; + void setHeight(qreal height); + bool heightIsSet() const; + + qreal scale() const; + void setScale(qreal scale); + bool scaleIsSet() const; + + qreal rotation() const; + void setRotation(qreal rotation); + bool rotationIsSet() const; + virtual ActionList actions(); virtual void saveOriginals(); diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp index ecaa607c..8d3d682 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -90,6 +90,7 @@ void QDeclarativeUtilModule::defineModule() QML_REGISTER_TYPE(Qt,4,6,Package,QDeclarativePackage); QML_REGISTER_TYPE(Qt,4,6,ParallelAnimation,QDeclarativeParallelAnimation); QML_REGISTER_TYPE(Qt,4,6,ParentAction,QDeclarativeParentAction); + QML_REGISTER_TYPE(Qt,4,6,ParentAnimation,QDeclarativeParentAnimation); QML_REGISTER_TYPE(Qt,4,6,ParentChange,QDeclarativeParentChange); QML_REGISTER_TYPE(Qt,4,6,PauseAnimation,QDeclarativePauseAnimation); QML_REGISTER_TYPE(Qt,4,6,PropertyAction,QDeclarativePropertyAction); -- cgit v0.12