|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 #include "HgMediaWallRenderer.h" |
|
18 #include "hgmediawalldataprovider.h" |
|
19 #include "hgquadrenderer.h" |
|
20 #include "hgquad.h" |
|
21 #include "hgimage.h" |
|
22 #include "HgImageFader.h" |
|
23 #include "hgvgquadrenderer.h" |
|
24 #include <qvector3d> |
|
25 #include <qtimer> |
|
26 #include <qpropertyanimation> |
|
27 #include <qstate.h> |
|
28 #include <qabstracttransition> |
|
29 #include <qstatemachine> |
|
30 #include <qsignaltransition> |
|
31 #include <qsequentialanimationgroup> |
|
32 #include <qparallelanimationgroup> |
|
33 #include <qvariantanimation> |
|
34 #include <qpolygon> |
|
35 #include <qpainter> |
|
36 #include <qpaintengine> |
|
37 |
|
38 const Qt::Orientation KDefaultOrientation(Qt::Vertical); |
|
39 const qreal KPi = 3.1415926535897932384626433832795; |
|
40 |
|
41 static qreal lerp(qreal start, qreal end, qreal t) |
|
42 { |
|
43 return start * (1.0f - t) + end * t; |
|
44 } |
|
45 |
|
46 class MyVectorAnimation : public QVariantAnimation |
|
47 { |
|
48 public: |
|
49 virtual void updateCurrentValue(const QVariant& value) |
|
50 { |
|
51 mValue = value.value<QVector3D>(); |
|
52 } |
|
53 QVector3D getValue() const |
|
54 { |
|
55 return mValue; |
|
56 } |
|
57 private: |
|
58 QVector3D mValue; |
|
59 }; |
|
60 |
|
61 class HgAnimatedQuad |
|
62 { |
|
63 public: |
|
64 |
|
65 HgAnimatedQuad(HgQuad* start, HgQuad* end, |
|
66 int duration) : mQuad(start) |
|
67 { |
|
68 mPositionAnimation.setDuration(duration); |
|
69 mPositionAnimation.setKeyValueAt(0, start->position()); |
|
70 mPositionAnimation.setKeyValueAt(1.0, end->position()); |
|
71 mPositionAnimation.setEasingCurve(QEasingCurve::Linear); |
|
72 |
|
73 mScaleAnimation.setDuration(duration); |
|
74 mScaleAnimation.setKeyValueAt(0, QVector3D(start->scale().x(), start->scale().y(), 0)); |
|
75 mScaleAnimation.setKeyValueAt(1, QVector3D(end->scale().x(), end->scale().y(), 0)); |
|
76 mScaleAnimation.setEasingCurve(QEasingCurve::Linear); |
|
77 |
|
78 } |
|
79 |
|
80 ~HgAnimatedQuad() |
|
81 { |
|
82 } |
|
83 |
|
84 void start() |
|
85 { |
|
86 mPositionAnimation.start(); |
|
87 mScaleAnimation.start(); |
|
88 } |
|
89 |
|
90 void update() |
|
91 { |
|
92 mQuad->setPosition(mPositionAnimation.currentValue().value<QVector3D>()); |
|
93 QVector3D scale = mScaleAnimation.currentValue().value<QVector3D>(); |
|
94 mQuad->setScale(QVector2D(scale.x(), scale.y())); |
|
95 } |
|
96 |
|
97 HgQuad* mQuad; |
|
98 MyVectorAnimation mPositionAnimation; |
|
99 MyVectorAnimation mScaleAnimation; |
|
100 }; |
|
101 |
|
102 HgMediaWallRenderer::HgMediaWallRenderer(HgMediaWallDataProvider* provider) : |
|
103 mDataProvider(provider), |
|
104 mRenderer(NULL), |
|
105 mIndicatorRenderer(NULL), |
|
106 mRendererInitialized(false), |
|
107 mOrientation(KDefaultOrientation), |
|
108 mNextOrientation(KDefaultOrientation), |
|
109 mStateAnimationAlpha(0), |
|
110 mStateAnimationOnGoing(false), |
|
111 mAnimationAlpha(0), |
|
112 mOpeningAnimationDuration(500), |
|
113 mOpenedItem(-1), |
|
114 mFlipAngle(qreal(360)), |
|
115 mZoomAmount(qreal(0.5)), |
|
116 mCoverflowMode(false), |
|
117 mRowCount(1), |
|
118 mNextRowCount(1), |
|
119 mStateAnimationDuration(300), |
|
120 mStep(1.1), |
|
121 mZfar(-2), |
|
122 mSpacing2D(10,10), |
|
123 mImageSize2D(100, 60), |
|
124 mCameraDistance(0), |
|
125 mCameraRotationY(0), |
|
126 mCameraRotationZ(0), |
|
127 mFrontCoverElevation(0.4), |
|
128 mReflectionsEnabled(true), |
|
129 mItemCountChanged(false), |
|
130 mOpenedItemState(ItemClosed) |
|
131 { |
|
132 createStateMachine(); |
|
133 mImageFader = new HgImageFader(); |
|
134 mRenderer = new HgVgQuadRenderer(256); |
|
135 mRendererInitialized = true; |
|
136 } |
|
137 |
|
138 HgMediaWallRenderer::~HgMediaWallRenderer() |
|
139 { |
|
140 delete mRenderer; |
|
141 delete mImageFader; |
|
142 delete mStateMachine; |
|
143 } |
|
144 |
|
145 |
|
146 void HgMediaWallRenderer::setCameraDistance(qreal distance) |
|
147 { |
|
148 mCameraDistance = distance; |
|
149 } |
|
150 |
|
151 void HgMediaWallRenderer::setCameraRotationY(qreal angle) |
|
152 { |
|
153 mCameraRotationY = angle; |
|
154 } |
|
155 |
|
156 void HgMediaWallRenderer::setCameraRotationZ(qreal angle) |
|
157 { |
|
158 mCameraRotationZ = angle; |
|
159 } |
|
160 |
|
161 qreal HgMediaWallRenderer::getCameraDistance() const |
|
162 { |
|
163 return mCameraDistance; |
|
164 } |
|
165 |
|
166 qreal HgMediaWallRenderer::getCameraRotationY() const |
|
167 { |
|
168 return mCameraRotationY; |
|
169 } |
|
170 |
|
171 qreal HgMediaWallRenderer::getCameraRotationZ() const |
|
172 { |
|
173 return mCameraRotationZ; |
|
174 } |
|
175 |
|
176 void HgMediaWallRenderer::draw( |
|
177 const QPointF& startPosition, |
|
178 const QPointF& position, |
|
179 const QPointF& targetPosition, |
|
180 qreal springVelocity, |
|
181 QPainter* painter) |
|
182 { |
|
183 // if still not initialized we cant draw anything |
|
184 if (!mRendererInitialized) |
|
185 return; |
|
186 |
|
187 if (mOrientation != mNextOrientation || |
|
188 mRowCount != mNextRowCount) |
|
189 { |
|
190 |
|
191 // save old state of the quads |
|
192 recordState(mOldState); |
|
193 |
|
194 // goto wanted orientation / rowcount |
|
195 mOrientation = mNextOrientation; |
|
196 mRowCount = mNextRowCount; |
|
197 setImageSize(mNextImageSize); |
|
198 |
|
199 // setup quads to new state |
|
200 setupRows(startPosition, position, targetPosition, springVelocity, painter); |
|
201 |
|
202 // record state for animation |
|
203 recordState(mNextState); |
|
204 |
|
205 startStateAnimation(painter); |
|
206 } |
|
207 else |
|
208 { |
|
209 if (!mStateAnimationOnGoing) |
|
210 { |
|
211 setupRows(startPosition, position, targetPosition, springVelocity, painter); |
|
212 } |
|
213 else |
|
214 { |
|
215 setupStateAnimation(painter); |
|
216 } |
|
217 } |
|
218 |
|
219 updateCameraMatrices(); |
|
220 drawQuads(painter); |
|
221 } |
|
222 |
|
223 void HgMediaWallRenderer::setupRows(const QPointF& startPosition, |
|
224 const QPointF& position, |
|
225 const QPointF& targetPosition, |
|
226 qreal springVelocity, |
|
227 QPainter* painter) |
|
228 { |
|
229 // draw the state for it |
|
230 resetQuads(); |
|
231 updateSpacingAndImageSize(); |
|
232 |
|
233 if (mCoverflowMode) |
|
234 { |
|
235 //setupRow(startPosition, position, targetPosition, springVelocity, painter, 0); |
|
236 setupCoverflow(startPosition, position, targetPosition, springVelocity, painter); |
|
237 } |
|
238 else |
|
239 { |
|
240 if (mOrientation == Qt::Vertical) |
|
241 { |
|
242 setupGridPortrait(startPosition, position, targetPosition, |
|
243 springVelocity, painter); |
|
244 } |
|
245 else |
|
246 { |
|
247 setupGridLandscape(startPosition, position, targetPosition, |
|
248 springVelocity, painter); |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 void HgMediaWallRenderer::setFlipAnimationAngle(qreal angleInDegrees) |
|
254 { |
|
255 mFlipAngle = angleInDegrees; |
|
256 } |
|
257 |
|
258 void HgMediaWallRenderer::setOpeningAnimationType(HgMediaWallRenderer::OpeningAnimationType type) |
|
259 { |
|
260 mOpeningAnimationType = type; |
|
261 } |
|
262 |
|
263 void HgMediaWallRenderer::setOpeningAnimationDuration(int msecs) |
|
264 { |
|
265 mOpeningAnimationDuration = msecs; |
|
266 } |
|
267 |
|
268 qreal HgMediaWallRenderer::animationAlpha() const |
|
269 { |
|
270 return mAnimationAlpha; |
|
271 } |
|
272 |
|
273 void HgMediaWallRenderer::setAnimationAlpha(qreal alpha) |
|
274 { |
|
275 mAnimationAlpha = alpha; |
|
276 |
|
277 if (mOpenedItemState == ItemClosing && alpha == 0.0f) |
|
278 mOpenedItemState = ItemClosed; |
|
279 |
|
280 if (mOpenedItemState == ItemOpening && alpha == 1.0f) |
|
281 mOpenedItemState = ItemOpened; |
|
282 |
|
283 emit renderingNeeded(); |
|
284 } |
|
285 |
|
286 qreal HgMediaWallRenderer::stateAnimationAlpha() const |
|
287 { |
|
288 return mStateAnimationAlpha; |
|
289 } |
|
290 |
|
291 void HgMediaWallRenderer::setStateAnimationAlpha(qreal alpha) |
|
292 { |
|
293 mStateAnimationAlpha = alpha; |
|
294 if (alpha == 1 && mStateAnimationOnGoing) |
|
295 { |
|
296 mStateAnimationOnGoing = false; |
|
297 } |
|
298 emit renderingNeeded(); |
|
299 } |
|
300 |
|
301 void HgMediaWallRenderer::createStateMachine() |
|
302 { |
|
303 mStateMachine = new QStateMachine(this); |
|
304 mStateMachine->setAnimated(true); |
|
305 |
|
306 QState* root = new QState(QState::ParallelStates); |
|
307 QState* p1 = new QState(root); |
|
308 QState* p2 = new QState(root); |
|
309 |
|
310 // create idle/opened states |
|
311 { |
|
312 QState* idle = new QState(p1); |
|
313 QState* opened = new QState(p1); |
|
314 |
|
315 idle->assignProperty(this, "animationAlpha", qreal(0)); |
|
316 opened->assignProperty(this, "animationAlpha", qreal(1)); |
|
317 |
|
318 // add opening animation |
|
319 QPropertyAnimation* anim1 = new QPropertyAnimation(this, "animationAlpha"); |
|
320 anim1->setDuration(mOpeningAnimationDuration); |
|
321 idle->addTransition(this, SIGNAL(toggleItem()), opened)->addAnimation(anim1); |
|
322 |
|
323 // add closing animation |
|
324 QPropertyAnimation* anim2 = new QPropertyAnimation(this, "animationAlpha"); |
|
325 anim2->setDuration(mOpeningAnimationDuration); |
|
326 opened->addTransition(this, SIGNAL(toggleItem()), idle)->addAnimation(anim2); |
|
327 |
|
328 QObject::connect(idle, SIGNAL(entered()), this, SLOT(onIdleState())); |
|
329 QObject::connect(opened, SIGNAL(entered()), this, SLOT(onOpenedState())); |
|
330 |
|
331 p1->setInitialState(idle); |
|
332 } |
|
333 |
|
334 // create two states to animate between |
|
335 { |
|
336 QState* s1 = new QState(p2); |
|
337 QState* s2 = new QState(p2); |
|
338 |
|
339 s1->assignProperty(this, "stateAnimationAlpha", qreal(0)); |
|
340 s2->assignProperty(this, "stateAnimationAlpha", qreal(0)); |
|
341 |
|
342 QPropertyAnimation* anim = new QPropertyAnimation(this, "stateAnimationAlpha"); |
|
343 anim->setStartValue(qreal(0)); |
|
344 anim->setEndValue(qreal(1)); |
|
345 anim->setDuration(mStateAnimationDuration); |
|
346 |
|
347 s1->addTransition(this, SIGNAL(toggleState()), s2)->addAnimation(anim); |
|
348 s2->addTransition(this, SIGNAL(toggleState()), s1)->addAnimation(anim); |
|
349 |
|
350 p2->setInitialState(s1); |
|
351 } |
|
352 |
|
353 root->setInitialState(p1); |
|
354 mStateMachine->addState(root); |
|
355 mStateMachine->setInitialState(root); |
|
356 mStateMachine->start(); |
|
357 |
|
358 } |
|
359 |
|
360 void HgMediaWallRenderer::onIdleState() |
|
361 { |
|
362 emit itemClosed(mOpenedItem); |
|
363 } |
|
364 |
|
365 void HgMediaWallRenderer::onOpenedState() |
|
366 { |
|
367 emit itemOpened(mOpenedItem); |
|
368 } |
|
369 |
|
370 void HgMediaWallRenderer::setOrientation(Qt::Orientation orientation, bool animate) |
|
371 { |
|
372 if (mOrientation != orientation) |
|
373 { |
|
374 mStateMachine->setAnimated(animate); |
|
375 mNextOrientation = orientation; |
|
376 |
|
377 if (!animate) |
|
378 mOrientation = orientation; |
|
379 else |
|
380 { |
|
381 emit renderingNeeded(); |
|
382 } |
|
383 } |
|
384 } |
|
385 |
|
386 Qt::Orientation HgMediaWallRenderer::getOrientation() const |
|
387 { |
|
388 return mOrientation; |
|
389 } |
|
390 |
|
391 void HgMediaWallRenderer::drawQuads(QPainter* painter) |
|
392 { |
|
393 mRenderer->transformQuads(mViewMatrix, mProjMatrix, mRect); |
|
394 |
|
395 mRenderer->drawQuads(mRect, painter); |
|
396 } |
|
397 |
|
398 |
|
399 void HgMediaWallRenderer::enableCoverflowMode(bool enabled) |
|
400 { |
|
401 mCoverflowMode = enabled; |
|
402 } |
|
403 |
|
404 bool HgMediaWallRenderer::coverflowModeEnabled() const |
|
405 { |
|
406 return mCoverflowMode; |
|
407 } |
|
408 |
|
409 void HgMediaWallRenderer::setRowCount(int rowCount, const QSizeF& newImageSize, bool animate) |
|
410 { |
|
411 if (rowCount != mRowCount) |
|
412 { |
|
413 mStateMachine->setAnimated(animate); |
|
414 |
|
415 mNextRowCount = rowCount; |
|
416 mNextImageSize = newImageSize; |
|
417 |
|
418 mColumnCount = rowCount; |
|
419 |
|
420 if (!animate) |
|
421 { |
|
422 mRowCount = rowCount; |
|
423 } |
|
424 else |
|
425 { |
|
426 emit renderingNeeded(); |
|
427 } |
|
428 |
|
429 } |
|
430 |
|
431 } |
|
432 |
|
433 int HgMediaWallRenderer::getRowCount() const |
|
434 { |
|
435 return mRowCount; |
|
436 } |
|
437 |
|
438 void HgMediaWallRenderer::recordState(HgMediaWallRenderer::State& state) |
|
439 { |
|
440 // cleanup old quads |
|
441 for (int i = 0; i < state.mQuads.size(); i++) |
|
442 { |
|
443 delete state.mQuads[i]; |
|
444 } |
|
445 |
|
446 state.mQuads.clear(); |
|
447 |
|
448 // record new quads |
|
449 for (int i = 0; i < mRenderer->quadCount(); i++) |
|
450 { |
|
451 HgQuad* quad = mRenderer->quad(i); |
|
452 if (!quad->visible()) |
|
453 continue; |
|
454 |
|
455 state.mQuads.append(quad->copy()); |
|
456 } |
|
457 } |
|
458 |
|
459 void HgMediaWallRenderer::setupStateAnimation(QPainter* painter) |
|
460 { |
|
461 Q_UNUSED(painter) |
|
462 |
|
463 resetQuads(); |
|
464 // setup quads from animated state |
|
465 for (int i = 0; i < mOldState.mQuads.size(); i++) |
|
466 { |
|
467 mAnimatedQuads[i]->update(); |
|
468 mRenderer->quad(i)->copyFrom(*mOldState.mQuads[i]); |
|
469 } |
|
470 } |
|
471 |
|
472 void HgMediaWallRenderer::resetQuads() |
|
473 { |
|
474 for (int i = 0; i < mRenderer->quadCount(); i++) |
|
475 mRenderer->quad(i)->setVisible(false); |
|
476 } |
|
477 |
|
478 HgQuad* HgMediaWallRenderer::getQuadAt(const QPointF& position) const |
|
479 { |
|
480 if (!mRendererInitialized) |
|
481 return NULL; |
|
482 |
|
483 return mRenderer->getQuadAt(position);//mapFromWindow(position)); |
|
484 } |
|
485 |
|
486 bool HgMediaWallRenderer::isItemOpen() const |
|
487 { |
|
488 return (mOpenedItem != -1 && mAnimationAlpha > 0); |
|
489 } |
|
490 |
|
491 void HgMediaWallRenderer::setRect(const QRectF& windowRect) |
|
492 { |
|
493 mRect = windowRect; |
|
494 } |
|
495 |
|
496 const QRectF& HgMediaWallRenderer::getRect() const |
|
497 { |
|
498 return mRect; |
|
499 } |
|
500 |
|
501 void HgMediaWallRenderer::updateCameraMatrices() |
|
502 { |
|
503 QMatrix4x4 view; |
|
504 |
|
505 view.setToIdentity(); |
|
506 |
|
507 view.lookAt(QVector3D(0.0, 0.0, 1.0f + mCameraDistance), |
|
508 QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f)); |
|
509 |
|
510 QMatrix4x4 rot; |
|
511 rot.rotate(mCameraRotationZ, QVector3D(0,0,1)); |
|
512 rot.rotate(mCameraRotationY, QVector3D(0,1,0)); |
|
513 view *= rot; |
|
514 |
|
515 qreal aspect = mRect.width() / mRect.height(); |
|
516 |
|
517 QMatrix4x4 proj; |
|
518 proj.setToIdentity(); |
|
519 |
|
520 if (mRect.width() <= mRect.height()) |
|
521 { |
|
522 qreal aspect = mRect.height() / mRect.width(); |
|
523 proj.frustum(-0.5f, 0.5f, -0.5f*aspect, 0.5f*aspect, 1.0f, 1000.0f); |
|
524 } |
|
525 else |
|
526 { |
|
527 qreal aspect = mRect.width() / mRect.height(); |
|
528 proj.frustum(-0.5f*aspect, 0.5f*aspect, -0.5f, 0.5f, 1.0f, 1000.0f); |
|
529 } |
|
530 |
|
531 mViewMatrix = view; |
|
532 mProjMatrix = proj; |
|
533 |
|
534 qreal mirrorPlaneY = getRowPosY(mRowCount-1)-mImageSize3D.height()/2; |
|
535 mRenderer->setMirroringPlaneY(mirrorPlaneY); |
|
536 } |
|
537 |
|
538 void HgMediaWallRenderer::updateSpacingAndImageSize() |
|
539 { |
|
540 qreal div = mRect.width() <= mRect.height() ? mRect.width() : mRect.height(); |
|
541 |
|
542 mSpacing3D = mSpacing2D / div; |
|
543 mImageSize3D = mImageSize2D / div; |
|
544 } |
|
545 |
|
546 void HgMediaWallRenderer::setSpacing(const QSizeF& spacing) |
|
547 { |
|
548 mSpacing2D = spacing; |
|
549 } |
|
550 |
|
551 void HgMediaWallRenderer::setImageSize(const QSizeF& imageSize) |
|
552 { |
|
553 mImageSize2D = imageSize; |
|
554 mNextImageSize = imageSize; |
|
555 } |
|
556 |
|
557 const QSizeF& HgMediaWallRenderer::getSpacing() const |
|
558 { |
|
559 return mSpacing2D; |
|
560 } |
|
561 |
|
562 const QSizeF& HgMediaWallRenderer::getImageSize() const |
|
563 { |
|
564 return mImageSize2D; |
|
565 } |
|
566 |
|
567 void HgMediaWallRenderer::setFrontCoverElevationFactor(qreal elevation) |
|
568 { |
|
569 mFrontCoverElevation = elevation; |
|
570 } |
|
571 |
|
572 qreal HgMediaWallRenderer::getFrontCoverElevationFactor() const |
|
573 { |
|
574 return mFrontCoverElevation; |
|
575 } |
|
576 |
|
577 void HgMediaWallRenderer::openItem(int index, bool animate) |
|
578 { |
|
579 if (isItemOpen()) |
|
580 return; |
|
581 |
|
582 mOpenedItem = index; |
|
583 mOpenedItemState = animate ? ItemOpening : ItemOpened; |
|
584 |
|
585 mStateMachine->setAnimated(animate); |
|
586 emit toggleItem(); |
|
587 |
|
588 } |
|
589 |
|
590 void HgMediaWallRenderer::closeItem(bool animate) |
|
591 { |
|
592 if (!isItemOpen()) |
|
593 return; |
|
594 |
|
595 mOpenedItemState = animate ? ItemClosing : ItemClosed; |
|
596 if (!animate) |
|
597 mOpenedItem = -1; |
|
598 |
|
599 mStateMachine->setAnimated(animate); |
|
600 emit toggleItem(); |
|
601 } |
|
602 |
|
603 qreal HgMediaWallRenderer::getRowPosY(int row) |
|
604 { |
|
605 qreal step = mSpacing3D.height() + mImageSize3D.height(); |
|
606 return mRowCount == 1 ? qreal(0) : (((qreal)mRowCount/qreal(2)-qreal(0.5)) - (qreal)row) * step; |
|
607 } |
|
608 |
|
609 qreal HgMediaWallRenderer::getColumnPosX(int col) |
|
610 { |
|
611 qreal step = -(mSpacing3D.width() + mImageSize3D.width()); |
|
612 return mColumnCount == 1 ? qreal(0) : (((qreal)mColumnCount/qreal(2)-qreal(0.5)) - (qreal)col) * step; |
|
613 } |
|
614 |
|
615 |
|
616 void HgMediaWallRenderer::enableReflections(bool enabled) |
|
617 { |
|
618 mReflectionsEnabled = enabled; |
|
619 } |
|
620 |
|
621 bool HgMediaWallRenderer::reflectionsEnabled() const |
|
622 { |
|
623 return mReflectionsEnabled; |
|
624 } |
|
625 |
|
626 QPointF HgMediaWallRenderer::mapFromWindow(const QPointF& point) const |
|
627 { |
|
628 return QPointF(point.x(), mRect.height() - point.y()); |
|
629 } |
|
630 |
|
631 void HgMediaWallRenderer::emitUpdate() |
|
632 { |
|
633 emit renderingNeeded(); |
|
634 } |
|
635 |
|
636 void HgMediaWallRenderer::applyOpeningAnimation(HgQuad* quad) |
|
637 { |
|
638 QQuaternion rot(0,0,0,1); |
|
639 qreal rotAngle = mAnimationAlpha * mFlipAngle; |
|
640 rot = QQuaternion::fromAxisAndAngle(QVector3D(0,1,0), rotAngle); |
|
641 quad->setRotation(rot); |
|
642 quad->setPosition(quad->position() + QVector3D(0,0,mAnimationAlpha * mZoomAmount)); |
|
643 } |
|
644 |
|
645 |
|
646 qreal HgMediaWallRenderer::getWorldWidth() const |
|
647 { |
|
648 qreal width = (qreal)mDataProvider->imageCount() / (qreal)mRowCount - 1.0f; |
|
649 |
|
650 if (mOrientation == Qt::Vertical) |
|
651 { |
|
652 qreal step = mSpacing2D.height() + mImageSize2D.height(); |
|
653 width -= (mRect.height() / step - 1.0f); |
|
654 } |
|
655 |
|
656 return width; |
|
657 } |
|
658 |
|
659 void HgMediaWallRenderer::beginRemoveRows(int start, int end) |
|
660 { |
|
661 mRemoveStart = start; |
|
662 mRemoveEnd = end; |
|
663 mItemCountChanged = true; |
|
664 |
|
665 recordState(mOldState); |
|
666 |
|
667 } |
|
668 |
|
669 void HgMediaWallRenderer::endRemoveRows() |
|
670 { |
|
671 |
|
672 mStateMachine->setAnimated(true); |
|
673 |
|
674 emit renderingNeeded(); |
|
675 |
|
676 } |
|
677 |
|
678 void HgMediaWallRenderer::startStateAnimation(QPainter* painter) |
|
679 { |
|
680 |
|
681 // clear previous animation quads |
|
682 for (int i = 0; i < mAnimatedQuads.size(); i++) |
|
683 { |
|
684 delete mAnimatedQuads[i]; |
|
685 } |
|
686 mAnimatedQuads.clear(); |
|
687 |
|
688 // setup animated quads |
|
689 HgQuad* defaultQuad = new HgQuad(); |
|
690 defaultQuad->setPosition(QVector3D(100,100,-100)); |
|
691 int n = mOldState.mQuads.count() < mNextState.mQuads.count() ? mNextState.mQuads.count() : mOldState.mQuads.count(); |
|
692 for (int i = 0; i < n; i++) |
|
693 { |
|
694 HgQuad* qA = (i >= mOldState.mQuads.count()) ? defaultQuad : mOldState.mQuads[i]; |
|
695 HgQuad* qB = (i >= mNextState.mQuads.count()) ? defaultQuad : mNextState.mQuads[i]; |
|
696 |
|
697 HgAnimatedQuad* q = new HgAnimatedQuad(qA, qB, mStateAnimationDuration); |
|
698 mAnimatedQuads.append(q); |
|
699 q->start(); |
|
700 } |
|
701 |
|
702 mStateAnimationOnGoing = true; |
|
703 |
|
704 // setup first frame of the animation |
|
705 setupStateAnimation(painter); |
|
706 |
|
707 // toggle state animation on |
|
708 toggleState(); |
|
709 |
|
710 } |
|
711 |
|
712 void HgMediaWallRenderer::setupCoverflow(const QPointF& startPosition, |
|
713 const QPointF& position, |
|
714 const QPointF& targetPosition, |
|
715 qreal springVelocity, |
|
716 QPainter* painter) |
|
717 { |
|
718 Q_UNUSED(startPosition) |
|
719 Q_UNUSED(targetPosition) |
|
720 Q_UNUSED(springVelocity) |
|
721 Q_UNUSED(painter) |
|
722 |
|
723 // save selected item for coverflow |
|
724 mSelectedItem = ceil(position.x()); |
|
725 |
|
726 int quadsVisible = (mRect.width() / mImageSize2D.width() + 1) * 4; |
|
727 int selectedItemIndex = quadsVisible / 2; |
|
728 |
|
729 qreal step = mSpacing3D.width() + mImageSize3D.width(); |
|
730 qreal ipos = floorf(position.x()); |
|
731 qreal frac = (position.x() - ipos) * step; |
|
732 qreal posX = -(qreal)(selectedItemIndex + 0) * step - frac; |
|
733 qreal zFar = -mFrontCoverElevation; |
|
734 qreal posY = 0; |
|
735 |
|
736 int count = mDataProvider->imageCount(); |
|
737 int quadIndex = 0; |
|
738 int itemIndex = ((int)(ipos - (qreal)selectedItemIndex)); |
|
739 int index = 0; |
|
740 |
|
741 while (1) |
|
742 { |
|
743 if (itemIndex < 0) |
|
744 { |
|
745 itemIndex++; |
|
746 posX += step; |
|
747 index++; |
|
748 continue; |
|
749 } |
|
750 else if (itemIndex >= count || index >= quadsVisible || quadIndex >= mRenderer->quadCount()) |
|
751 { |
|
752 break; |
|
753 } |
|
754 |
|
755 qreal posZ = zFar; |
|
756 |
|
757 // if this is center item modify its z |
|
758 qreal p = posX / step; |
|
759 if (p > -1.0f && p < 1.0f) |
|
760 { |
|
761 qreal d = lerp(-zFar, 0, qBound(qreal(0), qAbs(springVelocity)/6.0f, qreal(1))); |
|
762 posZ = zFar + sin((p+1.0f) * KPi / 2) * d; |
|
763 } |
|
764 |
|
765 // modify z also for sorting |
|
766 posZ -= 0.001f * abs(posX/step); |
|
767 |
|
768 // setup quad for this item |
|
769 HgQuad* quad = mRenderer->quad(quadIndex); |
|
770 setupDefaultQuad(QVector3D(posX, posY, posZ), itemIndex, mReflectionsEnabled, quadIndex); |
|
771 |
|
772 // step to next item |
|
773 posX += step; |
|
774 itemIndex++; |
|
775 index++; |
|
776 } |
|
777 |
|
778 } |
|
779 |
|
780 |
|
781 void HgMediaWallRenderer::setupGridPortrait(const QPointF& startPosition, |
|
782 const QPointF& position, |
|
783 const QPointF& targetPosition, |
|
784 qreal springVelocity, |
|
785 QPainter* painter) |
|
786 { |
|
787 Q_UNUSED(startPosition) |
|
788 Q_UNUSED(targetPosition) |
|
789 Q_UNUSED(springVelocity) |
|
790 Q_UNUSED(painter) |
|
791 |
|
792 int rowCount = (mRect.height() / mImageSize2D.height() + 1) * 4; |
|
793 int rowsUp = rowCount/2; |
|
794 |
|
795 qreal stepY = mSpacing3D.height() + mImageSize3D.height(); |
|
796 qreal ipos = floorf(position.x()); |
|
797 qreal frac = (position.x() - ipos) * stepY; |
|
798 qreal posY = -(qreal)rowsUp * stepY - frac; |
|
799 |
|
800 // adjust height so that we begin from top |
|
801 qreal div = mRect.width() <= mRect.height() ? mRect.width() : mRect.height(); |
|
802 posY -= mRect.height() / div / 2.0 - stepY / 2.0; |
|
803 |
|
804 int count = mDataProvider->imageCount(); |
|
805 int itemIndex = ((int)(ipos - (qreal)rowsUp)) * mColumnCount; |
|
806 int row = 0; |
|
807 int quadIndex = 0; |
|
808 |
|
809 while (1) |
|
810 { |
|
811 if (itemIndex < 0) |
|
812 { |
|
813 itemIndex+=mColumnCount; |
|
814 posY += stepY; |
|
815 row++; |
|
816 continue; |
|
817 } |
|
818 else if (itemIndex >= count || quadIndex >= mRenderer->quadCount() || row >= rowCount) |
|
819 { |
|
820 break; |
|
821 } |
|
822 |
|
823 setupGridRow(-posY, itemIndex, quadIndex); |
|
824 |
|
825 posY += stepY; |
|
826 row++; |
|
827 itemIndex+=mColumnCount; |
|
828 } |
|
829 |
|
830 } |
|
831 |
|
832 void HgMediaWallRenderer::setupGridLandscape(const QPointF& startPosition, |
|
833 const QPointF& position, |
|
834 const QPointF& targetPosition, |
|
835 qreal springVelocity, |
|
836 QPainter* painter) |
|
837 { |
|
838 Q_UNUSED(startPosition) |
|
839 Q_UNUSED(targetPosition) |
|
840 Q_UNUSED(springVelocity) |
|
841 Q_UNUSED(painter) |
|
842 |
|
843 int colCount = (mRect.width() / mImageSize2D.width() + 1) * 3; |
|
844 int colsLeft = colCount/2; |
|
845 |
|
846 qreal stepX = mSpacing3D.width() + mImageSize3D.width(); |
|
847 qreal ipos = floorf(position.x()); |
|
848 qreal frac = (position.x() - ipos) * stepX; |
|
849 qreal posX = -(qreal)colsLeft * stepX - frac; |
|
850 |
|
851 int count = mDataProvider->imageCount(); |
|
852 int itemIndex = ((int)(ipos - (qreal)colsLeft)) * mRowCount; |
|
853 int col = 0; |
|
854 int quadIndex = 0; |
|
855 |
|
856 while (1) |
|
857 { |
|
858 if (itemIndex < 0) |
|
859 { |
|
860 itemIndex+=mColumnCount; |
|
861 posX += stepX; |
|
862 col++; |
|
863 continue; |
|
864 } |
|
865 else if (itemIndex >= count || col >= colCount || quadIndex >= mRenderer->quadCount()) |
|
866 { |
|
867 break; |
|
868 } |
|
869 |
|
870 setupGridColumn(posX, itemIndex, quadIndex); |
|
871 |
|
872 posX += stepX; |
|
873 col++; |
|
874 itemIndex+=mRowCount; |
|
875 } |
|
876 } |
|
877 |
|
878 void HgMediaWallRenderer::setupGridColumn(qreal posX, int itemIndex, int& quadIndex) |
|
879 { |
|
880 for (int i = 0; i < mRowCount; i++) |
|
881 { |
|
882 qreal posY = getRowPosY(i); |
|
883 |
|
884 // enable reflections for the last row needed |
|
885 bool reflections = (i == (mRowCount-1) && mReflectionsEnabled); |
|
886 |
|
887 setupDefaultQuad(QVector3D(posX, posY, 0), itemIndex++, reflections, quadIndex); |
|
888 |
|
889 if (itemIndex >= mDataProvider->imageCount()) |
|
890 return; |
|
891 } |
|
892 } |
|
893 |
|
894 void HgMediaWallRenderer::setupGridRow(qreal posY, int itemIndex, int& quadIndex) |
|
895 { |
|
896 for (int i = 0; i < mColumnCount; i++) |
|
897 { |
|
898 qreal posX = getColumnPosX(i); |
|
899 setupDefaultQuad(QVector3D(posX, posY, 0), itemIndex++, false, quadIndex); |
|
900 if (itemIndex >= mDataProvider->imageCount()) |
|
901 return; |
|
902 } |
|
903 } |
|
904 |
|
905 void HgMediaWallRenderer::setupDefaultQuad(const QVector3D& pos, int itemIndex, bool reflectionsEnabled, int& quadIndex) |
|
906 { |
|
907 HgQuad* quad = mRenderer->quad(quadIndex++); |
|
908 quad->setPosition(pos); |
|
909 quad->setImage(mDataProvider->image(itemIndex)); |
|
910 quad->setVisible(true); |
|
911 quad->setScale(QVector2D(mImageSize3D.width(),mImageSize3D.height())); |
|
912 quad->setPivot(QVector2D(0,0)); |
|
913 quad->setUserData(QVariant(itemIndex)); |
|
914 quad->setRotation(QQuaternion(1,0,0,0)); |
|
915 quad->setOuterRotation(QQuaternion(1,0,0,0)); |
|
916 quad->enableMirrorImage(reflectionsEnabled); |
|
917 quad->setAlpha(1.0f); |
|
918 |
|
919 // apply opening animation if needed |
|
920 /* if (itemIndex == mOpenedItem) |
|
921 applyOpeningAnimation(quad); |
|
922 */ |
|
923 // setup indicator/decorator for the item if needed |
|
924 int flags = mDataProvider->flags(itemIndex); |
|
925 const HgImage* indicatorImage = mDataProvider->indicator(flags); |
|
926 if (flags != 0 && indicatorImage) |
|
927 { |
|
928 HgQuad* indicator = mRenderer->quad(quadIndex++); |
|
929 setupIndicator(quad, indicator, indicatorImage, |
|
930 itemIndex); |
|
931 indicator->enableMirrorImage(reflectionsEnabled); |
|
932 } |
|
933 |
|
934 |
|
935 } |
|
936 |
|
937 void HgMediaWallRenderer::setupIndicator(HgQuad* parent, |
|
938 HgQuad* indicator, const HgImage* indicatorImage, int itemIndex) |
|
939 { |
|
940 indicator->setPosition(parent->position()+ |
|
941 QVector3D(0.25*mImageSize3D.width(), -0.25*mImageSize3D.height(), 0.0001f)); |
|
942 indicator->setImage(indicatorImage); |
|
943 indicator->setVisible(true); |
|
944 indicator->setScale(QVector2D(0.25f*mImageSize3D.width(), 0.25f*mImageSize3D.height())); |
|
945 indicator->setPivot(QVector2D(0.0, 0.0)); |
|
946 indicator->setUserData(QVariant(itemIndex)); |
|
947 indicator->setRotation(parent->rotation()); |
|
948 indicator->setOuterRotation(parent->outerRotation()); |
|
949 indicator->enableMirrorImage(false); |
|
950 indicator->setAlpha(parent->alpha()); |
|
951 |
|
952 // apply opening animation to indicator if needed |
|
953 if (itemIndex == mOpenedItem) |
|
954 applyOpeningAnimation(indicator); |
|
955 } |
|
956 |
|
957 HgQuadRenderer* HgMediaWallRenderer::getRenderer() |
|
958 { |
|
959 return mRenderer; |
|
960 } |
|
961 |
|
962 bool HgMediaWallRenderer::getItemPoints(int index, QPolygonF& points) const |
|
963 { |
|
964 QPolygonF poly; |
|
965 if (!mRenderer->getQuadTranformedPoints(poly, index)) |
|
966 return false; |
|
967 |
|
968 points = poly; |
|
969 return true; |
|
970 } |
|
971 |
|
972 QList<HgQuad*> HgMediaWallRenderer::getVisibleQuads() const |
|
973 { |
|
974 return mRenderer->getVisibleQuads(QRectF(0, 0, mRect.width(), mRect.height())); |
|
975 } |
|
976 |
|
977 |