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:

Generated on Sun Nov 21 11:12:44 2004 for Qwt User's Guide by doxygen 1.3.5