add clipping support to AnimationEffect
REVIEW: 104898
This commit is contained in:
parent
ee53114054
commit
41a39a9928
3 changed files with 108 additions and 22 deletions
|
@ -111,6 +111,7 @@ AniData::AniData(const QString &str) // format: WindowMask:Attribute:Meta:Durati
|
||||||
else if (animation.at(1) == "Rotation") attribute = AnimationEffect::Rotation;
|
else if (animation.at(1) == "Rotation") attribute = AnimationEffect::Rotation;
|
||||||
else if (animation.at(1) == "Position") attribute = AnimationEffect::Position;
|
else if (animation.at(1) == "Position") attribute = AnimationEffect::Position;
|
||||||
else if (animation.at(1) == "Size") attribute = AnimationEffect::Size;
|
else if (animation.at(1) == "Size") attribute = AnimationEffect::Size;
|
||||||
|
else if (animation.at(1) == "Clip") attribute = AnimationEffect::Clip;
|
||||||
else {
|
else {
|
||||||
kDebug(1212) << "Invalid attribute" << animation.at(1);
|
kDebug(1212) << "Invalid attribute" << animation.at(1);
|
||||||
return;
|
return;
|
||||||
|
@ -178,6 +179,7 @@ QString AniData::toString() const
|
||||||
case AnimationEffect::Rotation: ret += "Rotation:"; break;
|
case AnimationEffect::Rotation: ret += "Rotation:"; break;
|
||||||
case AnimationEffect::Position: ret += "Position:"; break;
|
case AnimationEffect::Position: ret += "Position:"; break;
|
||||||
case AnimationEffect::Size: ret += "Size:"; break;
|
case AnimationEffect::Size: ret += "Size:"; break;
|
||||||
|
case AnimationEffect::Clip: ret += "Clip:"; break;
|
||||||
default: ret += ':';
|
default: ret += ':';
|
||||||
}
|
}
|
||||||
ret += QString::number(meta) + ':' + QString::number(duration) + ':' +
|
ret += QString::number(meta) + ':' + QString::number(duration) + ':' +
|
||||||
|
|
|
@ -158,6 +158,15 @@ void AnimationEffect::animate( EffectWindow *w, Attribute a, uint meta, int ms,
|
||||||
} else {
|
} else {
|
||||||
to.set(0.0, 0.0);
|
to.set(0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
} else if (a == Clip) {
|
||||||
|
if (!from.isValid()) {
|
||||||
|
from.set(1.0,1.0);
|
||||||
|
setMetaData( SourceAnchor, metaData(TargetAnchor, meta), meta );
|
||||||
|
}
|
||||||
|
if (!to.isValid()) {
|
||||||
|
to.set(1.0,1.0);
|
||||||
|
setMetaData( TargetAnchor, metaData(SourceAnchor, meta), meta );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_D(AnimationEffect);
|
Q_D(AnimationEffect);
|
||||||
|
@ -246,6 +255,89 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
||||||
effects->prePaintScreen(data, time);
|
effects->prePaintScreen(data, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xCoord(const QRect &r, int flag) {
|
||||||
|
if (flag & AnimationEffect::Left)
|
||||||
|
return r.x();
|
||||||
|
else if (flag & AnimationEffect::Right)
|
||||||
|
return r.right();
|
||||||
|
else
|
||||||
|
return r.x() + r.width()/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yCoord(const QRect &r, int flag) {
|
||||||
|
if (flag & AnimationEffect::Top)
|
||||||
|
return r.y();
|
||||||
|
else if (flag & AnimationEffect::Bottom)
|
||||||
|
return r.bottom();
|
||||||
|
else
|
||||||
|
return r.y() + r.height()/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect AnimationEffect::clipRect(const QRect &geo, const AniData &anim) const
|
||||||
|
{
|
||||||
|
QRect clip = geo;
|
||||||
|
FPx2 ratio = anim.from + progress(anim) * (anim.to - anim.from);
|
||||||
|
if (anim.from[0] < 1.0 || anim.to[0] < 1.0) {
|
||||||
|
clip.setWidth(clip.width() * ratio[0]);
|
||||||
|
}
|
||||||
|
if (anim.from[1] < 1.0 || anim.to[1] < 1.0) {
|
||||||
|
clip.setHeight(clip.height() * ratio[1]);
|
||||||
|
}
|
||||||
|
const QRect center = geo.adjusted(clip.width()/2, clip.height()/2,
|
||||||
|
-(clip.width()+1)/2, -(clip.height()+1)/2 );
|
||||||
|
const int x[2] = { xCoord(center, metaData(SourceAnchor, anim.meta)),
|
||||||
|
xCoord(center, metaData(TargetAnchor, anim.meta)) };
|
||||||
|
const int y[2] = { yCoord(center, metaData(SourceAnchor, anim.meta)),
|
||||||
|
yCoord(center, metaData(TargetAnchor, anim.meta)) };
|
||||||
|
const QPoint d(x[0] + ratio[0]*(x[1]-x[0]), y[0] + ratio[1]*(y[1]-y[0]));
|
||||||
|
clip.moveTopLeft(QPoint(d.x() - clip.width()/2, d.y() - clip.height()/2));
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationEffect::clipWindow(const EffectWindow *w, const AniData &anim, WindowQuadList &quads) const
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
const QRect geo = w->expandedGeometry();
|
||||||
|
QRect clip = AnimationEffect::clipRect(geo, anim);
|
||||||
|
WindowQuadList filtered;
|
||||||
|
if (clip.left() != geo.left()) {
|
||||||
|
quads = quads.splitAtX(clip.left());
|
||||||
|
foreach (const WindowQuad &quad, quads) {
|
||||||
|
if (quad.right() >= clip.left())
|
||||||
|
filtered << quad;
|
||||||
|
}
|
||||||
|
quads = filtered;
|
||||||
|
filtered.clear();
|
||||||
|
}
|
||||||
|
if (clip.right() != geo.right()) {
|
||||||
|
quads = quads.splitAtX(clip.left());
|
||||||
|
foreach (const WindowQuad &quad, quads) {
|
||||||
|
if (quad.right() <= clip.right())
|
||||||
|
filtered << quad;
|
||||||
|
}
|
||||||
|
quads = filtered;
|
||||||
|
filtered.clear();
|
||||||
|
}
|
||||||
|
if (clip.top() != geo.top()) {
|
||||||
|
quads = quads.splitAtY(clip.top());
|
||||||
|
foreach (const WindowQuad &quad, quads) {
|
||||||
|
if (quad.top() >= clip.top())
|
||||||
|
filtered << quad;
|
||||||
|
}
|
||||||
|
quads = filtered;
|
||||||
|
filtered.clear();
|
||||||
|
}
|
||||||
|
if (clip.bottom() != geo.bottom()) {
|
||||||
|
quads = quads.splitAtY(clip.bottom());
|
||||||
|
foreach (const WindowQuad &quad, quads) {
|
||||||
|
if (quad.bottom() <= clip.bottom())
|
||||||
|
filtered << quad;
|
||||||
|
}
|
||||||
|
quads = filtered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
||||||
{
|
{
|
||||||
Q_D(AnimationEffect);
|
Q_D(AnimationEffect);
|
||||||
|
@ -263,6 +355,8 @@ void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data,
|
||||||
else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) {
|
else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) {
|
||||||
data.setTransformed();
|
data.setTransformed();
|
||||||
data.mask |= PAINT_WINDOW_TRANSFORMED;
|
data.mask |= PAINT_WINDOW_TRANSFORMED;
|
||||||
|
if (anim->attribute == Clip)
|
||||||
|
clipWindow(w, *anim, data.quads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( isUsed ) {
|
if ( isUsed ) {
|
||||||
|
@ -289,25 +383,6 @@ static inline float geometryCompensation(int flags, float v)
|
||||||
return 0.5 * (1.0 - v); // half compensation
|
return 0.5 * (1.0 - v); // half compensation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int xCoord(const QRect &r, int flag) {
|
|
||||||
if (flag & AnimationEffect::Left)
|
|
||||||
return r.x();
|
|
||||||
else if (flag & AnimationEffect::Right)
|
|
||||||
return r.right();
|
|
||||||
else
|
|
||||||
return r.x() + r.width()/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int yCoord(const QRect &r, int flag) {
|
|
||||||
if (flag & AnimationEffect::Top)
|
|
||||||
return r.y();
|
|
||||||
else if (flag & AnimationEffect::Bottom)
|
|
||||||
return r.bottom();
|
|
||||||
else
|
|
||||||
return r.y() + r.height()/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
void AnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||||
{
|
{
|
||||||
Q_D(AnimationEffect);
|
Q_D(AnimationEffect);
|
||||||
|
@ -339,13 +414,17 @@ void AnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Wi
|
||||||
if (!anim->isOneDimensional()) {
|
if (!anim->isOneDimensional()) {
|
||||||
f1 = interpolated(*anim, 1);
|
f1 = interpolated(*anim, 1);
|
||||||
f2 = geometryCompensation( anim->meta & AnimationEffect::Vertical, f1 );
|
f2 = geometryCompensation( anim->meta & AnimationEffect::Vertical, f1 );
|
||||||
} else if ( ((anim->meta & AnimationEffect::Vertical)>>1) != (anim->meta & AnimationEffect::Horizontal) )
|
}
|
||||||
|
else if ( ((anim->meta & AnimationEffect::Vertical)>>1) != (anim->meta & AnimationEffect::Horizontal) )
|
||||||
f2 = geometryCompensation( anim->meta & AnimationEffect::Vertical, f1 );
|
f2 = geometryCompensation( anim->meta & AnimationEffect::Vertical, f1 );
|
||||||
data.yTranslate += f2 * sz.height();
|
data.yTranslate += f2 * sz.height();
|
||||||
data.yScale *= f1;
|
data.yScale *= f1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Clip:
|
||||||
|
region = clipRect(w->expandedGeometry(), *anim);
|
||||||
|
break;
|
||||||
case Translation:
|
case Translation:
|
||||||
data.xTranslate += interpolated(*anim, 0);
|
data.xTranslate += interpolated(*anim, 0);
|
||||||
data.yTranslate += interpolated(*anim, 1);
|
data.yTranslate += interpolated(*anim, 1);
|
||||||
|
@ -595,6 +674,9 @@ void AnimationEffect::updateLayerRepaints()
|
||||||
rects << r.translated(x[0], y[0]) << r.translated(x[1], y[1]);
|
rects << r.translated(x[0], y[0]) << r.translated(x[1], y[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Clip:
|
||||||
|
createRegion = true;
|
||||||
|
break;
|
||||||
case Size:
|
case Size:
|
||||||
case Scale: {
|
case Scale: {
|
||||||
createRegion = true;
|
createRegion = true;
|
||||||
|
|
|
@ -98,7 +98,7 @@ public:
|
||||||
Horizontal = Left|Right, Vertical = Top|Bottom, Mouse = 1<<4 };
|
Horizontal = Left|Right, Vertical = Top|Bottom, Mouse = 1<<4 };
|
||||||
enum Attribute {
|
enum Attribute {
|
||||||
Opacity = 0, Brightness, Saturation, Scale, Rotation,
|
Opacity = 0, Brightness, Saturation, Scale, Rotation,
|
||||||
Position, Size, Translation, Generic,
|
Position, Size, Translation, Clip, Generic,
|
||||||
NonFloatBase = Position
|
NonFloatBase = Position
|
||||||
};
|
};
|
||||||
enum MetaType { SourceAnchor, TargetAnchor,
|
enum MetaType { SourceAnchor, TargetAnchor,
|
||||||
|
@ -156,7 +156,7 @@ protected:
|
||||||
* Called whenever an animation end, passes the transformed @class EffectWindow @enum Attribute and originally supplied @param meta
|
* Called whenever an animation end, passes the transformed @class EffectWindow @enum Attribute and originally supplied @param meta
|
||||||
* You can reimplement it to keep a constant transformation for the window (ie. keep it a this opacity or position) or to start another animation
|
* You can reimplement it to keep a constant transformation for the window (ie. keep it a this opacity or position) or to start another animation
|
||||||
*/
|
*/
|
||||||
virtual void animationEnded( EffectWindow *, Attribute, uint meta ) {}
|
virtual void animationEnded( EffectWindow *, Attribute, uint meta ) {Q_UNUSED(meta);}
|
||||||
/**
|
/**
|
||||||
* Called if the transformed @enum Attribute is Generic. You should reimplement it if you transform this "Attribute".
|
* Called if the transformed @enum Attribute is Generic. You should reimplement it if you transform this "Attribute".
|
||||||
* You could use the meta information to eg. support more than one additional animations
|
* You could use the meta information to eg. support more than one additional animations
|
||||||
|
@ -165,6 +165,8 @@ protected:
|
||||||
{Q_UNUSED(w); Q_UNUSED(data); Q_UNUSED(progress); Q_UNUSED(meta);}
|
{Q_UNUSED(w); Q_UNUSED(data); Q_UNUSED(progress); Q_UNUSED(meta);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QRect clipRect(const QRect &windowRect, const AniData&) const;
|
||||||
|
void clipWindow(const EffectWindow *, const AniData &, WindowQuadList &) const;
|
||||||
float interpolated( const AniData&, int i = 0 ) const;
|
float interpolated( const AniData&, int i = 0 ) const;
|
||||||
float progress( const AniData& ) const;
|
float progress( const AniData& ) const;
|
||||||
void updateLayerRepaints();
|
void updateLayerRepaints();
|
||||||
|
|
Loading…
Reference in a new issue