KIO
delegateanimationhandler.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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);
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
00123
00124 return NULL;
00125 #endif
00126
00127
00128
00129
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
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
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
00171
00172
00173
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
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
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);
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
00245
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
00259
00260
00261 if (state->direction == QTimeLine::Backward || !state->index.isValid())
00262 {
00263 delete state;
00264 i.remove();
00265 }
00266 }
00267
00268
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