1 // Commit: 91501cc9b542de644cd70098a6bc5ff738cdeb49
2 /****************************************************************************
4 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
41 ****************************************************************************/
43 #include "qsganimation_p.h"
44 #include "qsganimation_p_p.h"
45 #include "qsgstateoperations_p.h"
47 #include <QtDeclarative/qdeclarativeinfo.h>
48 #include <QtCore/qmath.h>
49 #include <QtCore/qsequentialanimationgroup.h>
50 #include <QtCore/qparallelanimationgroup.h>
54 QSGParentAnimation::QSGParentAnimation(QObject *parent)
55 : QDeclarativeAnimationGroup(*(new QSGParentAnimationPrivate), parent)
57 Q_D(QSGParentAnimation);
58 d->topLevelGroup = new QSequentialAnimationGroup;
59 QDeclarative_setParent_noEvent(d->topLevelGroup, this);
61 d->startAction = new QActionAnimation;
62 QDeclarative_setParent_noEvent(d->startAction, d->topLevelGroup);
63 d->topLevelGroup->addAnimation(d->startAction);
65 d->ag = new QParallelAnimationGroup;
66 QDeclarative_setParent_noEvent(d->ag, d->topLevelGroup);
67 d->topLevelGroup->addAnimation(d->ag);
69 d->endAction = new QActionAnimation;
70 QDeclarative_setParent_noEvent(d->endAction, d->topLevelGroup);
71 d->topLevelGroup->addAnimation(d->endAction);
74 QSGParentAnimation::~QSGParentAnimation()
78 QSGItem *QSGParentAnimation::target() const
80 Q_D(const QSGParentAnimation);
84 void QSGParentAnimation::setTarget(QSGItem *target)
86 Q_D(QSGParentAnimation);
87 if (target == d->target)
94 QSGItem *QSGParentAnimation::newParent() const
96 Q_D(const QSGParentAnimation);
100 void QSGParentAnimation::setNewParent(QSGItem *newParent)
102 Q_D(QSGParentAnimation);
103 if (newParent == d->newParent)
106 d->newParent = newParent;
107 emit newParentChanged();
110 QSGItem *QSGParentAnimation::via() const
112 Q_D(const QSGParentAnimation);
116 void QSGParentAnimation::setVia(QSGItem *via)
118 Q_D(QSGParentAnimation);
126 //### mirrors same-named function in QSGItem
127 QPointF QSGParentAnimationPrivate::computeTransformOrigin(QSGItem::TransformOrigin origin, qreal width, qreal height) const
131 case QSGItem::TopLeft:
132 return QPointF(0, 0);
134 return QPointF(width / 2., 0);
135 case QSGItem::TopRight:
136 return QPointF(width, 0);
138 return QPointF(0, height / 2.);
139 case QSGItem::Center:
140 return QPointF(width / 2., height / 2.);
142 return QPointF(width, height / 2.);
143 case QSGItem::BottomLeft:
144 return QPointF(0, height);
145 case QSGItem::Bottom:
146 return QPointF(width / 2., height);
147 case QSGItem::BottomRight:
148 return QPointF(width, height);
152 void QSGParentAnimation::transition(QDeclarativeStateActions &actions,
153 QDeclarativeProperties &modified,
154 TransitionDirection direction)
156 Q_D(QSGParentAnimation);
158 struct QSGParentAnimationData : public QAbstractAnimationAction
160 QSGParentAnimationData() {}
161 ~QSGParentAnimationData() { qDeleteAll(pc); }
163 QDeclarativeStateActions actions;
164 //### reverse should probably apply on a per-action basis
166 QList<QSGParentChange *> pc;
167 virtual void doAction()
169 for (int ii = 0; ii < actions.count(); ++ii) {
170 const QDeclarativeAction &action = actions.at(ii);
172 action.event->reverse();
174 action.event->execute();
179 QSGParentAnimationData *data = new QSGParentAnimationData;
180 QSGParentAnimationData *viaData = new QSGParentAnimationData;
182 bool hasExplicit = false;
183 if (d->target && d->newParent) {
184 data->reverse = false;
185 QDeclarativeAction myAction;
186 QSGParentChange *pc = new QSGParentChange;
187 pc->setObject(d->target);
188 pc->setParent(d->newParent);
191 data->actions << myAction;
194 viaData->reverse = false;
195 QDeclarativeAction myVAction;
196 QSGParentChange *vpc = new QSGParentChange;
197 vpc->setObject(d->target);
198 vpc->setParent(d->via);
199 myVAction.event = vpc;
201 viaData->actions << myVAction;
203 //### once actions have concept of modified,
204 // loop to match appropriate ParentChanges and mark as modified
208 for (int i = 0; i < actions.size(); ++i) {
209 QDeclarativeAction &action = actions[i];
210 if (action.event && action.event->typeName() == QLatin1String("ParentChange")
211 && (!d->target || static_cast<QSGParentChange*>(action.event)->object() == d->target)) {
213 QSGParentChange *pc = static_cast<QSGParentChange*>(action.event);
214 QDeclarativeAction myAction = action;
215 data->reverse = action.reverseEvent;
217 //### this logic differs from PropertyAnimation
218 // (probably a result of modified vs. done)
220 QSGParentChange *epc = new QSGParentChange;
221 epc->setObject(static_cast<QSGParentChange*>(action.event)->object());
222 epc->setParent(d->newParent);
223 myAction.event = epc;
225 data->actions << myAction;
228 action.actionDone = true;
229 data->actions << myAction;
233 viaData->reverse = false;
234 QDeclarativeAction myAction;
235 QSGParentChange *vpc = new QSGParentChange;
236 vpc->setObject(pc->object());
237 vpc->setParent(d->via);
238 myAction.event = vpc;
240 viaData->actions << myAction;
241 QDeclarativeAction dummyAction;
242 QDeclarativeAction &xAction = pc->xIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
243 QDeclarativeAction &yAction = pc->yIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
244 QDeclarativeAction &sAction = pc->scaleIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
245 QDeclarativeAction &rAction = pc->rotationIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction;
246 QSGItem *target = pc->object();
247 QSGItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent();
249 //### this mirrors the logic in QSGParentChange.
251 const QTransform &transform = targetParent->itemTransform(d->via, &ok);
252 if (transform.type() >= QTransform::TxShear || !ok) {
253 qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under complex transform");
259 bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
260 if (ok && !isRotate) {
261 if (transform.m11() == transform.m22())
262 scale = transform.m11();
264 qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
267 } else if (ok && isRotate) {
268 if (transform.m11() == transform.m22())
269 scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
271 qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
276 rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
278 qmlInfo(this) << QSGParentAnimation::tr("Unable to preserve appearance under scale of 0");
283 const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal()));
286 if (ok && target->transformOrigin() != QSGItem::TopLeft) {
287 qreal w = target->width();
288 qreal h = target->height();
289 if (pc->widthIsSet() && i < actions.size() - 1)
290 w = actions[++i].toValue.toReal();
291 if (pc->heightIsSet() && i < actions.size() - 1)
292 h = actions[++i].toValue.toReal();
293 const QPointF &transformOrigin
294 = d->computeTransformOrigin(target->transformOrigin(), w,h);
295 qreal tempxt = transformOrigin.x();
296 qreal tempyt = transformOrigin.y();
298 t.translate(-tempxt, -tempyt);
300 t.scale(scale, scale);
301 t.translate(tempxt, tempyt);
302 const QPointF &offset = t.map(QPointF(0,0));
308 //qDebug() << x << y << rotation << scale;
311 sAction.toValue = sAction.toValue.toReal() * scale;
312 rAction.toValue = rAction.toValue.toReal() + rotation;
318 if (data->actions.count()) {
319 if (direction == QDeclarativeAbstractAnimation::Forward) {
320 d->startAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
321 d->endAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
323 d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
324 d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
331 //take care of any child animations
332 bool valid = d->defaultProperty.isValid();
333 for (int ii = 0; ii < d->animations.count(); ++ii) {
335 d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
336 d->animations.at(ii)->transition(actions, modified, direction);
341 QAbstractAnimation *QSGParentAnimation::qtAnimation()
343 Q_D(QSGParentAnimation);
344 return d->topLevelGroup;
347 QSGAnchorAnimation::QSGAnchorAnimation(QObject *parent)
348 : QDeclarativeAbstractAnimation(*(new QSGAnchorAnimationPrivate), parent)
350 Q_D(QSGAnchorAnimation);
351 d->va = new QDeclarativeBulkValueAnimator;
352 QDeclarative_setParent_noEvent(d->va, this);
355 QSGAnchorAnimation::~QSGAnchorAnimation()
359 QAbstractAnimation *QSGAnchorAnimation::qtAnimation()
361 Q_D(QSGAnchorAnimation);
365 QDeclarativeListProperty<QSGItem> QSGAnchorAnimation::targets()
367 Q_D(QSGAnchorAnimation);
368 return QDeclarativeListProperty<QSGItem>(this, d->targets);
371 int QSGAnchorAnimation::duration() const
373 Q_D(const QSGAnchorAnimation);
374 return d->va->duration();
377 void QSGAnchorAnimation::setDuration(int duration)
380 qmlInfo(this) << tr("Cannot set a duration of < 0");
384 Q_D(QSGAnchorAnimation);
385 if (d->va->duration() == duration)
387 d->va->setDuration(duration);
388 emit durationChanged(duration);
391 QEasingCurve QSGAnchorAnimation::easing() const
393 Q_D(const QSGAnchorAnimation);
394 return d->va->easingCurve();
397 void QSGAnchorAnimation::setEasing(const QEasingCurve &e)
399 Q_D(QSGAnchorAnimation);
400 if (d->va->easingCurve() == e)
403 d->va->setEasingCurve(e);
404 emit easingChanged(e);
407 void QSGAnchorAnimation::transition(QDeclarativeStateActions &actions,
408 QDeclarativeProperties &modified,
409 TransitionDirection direction)
412 Q_D(QSGAnchorAnimation);
413 QDeclarativeAnimationPropertyUpdater *data = new QDeclarativeAnimationPropertyUpdater;
414 data->interpolatorType = QMetaType::QReal;
415 data->interpolator = d->interpolator;
417 data->reverse = direction == Backward ? true : false;
418 data->fromSourced = false;
419 data->fromDefined = false;
421 for (int ii = 0; ii < actions.count(); ++ii) {
422 QDeclarativeAction &action = actions[ii];
423 if (action.event && action.event->typeName() == QLatin1String("AnchorChanges")
424 && (d->targets.isEmpty() || d->targets.contains(static_cast<QSGAnchorChanges*>(action.event)->object()))) {
425 data->actions << static_cast<QSGAnchorChanges*>(action.event)->additionalActions();
429 if (data->actions.count()) {
430 if (!d->rangeIsSet) {
431 d->va->setStartValue(qreal(0));
432 d->va->setEndValue(qreal(1));
433 d->rangeIsSet = true;
435 d->va->setAnimValue(data, QAbstractAnimation::DeleteWhenStopped);
436 d->va->setFromSourcedValue(&data->fromSourced);