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
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>
30 #include "layouts/layout.h"
31 #include "widgets/widget.h"
33 using namespace Plasma
;
35 class LayoutAnimator::Private
38 QHash
<LayoutAnimator::State
,int> effects
;
47 QHash
<LayoutItem
*,ItemGeometry
> geometries
;
48 QHash
<LayoutItem
*,LayoutAnimator::State
> states
;
49 QPointer
<QTimeLine
> timeLine
;
51 bool autoDeleteOnRemoval
;
55 , autoDeleteOnRemoval(false)
59 qreal
delta(qreal currentValue
) const
61 if ( currentValue
> lastValue
) {
62 return currentValue
- lastValue
;
64 return (1.0-lastValue
) + currentValue
;
68 QRectF
interpolateGeometry(LayoutItem
* item
,qreal value
) const
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
);
83 void prepareItemForState( LayoutItem
*item
, LayoutAnimator::State state
) {
85 // opacity setting for widgets
86 Widget
*widget
= dynamic_cast<Widget
*>(item
->graphicsItem());
88 if (state
== InsertedState
&& effects
[state
] == LayoutAnimator::FadeInMoveEffect
) {
89 widget
->setOpacity(0); // item is invisible immediately after insertion
91 widget
->setOpacity(1.0);
97 LayoutAnimator::LayoutAnimator(QObject
* parent
)
104 LayoutAnimator::~LayoutAnimator()
109 void LayoutAnimator::setAutoDeleteOnRemoval(bool autoDelete
)
111 if ( d
->autoDeleteOnRemoval
== autoDelete
)
114 d
->autoDeleteOnRemoval
= 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
)) );
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();
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
)) {
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
)
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
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
)
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
);
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());
253 if ( widget
!= 0 && d
->geometries
[item
].startGeometry
!= d
->geometries
[item
].endGeometry
) {
254 widget
->setOpacity( qAbs( (value
*2)-1.0 ) );
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
) )
268 setCurrentState(item
,StandardState
);
271 d
->states
.remove(item
);
272 d
->geometries
.remove(item
);
273 emit
stateChanged(item
, RemovedState
, DeadState
);
276 d
->geometries
[item
].startGeometry
= d
->geometries
[item
].endGeometry
;
283 void LayoutAnimator::updateItem( qreal value
, LayoutItem
* item
)
285 Q_ASSERT( value
>= 0 && value
<= 1.0 );
287 Q_ASSERT( d
->geometries
.contains(item
) );
289 switch ( effect(d
->states
[item
]) )
292 noEffectUpdateItem(value
,item
);
295 moveEffectUpdateItem(value
,item
,MoveEffect
);
297 case FadeInMoveEffect
:
298 moveEffectUpdateItem(value
,item
,FadeInMoveEffect
);
300 case FadeOutMoveEffect
:
301 moveEffectUpdateItem(value
,item
,FadeOutMoveEffect
);
304 fadeEffectUpdateItem(value
,item
);
311 #include "layoutanimator.moc"