Ejemplo n.º 1
0
 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 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);
    }
}
Ejemplo n.º 3
0
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;
}