Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / libs / plasma / layouts / layoutanimator.cpp
blob684bd15567b470d72b2b87583183cdcb65e1c2e2
1 /*
2 Copyright 2007 by Robert Knight <robertknight@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301 USA.
20 #include "layoutanimator.h"
22 #include <QtCore/QHash>
23 #include <QtCore/QList>
24 #include <QtCore/QPointer>
25 #include <QtCore/QTimeLine>
26 #include <QtGui/QGraphicsItem>
27 #include <QtGui/QGraphicsScene>
28 #include <QtDebug>
30 #include "layouts/layout.h"
31 #include "widgets/widget.h"
33 using namespace Plasma;
35 class LayoutAnimator::Private
37 public:
38 QHash<LayoutAnimator::State,int> effects;
40 class ItemGeometry
42 public:
43 QRectF startGeometry;
44 QRectF endGeometry;
45 };
47 QHash<LayoutItem*,ItemGeometry> geometries;
48 QHash<LayoutItem*,LayoutAnimator::State> states;
49 QPointer<QTimeLine> timeLine;
50 qreal lastValue;
51 bool autoDeleteOnRemoval;
53 Private()
54 : lastValue(0)
55 , autoDeleteOnRemoval(false)
59 qreal delta(qreal currentValue) const
61 if ( currentValue > lastValue ) {
62 return currentValue - lastValue;
63 } else {
64 return (1.0-lastValue) + currentValue;
68 QRectF interpolateGeometry(LayoutItem* item,qreal value) const
70 QRectF newGeometry;
72 const QRectF& current = geometries[item].startGeometry;
73 const QRectF& next = geometries[item].endGeometry;
75 newGeometry.setLeft(current.left() + (next.left()-current.left()) * value);
76 newGeometry.setRight(current.right() + (next.right()-current.right()) * value);
77 newGeometry.setTop(current.top() + (next.top()-current.top()) * value);
78 newGeometry.setBottom(current.bottom() + (next.bottom()-current.bottom()) * value);
80 return newGeometry;
83 void prepareItemForState( LayoutItem *item , LayoutAnimator::State state ) {
85 // opacity setting for widgets
86 Widget *widget = dynamic_cast<Widget*>(item->graphicsItem());
87 if (widget) {
88 if (state == InsertedState && effects[state] == LayoutAnimator::FadeInMoveEffect) {
89 widget->setOpacity(0); // item is invisible immediately after insertion
90 } else {
91 widget->setOpacity(1.0);
97 LayoutAnimator::LayoutAnimator(QObject* parent)
98 : QObject(parent),
99 d(new Private)
101 d->lastValue = 0;
104 LayoutAnimator::~LayoutAnimator()
106 delete d;
109 void LayoutAnimator::setAutoDeleteOnRemoval(bool autoDelete)
111 if ( d->autoDeleteOnRemoval == autoDelete )
112 return;
114 d->autoDeleteOnRemoval = autoDelete;
116 if ( autoDelete ) {
117 connect( this , SIGNAL(stateChanged(Plasma::LayoutItem*,Plasma::LayoutAnimator::State,Plasma::LayoutAnimator::State)) , this ,
118 SLOT(itemAutoDeleter(Plasma::LayoutItem*,Plasma::LayoutAnimator::State,Plasma::LayoutAnimator::State)) );
119 } else {
120 disconnect( this , SIGNAL(stateChanged(Plasma::LayoutItem*,Plasma::LayoutAnimator::State,Plasma::LayoutAnimator::State)) , this ,
121 SLOT(itemAutoDeleter(Plasma::LayoutItem*,Plasma::LayoutAnimator::State,Plasma::LayoutAnimator::State)) );
125 bool LayoutAnimator::autoDeleteOnRemoval() const
127 return d->autoDeleteOnRemoval;
130 void LayoutAnimator::itemAutoDeleter(Plasma::LayoutItem *item, Plasma::LayoutAnimator::State oldState, Plasma::LayoutAnimator::State newState)
132 if ( oldState == RemovedState && newState == DeadState ) {
133 if ( item->graphicsItem() ) {
134 item->graphicsItem()->scene()->removeItem( item->graphicsItem() );
136 if ( dynamic_cast<QGraphicsItem*>(item) != dynamic_cast<QGraphicsItem*>(item->graphicsItem()) )
137 delete item->graphicsItem();
140 delete item;
144 void LayoutAnimator::setEffect( State action , int effect )
146 d->effects[action] = effect;
148 int LayoutAnimator::effect(State action) const
150 return d->effects[action];
153 void LayoutAnimator::setCurrentState( LayoutItem* item , State state )
155 if (state == RemovedState && !d->states.contains(item)) {
156 return;
159 State oldState = d->states[item];
161 d->states[item] = state;
162 d->prepareItemForState(item,state);
164 emit stateChanged(item,oldState,state);
166 LayoutAnimator::State LayoutAnimator::state( LayoutItem* item ) const
168 return !d->states.contains(item) ? DeadState : d->states[item];
171 void LayoutAnimator::setTimeLine(QTimeLine* timeLine)
173 if ( d->timeLine ) {
174 disconnect( d->timeLine , SIGNAL(valueChanged(qreal)) , this ,
175 SLOT(valueChanged(qreal)) );
176 disconnect( d->timeLine , SIGNAL(finished()) , this ,
177 SLOT(animationCompleted()) );
180 d->timeLine = timeLine;
182 connect( d->timeLine , SIGNAL(valueChanged(qreal)) , this ,
183 SLOT(valueChanged(qreal)) );
184 connect( d->timeLine , SIGNAL(finished()) , this ,
185 SLOT(animationCompleted()) );
187 void LayoutAnimator::animationCompleted()
189 foreach( LayoutItem* item , d->states.keys() ) {
190 animationFinished(item);
193 QTimeLine* LayoutAnimator::timeLine() const
195 return d->timeLine;
197 void LayoutAnimator::valueChanged(qreal value)
199 foreach( LayoutItem* item , d->geometries.keys() ) {
200 updateItem(value,item);
203 d->lastValue = value;
206 void LayoutAnimator::setGeometry( LayoutItem* item , const QRectF& destGeometry )
208 Q_ASSERT( item );
210 Private::ItemGeometry& itemGeometry = d->geometries[item];
212 itemGeometry.startGeometry = item->geometry();
213 itemGeometry.endGeometry = destGeometry;
216 void LayoutAnimator::moveEffectUpdateItem( qreal value , LayoutItem* item , Effect effect )
218 Widget* widget = dynamic_cast<Widget*>(item->graphicsItem());
220 if ( widget && effect == FadeInMoveEffect ) {
221 widget->setOpacity( qMin(qreal(1.0),widget->opacity()+d->delta(value)) );
222 } else if ( widget && effect == FadeOutMoveEffect ) {
223 widget->setOpacity( qMax(qreal(0.0),widget->opacity()-d->delta(value)) );
227 if ( effect == FadeInMoveEffect || effect == FadeOutMoveEffect ) {
228 const QRectF finalGeometry = d->geometries[item].endGeometry;
230 if ( item->geometry() != finalGeometry ) {
231 item->setGeometry( finalGeometry );
233 } else {
234 item->setGeometry( d->interpolateGeometry(item,value) );
238 void LayoutAnimator::noEffectUpdateItem( qreal , LayoutItem* item )
240 const QRectF finalGeometry = d->geometries[item].endGeometry;
242 if ( item->geometry() != finalGeometry ) {
243 item->setGeometry( finalGeometry );
247 void LayoutAnimator::fadeEffectUpdateItem( qreal value , LayoutItem* item )
249 Widget* widget = dynamic_cast<Widget*>(item->graphicsItem());
251 qreal threshold = 0;
253 if ( widget != 0 && d->geometries[item].startGeometry != d->geometries[item].endGeometry ) {
254 widget->setOpacity( qAbs( (value*2)-1.0 ) );
255 threshold = 0.5;
258 const QRectF newGeometry = ( value < threshold ) ? d->geometries[item].startGeometry : d->geometries[item].endGeometry;
260 item->setGeometry(newGeometry);
263 void LayoutAnimator::animationFinished(LayoutItem* item)
265 switch ( state(item) )
267 case InsertedState:
268 setCurrentState(item,StandardState);
269 break;
270 case RemovedState:
271 d->states.remove(item);
272 d->geometries.remove(item);
273 emit stateChanged(item, RemovedState, DeadState);
274 break;
275 case StandardState:
276 d->geometries[item].startGeometry = d->geometries[item].endGeometry;
277 break;
278 default:
279 Q_ASSERT(false);
283 void LayoutAnimator::updateItem( qreal value , LayoutItem* item )
285 Q_ASSERT( value >= 0 && value <= 1.0 );
286 Q_ASSERT( item );
287 Q_ASSERT( d->geometries.contains(item) );
289 switch ( effect(d->states[item]) )
291 case NoEffect:
292 noEffectUpdateItem(value,item);
293 break;
294 case MoveEffect:
295 moveEffectUpdateItem(value,item,MoveEffect);
296 break;
297 case FadeInMoveEffect:
298 moveEffectUpdateItem(value,item,FadeInMoveEffect);
299 break;
300 case FadeOutMoveEffect:
301 moveEffectUpdateItem(value,item,FadeOutMoveEffect);
302 break;
303 case FadeEffect:
304 fadeEffectUpdateItem(value,item);
305 break;
306 default:
307 Q_ASSERT(false);
311 #include "layoutanimator.moc"