qt_demoe/qwtdemo/qwt/qwt_arrow_button.cpp

334 lines
8.1 KiB
C++

/* -*- 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 <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qevent.h>
#include <qapplication.h>
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 );
}