/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** * Qwt Widget Library * Copyright (C) 1997 Josef Wilgen * Copyright (C) 2002 Uwe Rathmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the Qwt License, Version 1.0 *****************************************************************************/ #include "qwt_arrow_button.h" #include "qwt_math.h" #include #include #include #include #include static const int MaxNum = 3; static const int Margin = 2; static const int Spacing = 1; class QwtArrowButton::PrivateData { public: int num; Qt::ArrowType arrowType; }; static QStyleOptionButton styleOpt( const QwtArrowButton* btn ) { QStyleOptionButton option; option.init( btn ); option.features = QStyleOptionButton::None; if ( btn->isFlat() ) option.features |= QStyleOptionButton::Flat; if ( btn->menu() ) option.features |= QStyleOptionButton::HasMenu; if ( btn->autoDefault() || btn->isDefault() ) option.features |= QStyleOptionButton::AutoDefaultButton; if ( btn->isDefault() ) option.features |= QStyleOptionButton::DefaultButton; if ( btn->isDown() ) option.state |= QStyle::State_Sunken; if ( !btn->isFlat() && !btn->isDown() ) option.state |= QStyle::State_Raised; return option; } /*! \param num Number of arrows \param arrowType see Qt::ArrowType in the Qt docs. \param parent Parent widget */ QwtArrowButton::QwtArrowButton( int num, Qt::ArrowType arrowType, QWidget *parent ): QPushButton( parent ) { d_data = new PrivateData; d_data->num = qBound( 1, num, MaxNum ); d_data->arrowType = arrowType; 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 ); } } //! Destructor QwtArrowButton::~QwtArrowButton() { delete d_data; d_data = NULL; } /*! \brief The direction of the arrows */ Qt::ArrowType QwtArrowButton::arrowType() const { return d_data->arrowType; } /*! \brief The number of arrows */ int QwtArrowButton::num() const { return d_data->num; } /*! \return the bounding rectangle for the label */ QRect QwtArrowButton::labelRect() const { const int m = Margin; QRect r = rect(); 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 ); } return r; } /*! Paint event handler \param event Paint event */ void QwtArrowButton::paintEvent( QPaintEvent *event ) { QPushButton::paintEvent( event ); QPainter painter( this ); drawButtonLabel( &painter ); } /*! \brief Draw the button label \param painter Painter \sa The Qt Manual for QPushButton */ void QwtArrowButton::drawButtonLabel( QPainter *painter ) { const bool isVertical = d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow; const QRect r = labelRect(); QSize boundingSize = labelRect().size(); if ( isVertical ) boundingSize.transpose(); const int w = ( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum; QSize arrow = arrowSize( Qt::RightArrow, QSize( w, boundingSize.height() ) ); if ( isVertical ) arrow.transpose(); QRect contentsSize; // aligned rect where to paint all arrows 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 ); } QRect arrowRect( contentsSize ); arrowRect.moveCenter( r.center() ); arrowRect.setSize( arrow ); painter->save(); for ( int i = 0; i < d_data->num; i++ ) { drawArrow( painter, arrowRect, d_data->arrowType ); int dx = 0; int dy = 0; if ( isVertical ) dy = arrow.height() + Spacing; else dx = arrow.width() + Spacing; arrowRect.translate( dx, dy ); } painter->restore(); if ( hasFocus() ) { QStyleOptionFocusRect option; option.init( this ); option.backgroundColor = palette().color( QPalette::Window ); style()->drawPrimitive( QStyle::PE_FrameFocusRect, &option, painter, this ); } } /*! Draw an arrow int a bounding rectangle \param painter Painter \param r Rectangle where to paint the arrow \param arrowType Arrow type */ void QwtArrowButton::drawArrow( QPainter *painter, const QRect &r, Qt::ArrowType arrowType ) const { 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; } painter->save(); painter->setRenderHint( QPainter::Antialiasing, true ); painter->setPen( Qt::NoPen ); painter->setBrush( palette().brush( QPalette::ButtonText ) ); painter->drawPolygon( pa ); painter->restore(); } /*! \return a size hint */ QSize QwtArrowButton::sizeHint() const { const QSize hint = minimumSizeHint(); return hint.expandedTo( QApplication::globalStrut() ); } /*! \brief Return a minimum size hint */ QSize QwtArrowButton::minimumSizeHint() const { const QSize asz = arrowSize( Qt::RightArrow, QSize() ); QSize sz( 2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(), 2 * Margin + asz.height() ); if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow ) sz.transpose(); QStyleOption styleOption; styleOption.init( this ); sz = style()->sizeFromContents( QStyle::CT_PushButton, &styleOption, sz, this ); return sz; } /*! Calculate the size for a arrow that fits into a rectangle of a given size \param arrowType Arrow type \param boundingSize Bounding size \return Size of the arrow */ QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType, const QSize &boundingSize ) const { QSize bs = boundingSize; if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) bs.transpose(); const int MinLen = 2; const QSize sz = bs.expandedTo( QSize( MinLen, 2 * MinLen - 1 ) ); // minimum int w = sz.width(); int h = 2 * w - 1; if ( h > sz.height() ) { h = sz.height(); w = ( h + 1 ) / 2; } QSize arrSize( w, h ); if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow ) arrSize.transpose(); return arrSize; } /*! \brief autoRepeat for the space keys */ void QwtArrowButton::keyPressEvent( QKeyEvent *event ) { if ( event->isAutoRepeat() && event->key() == Qt::Key_Space ) Q_EMIT clicked(); QPushButton::keyPressEvent( event ); }