1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktransition_p.h"
44 #include "qquickstate_p.h"
45 #include "qquickstate_p_p.h"
46 #include "qquickstatechangescript_p.h"
47 #include "qquickanimation_p.h"
48 #include "qquickanimation_p_p.h"
49 #include "qquicktransitionmanager_p_p.h"
51 #include "private/qparallelanimationgroupjob_p.h"
56 \qmlclass Transition QQuickTransition
57 \inqmlmodule QtQuick 2
58 \ingroup qml-animation-transition
59 \brief The Transition element defines animated transitions that occur on state changes.
61 A Transition defines the animations to be applied when a \l State change occurs.
63 For example, the following \l Rectangle has two states: the default state, and
64 an added "moved" state. In the "moved state, the rectangle's position changes
65 to (50, 50). The added Transition specifies that when the rectangle
66 changes between the default and the "moved" state, any changes
67 to the \c x and \c y properties should be animated, using an \c Easing.InOutQuad.
69 \snippet doc/src/snippets/qml/transition.qml 0
71 Notice the example does not require \l{PropertyAnimation::}{to} and
72 \l{PropertyAnimation::}{from} values for the NumberAnimation. As a convenience,
73 these properties are automatically set to the values of \c x and \c y before
74 and after the state change; the \c from values are provided by
75 the current values of \c x and \c y, and the \c to values are provided by
76 the PropertyChanges object. If you wish, you can provide \l{PropertyAnimation::}{to} and
77 \l{PropertyAnimation::}{from} values anyway to override the default values.
79 By default, a Transition's animations are applied for any state change in the
80 parent item. The Transition \l {Transition::}{from} and \l {Transition::}{to}
81 values can be set to restrict the animations to only be applied when changing
82 from one particular state to another.
84 To define multiple transitions, specify \l Item::transitions as a list:
86 \snippet doc/src/snippets/qml/transitions-list.qml list of transitions
88 If multiple Transitions are specified, only a single (best-matching) Transition will be applied for any particular
89 state change. In the example above, when changing to \c state1, the first transition will be used, rather
90 than the more generic second transition.
92 If a state change has a Transition that matches the same property as a
93 \l Behavior, the Transition animation overrides the \l Behavior for that
96 \sa {QML Animation and Transitions}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtQml}
99 //ParallelAnimationWrapper allows us to do a "callback" when the animation finishes, rather than connecting
100 //and disconnecting signals and slots frequently
101 class ParallelAnimationWrapper : public QParallelAnimationGroupJob
104 ParallelAnimationWrapper() : QParallelAnimationGroupJob() {}
105 QQuickTransitionManager *manager;
108 virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
111 class QQuickTransitionPrivate : public QObjectPrivate, QAnimationJobChangeListener
113 Q_DECLARE_PUBLIC(QQuickTransition)
115 QQuickTransitionPrivate()
116 : fromState(QLatin1String("*")), toState(QLatin1String("*"))
117 , runningInstanceCount(0), state(QAbstractAnimationJob::Stopped)
118 , reversed(false), reversible(false), enabled(true)
122 void removeStateChangeListener(QAbstractAnimationJob *anim)
125 anim->removeAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
130 quint32 runningInstanceCount;
131 QAbstractAnimationJob::State state;
136 virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State, QAbstractAnimationJob::State);
138 static void append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a);
139 static int animation_count(QQmlListProperty<QQuickAbstractAnimation> *list);
140 static QQuickAbstractAnimation* animation_at(QQmlListProperty<QQuickAbstractAnimation> *list, int pos);
141 static void clear_animations(QQmlListProperty<QQuickAbstractAnimation> *list);
142 QList<QQuickAbstractAnimation *> animations;
145 void QQuickTransitionPrivate::append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a)
147 QQuickTransition *q = static_cast<QQuickTransition *>(list->object);
148 q->d_func()->animations.append(a);
149 a->setDisableUserControl();
152 int QQuickTransitionPrivate::animation_count(QQmlListProperty<QQuickAbstractAnimation> *list)
154 QQuickTransition *q = static_cast<QQuickTransition *>(list->object);
155 return q->d_func()->animations.count();
158 QQuickAbstractAnimation* QQuickTransitionPrivate::animation_at(QQmlListProperty<QQuickAbstractAnimation> *list, int pos)
160 QQuickTransition *q = static_cast<QQuickTransition *>(list->object);
161 return q->d_func()->animations.at(pos);
164 void QQuickTransitionPrivate::clear_animations(QQmlListProperty<QQuickAbstractAnimation> *list)
166 QQuickTransition *q = static_cast<QQuickTransition *>(list->object);
167 while (q->d_func()->animations.count()) {
168 QQuickAbstractAnimation *firstAnim = q->d_func()->animations.at(0);
169 q->d_func()->animations.removeAll(firstAnim);
173 void QQuickTransitionPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
175 Q_Q(QQuickTransition);
177 if (newState == QAbstractAnimationJob::Running) {
178 if (!runningInstanceCount)
179 emit q->runningChanged();
180 runningInstanceCount++;
181 } else if (newState == QAbstractAnimationJob::Stopped) {
182 runningInstanceCount--;
183 if (!runningInstanceCount)
184 emit q->runningChanged();
188 void ParallelAnimationWrapper::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
190 QParallelAnimationGroupJob::updateState(newState, oldState);
191 if (newState == Stopped && (duration() == -1
192 || (direction() == QAbstractAnimationJob::Forward && currentLoopTime() == duration())
193 || (direction() == QAbstractAnimationJob::Backward && currentLoopTime() == 0)))
199 QQuickTransitionInstance::QQuickTransitionInstance(QQuickTransitionPrivate *transition, QAbstractAnimationJob *anim)
200 : m_transition(transition)
205 QQuickTransitionInstance::~QQuickTransitionInstance()
207 m_transition->removeStateChangeListener(m_anim);
211 void QQuickTransitionInstance::start()
217 void QQuickTransitionInstance::stop()
223 bool QQuickTransitionInstance::isRunning() const
225 return m_anim && m_anim->state() == QAbstractAnimationJob::Running;
228 QQuickTransition::QQuickTransition(QObject *parent)
229 : QObject(*(new QQuickTransitionPrivate), parent)
233 QQuickTransition::~QQuickTransition()
237 void QQuickTransition::setReversed(bool r)
239 Q_D(QQuickTransition);
243 QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::ActionList &actions,
244 QList<QQmlProperty> &after,
245 QQuickTransitionManager *manager,
246 QObject *defaultTarget)
248 Q_D(QQuickTransition);
250 qmlExecuteDeferred(this);
252 ParallelAnimationWrapper *group = new ParallelAnimationWrapper();
253 group->manager = manager;
255 QQuickAbstractAnimation::TransitionDirection direction = d->reversed ? QQuickAbstractAnimation::Backward : QQuickAbstractAnimation::Forward;
256 int start = d->reversed ? d->animations.count() - 1 : 0;
257 int end = d->reversed ? -1 : d->animations.count();
259 QAbstractAnimationJob *anim = 0;
260 for (int i = start; i != end;) {
261 anim = d->animations.at(i)->transition(actions, after, direction, defaultTarget);
263 d->reversed ? group->prependAnimation(anim) : group->appendAnimation(anim);
264 d->reversed ? --i : ++i;
267 group->setDirection(d->reversed ? QAbstractAnimationJob::Backward : QAbstractAnimationJob::Forward);
269 group->addAnimationChangeListener(d, QAbstractAnimationJob::StateChange);
270 QQuickTransitionInstance *wrapper = new QQuickTransitionInstance(d, group);
275 \qmlproperty string QtQuick2::Transition::from
276 \qmlproperty string QtQuick2::Transition::to
278 These properties indicate the state changes that trigger the transition.
280 The default values for these properties is "*" (that is, any state).
282 For example, the following transition has not set the \c to and \c from
283 properties, so the animation is always applied when changing between
284 the two states (i.e. when the mouse is pressed and released).
286 \snippet doc/src/snippets/qml/transition-from-to.qml 0
288 If the transition was changed to this:
290 \snippet doc/src/snippets/qml/transition-from-to-modified.qml modified transition
292 The animation would only be applied when changing from the default state to
293 the "brighter" state (i.e. when the mouse is pressed, but not on release).
295 Multiple \c to and \from values can be set by using a comma-separated string.
299 QString QQuickTransition::fromState() const
301 Q_D(const QQuickTransition);
305 void QQuickTransition::setFromState(const QString &f)
307 Q_D(QQuickTransition);
308 if (f == d->fromState)
316 \qmlproperty bool QtQuick2::Transition::reversible
317 This property holds whether the transition should be automatically reversed when the conditions that triggered this transition are reversed.
319 The default value is false.
321 By default, transitions run in parallel and are applied to all state
322 changes if the \l from and \l to states have not been set. In this
323 situation, the transition is automatically applied when a state change
324 is reversed, and it is not necessary to set this property to reverse
327 However, if a SequentialAnimation is used, or if the \l from or \l to
328 properties have been set, this property will need to be set to reverse
329 a transition when a state change is reverted. For example, the following
330 transition applies a sequential animation when the mouse is pressed,
331 and reverses the sequence of the animation when the mouse is released:
333 \snippet doc/src/snippets/qml/transition-reversible.qml 0
335 If the transition did not set the \c to and \c reversible values, then
336 on the mouse release, the transition would play the PropertyAnimation
337 before the ColorAnimation instead of reversing the sequence.
339 bool QQuickTransition::reversible() const
341 Q_D(const QQuickTransition);
342 return d->reversible;
345 void QQuickTransition::setReversible(bool r)
347 Q_D(QQuickTransition);
348 if (r == d->reversible)
352 emit reversibleChanged();
355 QString QQuickTransition::toState() const
357 Q_D(const QQuickTransition);
361 void QQuickTransition::setToState(const QString &t)
363 Q_D(QQuickTransition);
372 \qmlproperty bool QtQuick2::Transition::enabled
374 This property holds whether the Transition will be run when moving
375 from the \c from state to the \c to state.
377 By default a Transition is enabled.
379 Note that in some circumstances disabling a Transition may cause an
380 alternative Transition to be used in its place. In the following
381 example, the generic Transition will be used to animate the change
382 from \c state1 to \c state2, as the more specific Transition has
388 State { name: "state1" ... }
389 State { name: "state2" ... }
392 Transition { from: "state1"; to: "state2"; enabled: false ... }
399 bool QQuickTransition::enabled() const
401 Q_D(const QQuickTransition);
405 void QQuickTransition::setEnabled(bool enabled)
407 Q_D(QQuickTransition);
408 if (d->enabled == enabled)
410 d->enabled = enabled;
411 emit enabledChanged();
415 \qmlproperty bool QtQuick2::Transition::running
417 This property holds whether the transition is currently running.
419 This property is read only.
421 bool QQuickTransition::running() const
423 Q_D(const QQuickTransition);
424 return d->runningInstanceCount;
429 \qmlproperty list<Animation> QtQuick2::Transition::animations
432 This property holds a list of the animations to be run for this transition.
434 \snippet examples/declarative/toys/dynamicscene/dynamicscene.qml top-level transitions
436 The top-level animations are run in parallel. To run them sequentially,
437 define them within a SequentialAnimation:
439 \snippet doc/src/snippets/qml/transition-reversible.qml sequential animations
441 QQmlListProperty<QQuickAbstractAnimation> QQuickTransition::animations()
443 Q_D(QQuickTransition);
444 return QQmlListProperty<QQuickAbstractAnimation>(this, &d->animations, QQuickTransitionPrivate::append_animation,
445 QQuickTransitionPrivate::animation_count,
446 QQuickTransitionPrivate::animation_at,
447 QQuickTransitionPrivate::clear_animations);
452 //#include <qquicktransition.moc>