• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Plasma

animator.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 Aaron Seigo <aseigo@kde.org>
00003  *                 2007 Alexis Ménard <darktears31@gmail.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU Library General Public License as
00007  *   published by the Free Software Foundation; either version 2, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 #include "animator.h"
00022 
00023 #include <QGraphicsItem>
00024 #include <QTimeLine>
00025 #include <QTimerEvent>
00026 
00027 #include <kconfig.h>
00028 #include <kconfiggroup.h>
00029 #include <kservice.h>
00030 #include <kservicetypetrader.h>
00031 #include <kglobalsettings.h>
00032 
00033 #include "animationdriver.h"
00034 
00035 namespace Plasma
00036 {
00037 
00038 static const int MIN_TICK_RATE_INT = 10;
00039 static const qreal MIN_TICK_RATE = 10;
00040 
00041 struct AnimationState
00042 {
00043     QGraphicsItem *item;
00044     QObject *qobj;
00045     Animator::Animation animation;
00046     Animator::CurveShape curve;
00047     int interval;
00048     int currentInterval;
00049     int frames;
00050     int currentFrame;
00051     int id;
00052 };
00053 
00054 struct ElementAnimationState
00055 {
00056     QGraphicsItem *item;
00057     QObject *qobj;
00058     Animator::CurveShape curve;
00059     Animator::Animation animation;
00060     int interval;
00061     int currentInterval;
00062     int frames;
00063     int currentFrame;
00064     int id;
00065     QPixmap pixmap;
00066 };
00067 
00068 struct MovementState
00069 {
00070     QGraphicsItem *item;
00071     QObject *qobj;
00072     Animator::CurveShape curve;
00073     Animator::Movement movement;
00074     int interval;
00075     int currentInterval;
00076     int frames;
00077     int currentFrame;
00078     QPoint start;
00079     QPoint destination;
00080     int id;
00081 };
00082 
00083 struct CustomAnimationState
00084 {
00085     Animator::CurveShape curve;
00086     int frames;
00087     int currentFrame;
00088     int frameInterval;
00089     int interval;
00090     int currentInterval;
00091     int id;
00092     QObject *receiver;
00093     char *slot;
00094 };
00095 
00096 class AnimatorPrivate
00097 {
00098     public:
00099 
00100         AnimatorPrivate()
00101             : driver(0),
00102               animId(0),
00103               timerId(0)
00104         {
00105         }
00106 
00107         ~AnimatorPrivate()
00108         {
00109             cleanupStates();
00110             qDeleteAll(animatedItems);
00111             qDeleteAll(animatedElements);
00112             qDeleteAll(movingItems);
00113 
00114             QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
00115             while (it.hasNext()) {
00116                 it.next();
00117                 delete[] it.value()->slot;
00118                 delete it.value();
00119                 it.remove();
00120             }
00121 
00122             // Animator is a QObject
00123             // and we don't own the items
00124         }
00125 
00126         qreal calculateProgress(int time, int duration, Animator::CurveShape curve)
00127         {
00128             if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
00129                 return qreal(1.0);
00130             }
00131 
00132             timeline.setCurveShape(static_cast<QTimeLine::CurveShape>(curve));
00133             timeline.setDuration(duration);
00134             qreal progress = timeline.valueForTime(time);
00135             return progress;
00136         }
00137 
00138         void performAnimation(qreal amount, const AnimationState *state)
00139         {
00140             switch (state->animation) {
00141             case Animator::AppearAnimation:
00142                 driver->itemAppear(amount, state->item);
00143                 break;
00144             case Animator::DisappearAnimation:
00145                 driver->itemDisappear(amount, state->item);
00146                 if (amount >= 1) {
00147                     state->item->hide();
00148                 }
00149                 break;
00150             case Animator::ActivateAnimation:
00151                 driver->itemActivated(amount, state->item);
00152                 break;
00153             }
00154         }
00155 
00156         void performMovement(qreal amount, const MovementState *state)
00157         {
00158             switch (state->movement) {
00159                 case Animator::SlideInMovement:
00160                 case Animator::FastSlideInMovement:
00161                     //kDebug() << "performMovement, SlideInMovement";
00162                     driver->itemSlideIn(amount, state->item, state->start, state->destination);
00163                     break;
00164                 case Animator::SlideOutMovement:
00165                 case Animator::FastSlideOutMovement:
00166                     //kDebug() << "performMovement, SlideOutMovement";
00167                     driver->itemSlideOut(amount, state->item, state->start, state->destination);
00168                     break;
00169             }
00170         }
00171 
00172 
00173         void init(Animator *q);
00174         void cleanupStates();
00175         void animatedItemDestroyed(QObject*);
00176         void movingItemDestroyed(QObject*);
00177         void animatedElementDestroyed(QObject*);
00178         void customAnimReceiverDestroyed(QObject*);
00179 
00180         AnimationDriver *driver;
00181         int animId;
00182         int timerId;
00183         QTime time;
00184         QTimeLine timeline;
00185 
00186         // active items
00187         QMap<QGraphicsItem *, AnimationState *> animatedItems;
00188         QMap<QGraphicsItem *, MovementState *> movingItems;
00189         QMap<int, ElementAnimationState *> animatedElements;
00190         QMap<int, CustomAnimationState *> customAnims;
00191 
00192         // items to cull
00193         QSet<AnimationState *> animatedItemsToDelete;
00194         QSet<MovementState *> movingItemsToDelete;
00195         QSet<ElementAnimationState *> animatedElementsToDelete;
00196         QSet<CustomAnimationState *> customAnimsToDelete;
00197 };
00198 
00199 class AnimatorSingleton
00200 {
00201     public:
00202         Animator self;
00203 };
00204 
00205 K_GLOBAL_STATIC(AnimatorSingleton, privateSelf)
00206 
00207 Animator *Animator::self()
00208 {
00209     return &privateSelf->self;
00210 }
00211 
00212 Animator::Animator(QObject *parent)
00213     : QObject(parent),
00214       d(new AnimatorPrivate)
00215 {
00216     d->init(this);
00217 }
00218 
00219 Animator::~Animator()
00220 {
00221     delete d;
00222 }
00223 
00224 void AnimatorPrivate::animatedItemDestroyed(QObject *o)
00225 {
00226     //kDebug() << "testing for" << (void*)o;
00227     QMutableMapIterator<QGraphicsItem*, AnimationState*> it(animatedItems);
00228     while (it.hasNext()) {
00229         it.next();
00230         //kDebug() << "comparing against" << it.value()->qobj;
00231         if (it.value()->qobj == o) {
00232             kDebug() << "found deleted animated item";
00233             if (timerId) {
00234                 animatedItemsToDelete.insert(it.value());
00235             } else {
00236                 delete it.value();
00237             }
00238 
00239             it.remove();
00240         }
00241     }
00242 }
00243 
00244 void AnimatorPrivate::movingItemDestroyed(QObject *o)
00245 {
00246     QMutableMapIterator<QGraphicsItem*, MovementState*> it(movingItems);
00247     while (it.hasNext()) {
00248         it.next();
00249         if (it.value()->qobj == o) {
00250             if (timerId) {
00251                 movingItemsToDelete.insert(it.value());
00252             } else {
00253                 delete it.value();
00254             }
00255 
00256             it.remove();
00257         }
00258     }
00259 }
00260 
00261 void AnimatorPrivate::animatedElementDestroyed(QObject *o)
00262 {
00263     QMutableMapIterator<int, ElementAnimationState*> it(animatedElements);
00264     while (it.hasNext()) {
00265         it.next();
00266         if (it.value()->qobj == o) {
00267             if (timerId) {
00268                 animatedElementsToDelete.insert(it.value());
00269             } else {
00270                 delete it.value();
00271             }
00272 
00273             it.remove();
00274         }
00275     }
00276 }
00277 
00278 void AnimatorPrivate::customAnimReceiverDestroyed(QObject *o)
00279 {
00280     QMutableMapIterator<int, CustomAnimationState*> it(customAnims);
00281     while (it.hasNext()) {
00282         if (it.next().value()->receiver == o) {
00283             if (timerId) {
00284                 customAnimsToDelete.insert(it.value());
00285             } else {
00286                 delete[] it.value()->slot;
00287                 delete it.value();
00288             }
00289 
00290             it.remove();
00291         }
00292     }
00293 }
00294 
00295 int Animator::animateItem(QGraphicsItem *item, Animation animation)
00296 {
00297      //kDebug();
00298     // get rid of any existing animations on this item.
00299     //TODO: shoudl we allow multiple anims per item?
00300     QMap<QGraphicsItem*, AnimationState*>::iterator it = d->animatedItems.find(item);
00301     if (it != d->animatedItems.end()) {
00302         if (d->timerId) {
00303             d->animatedItemsToDelete.insert(it.value());
00304         } else {
00305             delete it.value();
00306         }
00307 
00308         d->animatedItems.erase(it);
00309     }
00310 
00311     int frames = d->driver->animationFps(animation);
00312 
00313     if (frames < 1) {
00314         // evidently this animator doesn't have an implementation
00315         // for this Animation
00316         return -1;
00317     }
00318 
00319     int duration = d->driver->animationDuration(animation);
00320 
00321     AnimationState *state = new AnimationState;
00322     state->id = ++d->animId;
00323     state->item = item;
00324     state->animation = animation;
00325     state->curve = d->driver->animationCurve(animation);
00326     state->frames = qMax(1.0, frames * (duration / 1000.0));
00327     state->currentFrame = 0;
00328     state->interval = d->driver->animationDuration(animation) / qreal(state->frames);
00329     state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
00330     state->currentInterval = state->interval;
00331     state->qobj = dynamic_cast<QObject*>(item);
00332 
00333     if (state->qobj) {
00334         //kDebug() << "!!!!!!!!!!!!!!!!!!!!!!!!! got us an object!";
00335         disconnect(state->qobj, SIGNAL(destroyed(QObject*)),
00336                    this, SLOT(animatedItemDestroyed(QObject*)));
00337         connect(state->qobj, SIGNAL(destroyed(QObject*)),
00338                 this, SLOT(animatedItemDestroyed(QObject*)));
00339     }
00340 
00341     d->animatedItems[item] = state;
00342     d->performAnimation(0, state);
00343 
00344     if (!d->timerId) {
00345         d->timerId = startTimer(MIN_TICK_RATE);
00346         d->time.restart();
00347     }
00348 
00349     return state->id;
00350 }
00351 
00352 int Animator::moveItem(QGraphicsItem *item, Movement movement, const QPoint &destination)
00353 {
00354      //kDebug();
00355      QMap<QGraphicsItem*, MovementState*>::iterator it = d->movingItems.find(item);
00356      if (it != d->movingItems.end()) {
00357          if (d->timerId) {
00358              d->movingItemsToDelete.insert(it.value());
00359          } else {
00360              delete it.value();
00361          }
00362 
00363          d->movingItems.erase(it);
00364      }
00365 
00366      int frames = d->driver->movementAnimationFps(movement);
00367      if (frames <= 1) {
00368           // evidently this animator doesn't have an implementation
00369           // for this Animation
00370           return -1;
00371      }
00372 
00373      MovementState *state = new MovementState;
00374      state->id = ++d->animId;
00375      state->destination = destination;
00376      state->start = item->pos().toPoint();
00377      state->item = item;
00378      state->movement = movement;
00379      state->curve = d->driver->movementAnimationCurve(movement);
00380      //TODO: variance in times based on the value of animation
00381      int duration = d->driver->movementAnimationDuration(movement);
00382      state->frames = qMax(1.0, frames * (duration / 1000.0));
00383      state->currentFrame = 0;
00384      state->interval = duration / qreal(state->frames);
00385      state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
00386 //     state->interval = (state->interval / MIN_TICK_RATE) * MIN_TICK_RATE;
00387 //     kDebug() << "interval of" << state->interval << state->frames << duration << frames;
00388      state->currentInterval = state->interval;
00389      state->qobj = dynamic_cast<QObject*>(item);
00390 
00391      if (state->qobj) {
00392         disconnect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
00393         connect(state->qobj, SIGNAL(destroyed(QObject*)), this, SLOT(movingItemDestroyed(QObject*)));
00394      }
00395 
00396      d->movingItems[item] = state;
00397      d->performMovement(0, state);
00398 
00399      if (!d->timerId) {
00400           d->timerId = startTimer(MIN_TICK_RATE);
00401           d->time.restart();
00402      }
00403 
00404      return state->id;
00405 }
00406 
00407 int Animator::customAnimation(int frames, int duration, Animator::CurveShape curve,
00408                               QObject *receiver, const char *slot)
00409 {
00410     if (frames < 1 || duration < 1 || !receiver || !slot) {
00411         return -1;
00412     }
00413 
00414     CustomAnimationState *state = new CustomAnimationState;
00415     state->id = ++d->animId;
00416     state->frames = frames;
00417     state->currentFrame = 0;
00418     state->curve = curve;
00419     state->frameInterval = qMax(qreal(1.0), duration / qreal(state->frames));
00420     state->interval = qMax(MIN_TICK_RATE_INT, state->frameInterval - (state->frameInterval % MIN_TICK_RATE_INT));
00421     state->currentInterval = state->interval;
00422     state->receiver = receiver;
00423     state->slot = qstrdup(slot);
00424 
00425     d->customAnims[state->id] = state;
00426 
00427     disconnect(receiver, SIGNAL(destroyed(QObject*)),
00428                this, SLOT(customAnimReceiverDestroyed(QObject*)));
00429     connect(receiver, SIGNAL(destroyed(QObject*)),
00430             this, SLOT(customAnimReceiverDestroyed(QObject*)));
00431 
00432     // try with only progress as argument
00433     if (!QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0))) {
00434         //try to pass also the animation id
00435         QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0), Q_ARG(int, state->id));
00436     }
00437 
00438     if (!d->timerId) {
00439         d->timerId = startTimer(MIN_TICK_RATE);
00440         d->time.restart();
00441     }
00442 
00443     return state->id;
00444 }
00445 
00446 void Animator::stopCustomAnimation(int id)
00447 {
00448     QMap<int, CustomAnimationState*>::iterator it = d->customAnims.find(id);
00449     if (it != d->customAnims.end()) {
00450         if (d->timerId) {
00451             d->customAnimsToDelete.insert(it.value());
00452         } else {
00453             delete[] it.value()->slot;
00454             delete it.value();
00455         }
00456 
00457         d->customAnims.erase(it);
00458     }
00459     //kDebug() << "stopCustomAnimation(AnimId " << id << ") done";
00460 }
00461 
00462 void Animator::stopItemAnimation(int id)
00463 {
00464     QMutableMapIterator<QGraphicsItem*, AnimationState*> it(d->animatedItems);
00465     while (it.hasNext()) {
00466         it.next();
00467         if (it.value()->id == id) {
00468             if (d->timerId) {
00469                 d->animatedItemsToDelete.insert(it.value());
00470             } else {
00471                 delete it.value();
00472             }
00473 
00474             it.remove();
00475             return;
00476         }
00477     }
00478 }
00479 
00480 void Animator::stopItemMovement(int id)
00481 {
00482     QMutableMapIterator<QGraphicsItem*, MovementState*> it(d->movingItems);
00483     while (it.hasNext()) {
00484         it.next();
00485         if (it.value()->id == id) {
00486             if (d->timerId) {
00487                 d->movingItemsToDelete.insert(it.value());
00488             } else {
00489                 delete it.value();
00490             }
00491 
00492             it.remove();
00493             return;
00494         }
00495     }
00496 }
00497 
00498 int Animator::animateElement(QGraphicsItem *item, Animation animation)
00499 {
00500     //kDebug() << "startElementAnimation(AnimId " << animation << ")";
00501     int frames = d->driver->elementAnimationFps(animation);
00502     int duration = d->driver->animationDuration(animation);
00503 
00504     ElementAnimationState *state = new ElementAnimationState;
00505     state->item = item;
00506     state->curve = d->driver->elementAnimationCurve(animation);
00507     state->animation = animation;
00508     state->frames = qMax(1.0, frames * (duration / 1000.0));
00509     state->currentFrame = 0;
00510     state->interval = duration / qreal(state->frames);
00511     state->interval = qMax(MIN_TICK_RATE_INT, state->interval - (state->interval % MIN_TICK_RATE_INT));
00512     state->currentInterval = state->interval;
00513     state->id = ++d->animId;
00514     state->qobj = dynamic_cast<QObject*>(item);
00515 
00516     if (state->qobj) {
00517         disconnect(state->qobj, SIGNAL(destroyed(QObject*)),
00518                    this, SLOT(animatedElementDestroyed(QObject*)));
00519         connect(state->qobj, SIGNAL(destroyed(QObject*)),
00520                 this, SLOT(animatedElementDestroyed(QObject*)));
00521     }
00522 
00523     //kDebug() << "animateElement " << animation << ", interval: "
00524     //         << state->interval << ", frames: " << state->frames;
00525     bool needTimer = true;
00526     if (state->frames < 1) {
00527         state->frames = 1;
00528         state->currentFrame = 1;
00529         needTimer = false;
00530     }
00531 
00532     d->animatedElements[state->id] = state;
00533 
00534     //kDebug() << "startElementAnimation(AnimId " << animation << ") returning " << state->id;
00535     if (needTimer && !d->timerId) {
00536         // start a 20fps timer;
00537         //TODO: should be started at the maximum frame rate needed only?
00538         d->timerId = startTimer(MIN_TICK_RATE);
00539         d->time.restart();
00540     }
00541     return state->id;
00542 }
00543 
00544 void Animator::stopElementAnimation(int id)
00545 {
00546     QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
00547     if (it != d->animatedElements.end()) {
00548         if (d->timerId) {
00549             d->animatedElementsToDelete.insert(it.value());
00550         } else {
00551             delete it.value();
00552         }
00553 
00554         d->animatedElements.erase(it);
00555     }
00556     //kDebug() << "stopElementAnimation(AnimId " << id << ") done";
00557 }
00558 
00559 void Animator::setInitialPixmap(int id, const QPixmap &pixmap)
00560 {
00561     QMap<int, ElementAnimationState*>::iterator it = d->animatedElements.find(id);
00562 
00563     if (it == d->animatedElements.end()) {
00564         kDebug() << "No entry found for id " << id;
00565         return;
00566     }
00567 
00568     it.value()->pixmap = pixmap;
00569 }
00570 
00571 QPixmap Animator::currentPixmap(int id)
00572 {
00573     QMap<int, ElementAnimationState*>::const_iterator it = d->animatedElements.constFind(id);
00574 
00575     if (it == d->animatedElements.constEnd()) {
00576         //kDebug() << "Animator::currentPixmap(" << id << ") found no entry for it!";
00577         return QPixmap();
00578     }
00579 
00580     ElementAnimationState *state = it.value();
00581     qreal progress = d->calculateProgress(state->currentFrame * state->interval,
00582                                           state->frames *  state->interval,
00583                                           state->curve);
00584     //kDebug() << "Animator::currentPixmap(" << id <<   " at " << progress;
00585 
00586     switch (state->animation) {
00587         case AppearAnimation:
00588             return d->driver->elementAppear(progress, state->pixmap);
00589             break;
00590         case DisappearAnimation:
00591             return d->driver->elementDisappear(progress, state->pixmap);
00592             break;
00593         case ActivateAnimation:
00594             break;
00595     }
00596 
00597     return state->pixmap;
00598 }
00599 
00600 bool Animator::isAnimating() const
00601 {
00602     return (!d->animatedItems.isEmpty() ||
00603             !d->movingItems.isEmpty() ||
00604             !d->animatedElements.isEmpty() ||
00605             !d->customAnims.isEmpty());
00606 }
00607 
00608 void Animator::timerEvent(QTimerEvent *event)
00609 {
00610     if (event->timerId() != d->timerId) {
00611         QObject::timerEvent(event);
00612         return;
00613     }
00614 
00615     Q_UNUSED(event)
00616     bool animationsRemain = false;
00617     int elapsed = MIN_TICK_RATE;
00618     if (d->time.elapsed() > elapsed) {
00619         elapsed = d->time.elapsed();
00620     }
00621     d->time.restart();
00622     //kDebug() << "timeEvent, elapsed time: " << elapsed;
00623 
00624     foreach (AnimationState *state, d->animatedItems) {
00625         if (d->animatedItemsToDelete.contains(state)) {
00626             continue;
00627         }
00628 
00629         if (state->currentInterval <= elapsed) {
00630             // we need to step forward!
00631             state->currentFrame +=
00632                 (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00633                 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00634 
00635             if (state->currentFrame < state->frames) {
00636                 qreal progress = d->calculateProgress(state->currentFrame * state->interval,
00637                                                       state->frames *  state->interval,
00638                                                       state->curve);
00639                 d->performAnimation(progress, state);
00640                 state->currentInterval = state->interval;
00641                 animationsRemain = true;
00642             } else {
00643                 d->performAnimation(1, state);
00644                 d->animatedItems.erase(d->animatedItems.find(state->item));
00645                 emit animationFinished(state->item, state->animation);
00646                 d->animatedItemsToDelete.insert(state);
00647             }
00648         } else {
00649             state->currentInterval -= elapsed;
00650             animationsRemain = true;
00651         }
00652     }
00653 
00654     foreach (MovementState *state, d->movingItems) {
00655         if (d->movingItemsToDelete.contains(state)) {
00656             continue;
00657         }
00658 
00659         if (state->currentInterval <= elapsed) {
00660             // we need to step forward!
00661             state->currentFrame +=
00662                 (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00663                 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00664 
00665             if (state->currentFrame < state->frames) {
00666                 //kDebug() << "movement";
00667                 qreal progress = d->calculateProgress(state->currentFrame * state->interval,
00668                                                       state->frames *  state->interval,
00669                                                       state->curve);
00670                 d->performMovement(progress, state);
00671                 animationsRemain = true;
00672             } else {
00673                 //kDebug() << "movement";
00674                 d->performMovement(1, state);
00675                 d->movingItems.erase(d->movingItems.find(state->item));
00676                 emit movementFinished(state->item);
00677                 d->movingItemsToDelete.insert(state);
00678             }
00679         } else {
00680             state->currentInterval -= elapsed;
00681             animationsRemain = true;
00682         }
00683     }
00684 
00685     foreach (ElementAnimationState *state, d->animatedElements) {
00686         if (d->animatedElementsToDelete.contains(state)) {
00687             continue;
00688         }
00689 
00690         if (state->currentFrame == state->frames) {
00691             //kDebug() << "skipping" << state->id << "as it is already at frame"
00692             //         << state->currentFrame << "of" << state->frames;
00693             // since we keep element animations around until they are
00694             // removed, we will end up with finished animations in the queue;
00695             // just skip them
00696             //TODO: should we move them to a separate QMap?
00697             continue;
00698         }
00699 
00700         if (state->currentInterval <= elapsed) {
00701             // we need to step forward!
00702             /*kDebug() << "stepping forwards element anim " << state->id
00703                        << " from " << state->currentFrame
00704                        << " by " << qMax(1, elapsed / state->interval) << " to "
00705                        << state->currentFrame + qMax(1, elapsed / state->interval) << endl;*/
00706             state->currentFrame +=
00707                 (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00708                 qMax(1, elapsed / state->interval) : state->frames - state->currentFrame;
00709 
00710             state->item->update();
00711             if (state->currentFrame < state->frames) {
00712                 state->currentInterval = state->interval;
00713                 animationsRemain = true;
00714             } else {
00715                 d->animatedElements.remove(state->id);
00716                 emit elementAnimationFinished(state->id);
00717                 d->animatedElementsToDelete.insert(state);
00718             }
00719         } else {
00720             state->currentInterval -= elapsed;
00721             animationsRemain = true;
00722         }
00723     }
00724 
00725     foreach (CustomAnimationState *state, d->customAnims) {
00726         if (d->customAnimsToDelete.contains(state)) {
00727             continue;
00728         }
00729 
00730         if (state->currentInterval <= elapsed) {
00731             // advance the frame
00732             state->currentFrame +=
00733                 (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ?
00734                 qMax(1, elapsed / state->frameInterval) : state->frames - state->currentFrame;
00735             /*kDebug() << "custom anim for" << state->receiver
00736                        << "to slot" << state->slot
00737                        << "with interval of" << state->interval
00738                        << "at frame" << state->currentFrame;*/
00739 
00740             if (state->currentFrame < state->frames) {
00741                 //kDebug () << "not the final frame";
00742                 //TODO: calculate a proper interval based on the curve
00743                 state->currentInterval = state->interval;
00744                 animationsRemain = true;
00745                 // signal the object
00746                 // try with only progress as argument
00747                 qreal progress = d->calculateProgress(state->currentFrame * state->interval,
00748                                                       state->frames *  state->interval,
00749                                                       state->curve);
00750                 if (!QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, progress))) {
00751                 //if fails try to add the animation id
00752                     QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, progress),
00753                                               Q_ARG(int, state->id));
00754                 }
00755             } else {
00756                 if (!QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1))) {
00757                     QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1), Q_ARG(int, state->id));
00758                 }
00759                 d->customAnims.erase(d->customAnims.find(state->id));
00760                 emit customAnimationFinished(state->id);
00761                 d->customAnimsToDelete.insert(state);
00762             }
00763         } else {
00764             state->currentInterval -= elapsed;
00765             animationsRemain = true;
00766         }
00767     }
00768 
00769     if (!animationsRemain && d->timerId) {
00770         killTimer(d->timerId);
00771         d->timerId = 0;
00772     }
00773 
00774     d->cleanupStates();
00775 }
00776 
00777 void AnimatorPrivate::init(Animator *q)
00778 {
00779     //FIXME: usage between different applications?
00780     KConfig c("plasmarc");
00781     KConfigGroup cg(&c, "Animator");
00782     QString pluginName = cg.readEntry("driver", "default");
00783 
00784     if (!pluginName.isEmpty()) {
00785         QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(pluginName);
00786         KService::List offers = KServiceTypeTrader::self()->query("Plasma/Animator", constraint);
00787 
00788         if (!offers.isEmpty()) {
00789             QString error;
00790 
00791             KPluginLoader plugin(*offers.first());
00792 
00793             if (Plasma::isPluginVersionCompatible(plugin.pluginVersion())) {
00794                 driver = offers.first()->createInstance<Plasma::AnimationDriver>(q, QVariantList(), &error);
00795             }
00796 
00797             if (!driver) {
00798                 kDebug() << "Could not load requested animator "
00799                          << offers.first() << ". Error given: " << error;
00800             }
00801         }
00802     }
00803 
00804     if (!driver) {
00805         driver = new AnimationDriver(q);
00806     }
00807 }
00808 
00809 void AnimatorPrivate::cleanupStates()
00810 {
00811     /*
00812     kDebug() << animatedItemsToDelete.count() << animatedElementsToDelete.count()
00813              << movingItemsToDelete.count() << customAnimsToDelete.count();
00814              */
00815     qDeleteAll(animatedItemsToDelete);
00816     animatedItemsToDelete.clear();
00817     qDeleteAll(animatedElementsToDelete);
00818     animatedElementsToDelete.clear();
00819     qDeleteAll(movingItemsToDelete);
00820     movingItemsToDelete.clear();
00821 
00822     QSetIterator<CustomAnimationState*> it(customAnimsToDelete);
00823     while (it.hasNext()) {
00824         CustomAnimationState *state = it.next();
00825         delete[] state->slot;
00826         delete state;
00827     }
00828     customAnimsToDelete.clear();
00829 }
00830 
00831 } // namespace Plasma
00832 
00833 #include <animator.moc>

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal