From 37b993d8ff3d45f6b115e51ed5feb60e7222fb4d Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Fri, 31 Aug 2007 15:19:02 +0000 Subject: [PATCH] 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 --- widgets/layoutanimator.cpp | 100 +++++++++++++++++++++++++++++++++---- widgets/layoutanimator.h | 43 +++++++++++++--- 2 files changed, 125 insertions(+), 18 deletions(-) diff --git a/widgets/layoutanimator.cpp b/widgets/layoutanimator.cpp index ee5ee4d4f..41d10ab40 100644 --- a/widgets/layoutanimator.cpp +++ b/widgets/layoutanimator.cpp @@ -46,10 +46,15 @@ public: QHash geometries; QHash states; - QPointer 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(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(item) != dynamic_cast(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); diff --git a/widgets/layoutanimator.h b/widgets/layoutanimator.h index 962e22bd3..15dd40c5a 100644 --- a/widgets/layoutanimator.h +++ b/widgets/layoutanimator.h @@ -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);