/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, 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. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lifecycle.h" #include "stickman.h" #include "node.h" #include "animation.h" #include "graphicsview.h" #include #include #if defined(QT_EXPERIMENTAL_SOLUTION) #include "qstatemachine.h" #include "qstate.h" #include "qeventtransition.h" #include "qsignaltransition.h" #include "qsignalevent.h" #include "qpropertyanimation.h" #include "qparallelanimationgroup.h" #endif class KeyPressTransition: public QSignalTransition { public: KeyPressTransition(GraphicsView *receiver, Qt::Key key) : QSignalTransition(receiver, SIGNAL(keyPressed(int))), m_key(key) { } KeyPressTransition(GraphicsView *receiver, Qt::Key key, QAbstractState *target) : QSignalTransition(receiver, SIGNAL(keyPressed(int)), QList() << target), m_key(key) { } virtual bool eventTest(QEvent *e) const { if (QSignalTransition::eventTest(e)) { QVariant key = static_cast(e)->arguments().at(0); return (key.toInt() == int(m_key)); } return false; } private: Qt::Key m_key; }; class LightningStrikesTransition: public QEventTransition { public: LightningStrikesTransition(QAbstractState *target) : QEventTransition(this, QEvent::Timer, QList() << target) { qsrand((uint)QDateTime::currentDateTime().toTime_t()); startTimer(1000); } virtual bool eventTest(QEvent *e) const { return QEventTransition::eventTest(e) && ((qrand() % 50) == 0); } }; LifeCycle::LifeCycle(StickMan *stickMan, GraphicsView *keyReceiver) : m_stickMan(stickMan), m_keyReceiver(keyReceiver) { // Create animation group to be used for all transitions m_animationGroup = new QParallelAnimationGroup(); const int stickManNodeCount = m_stickMan->nodeCount(); for (int i=0; inode(i), "position"); m_animationGroup->addAnimation(pa); } // Set up intial state graph m_machine = new QStateMachine(); m_machine->setGlobalRestorePolicy(QState::RestoreProperties); m_alive = new QState(m_machine->rootState()); m_alive->setObjectName("alive"); // Make it blink when lightning strikes before entering dead animation QState *lightningBlink = new QState(m_machine->rootState()); lightningBlink->setRestorePolicy(QState::DoNotRestoreProperties); lightningBlink->assignProperty(m_stickMan->scene(), "backgroundBrush", Qt::white); lightningBlink->assignProperty(m_stickMan, "penColor", Qt::black); lightningBlink->assignProperty(m_stickMan, "fillColor", Qt::white); lightningBlink->assignProperty(m_stickMan, "isDead", true); QTimer *timer = new QTimer(lightningBlink); timer->setSingleShot(true); timer->setInterval(100); lightningBlink->invokeMethodOnEntry(timer, "start"); lightningBlink->invokeMethodOnExit(timer, "stop"); m_dead = new QState(m_machine->rootState()); m_dead->setRestorePolicy(QState::DoNotRestoreProperties); m_dead->assignProperty(m_stickMan->scene(), "backgroundBrush", Qt::black); m_dead->assignProperty(m_stickMan, "penColor", Qt::white); m_dead->assignProperty(m_stickMan, "fillColor", Qt::black); m_dead->setObjectName("dead"); // Idle state (sets no properties) m_idle = new QState(m_alive); m_idle->setObjectName("idle"); m_alive->setInitialState(m_idle); // Lightning strikes at random m_alive->addTransition(new LightningStrikesTransition(lightningBlink)); //m_alive->addTransition(new KeyPressTransition(m_keyReceiver, Qt::Key_L, lightningBlink)); connectByAnimation(lightningBlink, m_dead, new QSignalTransition(timer, SIGNAL(timeout()))); m_machine->setInitialState(m_alive); } void LifeCycle::setResetKey(Qt::Key resetKey) { // When resetKey is pressed, enter the idle state and do a restoration animation // (requires no animation pointer, since no property is being set in the idle state) KeyPressTransition *trans = new KeyPressTransition(m_keyReceiver, resetKey, m_idle); trans->addAnimation(m_animationGroup); m_alive->addTransition(trans); } void LifeCycle::setDeathAnimation(const QString &fileName) { QState *deathAnimation = makeState(m_dead, fileName); m_dead->setInitialState(deathAnimation); } void LifeCycle::start() { m_machine->start(); } void LifeCycle::connectByAnimation(QState *s1, QAbstractState *s2, QAbstractTransition *transition) { if (transition == 0) { transition = s1->addTransition(s2); } else { transition->setTargetState(s2); s1->addTransition(transition); } transition->addAnimation(m_animationGroup); } void LifeCycle::addActivity(const QString &fileName, Qt::Key key) { QState *state = makeState(m_alive, fileName); connectByAnimation(m_alive, state, new KeyPressTransition(m_keyReceiver, key)); } QState *LifeCycle::makeState(QState *parentState, const QString &animationFileName) { QState *topLevel = new QState(parentState); Animation animation; { QFile file(animationFileName); if (file.open(QIODevice::ReadOnly)) animation.load(&file); } const int frameCount = animation.totalFrames(); QState *previousState = 0; for (int i=0; isetObjectName(QString::fromLatin1("frame %0").arg(i)); animation.setCurrentFrame(i); const int nodeCount = animation.nodeCount(); for (int j=0; jassignProperty(m_stickMan->node(j), "position", animation.nodePos(j)); if (previousState == 0) { topLevel->setInitialState(frameState); } else { connectByAnimation(previousState, frameState, new QSignalTransition(m_machine, SIGNAL(animationsFinished()))); } previousState = frameState; } // Loop connectByAnimation(previousState, topLevel->initialState(), new QSignalTransition(m_machine, SIGNAL(animationsFinished()))); return topLevel; } LifeCycle::~LifeCycle() { delete m_machine; delete m_animationGroup; }