Add auto-deletion functionality into LayoutAnimator which can be used to delete the item when its removal animation finishes. Emit a signal when the state of an item in the animator changes. Avoid repeatedly setting an item's geometry with the NoEffect effect. Added a DeadState into which items transition after their removal animation finishes or if they have not been added to the animator. When inserting an item with a fade in effect set the opacity to 0 if the item is a widget.

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=706933
This commit is contained in:
Robert Knight 2007-08-31 15:19:02 +00:00
parent b329ddb69a
commit 37b993d8ff
2 changed files with 125 additions and 18 deletions

View File

@ -46,10 +46,15 @@ public:
QHash<LayoutItem*,ItemGeometry> geometries;
QHash<LayoutItem*,LayoutAnimator::State> states;
QPointer<QTimeLine> timeLine;
qreal lastValue;
bool autoDeleteOnRemoval;
Private()
: lastValue(0)
, autoDeleteOnRemoval(false)
{
}
qreal delta(qreal currentValue) const
{
@ -73,6 +78,18 @@ public:
return newGeometry;
}
void prepareItemForState( LayoutItem *item , LayoutAnimator::State state ) {
// opacity setting for widgets
if ( state == InsertedState && effects[state] == LayoutAnimator::FadeInMoveEffect ) {
Widget *widget = dynamic_cast<Widget*>(item->graphicsItem());
if ( widget ) {
widget->setOpacity(0); // item is invisible immediately after insertion
}
}
}
};
LayoutAnimator::LayoutAnimator(QObject* parent)
@ -87,6 +104,39 @@ LayoutAnimator::~LayoutAnimator()
delete d;
}
void LayoutAnimator::setAutoDeleteOnRemoval(bool autoDelete)
{
if ( d->autoDeleteOnRemoval == autoDelete )
return;
d->autoDeleteOnRemoval = autoDelete;
if ( autoDelete ) {
connect( this , SIGNAL(stateChanged(LayoutItem*,State,State)) , this ,
SLOT(itemAutoDeleter(LayoutItem*,State,State)) );
} else {
disconnect( this , SIGNAL(stateChanged(LayoutItem*,State,State)) , this ,
SLOT(itemAutoDeleter(LayoutItem*,State,State)) );
}
}
bool LayoutAnimator::autoDeleteOnRemoval() const
{
return d->autoDeleteOnRemoval;
}
void LayoutAnimator::itemAutoDeleter(LayoutItem *item , State oldState , State newState)
{
if ( oldState == RemovedState && newState == DeadState ) {
if ( item->graphicsItem() ) {
item->graphicsItem()->scene()->removeItem( item->graphicsItem() );
if ( dynamic_cast<QGraphicsItem*>(item) != dynamic_cast<QGraphicsItem*>(item->graphicsItem()) )
delete item->graphicsItem();
}
delete item;
}
}
void LayoutAnimator::setEffect( State action , int effect )
{
d->effects[action] = effect;
@ -96,13 +146,22 @@ int LayoutAnimator::effect(State action) const
return d->effects[action];
}
void LayoutAnimator::setCurrentState( LayoutItem* item , State action )
void LayoutAnimator::setCurrentState( LayoutItem* item , State state )
{
d->states[item] = action;
State oldState = d->states[item];
d->states[item] = state;
d->prepareItemForState(item,state);
emit stateChanged(item,oldState,state);
}
LayoutAnimator::State LayoutAnimator::state( LayoutItem* item ) const
{
return d->states[item];
if ( !d->states.contains(item) ) {
return DeadState;
} else {
return d->states[item];
}
}
void LayoutAnimator::setTimeLine(QTimeLine* timeLine)
@ -121,6 +180,12 @@ void LayoutAnimator::setTimeLine(QTimeLine* timeLine)
connect( d->timeLine , SIGNAL(finished()) , this ,
SLOT(animationCompleted()) );
}
void LayoutAnimator::animationCompleted()
{
foreach( LayoutItem* item , d->states.keys() ) {
animationFinished(item);
}
}
QTimeLine* LayoutAnimator::timeLine() const
{
return d->timeLine;
@ -153,12 +218,23 @@ void LayoutAnimator::moveEffectUpdateItem( qreal value , LayoutItem* item , Effe
else if ( widget && effect == FadeOutMoveEffect )
widget->setOpacity( qMax(0.0,widget->opacity()-d->delta(value)) );
item->setGeometry( d->interpolateGeometry(item,value) );
if ( effect == FadeInMoveEffect ) {
const QRectF finalGeometry = d->geometries[item].endGeometry;
if ( item->geometry() != finalGeometry )
item->setGeometry( finalGeometry );
}
else
item->setGeometry( d->interpolateGeometry(item,value) );
}
void LayoutAnimator::noEffectUpdateItem( qreal , LayoutItem* item )
{
item->setGeometry( d->geometries[item].endGeometry );
const QRectF finalGeometry = d->geometries[item].endGeometry;
if ( item->geometry() != finalGeometry )
item->setGeometry( finalGeometry );
}
void LayoutAnimator::fadeEffectUpdateItem( qreal value , LayoutItem* item )
@ -184,17 +260,19 @@ void LayoutAnimator::fadeEffectUpdateItem( qreal value , LayoutItem* item )
void LayoutAnimator::animationFinished(LayoutItem* item)
{
switch (d->states[item])
switch ( state(item) )
{
case InsertedState:
d->states[item] = NormalState;
setCurrentState(item,StandardState);
break;
case RemovedState:
d->states.remove(item);
d->geometries.remove(item);
emit stateChanged( item , RemovedState , DeadState );
break;
case NormalState:
// do nothing
case StandardState:
d->geometries[item].startGeometry = d->geometries[item].endGeometry;
break;
default:
Q_ASSERT(false);

View File

@ -44,7 +44,7 @@ class LayoutItem;
*
* animator->setTimeLine(timeLine);
* animator->setEffect( LayoutAnimator::InsertedState , LayoutAnimator::FadeInMoveEffect );
* animator->setEffect( LayoutAnimator::NormalState , LayoutAnimator::MoveEffect );
* animator->setEffect( LayoutAnimator::StandardState , LayoutAnimator::MoveEffect );
* animator->setEffect( LayoutAnimator::RemovedState , LayoutAnimator::FadeOutMoveEffect );
* myLayout->setAnimator(animator);
*
@ -69,7 +69,7 @@ public:
/**
* State for an item which has recently been added to a layout.
* When the animation completes, the item's state will change to
* NormalState
* StandardState
*/
InsertedState,
/**
@ -77,13 +77,24 @@ public:
* Items will remain in this state until it is explicitly changed
* via setCurrentState()
*/
NormalState,
StandardState,
/**
* State for an item which is being removed from a layout.
* State for an item which is currently being removed from a layout.
* When the animation completes, the item will be removed from the
* animator and its state will be undefined.
*/
RemovedState
RemovedState,
/**
* State for an item whoose geometry is not managed by the animator.
*
* All LayoutItems are initially in this state and are moved into a
* different state ( usually InsertedState ) by calling
* setCurrentState( item , state )
*
* An item transitions into this state when the animation completes
* whilst the item is in RemovedState
*/
DeadState
};
/**
@ -146,7 +157,8 @@ public:
/**
* Sets the new geometry for a layout item.
* The item will animate from its current geometry to @p geometry, using
* the effect specified in setEffect()
* the effect specified in setEffect() for the state currently associated
* with @p item
*/
virtual void setGeometry( LayoutItem* item , const QRectF& geometry );
@ -159,12 +171,29 @@ public:
/** Returns the QTimeLine used by this animator. */
QTimeLine* timeLine() const;
/**
* Convenience feature which causes LayoutItems and their associated
* QGraphicsItems to be automatically deleted when their removal
* animation finishes.
*
* The default is false.
*/
void setAutoDeleteOnRemoval(bool autoDelete);
/** See setAutoDeleteOnRemoval() */
bool autoDeleteOnRemoval() const;
Q_SIGNALS:
/** This signal is emitted when the state of an item in the animator changes. */
void stateChanged( LayoutItem *item , State oldState , State newState );
protected:
virtual void updateItem( qreal value , LayoutItem* item );
private slots:
void valueChanged(qreal value);
void animationCompleted();
void itemAutoDeleter( LayoutItem *item , State oldState , State newState );
private:
void moveEffectUpdateItem(qreal value,LayoutItem* item,Effect effect);
void noEffectUpdateItem(qreal value,LayoutItem* item);