add clipping support to AnimationEffect

REVIEW: 104898
This commit is contained in:
Thomas Lübking 2012-03-28 23:13:37 +02:00
parent ee53114054
commit 41a39a9928
3 changed files with 108 additions and 22 deletions

View file

@ -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) + ':' +

View file

@ -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;

View file

@ -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();