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

KIO

delegateanimationhandler.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE project
00003 
00004    Copyright © 2007 Fredrik Höglund <fredrik@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include <QListView>
00023 #include <QAbstractItemView>
00024 #include <QPersistentModelIndex>
00025 #include <QTime>
00026 #include <QDebug>
00027 
00028 #include <cmath>
00029 
00030 #include "delegateanimationhandler_p.h"
00031 #include "delegateanimationhandler_p.moc"
00032 
00033 namespace KIO
00034 {
00035 
00036 // Needed because state() is a protected method
00037 class ProtectedAccessor : public QAbstractItemView
00038 {
00039 public:
00040     bool draggingState() const { return state() == DraggingState; }
00041 };
00042 
00043 
00044 
00045 // ---------------------------------------------------------------------------
00046 
00047 
00048 
00049 CachedRendering::CachedRendering(QStyle::State state, const QSize &size)
00050     : state(state), regular(QPixmap(size)), hover(QPixmap(size))
00051 {
00052     regular.fill(Qt::transparent);
00053     hover.fill(Qt::transparent);
00054 }
00055 
00056 
00057 
00058 // ---------------------------------------------------------------------------
00059 
00060 
00061 
00062 AnimationState::AnimationState(const QModelIndex &index)
00063         : index(index), direction(QTimeLine::Forward),
00064           animating(false), progress(0.0), renderCache(NULL)
00065 {
00066     creationTime.start();
00067 }
00068 
00069 
00070 AnimationState::~AnimationState()
00071 {
00072     delete renderCache;
00073 }
00074 
00075 
00076 bool AnimationState::update()
00077 {
00078     const qreal runtime = (direction == QTimeLine::Forward ? 150 : 250); // milliseconds
00079     const qreal increment = 1000. / runtime / 1000.;
00080     const qreal delta = increment * time.restart();
00081 
00082     if (direction == QTimeLine::Forward)
00083     {
00084         progress = qMin(qreal(1.0), progress + delta);
00085         animating = (progress < 1.0);
00086     }
00087     else
00088     {
00089         progress = qMax(qreal(0.0), progress - delta);
00090         animating = (progress > 0.0);
00091     }
00092 
00093     return !animating;
00094 }
00095 
00096 
00097 qreal AnimationState::hoverProgress() const
00098 {
00099 #ifndef M_PI_2
00100 #define M_PI_2 1.57079632679489661923
00101 #endif
00102     return qRound(255.0 * std::sin(progress * M_PI_2)) / 255.0;
00103 }
00104 
00105 
00106 
00107 // ---------------------------------------------------------------------------
00108 
00109 
00110 
00111 DelegateAnimationHandler::DelegateAnimationHandler(QObject *parent)
00112     : QObject(parent), timerId(0)
00113 {
00114 }
00115 
00116 
00117 AnimationState *DelegateAnimationHandler::animationState(const QStyleOption &option,
00118                                                          const QModelIndex &index,
00119                                                          const QAbstractItemView *view)
00120 {
00121 #if (QT_VERSION < 0x040300) || (QT_VERSION == 0x040300 && !defined(QT_KDE_QT_COPY))
00122     // Qt 4.3.0 and earlier versions have a bug that causes component alpha text
00123     // to be misrendered when drawn on a non-opaque background.
00124     return NULL;
00125 #endif
00126 
00127     // We can't do animations reliably when an item is being dragged, since that
00128     // item will be drawn in two locations at the same time and hovered in one and
00129     // not the other. We can't tell them apart because they both have the same index.
00130     if (!view || static_cast<const ProtectedAccessor*>(view)->draggingState())
00131         return NULL;
00132 
00133     AnimationState *state = findAnimationState(view, index);
00134     bool hover = option.state & QStyle::State_MouseOver;
00135 
00136     // If the cursor has entered an item
00137     if (!state && hover)
00138     {
00139         state = new AnimationState(index);
00140         addAnimationState(state, view);
00141 
00142         if (!fadeInAddTime.isValid() ||
00143             (fadeInAddTime.isValid() && fadeInAddTime.elapsed() > 300))
00144         {
00145             startAnimation(state);
00146         }
00147         else
00148         {
00149             state->animating = false;
00150             state->progress  = 1.0;
00151             state->direction = QTimeLine::Forward;
00152         }
00153 
00154         fadeInAddTime.restart();
00155     }
00156     else if (state)
00157     {
00158         // If the cursor has exited an item
00159         if (!hover && (!state->animating || state->direction == QTimeLine::Forward))
00160         {
00161             state->direction = QTimeLine::Backward;
00162 
00163             if (state->creationTime.elapsed() < 200)
00164                 state->progress = 0.0;
00165 
00166             startAnimation(state);
00167         }
00168         else if (hover && state->direction == QTimeLine::Backward)
00169         {
00170             // This is needed to handle the case where an item is dragged within
00171             // the view, and dropped in a different location. State_MouseOver will
00172             // initially not be set causing a "hover out" animation to start.
00173             // This reverses the direction as soon as we see the bit being set.
00174             state->direction = QTimeLine::Forward;
00175 
00176             if (!state->animating)
00177                 startAnimation(state);
00178         }
00179     }
00180 
00181     return state;
00182 }
00183 
00184 
00185 AnimationState *DelegateAnimationHandler::findAnimationState(const QAbstractItemView *view,
00186                                                              const QModelIndex &index) const
00187 {
00188     // Try to find a list of animation states for the view
00189     AnimationList *list = animationLists.value(view);
00190 
00191     if (list)
00192     {
00193         foreach (AnimationState *state, *list)
00194             if (state->index == index)
00195                 return state;
00196     }
00197 
00198     return NULL;
00199 }
00200 
00201 
00202 void DelegateAnimationHandler::addAnimationState(AnimationState *state, const QAbstractItemView *view)
00203 {
00204     AnimationList *list = animationLists.value(view);
00205 
00206     // If this is the first time we've seen this view
00207     if (!list)
00208     {
00209         connect(view, SIGNAL(destroyed(QObject*)), SLOT(viewDeleted(QObject*)));
00210 
00211         list = new AnimationList;
00212         animationLists.insert(view, list);
00213     }
00214 
00215     list->append(state);
00216 }
00217 
00218 
00219 void DelegateAnimationHandler::startAnimation(AnimationState *state)
00220 {
00221     state->time.start();
00222     state->animating = true;
00223 
00224     if (!timerId)
00225     {
00226         timerId = startTimer(1000 / 30); // 30 fps
00227     }
00228 }
00229 
00230 
00231 int DelegateAnimationHandler::runAnimations(AnimationList *list, const QAbstractItemView *view)
00232 {
00233     int activeAnimations = 0;
00234     QRegion region;
00235 
00236     QMutableLinkedListIterator<AnimationState*> i(*list);
00237     while (i.hasNext())
00238     {
00239         AnimationState *state = i.next();
00240 
00241         if (!state->animating)
00242             continue;
00243 
00244         // We need to make sure the index is still valid, since it could be removed
00245         // while the animation is running.
00246         if (state->index.isValid())
00247         {
00248             bool finished = state->update();
00249             region += view->visualRect(state->index);
00250 
00251             if (!finished)
00252             {
00253                 activeAnimations++;
00254                 continue;
00255             }
00256         }
00257 
00258         // If the direction is Forward, the state object needs to stick around
00259         // after the animation has finished, so we know that we've already done
00260         // a "hover in" for the index.
00261         if (state->direction == QTimeLine::Backward || !state->index.isValid())
00262         {
00263             delete state;
00264             i.remove();
00265         }
00266     }
00267 
00268     // Trigger a repaint of the animated indexes
00269     if (!region.isEmpty())
00270         const_cast<QAbstractItemView*>(view)->viewport()->update(region);
00271 
00272     return activeAnimations;
00273 }
00274 
00275 
00276 void DelegateAnimationHandler::viewDeleted(QObject *view)
00277 {
00278     AnimationList *list = animationLists.take(static_cast<QAbstractItemView*>(view));
00279     qDeleteAll(*list);
00280     delete list;
00281 }
00282 
00283 
00284 void DelegateAnimationHandler::timerEvent(QTimerEvent *)
00285 {
00286     int activeAnimations = 0;
00287 
00288     AnimationListsIterator i(animationLists);
00289     while (i.hasNext())
00290     {
00291         i.next();
00292         AnimationList *list = i.value();
00293         const QAbstractItemView *view = i.key();
00294 
00295         activeAnimations += runAnimations(list, view);
00296     }
00297 
00298     if (activeAnimations == 0 && timerId)
00299     {
00300         killTimer(timerId);
00301         timerId = 0;
00302     }
00303 }
00304 
00305 }
00306 

KIO

Skip menu "KIO"
  • 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
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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