
//  Copyright (C) 2009 by Arnaud Dupuis
//  a.dupuis@infinityperl.org
//  http://www.infinityperl.org
// 
//  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 3 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.,
//  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

#ifndef ASSUMA_EFFECT
#define ASSUMA_EFFECT

#include <QTransform>
#include <QTimeLine>
#include <QWidget>
#include <QObject>
/*! \class AssumaEffect
* \brief A class to display graphical effect.
*
* This class is the one used to show widgets with effects (like the sliding information popup, the moving widget, etc.)
* Supported effects are regrouped in the \sa Effects enum.
* \attention This API is fairly new and is likely to change without any notifications !
*/
class AssumaEffect : public QObject {
	Q_OBJECT
	signals:
		/*!
		* This signal is emitted when an effect finish.
		* \attention in the specific case of the SLIM_VERTICALLY effect, the widget is resized to its original height right after this signal is emitted. 
		* \attention This behavior may change in the futur.
		*/
		void AssumaEffectFinished();
		void AssumaEffectWasUpdated();
	public:
		//! Effects enum
                /*! This enum contains the effects supported by this class.
		\attention during GROW_VERTICALLY and SLIM_VERTICALLY effects the widget is moved to make the effect look like the widget grow (or shrink) from/to the bottom of the window.
		\attention Unlike (SLIM|GROW)_VERTICALLY the widget is not moved during the SHRINK_VERTICALLY and EXPAND_VERTICALLY effects. The visual difference is : in this case widget will grow/shrink to/from the top of the window.
                */
		enum Effects {
			SLIDE_FROM_BOTTOM,/*!< Widget slide from the bottom of its parent widget (x coordinate remains untouched). */
			GROW_VERTICALLY, /*!< Widget grow (in height) from 0 pixel to its original height. Effect is done in 500ms. */
			SLIM_VERTICALLY,/*!< Widget shrink vertically (in height) from its original size to 0. Effect is done in 500ms. \sa effectFinished()*/
			SHRINK_VERTICALLY, /*!< Widget shrink vertically from its original width to width - vSizeDelta(). Effect is done in 500ms.*/
			EXPAND_VERTICALLY, /*!< Widget expand vertically from its original height to height + vSizeDelta(). Effect is done in 500ms.*/
			SHRINK_HORIZONTALLY, /*!< Widget shrink horizontally from its original width to width - vSizeDelta(). Effect is done in 250ms.*/
			EXPAND_HORIZONTALLY, /*!< Widget expand horizontally from its original height to width + vSizeDelta(). Effect is done in 250ms.*/
		};
		//! Constructor
		/*!
		The constructor of the effect manager.
		\param parent the parent widget. (optional)
		\param widget the widget on which the effect will be applied (optional, but strongly advised !)
		\param effect the effect to apply (optional, default is SLIDE_FROM_BOTTOM)
		*/
		AssumaEffect( QObject *parent = 0, QWidget *widget = 0, Effects effect = SLIDE_FROM_BOTTOM);
		/*!
		* Return the current effect.
		* \return the current effect
		*/
		Effects currentEffect();
		/*!
		* Return the currently managed widget.
		* \return the current widget
		* \sa setEffect()
		*/
		QWidget* widget();
		/*!
		* Return true if the effect is going to reverse (apply opposite effect to return to initial state) and false otherwise.
		* \return a boolean
		* \sa timeBeforeReversing(), setReversing()
		*/
		bool isReversing();
		/*!
		* If the effect is set to reverse (with setReversing(true)), this function returns the time this effect manager will wait before reversing the effect.
		* \return a boolean
		* \sa isReversing(), setReversing()
		*/
		int timeBeforeReversing();
		/*!
		* Return the vertical size delta between the widget's size before the effect and the widget's size after the effect.
		* SHRINK_* will substract this value to the widget's size.
		* EXPAND_* will add this value to the widget's size.
		* \return the current widget
		* \sa setVSizeDelta()
		*/
		int vSizeDelta();
		/*!
		* Return true if the effect was cancelled, false otherwise.
		* \return a boolean
		* \sa cancel()
		*/
		bool wasCancelled();
	public slots:
		/*!
		* Set the current effect.
		* \code 
		* AssumaEffect *effect = new AssumaEffect(0,widget);
		* effect->setEffect( AssumaEffect::GROW_VERTICALLY );
		* \endcode
		* \param effect_name the effect to do.
		* \sa Effects
		*/
		void setEffect(Effects);
		/*!
		* Start an effect. While an effect run, it can be cancelled by calling the cancel() slot.
		* When the effect finish, it send the effectFinished() signal.
		* An effect can be reverse by calling the reverseEffect() slot. Default behavior is to reverse an effect (unless you call setReversing() to disablethe reversing).
		* \sa effectFinished(), reverseEffect(), setReversing()
		*/
		void doEffect();
		/*!
		* Reverse an effect. This slot is most likely to be called on an effect which have already ran to put the widget back to its initial state.
		* It is not forbidden to run reverseEffect() without prior call to doEffect() but strange behavior are to be expected !
		* Once an effect finish, the effectFinished() signal is emitted.
		* \sa doEffect();
		*/
		void reverseEffect();
		/*!
		* set the widget to transform with an effect.
		* \param widget the widget to apply the effect on.
		* \sa widget()
		*/
		void setWidget( QWidget * );
		/*!
		* Tell AssumaEffect if an effect is to be reversed or not. Default is true.
		* If you want to show a widget with an effect instead of just using its show() or setVisible() slots, you might want to call 
		* \code effect->setReversing(false) \endcode
		* before doEffect().
		* \param rev a boolean.
		* \sa isReversing()
		*/
		void setReversing( bool );
		/*!
		* If the effect is to be reversed automatically, it will wait for a certain time before calling reverseEffect().
		* You can set this delay by calling this slot. Time is set in milliseconds
		* \param time time to wait before reversing.
		* \sa timeBeforeReversing()
		*/
		void setTimeBeforeReversing(int);
		/*!
		* Some effect (like SHRINK_VERTICALLY or EXPAND_VERTICALLY) modify the size of a widget by a vertical delta (add or remove this delta to the widget's height).
		* This slot allow you to set this delta.
		* \param delta size (in pixel) to add or remove to the widget during an effect.
		* \sa vSizeDelta()
		*/
		void setVSizeDelta(int);
		/*!
		* Cancel the current effect. A cancelled effect cannot be "un-cancelled", you will have to create a new AssumaEffect object.
		* \sa wasCancelled()
		*/
		void cancel();
	private slots:
		void updateEffect(int);
		void effectFinished();
	private:
		Effects m_effect;
		QWidget *m_widget;
		QTimeLine *m_timeLine;
		QTransform *m_transform;
		bool m_reversing;
		bool m_closeWidgetOnFinish;
		bool m_wasCancelled;
		int m_timeBeforeReversing;
		int m_vSizeDelta;
		int e_INIT_HEIGHT;
		int e_INIT_WIDTH;
		int e_INIT_XPOS;
		int e_INIT_YPOS;
		
};

#endif
