1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qquickbehavior_p.h"
44 #include "qquickanimation_p.h"
45 #include <qqmlcontext.h>
47 #include <private/qqmlproperty_p.h>
48 #include <private/qqmlguard_p.h>
49 #include <private/qqmlengine_p.h>
50 #include <private/qabstractanimationjob_p.h>
51 #include <private/qquicktransition_p.h>
53 #include <private/qobject_p.h>
57 class QQuickBehaviorPrivate : public QObjectPrivate, public QAnimationJobChangeListener
59 Q_DECLARE_PUBLIC(QQuickBehavior)
61 QQuickBehaviorPrivate() : animation(0), animationInstance(0), enabled(true), finalized(false)
62 , blockRunningChanged(false) {}
64 virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
66 QQmlProperty property;
68 QQmlGuard<QQuickAbstractAnimation> animation;
69 QAbstractAnimationJob *animationInstance;
72 bool blockRunningChanged;
77 \instantiates QQuickBehavior
78 \inqmlmodule QtQuick 2
79 \ingroup qtquick-transitions-animations
80 \ingroup qtquick-interceptors
81 \brief Defines a default animation for a property change
83 A Behavior defines the default animation to be applied whenever a
84 particular property value changes.
86 For example, the following Behavior defines a NumberAnimation to be run
87 whenever the \l Rectangle's \c width value changes. When the MouseArea
88 is clicked, the \c width is changed, triggering the behavior's animation:
90 \snippet qml/behavior.qml 0
92 Note that a property cannot have more than one assigned Behavior. To provide
93 multiple animations within a Behavior, use ParallelAnimation or
96 If a \l{Qt Quick States}{state change} has a \l Transition that matches the same property as a
97 Behavior, the \l Transition animation overrides the Behavior for that
98 state change. For general advice on using Behaviors to animate state changes, see
99 \l{Using Qt Quick Behaviors with States}.
101 \sa {Animation and Transitions in Qt Quick}, {declarative/animation/behaviors}{Behavior example}, QtQml
105 QQuickBehavior::QQuickBehavior(QObject *parent)
106 : QObject(*(new QQuickBehaviorPrivate), parent)
110 QQuickBehavior::~QQuickBehavior()
113 delete d->animationInstance;
117 \qmlproperty Animation QtQuick2::Behavior::animation
120 This property holds the animation to run when the behavior is triggered.
123 QQuickAbstractAnimation *QQuickBehavior::animation()
129 void QQuickBehavior::setAnimation(QQuickAbstractAnimation *animation)
133 qmlInfo(this) << tr("Cannot change the animation assigned to a Behavior.");
137 d->animation = animation;
139 d->animation->setDefaultTarget(d->property);
140 d->animation->setDisableUserControl();
145 void QQuickBehaviorPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState,QAbstractAnimationJob::State)
147 if (!blockRunningChanged)
148 animation->notifyRunningChanged(newState == QAbstractAnimationJob::Running);
152 \qmlproperty bool QtQuick2::Behavior::enabled
154 This property holds whether the behavior will be triggered when the tracked
155 property changes value.
157 By default a Behavior is enabled.
160 bool QQuickBehavior::enabled() const
162 Q_D(const QQuickBehavior);
166 void QQuickBehavior::setEnabled(bool enabled)
169 if (d->enabled == enabled)
171 d->enabled = enabled;
172 emit enabledChanged();
175 void QQuickBehavior::write(const QVariant &value)
178 bool bypass = !d->enabled || !d->finalized;
180 qmlExecuteDeferred(this);
181 if (!d->animation || bypass) {
182 QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
183 d->targetValue = value;
187 if (d->animation->isRunning() && value == d->targetValue)
190 const QVariant ¤tValue = d->property.read();
191 d->targetValue = value;
193 if (d->animationInstance && d->animationInstance->duration() != -1
194 && !d->animationInstance->isStopped()) {
195 d->blockRunningChanged = true;
196 d->animationInstance->stop();
199 QQuickStateOperation::ActionList actions;
201 action.property = d->property;
202 action.fromValue = currentValue;
203 action.toValue = value;
206 QList<QQmlProperty> after;
207 QAbstractAnimationJob *prev = d->animationInstance;
208 d->animationInstance = d->animation->transition(actions, after, QQuickAbstractAnimation::Forward);
209 if (prev && prev != d->animationInstance)
212 if (d->animationInstance) {
213 if (d->animationInstance != prev)
214 d->animationInstance->addAnimationChangeListener(d, QAbstractAnimationJob::StateChange);
215 d->animationInstance->start();
216 d->blockRunningChanged = false;
218 if (!after.contains(d->property))
219 QQmlPropertyPrivate::write(d->property, value, QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
222 void QQuickBehavior::setTarget(const QQmlProperty &property)
225 d->property = property;
227 d->animation->setDefaultTarget(property);
229 QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(qmlEngine(this));
230 static int finalizedIdx = -1;
231 if (finalizedIdx < 0)
232 finalizedIdx = metaObject()->indexOfSlot("componentFinalized()");
233 engPriv->registerFinalizeCallback(this, finalizedIdx);
236 void QQuickBehavior::componentFinalized()