Blame style/animations/adwaitatransitionwidget.cpp

Packit 8e9c33
//////////////////////////////////////////////////////////////////////////////
Packit 8e9c33
// adwaitatransitionwidget.cpp
Packit 8e9c33
// stores event filters and maps widgets to transitions for transitions
Packit 8e9c33
// -------------------
Packit 8e9c33
//
Packit 8e9c33
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
Packit 8e9c33
//
Packit 8e9c33
// Permission is hereby granted, free of charge, to any person obtaining a copy
Packit 8e9c33
// of this software and associated documentation files (the "Software"), to
Packit 8e9c33
// deal in the Software without restriction, including without limitation the
Packit 8e9c33
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit 8e9c33
// sell copies of the Software, and to permit persons to whom the Software is
Packit 8e9c33
// furnished to do so, subject to the following conditions:
Packit 8e9c33
//
Packit 8e9c33
// The above copyright notice and this permission notice shall be included in
Packit 8e9c33
// all copies or substantial portions of the Software.
Packit 8e9c33
//
Packit 8e9c33
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 8e9c33
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 8e9c33
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit 8e9c33
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit 8e9c33
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit 8e9c33
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit 8e9c33
// IN THE SOFTWARE.
Packit 8e9c33
//////////////////////////////////////////////////////////////////////////////
Packit 8e9c33
Packit 8e9c33
#include "adwaitatransitionwidget.h"
Packit 8e9c33
Packit 8e9c33
#include <QPainter>
Packit 8e9c33
#include <QPaintEvent>
Packit 8e9c33
#include <QStyleOption>
Packit 8e9c33
#include <QTextStream>
Packit 8e9c33
Packit 8e9c33
namespace Adwaita
Packit 8e9c33
{
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    bool TransitionWidget::_paintEnabled = true;
Packit 8e9c33
    bool TransitionWidget::paintEnabled( void )
Packit 8e9c33
    { return _paintEnabled; }
Packit 8e9c33
Packit 8e9c33
    int TransitionWidget::_steps = 0;
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    TransitionWidget::TransitionWidget( QWidget* parent, int duration ):
Packit 8e9c33
        QWidget( parent ),
Packit 8e9c33
        _animation( new Animation( duration, this ) )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // background flags
Packit 8e9c33
        setAttribute( Qt::WA_NoSystemBackground );
Packit 8e9c33
        setAutoFillBackground( false );
Packit 8e9c33
Packit 8e9c33
        // setup animation
Packit 8e9c33
        _animation.data()->setStartValue( 0 );
Packit 8e9c33
        _animation.data()->setEndValue( 1.0 );
Packit 8e9c33
        _animation.data()->setTargetObject( this );
Packit 8e9c33
        _animation.data()->setPropertyName( "opacity" );
Packit 8e9c33
Packit 8e9c33
        // hide when animation is finished
Packit 8e9c33
        connect( _animation.data(), SIGNAL(finished()), SLOT(hide()) );
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    QPixmap TransitionWidget::grab( QWidget* widget, QRect rect )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // change rect
Packit 8e9c33
        if( !rect.isValid() ) rect = widget->rect();
Packit 8e9c33
        if( !rect.isValid() ) return QPixmap();
Packit 8e9c33
Packit 8e9c33
        // initialize pixmap
Packit 8e9c33
        QPixmap out( rect.size() );
Packit 8e9c33
        out.fill( Qt::transparent );
Packit 8e9c33
        _paintEnabled = false;
Packit 8e9c33
Packit 8e9c33
        if( testFlag( GrabFromWindow ) )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            rect = rect.translated( widget->mapTo( widget->window(), widget->rect().topLeft() ) );
Packit 8e9c33
            widget = widget->window();
Packit 8e9c33
            #if QT_VERSION < 0x050000
Packit 8e9c33
            out = QPixmap::grabWidget( widget, rect );
Packit 8e9c33
            #else
Packit 8e9c33
            out = widget->grab( rect );
Packit 8e9c33
            #endif
Packit 8e9c33
Packit 8e9c33
        } else {
Packit 8e9c33
Packit 8e9c33
            if( !testFlag( Transparent ) ) { grabBackground( out, widget, rect ); }
Packit 8e9c33
            grabWidget( out, widget, rect );
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        _paintEnabled = true;
Packit 8e9c33
Packit 8e9c33
        return out;
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    bool TransitionWidget::event( QEvent* event )
Packit 8e9c33
    {
Packit 8e9c33
        switch( event->type() )
Packit 8e9c33
        {
Packit 8e9c33
            case QEvent::MouseButtonPress:
Packit 8e9c33
            case QEvent::MouseButtonRelease:
Packit 8e9c33
            case QEvent::KeyPress:
Packit 8e9c33
            case QEvent::KeyRelease:
Packit 8e9c33
            endAnimation();
Packit 8e9c33
            hide();
Packit 8e9c33
            event->ignore();
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
            default: return QWidget::event( event );
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    void TransitionWidget::paintEvent( QPaintEvent* event )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // fully transparent case
Packit 8e9c33
        if( opacity() >= 1.0 && endPixmap().isNull() ) return;
Packit 8e9c33
        if( !_paintEnabled ) return;
Packit 8e9c33
Packit 8e9c33
        // get rect
Packit 8e9c33
        QRect rect = event->rect();
Packit 8e9c33
        if( !rect.isValid() ) rect = this->rect();
Packit 8e9c33
Packit 8e9c33
        // local pixmap
Packit 8e9c33
        bool paintOnWidget( testFlag( PaintOnWidget ) && !testFlag( Transparent ) );
Packit 8e9c33
        if( !paintOnWidget )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            if( _currentPixmap.isNull() || _currentPixmap.size() != size() )
Packit 8e9c33
            { _currentPixmap = QPixmap( size() ); }
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        // fill
Packit 8e9c33
        _currentPixmap.fill( Qt::transparent );
Packit 8e9c33
Packit 8e9c33
        // copy local pixmap to current
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            QPainter p;
Packit 8e9c33
Packit 8e9c33
            // draw end pixmap first, provided that opacity is small enough
Packit 8e9c33
            if( opacity() >= 0.004 && !_endPixmap.isNull() )
Packit 8e9c33
            {
Packit 8e9c33
Packit 8e9c33
                // faded endPixmap if parent target is transparent and opacity is
Packit 8e9c33
                if( opacity() <= 0.996 && testFlag( Transparent ) )
Packit 8e9c33
                {
Packit 8e9c33
Packit 8e9c33
                    fade( _endPixmap, _currentPixmap, opacity(), rect );
Packit 8e9c33
                    p.begin( &_currentPixmap );
Packit 8e9c33
                    p.setClipRect( event->rect() );
Packit 8e9c33
Packit 8e9c33
                } else {
Packit 8e9c33
Packit 8e9c33
                    if( paintOnWidget ) p.begin( this );
Packit 8e9c33
                    else p.begin( &_currentPixmap );
Packit 8e9c33
                    p.setClipRect( event->rect() );
Packit 8e9c33
                    p.drawPixmap( QPoint(), _endPixmap );
Packit 8e9c33
Packit 8e9c33
                }
Packit 8e9c33
Packit 8e9c33
            } else {
Packit 8e9c33
Packit 8e9c33
                if( paintOnWidget ) p.begin( this );
Packit 8e9c33
                else p.begin( &_currentPixmap );
Packit 8e9c33
                p.setClipRect( event->rect() );
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            // draw fading start pixmap
Packit 8e9c33
            if( opacity() <= 0.996 && !_startPixmap.isNull() )
Packit 8e9c33
            {
Packit 8e9c33
                if( opacity() >= 0.004 )
Packit 8e9c33
                {
Packit 8e9c33
Packit 8e9c33
                    fade( _startPixmap, _localStartPixmap, 1.0-opacity(), rect );
Packit 8e9c33
                    p.drawPixmap( QPoint(), _localStartPixmap );
Packit 8e9c33
Packit 8e9c33
                } else p.drawPixmap( QPoint(), _startPixmap );
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            p.end();
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        // copy current pixmap on widget
Packit 8e9c33
        if( !paintOnWidget )
Packit 8e9c33
        {
Packit 8e9c33
            QPainter p( this );
Packit 8e9c33
            p.setClipRect( event->rect() );
Packit 8e9c33
            p.drawPixmap( QPoint(0,0), _currentPixmap );
Packit 8e9c33
            p.end();
Packit 8e9c33
        }
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    void TransitionWidget::grabBackground( QPixmap& pixmap, QWidget* widget, QRect& rect ) const
Packit 8e9c33
    {
Packit 8e9c33
        if( !widget ) return;
Packit 8e9c33
Packit 8e9c33
        QWidgetList widgets;
Packit 8e9c33
        if( widget->autoFillBackground() )
Packit 8e9c33
        { widgets.append( widget ); }
Packit 8e9c33
Packit 8e9c33
        QWidget *parent(0);
Packit 8e9c33
Packit 8e9c33
        // get highest level parent
Packit 8e9c33
        for( parent = widget->parentWidget(); parent; parent = parent->parentWidget() )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            if( !( parent->isVisible() && parent->rect().isValid() ) ) continue;
Packit 8e9c33
Packit 8e9c33
            // store in list
Packit 8e9c33
            widgets.append( parent );
Packit 8e9c33
Packit 8e9c33
            // stop at topLevel
Packit 8e9c33
            if( parent->isTopLevel() || parent->autoFillBackground() ) break;
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        if( !parent ) parent = widget;
Packit 8e9c33
Packit 8e9c33
        // painting
Packit 8e9c33
        QPainter p(&pixmap);
Packit 8e9c33
        p.setClipRect( rect );
Packit 8e9c33
        QBrush backgroundBrush = parent->palette().brush( parent->backgroundRole());
Packit 8e9c33
        if( backgroundBrush.style() == Qt::TexturePattern)
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            p.drawTiledPixmap( rect, backgroundBrush.texture(), widget->mapTo( parent, rect.topLeft() ) );
Packit 8e9c33
Packit 8e9c33
        } else {
Packit 8e9c33
Packit 8e9c33
            p.fillRect( pixmap.rect(), backgroundBrush );
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        if( parent->isTopLevel() && parent->testAttribute(Qt::WA_StyledBackground))
Packit 8e9c33
        {
Packit 8e9c33
            QStyleOption option;
Packit 8e9c33
            option.initFrom(parent);
Packit 8e9c33
            option.rect = rect;
Packit 8e9c33
            option.rect.translate( widget->mapTo( parent, rect.topLeft() ) );
Packit 8e9c33
            p.translate(-option.rect.topLeft());
Packit 8e9c33
            parent->style()->drawPrimitive ( QStyle::PE_Widget, &option, &p, parent );
Packit 8e9c33
            p.translate(option.rect.topLeft());
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        // draw all widgets in parent list
Packit 8e9c33
        // backward
Packit 8e9c33
        QPaintEvent event(rect);
Packit 8e9c33
        for( int i = widgets.size() - 1; i>=0; i-- )
Packit 8e9c33
        {
Packit 8e9c33
            QWidget* w = widgets.at(i);
Packit 8e9c33
            w->render( &p, -widget->mapTo( w, rect.topLeft() ), rect, 0 );
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        // end
Packit 8e9c33
        p.end();
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    void TransitionWidget::grabWidget( QPixmap& pixmap, QWidget* widget, QRect& rect ) const
Packit 8e9c33
    { widget->render( &pixmap, pixmap.rect().topLeft(), rect, QWidget::DrawChildren ); }
Packit 8e9c33
Packit 8e9c33
    //________________________________________________
Packit 8e9c33
    void TransitionWidget::fade( const QPixmap& source, QPixmap& target, qreal opacity, const QRect& rect ) const
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        if( target.isNull() || target.size() != size() )
Packit 8e9c33
        { target = QPixmap( size() ); }
Packit 8e9c33
Packit 8e9c33
        // erase target
Packit 8e9c33
        target.fill( Qt::transparent );
Packit 8e9c33
Packit 8e9c33
        // check opacity
Packit 8e9c33
        if( opacity*255 < 1 ) return;
Packit 8e9c33
Packit 8e9c33
        QPainter p( &target );
Packit 8e9c33
        p.setClipRect( rect );
Packit 8e9c33
Packit 8e9c33
        // draw pixmap
Packit 8e9c33
        p.drawPixmap( QPoint(0,0), source );
Packit 8e9c33
Packit 8e9c33
        // opacity mask (0.996 corresponds to 254/255)
Packit 8e9c33
        if( opacity <= 0.996 )
Packit 8e9c33
        {
Packit 8e9c33
            p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
Packit 8e9c33
            QColor color( Qt::black );
Packit 8e9c33
            color.setAlphaF( opacity );
Packit 8e9c33
            p.fillRect(rect, color );
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        p.end();
Packit 8e9c33
        return;
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
}