26 #include "hbeffectgroup_p.h" |
26 #include "hbeffectgroup_p.h" |
27 #include "hbeffectabstract_p.h" |
27 #include "hbeffectabstract_p.h" |
28 #include "hbeffect.h" |
28 #include "hbeffect.h" |
29 #include "hbtimer_p.h" |
29 #include "hbtimer_p.h" |
30 #include "hbeffectdef_p.h" |
30 #include "hbeffectdef_p.h" |
31 #include "hbeffectinternal_p.h" |
|
32 #include "hbmainwindow.h" |
31 #include "hbmainwindow.h" |
33 #include "hbinstance.h" |
32 #include "hbinstance.h" |
34 |
33 |
35 #include <qglobal.h> |
34 #include <qglobal.h> |
36 #include <QMetaObject> |
35 #include <QMetaObject> |
37 #include <QTransform> |
36 #include <QTransform> |
38 #include <QGraphicsItem> |
37 #include <QGraphicsItem> |
39 #include <QGraphicsWidget> |
38 #include <QGraphicsWidget> |
40 #include <QGraphicsView> |
39 #include <QGraphicsView> |
41 #include <QTimer> |
|
42 |
40 |
43 #ifdef HB_FILTER_EFFECTS |
41 #ifdef HB_FILTER_EFFECTS |
44 #include "hbvgeffect_p.h" |
42 #include "hbvgeffect_p.h" |
45 #include "hbvgchainedeffect_p.h" |
43 #include "hbvgchainedeffect_p.h" |
46 #endif |
44 #endif |
47 |
|
48 |
45 |
49 HbEffectGroup::HbEffectGroup( |
46 HbEffectGroup::HbEffectGroup( |
50 const QString &effectEventType, |
47 const QString &effectEventType, |
51 QGraphicsItem *registrationItem, |
48 QGraphicsItem *registrationItem, |
52 QGraphicsItem *targetItem, |
49 QGraphicsItem *targetItem, |
300 mFinishedCount = 0; |
300 mFinishedCount = 0; |
301 } |
301 } |
302 |
302 |
303 // First resolve parameters and set the start states for all the effects. |
303 // First resolve parameters and set the start states for all the effects. |
304 // This is done before starting the effect animations to avoid screen flickering. |
304 // This is done before starting the effect animations to avoid screen flickering. |
305 |
|
306 QTransform transform; |
305 QTransform transform; |
307 |
306 foreach (HbEffectAbstract *effect, mEffects) { |
308 Q_FOREACH(HbEffectAbstract *effect, mEffects) { |
|
309 // Resolve parameters etc. |
307 // Resolve parameters etc. |
310 effect->init(); |
308 effect->init(); |
311 if (effect->interval() == 0) { |
309 if (effect->interval() == 0) { |
312 // Set start state if effect starts immediately |
310 // Set start state if effect starts immediately |
313 effect->setStartState(transform); |
311 effect->setStartState(transform); |
314 } |
312 } |
315 } |
313 } |
316 |
|
317 mTargetItem->setTransform(transform); |
314 mTargetItem->setTransform(transform); |
|
315 |
|
316 // Make the target item visible, if needed, now that the start state is set |
|
317 // for all the effects. |
|
318 if (mEffectFlags.testFlag(HbEffectInternal::ShowItemOnFirstUpdate)) { |
|
319 // In case of a view switch the registration item may be the HbView |
|
320 // itself and the target item is just the view's content widget. Make |
|
321 // sure both are visible. |
|
322 mTargetItem->setVisible(true); |
|
323 if (mRegistrationItem != mTargetItem) { |
|
324 mRegistrationItem->setVisible(true); |
|
325 } |
|
326 } |
|
327 |
|
328 mRegItemHidden = false; |
|
329 mTargetItemHidden = false; |
318 |
330 |
319 if (mEffects.empty()) { |
331 if (mEffects.empty()) { |
320 // No effect exists but user wants notification when effect finishes. |
332 // No effect exists but user wants notification when effect finishes. |
321 // Let the user do whatever he wanted to do when effect finishes. |
333 // Let the user do whatever he wanted to do when effect finishes. |
322 invokeObserver(Hb::EffectNotStarted); |
334 invokeObserver(Hb::EffectNotStarted); |
323 } |
335 } else { |
324 else { |
|
325 // Start state has been set for all the effects, |
336 // Start state has been set for all the effects, |
326 // next step is to start the effect animations. |
337 // next step is to start the effect animations. |
327 // Before that, resolve the view where the effect belongs if the effect is looping. |
338 // Before that, resolve the view where the effect belongs if the effect is looping. |
328 // This is needed for being able to pause looping effects when their view is inactive. |
339 // This is needed for being able to pause looping effects when their view is inactive. |
329 if (isLooping()) { |
340 if (isLooping()) { |
330 resolveView(); |
341 resolveView(); |
331 } |
342 } |
332 |
343 foreach (HbEffectAbstract *effect, mEffects) { |
333 Q_FOREACH(HbEffectAbstract *effect, mEffects) { |
|
334 // If the starttime is zero, start effect immediately |
344 // If the starttime is zero, start effect immediately |
335 if (effect->interval() == 0) { |
345 if (effect->interval() == 0) { |
336 effect->start(); // This may call group's effectFinished if the effect was empty. |
346 effect->start(); // This may call group's effectFinished if the effect was empty. |
337 } else { |
347 } else { |
338 //Else register the effect to timeline to wait its turn. |
348 //Else register the effect to timeline to wait its turn. |
340 } |
350 } |
341 } |
351 } |
342 } |
352 } |
343 } |
353 } |
344 |
354 |
345 void HbEffectGroup::resolveView() { |
355 void HbEffectGroup::resolveView() |
346 if (!mView) { |
356 { |
347 if (mTargetItem) { |
357 if (!mView && mTargetItem) { |
348 QGraphicsScene *scene = mTargetItem->scene(); |
358 QGraphicsScene *scene = mTargetItem->scene(); |
349 if (scene) { |
359 if (scene) { |
350 // Resolve the main window having the same scene that the item belongs to |
360 // Resolve the main window having the same scene that the item belongs to |
351 QList<HbMainWindow *> windowList = hbInstance->allMainWindows(); |
361 QList<HbMainWindow *> windowList = hbInstance->allMainWindows(); |
352 Q_FOREACH(const HbMainWindow *window, windowList) { |
362 foreach (const HbMainWindow *window, windowList) { |
353 if (window->scene() == scene) { |
363 if (window->scene() == scene) { |
354 mView = window->currentView(); |
364 mView = window->currentView(); |
355 break; |
365 break; |
356 } |
|
357 } |
366 } |
358 } |
367 } |
359 } |
368 } |
360 } |
369 } |
361 } |
370 } |
362 |
371 |
363 bool HbEffectGroup::hasTranslateEffect() const |
372 bool HbEffectGroup::hasTranslateEffect() const |
364 { |
373 { |
365 foreach(HbEffectAbstract *effect, mEffects) { |
374 foreach (HbEffectAbstract *effect, mEffects) { |
366 if (effect->name() == HB_EFFECT_NAME_TRANSLATE) { |
375 if (effect->name() == HB_EFFECT_NAME_TRANSLATE) { |
367 return true; |
376 return true; |
368 } |
377 } |
369 } |
378 } |
370 |
|
371 return false; |
379 return false; |
372 } |
380 } |
373 |
381 |
374 bool HbEffectGroup::hasRotateEffect() const |
382 bool HbEffectGroup::hasRotateEffect() const |
375 { |
383 { |
376 foreach(HbEffectAbstract *effect, mEffects) { |
384 foreach (HbEffectAbstract *effect, mEffects) { |
377 if (effect->name() == HB_EFFECT_NAME_ROTATE) { |
385 if (effect->name() == HB_EFFECT_NAME_ROTATE) { |
378 return true; |
386 return true; |
379 } |
387 } |
380 } |
388 } |
381 |
389 |
382 return false; |
390 return false; |
383 } |
391 } |
384 |
392 |
385 bool HbEffectGroup::hasScaleEffect() const |
393 bool HbEffectGroup::hasScaleEffect() const |
386 { |
394 { |
387 foreach(HbEffectAbstract *effect, mEffects) { |
395 foreach (HbEffectAbstract *effect, mEffects) { |
388 if (effect->name() == HB_EFFECT_NAME_SCALE) { |
396 if (effect->name() == HB_EFFECT_NAME_SCALE) { |
389 return true; |
397 return true; |
390 } |
398 } |
391 } |
399 } |
392 |
|
393 return false; |
400 return false; |
394 } |
401 } |
395 |
402 |
396 bool HbEffectGroup::hasOpacityEffect() const |
403 bool HbEffectGroup::hasOpacityEffect() const |
397 { |
404 { |
398 foreach(HbEffectAbstract *effect, mEffects) { |
405 foreach (HbEffectAbstract *effect, mEffects) { |
399 if (effect->name() == HB_EFFECT_NAME_OPACITY) { |
406 if (effect->name() == HB_EFFECT_NAME_OPACITY) { |
400 return true; |
407 return true; |
401 } |
408 } |
402 } |
409 } |
403 |
|
404 return false; |
410 return false; |
405 } |
411 } |
406 |
412 |
407 void HbEffectGroup::doHideEffect(const QTransform *transform, bool opacityEffectUsed) |
413 void HbEffectGroup::doClearEffect(const QTransform *transform, bool opacityEffectUsed) |
408 { |
414 { |
|
415 // Hide registration item if needed. |
|
416 if (mEffectFlags.testFlag(HbEffectInternal::HideRegItemBeforeClearingEffect)) { |
|
417 // We get here also from cancelAll() when starting a new effect so there |
|
418 // must be some guarding to do the hiding only once. |
|
419 if (!mRegItemHidden) { |
|
420 mRegItemHidden = true; |
|
421 // This flag affects the registration item only. |
|
422 mRegistrationItem->setVisible(false); |
|
423 } |
|
424 } |
|
425 // Same for the target item. |
|
426 if (mEffectFlags.testFlag(HbEffectInternal::HideTargetItemBeforeClearingEffect)) { |
|
427 if (!mTargetItemHidden) { |
|
428 mTargetItemHidden = true; |
|
429 mTargetItem->setVisible(false); |
|
430 } |
|
431 } |
|
432 // Reset the transformation. |
409 mTargetItem->setTransform(transform ? *transform : QTransform()); |
433 mTargetItem->setTransform(transform ? *transform : QTransform()); |
|
434 // Reset opacity. |
410 if (opacityEffectUsed) { |
435 if (opacityEffectUsed) { |
411 // Hide opacity effect by setting item fully opaque regardless of what |
436 // Hide opacity effect by setting item fully opaque regardless of what |
412 // its opacity value was before the effect. |
437 // its opacity value was before the effect. |
413 mTargetItem->setOpacity(1.0f); |
438 mTargetItem->setOpacity(1.0f); |
414 } |
439 } |
|
440 // Reset filter effects. |
415 #ifdef HB_FILTER_EFFECTS |
441 #ifdef HB_FILTER_EFFECTS |
416 deactivateVgEffect(); |
442 deactivateVgEffect(); |
417 #endif |
443 #endif |
418 } |
444 } |
419 |
445 |
420 void HbEffectGroup::cancelAll(bool sendCallback, bool itemIsValid, bool hideEffect, const QTransform &initialItemTransform) |
446 void HbEffectGroup::cancelAll(bool sendCallback, bool itemIsValid, bool clearEffect, const QTransform &initialItemTransform) |
421 { |
447 { |
|
448 // No checks for running state here. The cancellation (esp. the clearing of |
|
449 // the effect (if needed)) must be done always, regardless of the effect's |
|
450 // state. |
|
451 |
422 QTransform transform; |
452 QTransform transform; |
423 bool opacityEffectUsed = false; |
453 bool opacityEffectUsed = false; |
424 |
454 |
425 Q_FOREACH(HbEffectAbstract *effect, mEffects) { |
455 foreach (HbEffectAbstract *effect, mEffects) { |
426 if (effect) { |
456 if (effect) { |
427 HbTimer::instance()->unregisterEntry(effect); |
457 HbTimer::instance()->unregisterEntry(effect); |
428 effect->cancel(transform, itemIsValid); |
458 effect->cancel(transform, itemIsValid); |
429 if (effect->name() == HB_EFFECT_NAME_OPACITY) { |
459 if (effect->name() == HB_EFFECT_NAME_OPACITY) { |
430 opacityEffectUsed = true; |
460 opacityEffectUsed = true; |
432 } |
462 } |
433 } |
463 } |
434 |
464 |
435 if (itemIsValid) { |
465 if (itemIsValid) { |
436 // If effect needs to be removed, reset transform matrix and deactivate VG effect |
466 // If effect needs to be removed, reset transform matrix and deactivate VG effect |
437 if (hideEffect || mHideWhenFinished) { |
467 if (clearEffect || mEffectFlags.testFlag(HbEffectInternal::ClearEffectWhenFinished)) { |
438 doHideEffect(&initialItemTransform, opacityEffectUsed); |
468 doClearEffect(&initialItemTransform, opacityEffectUsed); |
439 } else { // Otherwise set transform corresponding to the end state of the effect |
469 } else { // Otherwise set transform corresponding to the end state of the effect |
440 mTargetItem->setTransform(initialItemTransform * transform); |
470 mTargetItem->setTransform(initialItemTransform * transform); |
441 } |
471 } |
442 } |
472 } |
443 |
473 |
444 // Do not set this to NotRunning before effect->cancel has been called because filter |
474 // Do not set this to NotRunning before effect->cancel has been called because filter |
445 // effects cancel does stuff that requires group->isRunning() return true. |
475 // effects cancel does stuff that requires group->isRunning() return true. |
446 mRunningState = NotRunning; |
476 mRunningState = NotRunning; |
447 |
477 |
448 // Invoke observer with cancel signal |
478 // Invoke observer with cancel signal |
449 if (sendCallback) |
479 if (sendCallback) { |
450 invokeObserver(Hb::EffectCancelled); |
480 invokeObserver(Hb::EffectCancelled); |
|
481 } |
451 } |
482 } |
452 |
483 |
453 void HbEffectGroup::effectFinished(Hb::EffectEvent reason) |
484 void HbEffectGroup::effectFinished(Hb::EffectEvent reason) |
454 { |
485 { |
455 // Inform the animated item when the whole effect group has finished. |
486 // Inform the animated item when the whole effect group has finished. |
456 if (++mFinishedCount == mEffects.count()) { |
487 if (++mFinishedCount == mEffects.count()) { |
457 mFinishedCount = 0; |
488 mFinishedCount = 0; |
458 |
489 |
459 // The animation framework funnily enough sends the finished signal before updating the animation with the final |
490 // The animation framework funnily enough sends the finished signal |
460 // value, so here we set running state to NotRunning asynchronously so the effect's final value gets still updated. |
491 // before updating the animation with the final value, so here we set |
|
492 // running state to NotRunning asynchronously so the effect's final |
|
493 // value gets still updated. |
461 mRunningState = FinishInProgress; |
494 mRunningState = FinishInProgress; |
462 QTimer::singleShot(0, this, SLOT(clearEffectRunning())); |
495 QMetaObject::invokeMethod(this, "clearEffectRunning", Qt::QueuedConnection); |
463 |
496 |
464 // Send callback if observer has been provided |
497 // Send callback if observer has been provided. Note that with the |
|
498 // EffectFinished reason the observer will be invoked asynchronously. |
465 invokeObserver(reason); |
499 invokeObserver(reason); |
466 } |
500 } |
467 |
501 |
468 // The effect group object is not deleted here, |
502 // The effect group object is not deleted here, |
469 // because it would need to be removed from the list of the effect groups in |
503 // because it would need to be removed from the list of the effect groups in |
476 // Comes here when effect has finished and running state is set to NotRunning asynchronously. |
510 // Comes here when effect has finished and running state is set to NotRunning asynchronously. |
477 // Only set running state to 'NotRunning' if the finish is still in progress, i.e. the effect |
511 // Only set running state to 'NotRunning' if the finish is still in progress, i.e. the effect |
478 // has not been restarted meanwhile. |
512 // has not been restarted meanwhile. |
479 if (mRunningState == FinishInProgress) { |
513 if (mRunningState == FinishInProgress) { |
480 mRunningState = NotRunning; |
514 mRunningState = NotRunning; |
481 // We are finished either normally or with EffectNotStarted. It is now the time to |
515 // We are finished either normally or with EffectNotStarted. It is now |
482 // get rid of all the "effects" caused by the effects in this group if the |
516 // the time to get rid of all the "effects" caused by the effects in |
483 // hide-when-finished flag is set. |
517 // this group, if needed. |
484 if (mHideWhenFinished) { |
518 if (mEffectFlags.testFlag(HbEffectInternal::ClearEffectWhenFinished)) { |
485 doHideEffect(0, hasOpacityEffect()); |
519 doClearEffect(0, hasOpacityEffect()); |
486 } |
520 } |
487 } |
521 } |
488 } |
522 } |
489 |
523 |
490 void HbEffectGroup::invokeObserver(Hb::EffectEvent reason) |
524 void HbEffectGroup::invokeObserver(Hb::EffectEvent reason) |
503 // This is done before invokeMethod to avoid crash if the callback |
537 // This is done before invokeMethod to avoid crash if the callback |
504 // deletes this object. |
538 // deletes this object. |
505 mObserver = 0; |
539 mObserver = 0; |
506 |
540 |
507 // Send callback if observer has been provided. Use queued connection if |
541 // Send callback if observer has been provided. Use queued connection if |
508 // the effect finished normally, because otherwise deleting the effect during the callback |
542 // the effect finished normally, because otherwise deleting the effect |
509 // would cause crash because this function finally returns back to animation framework code |
543 // during the callback would cause crash because this function finally |
510 // which assumes the effect objects are alive. |
544 // returns back to animation framework code which assumes the effect |
|
545 // objects are alive. |
511 QMetaObject::invokeMethod( |
546 QMetaObject::invokeMethod( |
512 observer, |
547 observer, |
513 mEffectFinishedSlotName.toAscii().data(), |
548 mEffectFinishedSlotName.toAscii().data(), |
514 reason == Hb::EffectFinished ? Qt::QueuedConnection : Qt::AutoConnection, |
549 reason == Hb::EffectFinished ? Qt::QueuedConnection : Qt::AutoConnection, |
515 QGenericReturnArgument(), |
550 QGenericReturnArgument(), |