Blame style/adwaitasplitterproxy.cpp

Packit 8e9c33
/*************************************************************************
Packit 8e9c33
 * Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr>    *
Packit 8e9c33
 *                                                                       *
Packit 8e9c33
 * This program is free software; you can redistribute it and/or modify  *
Packit 8e9c33
 * it under the terms of the GNU General Public License as published by  *
Packit 8e9c33
 * the Free Software Foundation; either version 2 of the License, or     *
Packit 8e9c33
 * (at your option) any later version.                                   *
Packit 8e9c33
 *                                                                       *
Packit 8e9c33
 * This program is distributed in the hope that it will be useful,       *
Packit 8e9c33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
Packit 8e9c33
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
Packit 8e9c33
 * GNU General Public License for more details.                          *
Packit 8e9c33
 *                                                                       *
Packit 8e9c33
 * You should have received a copy of the GNU General Public License     *
Packit 8e9c33
 * along with this program; if not, write to the                         *
Packit 8e9c33
 * Free Software Foundation, Inc.,                                       *
Packit 8e9c33
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
Packit 8e9c33
 *************************************************************************/
Packit 8e9c33
Packit 8e9c33
#include "adwaitasplitterproxy.h"
Packit 8e9c33
Packit 8e9c33
#include "adwaita.h"
Packit 8e9c33
#include "fakeadwaitastyleconfigdata.h"
Packit 8e9c33
Packit 8e9c33
#include <QCoreApplication>
Packit 8e9c33
#include <QDebug>
Packit 8e9c33
#include <QPainter>
Packit 8e9c33
Packit 8e9c33
namespace Adwaita
Packit 8e9c33
{
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    void SplitterFactory::setEnabled( bool value )
Packit 8e9c33
    {
Packit 8e9c33
        if( _enabled != value )
Packit 8e9c33
        {
Packit 8e9c33
            // store
Packit 8e9c33
            _enabled = value;
Packit 8e9c33
Packit 8e9c33
            // assign to existing splitters
Packit 8e9c33
            for( WidgetMap::iterator iter = _widgets.begin(); iter != _widgets.end(); ++iter )
Packit 8e9c33
            { if( iter.value() ) iter.value().data()->setEnabled( value ); }
Packit 8e9c33
        }
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    bool SplitterFactory::registerWidget( QWidget *widget )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // check widget type
Packit 8e9c33
        if( qobject_cast<QMainWindow*>( widget ) )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            WidgetMap::iterator iter( _widgets.find( widget ) );
Packit 8e9c33
            if( iter == _widgets.end() || !iter.value() )
Packit 8e9c33
            {
Packit 8e9c33
                widget->installEventFilter( &_addEventFilter );
Packit 8e9c33
                SplitterProxy* proxy( new SplitterProxy( widget, _enabled ) );
Packit 8e9c33
                widget->removeEventFilter( &_addEventFilter );
Packit 8e9c33
Packit 8e9c33
                widget->installEventFilter( proxy );
Packit 8e9c33
                _widgets.insert( widget, proxy );
Packit 8e9c33
Packit 8e9c33
            } else {
Packit 8e9c33
Packit 8e9c33
                widget->removeEventFilter( iter.value().data() );
Packit 8e9c33
                widget->installEventFilter( iter.value().data() );
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            return true;
Packit 8e9c33
Packit 8e9c33
        } else if( qobject_cast<QSplitterHandle*>( widget ) ) {
Packit 8e9c33
Packit 8e9c33
            QWidget* window( widget->window() );
Packit 8e9c33
            WidgetMap::iterator iter( _widgets.find( window ) );
Packit 8e9c33
            if( iter == _widgets.end() || !iter.value() )
Packit 8e9c33
            {
Packit 8e9c33
Packit 8e9c33
Packit 8e9c33
                window->installEventFilter( &_addEventFilter );
Packit 8e9c33
                SplitterProxy* proxy( new SplitterProxy( window, _enabled ) );
Packit 8e9c33
                window->removeEventFilter( &_addEventFilter );
Packit 8e9c33
Packit 8e9c33
                widget->installEventFilter( proxy );
Packit 8e9c33
                _widgets.insert( window, proxy );
Packit 8e9c33
Packit 8e9c33
            } else {
Packit 8e9c33
Packit 8e9c33
                widget->removeEventFilter( iter.value().data() );
Packit 8e9c33
                widget->installEventFilter( iter.value().data() );
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            return true;
Packit 8e9c33
Packit 8e9c33
        } else return false;
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    void SplitterFactory::unregisterWidget( QWidget *widget )
Packit 8e9c33
    {
Packit 8e9c33
        WidgetMap::iterator iter( _widgets.find( widget ) );
Packit 8e9c33
        if( iter != _widgets.end() )
Packit 8e9c33
        {
Packit 8e9c33
            if( iter.value() ) iter.value().data()->deleteLater();
Packit 8e9c33
            _widgets.erase( iter );
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    SplitterProxy::SplitterProxy( QWidget* parent, bool enabled ):
Packit 8e9c33
        QWidget( parent ),
Packit 8e9c33
        _enabled( enabled ),
Packit 8e9c33
        _timerId( 0 )
Packit 8e9c33
    {
Packit 8e9c33
        setAttribute( Qt::WA_TranslucentBackground, true );
Packit 8e9c33
        setAttribute( Qt::WA_OpaquePaintEvent, false );
Packit 8e9c33
        hide();
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    SplitterProxy::~SplitterProxy( void )
Packit 8e9c33
    {}
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    void SplitterProxy::setEnabled( bool value )
Packit 8e9c33
    {
Packit 8e9c33
        // make sure status has changed
Packit 8e9c33
        if( _enabled != value )
Packit 8e9c33
        {
Packit 8e9c33
            _enabled = value;
Packit 8e9c33
            if( _enabled ) clearSplitter();
Packit 8e9c33
        }
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    bool SplitterProxy::eventFilter( QObject* object, QEvent* event )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // do nothing if disabled
Packit 8e9c33
        if( !_enabled ) return false;
Packit 8e9c33
Packit 8e9c33
        // do nothing in case of mouse grab
Packit 8e9c33
        if( mouseGrabber() ) return false;
Packit 8e9c33
Packit 8e9c33
        switch( event->type() )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            case QEvent::HoverEnter:
Packit 8e9c33
            if( !isVisible() )
Packit 8e9c33
            {
Packit 8e9c33
Packit 8e9c33
                // cast to splitter handle
Packit 8e9c33
                if( QSplitterHandle* handle = qobject_cast<QSplitterHandle*>( object ) )
Packit 8e9c33
                { setSplitter( handle ); }
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
            case QEvent::HoverMove:
Packit 8e9c33
            case QEvent::HoverLeave:
Packit 8e9c33
            return isVisible() && object == _splitter.data();
Packit 8e9c33
Packit 8e9c33
            case QEvent::MouseMove:
Packit 8e9c33
            case QEvent::Timer:
Packit 8e9c33
            case QEvent::Move:
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
            case QEvent::CursorChange:
Packit 8e9c33
            if( QWidget *window = qobject_cast<QMainWindow*>( object ) )
Packit 8e9c33
            {
Packit 8e9c33
                if( window->cursor().shape() == Qt::SplitHCursor || window->cursor().shape() == Qt::SplitVCursor )
Packit 8e9c33
                { setSplitter( window ); }
Packit 8e9c33
            }
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
            case QEvent::WindowDeactivate:
Packit 8e9c33
            case QEvent::MouseButtonRelease:
Packit 8e9c33
            clearSplitter();
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
            default:
Packit 8e9c33
            return false;
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    bool SplitterProxy::event( QEvent *event )
Packit 8e9c33
    {
Packit 8e9c33
        switch( event->type() )
Packit 8e9c33
        {
Packit 8e9c33
Packit 8e9c33
            #if 0
Packit 8e9c33
            case QEvent::Paint:
Packit 8e9c33
            {
Packit 8e9c33
                QPainter painter( this );
Packit 8e9c33
                painter.setClipRegion( static_cast<QPaintEvent*>( event )->region() );
Packit 8e9c33
                painter.setRenderHints( QPainter::Antialiasing );
Packit 8e9c33
                painter.setPen( Qt::red );
Packit 8e9c33
                painter.drawRect( QRectF( rect() ).adjusted( 0.5, 0.5, -0.5, -0.5 ) );
Packit 8e9c33
                return true;
Packit 8e9c33
            }
Packit 8e9c33
            #endif
Packit 8e9c33
Packit 8e9c33
            case QEvent::MouseMove:
Packit 8e9c33
            case QEvent::MouseButtonPress:
Packit 8e9c33
            case QEvent::MouseButtonRelease:
Packit 8e9c33
            {
Packit 8e9c33
Packit 8e9c33
                // check splitter
Packit 8e9c33
                if( !_splitter ) return false;
Packit 8e9c33
Packit 8e9c33
                event->accept();
Packit 8e9c33
Packit 8e9c33
                // grab on mouse press
Packit 8e9c33
                if( event->type() == QEvent::MouseButtonPress)
Packit 8e9c33
                {
Packit 8e9c33
                    grabMouse();
Packit 8e9c33
                    resize(1,1);
Packit 8e9c33
                }
Packit 8e9c33
Packit 8e9c33
                // cast to mouse event
Packit 8e9c33
                QMouseEvent *mouseEvent( static_cast<QMouseEvent*>( event ) );
Packit 8e9c33
Packit 8e9c33
                // get relevant position to post mouse drag event to application
Packit 8e9c33
                if( event->type() == QEvent::MouseButtonPress )
Packit 8e9c33
                {
Packit 8e9c33
Packit 8e9c33
                    // use hook, to make sure splitter is properly dragged
Packit 8e9c33
                    QMouseEvent copy(
Packit 8e9c33
                        mouseEvent->type(),
Packit 8e9c33
                        _hook,
Packit 8e9c33
                        _splitter.data()->mapToGlobal(_hook),
Packit 8e9c33
                        mouseEvent->button(),
Packit 8e9c33
                        mouseEvent->buttons(), mouseEvent->modifiers());
Packit 8e9c33
Packit 8e9c33
                    QCoreApplication::sendEvent( _splitter.data(), &copy );
Packit 8e9c33
Packit 8e9c33
                } else {
Packit 8e9c33
Packit 8e9c33
                    // map event position to current splitter and post.
Packit 8e9c33
                   QMouseEvent copy(
Packit 8e9c33
                        mouseEvent->type(),
Packit 8e9c33
                        _splitter.data()->mapFromGlobal( mouseEvent->globalPos() ),
Packit 8e9c33
                        mouseEvent->globalPos(),
Packit 8e9c33
                        mouseEvent->button(),
Packit 8e9c33
                        mouseEvent->buttons(), mouseEvent->modifiers());
Packit 8e9c33
Packit 8e9c33
                    QCoreApplication::sendEvent( _splitter.data(), &copy );
Packit 8e9c33
Packit 8e9c33
Packit 8e9c33
                }
Packit 8e9c33
Packit 8e9c33
                // release grab on mouse-Release
Packit 8e9c33
                if( event->type() == QEvent::MouseButtonRelease && mouseGrabber() == this )
Packit 8e9c33
                { releaseMouse(); }
Packit 8e9c33
Packit 8e9c33
                return true;
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            case QEvent::Timer:
Packit 8e9c33
            if( static_cast<QTimerEvent*>( event )->timerId() != _timerId )
Packit 8e9c33
            { return QWidget::event( event ); }
Packit 8e9c33
Packit 8e9c33
            /*
Packit 8e9c33
            Fall through is intended.
Packit 8e9c33
            We somehow lost a QEvent::Leave before timeout. We fix it from here
Packit 8e9c33
            */
Packit 8e9c33
Packit 8e9c33
            case QEvent::HoverLeave:
Packit 8e9c33
            case QEvent::Leave:
Packit 8e9c33
            {
Packit 8e9c33
Packit 8e9c33
                if( mouseGrabber() == this )
Packit 8e9c33
                { return true; }
Packit 8e9c33
Packit 8e9c33
                // reset splitter
Packit 8e9c33
                if( isVisible() && !rect().contains( mapFromGlobal( QCursor::pos() ) ) )
Packit 8e9c33
                { clearSplitter(); }
Packit 8e9c33
                return true;
Packit 8e9c33
Packit 8e9c33
            }
Packit 8e9c33
Packit 8e9c33
            default:
Packit 8e9c33
            return QWidget::event( event );
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    void SplitterProxy::setSplitter( QWidget* widget )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // check if changed
Packit 8e9c33
        if( _splitter.data() == widget ) return;
Packit 8e9c33
Packit 8e9c33
        // get cursor position
Packit 8e9c33
        QPoint position( QCursor::pos() );
Packit 8e9c33
Packit 8e9c33
        // store splitter and hook
Packit 8e9c33
        _splitter = widget;
Packit 8e9c33
        _hook = _splitter.data()->mapFromGlobal( position );
Packit 8e9c33
Packit 8e9c33
        // adjust rect
Packit 8e9c33
        QRect rect( 0, 0, 2*StyleConfigData::splitterProxyWidth(), 2*StyleConfigData::splitterProxyWidth() );
Packit 8e9c33
        rect.moveCenter( parentWidget()->mapFromGlobal( position ) );
Packit 8e9c33
        setGeometry( rect );
Packit 8e9c33
        setCursor( _splitter.data()->cursor().shape() );
Packit 8e9c33
Packit 8e9c33
        // show
Packit 8e9c33
        raise();
Packit 8e9c33
        show();
Packit 8e9c33
Packit 8e9c33
        // timer used to automatically hide proxy in case leave events are lost
Packit 8e9c33
        if( !_timerId ) _timerId = startTimer(150);
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
Packit 8e9c33
    //____________________________________________________________________
Packit 8e9c33
    void SplitterProxy::clearSplitter( void )
Packit 8e9c33
    {
Packit 8e9c33
Packit 8e9c33
        // check if changed
Packit 8e9c33
        if( !_splitter ) return;
Packit 8e9c33
Packit 8e9c33
        // release mouse
Packit 8e9c33
        if( mouseGrabber() == this ) releaseMouse();
Packit 8e9c33
Packit 8e9c33
        // hide
Packit 8e9c33
        parentWidget()->setUpdatesEnabled(false);
Packit 8e9c33
        hide();
Packit 8e9c33
        parentWidget()->setUpdatesEnabled(true);
Packit 8e9c33
Packit 8e9c33
        // send hover event
Packit 8e9c33
        if( _splitter )
Packit 8e9c33
        {
Packit 8e9c33
            QHoverEvent hoverEvent(
Packit 8e9c33
                qobject_cast<QSplitterHandle*>(_splitter.data()) ? QEvent::HoverLeave : QEvent::HoverMove,
Packit 8e9c33
                _splitter.data()->mapFromGlobal(QCursor::pos()), _hook);
Packit 8e9c33
            QCoreApplication::sendEvent( _splitter.data(), &hoverEvent );
Packit 8e9c33
            _splitter.clear();
Packit 8e9c33
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
        // kill timer if any
Packit 8e9c33
        if( _timerId )
Packit 8e9c33
        {
Packit 8e9c33
            killTimer( _timerId );
Packit 8e9c33
            _timerId = 0;
Packit 8e9c33
        }
Packit 8e9c33
Packit 8e9c33
    }
Packit 8e9c33
Packit 8e9c33
}