#ifndef oxygentransitionwidget_h
#define oxygentransitionwidget_h
//////////////////////////////////////////////////////////////////////////////
// oxygentransitionwidget.h
// stores event filters and maps widgets to transitions for transitions
// -------------------
//
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////

#include "oxygenanimation.h"

#include <QtCore/QWeakPointer>
#include <QtGui/QWidget>

#include <cmath>

namespace Oxygen
{

    //! temporary widget used to perform smooth transition between one widget state and another
    class TransitionWidget: public QWidget
    {

        Q_OBJECT

        //! declare opacity property
        Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity )

        public:

        //! shortcut to painter
        typedef QWeakPointer<TransitionWidget> Pointer;

        //! constructor
        TransitionWidget( QWidget* parent, int duration );

        //! destructor
        virtual ~TransitionWidget( void )
        {}

        //!@name flags
        //@{
        enum Flag
        {
            None = 0,
            GrabFromWindow = 1<<0,
            Transparent = 1<<1,
            PaintOnWidget = 1<<2
        };

        Q_DECLARE_FLAGS(Flags, Flag)

        void setFlags( Flags value )
        { flags_ = value; }

        void setFlag( Flag flag, bool value = true )
        {
            if( value ) flags_ |= flag;
            else flags_ &= (~flag);
        }

        bool testFlag( Flag flag ) const
        { return flags_.testFlag( flag ); }

        //@}

        //! duration
        void setDuration( int duration )
        {
            if( animation_ )
            { animation_.data()->setDuration( duration ); }
        }

        //! duration
        int duration( void ) const
        { return ( animation_ ) ? animation_.data()->duration() : 0; }

        //! steps
        static void setSteps( int value )
        { steps_ = value; }

        //!@name opacity
        //@{

        virtual qreal opacity( void ) const
        { return opacity_; }

        virtual void setOpacity( qreal value )
        { opacity_ = digitize( value ); }

        //@}

        //@name pixmaps handling
        //@{

        //! start
        void resetStartPixmap( void )
        { setStartPixmap( QPixmap() ); }

        //! start
        void setStartPixmap( QPixmap pixmap )
        { startPixmap_ = pixmap; }

        //! start
        const QPixmap& startPixmap( void ) const
        { return startPixmap_; }

        //! end
        void resetEndPixmap( void )
        { setEndPixmap( QPixmap() ); }

        //! end
        void setEndPixmap( QPixmap pixmap )
        {
            endPixmap_ = pixmap;
            currentPixmap_ = pixmap;
        }

        //! start
        const QPixmap& endPixmap( void ) const
        { return endPixmap_; }

        //! current
        const QPixmap& currentPixmap( void ) const
        { return currentPixmap_; }

        //@}

        //! grap pixmap
        QPixmap grab( QWidget* = 0, QRect = QRect() );

        //! true if animated
        virtual bool isAnimated( void ) const
        { return animation_.data()->isRunning(); }

        //! end animation
        virtual void endAnimation( void )
        { if( animation_.data()->isRunning() ) animation_.data()->stop(); }

        //! animate transition
        virtual void animate( void )
        {
            endAnimation();
            animation_.data()->start();
        }

        //! true if paint is enabled
        static bool paintEnabled( void );

        signals:

        //! emmitted when animation is finished/aborder
        void finished( void );

        protected slots:

        /*! allows to trigger widget update in specified QRect only */
        virtual void setDirty( void )
        { update(); }

        protected:

        //! paint event
        virtual void paintEvent( QPaintEvent* );

        //! grab widget background
        /*!
        Background is not rendered properly using QWidget::render.
        Use home-made grabber instead. This is directly inspired from bespin.
        Copyright (C) 2007 Thomas Luebking <thomas.luebking@web.de>
        */
        virtual void grabBackground( QPixmap&, QWidget*, QRect& ) const;

        //! grab widget
        virtual void grabWidget( QPixmap&, QWidget*, QRect& ) const;

        //! fade pixmap
        virtual void fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& ) const;

        //! apply step
        virtual qreal digitize( const qreal& value ) const
        {
            if( steps_ > 0 ) return std::floor( value*steps_ )/steps_;
            else return value;
        }

        private:

        //! Flags
        Flags flags_;

        //! paint enabled
        static bool paintEnabled_;

        //! internal transition animation
        Animation::Pointer animation_;

        //! animation starting pixmap
        QPixmap startPixmap_;

        //! animation starting pixmap
        QPixmap endPixmap_;

        //! local start pixmap (used for fading)
        QPixmap localStartPixmap_;

        //! local end pixmap (used for fading)
        QPixmap localEndPixmap_;

        //! current pixmap
        QPixmap currentPixmap_;

        //! current state opacity
        qreal opacity_;

        //! steps
        static int steps_;

    };

}

#endif
