00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "animator.h"
00022
00023 #include <QGraphicsItem>
00024
00025 #include <KConfig>
00026 #include <KConfigGroup>
00027 #include <KService>
00028 #include <KServiceTypeTrader>
00029 #include <KGlobalSettings>
00030
00031 #include "animationdriver.h"
00032
00033 namespace Plasma
00034 {
00035
00036 static const int MIN_TICK_RATE_INT = 40;
00037 static const qreal MIN_TICK_RATE = 40;
00038
00039 struct AnimationState
00040 {
00041 QGraphicsItem *item;
00042 QObject *qobj;
00043 Animator::Animation animation;
00044 Animator::CurveShape curve;
00045 int interval;
00046 int currentInterval;
00047 int frames;
00048 int currentFrame;
00049 int id;
00050 };
00051
00052 struct ElementAnimationState
00053 {
00054 QGraphicsItem *item;
00055 QObject *qobj;
00056 Animator::CurveShape curve;
00057 Animator::Animation animation;
00058 int interval;
00059 int currentInterval;
00060 int frames;
00061 int currentFrame;
00062 int id;
00063 QPixmap pixmap;
00064 };
00065
00066 struct MovementState
00067 {
00068 QGraphicsItem *item;
00069 QObject *qobj;
00070 Animator::CurveShape curve;
00071 Animator::Movement movement;
00072 int interval;
00073 int currentInterval;
00074 int frames;
00075 int currentFrame;
00076 QPoint start;
00077 QPoint destination;
00078 int id;
00079 };
00080
00081 struct CustomAnimationState
00082 {
00083 Animator::CurveShape curve;
00084 int frames;
00085 int currentFrame;
00086 int interval;
00087 int currentInterval;
00088 int id;
00089 QObject* receiver;
00090 char* slot;
00091 };
00092
00093 class AnimatorPrivate
00094 {
00095 public:
00096
00097 AnimatorPrivate()
00098 : driver(0),
00099 animId(0),
00100 timerId(0)
00101 {
00102 }
00103
00104 ~AnimatorPrivate()
00105 {
00106 qDeleteAll(animatedItems);
00107 qDeleteAll(animatedElements);
00108 qDeleteAll(movingItems);
00109
00110 QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
00111 while (it.hasNext()) {
00112 delete it.value()->slot;
00113 delete it.value();
00114 it.remove();
00115 }
00116
00117
00118
00119 }
00120
00121 qreal calculateProgress(int frames, int currentFrame)
00122 {
00123 if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
00124 return qreal(1.0);
00125 }
00126
00127 qreal progress = frames;
00128 progress = currentFrame / progress;
00129 progress = qMin(qreal(1.0), qMax(qreal(0.0), progress));
00130 return progress;
00131 }
00132
00133 void performAnimation(qreal amount, const AnimationState* state)
00134 {
00135 switch (state->animation) {
00136 case Animator::AppearAnimation:
00137 driver->itemAppear(amount, state->item);
00138 break;
00139 case Animator::DisappearAnimation:
00140 driver->itemDisappear(amount, state->item);
00141 if (amount >= 1) {
00142 state->item->hide();
00143 }
00144 break;
00145 case Animator::ActivateAnimation:
00146 driver->itemActivated(amount, state->item);
00147 break;
00148 }
00149 }
00150
00151 void performMovement(qreal amount, const MovementState* state)
00152 {
00153 switch (state->movement) {
00154 case Animator::SlideInMovement:
00155 case Animator::FastSlideInMovement:
00156
00157 driver->itemSlideIn(amount, state->item, state->start, state->destination);
00158 break;
00159 case Animator::SlideOutMovement:
00160 case Animator::FastSlideOutMovement:
00161
00162 driver->itemSlideOut(amount, state->item, state->start, state->destination);
00163 break;
00164 }
00165 }
00166
00167 void init(Animator *q);
00168 void animatedItemDestroyed(QObject*);
00169 void movingItemDestroyed(QObject*);
00170 void animatedElementDestroyed(QObject*);
00171 void customAnimReceiverDestroyed(QObject*);
00172
00173 AnimationDriver* driver;
00174 int animId;
00175 int timerId;
00176 QTime time;
00177
00178
00179
00180
00181 QMap<QGraphicsItem*, AnimationState*> animatedItems;
00182 QMap<QGraphicsItem*, MovementState*> movingItems;
00183 QMap<int, ElementAnimationState*> animatedElements;
00184 QMap<int, CustomAnimationState*> customAnims;
00185 };
00186
00187 class AnimatorSingleton
00188 {
00189 public:
00190 Animator self;
00191 };
00192
00193 K_GLOBAL_STATIC( AnimatorSingleton, privateSelf )
00194
00195 Animator* Animator::self()
00196 {
00197 return &privateSelf->self;
00198 }
00199
00200
00201 Animator::Animator(QObject * parent)
00202 : QObject(parent),
00203 d(new AnimatorPrivate)
00204 {
00205 d->init(this);
00206 }
00207
00208 Animator::~Animator()
00209 {
00210 delete d;
00211 }
00212
00213 void AnimatorPrivate::animatedItemDestroyed(QObject* o)
00214 {
00215
00216 QMutableMapIterator<QGraphicsItem*, AnimationState*> it(animatedItems);
00217 while (it.hasNext()) {
00218 it.next();
00219
00220 if (it.value()->qobj == o) {
00221 kDebug() << "found deleted animated item";
00222 delete it.value();
00223 it.remove();
00224 }
00225 }
00226 }
00227
00228 void AnimatorPrivate::movingItemDestroyed(QObject* o)
00229 {
00230 QMutableMapIterator<QGraphicsItem*, MovementState*> it(movingItems);
00231 while (it.hasNext()) {
00232 it.next();
00233 if (it.value()->qobj == o) {
00234 delete it.value();
00235 it.remove();
00236 }
00237 }
00238 }
00239
00240 void AnimatorPrivate::animatedElementDestroyed(QObject* o)
00241 {
00242 QMutableMapIterator<int, ElementAnimationState*> it(animatedElements);
00243 while (it.hasNext()) {
00244 it.next();
00245 if (it.value()->qobj == o) {
00246 delete it.value();
00247 it.remove();
00248 }
00249 }
00250 }
00251
00252 void AnimatorPrivate::customAnimReceiverDestroyed(QObject* o)
00253 {
00254 QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
00255 while (it.hasNext()) {
00256 if (it.next().value()->receiver == o) {
00257 delete it.value()->slot;
00258 delete it.value();
00259 it.remove();
00260 }
00261 }
00262 }
00263
00264 int Animator::animateItem(QGraphicsItem* item, Animation animation)
00265 {
00266
00267
00268
00269 QMap<QGraphicsItem*, AnimationState*>::iterator it = d->animatedItems.find(item);
00270 if (it != d->animatedItems.end()) {
00271 delete it.value();
00272 d->animatedItems.erase(it);
00273 }
00274
00275 int frames = d->driver->animationFps(animation);
00276
00277 if (frames < 1) {
00278
00279
00280 return -1;
00281 }
00282
00283 AnimationState* state = new AnimationState;
00284 state->id = ++d->animId;
00285 state->item = item;
00286 state->animation = animation;
00287 state->curve = d->driver->animationCurve(animation);
00288
00289 state->frames = frames / 3;
00290 state->currentFrame = 0;
00291 state->interval = d->driver->animationDuration(animation) / state->frames;
00292 state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
00293 state->currentInterval = state->interval;
00294 state->qobj = dynamic_cast<QObject*>(item);
00295
00296 if (state->qobj) {
00297
00298 disconnect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(animatedItemDestroyed(QObject*)));
00299 connect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(animatedItemDestroyed(QObject*)));
00300 }
00301
00302 d->animatedItems[item] = state;
00303 d->performAnimation(0, state);
00304
00305 if (!d->timerId) {
00306 d->timerId = startTimer(MIN_TICK_RATE);
00307 d->time.restart();
00308 }
00309
00310 return state->id;
00311 }
00312
00313 int Animator::moveItem(QGraphicsItem* item, Movement movement, const QPoint &destination)
00314 {
00315
00316 QMap<QGraphicsItem*, MovementState*>::iterator it = d->movingItems.find(item);
00317 if (it != d->movingItems.end()) {
00318 delete it.value();
00319 d->movingItems.erase(it);
00320 }
00321
00322 int frames = d->driver->movementAnimationFps(movement);
00323 if (frames <= 1) {
00324
00325
00326 return -1;
00327 }
00328
00329 MovementState* state = new MovementState;
00330 state->id = ++d->animId;
00331 state->destination = destination;
00332 state->start = item->pos().toPoint();
00333 state->item = item;
00334 state->movement = movement;
00335 state->curve = d->driver->movementAnimationCurve(movement);
00336
00337 int duration = d->driver->movementAnimationDuration(movement);
00338 state->frames = (duration / 1000.0) * frames;
00339 state->currentFrame = 0;
00340 state->interval = duration / state->frames;
00341 state->interval -= qMax(MIN_TICK_RATE_INT, state->interval % MIN_TICK_RATE_INT);
00342
00343
00344 state->currentInterval = state->interval;
00345 state->qobj = dynamic_cast<QObject*>(item);
00346
00347 if (state->qobj) {
00348 disconnect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
00349 connect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
00350 }
00351
00352 d->movingItems[item] = state;
00353 d->performMovement(0, state);
00354
00355 if (!d->timerId) {
00356 d->timerId = startTimer(MIN_TICK_RATE);
00357 d->time.restart();
00358 }
00359
00360 return state->id;
00361 }
00362
00363 int Animator::customAnimation(int frames, int duration, Animator::CurveShape curve,
00364 QObject* receiver, const char* slot)
00365 {
00366 if (frames < 1 || duration < 1 || !receiver || !slot) {
00367 return -1;
00368 }
00369
00370 CustomAnimationState *state = new CustomAnimationState;
00371 state->id = ++d->animId;
00372 state->frames = frames;
00373 state->currentFrame = 0;
00374 state->curve = curve;
00375 state->interval = duration / qreal(state->frames);
00376 state->interval = qMax( 1, state->interval );
00377 state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
00378 state->currentInterval = state->interval;
00379 state->receiver = receiver;
00380 state->slot = qstrdup(slot);
00381
00382 d->customAnims[state->id] = state;
00383
00384 disconnect(receiver, SIGNAL(destroyed(QObject*)),
00385 this, SLOT(customAnimReceiverDestroyed(QObject*)));
00386 connect(receiver, SIGNAL(destroyed(QObject*)),
00387 this, SLOT(customAnimReceiverDestroyed(QObject*)));
00388
00389
00390 if (!QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0))) {
00391
00392 QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0), Q_ARG(int, state->id));
00393 }
00394
00395 if (!d->timerId) {
00396 d->timerId = startTimer(MIN_TICK_RATE);
00397 d->time.restart();
00398 }
00399
00400 return state->id;
00401 }
00402
00403 void Animator::stopCustomAnimation(int id)
00404 {
00405 QMap<int, CustomAnimationState*>::iterator it = d->customAnims.find(id);
00406 if (it != d->customAnims.end()) {
00407 delete [] it.value()->slot;
00408 delete it.value();
00409 d->customAnims.erase(it);
00410 }
00411
00412 }
00413
00414 void Animator::stopItemAnimation(int id)
00415 {
00416 QMutableMapIterator<QGraphicsItem*, AnimationState*> it(d->animatedItems);
00417 while (it.hasNext()) {
00418 it.next();
00419 if (it.value()->id == id) {
00420 delete it.value();
00421 it.remove();
00422 return;
00423 }
00424 }
00425 }
00426
00427 void Animator::stopItemMovement(int id)
00428 {
00429 QMutableMapIterator<QGraphicsItem*, MovementState*> it(d->movingItems);
00430 while (it.hasNext()) {
00431 it.next();
00432 if (it.value()->id == id) {
00433 delete it.value();
00434 it.remove();
00435 return;
00436 }
00437 }
00438 }
00439
00440 int Animator::animateElement(QGraphicsItem *item, Animation animation)
00441 {
00442
00443 ElementAnimationState *state = new ElementAnimationState;
00444 state->item = item;
00445 state->curve = d->driver->elementAnimationCurve(animation);
00446 state->animation = animation;
00447
00448 state->frames = d->driver->elementAnimationFps(animation) / 5;
00449 state->currentFrame = 0;
00450 state->interval = d->driver->elementAnimationDuration(animation) / state->frames;
00451 state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
00452 state->currentInterval = state->interval;
00453 state->id = ++d->animId;
00454 state->qobj = dynamic_cast<QObject*>(item);
00455
00456 if (state->qobj) {
00457 disconnect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(animatedElementDestroyed(QObject*)));
00458 connect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(animatedElementDestroyed(QObject*)));
00459 }
00460
00461
00462 bool needTimer = true;
00463 if (state->frames < 1) {
00464 state->frames = 1;
00465 state->currentFrame = 1;
00466 needTimer = false;
00467 }
00468
00469 d->animatedElements[state->id] = state;
00470
00471
00472 if (needTimer && !d->timerId) {
00473
00474
00475 d->timerId = startTimer(MIN_TICK_RATE);
00476 d->time.restart();
00477 }
00478 return state->id;
00479 }
00480
00481 void Animator::stopElementAnimation(int id)
00482 {
00483 QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
00484 if (it != d->animatedElements.end()) {
00485 delete it.value();
00486 d->animatedElements.erase(it);
00487 }
00488
00489 }
00490
00491 void Animator::setInitialPixmap(int id, const QPixmap &pixmap)
00492 {
00493 QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
00494
00495 if (it == d->animatedElements.end()) {
00496 kDebug() << "Animator::setInitialPixmap(" << id << ") found no entry for it!";
00497 return;
00498 }
00499
00500 it.value()->pixmap = pixmap;
00501 }
00502
00503 QPixmap Animator::currentPixmap(int id)
00504 {
00505 QMap<int, ElementAnimationState*>::const_iterator it = d->animatedElements.find(id);
00506
00507 if (it == d->animatedElements.constEnd()) {
00508
00509 return QPixmap();
00510 }
00511
00512 ElementAnimationState* state = it.value();
00513 qreal progress = state->frames;
00514
00515 progress = state->currentFrame / progress;
00516 progress = qMin(qreal(1.0), qMax(qreal(0.0), progress));
00517
00518
00519 switch (state->animation) {
00520 case AppearAnimation:
00521 return d->driver->elementAppear(progress, state->pixmap);
00522 break;
00523 case DisappearAnimation:
00524 return d->driver->elementDisappear(progress, state->pixmap);
00525 break;
00526 case ActivateAnimation:
00527 break;
00528 }
00529
00530 return state->pixmap;
00531 }
00532
00533 bool Animator::isAnimating() const
00534 {
00535 return (!d->animatedItems.isEmpty() ||
00536 !d->movingItems.isEmpty() ||
00537 !d->animatedElements.isEmpty() ||
00538 !d->customAnims.isEmpty());
00539 }
00540
00541 void Animator::timerEvent(QTimerEvent *event)
00542 {
00543 Q_UNUSED(event)
00544 bool animationsRemain = false;
00545 int elapsed = MIN_TICK_RATE;
00546 if (d->time.elapsed() > elapsed) {
00547 elapsed = d->time.elapsed();
00548 }
00549 d->time.restart();
00550
00551
00552 foreach (AnimationState* state, d->animatedItems) {
00553 if (state->currentInterval <= elapsed) {
00554
00555 state->currentFrame += (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00556 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00557
00558 if (state->currentFrame < state->frames) {
00559 qreal progress = d->calculateProgress(state->frames, state->currentFrame);
00560 d->performAnimation(progress, state);
00561 state->currentInterval = state->interval;
00562
00563 state->interval *= 1 - progress;
00564 animationsRemain = true;
00565 } else {
00566 d->performAnimation(1, state);
00567 d->animatedItems.erase(d->animatedItems.find(state->item));
00568 emit animationFinished(state->item, state->animation);
00569 delete state;
00570 }
00571 } else {
00572 state->currentInterval -= elapsed;
00573 animationsRemain = true;
00574 }
00575 }
00576
00577 foreach (MovementState* state, d->movingItems) {
00578 if (state->currentInterval <= elapsed) {
00579
00580 state->currentFrame += (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00581 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00582
00583 if (state->currentFrame < state->frames) {
00584
00585 d->performMovement(d->calculateProgress(state->frames, state->currentFrame), state);
00586
00587 state->currentInterval = state->interval;
00588 animationsRemain = true;
00589 } else {
00590
00591 d->performMovement(1, state);
00592 d->movingItems.erase(d->movingItems.find(state->item));
00593 emit movementFinished(state->item);
00594 delete state;
00595 }
00596 } else {
00597 state->currentInterval -= elapsed;
00598 animationsRemain = true;
00599 }
00600 }
00601
00602 foreach (ElementAnimationState* state, d->animatedElements) {
00603 if (state->currentFrame == state->frames) {
00604
00605
00606
00607
00608
00609 continue;
00610 }
00611
00612 if (state->currentInterval <= elapsed) {
00613
00614
00615
00616
00617 state->currentFrame += (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00618 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00619
00620 state->item->update();
00621 if (state->currentFrame < state->frames) {
00622 state->currentInterval = state->interval;
00623
00624 state->interval *= 1 - d->calculateProgress(state->frames, state->currentFrame);
00625 animationsRemain = true;
00626 } else {
00627 d->animatedElements.remove(state->id);
00628 emit elementAnimationFinished(state->id);
00629 delete state;
00630 }
00631 } else {
00632 state->currentInterval -= elapsed;
00633 animationsRemain = true;
00634 }
00635 }
00636
00637 foreach (CustomAnimationState *state, d->customAnims) {
00638 if (state->currentInterval <= elapsed) {
00639
00640 state->currentFrame += (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00641 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00642
00643
00644
00645 if (state->currentFrame < state->frames) {
00646
00647
00648 state->currentInterval = state->interval;
00649 animationsRemain = true;
00650
00651
00652 if (!QMetaObject::invokeMethod(state->receiver, state->slot,
00653 Q_ARG(qreal,
00654 d->calculateProgress(state->frames, state->currentFrame)))) {
00655
00656 QMetaObject::invokeMethod(state->receiver, state->slot,
00657 Q_ARG(qreal,
00658 d->calculateProgress(state->frames, state->currentFrame)), Q_ARG(int, state->id));
00659 }
00660 } else {
00661 if (!QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1))) {
00662 QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1), Q_ARG(int, state->id));
00663 }
00664 d->customAnims.erase(d->customAnims.find(state->id));
00665 emit customAnimationFinished(state->id);
00666 delete [] state->slot;
00667 delete state;
00668 }
00669 } else {
00670 state->currentInterval -= elapsed;
00671 animationsRemain = true;
00672 }
00673 }
00674
00675 if (!animationsRemain && d->timerId) {
00676 killTimer(d->timerId);
00677 d->timerId = 0;
00678 }
00679 }
00680
00681 void AnimatorPrivate::init(Animator *q)
00682 {
00683
00684 KConfig c("plasmarc");
00685 KConfigGroup cg(&c, "Animator");
00686 QString pluginName = cg.readEntry("driver", "default");
00687
00688 if (!pluginName.isEmpty()) {
00689 QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(pluginName);
00690 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Animator", constraint);
00691
00692 if (!offers.isEmpty()) {
00693 QString error;
00694
00695 KPluginLoader plugin(*offers.first());
00696
00697 if (Plasma::isPluginVersionCompatible(plugin.pluginVersion()))
00698 driver = offers.first()->createInstance<Plasma::AnimationDriver>(0, QVariantList(), &error);
00699
00700 if (!driver) {
00701 kDebug() << "Could not load requested animator " << offers.first() << ". Error given: " << error;
00702 }
00703 }
00704 }
00705
00706 if (!driver) {
00707 driver = new AnimationDriver(q);
00708 }
00709 }
00710
00711 }
00712
00713 #include <animator.moc>