1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the demonstration applications of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "itemcircleanimation.h"
43 #include "demoitemanimation.h"
45 #include "menumanager.h"
46 #include "mainwindow.h"
47 #include "menumanager.h"
49 static QGraphicsScene *sscene;
51 //////////////////// POST EFFECT STUFF ////////////////////////////////////////
53 class TickerPostEffect
56 virtual ~TickerPostEffect(){};
57 virtual void tick(float){};
58 virtual void transform(DemoItem *, QPointF &){};
61 class PostRotateXY : public TickerPostEffect
64 float currRotX, currRotY;
65 float speedx, speedy, curvx, curvy;
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){};
72 void tick(float adjust)
74 currRotX += speedx * adjust;
75 currRotY += speedy * adjust;
78 void transform(DemoItem *item, QPointF &pos)
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));
87 class PostRotateXYTwist : public TickerPostEffect
90 float currRotX, currRotY;
91 float speedx, speedy, curvx, curvy;
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){};
98 void tick(float adjust)
100 currRotX += speedx * adjust;
101 currRotY += speedy * adjust;
104 void transform(DemoItem *item, QPointF &pos)
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));
113 //////////////////// TICKER EFFECT STUFF //////////////////////////////////////
117 TickerPostEffect *postEffect;
119 enum EffectStatus{Normal, Intro, Outro} status;
121 float morphSpeed, moveSpeed;
122 float normalMorphSpeed, normalMoveSpeed;
123 bool useSheepDog, morphBetweenModels;
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){}
131 void setPostEffect(TickerPostEffect *effect)
137 virtual ~TickerEffect()
142 void slowDownAfterIntro(float adjust)
144 if (morphBetweenModels){
145 if (status == Intro){
146 float dec = 0.1 * adjust;
148 if (moveSpeed < Colors::tickerMoveSpeed){
149 moveSpeed = normalMoveSpeed;
150 morphSpeed = normalMorphSpeed;
157 void moveLetters(float adjust)
159 float adaptedMoveSpeed = this->moveSpeed * adjust;
160 float adaptedMorphSpeed = this->morphSpeed * adjust;
161 postEffect->tick(adjust);
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);
168 QPointF pos = letter->getGuidedPos();
169 postEffect->transform(letter, pos);
172 letter->setPosUsingSheepDog(pos, QRectF(0, 0, 800, 600));
178 virtual void tick(float adjust)
180 slowDownAfterIntro(adjust);
186 class EffectWhirlWind : public TickerEffect
189 EffectWhirlWind(LetterList *letters) : TickerEffect(letters)
192 for (int i=0; i<this->letters->size(); i++){
193 LetterItem *letter = this->letters->at(i);
194 letter->setGuidedPos(QPointF(0, 100));
199 class EffectSnake : public TickerEffect
202 EffectSnake(LetterList *letters) : TickerEffect(letters)
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)));
212 class EffectScan : public TickerEffect
215 EffectScan(LetterList *letters) : TickerEffect(letters)
217 for (int i=0; i<this->letters->size(); i++){
218 LetterItem *letter = this->letters->at(i);
219 letter->setGuidedPos(QPointF(100, -300));
224 class EffectRaindrops : public TickerEffect
227 EffectRaindrops(LetterList *letters) : TickerEffect(letters)
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));
236 class EffectLine : public TickerEffect
239 EffectLine(LetterList *letters) : TickerEffect(letters)
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));
248 //////////////////// TICKER STUFF /////////////////////////////////////////////
250 ItemCircleAnimation::ItemCircleAnimation(QGraphicsScene *scene, QGraphicsItem *parent)
251 : DemoItem(scene, parent)
254 this->letterCount = Colors::tickerLetterCount;
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);
263 this->setupLetters();
265 this->effect = 0;//new TickerEffect(this->letterList);
268 ItemCircleAnimation::~ItemCircleAnimation()
270 delete this->letterList;
271 delete this->qtGuide1;
272 delete this->qtGuide2;
273 delete this->qtGuide3;
277 void ItemCircleAnimation::createLetter(char c)
279 LetterItem *letter = new LetterItem(c, sscene, this);
280 this->letterList->append(letter);
283 void ItemCircleAnimation::setupLetters()
285 this->letterList = new LetterList();
287 QString s = Colors::tickerText;
288 int len = s.length();
290 for (; i < this->letterCount - len; i += len)
291 for (int l=0; l<len; l++)
292 createLetter(s[l].toLatin1());
294 // Fill inn with blanks:
295 for (; i < this->letterCount; ++i)
299 void ItemCircleAnimation::setupGuides()
304 this->qtGuide1 = new GuideCircle(QRectF(x, y, 260, 260), -36, 342);
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);
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);
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);
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));
336 void ItemCircleAnimation::useGuide(Guide *guide, int firstLetter, int lastLetter)
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);
345 void ItemCircleAnimation::useGuideQt()
347 if (this->currGuide != this->qtGuide1){
348 this->useGuide(qtGuide1, 0, this->letterCount);
349 this->currGuide = qtGuide1;
353 void ItemCircleAnimation::useGuideTt()
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;
363 QRectF ItemCircleAnimation::boundingRect() const
365 return QRectF(0, 0, 300, 320);
368 void ItemCircleAnimation::prepare()
372 void ItemCircleAnimation::switchToNextEffect()
377 switch (this->showCount){
379 this->effect = new EffectSnake(this->letterList);
382 this->effect = new EffectLine(this->letterList);
383 this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.0f, 0.003f, 0.0f));
386 this->effect = new EffectRaindrops(this->letterList);
387 this->effect->setPostEffect(new PostRotateXYTwist(0.01f, 0.005f, 0.003f, 0.003f));
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));
396 this->effect = new EffectWhirlWind(this->letterList);
400 void ItemCircleAnimation::animationStarted(int id)
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);
409 this->switchToNextEffect();
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;
418 else if (this->effect)
419 this->effect->useSheepDog = false;
421 this->tickTimer = QTime::currentTime();
424 void ItemCircleAnimation::animationStopped(int)
429 void ItemCircleAnimation::swapModel(){
430 if (this->currGuide == this->qtGuide2)
436 void ItemCircleAnimation::hoverEnterEvent(QGraphicsSceneHoverEvent *)
438 // Skip swap here to enhance ticker dragging
439 // this->swapModel();
442 void ItemCircleAnimation::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
447 void ItemCircleAnimation::setTickerScale(float s)
450 qtGuide1->setScale(this->scale, this->scale);
451 qtGuide2->setScale(this->scale, this->scale);
452 qtGuide3->setScale(this->scale, this->scale);
455 void ItemCircleAnimation::mousePressEvent(QGraphicsSceneMouseEvent *event)
457 this->mouseMoveLastPosition = event->scenePos();
458 if (event->button() == Qt::LeftButton)
459 this->setCursor(Qt::ClosedHandCursor);
461 this->switchToNextEffect();
464 void ItemCircleAnimation::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
466 if (event->button() == Qt::LeftButton)
467 this->setCursor(Qt::OpenHandCursor);
470 void ItemCircleAnimation::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
472 QPointF newPosition = event->scenePos();
473 this->setPosUsingSheepDog(this->pos() + newPosition - this->mouseMoveLastPosition, QRectF(-260, -280, 1350, 1160));
474 this->mouseMoveLastPosition = newPosition;
477 void ItemCircleAnimation::wheelEvent(QGraphicsSceneWheelEvent *event)
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;
484 void ItemCircleAnimation::pause(bool on)
487 this->tickTimer = QTime::currentTime();
490 void ItemCircleAnimation::tick()
492 if (this->paused || !this->effect)
495 float t = this->tickTimer.msecsTo(QTime::currentTime());
496 this->tickTimer = QTime::currentTime();
497 this->effect->tick(t/10.0f);
500 void ItemCircleAnimation::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
502 if (this->tickOnPaint)