Skip to content
Snippets Groups Projects
qwt_arrow_button.cpp 8.13 KiB
Newer Older
  • Learn to ignore specific revisions
  • pixhawk's avatar
    pixhawk committed
    /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
     * Qwt Widget Library
     * Copyright (C) 1997   Josef Wilgen
     * Copyright (C) 2002   Uwe Rathmann
    
    pixhawk's avatar
    pixhawk committed
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the Qwt License, Version 1.0
     *****************************************************************************/
    
    
    Bryant's avatar
    Bryant committed
    #include "qwt_arrow_button.h"
    #include "qwt_math.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <qpainter.h>
    #include <qstyle.h>
    
    Bryant's avatar
    Bryant committed
    #include <qstyleoption.h>
    
    pixhawk's avatar
    pixhawk committed
    #include <qevent.h>
    
    Bryant's avatar
    Bryant committed
    #include <qapplication.h>
    
    pixhawk's avatar
    pixhawk committed
    
    static const int MaxNum = 3;
    static const int Margin = 2;
    static const int Spacing = 1;
    
    class QwtArrowButton::PrivateData
    {
    public:
        int num;
        Qt::ArrowType arrowType;
    };
    
    
    Bryant's avatar
    Bryant committed
    static QStyleOptionButton styleOpt( const QwtArrowButton* btn )
    
    pixhawk's avatar
    pixhawk committed
    {
        QStyleOptionButton option;
    
    Bryant's avatar
    Bryant committed
        option.init( btn );
    
    pixhawk's avatar
    pixhawk committed
        option.features = QStyleOptionButton::None;
    
    Bryant's avatar
    Bryant committed
        if ( btn->isFlat() )
    
    pixhawk's avatar
    pixhawk committed
            option.features |= QStyleOptionButton::Flat;
    
    Bryant's avatar
    Bryant committed
        if ( btn->menu() )
    
    pixhawk's avatar
    pixhawk committed
            option.features |= QStyleOptionButton::HasMenu;
    
    Bryant's avatar
    Bryant committed
        if ( btn->autoDefault() || btn->isDefault() )
    
    pixhawk's avatar
    pixhawk committed
            option.features |= QStyleOptionButton::AutoDefaultButton;
    
    Bryant's avatar
    Bryant committed
        if ( btn->isDefault() )
    
    pixhawk's avatar
    pixhawk committed
            option.features |= QStyleOptionButton::DefaultButton;
    
    Bryant's avatar
    Bryant committed
        if ( btn->isDown() )
    
    pixhawk's avatar
    pixhawk committed
            option.state |= QStyle::State_Sunken;
    
    Bryant's avatar
    Bryant committed
        if ( !btn->isFlat() && !btn->isDown() )
    
    pixhawk's avatar
    pixhawk committed
            option.state |= QStyle::State_Raised;
    
        return option;
    }
    
    /*!
      \param num Number of arrows
    
    Bryant's avatar
    Bryant committed
      \param arrowType see Qt::ArrowType in the Qt docs.
    
    pixhawk's avatar
    pixhawk committed
      \param parent Parent widget
    */
    
    Bryant's avatar
    Bryant committed
    QwtArrowButton::QwtArrowButton( int num,
            Qt::ArrowType arrowType, QWidget *parent ):
        QPushButton( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data = new PrivateData;
    
    Bryant's avatar
    Bryant committed
        d_data->num = qBound( 1, num, MaxNum );
    
    pixhawk's avatar
    pixhawk committed
        d_data->arrowType = arrowType;
    
    
    Bryant's avatar
    Bryant committed
        setAutoRepeat( true );
        setAutoDefault( false );
    
        switch ( d_data->arrowType )
        {
            case Qt::LeftArrow:
            case Qt::RightArrow:
                setSizePolicy( QSizePolicy::Expanding,
                    QSizePolicy::Fixed );
                break;
            default:
                setSizePolicy( QSizePolicy::Fixed,
                    QSizePolicy::Expanding );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    //! Destructor
    QwtArrowButton::~QwtArrowButton()
    {
        delete d_data;
        d_data = NULL;
    }
    
    /*!
      \brief The direction of the arrows
    */
    
    Qt::ArrowType QwtArrowButton::arrowType() const
    {
        return d_data->arrowType;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \brief The number of arrows
    */
    
    int QwtArrowButton::num() const
    {
        return d_data->num;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return the bounding rectangle for the label
    
    pixhawk's avatar
    pixhawk committed
    */
    QRect QwtArrowButton::labelRect() const
    {
        const int m = Margin;
    
        QRect r = rect();
    
    Bryant's avatar
    Bryant committed
        r.setRect( r.x() + m, r.y() + m,
            r.width() - 2 * m, r.height() - 2 * m );
    
        if ( isDown() )
        {
            QStyleOptionButton option = styleOpt( this );
            const int ph = style()->pixelMetric(
                QStyle::PM_ButtonShiftHorizontal, &option, this );
            const int pv = style()->pixelMetric(
                QStyle::PM_ButtonShiftVertical, &option, this );
    
            r.translate( ph, pv );
    
    pixhawk's avatar
    pixhawk committed
        }
    
        return r;
    }
    
    /*!
       Paint event handler
       \param event Paint event
    */
    
    Bryant's avatar
    Bryant committed
    void QwtArrowButton::paintEvent( QPaintEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QPushButton::paintEvent( event );
        QPainter painter( this );
        drawButtonLabel( &painter );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \brief Draw the button label
    
      \param painter Painter
    
    Bryant's avatar
    Bryant committed
      \sa The Qt Manual for QPushButton
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtArrowButton::drawButtonLabel( QPainter *painter )
    
    pixhawk's avatar
    pixhawk committed
    {
        const bool isVertical = d_data->arrowType == Qt::UpArrow ||
    
    Bryant's avatar
    Bryant committed
            d_data->arrowType == Qt::DownArrow;
    
    pixhawk's avatar
    pixhawk committed
    
        const QRect r = labelRect();
        QSize boundingSize = labelRect().size();
        if ( isVertical )
            boundingSize.transpose();
    
    Bryant's avatar
    Bryant committed
            ( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QSize arrow = arrowSize( Qt::RightArrow,
            QSize( w, boundingSize.height() ) );
    
    pixhawk's avatar
    pixhawk committed
    
        if ( isVertical )
            arrow.transpose();
    
        QRect contentsSize; // aligned rect where to paint all arrows
    
    Bryant's avatar
    Bryant committed
        if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow )
        {
            contentsSize.setWidth( d_data->num * arrow.width()
                + ( d_data->num - 1 ) * Spacing );
            contentsSize.setHeight( arrow.height() );
        }
        else
        {
            contentsSize.setWidth( arrow.width() );
            contentsSize.setHeight( d_data->num * arrow.height()
                + ( d_data->num - 1 ) * Spacing );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        QRect arrowRect( contentsSize );
        arrowRect.moveCenter( r.center() );
        arrowRect.setSize( arrow );
    
    pixhawk's avatar
    pixhawk committed
    
        painter->save();
    
    Bryant's avatar
    Bryant committed
        for ( int i = 0; i < d_data->num; i++ )
        {
            drawArrow( painter, arrowRect, d_data->arrowType );
    
    pixhawk's avatar
    pixhawk committed
    
            int dx = 0;
            int dy = 0;
    
            if ( isVertical )
                dy = arrow.height() + Spacing;
            else
                dx = arrow.width() + Spacing;
    
    
    Bryant's avatar
    Bryant committed
            arrowRect.translate( dx, dy );
    
    pixhawk's avatar
    pixhawk committed
        }
        painter->restore();
    
    
    Bryant's avatar
    Bryant committed
        if ( hasFocus() )
        {
    
    pixhawk's avatar
    pixhawk committed
            QStyleOptionFocusRect option;
    
    Bryant's avatar
    Bryant committed
            option.init( this );
            option.backgroundColor = palette().color( QPalette::Window );
    
            style()->drawPrimitive( QStyle::PE_FrameFocusRect,
                &option, painter, this );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
        Draw an arrow int a bounding rectangle
    
    pixhawk's avatar
    pixhawk committed
    
        \param painter Painter
        \param r Rectangle where to paint the arrow
        \param arrowType Arrow type
    */
    
    Bryant's avatar
    Bryant committed
    void QwtArrowButton::drawArrow( QPainter *painter,
        const QRect &r, Qt::ArrowType arrowType ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QPolygon pa( 3 );
    
        switch ( arrowType )
        {
            case Qt::UpArrow:
                pa.setPoint( 0, r.bottomLeft() );
                pa.setPoint( 1, r.bottomRight() );
                pa.setPoint( 2, r.center().x(), r.top() );
                break;
            case Qt::DownArrow:
                pa.setPoint( 0, r.topLeft() );
                pa.setPoint( 1, r.topRight() );
                pa.setPoint( 2, r.center().x(), r.bottom() );
                break;
            case Qt::RightArrow:
                pa.setPoint( 0, r.topLeft() );
                pa.setPoint( 1, r.bottomLeft() );
                pa.setPoint( 2, r.right(), r.center().y() );
                break;
            case Qt::LeftArrow:
                pa.setPoint( 0, r.topRight() );
                pa.setPoint( 1, r.bottomRight() );
                pa.setPoint( 2, r.left(), r.center().y() );
                break;
            default:
                break;
    
    pixhawk's avatar
    pixhawk committed
        }
    
        painter->save();
    
    Bryant's avatar
    Bryant committed
    
        painter->setRenderHint( QPainter::Antialiasing, true );
        painter->setPen( Qt::NoPen );
        painter->setBrush( palette().brush( QPalette::ButtonText ) );
        painter->drawPolygon( pa );
    
    
    pixhawk's avatar
    pixhawk committed
        painter->restore();
    }
    
    /*!
      \return a size hint
    */
    QSize QwtArrowButton::sizeHint() const
    {
    
    Bryant's avatar
    Bryant committed
        const QSize hint = minimumSizeHint();
        return hint.expandedTo( QApplication::globalStrut() );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \brief Return a minimum size hint
    */
    QSize QwtArrowButton::minimumSizeHint() const
    {
    
    Bryant's avatar
    Bryant committed
        const QSize asz = arrowSize( Qt::RightArrow, QSize() );
    
    pixhawk's avatar
    pixhawk committed
    
        QSize sz(
    
    Bryant's avatar
    Bryant committed
            2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(),
    
    pixhawk's avatar
    pixhawk committed
            2 * Margin + asz.height()
        );
    
        if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow )
            sz.transpose();
    
        QStyleOption styleOption;
    
    Bryant's avatar
    Bryant committed
        styleOption.init( this );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        sz = style()->sizeFromContents( QStyle::CT_PushButton,
            &styleOption, sz, this );
    
    pixhawk's avatar
    pixhawk committed
    
        return sz;
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
       Calculate the size for a arrow that fits into a rectangle of a given size
    
    pixhawk's avatar
    pixhawk committed
    
       \param arrowType Arrow type
       \param boundingSize Bounding size
       \return Size of the arrow
    */
    
    Bryant's avatar
    Bryant committed
    QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType,
        const QSize &boundingSize ) const
    
    pixhawk's avatar
    pixhawk committed
    {
        QSize bs = boundingSize;
        if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
            bs.transpose();
    
    pixhawk's avatar
    pixhawk committed
        const int MinLen = 2;
        const QSize sz = bs.expandedTo(
    
    Bryant's avatar
    Bryant committed
            QSize( MinLen, 2 * MinLen - 1 ) ); // minimum
    
    pixhawk's avatar
    pixhawk committed
    
        int w = sz.width();
        int h = 2 * w - 1;
    
    
    Bryant's avatar
    Bryant committed
        if ( h > sz.height() )
        {
    
    pixhawk's avatar
    pixhawk committed
            h = sz.height();
    
    Bryant's avatar
    Bryant committed
            w = ( h + 1 ) / 2;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        QSize arrSize( w, h );
    
    pixhawk's avatar
    pixhawk committed
        if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
            arrSize.transpose();
    
        return arrSize;
    }
    
    /*!
      \brief autoRepeat for the space keys
    */
    
    Bryant's avatar
    Bryant committed
    void QwtArrowButton::keyPressEvent( QKeyEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( event->isAutoRepeat() && event->key() == Qt::Key_Space )
            Q_EMIT clicked();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QPushButton::keyPressEvent( event );
    
    pixhawk's avatar
    pixhawk committed
    }