# qwt_arrow_button.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 #include <qpainter.h>
    00011 #include <qstyle.h>
    00012 #include <qevent.h>
    00013 #include "qwt_math.h"
    00014 #include "qwt_polygon.h"
    00015 #include "qwt_arrow_button.h"
    00016
    00017 static const int MaxNum = 3;
    00018 static const int Margin = 2;
    00019 static const int Spacing = 1;
    00020
    00021 class QwtArrowButton::PrivateData
    00022 {
    00023 public:
    00024     int num;
    00025     Qt::ArrowType arrowType;
    00026 };
    00027
    00028
    00029 #if QT_VERSION >= 0x040000
    00030 #include <qstyleoption.h>
    00031 static QStyleOptionButton styleOpt(const QwtArrowButton* btn)
    00032 {
    00033     QStyleOptionButton option;
    00034     option.init(btn);
    00035     option.features = QStyleOptionButton::None;
    00036     if (btn->isFlat())
    00037         option.features |= QStyleOptionButton::Flat;
    00038     if (btn->menu())
    00039         option.features |= QStyleOptionButton::HasMenu;
    00040     if (btn->autoDefault() || btn->isDefault())
    00041         option.features |= QStyleOptionButton::AutoDefaultButton;
    00042     if (btn->isDefault())
    00043         option.features |= QStyleOptionButton::DefaultButton;
    00044     if (btn->isDown())
    00045         option.state |= QStyle::State_Sunken;
    00046     if (!btn->isFlat() && !btn->isDown())
    00047         option.state |= QStyle::State_Raised;
    00048
    00049     return option;
    00050 }
    00051 #endif
    00052
    00058 QwtArrowButton::QwtArrowButton(int num,
    00059         Qt::ArrowType arrowType, QWidget *parent):
    00060     QPushButton(parent)
    00061 {
    00062     d_data = new PrivateData;
    00063     d_data->num = qwtLim(num, 1, MaxNum);
    00064     d_data->arrowType = arrowType;
    00065
    00066     setAutoRepeat(true);
    00067     setAutoDefault(false);
    00068
    00069     switch(d_data->arrowType)
    00070     {
    00071         case Qt::LeftArrow:
    00072         case Qt::RightArrow:
    00073             setSizePolicy(QSizePolicy::Expanding,
    00074                 QSizePolicy::Fixed);
    00075             break;
    00076         default:
    00077             setSizePolicy(QSizePolicy::Fixed,
    00078                 QSizePolicy::Expanding);
    00079     }
    00080 }
    00081
    00083 QwtArrowButton::~QwtArrowButton()
    00084 {
    00085     delete d_data;
    00086     d_data = NULL;
    00087 }
    00088
    00092 Qt::ArrowType QwtArrowButton::arrowType() const
    00093 {
    00094     return d_data->arrowType;
    00095 }
    00096
    00100 int QwtArrowButton::num() const
    00101 {
    00102     return d_data->num;
    00103 }
    00104
    00108 QRect QwtArrowButton::labelRect() const
    00109 {
    00110     const int m = Margin;
    00111
    00112     QRect r = rect();
    00113     r.setRect(r.x() + m, r.y() + m,
    00114         r.width() - 2 * m, r.height() - 2 * m);
    00115
    00116     if ( isDown() )
    00117     {
    00118         int ph, pv;
    00119 #if QT_VERSION < 0x040000
    00120         ph = style().pixelMetric(
    00121             QStyle::PM_ButtonShiftHorizontal, this);
    00122         pv = style().pixelMetric(
    00123             QStyle::PM_ButtonShiftVertical, this);
    00124         r.moveBy(ph, pv);
    00125 #else
    00126         QStyleOptionButton option = styleOpt(this);
    00127         ph = style()->pixelMetric(
    00128             QStyle::PM_ButtonShiftHorizontal, &option, this);
    00129         pv = style()->pixelMetric(
    00130             QStyle::PM_ButtonShiftVertical, &option, this);
    00131         r.translate(ph, pv);
    00132 #endif
    00133     }
    00134
    00135     return r;
    00136 }
    00137
    00138 #if QT_VERSION >= 0x040000
    00139
    00143 void QwtArrowButton::paintEvent(QPaintEvent *event)
    00144 {
    00145     QPushButton::paintEvent(event);
    00146     QPainter painter(this);
    00147     drawButtonLabel(&painter);
    00148 }
    00149 #endif
    00150
    00157 void QwtArrowButton::drawButtonLabel(QPainter *painter)
    00158 {
    00159     const bool isVertical = d_data->arrowType == Qt::UpArrow ||
    00160         d_data->arrowType == Qt::DownArrow;
    00161
    00162     const QRect r = labelRect();
    00163     QSize boundingSize = labelRect().size();
    00164     if ( isVertical )
    00165         boundingSize.transpose();
    00166
    00167     const int w =
    00168         (boundingSize.width() - (MaxNum - 1) * Spacing) / MaxNum;
    00169
    00170     QSize arrow = arrowSize(Qt::RightArrow,
    00171         QSize(w, boundingSize.height()));
    00172
    00173     if ( isVertical )
    00174         arrow.transpose();
    00175
    00176     QRect contentsSize; // aligned rect where to paint all arrows
    00177     if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow )
    00178     {
    00179         contentsSize.setWidth(d_data->num * arrow.width()
    00180             + (d_data->num - 1) * Spacing);
    00181         contentsSize.setHeight(arrow.height());
    00182     }
    00183     else
    00184     {
    00185         contentsSize.setWidth(arrow.width());
    00186         contentsSize.setHeight(d_data->num * arrow.height()
    00187             + (d_data->num - 1) * Spacing);
    00188     }
    00189
    00190     QRect arrowRect(contentsSize);
    00191     arrowRect.moveCenter(r.center());
    00192     arrowRect.setSize(arrow);
    00193
    00194     painter->save();
    00195     for (int i = 0; i < d_data->num; i++)
    00196     {
    00197         drawArrow(painter, arrowRect, d_data->arrowType);
    00198
    00199         int dx = 0;
    00200         int dy = 0;
    00201
    00202         if ( isVertical )
    00203             dy = arrow.height() + Spacing;
    00204         else
    00205             dx = arrow.width() + Spacing;
    00206
    00207 #if QT_VERSION >= 0x040000
    00208         arrowRect.translate(dx, dy);
    00209 #else
    00210         arrowRect.moveBy(dx, dy);
    00211 #endif
    00212     }
    00213     painter->restore();
    00214
    00215     if ( hasFocus() )
    00216     {
    00217 #if QT_VERSION >= 0x040000
    00218         QStyleOptionFocusRect option;
    00219         option.init(this);
    00220         option.backgroundColor = palette().color(QPalette::Background);
    00221
    00222         style()->drawPrimitive(QStyle::PE_FrameFocusRect,
    00223             &option, painter, this);
    00224 #else
    00225         const QRect focusRect =
    00226             style().subRect(QStyle::SR_PushButtonFocusRect, this);
    00227         style().drawPrimitive(QStyle::PE_FocusRect, painter,
    00228             focusRect, colorGroup());
    00229 #endif
    00230     }
    00231 }
    00232
    00240 void QwtArrowButton::drawArrow(QPainter *painter,
    00241     const QRect &r, Qt::ArrowType arrowType) const
    00242 {
    00243     QwtPolygon pa(3);
    00244
    00245     switch(arrowType)
    00246     {
    00247         case Qt::UpArrow:
    00248             pa.setPoint(0, r.bottomLeft());
    00249             pa.setPoint(1, r.bottomRight());
    00250             pa.setPoint(2, r.center().x(), r.top());
    00251             break;
    00252         case Qt::DownArrow:
    00253             pa.setPoint(0, r.topLeft());
    00254             pa.setPoint(1, r.topRight());
    00255             pa.setPoint(2, r.center().x(), r.bottom());
    00256             break;
    00257         case Qt::RightArrow:
    00258             pa.setPoint(0, r.topLeft());
    00259             pa.setPoint(1, r.bottomLeft());
    00260             pa.setPoint(2, r.right(), r.center().y());
    00261             break;
    00262         case Qt::LeftArrow:
    00263             pa.setPoint(0, r.topRight());
    00264             pa.setPoint(1, r.bottomRight());
    00265             pa.setPoint(2, r.left(), r.center().y());
    00266             break;
    00267         default:
    00268             break;
    00269     }
    00270
    00271     painter->save();
    00272 #if QT_VERSION < 0x040000
    00273     painter->setPen(colorGroup().buttonText());
    00274     painter->setBrush(colorGroup().brush(QColorGroup::ButtonText));
    00275 #else
    00276     painter->setPen(palette().color(QPalette::ButtonText));
    00277     painter->setBrush(palette().brush(QPalette::ButtonText));
    00278 #endif
    00279     painter->drawPolygon(pa);
    00280     painter->restore();
    00281 }
    00282
    00286 QSize QwtArrowButton::sizeHint() const
    00287 {
    00288     return minimumSizeHint();
    00289 }
    00290
    00294 QSize QwtArrowButton::minimumSizeHint() const
    00295 {
    00296     const QSize asz = arrowSize(Qt::RightArrow, QSize());
    00297
    00298     QSize sz(
    00299         2 * Margin + (MaxNum - 1) * Spacing + MaxNum * asz.width(),
    00300         2 * Margin + asz.height()
    00301     );
    00302
    00303     if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow )
    00304         sz.transpose();
    00305
    00306 #if QT_VERSION >= 0x040000
    00307     QStyleOption styleOption;
    00308     styleOption.init(this);
    00309
    00310     const QSize hsz = style()->sizeFromContents(QStyle::CT_PushButton,
    00311         &styleOption, sz, this);
    00312 #if QT_VERSION < 0x040300
    00313     if ( hsz.width() != 80 ) // avoid a bug in the Cleanlooks style
    00314 #endif
    00315         sz = hsz;
    00316
    00317 #else
    00318     sz = style().sizeFromContents(QStyle::CT_PushButton, this, sz);
    00319 #endif
    00320
    00321     return sz;
    00322 }
    00323
    00331 QSize QwtArrowButton::arrowSize(Qt::ArrowType arrowType,
    00332     const QSize &boundingSize) const
    00333 {
    00334     QSize bs = boundingSize;
    00335     if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
    00336         bs.transpose();
    00337
    00338     const int MinLen = 2;
    00339     const QSize sz = bs.expandedTo(
    00340         QSize(MinLen, 2 * MinLen - 1)); // minimum
    00341
    00342     int w = sz.width();
    00343     int h = 2 * w - 1;
    00344
    00345     if ( h > sz.height() )
    00346     {
    00347         h = sz.height();
    00348         w = (h + 1) / 2;
    00349     }
    00350
    00351     QSize arrSize(w, h);
    00352     if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
    00353         arrSize.transpose();
    00354
    00355     return arrSize;
    00356 }
    00357
    00361 void QwtArrowButton::keyPressEvent(QKeyEvent *e)
    00362 {
    00363     if ( e->isAutoRepeat() && e->key() == Qt::Key_Space )
    00364         emit clicked();
    00365
    00366     QPushButton::keyPressEvent(e);
    00367 }