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