Commits

flupp committed 3653f8f

reworked tool tip placement and movement animation (fixes deprecation warning)

  • Participants
  • Parent commits 45eb443

Comments (0)

Files changed (11)

File applet/CMakeLists.txt

 include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES})
 
 set(smoothtasks_SRCS
+	SmoothTasks/Animation/AnimationThrowPoint.cpp
+	SmoothTasks/Animation/AnimationThrowRect.cpp
 	SmoothTasks/Applet.cpp
 	SmoothTasks/Task.cpp
 	SmoothTasks/TaskItem.cpp

File applet/SmoothTasks/Animation/AnimationThrow.h

+/***********************************************************************************
+* Smooth Tasks
+* Copyright (C) 2012 Toni Dietze <smooth-tasks@derflupp.e4ward.com>
+*
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+***********************************************************************************/
+
+#ifndef ANIMATIONTHROW_H
+#define ANIMATIONTHROW_H
+
+// C++
+#include <cmath>
+
+// Qt
+#include <QAbstractAnimation>
+#include <QVariant>
+
+// KDE
+#include <KDebug>
+
+namespace SmoothTasks {
+
+template <int SIZE, class CLASS>
+class AnimationThrow : public QAbstractAnimation
+{
+// The moc cannot handle template classes, so the propertys may not work,
+// see http://doc.qt.nokia.com/qq/qq15-academic.html
+// 	Q_OBJECT
+	Q_PROPERTY(qreal      acceleration READ acceleration WRITE setAcceleration)
+	Q_PROPERTY(CLASS      startValue   READ startValue   WRITE setStartValue  )
+	Q_PROPERTY(CLASS      endValue     READ endValue     WRITE setEndValue    )
+	Q_PROPERTY(QObject*   targetObject READ targetObject WRITE setTargetObject)
+	Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName)
+
+public:
+	AnimationThrow(QObject* parent = 0);
+	AnimationThrow(QObject* target, const QByteArray& propertyName, QObject* parent = 0);
+	virtual ~AnimationThrow() {}
+	void init();
+
+	/* implement */ virtual int duration() const { return -1; }
+
+	// Getter
+	const QObject* targetObject () const { return m_target             ; }
+	QObject*       targetObject ()       { return m_target             ; }
+	QByteArray     propertyName () const { return m_targetPropertyName ; }
+	qreal          acceleration () const { return m_acceleration       ; }
+	CLASS          startValue   () const { return convert(m_startValue); }
+	CLASS          endValue     () const { return convert(m_endValue  ); }
+
+	// Setter
+	void setTargetObject(QObject* target    ) { m_target = target; }
+	void setPropertyName(const QByteArray& propertyName) { m_targetPropertyName = propertyName; }
+	void setAcceleration(qreal acceleration ) { m_cacheDirty = true; m_acceleration = acceleration; }
+	void setStartValue  (const CLASS& value ) { m_cacheDirty = true; convert(value, m_startValue) ; }
+	void setEndValue    (const CLASS& value ) { m_cacheDirty = true; convert(value, m_endValue  ) ; }
+
+protected:
+	virtual CLASS convert(const qreal src[]) const = 0;
+	virtual void  convert(const CLASS& src, qreal dst[]) const = 0;
+
+	/* implement */ virtual void updateCurrentTime(int currentTime);
+
+private:
+	void updateCache();
+
+	QObject* m_target;
+	QByteArray m_targetPropertyName;
+	qreal m_acceleration;
+	qreal m_startValue[SIZE];
+	qreal m_endValue[SIZE];
+
+	bool  m_cacheDirty;
+	int   m_cachedDuration;
+	qreal m_cachedDurations[SIZE];
+};
+
+
+template <int SIZE, class CLASS>
+AnimationThrow<SIZE, CLASS>::AnimationThrow(QObject* parent)
+	: QAbstractAnimation(parent)
+	, m_target(0)
+	, m_acceleration(1.0)
+	, m_cacheDirty(true)
+{
+	init();
+}
+
+template <int SIZE, class CLASS>
+AnimationThrow<SIZE, CLASS>::AnimationThrow(QObject* target, const QByteArray& propertyName, QObject* parent)
+	: QAbstractAnimation(parent)
+	, m_target(target)
+	, m_targetPropertyName(propertyName)
+	, m_acceleration(1.0)
+	, m_cacheDirty(true)
+{
+	init();
+}
+
+template <int SIZE, class CLASS>
+void AnimationThrow<SIZE, CLASS>::init()
+{
+	for (int i = 0; i < SIZE; ++i) {
+		m_startValue[i] = 0;
+		m_endValue[i] = 0;
+	}
+}
+
+template <int SIZE, class CLASS>
+void AnimationThrow<SIZE, CLASS>::updateCurrentTime(int currentTime)
+{
+	if (!m_target || m_targetPropertyName.isEmpty()) {
+		kWarning() << "target or property name not set";
+		stop();
+		return;
+	}
+
+	updateCache();
+
+	qreal current[SIZE];
+	qreal t = 0.001 * static_cast<qreal>(currentTime);
+	for (int i = 0; i < SIZE; ++i) {
+		if (t < m_cachedDurations[i]) {
+			qreal t2 = 1 - t / m_cachedDurations[i];
+			current[i] = m_startValue[i] + (1 - t2 * t2) * (m_endValue[i] - m_startValue[i]);
+		} else {
+			current[i] = m_endValue[i];
+		}
+	}
+
+	if (!m_target->setProperty(m_targetPropertyName.constData(), QVariant(convert(current)))) {
+		kWarning()
+			<< "you're trying to animate a non-existing or wrong-typed property"
+			<< m_targetPropertyName.constData()
+			<< "of your QObject"
+			<< m_target;
+		stop();
+		return;
+	}
+
+	if (currentTime >= m_cachedDuration)
+		stop();
+}
+
+template <int SIZE, class CLASS>
+void AnimationThrow<SIZE, CLASS>::updateCache() {
+	if (!m_cacheDirty) return;
+	qreal dur = 0.0;
+	for (int i = 0; i < SIZE; ++i) {
+		qreal delta = m_endValue[i] - m_startValue[i];
+		m_cachedDurations[i] =  std::sqrt(std::abs(delta) / m_acceleration);
+		if (m_cachedDurations[i] > dur)
+			dur = m_cachedDurations[i];
+	}
+	m_cachedDuration = static_cast<int>(1000 * dur) + 1;
+	m_cacheDirty = false;
+}
+
+} // namespace SmoothTasks
+
+#endif // ANIMATIONTHROW_H

