You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
10 KiB
219 lines
10 KiB
/******************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2011 Thomas Lübking <thomas.luebking@web.de> |
|
|
|
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, see <http://www.gnu.org/licenses/>. |
|
*********************************************************************/ |
|
|
|
#ifndef ANIMATION_EFFECT_H |
|
#define ANIMATION_EFFECT_H |
|
|
|
#include <QEasingCurve> |
|
#include <QElapsedTimer> |
|
#include <qmath.h> |
|
#include <kwineffects.h> |
|
|
|
|
|
namespace KWin |
|
{ |
|
|
|
class KWIN_EXPORT FPx2 { |
|
public: |
|
FPx2() { f[0] = f[1] = 0.0; valid = false; } |
|
explicit FPx2(float v) { f[0] = f[1] = v; valid = true; } |
|
FPx2(float v1, float v2) { f[0] = v1; f[1] = v2; valid = true; } |
|
FPx2(const FPx2 &other) { f[0] = other.f[0]; f[1] = other.f[1]; valid = other.valid; } |
|
explicit FPx2(const QPoint &other) { f[0] = other.x(); f[1] = other.y(); valid = true; } |
|
explicit FPx2(const QPointF &other) { f[0] = other.x(); f[1] = other.y(); valid = true; } |
|
explicit FPx2(const QSize &other) { f[0] = other.width(); f[1] = other.height(); valid = true; } |
|
explicit FPx2(const QSizeF &other) { f[0] = other.width(); f[1] = other.height(); valid = true; } |
|
inline void invalidate() { valid = false; } |
|
inline bool isValid() const { return valid; } |
|
inline float operator[](int n) const { return f[n]; } |
|
inline QString toString() const { |
|
QString ret; |
|
if (valid) |
|
ret = QString::number(f[0]) + QStringLiteral(",") + QString::number(f[1]); |
|
else |
|
ret = QString(); |
|
return ret; |
|
} |
|
|
|
|
|
inline FPx2 &operator+=(const FPx2 &other) |
|
{ f[0] += other[0]; f[1] += other[1]; return *this; } |
|
inline FPx2 &operator-=(const FPx2 &other) |
|
{ f[0] -= other[0]; f[1] -= other[1]; return *this; } |
|
inline FPx2 &operator*=(float fl) |
|
{ f[0] *= fl; f[1] *= fl; return *this; } |
|
inline FPx2 &operator/=(float fl) |
|
{ f[0] /= fl; f[1] /= fl; return *this; } |
|
|
|
friend inline bool operator==(const FPx2 &f1, const FPx2 &f2) |
|
{ return f1[0] == f2[0] && f1[1] == f2[1]; } |
|
friend inline bool operator!=(const FPx2 &f1, const FPx2 &f2) |
|
{ return f1[0] != f2[0] || f1[1] != f2[1]; } |
|
friend inline const FPx2 operator+(const FPx2 &f1, const FPx2 &f2) |
|
{ return FPx2( f1[0] + f2[0], f1[1] + f2[1] ); } |
|
friend inline const FPx2 operator-(const FPx2 &f1, const FPx2 &f2) |
|
{ return FPx2( f1[0] - f2[0], f1[1] - f2[1] ); } |
|
friend inline const FPx2 operator*(const FPx2 &f, float fl) |
|
{ return FPx2( f[0] * fl, f[1] * fl ); } |
|
friend inline const FPx2 operator*(float fl, const FPx2 &f) |
|
{ return FPx2( f[0] * fl, f[1] *fl ); } |
|
friend inline const FPx2 operator-(const FPx2 &f) |
|
{ return FPx2( -f[0], -f[1] ); } |
|
friend inline const FPx2 operator/(const FPx2 &f, float fl) |
|
{ return FPx2( f[0] / fl, f[1] / fl ); } |
|
|
|
inline void set(float v) { f[0] = v; valid = true; } |
|
inline void set(float v1, float v2) { f[0] = v1; f[1] = v2; valid = true; } |
|
|
|
private: |
|
float f[2]; |
|
bool valid; |
|
}; |
|
|
|
class AniData; |
|
class AnimationEffectPrivate; |
|
class KWIN_EXPORT AnimationEffect : public Effect |
|
{ |
|
Q_OBJECT |
|
Q_ENUMS(Anchor) |
|
Q_ENUMS(Attribute) |
|
Q_ENUMS(MetaType) |
|
public: |
|
enum Anchor { Left = 1<<0, Top = 1<<1, Right = 1<<2, Bottom = 1<<3, |
|
Horizontal = Left|Right, Vertical = Top|Bottom, Mouse = 1<<4 }; |
|
enum Attribute { |
|
Opacity = 0, Brightness, Saturation, Scale, Rotation, DecorationOpacity, |
|
Position, Size, Translation, Clip, Generic, CrossFadePrevious, |
|
NonFloatBase = Position |
|
}; |
|
enum MetaType { SourceAnchor, TargetAnchor, |
|
RelativeSourceX, RelativeSourceY, RelativeTargetX, RelativeTargetY, Axis }; |
|
/** |
|
* Whenever you intend to connect to the EffectsHandler::windowClosed() signal, do so when reimplementing the constructor. |
|
* Do *not* add private slots named _windowClosed( EffectWindow* w ) or _windowDeleted( EffectWindow* w ) !! |
|
* The AnimationEffect connects them right *after* the construction. |
|
* If you shadow the _windowDeleted slot (it doesn't matter that it's a private slot!), this will lead to segfaults. |
|
* If you shadow _windowClosed() or connect your slot to EffectsHandler::windowClosed() after _windowClosed() was connected, animations for closing windows will fail. |
|
*/ |
|
AnimationEffect(); |
|
|
|
bool isActive() const; |
|
/** |
|
* Set and get predefined metatypes. |
|
* The first 24 bits are reserved for the AnimationEffect class - you can use the last 8 bits for custom hints. |
|
* In case you transform a Generic attribute, all 32 bits are yours and you can use them as you want and read them in your genericAnimation() implementation. |
|
*/ |
|
static int metaData(MetaType type, uint meta ); |
|
static void setMetaData(MetaType type, uint value, uint &meta ); |
|
|
|
/** |
|
* Reimplemented from KWIn::Effect |
|
*/ |
|
QString debug(const QString ¶meter) const; |
|
virtual void prePaintScreen( ScreenPrePaintData& data, int time ); |
|
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ); |
|
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); |
|
virtual void postPaintScreen(); |
|
|
|
/** |
|
* Gaussian (bumper) animation curve for QEasingCurve |
|
*/ |
|
static qreal qecGaussian(qreal progress) |
|
{ |
|
progress = 2*progress - 1; |
|
progress *= -5*progress; |
|
return qExp(progress); |
|
} |
|
|
|
static inline qint64 clock() { |
|
return s_clock.elapsed(); |
|
} |
|
|
|
protected: |
|
/** |
|
* The central function of this class - call it to create an animated transition of any supported attribute |
|
* @param w - The EffectWindow to manipulate |
|
* @param a - The @enum Attribute to manipulate |
|
* @param meta - Basically a wildcard to carry various extra information, eg. the anchor, relativity or rotation axis. You will probably use require it when performing Generic animations. |
|
* @param ms - How long the transition will last |
|
* @param to - The target value. FPx2 is an agnostic two component float type (like QPointF or QSizeF, but without requiring to be either and supporting an invalid state) |
|
* @param shape - How the animation progresses, eg. Linear progresses constantly while Exponential start slow and becomes very fast in the end |
|
* @param delay - When the animation will start compared to "now" (the window will remain at the "from" position until then) |
|
* @param from - the starting value, the default is invalid, ie. the attribute for the window is not transformed in the beginning |
|
* @return an ID that you can use to cancel a running animation |
|
*/ |
|
quint64 animate( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve = QEasingCurve(), int delay = 0, FPx2 from = FPx2() ) |
|
{ return p_animate(w, a, meta, ms, to, curve, delay, from, false); } |
|
|
|
/** |
|
* Equal to ::animate() with one important difference: |
|
* The target value for the attribute is kept until you ::cancel() this animation |
|
* @return an ID that you need to use to cancel this manipulation |
|
*/ |
|
quint64 set( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve = QEasingCurve(), int delay = 0, FPx2 from = FPx2() ) |
|
{ return p_animate(w, a, meta, ms, to, curve, delay, from, true); } |
|
|
|
/** |
|
* 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 ) {Q_UNUSED(meta);} |
|
|
|
/** |
|
* Cancel a running animation. @return true if an animation for @p animationId was found (and canceled) |
|
* NOTICE that there is NO animated reset of the original value. You'll have to provide that with a second animation |
|
* NOTICE as well that this will eventually release a Deleted window. |
|
* If you intend to run another animation on the (Deleted) window, you have to do that before cancelling the old animation (to keep the window around) |
|
*/ |
|
bool cancel(quint64 animationId); |
|
/** |
|
* 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 |
|
*/ |
|
virtual void genericAnimation( EffectWindow *w, WindowPaintData &data, float progress, uint meta ) |
|
{Q_UNUSED(w); Q_UNUSED(data); Q_UNUSED(progress); Q_UNUSED(meta);} |
|
|
|
private: |
|
quint64 p_animate( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve, int delay, FPx2 from, bool keepAtTarget ); |
|
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 disconnectGeometryChanges(); |
|
void updateLayerRepaints(); |
|
private Q_SLOTS: |
|
void init(); |
|
void triggerRepaint(); |
|
void _windowClosed( KWin::EffectWindow* w ); |
|
void _windowDeleted( KWin::EffectWindow* w ); |
|
void _expandedGeometryChanged(KWin::EffectWindow *w, const QRect &old); |
|
private: |
|
static QElapsedTimer s_clock; |
|
typedef QMap< EffectWindow*, QPair<QList<AniData>, QRect> > AniMap; |
|
AnimationEffectPrivate * const d_ptr; |
|
Q_DECLARE_PRIVATE(AnimationEffect) |
|
}; |
|
|
|
|
|
} // namespace |
|
QDebug operator<<(QDebug dbg, const KWin::FPx2 &fpx2); |
|
Q_DECLARE_METATYPE(KWin::FPx2) |
|
|
|
#endif // ANIMATION_EFFECT_H
|
|
|