362 lines
9.7 KiB
C++
362 lines
9.7 KiB
C++
/*
|
|
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 "effect/effecthandler.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 QList<EffectWindow *> &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 QList<EffectWindow *> 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
|