File applet/SmoothTasks/Animation/AnimationThrowPoint.cpp

+/***********************************************************************************
+* Smooth Tasks
+* Copyright (C) 2012 Toni Dietze <smooth-tasks@derflupp.e4ward.com>
+*
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+***********************************************************************************/
+
+#include "AnimationThrowPoint.h"
+
+#include <QPointF>
+
+namespace SmoothTasks {
+
+AnimationThrowPoint::AnimationThrowPoint(QObject* parent)
+	: AnimationThrow<2, QPointF>(parent)
+{}
+
+AnimationThrowPoint::AnimationThrowPoint(QObject* target, const QByteArray& propertyName, QObject* parent)
+	: AnimationThrow<2, QPointF>(target, propertyName, parent)
+{}
+
+AnimationThrowPoint::~AnimationThrowPoint() {
+}
+
+QPointF AnimationThrowPoint::convert(const qreal src[]) const {
+	return QPointF(src[0], src[1]);
+}
+
+void AnimationThrowPoint::convert(const QPointF& src, qreal dst[]) const {
+	dst[0] = src.x();
+	dst[1] = src.y();
+}
+
+} // namespace SmoothTasks

File applet/SmoothTasks/Animation/AnimationThrowPoint.h

+/***********************************************************************************
+* Smooth Tasks
+* Copyright (C) 2012 Toni Dietze <smooth-tasks@derflupp.e4ward.com>
+*
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+***********************************************************************************/
+
+#ifndef ANIMATIONTHROWPOINT_H
+#define ANIMATIONTHROWPOINT_H
+
+#include <SmoothTasks/Animation/AnimationThrow.h>
+
+class QPointF;
+
+namespace SmoothTasks {
+
+class AnimationThrowPoint : public AnimationThrow<2, QPointF>
+{
+	Q_OBJECT
+
+public:
+	AnimationThrowPoint(QObject* parent = 0);
+	AnimationThrowPoint(QObject* target, const QByteArray& propertyName, QObject* parent = 0);
+	virtual ~AnimationThrowPoint();
+
+	/* implement */ virtual QPointF convert(const qreal src[]) const;
+	/* implement */ virtual void    convert(const QPointF& src, qreal dst[]) const;
+};
+
+} // namespace SmoothTasks
+
+#endif // ANIMATIONTHROWPOINT_H

