Move window motion manager to the slideback effect
Slide back is the only remaining its user.
This commit is contained in:
parent
b0292fc0de
commit
96e979c736
6 changed files with 649 additions and 623 deletions
|
@ -2412,276 +2412,6 @@ void RenderGeometry::postProcessTextureCoordinates(const QMatrix4x4 &textureMatr
|
|||
}
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Motion1D
|
||||
***************************************************************/
|
||||
|
||||
Motion1D::Motion1D(double initial, double strength, double smoothness)
|
||||
: Motion<double>(initial, strength, smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
Motion1D::Motion1D(const Motion1D &other)
|
||||
: Motion<double>(other)
|
||||
{
|
||||
}
|
||||
|
||||
Motion1D::~Motion1D()
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Motion2D
|
||||
***************************************************************/
|
||||
|
||||
Motion2D::Motion2D(QPointF initial, double strength, double smoothness)
|
||||
: Motion<QPointF>(initial, strength, smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
Motion2D::Motion2D(const Motion2D &other)
|
||||
: Motion<QPointF>(other)
|
||||
{
|
||||
}
|
||||
|
||||
Motion2D::~Motion2D()
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
WindowMotionManager
|
||||
***************************************************************/
|
||||
|
||||
WindowMotionManager::WindowMotionManager(bool useGlobalAnimationModifier)
|
||||
: m_useGlobalAnimationModifier(useGlobalAnimationModifier)
|
||||
|
||||
{
|
||||
// TODO: Allow developer to modify motion attributes
|
||||
} // TODO: What happens when the window moves by an external force?
|
||||
|
||||
WindowMotionManager::~WindowMotionManager()
|
||||
{
|
||||
}
|
||||
|
||||
void WindowMotionManager::manage(EffectWindow *w)
|
||||
{
|
||||
if (m_managedWindows.contains(w)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double strength = 0.08;
|
||||
double smoothness = 4.0;
|
||||
if (m_useGlobalAnimationModifier && effects->animationTimeFactor()) {
|
||||
// If the factor is == 0 then we just skip the calculation completely
|
||||
strength = 0.08 / effects->animationTimeFactor();
|
||||
smoothness = effects->animationTimeFactor() * 4.0;
|
||||
}
|
||||
|
||||
WindowMotion &motion = m_managedWindows[w];
|
||||
motion.translation.setStrength(strength);
|
||||
motion.translation.setSmoothness(smoothness);
|
||||
motion.scale.setStrength(strength * 1.33);
|
||||
motion.scale.setSmoothness(smoothness / 2.0);
|
||||
|
||||
motion.translation.setValue(w->pos());
|
||||
motion.scale.setValue(QPointF(1.0, 1.0));
|
||||
}
|
||||
|
||||
void WindowMotionManager::unmanage(EffectWindow *w)
|
||||
{
|
||||
m_movingWindowsSet.remove(w);
|
||||
m_managedWindows.remove(w);
|
||||
}
|
||||
|
||||
void WindowMotionManager::unmanageAll()
|
||||
{
|
||||
m_managedWindows.clear();
|
||||
m_movingWindowsSet.clear();
|
||||
}
|
||||
|
||||
void WindowMotionManager::calculate(int time)
|
||||
{
|
||||
if (!effects->animationTimeFactor()) {
|
||||
// Just skip it completely if the user wants no animation
|
||||
m_movingWindowsSet.clear();
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.finish();
|
||||
motion->scale.finish();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
int stopped = 0;
|
||||
|
||||
// TODO: What happens when distance() == 0 but we are still moving fast?
|
||||
// TODO: Motion needs to be calculated from the window's center
|
||||
|
||||
Motion2D *trans = &motion->translation;
|
||||
if (trans->distance().isNull()) {
|
||||
++stopped;
|
||||
} else {
|
||||
// Still moving
|
||||
trans->calculate(time);
|
||||
const short fx = trans->target().x() <= trans->startValue().x() ? -1 : 1;
|
||||
const short fy = trans->target().y() <= trans->startValue().y() ? -1 : 1;
|
||||
if (trans->distance().x() * fx / 0.5 < 1.0 && trans->velocity().x() * fx / 0.2 < 1.0
|
||||
&& trans->distance().y() * fy / 0.5 < 1.0 && trans->velocity().y() * fy / 0.2 < 1.0) {
|
||||
// Hide tiny oscillations
|
||||
motion->translation.finish();
|
||||
++stopped;
|
||||
}
|
||||
}
|
||||
|
||||
Motion2D *scale = &motion->scale;
|
||||
if (scale->distance().isNull()) {
|
||||
++stopped;
|
||||
} else {
|
||||
// Still scaling
|
||||
scale->calculate(time);
|
||||
const short fx = scale->target().x() < 1.0 ? -1 : 1;
|
||||
const short fy = scale->target().y() < 1.0 ? -1 : 1;
|
||||
if (scale->distance().x() * fx / 0.001 < 1.0 && scale->velocity().x() * fx / 0.05 < 1.0
|
||||
&& scale->distance().y() * fy / 0.001 < 1.0 && scale->velocity().y() * fy / 0.05 < 1.0) {
|
||||
// Hide tiny oscillations
|
||||
motion->scale.finish();
|
||||
++stopped;
|
||||
}
|
||||
}
|
||||
|
||||
// We just finished this window's motion
|
||||
if (stopped == 2) {
|
||||
m_movingWindowsSet.remove(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMotionManager::reset()
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
EffectWindow *window = it.key();
|
||||
motion->translation.setTarget(window->pos());
|
||||
motion->translation.finish();
|
||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||
motion->scale.finish();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMotionManager::reset(EffectWindow *w)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.setTarget(w->pos());
|
||||
motion->translation.finish();
|
||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||
motion->scale.finish();
|
||||
}
|
||||
|
||||
void WindowMotionManager::apply(EffectWindow *w, WindowPaintData &data)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
WindowMotion *motion = &it.value();
|
||||
data += (motion->translation.value() - QPointF(w->x(), w->y()));
|
||||
data *= QVector2D(motion->scale.value());
|
||||
}
|
||||
|
||||
void WindowMotionManager::moveWindow(EffectWindow *w, QPoint target, double scale, double yScale)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
Q_ASSERT(it != m_managedWindows.end()); // Notify the effect author that they did something wrong
|
||||
|
||||
WindowMotion *motion = &it.value();
|
||||
|
||||
if (yScale == 0.0) {
|
||||
yScale = scale;
|
||||
}
|
||||
QPointF scalePoint(scale, yScale);
|
||||
|
||||
if (motion->translation.value() == target && motion->scale.value() == scalePoint) {
|
||||
return; // Window already at that position
|
||||
}
|
||||
|
||||
motion->translation.setTarget(target);
|
||||
motion->scale.setTarget(scalePoint);
|
||||
|
||||
m_movingWindowsSet << w;
|
||||
}
|
||||
|
||||
QRectF WindowMotionManager::transformedGeometry(EffectWindow *w) const
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return w->frameGeometry();
|
||||
}
|
||||
|
||||
const WindowMotion *motion = &it.value();
|
||||
QRectF geometry(w->frameGeometry());
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
geometry.moveTo(motion->translation.value());
|
||||
geometry.setWidth(geometry.width() * motion->scale.value().x());
|
||||
geometry.setHeight(geometry.height() * motion->scale.value().y());
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
void WindowMotionManager::setTransformedGeometry(EffectWindow *w, const QRectF &geometry)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.setValue(geometry.topLeft());
|
||||
motion->scale.setValue(QPointF(geometry.width() / qreal(w->width()), geometry.height() / qreal(w->height())));
|
||||
}
|
||||
|
||||
QRectF WindowMotionManager::targetGeometry(EffectWindow *w) const
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return w->frameGeometry();
|
||||
}
|
||||
|
||||
const WindowMotion *motion = &it.value();
|
||||
QRectF geometry(w->frameGeometry());
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
geometry.moveTo(motion->translation.target());
|
||||
geometry.setWidth(geometry.width() * motion->scale.target().x());
|
||||
geometry.setHeight(geometry.height() * motion->scale.target().y());
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
EffectWindow *WindowMotionManager::windowAtPoint(QPoint point, bool useStackingOrder) const
|
||||
{
|
||||
// TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
|
||||
QHash<EffectWindow *, WindowMotion>::ConstIterator it = m_managedWindows.constBegin();
|
||||
while (it != m_managedWindows.constEnd()) {
|
||||
if (exclusiveContains(transformedGeometry(it.key()), point)) {
|
||||
return it.key();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "moc_effects.cpp"
|
||||
|
|
|
@ -2294,300 +2294,6 @@ private:
|
|||
VertexSnappingMode m_vertexSnappingMode = VertexSnappingMode::Round;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
template<typename T>
|
||||
class KWIN_EXPORT Motion
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new motion object. "Strength" is the amount of
|
||||
* acceleration that is applied to the object when the target
|
||||
* changes and "smoothness" relates to how fast the object
|
||||
* can change its direction and speed.
|
||||
*/
|
||||
explicit Motion(T initial, double strength, double smoothness);
|
||||
/**
|
||||
* Creates an exact copy of another motion object, including
|
||||
* position, target and velocity.
|
||||
*/
|
||||
Motion(const Motion<T> &other);
|
||||
~Motion();
|
||||
|
||||
inline T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
inline void setValue(const T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
inline T target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
inline void setTarget(const T target)
|
||||
{
|
||||
m_start = m_value;
|
||||
m_target = target;
|
||||
}
|
||||
inline T velocity() const
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
inline void setVelocity(const T velocity)
|
||||
{
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
inline double strength() const
|
||||
{
|
||||
return m_strength;
|
||||
}
|
||||
inline void setStrength(const double strength)
|
||||
{
|
||||
m_strength = strength;
|
||||
}
|
||||
inline double smoothness() const
|
||||
{
|
||||
return m_smoothness;
|
||||
}
|
||||
inline void setSmoothness(const double smoothness)
|
||||
{
|
||||
m_smoothness = smoothness;
|
||||
}
|
||||
inline T startValue()
|
||||
{
|
||||
return m_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance between the current position and the target.
|
||||
*/
|
||||
inline T distance() const
|
||||
{
|
||||
return m_target - m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the new position if not at the target. Called
|
||||
* once per frame only.
|
||||
*/
|
||||
void calculate(const int msec);
|
||||
/**
|
||||
* Place the object on top of the target immediately,
|
||||
* bypassing all movement calculation.
|
||||
*/
|
||||
void finish();
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
T m_start;
|
||||
T m_target;
|
||||
T m_velocity;
|
||||
double m_strength;
|
||||
double m_smoothness;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short A single 1D motion dynamics object.
|
||||
*
|
||||
* This class represents a single object that can be moved around a
|
||||
* 1D space. Although it can be used directly by itself it is
|
||||
* recommended to use a motion manager instead.
|
||||
*/
|
||||
class KWIN_EXPORT Motion1D : public Motion<double>
|
||||
{
|
||||
public:
|
||||
explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0);
|
||||
Motion1D(const Motion1D &other);
|
||||
~Motion1D();
|
||||
};
|
||||
|
||||
/**
|
||||
* @short A single 2D motion dynamics object.
|
||||
*
|
||||
* This class represents a single object that can be moved around a
|
||||
* 2D space. Although it can be used directly by itself it is
|
||||
* recommended to use a motion manager instead.
|
||||
*/
|
||||
class KWIN_EXPORT Motion2D : public Motion<QPointF>
|
||||
{
|
||||
public:
|
||||
explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0);
|
||||
Motion2D(const Motion2D &other);
|
||||
~Motion2D();
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Helper class for motion dynamics in KWin effects.
|
||||
*
|
||||
* This motion manager class is intended to help KWin effect authors
|
||||
* move windows across the screen smoothly and naturally. Once
|
||||
* windows are registered by the manager the effect can issue move
|
||||
* commands with the moveWindow() methods. The position of any
|
||||
* managed window can be determined in realtime by the
|
||||
* transformedGeometry() method. As the manager knows if any windows
|
||||
* are moving at any given time it can also be used as a notifier as
|
||||
* to see whether the effect is active or not.
|
||||
*/
|
||||
class KWIN_EXPORT WindowMotionManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new window manager object.
|
||||
*/
|
||||
explicit WindowMotionManager(bool useGlobalAnimationModifier = true);
|
||||
~WindowMotionManager();
|
||||
|
||||
/**
|
||||
* Register a window for managing.
|
||||
*/
|
||||
void manage(EffectWindow *w);
|
||||
/**
|
||||
* Register a list of windows for managing.
|
||||
*/
|
||||
inline void manage(const EffectWindowList &list)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
manage(list.at(i));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deregister a window. All transformations applied to the
|
||||
* window will be permanently removed and cannot be recovered.
|
||||
*/
|
||||
void unmanage(EffectWindow *w);
|
||||
/**
|
||||
* Deregister all windows, returning the manager to its
|
||||
* originally initiated state.
|
||||
*/
|
||||
void unmanageAll();
|
||||
/**
|
||||
* Determine the new positions for windows that have not
|
||||
* reached their target. Called once per frame, usually in
|
||||
* prePaintScreen(). Remember to set the
|
||||
* Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag.
|
||||
*/
|
||||
void calculate(int time);
|
||||
/**
|
||||
* Modify a registered window's paint data to make it appear
|
||||
* at its real location on the screen. Usually called in
|
||||
* paintWindow(). Remember to flag the window as having been
|
||||
* transformed in prePaintWindow() by calling
|
||||
* WindowPrePaintData::setTransformed()
|
||||
*/
|
||||
void apply(EffectWindow *w, WindowPaintData &data);
|
||||
/**
|
||||
* Set all motion targets and values back to where the
|
||||
* windows were before transformations. The same as
|
||||
* unmanaging then remanaging all windows.
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* Resets the motion target and current value of a single
|
||||
* window.
|
||||
*/
|
||||
void reset(EffectWindow *w);
|
||||
|
||||
/**
|
||||
* Ask the manager to move the window to the target position
|
||||
* with the specified scale. If `yScale` is not provided or
|
||||
* set to 0.0, `scale` will be used as the scale in the
|
||||
* vertical direction as well as in the horizontal direction.
|
||||
*/
|
||||
void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0);
|
||||
/**
|
||||
* This is an overloaded method, provided for convenience.
|
||||
*
|
||||
* Ask the manager to move the window to the target rectangle.
|
||||
* Automatically determines scale.
|
||||
*/
|
||||
inline void moveWindow(EffectWindow *w, QRect target)
|
||||
{
|
||||
// TODO: Scale might be slightly different in the comparison due to rounding
|
||||
moveWindow(w, target.topLeft(),
|
||||
target.width() / double(w->width()), target.height() / double(w->height()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current tranformed geometry of a registered
|
||||
* window.
|
||||
*/
|
||||
QRectF transformedGeometry(EffectWindow *w) const;
|
||||
/**
|
||||
* Sets the current transformed geometry of a registered window to the given geometry.
|
||||
* @see transformedGeometry
|
||||
* @since 4.5
|
||||
*/
|
||||
void setTransformedGeometry(EffectWindow *w, const QRectF &geometry);
|
||||
/**
|
||||
* Retrieve the current target geometry of a registered
|
||||
* window.
|
||||
*/
|
||||
QRectF targetGeometry(EffectWindow *w) const;
|
||||
/**
|
||||
* Return the window that has its transformed geometry under
|
||||
* the specified point. It is recommended to use the stacking
|
||||
* order as it's what the user sees, but it is slightly
|
||||
* slower to process.
|
||||
*/
|
||||
EffectWindow *windowAtPoint(QPoint point, bool useStackingOrder = true) const;
|
||||
|
||||
/**
|
||||
* Return a list of all currently registered windows.
|
||||
*/
|
||||
inline EffectWindowList managedWindows() const
|
||||
{
|
||||
return m_managedWindows.keys();
|
||||
}
|
||||
/**
|
||||
* Returns whether or not a specified window is being managed
|
||||
* by this manager object.
|
||||
*/
|
||||
inline bool isManaging(EffectWindow *w) const
|
||||
{
|
||||
return m_managedWindows.contains(w);
|
||||
}
|
||||
/**
|
||||
* Returns whether or not this manager object is actually
|
||||
* managing any windows or not.
|
||||
*/
|
||||
inline bool managingWindows() const
|
||||
{
|
||||
return !m_managedWindows.empty();
|
||||
}
|
||||
/**
|
||||
* Returns whether all windows have reached their targets yet
|
||||
* or not. Can be used to see if an effect should be
|
||||
* processed and displayed or not.
|
||||
*/
|
||||
inline bool areWindowsMoving() const
|
||||
{
|
||||
return !m_movingWindowsSet.isEmpty();
|
||||
}
|
||||
/**
|
||||
* Returns whether a window has reached its targets yet
|
||||
* or not.
|
||||
*/
|
||||
inline bool isWindowMoving(EffectWindow *w) const
|
||||
{
|
||||
return m_movingWindowsSet.contains(w);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_useGlobalAnimationModifier;
|
||||
struct WindowMotion
|
||||
{
|
||||
// TODO: Rotation, etc?
|
||||
Motion2D translation; // Absolute position
|
||||
Motion2D scale; // xScale and yScale
|
||||
};
|
||||
QHash<EffectWindow *, WindowMotion> m_managedWindows;
|
||||
QSet<EffectWindow *> m_movingWindowsSet;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pointer to the global EffectsHandler object.
|
||||
*/
|
||||
|
@ -2682,61 +2388,6 @@ inline QRectF WindowQuad::bounds() const
|
|||
return QRectF(QPointF(left(), top()), QPointF(right(), bottom()));
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Motion
|
||||
***************************************************************/
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::Motion(T initial, double strength, double smoothness)
|
||||
: m_value(initial)
|
||||
, m_start(initial)
|
||||
, m_target(initial)
|
||||
, m_velocity()
|
||||
, m_strength(strength)
|
||||
, m_smoothness(smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::Motion(const Motion &other)
|
||||
: m_value(other.value())
|
||||
, m_start(other.target())
|
||||
, m_target(other.target())
|
||||
, m_velocity(other.velocity())
|
||||
, m_strength(other.strength())
|
||||
, m_smoothness(other.smoothness())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::~Motion()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Motion<T>::calculate(const int msec)
|
||||
{
|
||||
if (m_value == m_target && m_velocity == T()) { // At target and not moving
|
||||
return;
|
||||
}
|
||||
|
||||
// Poor man's time independent calculation
|
||||
int steps = std::max(1, msec / 5);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
T diff = m_target - m_value;
|
||||
T strength = diff * m_strength;
|
||||
m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0);
|
||||
m_value += m_velocity;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Motion<T>::finish()
|
||||
{
|
||||
m_value = m_target;
|
||||
m_velocity = T();
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
EffectWindow
|
||||
***************************************************************/
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#######################################
|
||||
# Effect
|
||||
|
||||
# Source files
|
||||
set(slideback_SOURCES
|
||||
kwin_add_builtin_effect(slideback)
|
||||
target_sources(slideback PRIVATE
|
||||
main.cpp
|
||||
motionmanager.cpp
|
||||
slideback.cpp
|
||||
)
|
||||
|
||||
kwin_add_builtin_effect(slideback ${slideback_SOURCES})
|
||||
target_link_libraries(slideback PRIVATE
|
||||
kwin
|
||||
)
|
||||
|
|
284
src/plugins/slideback/motionmanager.cpp
Normal file
284
src/plugins/slideback/motionmanager.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "plugins/slideback/motionmanager.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
/***************************************************************
|
||||
Motion1D
|
||||
***************************************************************/
|
||||
|
||||
Motion1D::Motion1D(double initial, double strength, double smoothness)
|
||||
: Motion<double>(initial, strength, smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
Motion1D::Motion1D(const Motion1D &other)
|
||||
: Motion<double>(other)
|
||||
{
|
||||
}
|
||||
|
||||
Motion1D::~Motion1D()
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Motion2D
|
||||
***************************************************************/
|
||||
|
||||
Motion2D::Motion2D(QPointF initial, double strength, double smoothness)
|
||||
: Motion<QPointF>(initial, strength, smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
Motion2D::Motion2D(const Motion2D &other)
|
||||
: Motion<QPointF>(other)
|
||||
{
|
||||
}
|
||||
|
||||
Motion2D::~Motion2D()
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
WindowMotionManager
|
||||
***************************************************************/
|
||||
|
||||
WindowMotionManager::WindowMotionManager(bool useGlobalAnimationModifier)
|
||||
: m_useGlobalAnimationModifier(useGlobalAnimationModifier)
|
||||
|
||||
{
|
||||
// TODO: Allow developer to modify motion attributes
|
||||
} // TODO: What happens when the window moves by an external force?
|
||||
|
||||
WindowMotionManager::~WindowMotionManager()
|
||||
{
|
||||
}
|
||||
|
||||
void WindowMotionManager::manage(EffectWindow *w)
|
||||
{
|
||||
if (m_managedWindows.contains(w)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double strength = 0.08;
|
||||
double smoothness = 4.0;
|
||||
if (m_useGlobalAnimationModifier && effects->animationTimeFactor()) {
|
||||
// If the factor is == 0 then we just skip the calculation completely
|
||||
strength = 0.08 / effects->animationTimeFactor();
|
||||
smoothness = effects->animationTimeFactor() * 4.0;
|
||||
}
|
||||
|
||||
WindowMotion &motion = m_managedWindows[w];
|
||||
motion.translation.setStrength(strength);
|
||||
motion.translation.setSmoothness(smoothness);
|
||||
motion.scale.setStrength(strength * 1.33);
|
||||
motion.scale.setSmoothness(smoothness / 2.0);
|
||||
|
||||
motion.translation.setValue(w->pos());
|
||||
motion.scale.setValue(QPointF(1.0, 1.0));
|
||||
}
|
||||
|
||||
void WindowMotionManager::unmanage(EffectWindow *w)
|
||||
{
|
||||
m_movingWindowsSet.remove(w);
|
||||
m_managedWindows.remove(w);
|
||||
}
|
||||
|
||||
void WindowMotionManager::unmanageAll()
|
||||
{
|
||||
m_managedWindows.clear();
|
||||
m_movingWindowsSet.clear();
|
||||
}
|
||||
|
||||
void WindowMotionManager::calculate(int time)
|
||||
{
|
||||
if (!effects->animationTimeFactor()) {
|
||||
// Just skip it completely if the user wants no animation
|
||||
m_movingWindowsSet.clear();
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.finish();
|
||||
motion->scale.finish();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
int stopped = 0;
|
||||
|
||||
// TODO: What happens when distance() == 0 but we are still moving fast?
|
||||
// TODO: Motion needs to be calculated from the window's center
|
||||
|
||||
Motion2D *trans = &motion->translation;
|
||||
if (trans->distance().isNull()) {
|
||||
++stopped;
|
||||
} else {
|
||||
// Still moving
|
||||
trans->calculate(time);
|
||||
const short fx = trans->target().x() <= trans->startValue().x() ? -1 : 1;
|
||||
const short fy = trans->target().y() <= trans->startValue().y() ? -1 : 1;
|
||||
if (trans->distance().x() * fx / 0.5 < 1.0 && trans->velocity().x() * fx / 0.2 < 1.0
|
||||
&& trans->distance().y() * fy / 0.5 < 1.0 && trans->velocity().y() * fy / 0.2 < 1.0) {
|
||||
// Hide tiny oscillations
|
||||
motion->translation.finish();
|
||||
++stopped;
|
||||
}
|
||||
}
|
||||
|
||||
Motion2D *scale = &motion->scale;
|
||||
if (scale->distance().isNull()) {
|
||||
++stopped;
|
||||
} else {
|
||||
// Still scaling
|
||||
scale->calculate(time);
|
||||
const short fx = scale->target().x() < 1.0 ? -1 : 1;
|
||||
const short fy = scale->target().y() < 1.0 ? -1 : 1;
|
||||
if (scale->distance().x() * fx / 0.001 < 1.0 && scale->velocity().x() * fx / 0.05 < 1.0
|
||||
&& scale->distance().y() * fy / 0.001 < 1.0 && scale->velocity().y() * fy / 0.05 < 1.0) {
|
||||
// Hide tiny oscillations
|
||||
motion->scale.finish();
|
||||
++stopped;
|
||||
}
|
||||
}
|
||||
|
||||
// We just finished this window's motion
|
||||
if (stopped == 2) {
|
||||
m_movingWindowsSet.remove(it.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMotionManager::reset()
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||
for (; it != m_managedWindows.end(); ++it) {
|
||||
WindowMotion *motion = &it.value();
|
||||
EffectWindow *window = it.key();
|
||||
motion->translation.setTarget(window->pos());
|
||||
motion->translation.finish();
|
||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||
motion->scale.finish();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowMotionManager::reset(EffectWindow *w)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.setTarget(w->pos());
|
||||
motion->translation.finish();
|
||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||
motion->scale.finish();
|
||||
}
|
||||
|
||||
void WindowMotionManager::apply(EffectWindow *w, WindowPaintData &data)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
WindowMotion *motion = &it.value();
|
||||
data += (motion->translation.value() - QPointF(w->x(), w->y()));
|
||||
data *= QVector2D(motion->scale.value());
|
||||
}
|
||||
|
||||
void WindowMotionManager::moveWindow(EffectWindow *w, QPoint target, double scale, double yScale)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
Q_ASSERT(it != m_managedWindows.end()); // Notify the effect author that they did something wrong
|
||||
|
||||
WindowMotion *motion = &it.value();
|
||||
|
||||
if (yScale == 0.0) {
|
||||
yScale = scale;
|
||||
}
|
||||
QPointF scalePoint(scale, yScale);
|
||||
|
||||
if (motion->translation.value() == target && motion->scale.value() == scalePoint) {
|
||||
return; // Window already at that position
|
||||
}
|
||||
|
||||
motion->translation.setTarget(target);
|
||||
motion->scale.setTarget(scalePoint);
|
||||
|
||||
m_movingWindowsSet << w;
|
||||
}
|
||||
|
||||
QRectF WindowMotionManager::transformedGeometry(EffectWindow *w) const
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return w->frameGeometry();
|
||||
}
|
||||
|
||||
const WindowMotion *motion = &it.value();
|
||||
QRectF geometry(w->frameGeometry());
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
geometry.moveTo(motion->translation.value());
|
||||
geometry.setWidth(geometry.width() * motion->scale.value().x());
|
||||
geometry.setHeight(geometry.height() * motion->scale.value().y());
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
void WindowMotionManager::setTransformedGeometry(EffectWindow *w, const QRectF &geometry)
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return;
|
||||
}
|
||||
WindowMotion *motion = &it.value();
|
||||
motion->translation.setValue(geometry.topLeft());
|
||||
motion->scale.setValue(QPointF(geometry.width() / qreal(w->width()), geometry.height() / qreal(w->height())));
|
||||
}
|
||||
|
||||
QRectF WindowMotionManager::targetGeometry(EffectWindow *w) const
|
||||
{
|
||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||
if (it == m_managedWindows.end()) {
|
||||
return w->frameGeometry();
|
||||
}
|
||||
|
||||
const WindowMotion *motion = &it.value();
|
||||
QRectF geometry(w->frameGeometry());
|
||||
|
||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||
geometry.moveTo(motion->translation.target());
|
||||
geometry.setWidth(geometry.width() * motion->scale.target().x());
|
||||
geometry.setHeight(geometry.height() * motion->scale.target().y());
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
EffectWindow *WindowMotionManager::windowAtPoint(QPoint point, bool useStackingOrder) const
|
||||
{
|
||||
// TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
|
||||
QHash<EffectWindow *, WindowMotion>::ConstIterator it = m_managedWindows.constBegin();
|
||||
while (it != m_managedWindows.constEnd()) {
|
||||
if (exclusiveContains(transformedGeometry(it.key()), point)) {
|
||||
return it.key();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
361
src/plugins/slideback/motionmanager.h
Normal file
361
src/plugins/slideback/motionmanager.h
Normal file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||
SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libkwineffects/effects.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
template<typename T>
|
||||
class KWIN_EXPORT Motion
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new motion object. "Strength" is the amount of
|
||||
* acceleration that is applied to the object when the target
|
||||
* changes and "smoothness" relates to how fast the object
|
||||
* can change its direction and speed.
|
||||
*/
|
||||
explicit Motion(T initial, double strength, double smoothness);
|
||||
/**
|
||||
* Creates an exact copy of another motion object, including
|
||||
* position, target and velocity.
|
||||
*/
|
||||
Motion(const Motion<T> &other);
|
||||
~Motion();
|
||||
|
||||
inline T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
inline void setValue(const T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
inline T target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
inline void setTarget(const T target)
|
||||
{
|
||||
m_start = m_value;
|
||||
m_target = target;
|
||||
}
|
||||
inline T velocity() const
|
||||
{
|
||||
return m_velocity;
|
||||
}
|
||||
inline void setVelocity(const T velocity)
|
||||
{
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
inline double strength() const
|
||||
{
|
||||
return m_strength;
|
||||
}
|
||||
inline void setStrength(const double strength)
|
||||
{
|
||||
m_strength = strength;
|
||||
}
|
||||
inline double smoothness() const
|
||||
{
|
||||
return m_smoothness;
|
||||
}
|
||||
inline void setSmoothness(const double smoothness)
|
||||
{
|
||||
m_smoothness = smoothness;
|
||||
}
|
||||
inline T startValue()
|
||||
{
|
||||
return m_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance between the current position and the target.
|
||||
*/
|
||||
inline T distance() const
|
||||
{
|
||||
return m_target - m_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the new position if not at the target. Called
|
||||
* once per frame only.
|
||||
*/
|
||||
void calculate(const int msec);
|
||||
/**
|
||||
* Place the object on top of the target immediately,
|
||||
* bypassing all movement calculation.
|
||||
*/
|
||||
void finish();
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
T m_start;
|
||||
T m_target;
|
||||
T m_velocity;
|
||||
double m_strength;
|
||||
double m_smoothness;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short A single 1D motion dynamics object.
|
||||
*
|
||||
* This class represents a single object that can be moved around a
|
||||
* 1D space. Although it can be used directly by itself it is
|
||||
* recommended to use a motion manager instead.
|
||||
*/
|
||||
class KWIN_EXPORT Motion1D : public Motion<double>
|
||||
{
|
||||
public:
|
||||
explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0);
|
||||
Motion1D(const Motion1D &other);
|
||||
~Motion1D();
|
||||
};
|
||||
|
||||
/**
|
||||
* @short A single 2D motion dynamics object.
|
||||
*
|
||||
* This class represents a single object that can be moved around a
|
||||
* 2D space. Although it can be used directly by itself it is
|
||||
* recommended to use a motion manager instead.
|
||||
*/
|
||||
class KWIN_EXPORT Motion2D : public Motion<QPointF>
|
||||
{
|
||||
public:
|
||||
explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0);
|
||||
Motion2D(const Motion2D &other);
|
||||
~Motion2D();
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Helper class for motion dynamics in KWin effects.
|
||||
*
|
||||
* This motion manager class is intended to help KWin effect authors
|
||||
* move windows across the screen smoothly and naturally. Once
|
||||
* windows are registered by the manager the effect can issue move
|
||||
* commands with the moveWindow() methods. The position of any
|
||||
* managed window can be determined in realtime by the
|
||||
* transformedGeometry() method. As the manager knows if any windows
|
||||
* are moving at any given time it can also be used as a notifier as
|
||||
* to see whether the effect is active or not.
|
||||
*/
|
||||
class KWIN_EXPORT WindowMotionManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new window manager object.
|
||||
*/
|
||||
explicit WindowMotionManager(bool useGlobalAnimationModifier = true);
|
||||
~WindowMotionManager();
|
||||
|
||||
/**
|
||||
* Register a window for managing.
|
||||
*/
|
||||
void manage(EffectWindow *w);
|
||||
/**
|
||||
* Register a list of windows for managing.
|
||||
*/
|
||||
inline void manage(const EffectWindowList &list)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
manage(list.at(i));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deregister a window. All transformations applied to the
|
||||
* window will be permanently removed and cannot be recovered.
|
||||
*/
|
||||
void unmanage(EffectWindow *w);
|
||||
/**
|
||||
* Deregister all windows, returning the manager to its
|
||||
* originally initiated state.
|
||||
*/
|
||||
void unmanageAll();
|
||||
/**
|
||||
* Determine the new positions for windows that have not
|
||||
* reached their target. Called once per frame, usually in
|
||||
* prePaintScreen(). Remember to set the
|
||||
* Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag.
|
||||
*/
|
||||
void calculate(int time);
|
||||
/**
|
||||
* Modify a registered window's paint data to make it appear
|
||||
* at its real location on the screen. Usually called in
|
||||
* paintWindow(). Remember to flag the window as having been
|
||||
* transformed in prePaintWindow() by calling
|
||||
* WindowPrePaintData::setTransformed()
|
||||
*/
|
||||
void apply(EffectWindow *w, WindowPaintData &data);
|
||||
/**
|
||||
* Set all motion targets and values back to where the
|
||||
* windows were before transformations. The same as
|
||||
* unmanaging then remanaging all windows.
|
||||
*/
|
||||
void reset();
|
||||
/**
|
||||
* Resets the motion target and current value of a single
|
||||
* window.
|
||||
*/
|
||||
void reset(EffectWindow *w);
|
||||
|
||||
/**
|
||||
* Ask the manager to move the window to the target position
|
||||
* with the specified scale. If `yScale` is not provided or
|
||||
* set to 0.0, `scale` will be used as the scale in the
|
||||
* vertical direction as well as in the horizontal direction.
|
||||
*/
|
||||
void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0);
|
||||
/**
|
||||
* This is an overloaded method, provided for convenience.
|
||||
*
|
||||
* Ask the manager to move the window to the target rectangle.
|
||||
* Automatically determines scale.
|
||||
*/
|
||||
inline void moveWindow(EffectWindow *w, QRect target)
|
||||
{
|
||||
// TODO: Scale might be slightly different in the comparison due to rounding
|
||||
moveWindow(w, target.topLeft(),
|
||||
target.width() / double(w->width()), target.height() / double(w->height()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current tranformed geometry of a registered
|
||||
* window.
|
||||
*/
|
||||
QRectF transformedGeometry(EffectWindow *w) const;
|
||||
/**
|
||||
* Sets the current transformed geometry of a registered window to the given geometry.
|
||||
* @see transformedGeometry
|
||||
* @since 4.5
|
||||
*/
|
||||
void setTransformedGeometry(EffectWindow *w, const QRectF &geometry);
|
||||
/**
|
||||
* Retrieve the current target geometry of a registered
|
||||
* window.
|
||||
*/
|
||||
QRectF targetGeometry(EffectWindow *w) const;
|
||||
/**
|
||||
* Return the window that has its transformed geometry under
|
||||
* the specified point. It is recommended to use the stacking
|
||||
* order as it's what the user sees, but it is slightly
|
||||
* slower to process.
|
||||
*/
|
||||
EffectWindow *windowAtPoint(QPoint point, bool useStackingOrder = true) const;
|
||||
|
||||
/**
|
||||
* Return a list of all currently registered windows.
|
||||
*/
|
||||
inline EffectWindowList managedWindows() const
|
||||
{
|
||||
return m_managedWindows.keys();
|
||||
}
|
||||
/**
|
||||
* Returns whether or not a specified window is being managed
|
||||
* by this manager object.
|
||||
*/
|
||||
inline bool isManaging(EffectWindow *w) const
|
||||
{
|
||||
return m_managedWindows.contains(w);
|
||||
}
|
||||
/**
|
||||
* Returns whether or not this manager object is actually
|
||||
* managing any windows or not.
|
||||
*/
|
||||
inline bool managingWindows() const
|
||||
{
|
||||
return !m_managedWindows.empty();
|
||||
}
|
||||
/**
|
||||
* Returns whether all windows have reached their targets yet
|
||||
* or not. Can be used to see if an effect should be
|
||||
* processed and displayed or not.
|
||||
*/
|
||||
inline bool areWindowsMoving() const
|
||||
{
|
||||
return !m_movingWindowsSet.isEmpty();
|
||||
}
|
||||
/**
|
||||
* Returns whether a window has reached its targets yet
|
||||
* or not.
|
||||
*/
|
||||
inline bool isWindowMoving(EffectWindow *w) const
|
||||
{
|
||||
return m_movingWindowsSet.contains(w);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_useGlobalAnimationModifier;
|
||||
struct WindowMotion
|
||||
{
|
||||
// TODO: Rotation, etc?
|
||||
Motion2D translation; // Absolute position
|
||||
Motion2D scale; // xScale and yScale
|
||||
};
|
||||
QHash<EffectWindow *, WindowMotion> m_managedWindows;
|
||||
QSet<EffectWindow *> m_movingWindowsSet;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::Motion(T initial, double strength, double smoothness)
|
||||
: m_value(initial)
|
||||
, m_start(initial)
|
||||
, m_target(initial)
|
||||
, m_velocity()
|
||||
, m_strength(strength)
|
||||
, m_smoothness(smoothness)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::Motion(const Motion &other)
|
||||
: m_value(other.value())
|
||||
, m_start(other.target())
|
||||
, m_target(other.target())
|
||||
, m_velocity(other.velocity())
|
||||
, m_strength(other.strength())
|
||||
, m_smoothness(other.smoothness())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Motion<T>::~Motion()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Motion<T>::calculate(const int msec)
|
||||
{
|
||||
if (m_value == m_target && m_velocity == T()) { // At target and not moving
|
||||
return;
|
||||
}
|
||||
|
||||
// Poor man's time independent calculation
|
||||
int steps = std::max(1, msec / 5);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
T diff = m_target - m_value;
|
||||
T strength = diff * m_strength;
|
||||
m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0);
|
||||
m_value += m_velocity;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Motion<T>::finish()
|
||||
{
|
||||
m_value = m_target;
|
||||
m_velocity = T();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
// Include with base class for effects.
|
||||
#include "libkwineffects/effects.h"
|
||||
#include "plugins/slideback/motionmanager.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue