Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

# qwt_push_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 // vim: expandtab
    00011
    00012 #include <qpainter.h>
    00013 #include <qpicture.h>
    00014 #include <qsimplerichtext.h>
    00015 #include <qstylesheet.h>
    00016 #include <qstyle.h>
    00017 #include "qwt_text.h"
    00018 #include "qwt_push_button.h"
    00019
    00020 #ifndef QT_NO_PICTURE
    00021
    00022 class QwtPBPaintFilter: public QPicture
    00023 {
    00024     // A helper class that filters the QPushButton paint commands
    00025     // and changes them according the additional features of QwtPushButton
    00026
    00027 public:
    00028     QwtPBPaintFilter(const QwtPushButton *);
    00029
    00030 protected:
    00031     virtual bool cmd(int, QPainter *, QPDevCmdParam *);
    00032
    00033 private:
    00034     bool isLabel(const QPixmap *) const;
    00035     QRect indentRect(const QRect &) const;
    00036
    00037     const QwtPushButton *d_button;
    00038     QRect d_iconRect;
    00039     bool d_inFilter;
    00040 };
    00041
    00042 QwtPBPaintFilter::QwtPBPaintFilter(const QwtPushButton *button):
    00043     d_button(button),
    00044     d_inFilter(FALSE)
    00045 {
    00046 }
    00047
    00048 bool QwtPBPaintFilter::cmd(int c, QPainter *painter, QPDevCmdParam *param)
    00049 {
    00050     switch(c)
    00051     {
    00052         case PdcDrawTextFormatted:
    00053         case PdcDrawText2Formatted:
    00054         {
    00055             Qt::TextFormat textFormat = d_button->usedTextFormat();
    00056             if ( textFormat == Qt::PlainText )
    00057             {
    00058                 param[1].ival = d_button->alignment();
    00059
    00060                 QRect &r = *((QRect *)param[0].rect);
    00061                 r = indentRect(r);
    00062
    00063                 return QPicture::cmd(c, painter, param);
    00064             }
    00065             if ( textFormat == Qt::RichText )
    00066             {
    00067                 if ( !d_inFilter ) // avoid recursive calls
    00068                 {
    00069                     d_inFilter = TRUE;
    00070                     QwtRichText richText(*param[2].str, painter->font(),
    00071                         d_button->alignment(), painter->pen().color());
    00072                     richText.draw(painter, indentRect(*param[0].rect));
    00073                     d_inFilter = FALSE;
    00074                     return TRUE;
    00075                 }
    00076             }
    00077             break;
    00078         }
    00079         case PdcDrawPixmap:
    00080         {
    00081             if ( d_inFilter ) // avoid recursive calls
    00082             {
    00083                 // There might be pixmaps embedded in rich text.
    00084                 // This problem is solved by the d_inFilter guard
    00085                 // above too.
    00086                 break;
    00087             }
    00088
    00089             if ( isLabel(param[1].pixmap) &&
    00090                 !(d_button->alignment() & Qt::AlignCenter))
    00091             {
    00092                 const QRect contentsRect =
    00093 #if QT_VERSION >= 300
    00094                     d_button->style().subRect(
    00095                         QStyle::SR_PushButtonContents, d_button);
    00096 #else
    00097                     d_button->style().pushButtonContentsRect(
    00098                         (QPushButton *)d_button);
    00099 #endif
    00100
    00101                 QRect pixRect = contentsRect;
    00102                 if ( !d_iconRect.isEmpty() )
    00103                     pixRect.setX(d_iconRect.right());
    00104
    00105                 // Many styles move the label right/down
    00106                 // when the button is down.
    00107
    00108 #if QT_VERSION >= 300
    00109                 const QRect &r = *((QRect *)param[0].rect);
    00110 #else
    00111                 const QRect r(*param[0].point, param[1].pixmap->size());
    00112 #endif
    00113                 const int offsetY = r.center().y() - pixRect.center().y();
    00114                 const int offsetX = d_iconRect.isEmpty() ? offsetY : 0;
    00115                 pixRect.moveBy(offsetX, offsetY);
    00116
    00117                 if ( d_button->indent() > 0 )
    00118                 {
    00119                     const int indent = d_button->indent();
    00120                     const int align = d_button->alignment();
    00121
    00122                     if ( align & Qt::AlignRight )
    00123                         pixRect.setRight(pixRect.right() - indent);
    00124                     else if ( align & Qt::AlignLeft )
    00125                         pixRect.setLeft(pixRect.left() + indent);
    00126
    00127                     if ( align & Qt::AlignTop )
    00128                         pixRect.setTop(pixRect.top() + indent);
    00129                     else if ( align & Qt::AlignBottom )
    00130                         pixRect.setBottom(pixRect.bottom() - indent);
    00131                 }
    00132
    00133                 pixRect &= contentsRect; // clip to contentsRect
    00134
    00135                 d_inFilter = TRUE;
    00136
    00137                 d_button->style().drawItem(painter,
    00138 #if QT_VERSION >= 300
    00139                     pixRect,
    00140 #else
    00141                     pixRect.x(), pixRect.y(),
    00142                     pixRect.width(), pixRect.height(),
    00143 #endif
    00144                     d_button->alignment(), d_button->colorGroup(),
    00145                     d_button->isEnabled(), param[1].pixmap, QString::null);
    00146
    00147                 d_inFilter = FALSE;
    00148                 return TRUE;
    00149             }
    00150             else
    00151             {
    00152                 // We save the position of the icon. We need it later
    00153                 // to align the label pixmap. Hope that there are no styles
    00154                 // that paint the pixmap before the icon.
    00155 #if QT_VERSION < 300
    00156                 d_iconRect = QRect(*param[0].point, param[1].pixmap->size());
    00157 #else
    00158                 d_iconRect = *param[0].rect;
    00159 #endif
    00160             }
    00161             break;
    00162         }
    00163     }
    00164     return QPicture::cmd(c, painter, param);
    00165 }
    00166
    00167 QRect QwtPBPaintFilter::indentRect(const QRect &rect) const
    00168 {
    00169     const int indent = d_button->indent();
    00170     if ( indent <= 0 )
    00171         return rect;
    00172
    00173     QRect r = rect;
    00174     if ( d_button->alignment() & Qt::AlignRight )
    00175         r.setRight(r.right() - indent);
    00176     else if ( d_button->alignment() & Qt::AlignLeft )
    00177         r.setLeft(r.left() + indent);
    00178
    00179     if ( d_button->alignment() & Qt::AlignTop )
    00180         r.setTop(r.top() + indent);
    00181     else if ( d_button->alignment() & Qt::AlignBottom )
    00182         r.setBottom(r.bottom() - indent);
    00183
    00184     return r;
    00185 }
    00186
    00187 bool QwtPBPaintFilter::isLabel(const QPixmap *pixmap) const
    00188 {
    00189     if ( !d_button->pixmap() ||
    00190         d_button->pixmap()->serialNumber() != pixmap->serialNumber() )
    00191     {
    00192         return FALSE;
    00193     }
    00194
    00195     if ( d_button->iconSet() && !d_button->iconSet()->isNull() )
    00196     {
    00197         if ( d_button->iconSet()->pixmap().serialNumber() ==
    00198             pixmap->serialNumber() )
    00199         {
    00200             // Iconset and label are both set, and use the same pixmap.
    00201             // We hope the iconSet is painted first.
    00202
    00203             static bool firstPixmap = TRUE;
    00204             firstPixmap = !firstPixmap;
    00205
    00206             return !firstPixmap;
    00207         }
    00208     }
    00209     return TRUE;
    00210 }
    00211
    00212 #endif // !QT_NO_PICTURE
    00213
    00217 QwtPushButton::QwtPushButton(QWidget *parent, const char *name):
    00218     QPushButton(parent, name)
    00219 {
    00220     init();
    00221 }
    00222
    00227 QwtPushButton::QwtPushButton(const QString &text,
    00228         QWidget *parent, const char *name):
    00229     QPushButton(text, parent, name)
    00230 {
    00231     init();
    00232 }
    00233
    00237 QwtPushButton::QwtPushButton(const QIconSet &iconSet, const QString &text,
    00238         QWidget *parent, const char *name):
    00239     QPushButton(iconSet, text, parent, name)
    00240 {
    00241     init();
    00242 }
    00243
    00245 void QwtPushButton::init()
    00246 {
    00247     d_textFormat = Qt::AutoText;
    00248     d_alignment = Qt::AlignCenter | Qt::ExpandTabs | Qt::WordBreak;
    00249     d_indent = 4;
    00250 }
    00251
    00262 Qt::TextFormat QwtPushButton::usedTextFormat() const
    00263 {
    00264 #ifndef QT_NO_PICTURE
    00265     if ( d_textFormat == Qt::AutoText && QStyleSheet::mightBeRichText(text()) )
    00266         return Qt::RichText;
    00267 #endif
    00268
    00269     return Qt::PlainText;
    00270 }
    00271
    00277 Qt::TextFormat QwtPushButton::textFormat() const
    00278 {
    00279     return d_textFormat;
    00280 }
    00281
    00291 void QwtPushButton::setTextFormat(TextFormat textFormat)
    00292 {
    00293     d_textFormat = textFormat;
    00294 }
    00295
    00301 int QwtPushButton::alignment() const
    00302 {
    00303     return d_alignment;
    00304 }
    00305
    00315 void QwtPushButton::setAlignment(int alignment)
    00316 {
    00317     d_alignment = alignment;
    00318 }
    00319
    00325 int QwtPushButton::indent() const
    00326 {
    00327     return d_indent;
    00328 }
    00329
    00340 void QwtPushButton::setIndent(int indent)
    00341 {
    00342     d_indent = indent;
    00343 }
    00344
    00352 int QwtPushButton::heightForWidth(int width) const
    00353 {
    00354     if ( pixmap() )
    00355         return QPushButton::heightForWidth(width);
    00356
    00357     QwtText *txt = QwtText::makeText(text(), usedTextFormat(),
    00358         d_alignment, font());
    00359
    00360     int h = sizeHint().height();
    00361     h -= txt->boundingRect().height();
    00362     h += txt->heightForWidth(width);
    00363
    00364     delete txt;
    00365
    00366     return h;
    00367 }
    00368
    00370 QSize QwtPushButton::sizeHint() const
    00371 {
    00372     QSize hint = QPushButton::sizeHint();
    00373
    00374     if ( d_indent > 0 )
    00375     {
    00376         if ( (d_alignment & Qt::AlignLeft)
    00377             || (d_alignment & Qt::AlignRight) )
    00378         {
    00379             hint.setWidth(hint.width() + d_indent);
    00380         }
    00381         if ( (d_alignment & Qt::AlignTop)
    00382             || (d_alignment & Qt::AlignBottom) )
    00383         {
    00384             hint.setHeight(hint.height() + d_indent);
    00385         }
    00386     }
    00387
    00388     if ( pixmap() )
    00389         return hint;
    00390
    00391     const Qt::TextFormat textFormat = usedTextFormat();
    00392     if ( textFormat == Qt::RichText )
    00393     {
    00394         QwtRichText richText(text(), font(), d_alignment);
    00395
    00396         const QSize sizeText = fontMetrics().size(Qt::ShowPrefix, text());
    00397         const QSize sizeRichText(richText.boundingRect().size());
    00398
    00399         int iconHeight = 0;
    00400         if ( iconSet() && !iconSet()->isNull() )
    00401         {
    00402             iconHeight = iconSet()->pixmap(QIconSet::Small,
    00403                 QIconSet::Normal).height();
    00404         }
    00405
    00406         const int heightText = QMAX(iconHeight, sizeText.height());
    00407         const int heightRichText = QMAX(iconHeight, sizeRichText.height());
    00408
    00409         hint.setWidth(hint.width() - sizeText.width() + sizeRichText.width());
    00410         hint.setHeight(hint.height() - heightText + heightRichText);
    00411     }
    00412
    00413     return hint;
    00414 }
    00415
    00417 void QwtPushButton::drawButtonLabel(QPainter *painter)
    00418 {
    00419 #ifndef QT_NO_PICTURE
    00420     // Unfortunately QStyle doesnīt offer an API to add
    00421     // the alignment and rich text features. But we donīt want
    00422     // to paint the button label on our own, as we would lose
    00423     // the flexibility of the styles. So we let the style
    00424     // paint the button label to a QPicture first, change
    00425     // the paint commands and replay the manipulated commands
    00426     // to the button.
    00427
    00428     QwtPBPaintFilter paintFilter(this);
    00429
    00430     QPainter picPainter(&paintFilter);
    00431     picPainter.setFont(painter->font());
    00432
    00433 #if QT_VERSION >= 300
    00434     // When painting to QPicture the dotted line of the focus rect is
    00435     // set to solid. ( 06.08.2003 )
    00436     // So we donīt set the Style_HasFocus flag and paint the focus rect
    00437     // later directly to the button.
    00438
    00439     QStyle::SFlags flags = QStyle::Style_Default;
    00440     if (isEnabled())
    00441         flags |= QStyle::Style_Enabled;
    00442     if (isDown())
    00443         flags |= QStyle::Style_Down;
    00444     if (isOn())
    00445         flags |= QStyle::Style_On;
    00446     if (! isFlat() && ! isDown())
    00447         flags |= QStyle::Style_Raised;
    00448     if (isDefault())
    00449         flags |= QStyle::Style_ButtonDefault;
    00450
    00451     style().drawControl(QStyle::CE_PushButtonLabel, &picPainter, this,
    00452             style().subRect(QStyle::SR_PushButtonContents, this),
    00453             colorGroup(), flags);
    00454 #else
    00455     // For Qt <= 2.x the focus rect is not painted in
    00456     // drawButtonLabel. So we donīt need a workaround here.
    00457
    00458     QPushButton::drawButtonLabel(&picPainter);
    00459 #endif
    00460
    00461     picPainter.end();
    00462
    00463     paintFilter.play(painter);
    00464
    00465 #if QT_VERSION >= 300
    00466     if (hasFocus())
    00467     {
    00468         // Paint the focus rect on top of the button label.
    00469
    00470         flags |= QStyle::Style_HasFocus;
    00471         style().drawPrimitive(QStyle::PE_FocusRect, painter,
    00472             style().subRect(QStyle::SR_PushButtonFocusRect, this),
    00473             colorGroup(), flags);
    00474     }
    00475 #endif
    00476
    00477 #else // QT_NO_PICTURE
    00478     QPushButton::drawButtonLabel(painter);
    00479 #endif
    00480 }
    00481
    00482 // Local Variables:
    00483 // mode: C++
    00484 // c-file-style: "stroustrup"
    00485 // indent-tabs-mode: nil
    00486 // End: