// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include class Tst_QtQuickTimeline : public QObject { Q_OBJECT private Q_SLOTS: void checkImport(); void simpleTest(); void parameterization(); void vectors(); void deltaFunction(); void keyframeUpdate(); void easingcurveInterpolation(); void restoreBindingTest(); }; inline QUrl testFileUrl(const QString &fileName) { static const QString dir = QTest::qFindTestData("data"); QString result = dir; result += QLatin1Char('/'); result += fileName; return QUrl::fromLocalFile(result); } void Tst_QtQuickTimeline::checkImport() { QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.0; import QtQuick.Timeline 1.0; Item { }", QUrl()); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); } void Tst_QtQuickTimeline::simpleTest() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("simpletest.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *rectangle = object->findChild("rectangle"); QVERIFY(rectangle); QCOMPARE(rectangle->property("width").toInt(), 20); QCOMPARE(rectangle->property("height").toInt(), 20); QCOMPARE(rectangle->property("color").value(), QColor("blue")); QCOMPARE(rectangle->property("x").toInt(), 100); QCOMPARE(rectangle->property("y").toInt(), 100); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 100); QCOMPARE(timeline->property("currentFrame").toInt(), 50); auto *animation = object->findChild("animation"); QVERIFY(animation); QCOMPARE(animation->property("running").toBool(), false); QCOMPARE(animation->property("duration").toInt(), 200); QCOMPARE(animation->property("loops").toInt(), 1); QCOMPARE(animation->property("from").toInt(), 0); QCOMPARE(animation->property("to").toInt(), 100); auto *group = object->findChild("group01"); QVERIFY(group); QCOMPARE(group->property("target").value(), rectangle); timeline->setProperty("currentFrame", 0); QCOMPARE(rectangle->property("color").value(), QColor("red")); QCOMPARE(rectangle->property("x").toInt(), 0); QCOMPARE(rectangle->property("y").toInt(), 0); timeline->setProperty("currentFrame", 100); QCOMPARE(rectangle->property("color").value(), QColor("yellow")); QCOMPARE(rectangle->property("x").toInt(), 200); QCOMPARE(rectangle->property("y").toInt(), 200); timeline->setProperty("enabled", false); QCOMPARE(rectangle->property("color").value(), QColor("red")); QCOMPARE(rectangle->property("x").toInt(), 0); QCOMPARE(rectangle->property("y").toInt(), 0); timeline->setProperty("currentFrame", 0); timeline->setProperty("enabled", true); animation->setProperty("running", true); QCOMPARE(animation->property("running").toBool(), true); } void Tst_QtQuickTimeline::parameterization() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("parameterization.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 200); QCOMPARE(timeline->property("currentFrame").toInt(), 10); auto *needle = object->findChild("needle"); QVERIFY(needle); QCOMPARE(needle->property("width").toInt(), 150); QCOMPARE(needle->property("height").toInt(), 4); QCOMPARE(needle->property("x").toInt(), 0); QCOMPARE(needle->property("y").toInt(), 148); auto *group = object->findChild("group01"); QVERIFY(group); QCOMPARE(group->property("target").value(), needle); auto *textInput = object->findChild("textInput"); QVERIFY(textInput); QCOMPARE(textInput->property("text").toString(), "10"); textInput->setProperty("text", "0"); QCOMPARE(needle->property("color").value(), QColor("blue")); timeline->setProperty("enabled", false); QCOMPARE(needle->property("color").value(), QColor("#c41616")); QCOMPARE(needle->property("rotation").toInt(), 0); timeline->setProperty("enabled", true); textInput->setProperty("text", "100"); QCOMPARE(needle->property("color").value(), QColor("green")); QCOMPARE(needle->property("rotation").toInt(), 90); textInput->setProperty("text", "200"); QCOMPARE(needle->property("color").value(), QColor("red")); QCOMPARE(needle->property("rotation").toInt(), 180); } void Tst_QtQuickTimeline::Tst_QtQuickTimeline::vectors() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("vectors.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 200); QCOMPARE(timeline->property("currentFrame").toInt(), 0); auto *rotation = object->findChild("rotation"); QVERIFY(rotation); auto vector = rotation->property("origin").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 0.0); QCOMPARE(vector.y(), 30.0); vector = rotation->property("axis").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 0.0); QCOMPARE(vector.y(), 1.0); QCOMPARE(vector.z(), 0.0); timeline->setProperty("currentFrame", 50); vector = rotation->property("axis").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 1.0); QCOMPARE(vector.y(), 1.0); QCOMPARE(vector.z(), 0.0); vector = rotation->property("origin").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 10.0); QCOMPARE(vector.y(), 30.0); timeline->setProperty("currentFrame", 100); vector = rotation->property("axis").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 0.0); QCOMPARE(vector.y(), 1.0); QCOMPARE(vector.z(), 0.0); vector = rotation->property("origin").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 20.0); QCOMPARE(vector.y(), 30.0); timeline->setProperty("enabled", false); vector = rotation->property("origin").value(); QVERIFY(!vector.isNull()); QCOMPARE(vector.x(), 30.0); QCOMPARE(vector.y(), 30.0); } void Tst_QtQuickTimeline::deltaFunction() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("deltafunction.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 100); QCOMPARE(timeline->property("currentFrame").toInt(), 0); auto *text = object->findChild("text"); QVERIFY(text); QCOMPARE(text->property("text").toString(), "frame0"); auto *group = object->findChild("group01"); QVERIFY(group); QCOMPARE(group->property("target").value(), text); timeline->setProperty("enabled", false); QCOMPARE(text->property("text").toString(), "no timeline"); timeline->setProperty("enabled", true); QCOMPARE(text->property("text").toString(), "frame0"); timeline->setProperty("currentFrame", 49); QCOMPARE(text->property("text").toString(), "frame0"); timeline->setProperty("currentFrame", 50); QCOMPARE(text->property("text").toString(), "frame50"); timeline->setProperty("currentFrame", 51); QCOMPARE(text->property("text").toString(), "frame50"); timeline->setProperty("currentFrame", 49); QCOMPARE(text->property("text").toString(), "frame0"); timeline->setProperty("currentFrame", 99); QCOMPARE(text->property("text").toString(), "frame50"); timeline->setProperty("currentFrame", 100); QCOMPARE(text->property("text").toString(), "frame100"); timeline->setProperty("currentFrame", 101); QCOMPARE(text->property("text").toString(), "frame100"); } void Tst_QtQuickTimeline::keyframeUpdate() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("simpletest.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 100); QCOMPARE(timeline->property("currentFrame").toInt(), 50); auto *rectangle = object->findChild("rectangle"); QVERIFY(rectangle); QCOMPARE(rectangle->property("x").toInt(), 100); auto *keyframe = object->findChild("keyframe"); QVERIFY(keyframe); QCOMPARE(keyframe->property("frame").toInt(), 50); QCOMPARE(keyframe->property("value").toInt(), 100); keyframe->setProperty("value", 70); QCOMPARE(keyframe->property("value").toInt(), 70); QCOMPARE(rectangle->property("x").toInt(), 70); keyframe->setProperty("value", 90); QCOMPARE(keyframe->property("value").toInt(), 90); QCOMPARE(rectangle->property("x").toInt(), 90); timeline->setProperty("currentFrame", 60); QCOMPARE(timeline->property("currentFrame").toInt(), 60); QVERIFY(rectangle->property("x").toInt() != 90); keyframe->setProperty("frame", 60); QCOMPARE(rectangle->property("x").toInt(), 90); } void Tst_QtQuickTimeline::easingcurveInterpolation() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("simpletest.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), true); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 100); QCOMPARE(timeline->property("currentFrame").toInt(), 50); auto *rectangle = object->findChild("rectangle"); QVERIFY(rectangle); QCOMPARE(rectangle->property("y").toInt(), 100); auto *keyframe = object->findChild("easingBounce"); QVERIFY(keyframe); QCOMPARE(keyframe->property("frame").toInt(), 100); QCOMPARE(keyframe->property("value").toInt(), 200); auto easingCurve = keyframe->property("easing").value(); QCOMPARE(easingCurve.type(), QEasingCurve::InBounce); timeline->setProperty("currentFrame", 100); QCOMPARE(rectangle->property("y").toInt(), 200); timeline->setProperty("currentFrame", 75); qreal progress = easingCurve.valueForProgress(0.5); qreal final = (1 - progress) * 100 + progress * 200; QCOMPARE(rectangle->property("y").toReal(), final); timeline->setProperty("currentFrame", 90); progress = easingCurve.valueForProgress(0.8); final = (1 - progress) * 100 + progress * 200; QCOMPARE(rectangle->property("y").toReal(), final); timeline->setProperty("currentFrame", 95); progress = easingCurve.valueForProgress(0.9); final = (1 - progress) * 100 + progress * 200; QCOMPARE(rectangle->property("y").toReal(), final); timeline->setProperty("currentFrame", 55); progress = easingCurve.valueForProgress(0.1); final = (1 - progress) * 100 + progress * 200; QCOMPARE(rectangle->property("y").toReal(), final); timeline->setProperty("currentFrame", 60); progress = easingCurve.valueForProgress(0.2); final = (1 - progress) * 100 + progress * 200; QCOMPARE(rectangle->property("y").toReal(), final); } void Tst_QtQuickTimeline::restoreBindingTest() { QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("restorebindingtest.qml")); QScopedPointer object(component.create()); QVERIFY2(!object.isNull(), qPrintable(component.errorString())); auto *rectangle = object->findChild("rectangle"); QVERIFY(rectangle); QCOMPARE(rectangle->property("offset").toInt(), 0); QCOMPARE(rectangle->property("x").toInt(), 0); QCOMPARE(rectangle->property("y").toInt(), 0); auto *timeline = object->findChild("timeline"); QVERIFY(timeline); QCOMPARE(timeline->property("enabled").toBool(), false); QCOMPARE(timeline->property("startFrame").toInt(), 0); QCOMPARE(timeline->property("endFrame").toInt(), 100); QCOMPARE(timeline->property("currentFrame").toInt(), 50); // currentFrame == 50 timeline->setProperty("enabled", true); QCOMPARE(rectangle->property("x").toInt(), 70); QCOMPARE(rectangle->property("y").toInt(), 70); timeline->setProperty("currentFrame", 0); QCOMPARE(rectangle->property("x").toInt(), 140); QCOMPARE(rectangle->property("y").toInt(), 0); timeline->setProperty("currentFrame", 100); QCOMPARE(rectangle->property("x").toInt(), 0); QCOMPARE(rectangle->property("y").toInt(), 140); timeline->setProperty("enabled", false); // check restoring of the original binding QCOMPARE(rectangle->property("x").toInt(), 0); QCOMPARE(rectangle->property("y").toInt(), 0); rectangle->setProperty("offset", 50); QCOMPARE(rectangle->property("x").toInt(), 50); QCOMPARE(rectangle->property("y").toInt(), 50); timeline->setProperty("enabled", true); // currentFrame == 100, offset == 50 QCOMPARE(rectangle->property("x").toInt(), 50); QCOMPARE(rectangle->property("y").toInt(), 140); } QTEST_MAIN(Tst_QtQuickTimeline) #include "tst_qtquicktimeline.moc"