source: trunk/demos/qtdemo/itemcircleanimation.cpp@ 858

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 15.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the demonstration applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "itemcircleanimation.h"
43#include "demoitemanimation.h"
44#include "colors.h"
45#include "menumanager.h"
46#include "mainwindow.h"
47#include "menumanager.h"
48
49static QGraphicsScene *sscene;
50
51//////////////////// POST EFFECT STUFF ////////////////////////////////////////
52
53class TickerPostEffect
54{
55public:
56 virtual ~TickerPostEffect(){};
57 virtual void tick(float){};
58 virtual void transform(DemoItem *, QPointF &){};
59};
60
61class PostRotateXY : public TickerPostEffect
62{
63public:
64 float currRotX, currRotY;
65 float speedx, speedy, curvx, curvy;
66
67 PostRotateXY(float speedx, float speedy, float curvx, float curvy)
68 : currRotX(0), currRotY(0),
69 speedx(speedx), speedy(speedy),
70 curvx(curvx), curvy(curvy){};
71
72 void tick(float adjust)
73 {
74 currRotX += speedx * adjust;
75 currRotY += speedy * adjust;
76 }
77
78 void transform(DemoItem *item, QPointF &pos)
79 {
80 DemoItem *parent = (DemoItem *) item->parentItem();
81 QPointF center = parent->boundingRect().center();
82 pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.x() * curvx));
83 pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.y() * curvy));
84 }
85};
86
87class PostRotateXYTwist : public TickerPostEffect
88{
89public:
90 float currRotX, currRotY;
91 float speedx, speedy, curvx, curvy;
92
93 PostRotateXYTwist(float speedx, float speedy, float curvx, float curvy)
94 : currRotX(0), currRotY(0),
95 speedx(speedx), speedy(speedy),
96 curvx(curvx), curvy(curvy){};
97
98 void tick(float adjust)
99 {
100 currRotX += speedx * adjust;
101 currRotY += speedy * adjust;
102 }
103
104 void transform(DemoItem *item, QPointF &pos)
105 {
106 DemoItem *parent = (DemoItem *) item->parentItem();
107 QPointF center = parent->boundingRect().center();
108 pos.setX(center.x() + (pos.x() - center.x()) * cos(currRotX + pos.y() * curvx));
109 pos.setY(center.y() + (pos.y() - center.y()) * cos(currRotY + pos.x() * curvy));
110 }
111};
112
113//////////////////// TICKER EFFECT STUFF //////////////////////////////////////
114
115class TickerEffect
116{
117 TickerPostEffect *postEffect;
118public:
119 enum EffectStatus{Normal, Intro, Outro} status;
120 LetterList *letters;
121 float morphSpeed, moveSpeed;
122 float normalMorphSpeed, normalMoveSpeed;
123 bool useSheepDog, morphBetweenModels;
124
125 TickerEffect(LetterList *letters)
126 : postEffect(new TickerPostEffect()), status(Intro), letters(letters),
127 morphSpeed(Colors::tickerMorphSpeed), moveSpeed(Colors::tickerMoveSpeed),
128 normalMorphSpeed(Colors::tickerMorphSpeed), normalMoveSpeed(Colors::tickerMoveSpeed),
129 useSheepDog(true), morphBetweenModels(!Colors::noTickerMorph){}
130
131 void setPostEffect(TickerPostEffect *effect)
132 {
133 delete postEffect;
134 postEffect = effect;
135 }
136
137 virtual ~TickerEffect()
138 {
139 delete postEffect;
140 }
141
142 void slowDownAfterIntro(float adjust)
143 {
144 if (morphBetweenModels){
145 if (status == Intro){
146 float dec = 0.1 * adjust;
147 moveSpeed -= dec;
148 if (moveSpeed < Colors::tickerMoveSpeed){
149 moveSpeed = normalMoveSpeed;
150 morphSpeed = normalMorphSpeed;
151 status = Normal;
152 }
153 }
154 }
155 }
156
157 void moveLetters(float adjust)
158 {
159 float adaptedMoveSpeed = this->moveSpeed * adjust;
160 float adaptedMorphSpeed = this->morphSpeed * adjust;
161 postEffect->tick(adjust);
162
163 for (int i=0; i<letters->size(); i++){
164 LetterItem *letter = letters->at(i);
165 letter->guideAdvance(this->morphBetweenModels ? adaptedMoveSpeed : Colors::tickerMoveSpeed);
166 letter->guideMove(this->morphBetweenModels ? adaptedMorphSpeed : -1);
167
168 QPointF pos = letter->getGuidedPos();
169 postEffect->transform(letter, pos);
170
171 if (useSheepDog)
172 letter->setPosUsingSheepDog(pos, QRectF(0, 0, 800, 600));
173 else
174 letter->setPos(pos);
175 }
176 }
177
178 virtual void tick(float adjust)
179 {
180 slowDownAfterIntro(adjust);
181 moveLetters(adjust);
182 }
183
184};
185
186class EffectWhirlWind : public TickerEffect
187{
188public:
189 EffectWhirlWind(LetterList *letters) : TickerEffect(letters)
190 {
191 moveSpeed = 50;
192 for (int i=0; i<this->letters->size(); i++){
193 LetterItem *letter = this->letters->at(i);
194 letter->setGuidedPos(QPointF(0, 100));
195 }
196 }
197};
198
199class EffectSnake : public TickerEffect
200{
201public:
202 EffectSnake(LetterList *letters) : TickerEffect(letters)
203 {
204 moveSpeed = 40;
205 for (int i=0; i<this->letters->size(); i++){
206 LetterItem *letter = this->letters->at(i);
207 letter->setGuidedPos(QPointF(0, -250 - (i * 5)));
208 }
209 }
210};
211
212class EffectScan : public TickerEffect
213{
214public:
215 EffectScan(LetterList *letters) : TickerEffect(letters)
216 {
217 for (int i=0; i<this->letters->size(); i++){
218 LetterItem *letter = this->letters->at(i);
219 letter->setGuidedPos(QPointF(100, -300));
220 }
221 }
222};
223
224class EffectRaindrops : public TickerEffect
225{
226public:
227 EffectRaindrops(LetterList *letters) : TickerEffect(letters)
228 {
229 for (int i=0; i<this->letters->size(); i++){
230 LetterItem *letter = this->letters->at(i);
231 letter->setGuidedPos(QPointF(-100 + rand() % 200, - 200.0f - rand() % 1300));
232 }
233 }
234};
235
236class EffectLine : public TickerEffect
237{
238public:
239 EffectLine(LetterList *letters) : TickerEffect(letters)
240 {
241 for (int i=0; i<this->letters->size(); i++){
242 LetterItem *letter = this->letters->at(i);
243 letter->setGuidedPos(QPointF(100, 500.0f + i * 20));
244 }
245 }
246};
247
248//////////////////// TICKER STUFF /////////////////////////////////////////////
249
250ItemCircleAnimation::ItemCircleAnimation(QGraphicsScene *scene, QGraphicsItem *parent)
251 : DemoItem(scene, parent)
252{
253 sscene = scene;
254 this->letterCount = Colors::tickerLetterCount;
255 this->scale = 1;
256 this->showCount = -1;
257 this->tickOnPaint = false;
258 this->paused = false;
259 this->doIntroTransitions = true;
260 this->setAcceptsHoverEvents(true);
261 this->setCursor(Qt::OpenHandCursor);
262 this->setupGuides();
263 this->setupLetters();
264 this->useGuideQt();
265 this->effect = 0;//new TickerEffect(this->letterList);
266}
267
268ItemCircleAnimation::~ItemCircleAnimation()
269{
270 delete this->letterList;
271 delete this->qtGuide1;
272 delete this->qtGuide2;
273 delete this->qtGuide3;
274 delete this->effect;
275}
276
277void ItemCircleAnimation::createLetter(char c)
278{
279 LetterItem *letter = new LetterItem(c, sscene, this);
280 this->letterList->append(letter);
281}
282
283void ItemCircleAnimation::setupLetters()
284{
285 this->letterList = new LetterList();
286
287 QString s = Colors::tickerText;
288 int len = s.length();
289 int i = 0;
290 for (; i < this->letterCount - len; i += len)
291 for (int l=0; l<len; l++)
292 createLetter(s[l].toLatin1());
293
294 // Fill inn with blanks:
295 for (; i < this->letterCount; ++i)
296 createLetter(' ');
297}
298
299void ItemCircleAnimation::setupGuides()
300{
301 int x = 0;
302 int y = 20;
303
304 this->qtGuide1 = new GuideCircle(QRectF(x, y, 260, 260), -36, 342);
305 this->currGuide = 0;
306 new GuideLine(QPointF(x + 240, y + 268), this->qtGuide1);
307 new GuideLine(QPointF(x + 265, y + 246), this->qtGuide1);
308 new GuideLine(QPointF(x + 158, y + 134), this->qtGuide1);
309 new GuideLine(QPointF(x + 184, y + 109), this->qtGuide1);
310 new GuideLine(QPointF(x + 160, y + 82), this->qtGuide1);
311 new GuideLine(QPointF(x + 77, y + 163), this->qtGuide1); // T-top
312 new GuideLine(QPointF(x + 100, y + 190), this->qtGuide1);
313 new GuideLine(QPointF(x + 132, y + 159), this->qtGuide1);
314 new GuideLine(QPointF(x + 188, y + 211), this->qtGuide1);
315 new GuideCircle(QRectF(x + 30, y + 30, 200, 200), -30, 336, GuideCircle::CW, this->qtGuide1);
316 new GuideLine(QPointF(x + 238, y + 201), this->qtGuide1);
317
318 y = 30;
319 this->qtGuide2 = new GuideCircle(QRectF(x + 30, y + 30, 200, 200), 135, 270, GuideCircle::CCW);
320 new GuideLine(QPointF(x + 222, y + 38), this->qtGuide2);
321 new GuideCircle(QRectF(x, y, 260, 260), 135, 270, GuideCircle::CW, this->qtGuide2);
322 new GuideLine(QPointF(x + 59, y + 59), this->qtGuide2);
323
324 x = 115;
325 y = 10;
326 this->qtGuide3 = new GuideLine(QLineF(x, y, x + 30, y));
327 new GuideLine(QPointF(x + 30, y + 170), this->qtGuide3);
328 new GuideLine(QPointF(x, y + 170), this->qtGuide3);
329 new GuideLine(QPointF(x, y), this->qtGuide3);
330
331 this->qtGuide1->setFence(QRectF(0, 0, 800, 600));
332 this->qtGuide2->setFence(QRectF(0, 0, 800, 600));
333 this->qtGuide3->setFence(QRectF(0, 0, 800, 600));
334}
335
336void ItemCircleAnimation::useGuide(Guide *guide, int firstLetter, int lastLetter)
337{
338 float padding = guide->lengthAll() / float(lastLetter - firstLetter);
339 for (int i=firstLetter; i<lastLetter; i++){
340 LetterItem *letter = this->letterList->at(i);
341 letter->useGuide(guide, (i - firstLetter) * padding);
342 }
343}
344
345void ItemCircleAnimation::useGuideQt()
346{
347 if (this->currGuide != this->qtGuide1){
348 this->useGuide(qtGuide1, 0, this->letterCount);
349 this->currGuide = qtGuide1;
350 }
351}
352
353void ItemCircleAnimation::useGuideTt()
354{
355 if (this->currGuide != this->qtGuide2){
356 int split = int(this->letterCount * 5.0 / 7.0);
357 this->useGuide(qtGuide2, 0, split);
358 this->useGuide(qtGuide3, split, this->letterCount);
359 this->currGuide = qtGuide2;
360 }
361}
362
363QRectF ItemCircleAnimation::boundingRect() const
364{
365 return QRectF(0, 0, 300, 320);
366}
367
368void ItemCircleAnimation::prepare()
369{
370}
371
372void ItemCircleAnimation::switchToNextEffect()
373{
374 ++this->showCount;
375 delete this->effect;
376
377 switch (this->showCount){
378 case 1:
379 this->effect = new EffectSnake(this->letterList);
380 break;
381 case 2:
382 this->effect = new EffectLine(this->letterList);
383 this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.0f, 0.003f, 0.0f));
384 break;
385 case 3:
386 this->effect = new EffectRaindrops(this->letterList);
387 this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.005f, 0.003f, 0.003f));
388 break;
389 case 4:
390 this->effect = new EffectScan(this->letterList);
391 this->effect->normalMoveSpeed = 0;
392 this->effect->setPostEffect(new PostRotateXY(0.008f, 0.0f, 0.005f, 0.0f));
393 break;
394 default:
395 this->showCount = 0;
396 this->effect = new EffectWhirlWind(this->letterList);
397 }
398}
399
400void ItemCircleAnimation::animationStarted(int id)
401{
402 if (id == DemoItemAnimation::ANIM_IN){
403 if (this->doIntroTransitions){
404 // Make all letters dissapear
405 for (int i=0; i<this->letterList->size(); i++){
406 LetterItem *letter = this->letterList->at(i);
407 letter->setPos(1000, 0);
408 }
409 this->switchToNextEffect();
410 this->useGuideQt();
411 this->scale = 1;
412 // The first time we run, we have a rather large
413 // delay to perform benchmark before the ticker shows.
414 // But now, since we are showing, use a more appropriate value:
415 this->currentAnimation->startDelay = 1500;
416 }
417 }
418 else if (this->effect)
419 this->effect->useSheepDog = false;
420
421 this->tickTimer = QTime::currentTime();
422}
423
424void ItemCircleAnimation::animationStopped(int)
425{
426 // Nothing to do.
427}
428
429void ItemCircleAnimation::swapModel(){
430 if (this->currGuide == this->qtGuide2)
431 this->useGuideQt();
432 else
433 this->useGuideTt();
434}
435
436void ItemCircleAnimation::hoverEnterEvent(QGraphicsSceneHoverEvent *)
437{
438// Skip swap here to enhance ticker dragging
439// this->swapModel();
440}
441
442void ItemCircleAnimation::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
443{
444 this->swapModel();
445}
446
447void ItemCircleAnimation::setTickerScale(float s)
448{
449 this->scale = s;
450 qtGuide1->setScale(this->scale, this->scale);
451 qtGuide2->setScale(this->scale, this->scale);
452 qtGuide3->setScale(this->scale, this->scale);
453}
454
455void ItemCircleAnimation::mousePressEvent(QGraphicsSceneMouseEvent *event)
456{
457 this->mouseMoveLastPosition = event->scenePos();
458 if (event->button() == Qt::LeftButton)
459 this->setCursor(Qt::ClosedHandCursor);
460 else
461 this->switchToNextEffect();
462}
463
464void ItemCircleAnimation::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
465{
466 if (event->button() == Qt::LeftButton)
467 this->setCursor(Qt::OpenHandCursor);
468}
469
470void ItemCircleAnimation::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
471{
472 QPointF newPosition = event->scenePos();
473 this->setPosUsingSheepDog(this->pos() + newPosition - this->mouseMoveLastPosition, QRectF(-260, -280, 1350, 1160));
474 this->mouseMoveLastPosition = newPosition;
475}
476
477void ItemCircleAnimation::wheelEvent(QGraphicsSceneWheelEvent *event)
478{
479 this->effect->moveSpeed = this->effect->moveSpeed + (event->delta() > 0 ? -0.20 : 0.20);
480 if (this->effect->moveSpeed < 0)
481 this->effect->moveSpeed = 0;
482}
483
484void ItemCircleAnimation::pause(bool on)
485{
486 this->paused = on;
487 this->tickTimer = QTime::currentTime();
488}
489
490void ItemCircleAnimation::tick()
491{
492 if (this->paused || !this->effect)
493 return;
494
495 float t = this->tickTimer.msecsTo(QTime::currentTime());
496 this->tickTimer = QTime::currentTime();
497 this->effect->tick(t/10.0f);
498}
499
500void ItemCircleAnimation::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
501{
502 if (this->tickOnPaint)
503 tick();
504}
505
506
507
508
Note: See TracBrowser for help on using the repository browser.