diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index 343338c661c5fe0083e4f465c5fba0806cf966a6..da961763ede1f8f17edb757d130180b72078a610 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -277,6 +277,8 @@ QAbstractAnimationJob::QAbstractAnimationJob() , m_isGroup(false) , m_disableUserControl(false) , m_hasCurrentTimeChangeListeners(false) + , m_isRenderThreadJob(false) + , m_isRenderThreadProxy(false) { } diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h index abf3cd6df6060b8f09f6c3c4a56f728a6ee7fb2e..95a238405cfd0ac6ddd2b7fd5265dc03560c7216 100644 --- a/src/qml/animations/qabstractanimationjob_p.h +++ b/src/qml/animations/qabstractanimationjob_p.h @@ -113,6 +113,10 @@ public: QAbstractAnimationJob *nextSibling() const { return m_nextSibling; } QAbstractAnimationJob *previousSibling() const { return m_previousSibling; } + bool isGroup() const { return m_isGroup; } + bool isRenderThreadJob() const { return m_isRenderThreadJob; } + bool isRenderThreadProxy() const { return m_isRenderThreadProxy; } + protected: virtual void updateCurrentTime(int) {} virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); @@ -157,6 +161,8 @@ protected: bool m_isGroup:1; bool m_disableUserControl:1; bool m_hasCurrentTimeChangeListeners:1; + bool m_isRenderThreadJob:1; + bool m_isRenderThreadProxy:1; friend class QQmlAnimationTimer; friend class QAnimationGroupJob; diff --git a/src/quick/doc/snippets/qml/animators.qml b/src/quick/doc/snippets/qml/animators.qml new file mode 100644 index 0000000000000000000000000000000000000000..4b9e4f425089c40b136ae6247554890d290f62a3 --- /dev/null +++ b/src/quick/doc/snippets/qml/animators.qml @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 + +Rectangle { + + width: 320 + height: 480 + + color: "steelblue" + + Grid { + anchors.fill: parent + anchors.margins: 20 + columnSpacing: 30 + rowSpacing: 30 + columns: 4 + rows: 4 + + property real cellWidth: (width - (columns - 1) * columnSpacing) / columns; + property real cellHeight: (height - (rows - 1) * rowSpacing) / rows; + + Item { + width: parent.cellWidth + height: parent.cellHeight +//! [x on] +Rectangle { + width: 50 + height: 50 + color: "lightsteelblue" + XAnimator on x { + from: 10; + to: 0; + duration: 1000 + } +} +//! [x on] + } + Item { + width: parent.cellWidth + height: parent.cellHeight +//! [x target] +Rectangle { + id: xmovingBox + width: 50 + height: 50 + color: "lightsteelblue" + XAnimator { + target: xmovingBox; + from: 10; + to: 0; + duration: 1000 + running: true + } +} +//! [x target] + } + Item { + width: parent.cellWidth + height: parent.cellHeight +//! [y on] +Rectangle { + width: 50 + height: 50 + color: "lightsteelblue" + YAnimator on y { + from: 10; + to: 0; + duration: 1000 + } +} +//! [y on] + } + Item { + width: parent.cellWidth + height: parent.cellHeight +//! [y target] +Rectangle { + id: ymovingBox + width: 50 + height: 50 + color: "lightsteelblue" + YAnimator { + target: ymovingBox; + from: 10; + to: 0; + duration: 1000 + running: true + } +} +//! [y target] + } +//! [rotation on] +Rectangle { + width: 50 + height: 50 + color: "lightsteelblue" + RotationAnimator on rotation { + from: 0; + to: 360; + duration: 1000 + } +} +//! [rotation on] +//! [rotation target] +Rectangle { + id: rotatingBox + width: 50 + height: 50 + color: "lightsteelblue" + RotationAnimator { + target: rotatingBox; + from: 0; + to: 360; + duration: 1000 + running: true + } +} +//! [rotation target] +//! [scale on] +Rectangle { + width: 50 + height: 50 + color: "lightsteelblue" + ScaleAnimator on scale { + from: 0.5; + to: 1; + duration: 1000 + } +} +//! [scale on] +//! [scale target] +Rectangle { + id: scalingBox + width: 50 + height: 50 + color: "lightsteelblue" + ScaleAnimator { + target: scalingBox; + from: 0.5; + to: 1; + duration: 1000 + running: true + } +} +//! [scale target] +//! [opacity on] +Rectangle { + width: 50 + height: 50 + color: "lightsteelblue" + OpacityAnimator on opacity{ + from: 0; + to: 1; + duration: 1000 + } +} +//! [opacity on] +//! [opacity target] +Rectangle { + id: opacityBox + width: 50 + height: 50 + color: "lightsteelblue" + OpacityAnimator { + target: opacityBox; + from: 0; + to: 1; + duration: 1000 + running: true + } +} +//! [opacity target] +//![shaderon] +ShaderEffect { + width: 50 + height: 50 + property variant t; + UniformAnimator on t { + from: 0 + to: 1 + duration: 1000 + } + fragmentShader: + " + uniform lowp float t; + varying highp vec2 qt_TexCoord0; + void main() { + lowp float c = qt_TexCoord0.y; + gl_FragColor = vec4(c * t, 0, 0, 1); + } + " +} +//![shaderon] +//![shader target] +ShaderEffect { + id: shader + width: 50 + height: 50 + property variant t; + UniformAnimator { + target: shader + uniform: "t" + from: 0 + to: 1 + duration: 1000 + running: true + } + fragmentShader: + " + uniform lowp float t; + varying highp vec2 qt_TexCoord0; + void main() { + lowp float c = qt_TexCoord0.y; + gl_FragColor = vec4(0, 0, c * t, 1); + } + " +} +//![shader target] +//![mixed] +Rectangle { + id: mixBox + width: 50 + height: 50 + ParallelAnimation { + ColorAnimation { + target: mixBox + property: "color" + from: "forestgreen" + to: "lightsteelblue"; + duration: 1000 + } + ScaleAnimator { + target: mixBox + from: 2 + to: 1 + duration: 1000 + } + running: true + } +} +//! [mixed] + } +} diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 5b4145e23556d5f09fb2a72681eaa809e87986ea..923b7605e1820e4e19e6f4a137ed3cb3d006d128 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -53,6 +53,7 @@ #include <QtQuick/private/qsgflashnode_p.h> #include <private/qsgrenderloop_p.h> +#include <private/qquickanimatorcontroller_p.h> #include <private/qguiapplication_p.h> #include <QtGui/QInputMethod> @@ -319,6 +320,8 @@ void QQuickWindowPrivate::syncSceneGraph() QML_MEMORY_SCOPE_STRING("SceneGraph"); Q_Q(QQuickWindow); + animationController->beforeNodeSync(); + emit q->beforeSynchronizing(); if (!renderer) { forceUpdate(contentItem); @@ -331,6 +334,8 @@ void QQuickWindowPrivate::syncSceneGraph() updateDirtyNodes(); + animationController->afterNodeSync(); + // Copy the current state of clearing from window into renderer. renderer->setClearColor(clearColor); QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer; @@ -344,6 +349,7 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size) { QML_MEMORY_SCOPE_STRING("SceneGraph"); Q_Q(QQuickWindow); + animationController->advance(); emit q->beforeRendering(); int fboId = 0; const qreal devicePixelRatio = q->devicePixelRatio(); @@ -414,6 +420,9 @@ void QQuickWindowPrivate::init(QQuickWindow *c) q->setSurfaceType(QWindow::OpenGLSurface); q->setFormat(context->defaultSurfaceFormat()); + animationController = new QQuickAnimatorController(); + animationController->window = q; + QObject::connect(context, SIGNAL(initialized()), q, SIGNAL(sceneGraphInitialized()), Qt::DirectConnection); QObject::connect(context, SIGNAL(invalidated()), q, SIGNAL(sceneGraphInvalidated()), Qt::DirectConnection); QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection); @@ -990,6 +999,7 @@ QQuickWindow::~QQuickWindow() { Q_D(QQuickWindow); + d->animationController->deleteLater(); d->windowManager->windowDestroyed(this); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index e29ceb521ffd4f9d51081b0b461eeed469796bad..c656eacce730c3eaf8376a10afa1ab2f2b0fcce4 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -71,6 +71,7 @@ QT_BEGIN_NAMESPACE //Make it easy to identify and customize the root item if needed +class QQuickAnimatorController; class QSGRenderLoop; class QQuickDragGrabber; @@ -197,6 +198,7 @@ public: QSGRenderer *renderer; QSGRenderLoop *windowManager; + QQuickAnimatorController *animationController; QColor clearColor; diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index e099d94a53cf9b2960e8992f21496435d6de8c67..890f5793159e19f16bf69c7a6fe002a8afffda36 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -124,6 +124,18 @@ public: bool eventPending; }; +bool QSGRenderLoop::useConsistentTiming() +{ + bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL); + // Enable fixed animation steps... + QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP"); + bool fixedAnimationSteps = bufferQueuing; + if (fixed == "no") + fixedAnimationSteps = false; + else if (fixed.length()) + fixedAnimationSteps = true; + return fixedAnimationSteps; +} QSGRenderLoop *QSGRenderLoop::instance() { @@ -131,16 +143,7 @@ QSGRenderLoop *QSGRenderLoop::instance() s_instance = QSGContext::createWindowManager(); - bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL); - - // Enable fixed animation steps... - QByteArray fixed = qgetenv("QML_FIXED_ANIMATION_STEP"); - bool fixedAnimationSteps = bufferQueuing; - if (fixed == "no") - fixedAnimationSteps = false; - else if (fixed.length()) - fixedAnimationSteps = true; - if (fixedAnimationSteps) + if (useConsistentTiming()) QUnifiedTimer::instance(true)->setConsistentTiming(true); if (!s_instance) { diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 1e9a645cf4f2b2e72f4e3f89c1bf37feec849382..99b3ab677d458aae3da962b5195fabaf99d422bd 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -79,6 +79,8 @@ public: static QSGRenderLoop *instance(); static void setInstance(QSGRenderLoop *instance); + static bool useConsistentTiming(); + virtual bool interleaveIncubation() const { return false; } Q_SIGNALS: diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index ba7bdbb2f479995eff7440be8ad438a37f6c20d0..88bc013306f739f87ab844cbcf941afadfc8ca12 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -55,6 +55,7 @@ #include <QtQuick/private/qsgrenderer_p.h> #include "qsgthreadedrenderloop_p.h" +#include <private/qquickanimatorcontroller_p.h> #include <private/qqmlprofilerservice_p.h> @@ -329,8 +330,6 @@ public: QOpenGLContext *gl; QSGContext *sg; - QEventLoop eventLoop; - uint pendingUpdate; uint sleeping; uint syncResultedInChanges; @@ -861,6 +860,10 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) m_thread->gl = ctx; } + QQuickAnimatorController *controller = QQuickWindowPrivate::get(window)->animationController; + if (controller->thread() != m_thread) + controller->moveToThread(m_thread); + m_thread->start(); } else { diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index c05b254b516cd0ac1e0e253bd86b0765df8dca97..904842b91e39a1b6a6279ac97836d88b6ec18d35 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -42,6 +42,8 @@ #include "qquickanimation_p.h" #include "qquickanimation_p_p.h" +#include "qquickanimatorjob_p.h" + #include <private/qquickstatechangescript_p.h> #include <private/qqmlcontext_p.h> @@ -171,8 +173,11 @@ void QQuickAbstractAnimationPrivate::commence() delete oldInstance; if (animationInstance) { - if (oldInstance != animationInstance) + if (oldInstance != animationInstance) { + if (q->threadingModel() == QQuickAbstractAnimation::RenderThread) + animationInstance = new QQuickAnimatorProxyJob(animationInstance, q); animationInstance->addAnimationChangeListener(this, QAbstractAnimationJob::Completion); + } animationInstance->start(); if (animationInstance->isStopped()) { running = false; @@ -643,6 +648,11 @@ void QQuickAbstractAnimationPrivate::animationFinished(QAbstractAnimationJob*) } } +QQuickAbstractAnimation::ThreadingModel QQuickAbstractAnimation::threadingModel() const +{ + return GuiThread; +} + /*! \qmltype PauseAnimation \instantiates QQuickPauseAnimation @@ -1713,6 +1723,21 @@ QQuickSequentialAnimation::~QQuickSequentialAnimation() { } +QQuickAbstractAnimation::ThreadingModel QQuickSequentialAnimation::threadingModel() const +{ + Q_D(const QQuickAnimationGroup); + + ThreadingModel style = AnyThread; + for (int i=0; i<d->animations.size(); ++i) { + ThreadingModel ces = d->animations.at(i)->threadingModel(); + if (ces == GuiThread) + return GuiThread; + else if (ces == RenderThread) + style = RenderThread; + } + return style; +} + QAbstractAnimationJob* QQuickSequentialAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -1729,14 +1754,19 @@ QAbstractAnimationJob* QQuickSequentialAnimation::transition(QQuickStateActions from = d->animations.count() - 1; } + ThreadingModel execution = threadingModel(); + bool valid = d->defaultProperty.isValid(); QAbstractAnimationJob* anim; for (int ii = from; ii < d->animations.count() && ii >= 0; ii += inc) { if (valid) d->animations.at(ii)->setDefaultTarget(d->defaultProperty); anim = d->animations.at(ii)->transition(actions, modified, direction, defaultTarget); - if (anim) + if (anim) { + if (d->animations.at(ii)->threadingModel() == RenderThread && execution != RenderThread) + anim = new QQuickAnimatorProxyJob(anim, this); inc == -1 ? ag->prependAnimation(anim) : ag->appendAnimation(anim); + } } return initInstance(ag); @@ -1782,6 +1812,23 @@ QQuickParallelAnimation::~QQuickParallelAnimation() { } +QQuickAbstractAnimation::ThreadingModel QQuickParallelAnimation::threadingModel() const +{ + Q_D(const QQuickAnimationGroup); + + ThreadingModel style = AnyThread; + for (int i=0; i<d->animations.size(); ++i) { + ThreadingModel ces = d->animations.at(i)->threadingModel(); + if (ces == GuiThread) + return GuiThread; + else if (ces == RenderThread) + style = RenderThread; + } + return style; +} + + + QAbstractAnimationJob* QQuickParallelAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -1790,14 +1837,19 @@ QAbstractAnimationJob* QQuickParallelAnimation::transition(QQuickStateActions &a Q_D(QQuickAnimationGroup); QParallelAnimationGroupJob *ag = new QParallelAnimationGroupJob; + ThreadingModel style = threadingModel(); + bool valid = d->defaultProperty.isValid(); QAbstractAnimationJob* anim; for (int ii = 0; ii < d->animations.count(); ++ii) { if (valid) d->animations.at(ii)->setDefaultTarget(d->defaultProperty); anim = d->animations.at(ii)->transition(actions, modified, direction, defaultTarget); - if (anim) + if (anim) { + if (d->animations.at(ii)->threadingModel() == RenderThread && style != RenderThread) + anim = new QQuickAnimatorProxyJob(anim, this); ag->appendAnimation(anim); + } } return initInstance(ag); } @@ -2034,6 +2086,8 @@ void QQuickPropertyAnimation::setTo(const QVariant &t) \qmlproperty real QtQuick2::PropertyAnimation::easing.overshoot \qmlproperty real QtQuick2::PropertyAnimation::easing.period \qmlproperty list<real> QtQuick2::PropertyAnimation::easing.bezierCurve + +//! propertyanimation.easing \brief Specifies the easing curve used for the animation To specify an easing curve you need to specify at least the type. For some curves you can also specify @@ -2235,6 +2289,7 @@ void QQuickPropertyAnimation::setTo(const QVariant &t) See the \l {qml/animation/easing}{easing} example for a demonstration of the different easing settings. +//! propertyanimation.easing */ QEasingCurve QQuickPropertyAnimation::easing() const { diff --git a/src/quick/util/qquickanimation_p.h b/src/quick/util/qquickanimation_p.h index 82d1ba269e9f11cafa8ac4c6aceb86c7e57b1a00..8851bed9696a0c83741149f3a30b32dfac8d8018 100644 --- a/src/quick/util/qquickanimation_p.h +++ b/src/quick/util/qquickanimation_p.h @@ -73,6 +73,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAbstractAnimation : public QObject, public QQ Q_CLASSINFO("DefaultMethod", "start()") public: + enum ThreadingModel { + GuiThread, + RenderThread, + AnyThread + }; + QQuickAbstractAnimation(QObject *parent=0); virtual ~QQuickAbstractAnimation(); @@ -102,6 +108,8 @@ public: void classBegin(); void componentComplete(); + virtual ThreadingModel threadingModel() const; + Q_SIGNALS: void started(); void stopped(); @@ -421,6 +429,7 @@ public: virtual ~QQuickSequentialAnimation(); protected: + virtual ThreadingModel threadingModel() const; virtual QAbstractAnimationJob* transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -437,6 +446,7 @@ public: virtual ~QQuickParallelAnimation(); protected: + virtual ThreadingModel threadingModel() const; virtual QAbstractAnimationJob* transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, diff --git a/src/quick/util/qquickanimationcontroller.cpp b/src/quick/util/qquickanimationcontroller.cpp index dd9ced4bd9b0aa683e326057922d965f19515f34..caf1408bb352205562920df883a7ebdad63cb315 100644 --- a/src/quick/util/qquickanimationcontroller.cpp +++ b/src/quick/util/qquickanimationcontroller.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the QtQuick module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage diff --git a/src/quick/util/qquickanimationcontroller_p.h b/src/quick/util/qquickanimationcontroller_p.h index 5286e7753494c7545fd2518570d1becb88717918..b11a602f327ef003444bcbc6337f09ad97cd0b25 100644 --- a/src/quick/util/qquickanimationcontroller_p.h +++ b/src/quick/util/qquickanimationcontroller_p.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the QtQuick module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage diff --git a/src/quick/util/qquickanimator.cpp b/src/quick/util/qquickanimator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6f9f20aae589dd839b75f38be27666c1f1233af --- /dev/null +++ b/src/quick/util/qquickanimator.cpp @@ -0,0 +1,565 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickanimator_p_p.h" +#include "qquickanimatorjob_p.h" + +#include <private/qquickitem_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Animator + \instantiates QQuickAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief Is the base of all QML animators. + + Animator types are a special type of animation which operate + directly on Qt Quick's scene graph, rather than the QML objects and their + properties like regular Animation types do. This has the benefit that + Animator based animations can animate on the \l + {Threaded Render Loop}{scene graph's rendering thread} even when the + UI thread is blocked. + + The value of the QML property will be updated after the animation has + finished. The property is not updated while the animation is running. + + The Animator types can be used just like any other Animation type. + + \snippet qml/animators.qml mixed + + If all sub-animations of ParallelAnimation and SequentialAnimation + are Animator types, the ParallelAnimation and SequentialAnimation will + also be treated as an Animator and be run on the scene graph's rendering + thread when possible. + + The Animator type cannot be used directly in a QML file. It exists + to provide a set of common properties and methods, available across all the + other animator types that inherit from it. Attempting to use the Animator + type directly will result in an error. + */ + +QQuickAnimator::QQuickAnimator(QQuickAnimatorPrivate &dd, QObject *parent) + : QQuickAbstractAnimation(dd, parent) +{ +} + +QQuickAnimator::QQuickAnimator(QObject *parent) + : QQuickAbstractAnimation(*new QQuickAnimatorPrivate, parent) +{ +} + +/*! + \qmlproperty QtQuick2::Item QtQuick2::Animator::target + + This property holds the target item of the animator. + + \note Animator targets must be Item based types. + */ + +void QQuickAnimator::setTargetItem(QQuickItem *target) +{ + Q_D(QQuickAnimator); + if (target == d->target) + return; + d->target = target; + Q_EMIT targetItemChanged(d->target); +} + +QQuickItem *QQuickAnimator::targetItem() const +{ + Q_D(const QQuickAnimator); + return d->target; +} + +/*! + \qmlproperty int QtQuick2::Animator::duration + This property holds the duration of the animation in milliseconds. + + The default value is 250. +*/ +void QQuickAnimator::setDuration(int duration) +{ + Q_D(QQuickAnimator); + if (duration == d->duration) + return; + d->duration = duration; + Q_EMIT durationChanged(duration); +} + +int QQuickAnimator::duration() const +{ + Q_D(const QQuickAnimator); + return d->duration; +} + +/*! + \qmlpropertygroup QtQuick2::Animator::easing + \qmlproperty enumeration QtQuick2::Animator::easing.type + \qmlproperty real QtQuick2::Animator::easing.amplitude + \qmlproperty real QtQuick2::Animator::easing.overshoot + \qmlproperty real QtQuick2::Animator::easing.period + \qmlproperty list<real> QtQuick2::Animator::easing.bezierCurve + \include qquickanimation.cpp propertyanimation.easing +*/ + +void QQuickAnimator::setEasing(const QEasingCurve &easing) +{ + Q_D(QQuickAnimator); + if (easing == d->easing) + return; + d->easing = easing; + Q_EMIT easingChanged(d->easing); +} + +QEasingCurve QQuickAnimator::easing() const +{ + Q_D(const QQuickAnimator); + return d->easing; +} + +/*! + \qmlproperty real QtQuick2::Animator::to + This property holds the end value for the animation. + + If the Animator is defined within a \l Transition or \l Behavior, + this value defaults to the value defined in the end state of the + \l Transition, or the value of the property change that triggered the + \l Behavior. + */ + +void QQuickAnimator::setTo(qreal to) +{ + Q_D(QQuickAnimator); + if (to == d->to) + return; + d->isToDefined = true; + d->to = to; + Q_EMIT toChanged(d->to); +} + +qreal QQuickAnimator::to() const +{ + Q_D(const QQuickAnimator); + return d->to; +} + +/*! + \qmlproperty real QtQuick2::Animator::from + This property holds the starting value for the animation. + + If the Animator is defined within a \l Transition or \l Behavior, + this value defaults to the value defined in the starting state of the + \l Transition, or the current value of the property at the moment the + \l Behavior is triggered. + + \sa {Animation and Transitions in Qt Quick} +*/ + +void QQuickAnimator::setFrom(qreal from) +{ + Q_D(QQuickAnimator); + if (from == d->from) + return; + d->isFromDefined = true; + d->from = from; + Q_EMIT fromChanged(d->from); +} + +qreal QQuickAnimator::from() const +{ + Q_D(const QQuickAnimator); + return d->from; +} + +void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, + const QString &propertyName, + QQuickStateActions &actions, + QQmlProperties &modified) +{ + + if (actions.size()) { + for (int i=0; i<actions.size(); ++i) { + QQuickAction &action = actions[i]; + if (action.property.name() != propertyName) + continue; + modified << action.property; + + job->setTarget(qobject_cast<QQuickItem *>(action.property.object())); + + if (isFromDefined) + job->setFrom(from); + else if (action.fromValue.isValid()) + job->setFrom(action.fromValue.toReal()); + else + job->setFrom(action.property.read().toReal()); + + if (isToDefined) + job->setTo(to); + else if (action.toValue.isValid()) + job->setTo(action.toValue.toReal()); + else + job->setTo(action.property.read().toReal()); + + // This magic line is in sync with what PropertyAnimation does + // and prevents the animation to end up in the "completeList" + // which forces action.toValue to be written directly to + // the item when a transition is cancelled. + action.fromValue = action.toValue; + } + } else { + job->setTarget(target); + job->setFrom(from); + job->setTo(to); + } + + if (!job->target() && defaultProperty.object()) + job->setTarget(qobject_cast<QQuickItem *>(defaultProperty.object())); + + job->setDuration(duration); + job->setLoopCount(loopCount); + job->setEasingCurve(easing); +} + +QAbstractAnimationJob *QQuickAnimator::transition(QQuickStateActions &actions, + QQmlProperties &modified, + TransitionDirection, + QObject *) +{ + Q_D(QQuickAnimator); + + if (d->defaultProperty.isValid() && propertyName() != d->defaultProperty.name()) { + qDebug() << Q_FUNC_INFO << "property name conflict..."; + return 0; + } + + QQuickAnimatorJob *job = createJob(); + if (!job) + return 0; + + d->apply(job, propertyName(), actions, modified); + + if (!job->target()) { + delete job; + return 0; + } + + return job; +} + +/*! + \qmltype XAnimator + \instantiates QQuickXAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The XAnimator type animates the x position of an Item. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of Item::x is updated after the animation has finished. + + The following snippet shows how to use a XAnimator together + with a Rectangle item. + + \snippet qml/animators.qml x target + + It is also possible to use the \c on keyword to tie the + XAnimator directly to an Item instance. + + \snippet qml/animators.qml x on + + + */ + +QQuickXAnimator::QQuickXAnimator(QObject *parent) : QQuickAnimator(parent) {} + +QQuickAnimatorJob *QQuickXAnimator::createJob() const { return new QQuickXAnimatorJob(); } + +/*! + \qmltype YAnimator + \instantiates QQuickYAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The YAnimator type animates the y position of an Item. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of Item::y is updated after the animation has finished. + + The following snippet shows how to use a YAnimator together + with a Rectangle item. + + \snippet qml/animators.qml y target + + It is also possible to use the \c on keyword to tie the + YAnimator directly to an Item instance. + + \snippet qml/animators.qml y on + + + */ + +QQuickYAnimator::QQuickYAnimator(QObject *parent) : QQuickAnimator(parent) {} + +QQuickAnimatorJob *QQuickYAnimator::createJob() const { return new QQuickYAnimatorJob(); } + +/*! + \qmltype ScaleAnimator + \instantiates QQuickScaleAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The ScaleAnimator type animates the scale factor of an Item. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of Item::scale is updated after the animation has finished. + + The following snippet shows how to use a ScaleAnimator together + with a Rectangle item. + + \snippet qml/animators.qml scale target + + It is also possible to use the \c on keyword to tie the + ScaleAnimator directly to an Item instance. + + \snippet qml/animators.qml scale on + + \sa Item::transformOrigin, RotationAnimator + */ + +QQuickScaleAnimator::QQuickScaleAnimator(QObject *parent) : QQuickAnimator(parent) {} + +QQuickAnimatorJob *QQuickScaleAnimator::createJob() const { return new QQuickScaleAnimatorJob(); } + +/*! + \qmltype OpacityAnimator + \instantiates QQuickOpacityAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The OpacityAnimator type animates the opacity of an Item. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of Item::opacity is updated after the animation has finished. + + The following snippet shows how to use a OpacityAnimator together + with a Rectangle item. + + \snippet qml/animators.qml opacity target + + It is also possible to use the \c on keyword to tie the + OpacityAnimator directly to an Item instance. + + \snippet qml/animators.qml opacity on + + */ + +QQuickOpacityAnimator::QQuickOpacityAnimator(QObject *parent) : QQuickAnimator(parent) {} + +QQuickAnimatorJob *QQuickOpacityAnimator::createJob() const { return new QQuickOpacityAnimatorJob(); } + +/*! + \qmltype RotationAnimator + \instantiates QQuickRotationAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The RotationAnimator type animates the rotation of an Item. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of Item::rotation is updated after the animation has finished. + + The following snippet shows how to use a RotationAnimator together + with a Rectangle item. + + \snippet qml/animators.qml rotation target + + It is also possible to use the \c on keyword to tie the + RotationAnimator directly to the \c rotation property of an Item + instance. + + \snippet qml/animators.qml rotation on + + \sa Item::transformOrigin, ScaleAnimator + */ + +QQuickRotationAnimator::QQuickRotationAnimator(QObject *parent) + : QQuickAnimator(*new QQuickRotationAnimatorPrivate, parent) +{ +} + +QQuickAnimatorJob *QQuickRotationAnimator::createJob() const { + Q_D(const QQuickRotationAnimator); + QQuickRotationAnimatorJob *job = new QQuickRotationAnimatorJob(); + job->setDirection(d->direction); + return job; +} + +/*! + \qmlproperty enumeration QtQuick2::RotationAnimator::direction + This property holds the direction of the rotation. + + Possible values are: + + \list + \li RotationAnimator.Numerical (default) - Rotate by linearly interpolating between the two numbers. + A rotation from 10 to 350 will rotate 340 degrees clockwise. + \li RotationAnimator.Clockwise - Rotate clockwise between the two values + \li RotationAnimator.Counterclockwise - Rotate counterclockwise between the two values + \li RotationAnimator.Shortest - Rotate in the direction that produces the shortest animation path. + A rotation from 10 to 350 will rotate 20 degrees counterclockwise. + \endlist +*/ +void QQuickRotationAnimator::setDirection(RotationDirection dir) +{ + Q_D(QQuickRotationAnimator); + if (d->direction == dir) + return; + d->direction = dir; + Q_EMIT directionChanged(d->direction); +} + +QQuickRotationAnimator::RotationDirection QQuickRotationAnimator::direction() const +{ + Q_D(const QQuickRotationAnimator); + return d->direction; +} + +/*! + \qmltype UniformAnimator + \instantiates QQuickUniformAnimator + \inqmlmodule QtQuick 2 + \since QtQuick 2.2 + \ingroup qtquick-transitions-animations + \brief The UniformAnimator type animates a uniform of a ShaderEffect. + + \l{Animator} types are different from normal Animation types. When + using an Animator, the animation can be run in the render thread + and the property value will jump to the end when the animation is + complete. + + The value of the QML property defining the uniform is updated after + the animation has finished. + + The following snippet shows how to use a UniformAnimator together + with a ShaderEffect item. + + \snippet qml/animators.qml shader target + + It is also possible to use the \c on keyword to tie the + UniformAnimator directly to a uniform of a ShaderEffect + instance. + + \snippet qml/animators.qml shader on + + \sa ShaderEffect, ShaderEffectSource + */ + +QQuickUniformAnimator::QQuickUniformAnimator(QObject *parent) + : QQuickAnimator(*new QQuickUniformAnimatorPrivate, parent) +{ +} + +/*! + \qmlproperty string QtQuick2::UniformAnimator::uniform + This property holds the name of the uniform to animate. + + The value of the uniform must correspond to both a property + on the target ShaderEffect and must be a uniform of type + \c float in the fragment or vertex shader. + */ +void QQuickUniformAnimator::setUniform(const QString &uniform) +{ + Q_D(QQuickUniformAnimator); + if (d->uniform == uniform) + return; + d->uniform = uniform; + Q_EMIT uniformChanged(d->uniform); +} + +QString QQuickUniformAnimator::uniform() const +{ + Q_D(const QQuickUniformAnimator); + return d->uniform; +} + +QString QQuickUniformAnimator::propertyName() const +{ + Q_D(const QQuickUniformAnimator); + if (!d->uniform.isEmpty()) + return d->uniform; + return d->defaultProperty.name(); +} + +QQuickAnimatorJob *QQuickUniformAnimator::createJob() const +{ + QString u = propertyName(); + if (u.isEmpty()) + return 0; + + QQuickUniformAnimatorJob *job = new QQuickUniformAnimatorJob(); + job->setUniform(u.toLatin1()); + return job; +} + +QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h new file mode 100644 index 0000000000000000000000000000000000000000..e5916c624c9088e6cb0912e64f02c40197be20a1 --- /dev/null +++ b/src/quick/util/qquickanimator_p.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATOR_P_H +#define QQUICKANIMATOR_P_H + +#include "qquickanimation_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickItem; + +class QQuickAnimatorJob; +class QQuickAnimatorPrivate; +class Q_QUICK_PRIVATE_EXPORT QQuickAnimator : public QQuickAbstractAnimation +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQuickAnimator) + Q_PROPERTY(QQuickItem *target READ targetItem WRITE setTargetItem NOTIFY targetItemChanged) + Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged) + Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) + Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged) + Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged) + +public: + QQuickItem *targetItem() const; + void setTargetItem(QQuickItem *target); + + int duration() const; + void setDuration(int duration); + + QEasingCurve easing() const; + void setEasing(const QEasingCurve & easing); + + qreal to() const; + void setTo(qreal to); + + qreal from() const; + void setFrom(qreal from); + +protected: + ThreadingModel threadingModel() const { return RenderThread; } + virtual QQuickAnimatorJob *createJob() const = 0; + virtual QString propertyName() const = 0; + QAbstractAnimationJob *transition(QQuickStateActions &actions, + QQmlProperties &modified, + TransitionDirection, + QObject *); + + QQuickAnimator(QQuickAnimatorPrivate &dd, QObject *parent = 0); + QQuickAnimator(QObject *parent = 0); + +Q_SIGNALS: + void targetItemChanged(QQuickItem *); + void durationChanged(int duration); + void easingChanged(const QEasingCurve &curve); + void toChanged(qreal to); + void fromChanged(qreal from); +}; + +class QQuickScaleAnimatorPrivate; +class Q_QUICK_PRIVATE_EXPORT QQuickScaleAnimator : public QQuickAnimator +{ + Q_OBJECT +public: + QQuickScaleAnimator(QObject *parent = 0); +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const { return QStringLiteral("scale"); } +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickXAnimator : public QQuickAnimator +{ + Q_OBJECT +public: + QQuickXAnimator(QObject *parent = 0); +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const{ return QStringLiteral("x"); } +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickYAnimator : public QQuickAnimator +{ + Q_OBJECT +public: + QQuickYAnimator(QObject *parent = 0); +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const { return QStringLiteral("y"); } +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimator : public QQuickAnimator +{ + Q_OBJECT +public: + QQuickOpacityAnimator(QObject *parent = 0); +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const { return QStringLiteral("opacity"); } +}; + +class QQuickRotationAnimatorPrivate; +class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimator : public QQuickAnimator +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQuickRotationAnimator) + Q_PROPERTY(RotationDirection direction READ direction WRITE setDirection NOTIFY directionChanged) + + Q_ENUMS(RotationDirection) + +public: + enum RotationDirection { Numerical, Shortest, Clockwise, Counterclockwise }; + + QQuickRotationAnimator(QObject *parent = 0); + + void setDirection(RotationDirection dir); + RotationDirection direction() const; + +Q_SIGNALS: + void directionChanged(RotationDirection dir); + +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const { return QStringLiteral("rotation"); } +}; + +class QQuickUniformAnimatorPrivate; +class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimator : public QQuickAnimator +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQuickUniformAnimator) + Q_PROPERTY(QString uniform READ uniform WRITE setUniform NOTIFY uniformChanged) + +public: + QQuickUniformAnimator(QObject *parent = 0); + + QString uniform() const; + void setUniform(const QString &); + +Q_SIGNALS: + void uniformChanged(const QString &); + +protected: + QQuickAnimatorJob *createJob() const; + QString propertyName() const; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickAnimator) +QML_DECLARE_TYPE(QQuickXAnimator) +QML_DECLARE_TYPE(QQuickYAnimator) +QML_DECLARE_TYPE(QQuickScaleAnimator) +QML_DECLARE_TYPE(QQuickRotationAnimator) +QML_DECLARE_TYPE(QQuickOpacityAnimator) +QML_DECLARE_TYPE(QQuickUniformAnimator) + +#endif // QQUICKANIMATOR_P_H diff --git a/src/quick/util/qquickanimator_p_p.h b/src/quick/util/qquickanimator_p_p.h new file mode 100644 index 0000000000000000000000000000000000000000..cc25496a8ffd760cbe8722d65219a2a253d09e57 --- /dev/null +++ b/src/quick/util/qquickanimator_p_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATOR_P_P_H +#define QQUICKANIMATOR_P_P_H + +#include "qquickanimator_p.h" +#include "qquickanimation_p_p.h" +#include <QtQuick/qquickitem.h> + +QT_BEGIN_NAMESPACE + +class QQuickAnimatorJob; + +class QQuickAnimatorPrivate : public QQuickAbstractAnimationPrivate +{ + Q_DECLARE_PUBLIC(QQuickAnimator) +public: + QQuickAnimatorPrivate() + : target(0) + , duration(250) + , from(0) + , to(0) + , isFromDefined(false) + , isToDefined(false) + { + } + + QPointer<QQuickItem> target; + int duration; + QEasingCurve easing; + qreal from; + qreal to; + + uint isFromDefined : 1; + uint isToDefined : 1; + + void apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified); +}; + +class QQuickRotationAnimatorPrivate : public QQuickAnimatorPrivate +{ +public: + QQuickRotationAnimatorPrivate() + : direction(QQuickRotationAnimator::Numerical) + { + } + QQuickRotationAnimator::RotationDirection direction; +}; + +class QQuickUniformAnimatorPrivate : public QQuickAnimatorPrivate +{ +public: + QString uniform; +}; + +QT_END_NAMESPACE + +#endif // QQUICKANIMATOR_P_P_H diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73d2882c052e5e6cc1f19117744ce8fb9cb9d5ea --- /dev/null +++ b/src/quick/util/qquickanimatorcontroller.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickanimatorcontroller_p.h" + +#include <private/qquickwindow_p.h> +#include <private/qsgrenderloop_p.h> + +#include <private/qanimationgroupjob_p.h> + +#include <QtGui/qscreen.h> + +QT_BEGIN_NAMESPACE + +QQuickAnimatorController::QQuickAnimatorController() + : window(0) + , driver(0) +{ +} + +QQuickAnimatorController::~QQuickAnimatorController() +{ + qDeleteAll(activeRootAnimations); +} + +void QQuickAnimatorController::advance() +{ + if (driver && driver->isRunning()) { + // This lock is to prevent conflicts with syncBackCurrentValues + mutex.lock(); + driver->advance(); + mutex.unlock(); + } + + // The animation system uses a chain of queued connections to + // start the animation driver and these won't get delievered until, + // at best, after this frame. We need to track if animations + // are running here so we can keep on rendering in that case. + bool running = driver && driver->isRunning(); + for (QSet<QAbstractAnimationJob *>::const_iterator it = activeRootAnimations.constBegin(); + !running && it != activeRootAnimations.constEnd(); ++it) { + if ((*it)->isRunning()) + running = true; + } + + for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin(); + it != activeLeafAnimations.constEnd(); ++it) { + if ((*it)->isTransform()) { + QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it); + xform->transformHelper()->apply(); + } + } + + if (running) + window->update(); +} + +static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c) +{ + if (job->isRenderThreadJob()) { + QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job); + j->initialize(c); + } else if (job->isGroup()) { + QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job); + for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling()) + qquick_initialize_helper(a, c); + } +} + +void QQuickAnimatorController::beforeNodeSync() +{ + if (!driver && window->thread() != window->openglContext()->thread()) { + driver = QQuickWindowPrivate::get(window)->context->createAnimationDriver(this); + connect(driver, SIGNAL(started()), this, SLOT(animationsStarted()), Qt::DirectConnection); + connect(driver, SIGNAL(stopped()), this, SLOT(animationsStopped()), Qt::DirectConnection); + driver->install(); + + QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming()); + } + + // Force a render pass if we are adding new animations + // so that advance will be called.. + if (starting.size()) + window->update(); + + for (int i=0; i<starting.size(); ++i) { + QAbstractAnimationJob *job = starting.at(i); + qquick_initialize_helper(job, this); + job->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange); + job->start(); + } + starting.clear(); + + for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin(); + it != activeLeafAnimations.constEnd(); ++it) { + if ((*it)->isTransform()) { + QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it); + xform->transformHelper()->sync(); + } + } +} + +void QQuickAnimatorController::afterNodeSync() +{ + for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin(); + it != activeLeafAnimations.constEnd(); ++it) { + if ((*it)->isUniform()) { + QQuickUniformAnimatorJob *job = static_cast<QQuickUniformAnimatorJob *>(*it); + job->afterNodeSync(); + } + } +} + + +void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job) +{ + mutex.lock(); + starting << job; + mutex.unlock(); +} + +void QQuickAnimatorController::animationsStopped() +{ +} + +void QQuickAnimatorController::animationsStarted() +{ + window->update(); +} + +void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job, + QAbstractAnimationJob::State newState, + QAbstractAnimationJob::State) +{ + if (newState == QAbstractAnimationJob::Running) + activeRootAnimations << job; + else + activeRootAnimations.remove(job); +} + +bool QQuickAnimatorController::event(QEvent *e) +{ + if ((int) e->type() == StopAnimation) { + QAbstractAnimationJob *job = static_cast<Event *>(e)->job; + mutex.lock(); + starting.removeOne(job); + mutex.unlock(); + job->stop(); + return true; + + } else if ((uint) e->type() == DeleteAnimation) { + QAbstractAnimationJob *job = static_cast<Event *>(e)->job; + mutex.lock(); + starting.removeOne(job); + mutex.unlock(); + job->stop(); + delete job; + return true; + } + + return QObject::event(e); +} + +QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h new file mode 100644 index 0000000000000000000000000000000000000000..1c79e3c493c9559001a3eef9c0d7c0d988ee2515 --- /dev/null +++ b/src/quick/util/qquickanimatorcontroller_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATORCONTROLLER_P_H +#define QQUICKANIMATORCONTROLLER_P_H + +#include "qquickanimatorjob_p.h" +#include <QtQuick/qsgnode.h> +#include <QtQuick/qquickitem.h> + +#include <QtCore/qmutex.h> + +QT_BEGIN_NAMESPACE + +class QQuickAnimatorController : public QObject, public QAnimationJobChangeListener +{ + Q_OBJECT + +public: + + enum EventType { + // GUI to RT events + StartAnimation = QEvent::User + 1, + StopAnimation, + DeleteAnimation, + + // RT back to GUI events + AnimationFinished + }; + + class Event : public QEvent { + public: + Event(QAbstractAnimationJob *j, EventType type) + : QEvent(QEvent::Type(type)) + , job(j) + { + } + QAbstractAnimationJob *job; + }; + + QQuickAnimatorController(); + ~QQuickAnimatorController(); + + void advance(); + void beforeNodeSync(); + void afterNodeSync(); + + bool event(QEvent *); + + void startAnimation(QAbstractAnimationJob *job); + + void animationStateChanged(QAbstractAnimationJob *job, + QAbstractAnimationJob::State newState, + QAbstractAnimationJob::State oldState); + +public Q_SLOTS: + void animationsStarted(); + void animationsStopped(); + +public: + QList<QAbstractAnimationJob *> starting; + QList<QAbstractAnimationJob *> stopped; + + QSet<QAbstractAnimationJob *> activeRootAnimations; + QSet<QQuickAnimatorJob *> activeLeafAnimations; + + QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> transforms; + + QQuickWindow *window; + + QAnimationDriver *driver; + + QMutex mutex; +}; + +QT_END_NAMESPACE + +#endif // QQUICKANIMATORCONTROLLER_P_H diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3270faa652ae434a120cd82cc2ae273991a673a9 --- /dev/null +++ b/src/quick/util/qquickanimatorjob.cpp @@ -0,0 +1,532 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickanimatorcontroller_p.h" +#include "qquickanimatorjob_p.h" +#include "qquickanimator_p.h" +#include "qquickanimator_p_p.h" +#include <private/qquickwindow_p.h> +#include <private/qquickitem_p.h> +#include <private/qquickshadereffectnode_p.h> + +#include <private/qanimationgroupjob_p.h> + +#include <qcoreapplication.h> + +QT_BEGIN_NAMESPACE + +QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObject *item) + : m_controller(0) + , m_job(job) + , m_internalState(State_Stopped) +{ + m_isRenderThreadProxy = true; + m_animation = qobject_cast<QQuickAbstractAnimation *>(item); + + setLoopCount(job->loopCount()); + + // Instead of setting duration to job->duration() we need to set it to -1 so that + // it runs as long as the job is running on the render thread. If we gave it + // an explicit duration, it would be stopped, potentially stopping the RT animation + // prematurely. + // This means that the animation driver will tick on the GUI thread as long + // as the animation is running on the render thread, but this overhead will + // be negligiblie compared to animating and re-rendering the scene on the render thread. + m_duration = -1; + + job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion); + + QObject *ctx = findAnimationContext(m_animation); + if (!ctx) { + qWarning("QtQuick: unable to find animation context for RT animation..."); + return; + } + + QQuickWindow *window = qobject_cast<QQuickWindow *>(ctx); + if (window) { + setWindow(window); + } else { + QQuickItem *item = qobject_cast<QQuickItem *>(ctx); + if (item->window()) + setWindow(item->window()); + else + connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(windowChanged(QQuickWindow*))); + } +} + +QQuickAnimatorProxyJob::~QQuickAnimatorProxyJob() +{ + deleteJob(); +} + +void QQuickAnimatorProxyJob::deleteJob() +{ + if (m_job) { + if (m_controller && m_internalState != State_Starting) + QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::DeleteAnimation)); + else + delete m_job; + m_job = 0; + } +} + +QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a) +{ + QObject *p = a->parent(); + while (p != 0 && qobject_cast<QQuickWindow *>(p) == 0 && qobject_cast<QQuickItem *>(p) == 0) + p = p->parent(); + return p; +} + +void QQuickAnimatorProxyJob::updateCurrentTime(int) +{ +} + +void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State) +{ + if (m_state == Running) { + if (m_controller) { + m_internalState = State_Running; + startOnRenderThread(); + } else { + m_internalState = State_Starting; + } + } else if (newState == Stopped) { + syncBackCurrentValues(); + if (m_internalState == State_Starting) + m_internalState = State_Stopped; + else { + QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::StopAnimation)); + } + } +} + +void QQuickAnimatorProxyJob::windowChanged(QQuickWindow *window) +{ + setWindow(window); +} + +void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) +{ + if (m_controller) { + stop(); + deleteJob(); + m_controller = 0; + } + if (!window) + return; + + m_controller = QQuickWindowPrivate::get(window)->animationController; + + if (window->openglContext()) + readyToAnimate(); + else + connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(sceneGraphInitialized())); +} + +void QQuickAnimatorProxyJob::sceneGraphInitialized() +{ + readyToAnimate(); + disconnect(this, SLOT(sceneGraphInitialized())); +} + +void QQuickAnimatorProxyJob::readyToAnimate() +{ + if (m_internalState == State_Starting) { + startOnRenderThread(); + } +} + +void QQuickAnimatorProxyJob::animationFinished(QAbstractAnimationJob *job) +{ + QCoreApplication::postEvent(this, new QQuickAnimatorController::Event(job, QQuickAnimatorController::AnimationFinished)); +} + +bool QQuickAnimatorProxyJob::event(QEvent *e) +{ + if ((uint) e->type() == QQuickAnimatorController::AnimationFinished) { + // Update the duration of this proxy to the current time and stop it so + // that parent animations can progress gracefully + m_duration = m_currentTime; + stop(); + return true; + } + + return QObject::event(e); +} + +void QQuickAnimatorProxyJob::startOnRenderThread() +{ + m_internalState = State_Running; + // Force a "sync" pass as the newly started animation needs to sync properties from GUI. + m_controller->startAnimation(m_job); + QQuickWindowPrivate::get(m_controller->window)->dirtyItem(0); +} + +static void qquick_syncback_helper(QAbstractAnimationJob *job) +{ + if (job->isRenderThreadJob()) { + QQuickAnimatorJob *a = static_cast<QQuickAnimatorJob *>(job); + if (a->controller()) + a->writeBack(); + } else if (job->isGroup()) { + QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job); + for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling()) + qquick_syncback_helper(a); + } +} + +void QQuickAnimatorProxyJob::syncBackCurrentValues() +{ + qquick_syncback_helper(m_job); +} + +QQuickAnimatorJob::QQuickAnimatorJob() + : m_target(0) + , m_controller(0) + , m_from(0) + , m_to(0) + , m_value(0) + , m_duration(0) + , m_isTransform(false) + , m_isUniform(false) +{ + m_isRenderThreadJob = true; +} + +qreal QQuickAnimatorJob::value() const +{ + qreal v; + m_controller->mutex.lock(); + v = m_value; + m_controller->mutex.unlock(); + return v; +} + +void QQuickAnimatorJob::setTarget(QQuickItem *target) +{ + m_target = target; +} + +void QQuickAnimatorJob::initialize(QQuickAnimatorController *controller) +{ + m_controller = controller; +} + +void QQuickAnimatorJob::updateState(State newState, State oldState) +{ + if (newState == Running) { + m_controller->activeLeafAnimations << this; + } else if (oldState == Running) { + m_controller->activeLeafAnimations.remove(this); + } +} + +QQuickTransformAnimatorJob::QQuickTransformAnimatorJob() + : m_helper(0) +{ + m_isTransform = true; +} + +QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob() +{ + if (m_helper && --m_helper->ref == 0) { + m_controller->transforms.remove(m_helper->item); + delete m_helper; + } +} + +void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller) +{ + QQuickAnimatorJob::initialize(controller); + + m_helper = m_controller->transforms.value(m_target); + if (!m_helper) { + m_helper = new Helper(); + m_helper->item = m_target; + m_controller->transforms.insert(m_target, m_helper); + } else { + ++m_helper->ref; + } + m_helper->sync(); +} + + +void QQuickTransformAnimatorJob::Helper::sync() +{ + const quint32 mask = QQuickItemPrivate::Position + | QQuickItemPrivate::BasicTransform + | QQuickItemPrivate::TransformOrigin; + + quint32 dirty = mask & QQuickItemPrivate::get(item)->dirtyAttributes; + + if (!wasSynced) { + dirty = 0xffffffffu; + wasSynced = true; + } + + if (dirty == 0) + return; + + node = QQuickItemPrivate::get(item)->itemNode(); + + if (dirty & QQuickItemPrivate::Position) { + dx = item->x(); + dy = item->y(); + } + + if (dirty & QQuickItemPrivate::BasicTransform) { + scale = item->scale(); + rotation = item->rotation(); + } + + if (dirty & QQuickItemPrivate::TransformOrigin) { + QPointF o = item->transformOriginPoint(); + ox = o.x(); + oy = o.y(); + } +} + +void QQuickTransformAnimatorJob::Helper::apply() +{ + if (!wasChanged) + return; + + QMatrix4x4 m; + m.translate(dx, dy); + m.translate(ox, oy); + m.scale(scale); + m.rotate(rotation, 0, 0, 1); + m.translate(-ox, -oy); + node->setMatrix(m); + + wasChanged = false; +} + + + +void QQuickXAnimatorJob::writeBack() +{ + if (m_target) + m_target->setX(value()); +} + +void QQuickXAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); + m_helper->dx = m_value; + m_helper->wasChanged = true; +} + +void QQuickYAnimatorJob::writeBack() +{ + if (m_target) + m_target->setY(value()); +} + +void QQuickYAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); + m_helper->dy = m_value; + m_helper->wasChanged = true; +} + +QQuickOpacityAnimatorJob::QQuickOpacityAnimatorJob() + : m_opacityNode(0) +{ +} + +void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller) +{ + QQuickAnimatorJob::initialize(controller); + QQuickItemPrivate *d = QQuickItemPrivate::get(m_target); + m_opacityNode = d->opacityNode(); + if (!m_opacityNode) { + m_opacityNode = new QSGOpacityNode(); + d->extra.value().opacityNode = m_opacityNode; + + QSGNode *child = d->clipNode(); + if (!child) + child = d->rootNode(); + if (!child) + child = d->groupNode; + + if (child) { + if (child->parent()) + child->parent()->removeChildNode(child); + m_opacityNode->appendChildNode(child); + } + + d->itemNode()->appendChildNode(m_opacityNode); + } +} + +void QQuickOpacityAnimatorJob::writeBack() +{ + if (m_target) + m_target->setOpacity(value()); +} + +void QQuickOpacityAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); + m_opacityNode->setOpacity(m_value); +} + +void QQuickScaleAnimatorJob::writeBack() +{ + if (m_target) + m_target->setScale(value()); +} + +void QQuickScaleAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); + m_helper->scale = m_value; + m_helper->wasChanged = true; +} + +QQuickRotationAnimatorJob::QQuickRotationAnimatorJob() + : m_direction(QQuickRotationAnimator::Numerical) +{ +} + +extern QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress); +extern QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress); +extern QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress); + +void QQuickRotationAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + float t = m_easing.valueForProgress(time / (qreal) m_duration); + switch (m_direction) { + case QQuickRotationAnimator::Clockwise: + m_value = _q_interpolateClockwiseRotation(m_from, m_to, t).toFloat(); + break; + case QQuickRotationAnimator::Counterclockwise: + m_value = _q_interpolateCounterclockwiseRotation(m_from, m_to, t).toFloat(); + break; + case QQuickRotationAnimator::Shortest: + m_value = _q_interpolateShortestRotation(m_from, m_to, t).toFloat(); + break; + case QQuickRotationAnimator::Numerical: + m_value = m_from + (m_to - m_from) * t; + break; + } + m_helper->rotation = m_value; + m_helper->wasChanged = true; +} + +void QQuickRotationAnimatorJob::writeBack() +{ + if (m_target) + m_target->setRotation(value()); +} + +QQuickUniformAnimatorJob::QQuickUniformAnimatorJob() + : m_node(0) + , m_uniformIndex(-1) + , m_uniformType(-1) +{ + m_isUniform = true; +} + +void QQuickUniformAnimatorJob::setTarget(QQuickItem *target) +{ + if (qobject_cast<QQuickShaderEffect *>(target) != 0) + m_target = target; +} + +void QQuickUniformAnimatorJob::afterNodeSync() +{ + m_node = static_cast<QQuickShaderEffectNode *>(QQuickItemPrivate::get(m_target)->paintNode); + + if (m_node) { + m_uniformIndex = -1; + m_uniformType = -1; + QQuickShaderEffectMaterial *material = + static_cast<QQuickShaderEffectMaterial *>(m_node->material()); + bool found = false; + for (int t=0; !found && t<QQuickShaderEffectMaterialKey::ShaderTypeCount; ++t) { + const QVector<QQuickShaderEffectMaterial::UniformData> &uniforms = material->uniforms[t]; + for (int i=0; i<uniforms.size(); ++i) { + if (uniforms.at(i).name == m_uniform) { + m_uniformIndex = i; + m_uniformType = t; + found = true; + break; + } + } + } + } + +} + +void QQuickUniformAnimatorJob::updateCurrentTime(int time) +{ + Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread()); + + if (!m_node || m_uniformIndex == -1 || m_uniformType == -1) + return; + + m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration); + + QQuickShaderEffectMaterial *material = + static_cast<QQuickShaderEffectMaterial *>(m_node->material()); + material->uniforms[m_uniformType][m_uniformIndex].value = m_value; +} + +void QQuickUniformAnimatorJob::writeBack() +{ + if (m_target) + m_target->setProperty(m_uniform, value()); +} + +QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h new file mode 100644 index 0000000000000000000000000000000000000000..c6814523c6eae1127bf1b4741e8ac698aba38379 --- /dev/null +++ b/src/quick/util/qquickanimatorjob_p.h @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATORJOB_P_H +#define QQUICKANIMATORJOB_P_H + +#include <private/qabstractanimationjob_p.h> +#include <private/qquickanimator_p.h> +#include <private/qtquickglobal_p.h> + +#include <QtQuick/qquickitem.h> + +#include <QtCore/qeasingcurve.h> + +QT_BEGIN_NAMESPACE + +class QQuickAnimator; +class QQuickWindow; +class QQuickItem; +class QQuickAbstractAnimation; + +class QQuickAnimatorController; +class QQuickAnimatorProxyJobPrivate; +class QQuickShaderEffectNode; + +class QSGOpacityNode; + +class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorProxyJob : public QObject, public QAbstractAnimationJob, public QAnimationJobChangeListener +{ + Q_OBJECT + +public: + QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObject *item); + ~QQuickAnimatorProxyJob(); + + int duration() const { return m_duration; } + + virtual void animationFinished(QAbstractAnimationJob *); + +protected: + bool event(QEvent *); + + void updateCurrentTime(int); + void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); + +public Q_SLOTS: + void windowChanged(QQuickWindow *window); + void sceneGraphInitialized(); + +private: + void deleteJob(); + void syncBackCurrentValues(); + void readyToAnimate(); + void setWindow(QQuickWindow *window); + static QObject *findAnimationContext(QQuickAbstractAnimation *); + void startOnRenderThread(); + + QQuickAnimatorController *m_controller; + QQuickAbstractAnimation *m_animation; + QAbstractAnimationJob *m_job; + int m_duration; + + enum InternalState { + State_Starting, // Used when it should be running, but no we're still missing the controller. + State_Running, + State_Paused, + State_Stopped + }; + + InternalState m_internalState; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorJob : public QAbstractAnimationJob +{ +public: + virtual void setTarget(QQuickItem *target); + QQuickItem *target() const { return m_target; } + + void setFrom(qreal scale) { m_from = scale; } + qreal from() const { return m_from; } + + void setTo(qreal to) { m_to = to; } + qreal to() const { return m_to; } + + void setDuration(int duration) { m_duration = duration; } + int duration() const { return m_duration; } + + QEasingCurve easingCurve() const { return m_easing; } + void setEasingCurve(const QEasingCurve &curve) { m_easing = curve; } + + virtual void initialize(QQuickAnimatorController *controller); + virtual void writeBack() = 0; + + bool isTransform() const { return m_isTransform; } + bool isUniform() const { return m_isUniform; } + + qreal value() const; + + QQuickAnimatorController *controller() const { return m_controller; } + +protected: + QQuickAnimatorJob(); + void updateState(State newState, State oldState); + + QPointer<QQuickItem> m_target; + QQuickAnimatorController *m_controller; + + qreal m_from; + qreal m_to; + qreal m_value; + + QEasingCurve m_easing; + + int m_duration; + + uint m_feedback : 1; + uint m_isTransform : 1; + uint m_isUniform : 1; +}; + +class QQuickTransformAnimatorJob : public QQuickAnimatorJob +{ +public: + + struct Helper + { + Helper() + : ref(1) + , item(0) + , node(0) + , ox(0) + , oy(0) + , dx(0) + , dy(0) + , scale(1) + , rotation(0) + , wasSynced(false) + , wasChanged(false) + { + } + + void sync(); + void apply(); + + int ref; + QQuickItem *item; + QSGTransformNode *node; + + // Origin + float ox; + float oy; + + float dx; + float dy; + float scale; + float rotation; + + uint wasSynced : 1; + uint wasChanged : 1; + }; + + ~QQuickTransformAnimatorJob(); + Helper *transformHelper() const { return m_helper; } + +protected: + QQuickTransformAnimatorJob(); + void initialize(QQuickAnimatorController *controller); + + Helper *m_helper; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickScaleAnimatorJob : public QQuickTransformAnimatorJob +{ +public: + void updateCurrentTime(int time); + void writeBack(); +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickXAnimatorJob : public QQuickTransformAnimatorJob +{ +public: + void updateCurrentTime(int time); + void writeBack(); +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickYAnimatorJob : public QQuickTransformAnimatorJob +{ +public: + void updateCurrentTime(int time); + void writeBack(); +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickRotationAnimatorJob : public QQuickTransformAnimatorJob +{ +public: + QQuickRotationAnimatorJob(); + + void updateCurrentTime(int time); + void writeBack(); + + void setDirection(QQuickRotationAnimator::RotationDirection direction) { m_direction = direction; } + QQuickRotationAnimator::RotationDirection direction() const { return m_direction; } + +private: + QQuickRotationAnimator::RotationDirection m_direction; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickOpacityAnimatorJob : public QQuickAnimatorJob +{ +public: + QQuickOpacityAnimatorJob(); + + void initialize(QQuickAnimatorController *controller); + void updateCurrentTime(int time); + void writeBack(); + +private: + QSGOpacityNode *m_opacityNode; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimatorJob : public QQuickAnimatorJob +{ +public: + QQuickUniformAnimatorJob(); + + void setTarget(QQuickItem *target); + + void setUniform(const QByteArray &uniform) { m_uniform = uniform; } + QByteArray uniform() const { return m_uniform; } + + void afterNodeSync(); + + void updateCurrentTime(int time); + void writeBack(); + +private: + QByteArray m_uniform; + QQuickShaderEffectNode *m_node; + + int m_uniformIndex : 8; + int m_uniformType : 8; +}; + +QT_END_NAMESPACE + +#endif // QQUICKANIMATORJOB_P_H diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp index 2d765dc5ee21ce5f4138a0d1809d421ba486d7b0..855e99e5a9fe149b986ca8e0971d8e4ba3012aa2 100644 --- a/src/quick/util/qquickbehavior.cpp +++ b/src/quick/util/qquickbehavior.cpp @@ -49,6 +49,8 @@ #include <private/qabstractanimationjob_p.h> #include <private/qquicktransition_p.h> +#include <private/qquickanimatorjob_p.h> + #include <private/qobject_p.h> QT_BEGIN_NAMESPACE @@ -186,14 +188,18 @@ void QQuickBehavior::write(const QVariant &value) if (d->animation->isRunning() && value == d->targetValue) return; - const QVariant ¤tValue = d->property.read(); d->targetValue = value; - if (d->animationInstance && d->animationInstance->duration() != -1 + if (d->animationInstance + && (d->animationInstance->duration() != -1 + || d->animationInstance->isRenderThreadProxy()) && !d->animationInstance->isStopped()) { d->blockRunningChanged = true; d->animationInstance->stop(); } + // Render thread animations use "stop" to synchronize the property back + // to the item, so we need to read the value after. + const QVariant ¤tValue = d->property.read(); QQuickStateOperation::ActionList actions; QQuickAction action; @@ -205,6 +211,10 @@ void QQuickBehavior::write(const QVariant &value) QList<QQmlProperty> after; QAbstractAnimationJob *prev = d->animationInstance; d->animationInstance = d->animation->transition(actions, after, QQuickAbstractAnimation::Forward); + + if (d->animationInstance && d->animation->threadingModel() == QQuickAbstractAnimation::RenderThread) + d->animationInstance = new QQuickAnimatorProxyJob(d->animationInstance, d->animation); + if (prev && prev != d->animationInstance) delete prev; diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp index ead28fe49693ca05056afb634ed1887f4d5b3035..4db3fbbad762245cbd7e5dad5ba888462fb6be78 100644 --- a/src/quick/util/qquicktransition.cpp +++ b/src/quick/util/qquicktransition.cpp @@ -48,6 +48,8 @@ #include "qquickanimation_p_p.h" #include "qquicktransitionmanager_p_p.h" +#include <private/qquickanimatorjob_p.h> + #include "private/qparallelanimationgroupjob_p.h" QT_BEGIN_NAMESPACE @@ -260,8 +262,11 @@ QQuickTransitionInstance *QQuickTransition::prepare(QQuickStateOperation::Action QAbstractAnimationJob *anim = 0; for (int i = start; i != end;) { anim = d->animations.at(i)->transition(actions, after, direction, defaultTarget); - if (anim) + if (anim) { + if (d->animations.at(i)->threadingModel() == QQuickAbstractAnimation::RenderThread) + anim = new QQuickAnimatorProxyJob(anim, d->animations.at(i)); d->reversed ? group->prependAnimation(anim) : group->appendAnimation(anim); + } d->reversed ? --i : ++i; } diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index fdf83141454256b9c6cdc83d812f8962485e4281..ccde83ca6eefade9d529858f75b71e06e8a07959 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -53,6 +53,7 @@ #include "qquickstate_p_p.h" #include "qquicksystempalette_p.h" #include "qquicktransition_p.h" +#include "qquickanimator_p.h" #include <qqmlinfo.h> #include <private/qqmltypenotavailable_p.h> #include <private/qquickanimationcontroller_p.h> @@ -91,6 +92,14 @@ void QQuickUtilModule::defineModule() qmlRegisterType<QQuickTransition>("QtQuick",2,0,"Transition"); qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation"); + qmlRegisterUncreatableType<QQuickAnimator>("QtQuick", 2, 2, "Animator", QQuickAbstractAnimation::tr("Animator is an abstract class")); + qmlRegisterType<QQuickXAnimator>("QtQuick", 2, 2, "XAnimator"); + qmlRegisterType<QQuickYAnimator>("QtQuick", 2, 2, "YAnimator"); + qmlRegisterType<QQuickScaleAnimator>("QtQuick", 2, 2, "ScaleAnimator"); + qmlRegisterType<QQuickRotationAnimator>("QtQuick", 2, 2, "RotationAnimator"); + qmlRegisterType<QQuickOpacityAnimator>("QtQuick", 2, 2, "OpacityAnimator"); + qmlRegisterType<QQuickUniformAnimator>("QtQuick", 2, 2, "UniformAnimator"); + qmlRegisterType<QQuickStateOperation>(); qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser); diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 7f77f7f7020bfa56d30002dbb89c2bb1057c0010..fae1103d47a4c81fb99052d3b3f73a6a902c5653 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -22,7 +22,10 @@ SOURCES += \ $$PWD/qquickimageprovider.cpp \ $$PWD/qquicksvgparser.cpp \ $$PWD/qquickvaluetypes.cpp \ - $$PWD/qquickglobal.cpp + $$PWD/qquickglobal.cpp \ + $$PWD/qquickanimator.cpp \ + $$PWD/qquickanimatorjob.cpp \ + $$PWD/qquickanimatorcontroller.cpp HEADERS += \ $$PWD/qquickapplication_p.h\ @@ -51,4 +54,8 @@ HEADERS += \ $$PWD/qquickpathinterpolator_p.h \ $$PWD/qquickimageprovider.h \ $$PWD/qquicksvgparser_p.h \ - $$PWD/qquickvaluetypes_p.h + $$PWD/qquickvaluetypes_p.h \ + $$PWD/qquickanimator_p.h \ + $$PWD/qquickanimator_p_p.h \ + $$PWD/qquickanimatorjob_p.h \ + $$PWD/qquickanimatorcontroller_p.h diff --git a/tests/auto/quick/qquickanimators/data/Box.qml b/tests/auto/quick/qquickanimators/data/Box.qml new file mode 100644 index 0000000000000000000000000000000000000000..cff3e7f92943e8390ac1ac1c9265fedbb9d885cb --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/Box.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 + +Rectangle { + id: box + gradient: Gradient { + GradientStop { position: 0.1; color: "red" } + GradientStop { position: 0.9; color: "blue" } + } + width: 100 + height: 100 + anchors.centerIn: parent + antialiasing: true + + property int rotationChangeCounter: 0 + onRotationChanged: ++rotationChangeCounter; + + property int scaleChangeCounter: 0 + onScaleChanged: ++scaleChangeCounter; + + property int opacityChangeCounter: 0 + onOpacityChanged: ++opacityChangeCounter + + property int xChangeCounter: 0; + onXChanged: ++xChangeCounter; + + property int yChangeCounter: 0; + onYChanged: ++yChangeCounter; + +} diff --git a/tests/auto/quick/qquickanimators/data/tst_behavior.qml b/tests/auto/quick/qquickanimators/data/tst_behavior.qml new file mode 100644 index 0000000000000000000000000000000000000000..b22cc93b097c57bcdd68941e0e36ea7116520370 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_behavior.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "behavior" + when: box.scale == 2 + function test_endresult() { + compare(box.scaleChangeCounter, 1); + compare(box.scale, 2); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(1, 0, 0, 1)); + compare(image.pixel(199, 199), Qt.rgba(0, 0, 1, 1)); + } + } + + Box { + id: box + Behavior on scale { ScaleAnimator { id: animation; duration: 300; } } + } + + Timer { + interval: 1000; + repeat: false + running: true + onTriggered: box.scale = 2 + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_mixedparallel.qml b/tests/auto/quick/qquickanimators/data/tst_mixedparallel.qml new file mode 100644 index 0000000000000000000000000000000000000000..9cd28f2493d8b68fec7bc2d150e236763a1339d8 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_mixedparallel.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "mixedparallel" + when: !animation.running + function test_endresult() { + compare(box.rotationChangeCounter, 1); + compare(box.scale, 2); + compare(box.rotation, 180); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(0, 0, 1, 1)); + compare(image.pixel(199, 199), Qt.rgba(1, 0, 0, 1)); + } + } + + Box { + id: box + ParallelAnimation { + id: animation + NumberAnimation { target: box; property: "scale"; from: 1; to: 2.0; duration: 1000; } + RotationAnimator { target: box; from: 0; to: 180; duration: 1000; } + running: true + loops: 1; + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_mixedsequential.qml b/tests/auto/quick/qquickanimators/data/tst_mixedsequential.qml new file mode 100644 index 0000000000000000000000000000000000000000..4c62bc801865e0d8caa90214caded4e5484b9435 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_mixedsequential.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "mixedsequential" + when: !animation.running + function test_endresult() { + compare(box.rotationChangeCounter, 1); + compare(box.scale, 2); + compare(box.rotation, 180); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(0, 0, 1, 1)); + compare(image.pixel(199, 199), Qt.rgba(1, 0, 0, 1)); + } + } + + Box { + id: box + ParallelAnimation { + id: animation + NumberAnimation { target: box; property: "scale"; from: 1; to: 2.0; duration: 500; } + RotationAnimator { target: box; from: 0; to: 180; duration: 500; } + running: true + loops: 1; + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_nested.qml b/tests/auto/quick/qquickanimators/data/tst_nested.qml new file mode 100644 index 0000000000000000000000000000000000000000..95cb70cb482369acd46303430040b44220551405 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_nested.qml @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "nested" + when: !animation.running + function test_endresult() { + compare(box.before, 2); + compare(box.after, 2); + } + } + + Box { + id: box + + anchors.centerIn: undefined + + property int before: 0; + property int after: 0; + + SequentialAnimation { + id: animation; + ScriptAction { script: box.before++; } + ParallelAnimation { + ScaleAnimator { target: box; from: 2.0; to: 1; duration: 500; } + OpacityAnimator { target: box; from: 0; to: 1; duration: 500; } + } + PauseAnimation { duration: 500 } + SequentialAnimation { + ParallelAnimation { + XAnimator { target: box; from: 0; to: 100; duration: 500} + RotationAnimator { target: box; from: 0; to: 90; duration: 500 } + } + ParallelAnimation { + XAnimator { target: box; from: 100; to: 0; duration: 500 } + RotationAnimator { target: box; from: 90; to: 0; duration: 500 } + } + } + ScriptAction { script: box.after++; } + running: true + loops: 2 + } + } + +} diff --git a/tests/auto/quick/qquickanimators/data/tst_on.qml b/tests/auto/quick/qquickanimators/data/tst_on.qml new file mode 100644 index 0000000000000000000000000000000000000000..e48d7107f9268d2a7ed8eb168eafeebf9df78a54 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_on.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "on" + when: !animx.running && !animy.running + && !anims.running && !animr.running + && !animo.running; + function test_endresult() { + compare(box.xChangeCounter, 1); + compare(box.yChangeCounter, 1); + compare(box.scaleChangeCounter, 1); + compare(box.rotationChangeCounter, 1); + compare(box.opacityChangeCounter, 1); + compare(box.x, 100); + compare(box.y, 100); + compare(box.scale, 2); + compare(box.rotation, 180); + compare(box.opacity, 0.5); + } + } + + Box { + id: box + anchors.centerIn: undefined + XAnimator on x { id: animx; from: 0; to: 100; duration: 1000 } + YAnimator on y { id: animy; from: 0; to: 100; duration: 1000 } + ScaleAnimator on scale { id: anims; from: 1; to: 2; duration: 1000 } + RotationAnimator on rotation { id: animr ; from: 0; to: 180; duration: 1000 } + OpacityAnimator on opacity { id: animo; from: 1; to: 0.5; duration: 1000 } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_opacity.qml b/tests/auto/quick/qquickanimators/data/tst_opacity.qml new file mode 100644 index 0000000000000000000000000000000000000000..a785b2b3f320eaa20cd8ca03cb20fe6474601e8e --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_opacity.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "opacity" + when: !animation.running + function test_endresult() { + compare(box.opacityChangeCounter, 1); + compare(box.opacity, 0.5); + var image = grabImage(root); + compare(image.red(50, 50), 255); + verify(image.green(50, 50) > 0); + verify(image.blue(50, 50) > 0); + } + } + + Box { + id: box + + OpacityAnimator { + id: animation + target: box + from: 1; + to: 0.5 + duration: 1000 + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_parallel.qml b/tests/auto/quick/qquickanimators/data/tst_parallel.qml new file mode 100644 index 0000000000000000000000000000000000000000..3105d3c2ddc5d177ebb33278bd3220ec85446c16 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_parallel.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "parallel" + when: !animation.running + function test_endresult() { + compare(box.rotationChangeCounter, 1); + compare(box.scaleChangeCounter, 1); + compare(box.scale, 2); + compare(box.rotation, 180); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(0, 0, 1, 1)); + compare(image.pixel(199, 199), Qt.rgba(1, 0, 0, 1)); + } + } + + Box { + id: box + ParallelAnimation { + id: animation + ScaleAnimator { target: box; from: 1; to: 2.0; duration: 1000; } + RotationAnimator { target: box; from: 0; to: 180; duration: 1000; } + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_restart.qml b/tests/auto/quick/qquickanimators/data/tst_restart.qml new file mode 100644 index 0000000000000000000000000000000000000000..42c7a33a8b9d0190f4a3ce85c3cd7c111ab3e2d0 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_restart.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + property int restartCount: 5; + + TestCase { + id: testcase + name: "restart" + when: root.restartCount == 0 && animation.running == false; + function test_endresult() { + compare(box.scale, 2); + } + } + + Box { + id: box + + ScaleAnimator { + id: animation + target: box; + from: 1; + to: 2.0; + duration: 100; + loops: 1 + running: false; + } + + Timer { + id: timer; + interval: 500 + running: true + repeat: true + onTriggered: { + animation.running = true; + --root.restartCount; + } + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_rotation.qml b/tests/auto/quick/qquickanimators/data/tst_rotation.qml new file mode 100644 index 0000000000000000000000000000000000000000..517cf5945631138d1cad241439da3e057d62bf3b --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_rotation.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "rotation" + when: !animation.running + function test_endresult() { + compare(box.rotationChangeCounter, 1); + compare(box.rotation, 180); + var image = grabImage(root); + compare(image.pixel(50, 50), Qt.rgba(0, 0, 1)); + } + } + + Box { + id: box + RotationAnimator { + id: animation + target: box + from: 0; + to: 180 + duration: 1000 + easing.type: Easing.InOutBack + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_scale.qml b/tests/auto/quick/qquickanimators/data/tst_scale.qml new file mode 100644 index 0000000000000000000000000000000000000000..6fd4668684c428fe87e94e1f78be922e42b0c8de --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_scale.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "scale" + when: !animation.running + function test_endresult() { + compare(box.scaleChangeCounter, 1); + compare(box.scale, 2); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(1, 0, 0)); + } + } + + Box { + id: box + + ScaleAnimator { + id: animation + target: box + from: 1; + to: 2.0 + duration: 1000 + easing.type: Easing.InOutCubic + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_sequential.qml b/tests/auto/quick/qquickanimators/data/tst_sequential.qml new file mode 100644 index 0000000000000000000000000000000000000000..2bb14f8acfd78f8069d08c7421a11c9ea0f272c2 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_sequential.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "parallel" + when: !animation.running + function test_endresult() { + compare(box.rotationChangeCounter, 1); + compare(box.scaleChangeCounter, 1); + compare(box.scale, 2); + compare(box.rotation, 180); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(0, 0, 1, 1)); + compare(image.pixel(199, 199), Qt.rgba(1, 0, 0, 1)); + } + } + + Box { + id: box + SequentialAnimation { + id: animation + ScaleAnimator { target: box; from: 1; to: 2.0; duration: 1000; } + RotationAnimator { target: box; from: 0; to: 180; duration: 1000; } + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_transformorigin.qml b/tests/auto/quick/qquickanimators/data/tst_transformorigin.qml new file mode 100644 index 0000000000000000000000000000000000000000..0211d0305d5a129d927b7126e61d5379d6778d97 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_transformorigin.qml @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 300 + height: 300 + + Timer { + id: timer; + running: testCase.windowShown + interval: 1000 + repeat: false + onTriggered: triggered = true; + property bool triggered: false; + } + + TestCase { + id: testCase + name: "transformorigin" + when: timer.triggered + function test_endresult() { + + var image = grabImage(root); + + var white = Qt.rgba(1, 1, 1); + var blue = Qt.rgba(0, 0, 1); + + + // topleft + compare(image.pixel(40, 40), white); + compare(image.pixel(60, 40), white); + compare(image.pixel(40, 60), white); + compare(image.pixel(60, 60), blue); + + // top + compare(image.pixel(140, 40), white); + compare(image.pixel(160, 40), white); + compare(image.pixel(140, 60), blue); + compare(image.pixel(160, 60), blue); + + // topright + compare(image.pixel(240, 40), white); + compare(image.pixel(260, 40), white); + compare(image.pixel(240, 60), blue); + compare(image.pixel(260, 60), white); + + + // left + compare(image.pixel(40, 140), white); + compare(image.pixel(60, 140), blue); + compare(image.pixel(40, 160), white); + compare(image.pixel(60, 160), blue); + + // center + compare(image.pixel(140, 140), blue); + compare(image.pixel(160, 140), blue); + compare(image.pixel(140, 160), blue); + compare(image.pixel(160, 160), blue); + + // right + compare(image.pixel(240, 140), blue); + compare(image.pixel(260, 140), white); + compare(image.pixel(240, 160), blue); + compare(image.pixel(260, 160), white); + + + // bottomleft + compare(image.pixel(40, 240), white); + compare(image.pixel(60, 240), blue); + compare(image.pixel(40, 260), white); + compare(image.pixel(60, 260), white); + + // bottom + compare(image.pixel(140, 240), blue); + compare(image.pixel(160, 240), blue); + compare(image.pixel(140, 260), white); + compare(image.pixel(160, 260), white); + + // bottomright + compare(image.pixel(240, 240), blue); + compare(image.pixel(260, 240), white); + compare(image.pixel(240, 260), white); + compare(image.pixel(260, 260), white); + + } + } + + property var origins: [Item.TopLeft, Item.Top, Item.TopRight, + Item.Left, Item.Center, Item.Right, + Item.BottomLeft, Item.Bottom, Item.BottomRight]; + + Grid { + anchors.fill: parent + rows: 3 + columns: 3 + + Repeater { + model: 9 + Item { + width: 100 + height: 100 + Rectangle { + id: box + color: "blue" + anchors.centerIn: parent + width: 10 + height: 10 + antialiasing: true; + + transformOrigin: root.origins[index]; + + ScaleAnimator { target: box; from: 1; to: 5.5; duration: 1000; running: true; } + } + } + } + } + +} diff --git a/tests/auto/quick/qquickanimators/data/tst_transition.qml b/tests/auto/quick/qquickanimators/data/tst_transition.qml new file mode 100644 index 0000000000000000000000000000000000000000..8e21a6537e8190c5a49435bb13a00e918376b8ee --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_transition.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testcase + name: "transition" + when: box.scale == 2 + function test_endresult() { + compare(box.scaleChangeCounter, 1); + compare(box.scale, 2); + var image = grabImage(root); + compare(image.pixel(0, 0), Qt.rgba(1, 0, 0)); + compare(image.pixel(199, 199), Qt.rgba(0, 0, 1)); + } + } + + states: [ + State { + name: "one" + PropertyChanges { target: box; scale: 1 } + }, + State { + name: "two" + PropertyChanges { target: box; scale: 2 } + } + ] + state: "one" + + transitions: [ + Transition { + ScaleAnimator { duration: 200; } + } + ] + + Box { + id: box + } + + Timer { + interval: 1000; + repeat: false + running: true + onTriggered: root.state = "two" + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_x.qml b/tests/auto/quick/qquickanimators/data/tst_x.qml new file mode 100644 index 0000000000000000000000000000000000000000..70ecf96346f653c7a8915e46a1f82f82c4159607 --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_x.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "x" + when: !animation.running + function test_endresult() { + compare(box.xChangeCounter, 1); + compare(box.x, 100); + var image = grabImage(root); + compare(image.pixel(100, 50), Qt.rgba(1, 0, 0)); + compare(image.pixel(99, 50), Qt.rgba(1, 1, 1)); // outside on the left + } + } + + Box { + id: box + + anchors.centerIn: undefined + + XAnimator { + id: animation + target: box + from: 0; + to: 100 + duration: 1000 + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/data/tst_y.qml b/tests/auto/quick/qquickanimators/data/tst_y.qml new file mode 100644 index 0000000000000000000000000000000000000000..428d42a6c387c87e036272a9bf5ca2d6b575f21a --- /dev/null +++ b/tests/auto/quick/qquickanimators/data/tst_y.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 + +Item { + id: root; + width: 200 + height: 200 + + TestCase { + id: testCase + name: "y" + when: !animation.running + function test_endresult() { + compare(box.yChangeCounter, 1); + compare(box.y, 100); + var image = grabImage(root); + compare(image.pixel(50, 100), Qt.rgba(1, 0, 0)); + compare(image.pixel(50, 99), Qt.rgba(1, 1, 1)); // outside on the left + } + } + + Box { + id: box + + anchors.centerIn: undefined + + YAnimator { + id: animation + target: box + from: 0; + to: 100 + duration: 1000 + running: true + } + } +} diff --git a/tests/auto/quick/qquickanimators/qquickanimators.pro b/tests/auto/quick/qquickanimators/qquickanimators.pro new file mode 100644 index 0000000000000000000000000000000000000000..4fa0438e412349438e3dcb84e15df381e59ad227 --- /dev/null +++ b/tests/auto/quick/qquickanimators/qquickanimators.pro @@ -0,0 +1,14 @@ +QT += core-private gui-private qml-private +TEMPLATE=app +TARGET=tst_qquickanimators + +CONFIG += qmltestcase +SOURCES += tst_qquickanimators.cpp + +TESTDATA = data/* + +OTHER_FILES += \ + data/tst_scale.qml \ + data/Scale.qml \ + tst_on.qml \ + data/tst_nested.qml diff --git a/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp b/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3f982091fb37c430fbed48d3664687e40e66ff7 --- /dev/null +++ b/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuickTest/quicktest.h> + +QUICK_TEST_MAIN(qquickanimators)