diff --git a/libkwineffects/anidata.cpp b/libkwineffects/anidata.cpp index 325e924d7a..3bb970f550 100644 --- a/libkwineffects/anidata.cpp +++ b/libkwineffects/anidata.cpp @@ -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) == "Position") attribute = AnimationEffect::Position; else if (animation.at(1) == "Size") attribute = AnimationEffect::Size; + else if (animation.at(1) == "Clip") attribute = AnimationEffect::Clip; else { kDebug(1212) << "Invalid attribute" << animation.at(1); return; @@ -178,6 +179,7 @@ QString AniData::toString() const case AnimationEffect::Rotation: ret += "Rotation:"; break; case AnimationEffect::Position: ret += "Position:"; break; case AnimationEffect::Size: ret += "Size:"; break; + case AnimationEffect::Clip: ret += "Clip:"; break; default: ret += ':'; } ret += QString::number(meta) + ':' + QString::number(duration) + ':' + diff --git a/libkwineffects/kwinanimationeffect.cpp b/libkwineffects/kwinanimationeffect.cpp index 347361a6c6..4ef79e43ac 100644 --- a/libkwineffects/kwinanimationeffect.cpp +++ b/libkwineffects/kwinanimationeffect.cpp @@ -158,6 +158,15 @@ void AnimationEffect::animate( EffectWindow *w, Attribute a, uint meta, int ms, } else { 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); @@ -246,6 +255,89 @@ void AnimationEffect::prePaintScreen( ScreenPrePaintData& data, int 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 ) { Q_D(AnimationEffect); @@ -263,6 +355,8 @@ void AnimationEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, else if (!(anim->attribute == Brightness || anim->attribute == Saturation)) { data.setTransformed(); data.mask |= PAINT_WINDOW_TRANSFORMED; + if (anim->attribute == Clip) + clipWindow(w, *anim, data.quads); } } if ( isUsed ) { @@ -289,25 +383,6 @@ static inline float geometryCompensation(int flags, float v) 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 ) { Q_D(AnimationEffect); @@ -339,13 +414,17 @@ void AnimationEffect::paintWindow( EffectWindow* w, int mask, QRegion region, Wi if (!anim->isOneDimensional()) { f1 = interpolated(*anim, 1); 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 ); data.yTranslate += f2 * sz.height(); data.yScale *= f1; } break; } + case Clip: + region = clipRect(w->expandedGeometry(), *anim); + break; case Translation: data.xTranslate += interpolated(*anim, 0); 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]); break; } + case Clip: + createRegion = true; + break; case Size: case Scale: { createRegion = true; diff --git a/libkwineffects/kwinanimationeffect.h b/libkwineffects/kwinanimationeffect.h index e31110dae8..2ffaa22184 100644 --- a/libkwineffects/kwinanimationeffect.h +++ b/libkwineffects/kwinanimationeffect.h @@ -98,7 +98,7 @@ public: Horizontal = Left|Right, Vertical = Top|Bottom, Mouse = 1<<4 }; enum Attribute { Opacity = 0, Brightness, Saturation, Scale, Rotation, - Position, Size, Translation, Generic, + Position, Size, Translation, Clip, Generic, NonFloatBase = Position }; 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 * 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". * 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);} 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 progress( const AniData& ) const; void updateLayerRepaints();