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 "delegateanimationhandler_p.h"
00023
00024 #include <QListView>
00025 #include <QAbstractItemView>
00026 #include <QPersistentModelIndex>
00027 #include <QTime>
00028 #include <QDebug>
00029
00030 #include <cmath>
00031
00032 #include "delegateanimationhandler_p.moc"
00033
00034 namespace KIO
00035 {
00036
00037
00038 class ProtectedAccessor : public QAbstractItemView
00039 {
00040 public:
00041 bool draggingState() const { return state() == DraggingState; }
00042 };
00043
00044
00045
00046
00047
00048
00049
00050 CachedRendering::CachedRendering(QStyle::State state, const QSize &size)
00051 : state(state), regular(QPixmap(size)), hover(QPixmap(size))
00052 {
00053 regular.fill(Qt::transparent);
00054 hover.fill(Qt::transparent);
00055 }
00056
00057
00058
00059
00060
00061
00062
00063 AnimationState::AnimationState(const QModelIndex &index)
00064 : index(index), direction(QTimeLine::Forward),
00065 animating(false), progress(0.0), renderCache(NULL)
00066 {
00067 creationTime.start();
00068 }
00069
00070
00071 AnimationState::~AnimationState()
00072 {
00073 delete renderCache;
00074 }
00075
00076
00077 bool AnimationState::update()
00078 {
00079 const qreal runtime = (direction == QTimeLine::Forward ? 150 : 250);
00080 const qreal increment = 1000. / runtime / 1000.;
00081 const qreal delta = increment * time.restart();
00082
00083 if (direction == QTimeLine::Forward)
00084 {
00085 progress = qMin(qreal(1.0), progress + delta);
00086 animating = (progress < 1.0);
00087 }
00088 else
00089 {
00090 progress = qMax(qreal(0.0), progress - delta);
00091 animating = (progress > 0.0);
00092 }
00093
00094 return !animating;
00095 }
00096
00097
00098 qreal AnimationState::hoverProgress() const
00099 {
00100 #ifndef M_PI_2
00101 #define M_PI_2 1.57079632679489661923
00102 #endif
00103 return qRound(255.0 * std::sin(progress * M_PI_2)) / 255.0;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112 DelegateAnimationHandler::DelegateAnimationHandler(QObject *parent)
00113 : QObject(parent), timerId(0)
00114 {
00115 }
00116
00117
00118 AnimationState *DelegateAnimationHandler::animationState(const QStyleOption &option,
00119 const QModelIndex &index,
00120 const QAbstractItemView *view)
00121 {
00122
00123
00124
00125 if (!view || static_cast<const ProtectedAccessor*>(view)->draggingState())
00126 return NULL;
00127
00128 AnimationState *state = findAnimationState(view, index);
00129 bool hover = option.state & QStyle::State_MouseOver;
00130
00131
00132 if (!state && hover)
00133 {
00134 state = new AnimationState(index);
00135 addAnimationState(state, view);
00136
00137 if (!fadeInAddTime.isValid() ||
00138 (fadeInAddTime.isValid() && fadeInAddTime.elapsed() > 300))
00139 {
00140 startAnimation(state);
00141 }
00142 else
00143 {
00144 state->animating = false;
00145 state->progress = 1.0;
00146 state->direction = QTimeLine::Forward;
00147 }
00148
00149 fadeInAddTime.restart();
00150 }
00151 else if (state)
00152 {
00153
00154 if (!hover && (!state->animating || state->direction == QTimeLine::Forward))
00155 {
00156 state->direction = QTimeLine::Backward;
00157
00158 if (state->creationTime.elapsed() < 200)
00159 state->progress = 0.0;
00160
00161 startAnimation(state);
00162 }
00163 else if (hover && state->direction == QTimeLine::Backward)
00164 {
00165
00166
00167
00168
00169 state->direction = QTimeLine::Forward;
00170
00171 if (!state->animating)
00172 startAnimation(state);
00173 }
00174 }
00175
00176 return state;
00177 }
00178
00179
00180 AnimationState *DelegateAnimationHandler::findAnimationState(const QAbstractItemView *view,
00181 const QModelIndex &index) const
00182 {
00183
00184 AnimationList *list = animationLists.value(view);
00185
00186 if (list)
00187 {
00188 foreach (AnimationState *state, *list)
00189 if (state->index == index)
00190 return state;
00191 }
00192
00193 return NULL;
00194 }
00195
00196
00197 void DelegateAnimationHandler::addAnimationState(AnimationState *state, const QAbstractItemView *view)
00198 {
00199 AnimationList *list = animationLists.value(view);
00200
00201
00202 if (!list)
00203 {
00204 connect(view, SIGNAL(destroyed(QObject*)), SLOT(viewDeleted(QObject*)));
00205
00206 list = new AnimationList;
00207 animationLists.insert(view, list);
00208 }
00209
00210 list->append(state);
00211 }
00212
00213
00214 void DelegateAnimationHandler::startAnimation(AnimationState *state)
00215 {
00216 state->time.start();
00217 state->animating = true;
00218
00219 if (!timerId)
00220 {
00221 timerId = startTimer(1000 / 30);
00222 }
00223 }
00224
00225
00226 int DelegateAnimationHandler::runAnimations(AnimationList *list, const QAbstractItemView *view)
00227 {
00228 int activeAnimations = 0;
00229 QRegion region;
00230
00231 QMutableLinkedListIterator<AnimationState*> i(*list);
00232 while (i.hasNext())
00233 {
00234 AnimationState *state = i.next();
00235
00236 if (!state->animating)
00237 continue;
00238
00239
00240
00241 if (state->index.isValid())
00242 {
00243 bool finished = state->update();
00244 region += view->visualRect(state->index);
00245
00246 if (!finished)
00247 {
00248 activeAnimations++;
00249 continue;
00250 }
00251 }
00252
00253
00254
00255
00256 if (state->direction == QTimeLine::Backward || !state->index.isValid())
00257 {
00258 delete state;
00259 i.remove();
00260 }
00261 }
00262
00263
00264 if (!region.isEmpty())
00265 const_cast<QAbstractItemView*>(view)->viewport()->update(region);
00266
00267 return activeAnimations;
00268 }
00269
00270
00271 void DelegateAnimationHandler::viewDeleted(QObject *view)
00272 {
00273 AnimationList *list = animationLists.take(static_cast<QAbstractItemView*>(view));
00274 qDeleteAll(*list);
00275 delete list;
00276 }
00277
00278
00279 void DelegateAnimationHandler::timerEvent(QTimerEvent *)
00280 {
00281 int activeAnimations = 0;
00282
00283 AnimationListsIterator i(animationLists);
00284 while (i.hasNext())
00285 {
00286 i.next();
00287 AnimationList *list = i.value();
00288 const QAbstractItemView *view = i.key();
00289
00290 activeAnimations += runAnimations(list, view);
00291 }
00292
00293 if (activeAnimations == 0 && timerId)
00294 {
00295 killTimer(timerId);
00296 timerId = 0;
00297 }
00298 }
00299
00300 }
00301