File applet/SmoothTasks/Animation/AnimationThrowRect.cpp

+/***********************************************************************************
+* Smooth Tasks
+* Copyright (C) 2012 Toni Dietze <smooth-tasks@derflupp.e4ward.com>
+*
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+***********************************************************************************/
+
+#include "AnimationThrowRect.h"
+
+#include <QRectF>
+
+namespace SmoothTasks {
+
+AnimationThrowRect::AnimationThrowRect(QObject* parent)
+	: AnimationThrow<4, QRectF>(parent)
+{}
+
+AnimationThrowRect::AnimationThrowRect(QObject* target, const QByteArray& propertyName, QObject* parent)
+	: AnimationThrow<4, QRectF>(target, propertyName, parent)
+{}
+
+AnimationThrowRect::~AnimationThrowRect() {
+}
+
+QRectF AnimationThrowRect::convert(const qreal src[]) const {
+	QRectF rect;
+	rect.setCoords(src[0], src[1], src[2], src[3]);
+	return rect;
+}
+
+void AnimationThrowRect::convert(const QRectF& src, qreal dst[]) const {
+	src.getCoords(dst, dst + 1, dst + 2, dst + 3);
+}
+
+} // namespace SmoothTasks

File applet/SmoothTasks/Animation/AnimationThrowRect.h

+/***********************************************************************************
+* Smooth Tasks
+* Copyright (C) 2012 Toni Dietze <smooth-tasks@derflupp.e4ward.com>
+*
+* 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, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*
+***********************************************************************************/
+
+#ifndef ANIMATIONTHROWRECT_H
+#define ANIMATIONTHROWRECT_H
+
+#include <SmoothTasks/Animation/AnimationThrow.h>
+
+class QRectF;
+
+namespace SmoothTasks {
+
+class AnimationThrowRect : public AnimationThrow<4, QRectF>
+{
+	Q_OBJECT
+
+public:
+	AnimationThrowRect(QObject* parent = 0);
+	AnimationThrowRect(QObject* target, const QByteArray& propertyName, QObject* parent = 0);
+	virtual ~AnimationThrowRect();
+
+	/* implement */ virtual QRectF convert(const qreal src[]) const;
+	/* implement */ virtual void   convert(const QRectF& src, qreal dst[]) const;
+};
+
+} // namespace SmoothTasks
+
+#endif // ANIMATIONTHROWRECT_H

File applet/SmoothTasks/SmoothToolTip.cpp

 ***********************************************************************************/
 
 #include "SmoothTasks/SmoothToolTip.h"
+
 #include "SmoothTasks/ToolTipWidget.h"
 #include "SmoothTasks/WindowPreview.h"
 #include "SmoothTasks/TaskItem.h"
 #include "SmoothTasks/Task.h"
 
+#include <Plasma/Containment>
+#include <Plasma/Corona>
 #include <Plasma/Theme>
 #include <Plasma/IconWidget>
 #include <Plasma/WindowEffects>
 	  m_highlightDelay(new QTimer(this)),
 	  m_highlighting(false),
 	  m_scrollAnimation(0),
