virtual void doAction() { for (int ii = 0; ii < actions.count(); ++ii) { const QQuickAction &action = actions.at(ii); if (reverse) action.event->reverse(); else action.event->execute(); } }
void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified, QObject *defaultTarget) { if (actions.size()) { for (int i=0; i<actions.size(); ++i) { QQuickStateAction &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; } } if (modified.isEmpty()) { job->setTarget(target); job->setFrom(from); job->setTo(to); } if (!job->target()) { if (defaultProperty.object()) job->setTarget(qobject_cast<QQuickItem *>(defaultProperty.object())); else job->setTarget(qobject_cast<QQuickItem *>(defaultTarget)); } job->setDuration(duration); job->setLoopCount(loopCount); job->setEasingCurve(easing); }
void QSGSequentialAnimation::prepareTransition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, QObject *defaultTarget) { if (direction != Forward) qWarning("QSGSequentialAnimation::prepareTransition - Backward transition not yet supported."); if (actions.count() > 0) { registerToHost(actions.at(0).property.object()); } int count = children().count(); for (int i = 0; i < count; i++) { QSGAbstractAnimation* a = dynamic_cast<QSGAbstractAnimation*> (children().at(i)); if (a) a->prepareTransition(actions, modified, direction, defaultTarget); } }
QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, QObject *defaultTarget) { Q_D(QQuickParentAnimation); struct QQuickParentAnimationData : public QAbstractAnimationAction { QQuickParentAnimationData() : reverse(false) {} ~QQuickParentAnimationData() { qDeleteAll(pc); } QQuickStateActions actions; //### reverse should probably apply on a per-action basis bool reverse; QList<QQuickParentChange *> pc; void doAction() Q_DECL_OVERRIDE { for (int ii = 0; ii < actions.count(); ++ii) { const QQuickStateAction &action = actions.at(ii); if (reverse) action.event->reverse(); else action.event->execute(); } } }; QQuickParentAnimationData *data = new QQuickParentAnimationData; QQuickParentAnimationData *viaData = new QQuickParentAnimationData; bool hasExplicit = false; if (d->target && d->newParent) { data->reverse = false; QQuickStateAction myAction; QQuickParentChange *pc = new QQuickParentChange; pc->setObject(d->target); pc->setParent(d->newParent); myAction.event = pc; data->pc << pc; data->actions << myAction; hasExplicit = true; if (d->via) { viaData->reverse = false; QQuickStateAction myVAction; QQuickParentChange *vpc = new QQuickParentChange; vpc->setObject(d->target); vpc->setParent(d->via); myVAction.event = vpc; viaData->pc << vpc; viaData->actions << myVAction; } //### once actions have concept of modified, // loop to match appropriate ParentChanges and mark as modified } if (!hasExplicit) for (int i = 0; i < actions.size(); ++i) { QQuickStateAction &action = actions[i]; if (action.event && action.event->type() == QQuickStateActionEvent::ParentChange && (!d->target || static_cast<QQuickParentChange*>(action.event)->object() == d->target)) { QQuickParentChange *pc = static_cast<QQuickParentChange*>(action.event); QQuickStateAction myAction = action; data->reverse = action.reverseEvent; //### this logic differs from PropertyAnimation // (probably a result of modified vs. done) if (d->newParent) { QQuickParentChange *epc = new QQuickParentChange; epc->setObject(static_cast<QQuickParentChange*>(action.event)->object()); epc->setParent(d->newParent); myAction.event = epc; data->pc << epc; data->actions << myAction; pc = epc; } else { action.actionDone = true; data->actions << myAction; } if (d->via) { viaData->reverse = false; QQuickStateAction myAction; QQuickParentChange *vpc = new QQuickParentChange; vpc->setObject(pc->object()); vpc->setParent(d->via); myAction.event = vpc; viaData->pc << vpc; viaData->actions << myAction; QQuickStateAction dummyAction; QQuickStateAction &xAction = pc->xIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction; QQuickStateAction &yAction = pc->yIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction; QQuickStateAction &sAction = pc->scaleIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction; QQuickStateAction &rAction = pc->rotationIsSet() && i < actions.size()-1 ? actions[++i] : dummyAction; QQuickItem *target = pc->object(); QQuickItem *targetParent = action.reverseEvent ? pc->originalParent() : pc->parent(); //### this mirrors the logic in QQuickParentChange. bool ok; const QTransform &transform = targetParent->itemTransform(d->via, &ok); if (transform.type() >= QTransform::TxShear || !ok) { qmlInfo(this) << QQuickParentAnimation::tr("Unable to preserve appearance under complex transform"); ok = false; } qreal scale = 1; qreal rotation = 0; bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0); if (ok && !isRotate) { if (transform.m11() == transform.m22()) scale = transform.m11(); else { qmlInfo(this) << QQuickParentAnimation::tr("Unable to preserve appearance under non-uniform scale"); ok = false; } } else if (ok && isRotate) { if (transform.m11() == transform.m22()) scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12()); else { qmlInfo(this) << QQuickParentAnimation::tr("Unable to preserve appearance under non-uniform scale"); ok = false; } if (scale != 0) rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; else { qmlInfo(this) << QQuickParentAnimation::tr("Unable to preserve appearance under scale of 0"); ok = false; } } const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal())); qreal x = point.x(); qreal y = point.y(); if (ok && target->transformOrigin() != QQuickItem::TopLeft) { qreal w = target->width(); qreal h = target->height(); if (pc->widthIsSet() && i < actions.size() - 1) w = actions[++i].toValue.toReal(); if (pc->heightIsSet() && i < actions.size() - 1) h = actions[++i].toValue.toReal(); const QPointF &transformOrigin = d->computeTransformOrigin(target->transformOrigin(), w,h); qreal tempxt = transformOrigin.x(); qreal tempyt = transformOrigin.y(); QTransform t; t.translate(-tempxt, -tempyt); t.rotate(rotation); t.scale(scale, scale); t.translate(tempxt, tempyt); const QPointF &offset = t.map(QPointF(0,0)); x += offset.x(); y += offset.y(); } if (ok) { //qDebug() << x << y << rotation << scale; xAction.toValue = x; yAction.toValue = y; sAction.toValue = sAction.toValue.toReal() * scale; rAction.toValue = rAction.toValue.toReal() + rotation; } } } } if (data->actions.count()) { QSequentialAnimationGroupJob *topLevelGroup = new QSequentialAnimationGroupJob; QActionAnimation *viaAction = d->via ? new QActionAnimation : 0; QActionAnimation *targetAction = new QActionAnimation; //we'll assume the common case by far is to have children, and always create ag QParallelAnimationGroupJob *ag = new QParallelAnimationGroupJob; if (d->via) viaAction->setAnimAction(viaData); targetAction->setAnimAction(data); //take care of any child animations 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) ag->appendAnimation(anim); } //TODO: simplify/clarify logic bool forwards = direction == QQuickAbstractAnimation::Forward; if (forwards) { topLevelGroup->appendAnimation(d->via ? viaAction : targetAction); topLevelGroup->appendAnimation(ag); if (d->via) topLevelGroup->appendAnimation(targetAction); } else { if (d->via) topLevelGroup->appendAnimation(targetAction); topLevelGroup->appendAnimation(ag); topLevelGroup->appendAnimation(d->via ? viaAction : targetAction); } return initInstance(topLevelGroup); } else { delete data; delete viaData; } return 0; }