You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
8.1 KiB
333 lines
8.1 KiB
/* -*- 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 ); |
|
}
|
|
|