-	  m_dx(0),
-	  m_xStart(0),
-	  m_dy(0),
-	  m_yStart(0),
-	  m_moveAnimation(false),
-	  m_moveAnimationUpdated(false),
-	  m_position(0),
-	  m_size(0, 0),
 	  m_closeIcon(),
 	  m_hoverCloseIcon() {
 	
 	connect(
-		Plasma::Animator::self(), SIGNAL(customAnimationFinished(int)),
-		this, SLOT(animationFinished(int)));
-
-	connect(
 		applet, SIGNAL(mouseEnter()),
 		this, SLOT(stopEffect()));
 
 }
 
 SmoothToolTip::~SmoothToolTip() {
-	stopScrollAnimation(true);
+	stopScrollAnimation();
 	m_widget->hide();
 	delete m_widget;
 	m_widget = NULL;
 	if (m_hoverItem.isNull()) {
 		return;
 	}
-	int newPosition = 0;
-	m_widget->adjustSize();
-	QSize newSize(m_widget->frameSize());
-	QPoint pos(m_hoverItem->popupPosition(newSize, true, &newPosition));
-	
-	if (pos == m_widget->pos() && m_scrollAnimation == 0) {
-		if (forceAnimated) {
-			m_shown = true;
-			m_widget->show();
-		}
+
+	Plasma::Corona* corona = qobject_cast<Plasma::Corona*>(m_hoverItem->scene());
+	if (!corona) {
+		kWarning()
+			<< "the following object's scene() is not a Plasma::Corona instance, cannot show tool tip:"
+			<< m_hoverItem;
 		return;
 	}
+	QSize newSize(m_widget->frameSize());
+	QPoint pos = corona->popupPosition(m_hoverItem, newSize, Qt::AlignCenter);
 
-	int xStart = m_widget->x();
-	int yStart = m_widget->y();
+	if (pos == m_widget->pos())
+		return;
 
-	if (m_scrollAnimation && m_moveAnimation) {
-		m_moveAnimationUpdated = true;
-		if (forceAnimated) {
-			m_shown = true;
-			m_widget->show();
-		}
-		return;
-	}
-	
-	if (forceAnimated) {
-		m_moveAnimation = true;
-
-		if (m_position & ToolTipBase::Top) {
-			yStart -= newSize.height() - m_size.height();
-		}
-		else if (m_position & ToolTipBase::Middle) {
-			yStart -= (newSize.height() - m_size.height()) / 2;
-		}
-		int dy = pos.y() - yStart;
-
-		if (m_position & ToolTipBase::Left) {
-			xStart -= newSize.width() - m_size.width();
-		}
-		else if (m_position & ToolTipBase::Center) {
-			xStart -= (newSize.width() - m_size.width()) / 2;
-		}
-		int dx = pos.x() - xStart;
-
-		m_position = newPosition;
-		m_size     = newSize;
-		m_widget->move(xStart, yStart);
-
-		m_shown = true;
-		m_widget->show();
-
-		startScrollAnimation(dx, dy, m_applet->toolTipMoveDuraton());
-	}
-	else {
-		m_position = newPosition;
-		m_size     = newSize;
+	if (forceAnimated || m_scrollAnimation)
+		startScrollAnimation(pos.x() - m_widget->x(), pos.y() - m_widget->y());
+	else
 		m_widget->move(pos);
-	}
 }
 
 void SmoothToolTip::moveTo(WindowPreview *preview, const QPoint& mousePos) {
 		const int bottom       = top + preview->height();
 		
 		if (top < screenTop) {
-			startScrollAnimation(0, screenTop - top - offset.y(), m_applet->toolTipMoveDuraton());
+			startScrollAnimation(0, screenTop - top - offset.y());
 		}
 		else if (bottom > screenBottom) {
-			startScrollAnimation(0, screenBottom - bottom - offset.y(), m_applet->toolTipMoveDuraton());
+			startScrollAnimation(0, screenBottom - bottom - offset.y());
 		}
 		else {
-			startScrollAnimation(0, -offset.y(), m_applet->toolTipMoveDuraton());
+			startScrollAnimation(0, -offset.y());
 		}
 	}
 	else {
 		const int right       = left + preview->width();
 		
 		if (left < screenLeft) {
-			startScrollAnimation(screenLeft - left - offset.x(), 0, m_applet->toolTipMoveDuraton());
+			startScrollAnimation(screenLeft - left - offset.x(), 0);
 		}
 		else if (right > screenRight) {
-			startScrollAnimation(screenRight - right - offset.x(), 0, m_applet->toolTipMoveDuraton());
+			startScrollAnimation(screenRight - right - offset.x(), 0);
 		}
 		else {
-			startScrollAnimation(-offset.x(), 0, m_applet->toolTipMoveDuraton());
+			startScrollAnimation(-offset.x(), 0);
 		}
 	}
 }
 
