Add LayoutAnimator class. This provides a way to animate changes in layouts. eg. Fading in new items, fading out removed items, moving and resizing items smoothly as the layout changes. The layouts themselves need some small changes to make use of this class, and the client code must create the animator, attach it to the layout and choose the animation effects to use.
svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=700844
This commit is contained in:
parent
cee77d79d9
commit
2475cfed09
@ -34,10 +34,12 @@ set(plasma_LIB_SRCS
|
||||
widgets/boxlayout.cpp
|
||||
widgets/checkbox.cpp
|
||||
widgets/hboxlayout.cpp
|
||||
# widgets/flowlayout.cpp
|
||||
widgets/flash.cpp
|
||||
widgets/icon.cpp
|
||||
widgets/label.cpp
|
||||
widgets/layout.cpp
|
||||
widgets/layoutanimator.cpp
|
||||
widgets/layoutitem.cpp
|
||||
widgets/lineedit.cpp
|
||||
widgets/pushbutton.cpp
|
||||
|
233
widgets/layoutanimator.cpp
Normal file
233
widgets/layoutanimator.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "layoutanimator.h"
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtCore/QTimeLine>
|
||||
#include <QtGui/QGraphicsItem>
|
||||
#include <QtGui/QGraphicsScene>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "layout.h"
|
||||
#include "widget.h"
|
||||
|
||||
using namespace Plasma;
|
||||
|
||||
class LayoutAnimator::Private
|
||||
{
|
||||
public:
|
||||
QHash<LayoutAnimator::State,int> effects;
|
||||
|
||||
class ItemGeometry
|
||||
{
|
||||
public:
|
||||
QRectF startGeometry;
|
||||
QRectF endGeometry;
|
||||
};
|
||||
|
||||
QHash<LayoutItem*,ItemGeometry> geometries;
|
||||
QHash<LayoutItem*,LayoutAnimator::State> states;
|
||||
|
||||
QPointer<QTimeLine> timeLine;
|
||||
|
||||
qreal lastValue;
|
||||
|
||||
qreal delta(qreal currentValue) const
|
||||
{
|
||||
if ( currentValue > lastValue )
|
||||
return currentValue - lastValue;
|
||||
else
|
||||
return (1.0-lastValue) + currentValue;
|
||||
}
|
||||
|
||||
QRectF interpolateGeometry(LayoutItem* item,qreal value) const
|
||||
{
|
||||
QRectF newGeometry;
|
||||
|
||||
const QRectF& current = geometries[item].startGeometry;
|
||||
const QRectF& next = geometries[item].endGeometry;
|
||||
|
||||
newGeometry.setLeft(current.left() + (next.left()-current.left()) * value);
|
||||
newGeometry.setRight(current.right() + (next.right()-current.right()) * value);
|
||||
newGeometry.setTop(current.top() + (next.top()-current.top()) * value);
|
||||
newGeometry.setBottom(current.bottom() + (next.bottom()-current.bottom()) * value);
|
||||
|
||||
return newGeometry;
|
||||
}
|
||||
};
|
||||
|
||||
LayoutAnimator::LayoutAnimator(QObject* parent)
|
||||
: QObject(parent),
|
||||
d(new Private)
|
||||
{
|
||||
d->lastValue = 0;
|
||||
}
|
||||
|
||||
LayoutAnimator::~LayoutAnimator()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void LayoutAnimator::setEffect( State action , int effect )
|
||||
{
|
||||
d->effects[action] = effect;
|
||||
}
|
||||
int LayoutAnimator::effect(State action) const
|
||||
{
|
||||
return d->effects[action];
|
||||
}
|
||||
|
||||
void LayoutAnimator::setCurrentState( LayoutItem* item , State action )
|
||||
{
|
||||
d->states[item] = action;
|
||||
}
|
||||
LayoutAnimator::State LayoutAnimator::state( LayoutItem* item ) const
|
||||
{
|
||||
return d->states[item];
|
||||
}
|
||||
|
||||
void LayoutAnimator::setTimeLine(QTimeLine* timeLine)
|
||||
{
|
||||
if ( d->timeLine ) {
|
||||
disconnect( d->timeLine , SIGNAL(valueChanged(qreal)) , this ,
|
||||
SLOT(valueChanged(qreal)) );
|
||||
disconnect( d->timeLine , SIGNAL(finished()) , this ,
|
||||
SLOT(animationCompleted()) );
|
||||
}
|
||||
|
||||
d->timeLine = timeLine;
|
||||
|
||||
connect( d->timeLine , SIGNAL(valueChanged(qreal)) , this ,
|
||||
SLOT(valueChanged(qreal)) );
|
||||
connect( d->timeLine , SIGNAL(finished()) , this ,
|
||||
SLOT(animationCompleted()) );
|
||||
}
|
||||
QTimeLine* LayoutAnimator::timeLine() const
|
||||
{
|
||||
return d->timeLine;
|
||||
}
|
||||
void LayoutAnimator::valueChanged(qreal value)
|
||||
{
|
||||
foreach( LayoutItem* item , d->geometries.keys() ) {
|
||||
updateItem(value,item);
|
||||
}
|
||||
|
||||
d->lastValue = value;
|
||||
}
|
||||
|
||||
void LayoutAnimator::setGeometry( LayoutItem* item , const QRectF& destGeometry )
|
||||
{
|
||||
Q_ASSERT( item );
|
||||
|
||||
Private::ItemGeometry& itemGeometry = d->geometries[item];
|
||||
|
||||
itemGeometry.startGeometry = item->geometry();
|
||||
itemGeometry.endGeometry = destGeometry;
|
||||
}
|
||||
|
||||
void LayoutAnimator::moveEffectUpdateItem( qreal value , LayoutItem* item , Effect effect )
|
||||
{
|
||||
Widget* widget = dynamic_cast<Widget*>(item->graphicsItem());
|
||||
|
||||
if ( widget && effect == FadeInMoveEffect )
|
||||
widget->setOpacity( qMin(1.0,widget->opacity()+d->delta(value)) );
|
||||
else if ( widget && effect == FadeOutMoveEffect )
|
||||
widget->setOpacity( qMax(0.0,widget->opacity()-d->delta(value)) );
|
||||
|
||||
item->setGeometry( d->interpolateGeometry(item,value) );
|
||||
}
|
||||
|
||||
void LayoutAnimator::noEffectUpdateItem( qreal , LayoutItem* item )
|
||||
{
|
||||
item->setGeometry( d->geometries[item].endGeometry );
|
||||
}
|
||||
|
||||
void LayoutAnimator::fadeEffectUpdateItem( qreal value , LayoutItem* item )
|
||||
{
|
||||
Widget* widget = dynamic_cast<Widget*>(item->graphicsItem());
|
||||
|
||||
qreal threshold = 0;
|
||||
|
||||
if ( widget != 0 && d->geometries[item].startGeometry != d->geometries[item].endGeometry ) {
|
||||
widget->setOpacity( qAbs( (value*2)-1.0 ) );
|
||||
threshold = 0.5;
|
||||
}
|
||||
|
||||
QRectF newGeometry;
|
||||
|
||||
if ( value < threshold )
|
||||
newGeometry = d->geometries[item].startGeometry;
|
||||
else
|
||||
newGeometry = d->geometries[item].endGeometry;
|
||||
|
||||
item->setGeometry(newGeometry);
|
||||
}
|
||||
|
||||
void LayoutAnimator::animationFinished(LayoutItem* item)
|
||||
{
|
||||
switch (d->states[item])
|
||||
{
|
||||
case InsertedState:
|
||||
d->states[item] = NormalState;
|
||||
break;
|
||||
case RemovedState:
|
||||
d->states.remove(item);
|
||||
d->geometries.remove(item);
|
||||
break;
|
||||
case NormalState:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutAnimator::updateItem( qreal value , LayoutItem* item )
|
||||
{
|
||||
Q_ASSERT( value >= 0 && value <= 1.0 );
|
||||
Q_ASSERT( item );
|
||||
Q_ASSERT( d->geometries.contains(item) );
|
||||
|
||||
switch ( effect(d->states[item]) )
|
||||
{
|
||||
case NoEffect:
|
||||
noEffectUpdateItem(value,item);
|
||||
break;
|
||||
case MoveEffect:
|
||||
moveEffectUpdateItem(value,item,MoveEffect);
|
||||
break;
|
||||
case FadeInMoveEffect:
|
||||
moveEffectUpdateItem(value,item,FadeInMoveEffect);
|
||||
break;
|
||||
case FadeOutMoveEffect:
|
||||
moveEffectUpdateItem(value,item,FadeOutMoveEffect);
|
||||
break;
|
||||
case FadeEffect:
|
||||
fadeEffectUpdateItem(value,item);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
#include "layoutanimator.moc"
|
||||
|
184
widgets/layoutanimator.h
Normal file
184
widgets/layoutanimator.h
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __LAYOUTANIMATOR__
|
||||
#define __LAYOUTANIMATOR__
|
||||
|
||||
#include <QtCore/QRectF>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <plasma/plasma_export.h>
|
||||
|
||||
class QTimeLine;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class Layout;
|
||||
class LayoutItem;
|
||||
|
||||
/**
|
||||
* LayoutAnimator can be used to animate changes
|
||||
* in Layouts.
|
||||
*
|
||||
* @code
|
||||
*
|
||||
* LayoutAnimator* animator = new LayoutAnimator;
|
||||
* QTimeLine* timeLine = new QTimeLine;
|
||||
*
|
||||
* animator->setTimeLine(timeLine);
|
||||
* animator->setEffect( LayoutAnimator::InsertedState , LayoutAnimator::FadeInMoveEffect );
|
||||
* animator->setEffect( LayoutAnimator::NormalState , LayoutAnimator::MoveEffect );
|
||||
* animator->setEffect( LayoutAnimator::RemovedState , LayoutAnimator::FadeOutMoveEffect );
|
||||
* myLayout->setAnimator(animator);
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
class PLASMA_EXPORT LayoutAnimator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructs a new layout animator with the specified parent. */
|
||||
explicit LayoutAnimator(QObject* parent = 0);
|
||||
~LayoutAnimator();
|
||||
|
||||
/**
|
||||
* This enum describes the possible states which a layout item may be in.
|
||||
* Different effects can be defined for items which are being inserted,
|
||||
* moved or resized or removed from layouts.
|
||||
*/
|
||||
enum State
|
||||
{
|
||||
/**
|
||||
* State for an item which has recently been added to a layout.
|
||||
* When the animation completes, the item's state will change to
|
||||
* NormalState
|
||||
*/
|
||||
InsertedState,
|
||||
/**
|
||||
* Normal state for items in the layout.
|
||||
* Items will remain in this state until it is explicitly changed
|
||||
* via setCurrentState()
|
||||
*/
|
||||
NormalState,
|
||||
/**
|
||||
* State for an item which is being removed from a layout.
|
||||
* When the animation completes, the item will be removed from the
|
||||
* animator and its state will be undefined.
|
||||
*/
|
||||
RemovedState
|
||||
};
|
||||
|
||||
/**
|
||||
* This enum describes the available effects which can be used
|
||||
* to animate changes in a layout.
|
||||
*/
|
||||
enum Effect
|
||||
{
|
||||
/**
|
||||
* No effect. When the animation begins, the item immediately appears
|
||||
* in its final position and size.
|
||||
*/
|
||||
NoEffect,
|
||||
/**
|
||||
* The item is smoothly moved and resized from its initial geometry to its final
|
||||
* geometry as the animation progresses.
|
||||
*/
|
||||
MoveEffect,
|
||||
/**
|
||||
* The item fades out during the first half of the animation in its initial geometry
|
||||
* and then fades in at its final position and size during the second half of
|
||||
* the animation.
|
||||
*/
|
||||
FadeEffect,
|
||||
/**
|
||||
* The item is initially invisible and fades in whilst moving and resizing to
|
||||
* its final position as the animation progresses.
|
||||
*/
|
||||
FadeInMoveEffect,
|
||||
/**
|
||||
* The item is initially fully opqaue and fades out whilst moving and resizing
|
||||
* to its final position as the animation progresses.
|
||||
*/
|
||||
FadeOutMoveEffect
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the @p effect for items in the layout which are under-going a change
|
||||
* specified by @p action.
|
||||
*
|
||||
* This allows different effects to be defined for items which are being added to,
|
||||
* removed from, or repositioned inside layouts.
|
||||
*/
|
||||
void setEffect( State state , int effect );
|
||||
/** See setEffect() */
|
||||
int effect( State state ) const;
|
||||
|
||||
/**
|
||||
* Sets the current action for a particular layout item. The Layout class
|
||||
* should call this before changing an item so that the animator can apply the correct
|
||||
* animation.
|
||||
*
|
||||
* When the current animation completes, depending on the current @p state, the item
|
||||
* may advance into a new state.
|
||||
*/
|
||||
void setCurrentState( LayoutItem* item , State state );
|
||||
/** See setCurrentState() */
|
||||
State state( LayoutItem* item ) const;
|
||||
|
||||
/**
|
||||
* 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()
|
||||
*/
|
||||
virtual void setGeometry( LayoutItem* item , const QRectF& geometry );
|
||||
|
||||
/**
|
||||
* Sets the time line used by this animator.
|
||||
*
|
||||
* The duration of the animation can be changed by altering @p timeLine 's duration
|
||||
*/
|
||||
void setTimeLine( QTimeLine* timeLine );
|
||||
/** Returns the QTimeLine used by this animator. */
|
||||
QTimeLine* timeLine() const;
|
||||
|
||||
protected:
|
||||
virtual void updateItem( qreal value , LayoutItem* item );
|
||||
|
||||
private slots:
|
||||
void valueChanged(qreal value);
|
||||
|
||||
private:
|
||||
void moveEffectUpdateItem(qreal value,LayoutItem* item,Effect effect);
|
||||
void noEffectUpdateItem(qreal value,LayoutItem* item);
|
||||
void fadeEffectUpdateItem(qreal value,LayoutItem* item);
|
||||
|
||||
void animationFinished(LayoutItem* item);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __LAYOUTANIMATOR__
|
||||
|
@ -89,6 +89,10 @@ void Widget::setOpacity(qreal opacity)
|
||||
{
|
||||
d->opacity = opacity;
|
||||
}
|
||||
qreal Widget::opacity() const
|
||||
{
|
||||
return d->opacity;
|
||||
}
|
||||
|
||||
Qt::Orientations Widget::expandingDirections() const
|
||||
{
|
||||
@ -188,6 +192,9 @@ QSizeF Widget::sizeHint() const
|
||||
|
||||
void Widget::setSize(const QSizeF &newSize)
|
||||
{
|
||||
if ( newSize != d->size )
|
||||
return;
|
||||
|
||||
prepareGeometryChange();
|
||||
qreal width = qBound(d->minimumSize.width(), newSize.width(), d->maximumSize.width());
|
||||
qreal height = qBound(d->minimumSize.height(), newSize.height(), d->maximumSize.height());
|
||||
|
@ -219,6 +219,7 @@ public:
|
||||
Q_INVOKABLE void addChild(Widget *widget);
|
||||
|
||||
void setOpacity(qreal opacity);
|
||||
qreal opacity() const;
|
||||
|
||||
virtual QGraphicsItem* graphicsItem();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user