diff -r 000000000000 -r 1918ee327afb demos/qtdemo/itemcircleanimation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demos/qtdemo/itemcircleanimation.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,507 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemcircleanimation.h" +#include "demoitemanimation.h" +#include "colors.h" +#include "menumanager.h" +#include "mainwindow.h" +#include "menumanager.h" + +static QGraphicsScene *sscene; + +//////////////////// POST EFFECT STUFF //////////////////////////////////////// + +class TickerPostEffect +{ +public: + virtual ~TickerPostEffect(){}; + virtual void tick(float){}; + virtual void transform(DemoItem *, QPointF &){}; +}; + +class PostRotateXY : public TickerPostEffect +{ +public: + float currRotX, currRotY; + float speedx, speedy, curvx, curvy; + + PostRotateXY(float speedx, float speedy, float curvx, float curvy) + : currRotX(0), currRotY(0), + speedx(speedx), speedy(speedy), + curvx(curvx), curvy(curvy){}; + + void tick(float adjust) + { + currRotX += speedx * adjust; + currRotY += speedy * adjust; + } + + void transform(DemoItem *item, QPointF &pos) + { + DemoItem *parent = (DemoItem *) item->parentItem(); + QPointF center = parent->boundingRect().center(); + pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.x() * curvx)); + pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.y() * curvy)); + } +}; + +class PostRotateXYTwist : public TickerPostEffect +{ +public: + float currRotX, currRotY; + float speedx, speedy, curvx, curvy; + + PostRotateXYTwist(float speedx, float speedy, float curvx, float curvy) + : currRotX(0), currRotY(0), + speedx(speedx), speedy(speedy), + curvx(curvx), curvy(curvy){}; + + void tick(float adjust) + { + currRotX += speedx * adjust; + currRotY += speedy * adjust; + } + + void transform(DemoItem *item, QPointF &pos) + { + DemoItem *parent = (DemoItem *) item->parentItem(); + QPointF center = parent->boundingRect().center(); + pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.y() * curvx)); + pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.x() * curvy)); + } +}; + +//////////////////// TICKER EFFECT STUFF ////////////////////////////////////// + +class TickerEffect +{ + TickerPostEffect *postEffect; +public: + enum EffectStatus{Normal, Intro, Outro} status; + LetterList *letters; + float morphSpeed, moveSpeed; + float normalMorphSpeed, normalMoveSpeed; + bool useSheepDog, morphBetweenModels; + + TickerEffect(LetterList *letters) + : postEffect(new TickerPostEffect()), status(Intro), letters(letters), + morphSpeed(Colors::tickerMorphSpeed), moveSpeed(Colors::tickerMoveSpeed), + normalMorphSpeed(Colors::tickerMorphSpeed), normalMoveSpeed(Colors::tickerMoveSpeed), + useSheepDog(true), morphBetweenModels(!Colors::noTickerMorph){} + + void setPostEffect(TickerPostEffect *effect) + { + delete postEffect; + postEffect = effect; + } + + virtual ~TickerEffect() + { + delete postEffect; + } + + void slowDownAfterIntro(float adjust) + { + if (morphBetweenModels){ + if (status == Intro){ + float dec = 0.1 * adjust; + moveSpeed -= dec; + if (moveSpeed < Colors::tickerMoveSpeed){ + moveSpeed = normalMoveSpeed; + morphSpeed = normalMorphSpeed; + status = Normal; + } + } + } + } + + void moveLetters(float adjust) + { + float adaptedMoveSpeed = this->moveSpeed * adjust; + float adaptedMorphSpeed = this->morphSpeed * adjust; + postEffect->tick(adjust); + + for (int i=0; isize(); i++){ + LetterItem *letter = letters->at(i); + letter->guideAdvance(this->morphBetweenModels ? adaptedMoveSpeed : Colors::tickerMoveSpeed); + letter->guideMove(this->morphBetweenModels ? adaptedMorphSpeed : -1); + + QPointF pos = letter->getGuidedPos(); + postEffect->transform(letter, pos); + + if (useSheepDog) + letter->setPosUsingSheepDog(pos, QRectF(0, 0, 800, 600)); + else + letter->setPos(pos); + } + } + + virtual void tick(float adjust) + { + slowDownAfterIntro(adjust); + moveLetters(adjust); + } + +}; + +class EffectWhirlWind : public TickerEffect +{ +public: + EffectWhirlWind(LetterList *letters) : TickerEffect(letters) + { + moveSpeed = 50; + for (int i=0; iletters->size(); i++){ + LetterItem *letter = this->letters->at(i); + letter->setGuidedPos(QPointF(0, 100)); + } + } +}; + +class EffectSnake : public TickerEffect +{ +public: + EffectSnake(LetterList *letters) : TickerEffect(letters) + { + moveSpeed = 40; + for (int i=0; iletters->size(); i++){ + LetterItem *letter = this->letters->at(i); + letter->setGuidedPos(QPointF(0, -250 - (i * 5))); + } + } +}; + +class EffectScan : public TickerEffect +{ +public: + EffectScan(LetterList *letters) : TickerEffect(letters) + { + for (int i=0; iletters->size(); i++){ + LetterItem *letter = this->letters->at(i); + letter->setGuidedPos(QPointF(100, -300)); + } + } +}; + +class EffectRaindrops : public TickerEffect +{ +public: + EffectRaindrops(LetterList *letters) : TickerEffect(letters) + { + for (int i=0; iletters->size(); i++){ + LetterItem *letter = this->letters->at(i); + letter->setGuidedPos(QPointF(-100 + rand() % 200, - 200.0f - rand() % 1300)); + } + } +}; + +class EffectLine : public TickerEffect +{ +public: + EffectLine(LetterList *letters) : TickerEffect(letters) + { + for (int i=0; iletters->size(); i++){ + LetterItem *letter = this->letters->at(i); + letter->setGuidedPos(QPointF(100, 500.0f + i * 20)); + } + } +}; + +//////////////////// TICKER STUFF ///////////////////////////////////////////// + +ItemCircleAnimation::ItemCircleAnimation(QGraphicsScene *scene, QGraphicsItem *parent) + : DemoItem(scene, parent) +{ + sscene = scene; + this->letterCount = Colors::tickerLetterCount; + this->scale = 1; + this->showCount = -1; + this->tickOnPaint = false; + this->paused = false; + this->doIntroTransitions = true; + this->setAcceptsHoverEvents(true); + this->setCursor(Qt::OpenHandCursor); + this->setupGuides(); + this->setupLetters(); + this->useGuideQt(); + this->effect = 0;//new TickerEffect(this->letterList); +} + +ItemCircleAnimation::~ItemCircleAnimation() +{ + delete this->letterList; + delete this->qtGuide1; + delete this->qtGuide2; + delete this->qtGuide3; + delete this->effect; +} + +void ItemCircleAnimation::createLetter(char c) +{ + LetterItem *letter = new LetterItem(c, sscene, this); + this->letterList->append(letter); +} + +void ItemCircleAnimation::setupLetters() +{ + this->letterList = new LetterList(); + + QString s = Colors::tickerText; + int len = s.length(); + int i = 0; + for (; i < this->letterCount - len; i += len) + for (int l=0; lletterCount; ++i) + createLetter(' '); +} + +void ItemCircleAnimation::setupGuides() +{ + int x = 0; + int y = 20; + + this->qtGuide1 = new GuideCircle(QRectF(x, y, 260, 260), -36, 342); + new GuideLine(QPointF(x + 240, y + 268), this->qtGuide1); + new GuideLine(QPointF(x + 265, y + 246), this->qtGuide1); + new GuideLine(QPointF(x + 158, y + 134), this->qtGuide1); + new GuideLine(QPointF(x + 184, y + 109), this->qtGuide1); + new GuideLine(QPointF(x + 160, y + 82), this->qtGuide1); + new GuideLine(QPointF(x + 77, y + 163), this->qtGuide1); // T-top + new GuideLine(QPointF(x + 100, y + 190), this->qtGuide1); + new GuideLine(QPointF(x + 132, y + 159), this->qtGuide1); + new GuideLine(QPointF(x + 188, y + 211), this->qtGuide1); + new GuideCircle(QRectF(x + 30, y + 30, 200, 200), -30, 336, GuideCircle::CW, this->qtGuide1); + new GuideLine(QPointF(x + 238, y + 201), this->qtGuide1); + + y = 30; + this->qtGuide2 = new GuideCircle(QRectF(x + 30, y + 30, 200, 200), 135, 270, GuideCircle::CCW); + new GuideLine(QPointF(x + 222, y + 38), this->qtGuide2); + new GuideCircle(QRectF(x, y, 260, 260), 135, 270, GuideCircle::CW, this->qtGuide2); + new GuideLine(QPointF(x + 59, y + 59), this->qtGuide2); + + x = 115; + y = 10; + this->qtGuide3 = new GuideLine(QLineF(x, y, x + 30, y)); + new GuideLine(QPointF(x + 30, y + 170), this->qtGuide3); + new GuideLine(QPointF(x, y + 170), this->qtGuide3); + new GuideLine(QPointF(x, y), this->qtGuide3); + + this->qtGuide1->setFence(QRectF(0, 0, 800, 600)); + this->qtGuide2->setFence(QRectF(0, 0, 800, 600)); + this->qtGuide3->setFence(QRectF(0, 0, 800, 600)); +} + +void ItemCircleAnimation::useGuide(Guide *guide, int firstLetter, int lastLetter) +{ + float padding = guide->lengthAll() / float(lastLetter - firstLetter); + for (int i=firstLetter; iletterList->at(i); + letter->useGuide(guide, (i - firstLetter) * padding); + } +} + +void ItemCircleAnimation::useGuideQt() +{ + if (this->currGuide != this->qtGuide1){ + this->useGuide(qtGuide1, 0, this->letterCount); + this->currGuide = qtGuide1; + } +} + +void ItemCircleAnimation::useGuideTt() +{ + if (this->currGuide != this->qtGuide2){ + int split = int(this->letterCount * 5.0 / 7.0); + this->useGuide(qtGuide2, 0, split); + this->useGuide(qtGuide3, split, this->letterCount); + this->currGuide = qtGuide2; + } +} + +QRectF ItemCircleAnimation::boundingRect() const +{ + return QRectF(0, 0, 300, 320); +} + +void ItemCircleAnimation::prepare() +{ +} + +void ItemCircleAnimation::switchToNextEffect() +{ + ++this->showCount; + delete this->effect; + + switch (this->showCount){ + case 1: + this->effect = new EffectSnake(this->letterList); + break; + case 2: + this->effect = new EffectLine(this->letterList); + this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.0f, 0.003f, 0.0f)); + break; + case 3: + this->effect = new EffectRaindrops(this->letterList); + this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.005f, 0.003f, 0.003f)); + break; + case 4: + this->effect = new EffectScan(this->letterList); + this->effect->normalMoveSpeed = 0; + this->effect->setPostEffect(new PostRotateXY(0.008f, 0.0f, 0.005f, 0.0f)); + break; + default: + this->showCount = 0; + this->effect = new EffectWhirlWind(this->letterList); + } +} + +void ItemCircleAnimation::animationStarted(int id) +{ + if (id == DemoItemAnimation::ANIM_IN){ + if (this->doIntroTransitions){ + // Make all letters dissapear + for (int i=0; iletterList->size(); i++){ + LetterItem *letter = this->letterList->at(i); + letter->setPos(1000, 0); + } + this->switchToNextEffect(); + this->useGuideQt(); + this->scale = 1; + // The first time we run, we have a rather large + // delay to perform benchmark before the ticker shows. + // But now, since we are showing, use a more appropriate value: + this->currentAnimation->startDelay = 1500; + } + } + else if (this->effect) + this->effect->useSheepDog = false; + + this->tickTimer = QTime::currentTime(); +} + +void ItemCircleAnimation::animationStopped(int) +{ + // Nothing to do. +} + +void ItemCircleAnimation::swapModel(){ + if (this->currGuide == this->qtGuide2) + this->useGuideQt(); + else + this->useGuideTt(); +} + +void ItemCircleAnimation::hoverEnterEvent(QGraphicsSceneHoverEvent *) +{ +// Skip swap here to enhance ticker dragging +// this->swapModel(); +} + +void ItemCircleAnimation::hoverLeaveEvent(QGraphicsSceneHoverEvent *) +{ + this->swapModel(); +} + +void ItemCircleAnimation::setTickerScale(float s) +{ + this->scale = s; + qtGuide1->setScale(this->scale, this->scale); + qtGuide2->setScale(this->scale, this->scale); + qtGuide3->setScale(this->scale, this->scale); +} + +void ItemCircleAnimation::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + this->mouseMoveLastPosition = event->scenePos(); + if (event->button() == Qt::LeftButton) + this->setCursor(Qt::ClosedHandCursor); + else + this->switchToNextEffect(); +} + +void ItemCircleAnimation::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + this->setCursor(Qt::OpenHandCursor); +} + +void ItemCircleAnimation::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + QPointF newPosition = event->scenePos(); + this->setPosUsingSheepDog(this->pos() + newPosition - this->mouseMoveLastPosition, QRectF(-260, -280, 1350, 1160)); + this->mouseMoveLastPosition = newPosition; +} + +void ItemCircleAnimation::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + this->effect->moveSpeed = this->effect->moveSpeed + (event->delta() > 0 ? -0.20 : 0.20); + if (this->effect->moveSpeed < 0) + this->effect->moveSpeed = 0; +} + +void ItemCircleAnimation::pause(bool on) +{ + this->paused = on; + this->tickTimer = QTime::currentTime(); +} + +void ItemCircleAnimation::tick() +{ + if (this->paused || !this->effect) + return; + + float t = this->tickTimer.msecsTo(QTime::currentTime()); + this->tickTimer = QTime::currentTime(); + this->effect->tick(t/10.0f); +} + +void ItemCircleAnimation::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (this->tickOnPaint) + tick(); +} + + + +