-void SmoothToolTip::startScrollAnimation(int dx, int dy, int duration) {
-	if (m_scrollAnimation) {
-		Plasma::Animator::self()->stopCustomAnimation(m_scrollAnimation);
-		m_scrollAnimation = 0;
-	}
-
-	int frames = m_applet->fps() * duration / 1000; 
-	m_dx     = dx;
-	m_xStart = m_widget->x();
-	m_dy     = dy;
-	m_yStart = m_widget->y();
-
-	if (frames <= 0) {
-		m_scrollAnimation = 0;
-		animateScroll(1.0);
-		animationFinished(m_scrollAnimation);
-	}
-	else {
-		m_scrollAnimation = Plasma::Animator::self()->customAnimation(
-			frames, duration,
-			Plasma::Animator::LinearCurve,
-			this, "animateScroll");
-	}
+void SmoothToolTip::startScrollAnimation(int dx, int dy) {
+	if (!m_scrollAnimation)
+		m_scrollAnimation = new AnimationThrowPoint(m_widget, "pos", this);
+	else
+		m_scrollAnimation->setTargetObject(m_widget);
+	m_scrollAnimation->setAcceleration(2000.0);  // TODO: make variable
+	m_scrollAnimation->setStartValue(m_widget->pos());
+	m_scrollAnimation->setEndValue(m_widget->pos() + QPoint(dx, dy));
+	m_scrollAnimation->start(QAbstractAnimation::DeleteWhenStopped);
 }
 
-void SmoothToolTip::animationFinished(int animation) {
-	if (animation == m_scrollAnimation) {
-		m_scrollAnimation = 0;
-		m_dx              = 0;
-		m_xStart          = 0;
-		m_dy              = 0;
-		m_yStart          = 0;
-		m_moveAnimation   = false;
-
-		if (m_moveAnimationUpdated) {
-			m_moveAnimationUpdated = false;
-			moveBesideTaskItem(m_shown);
-		}
-	}
-}
-
-void SmoothToolTip::stopScrollAnimation(bool force) {
-	if (force || !m_moveAnimation) {
-		if (m_scrollAnimation) {
-			Plasma::Animator::self()->stopCustomAnimation(m_scrollAnimation);
-		}
-		m_scrollAnimation      = 0;
-		m_dx                   = 0;
-		m_xStart               = 0;
-		m_dy                   = 0;
-		m_yStart               = 0;
-		m_moveAnimation        = false;
-		m_moveAnimationUpdated = false;
-	}
-}
-
-void SmoothToolTip::animateScroll(qreal progress) {
-	int x = m_xStart + (int)(progress * m_dx);
-	int y = m_yStart + (int)(progress * m_dy);
-	m_widget->move(x, y);
-	
-	if (m_moveAnimationUpdated && !m_hoverItem.isNull()) {
-		QPoint pos = m_hoverItem->popupPosition(m_widget->size(), true, NULL);
-	
-		int dx = pos.x() - x;
-		int dy = pos.y() - y;
-
-		if ((dx <= 0.0 && m_dx >= 0.0) || (dx >= 0.0 && m_dx <= 0.0) ||
-			(dy <= 0.0 && m_dy >= 0.0) || (dy >= 0.0 && m_dy <= 0.0)) {
-			stopScrollAnimation(true);
-			moveBesideTaskItem(m_shown);
-		}
-	}
+void SmoothToolTip::stopScrollAnimation() {
+	delete m_scrollAnimation;
+	m_scrollAnimation = 0;
 }
 
 void SmoothToolTip::leave() {
 	m_hover        = false;
 	m_hoverPreview = NULL;
 
-	stopScrollAnimation();
-
 	itemLeave(m_hoverItem);
 }
 
 }
 
 void SmoothToolTip::clear() {
-	stopScrollAnimation(true);
+	stopScrollAnimation();
 
 	Plasma::WindowEffects::showWindowThumbnails(m_widget->winId());
 
 }
 
 void SmoothToolTip::setTasks(TaskManager::ItemList tasks) {
+	QSize oldSize = m_widget->size();
+
 	QBoxLayout *layout = qobject_cast<QBoxLayout*>(m_widget->layout());
 	const int N = tasks.count();
 	int actualWidth  = 0;
 	layout->activate();
 	m_widget->adjustSize();
 	m_previewsUpdated = false;
+
+	// correct position of resized tooltip to prevent overlapping with m_widget
+	QSize newSize = m_widget->size();
+	if (oldSize != newSize) {
+		Plasma::Direction direction = Plasma::Up;
+		Plasma::Containment* c = dynamic_cast<Plasma::Containment*>(m_hoverItem->topLevelItem());
+		if (c) direction = Plasma::locationToDirection(c->location());
+		int deltaX = oldSize.width () - newSize.width ();
+		int deltaY = oldSize.height() - newSize.height();
+		switch (direction) {
+			case Plasma::Down : deltaY  = 0;
+			case Plasma::Up   : deltaX /= 2; break;
+			case Plasma::Right: deltaX  = 0;
+			case Plasma::Left : deltaY /= 2; break;
+		}
+		m_widget->move(m_widget->x() + deltaX, m_widget->y() + deltaY);
+	}
 }
 
 void SmoothToolTip::previewWindowSizeChanged() {

File applet/SmoothTasks/SmoothToolTip.h

 #include <QPaintEvent>
 #include <QEvent>
 #include <QMouseEvent>
+#include <QPointer>
 
 #include <Plasma/FrameSvg>
 
 #include <KWindowSystem>
 #include <NETRootInfo>
 
+#include "SmoothTasks/Animation/AnimationThrowPoint.h"
 #include "SmoothTasks/Applet.h"
 #include "SmoothTasks/DelayedToolTip.h"
 
 namespace SmoothTasks {
 
+class AnimationThrowPoint;
 class WindowPreview;
 class ToolTipWidget;
 class Task;
 	private slots:
 		void updateTheme();
 		void previewLayoutChanged(Applet::PreviewLayoutType previewLayout);
-		void animateScroll(qreal progress);
-		void animationFinished(int animation);
 		void previewWindowSizeChanged();
 		void enterWindowPreview(WindowPreview *preview);
 		void leaveWindowPreview(WindowPreview *preview);
 		void setTasks(TaskManager::ItemList tasks);
 		void clear();
 		void leave();
-		void startScrollAnimation(int dx, int dy, int speed);
-		void stopScrollAnimation(bool force = false);
+		void startScrollAnimation(int dx, int dy);
+		void stopScrollAnimation();
 		void moveTo(WindowPreview *preview, const QPoint& mousePos);
 		void updatePreviews();
 		bool isVertical() const;
 		bool                   m_highlighting;
 
 		// animation:
-		int   m_scrollAnimation;
-		int   m_dx;
-		int   m_xStart;
-		int   m_dy;
-		int   m_yStart;
-		bool  m_moveAnimation;
-		bool  m_moveAnimationUpdated;
-		int   m_position;
-		QSize m_size;
+		QPointer<AnimationThrowPoint> m_scrollAnimation;
 
 		// close icon:
 		QPixmap m_closeIcon;

File applet/SmoothTasks/TaskItem.cpp

 	setGeometry(m_animationDestinationGeometry);
 }
 
-QPoint TaskItem::popupPosition(const QSize& size, bool center, int *toolTipPosition) {
-//	return m_applet->containment()->corona()->popupPosition(this, size);
-	const QRect  geometry(iconGeometry());
-	const QRectF bounds(boundingRect());
-	int x = geometry.left();
-	int y = geometry.top();
-	int toolTipPos = center ?
-		ToolTipBase::Center | ToolTipBase::Middle :
-		ToolTipBase::Right  | ToolTipBase::Top;
-	
-	const QRect currentScreenRect(m_applet->currentScreenGeometry());
-	const int screenLeft   = currentScreenRect.left();
-	const int screenTop    = currentScreenRect.top();
-	const int screenRight  = screenLeft + currentScreenRect.width();
-	const int screenBottom = screenTop  + currentScreenRect.height();
-
-#define SET_VERTICAL(POS) \
-	toolTipPos = (toolTipPos & ToolTipBase::HorizontalMask) | ToolTipBase::POS;
-
-#define SET_HORIZONTAL(POS) \
-	toolTipPos = (toolTipPos & ToolTipBase::VerticalMask)   | ToolTipBase::POS;
-
-	// TODO: maybe don't take location from the applet, like orientation?
-	switch (m_applet->location()) {
-		case Plasma::BottomEdge:
-			if (center) x -= (size.width() - bounds.width()) / 2;
-			y -= size.height();
-			SET_VERTICAL(Top)
-			break;
-		case Plasma::TopEdge:
-			if (center) x -= (size.width() - bounds.width()) / 2;
-			y += bounds.height();
-			SET_VERTICAL(Bottom)
-			break;
-		case Plasma::LeftEdge:
-			x += bounds.width();
-			if (center) y -= (size.height() - bounds.height()) / 2;
-			SET_HORIZONTAL(Right)
-			break;
-		case Plasma::RightEdge:
-			x -= size.width();
-			if (center) y -= (size.height() - bounds.height()) / 2;
-			SET_HORIZONTAL(Left)
-			break;
-		default:
-			if (m_orientation == Qt::Vertical) {
-				if (center) y -= (size.height() - bounds.height()) / 2;
-
-				if (x + size.width() + bounds.width() > screenRight) {
-					x -= size.width();
-					SET_HORIZONTAL(Right)
-				}
-				else {
-					x += bounds.width();
-					SET_HORIZONTAL(Left)
-				}
-			}
-			else {
-				if (center) x -= (size.width() - bounds.width()) / 2;
-
-				if (y - size.height() >= screenTop) {
-					y -= size.height();
-					SET_VERTICAL(Top)
-				}
-				else {
-					y += bounds.height();
-					SET_VERTICAL(Bottom)
-				}
-			}
-	}
-
-	if (m_applet->location() != Plasma::LeftEdge && x + size.width() > screenRight) {
-		x = screenRight - size.width();
-	}
-	
-	if (m_applet->location() != Plasma::RightEdge && x < screenLeft) {
-		x = screenLeft;
-	}
-
-	if (m_applet->location() != Plasma::TopEdge && y + size.height() > screenBottom) {
-		y = screenBottom - size.height();
-	}
-	
-	if (m_applet->location() != Plasma::BottomEdge && y < screenTop) {
-		y = screenTop;
-	}
-
-	if (toolTipPosition) {
-		*toolTipPosition = toolTipPos;
-	}
-
-	return QPoint(x, y);
-}
-
 // XXX: for some reason sometimes this cannot find a parent view when
 //      TaskItem width > heigth and shown in the plasmoidviewer
 QRect TaskItem::iconGeometry() const {

File applet/SmoothTasks/TaskItem.h

 	void setAnimationTargetGeometry(const QRectF& rect);
 	QRectF animationTargetGeometry() const { return m_animationDestinationGeometry; }
 	
-	QPoint popupPosition(const QSize& size, bool center, int *toolTipPosition);
-	
 	QPointF mapFromGlobal(const QPoint& point, bool *contained = NULL) const;
 	
 	QSizeF preferredRdSizeStatic(const qreal maxRdHeight = std::numeric_limits<qreal>::infinity()) const;

File applet/SmoothTasks/ToolTipWidget.cpp

 }
 
 void ToolTipWidget::mouseMoveEvent(QMouseEvent *event) {
-	if (m_toolTip->m_moveAnimation) {
+	if (m_toolTip->m_scrollAnimation) {
 		return;
 	}
 
 		const int screenTop    = screenGeom.top();
 		const int screenBottom = screenTop + screenGeom.height();
 
-		if (m_toolTip->m_dy == 0) {
+		if (!m_toolTip->m_scrollAnimation) {
 			if (y < screenTop && mouseY - ANIMATION_MARGIN <= screenTop) {
 				const int dy = screenTop - y;
-				m_toolTip->startScrollAnimation(0, dy, qAbs(dy) * SCROLL_DURATION);
+				m_toolTip->startScrollAnimation(0, dy);
 			}
 			else if (y + height > screenBottom && mouseY + ANIMATION_MARGIN >= screenBottom) {
 				const int dy = -(y + height - screenBottom);
-				m_toolTip->startScrollAnimation(0, dy, qAbs(dy) * SCROLL_DURATION);
+				m_toolTip->startScrollAnimation(0, dy);
 			}
 		}
 		else if (
 		const int screenLeft  = screenGeom.left();
 		const int screenRight = screenLeft + screenGeom.width();
 
-		if (m_toolTip->m_dx == 0) {
+		if (!m_toolTip->m_scrollAnimation) {
 			if (x < screenLeft && mouseX - ANIMATION_MARGIN <= screenLeft) {
 				const int dx = screenLeft - x;
-				m_toolTip->startScrollAnimation(dx, 0, qAbs(dx) * SCROLL_DURATION);
+				m_toolTip->startScrollAnimation(dx, 0);
 			}
 			else if (x + width > screenRight && mouseX + ANIMATION_MARGIN >= screenRight) {
 				const int dx = -(x + width - screenRight);
-				m_toolTip->startScrollAnimation(dx, 0, qAbs(dx) * SCROLL_DURATION);
+				m_toolTip->startScrollAnimation(dx, 0);
 			}
 		}
 		else if (