From 0795351f7c252f1eed97253f64e2d5839ad8a975 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 17 Apr 2012 11:35:14 +1000 Subject: populate transition for positioners Fix positioners to apply a "populate" transition for initially added items. This is consistent with ListView and GridView and also fixes the behaviour from QtQuick 1.x where the positioners were instead running the "move" transition for initially added items. Change-Id: Ib43f1141ce3e7379df085c178b684f89b8567403 Reviewed-by: Alan Alpert --- .../quick/positioners/positioners-transitions.qml | 35 +++-- examples/quick/positioners/positioners.qml | 13 +- src/quick/items/qquickitemviewtransition.cpp | 8 +- src/quick/items/qquickpositioners.cpp | 141 +++++++++++++++--- src/quick/items/qquickpositioners_p.h | 5 + .../quick/qquickpositioners/data/grid-animated.qml | 5 + .../qquickpositioners/data/horizontal-animated.qml | 6 + .../quick/qquickpositioners/data/transitions.qml | 57 ++++++-- .../qquickpositioners/data/vertical-animated.qml | 5 + .../qquickpositioners/tst_qquickpositioners.cpp | 158 +++++++++++++++++++-- 10 files changed, 378 insertions(+), 55 deletions(-) diff --git a/examples/quick/positioners/positioners-transitions.qml b/examples/quick/positioners/positioners-transitions.qml index e573c94343..64d5c52748 100644 --- a/examples/quick/positioners/positioners-transitions.qml +++ b/examples/quick/positioners/positioners-transitions.qml @@ -44,6 +44,7 @@ Rectangle { id: page width: 320; height: 480 property real effectiveOpacity: 1.0 + Timer { interval: 2000 running: true @@ -52,14 +53,17 @@ Rectangle { } Column { - id: layout1 y: 0 - move: Transition { - NumberAnimation { properties: "y"; easing.type: Easing.OutBounce } + + populate: Transition { + NumberAnimation { properties: "x,y"; from: 200; duration: 1500; easing.type: Easing.OutBounce } } add: Transition { NumberAnimation { properties: "y"; easing.type: Easing.OutQuad } } + move: Transition { + NumberAnimation { properties: "y"; easing.type: Easing.OutBounce } + } Rectangle { color: "red"; width: 100; height: 50; border.color: "black"; radius: 15 } @@ -92,14 +96,17 @@ Rectangle { } Row { - id: layout2 y: 320 - move: Transition { - NumberAnimation { properties: "x"; easing.type: Easing.OutBounce } + + populate: Transition { + NumberAnimation { properties: "x,y"; from: 200; duration: 1500; easing.type: Easing.OutBounce } } add: Transition { NumberAnimation { properties: "x"; easing.type: Easing.OutQuad } } + move: Transition { + NumberAnimation { properties: "x"; easing.type: Easing.OutBounce } + } Rectangle { color: "red"; width: 50; height: 100; border.color: "black"; radius: 15 } @@ -135,13 +142,16 @@ Rectangle { x: 120; y: 0 columns: 3 - move: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce } + populate: Transition { + NumberAnimation { properties: "x,y"; from: 200; duration: 1500; easing.type: Easing.OutBounce } } - add: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce } } + move: Transition { + NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce } + } + Rectangle { color: "red"; width: 50; height: 50; border.color: "black"; radius: 15 } @@ -188,7 +198,6 @@ Rectangle { } Flow { - id: layout4 x: 120; y: 160; width: 150 //! [move] @@ -203,6 +212,12 @@ Rectangle { } //! [add] + //! [populate] + populate: Transition { + NumberAnimation { properties: "x,y"; from: 200; duration: 1500; easing.type: Easing.OutBounce } + } + //! [populate] + Rectangle { color: "red"; width: 50; height: 50; border.color: "black"; radius: 15 } Rectangle { diff --git a/examples/quick/positioners/positioners.qml b/examples/quick/positioners/positioners.qml index 34caea327c..859d6bd6c5 100644 --- a/examples/quick/positioners/positioners.qml +++ b/examples/quick/positioners/positioners.qml @@ -50,15 +50,20 @@ import "../../shared" as Examples This is a collection of small QML examples relating to positioners. Each example is a small QML file emphasizing a particular element or feature. - Transitions shows animated transistions when showing or hiding items in a positioner. + Transitions shows animated transitions when showing or hiding items in a positioner. It consists of a scene populated with items in a variety of positioners: Column, Row, Grid and Flow. Each positioner has animations described as Transitions. + \snippet examples/quick/positioners/positioners-transitions.qml move - The move transition specifies how items inside the positioner will animate when they are displaced by items appearing or disappearing. + The move transition specifies how items inside a positioner will animate when they are displaced by the appearance or disappearance of other items. + \snippet examples/quick/positioners/positioners-transitions.qml add - The add transition specifies how items will appear when they are added to the positioner. + The add transition specifies how items will appear when they are added to a positioner. + + \snippet examples/quick/positioners/positioners-transitions.qml populate + The populate transition specifies how items will appear when their parent positioner is first created. - Attached Properties show using the attached property to determine where in a positioner an item is. + Attached Properties shows how the Positioner attached property can be used to determine where an item is within a positioner. \snippet examples/quick/positioners/positioners-attachedproperties.qml 0 */ diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index c680945e04..c1f1e515ff 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -577,8 +577,8 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) operations: \list - \li \c populate - the transition to run when a view is created, or when the model changes - \li \c add - the transition to apply to items that are added to the view + \li \c populate - the transition to apply to the items created initially for the view, or when the model changes + \li \c add - the transition to apply to items that are added to the view after it has been created \li \c remove - the transition to apply to items that are removed from the view \li \c move - the transition to apply to items that are moved within the view (i.e. as a result of a move operation in the model) @@ -593,7 +593,9 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) items rather than data models, the following properties are used instead: \list - \li \c add - the transition to apply to items that are created for the positioner, added to + \li \c populate - the transition to apply to items that have been added to the positioner at the + time of its creation + \li \c add - the transition to apply to items that are added to or reparented to the positioner, or items that have become \l {Item::}{visible} \li \c move - the transition to apply to items that have moved within the positioner, including when they are displaced due to the addition or removal of other items, or when items are otherwise diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 97a74c6765..37c3ef1224 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -195,6 +195,23 @@ void QQuickBasePositioner::setSpacing(qreal s) emit spacingChanged(); } +QQuickTransition *QQuickBasePositioner::populate() const +{ + Q_D(const QQuickBasePositioner); + return d->transitioner ? d->transitioner->populateTransition : 0; +} + +void QQuickBasePositioner::setPopulate(QQuickTransition *transition) +{ + Q_D(QQuickBasePositioner); + if (!d->transitioner) + d->transitioner = new QQuickItemViewTransitioner; + if (d->transitioner->populateTransition != transition) { + d->transitioner->populateTransition = transition; + emit populateChanged(); + } +} + QQuickTransition *QQuickBasePositioner::move() const { Q_D(const QQuickBasePositioner); @@ -233,9 +250,14 @@ void QQuickBasePositioner::setAdd(QQuickTransition *add) void QQuickBasePositioner::componentComplete() { + Q_D(QQuickBasePositioner); QQuickItem::componentComplete(); + if (d->transitioner) + d->transitioner->setPopulateTransitionEnabled(true); positionedItems.reserve(childItems().count()); prePositioning(); + if (d->transitioner) + d->transitioner->setPopulateTransitionEnabled(false); } void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &value) @@ -301,7 +323,10 @@ void QQuickBasePositioner::prePositioning() if (addedIndex < 0) addedIndex = posItem.index; PositionedItem *theItem = &positionedItems[positionedItems.count()-1]; - theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true); + if (d->transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) + theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::PopulateTransition, true); + else if (!d->transitioner->populateTransitionEnabled()) + theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true); } } } else { @@ -354,7 +379,7 @@ void QQuickBasePositioner::prePositioning() } if (d->transitioner) { - QRectF viewBounds; + QRectF viewBounds(QPointF(), contentSize); for (int i=0; itransitioner, viewBounds); for (int i=0; irootContext(); + ctxt->setContextProperty("usePopulateTransition", usePopulateTransition); + ctxt->setContextProperty("enableAddTransition", true); + ctxt->setContextProperty("dynamicallyPopulate", dynamicallyPopulate); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); + ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); + ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom); + ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia); + ctxt->setContextProperty("testedPositioner", positionerObjectName); + canvas->setSource(testFileUrl("transitions.qml")); + + QQuickItem *positioner = canvas->rootObject()->findChild(positionerObjectName); + QVERIFY(positioner); + canvas->show(); + qApp->processEvents(); + + if (!dynamicallyPopulate && usePopulateTransition) { + QTRY_COMPARE(canvas->rootObject()->property("populateTransitionsDone").toInt(), model.count()); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), 0); + + QList > targetData; + QList targetIndexes; + for (int i=0; i targetItems = findItems(positioner, "wrapper", targetIndexes); + model_targetItems_transitionFrom.matchAgainst(targetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos"); + matchItemsAndIndexes(canvas->rootObject()->property("targetTrans_items").toMap(), model, targetIndexes); + matchIndexLists(canvas->rootObject()->property("targetTrans_targetIndexes").toList(), targetIndexes); + matchItemLists(canvas->rootObject()->property("targetTrans_targetItems").toList(), targetItems); + + } else if (dynamicallyPopulate) { + QTRY_COMPARE(canvas->rootObject()->property("populateTransitionsDone").toInt(), 0); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), model.count()); + } else { + QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + QTRY_COMPARE(canvas->rootObject()->property("populateTransitionsDone").toInt(), 0); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), 0); + } + + checkItemPositions(positioner, &model, canvas->rootObject()->property("incrementalSize").toInt()); + + // add an item and check this is done with add transition, not populate + canvas->rootObject()->setProperty("populateTransitionsDone", 0); + canvas->rootObject()->setProperty("addTransitionsDone", 0); + model.insertItem(0, "new item", ""); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), 1); + QTRY_COMPARE(canvas->rootObject()->property("populateTransitionsDone").toInt(), 0); + + delete canvas; +} + +void tst_qquickpositioners::populateTransitions_data() +{ + QTest::addColumn("dynamicallyPopulate"); + QTest::addColumn("usePopulateTransition"); + + QTest::newRow("statically populate") << false << true; + QTest::newRow("statically populate, no populate transition") << false << false; + + QTest::newRow("dynamically populate") << true << true; + QTest::newRow("dynamically populate, no populate transition") << true << false; +} + void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) { QFETCH(int, initialItemCount); @@ -520,13 +655,12 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) QPointF displacedItems_transitionVia(100, 100); QaimModel model; - for (int i = 0; i < initialItemCount; i++) - model.addItem("Original item" + QString::number(i), ""); QaimModel model_targetItems_transitionFrom; QaimModel model_displacedItems_transitionVia; QQuickView *canvas = QQuickViewTestUtil::createView(); QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("usePopulateTransition", false); ctxt->setContextProperty("enableAddTransition", true); ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); @@ -536,12 +670,15 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) canvas->show(); qApp->processEvents(); - QList > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); - QQuickItem *positioner = canvas->rootObject()->findChild(positionerObjectName); QVERIFY(positioner); positioner->findChild("repeater")->setProperty("model", QVariant::fromValue(&model)); + QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + for (int i = 0; i < initialItemCount; i++) + model.addItem("Original item" + QString::number(i), ""); + + QList > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); QList > targetData; QList targetIndexes; for (int i=0; i targetItems = findItems(positioner, "wrapper", targetIndexes); - // check initial add transition - // (positioners run the add transition on all items that are initially created for the view) - QTRY_COMPARE(canvas->rootObject()->property("targetTransitionsDone").toInt(), initialItemCount); + // check add transition was run for first lot of added items + QTRY_COMPARE(canvas->rootObject()->property("populateTransitionsDone").toInt(), 0); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), initialItemCount); QTRY_COMPARE(canvas->rootObject()->property("displaceTransitionsDone").toInt(), 0); model_targetItems_transitionFrom.matchAgainst(targetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos"); matchItemsAndIndexes(canvas->rootObject()->property("targetTrans_items").toMap(), model, targetIndexes); @@ -560,7 +697,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) matchItemLists(canvas->rootObject()->property("targetTrans_targetItems").toList(), targetItems); model_targetItems_transitionFrom.clear(); - canvas->rootObject()->setProperty("targetTransitionsDone", 0); + canvas->rootObject()->setProperty("addTransitionsDone", 0); canvas->rootObject()->setProperty("targetTrans_items", QVariantMap()); canvas->rootObject()->setProperty("targetTrans_targetIndexes", QVariantList()); canvas->rootObject()->setProperty("targetTrans_targetItems", QVariantList()); @@ -577,7 +714,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) targetItems = findItems(positioner, "wrapper", targetIndexes); - QTRY_COMPARE(canvas->rootObject()->property("targetTransitionsDone").toInt(), targetData.count()); + QTRY_COMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), targetData.count()); QTRY_COMPARE(canvas->rootObject()->property("displaceTransitionsDone").toInt(), expectedDisplacedIndexes.count()); // check the target and displaced items were animated @@ -636,6 +773,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) QQuickView *canvas = QQuickViewTestUtil::createView(); QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("usePopulateTransition", false); ctxt->setContextProperty("enableAddTransition", QVariant(false)); ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom); ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia); @@ -669,7 +807,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) } QTRY_COMPARE(canvas->rootObject()->property("displaceTransitionsDone").toInt(), expectedDisplacedIndexes.count()); - QCOMPARE(canvas->rootObject()->property("targetTransitionsDone").toInt(), 0); + QCOMPARE(canvas->rootObject()->property("addTransitionsDone").toInt(), 0); // check the target and displaced items were animated QCOMPARE(model_targetItems_transitionFrom.count(), 0); -- cgit v1.2.3