qwt_text_engine.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2003   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 <qpixmap.h>
00014 #include <qimage.h>
00015 #include <qmap.h>
00016 #include <qwidget.h>
00017 #include "qwt_math.h"
00018 #include "qwt_painter.h"
00019 #include "qwt_text_engine.h"
00020 
00021 #if QT_VERSION < 0x040000
00022 
00023 #include <qsimplerichtext.h>
00024 #include <qstylesheet.h>
00025 
00026 class QwtRichTextDocument: public QSimpleRichText
00027 {
00028 public:
00029     QwtRichTextDocument(const QString &text, const QFont &font):
00030         QSimpleRichText(text, font)
00031     {
00032     }
00033 };
00034 
00035 #else // QT_VERSION >= 0x040000
00036 
00037 #if QT_VERSION < 0x040200
00038 #define USE_LABEL 1
00039 #endif
00040 
00041 #ifdef USE_LABEL
00042 #include <qlabel.h>
00043 #else
00044 #include <qtextobject.h>
00045 #endif
00046 #include <qtextdocument.h>
00047 #include <qabstracttextdocumentlayout.h>
00048 
00049 class QwtRichTextDocument: public QTextDocument
00050 {
00051 public:
00052     QwtRichTextDocument(const QString &text, const QFont &font)
00053     {
00054         setUndoRedoEnabled(false);
00055         setDefaultFont(font);
00056         setHtml(text);
00057 
00058         // make sure we have a document layout
00059         (void)documentLayout();
00060     }
00061 };
00062 
00063 #endif
00064 
00065 class QwtPlainTextEngine::PrivateData
00066 {
00067 public:
00068     int effectiveAscent(const QFont &font) const
00069     {
00070         const QString fontKey = font.key();
00071 
00072         QMap<QString, int>::const_iterator it = 
00073             d_ascentCache.find(fontKey);
00074         if ( it == d_ascentCache.end() )
00075         {
00076             int ascent = findAscent(font);
00077             it = d_ascentCache.insert(fontKey, ascent);
00078         }
00079 
00080         return (*it);
00081     }
00082 
00083 private:
00084     int findAscent(const QFont &font) const
00085     {
00086         static const QString dummy("E");
00087         static const QColor white(Qt::white);
00088 
00089         const QFontMetrics fm(font);
00090         QPixmap pm(fm.width(dummy), fm.height()); 
00091         pm.fill(white);
00092 
00093         QPainter p(&pm);
00094         p.setFont(font);  
00095         p.drawText(0, 0,  pm.width(), pm.height(), 0, dummy);
00096         p.end();
00097 
00098     #if QT_VERSION < 0x040000
00099         const QImage img = pm.convertToImage();
00100     #else
00101         const QImage img = pm.toImage();
00102     #endif
00103 
00104         int row = 0;
00105         for ( row = 0; row < img.height(); row++ )
00106         {   
00107             const QRgb *line = (const QRgb *)img.scanLine(row);
00108 
00109             const int w = pm.width();
00110             for ( int col = 0; col < w; col++ )
00111             {   
00112                 if ( line[col] != white.rgb() )
00113                     return fm.ascent() - row + 1;
00114             }
00115         }
00116 
00117         return fm.ascent();
00118     }   
00119 
00120     mutable QMap<QString, int> d_ascentCache;
00121 };
00122 
00124 QwtTextEngine::QwtTextEngine()
00125 {
00126 }
00127 
00129 QwtTextEngine::~QwtTextEngine()
00130 {
00131 }
00132 
00134 QwtPlainTextEngine::QwtPlainTextEngine()
00135 {
00136     d_data = new PrivateData;
00137 }
00138 
00140 QwtPlainTextEngine::~QwtPlainTextEngine()
00141 {
00142     delete d_data;
00143 }
00144 
00155 int QwtPlainTextEngine::heightForWidth(const QFont& font, int flags,
00156         const QString& text, int width) const
00157 {
00158     const QFontMetrics fm(font);
00159     const QRect rect = fm.boundingRect(
00160         0, 0, width, QWIDGETSIZE_MAX, flags, text);
00161 
00162     return rect.height();
00163 }
00164 
00174 QSize QwtPlainTextEngine::textSize(const QFont &font,
00175     int flags, const QString& text) const
00176 {
00177     const QFontMetrics fm(font);
00178     const QRect rect = fm.boundingRect(
00179         0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, flags, text);
00180 
00181     return rect.size();
00182 }
00183 
00193 void QwtPlainTextEngine::textMargins(const QFont &font, const QString &,
00194     int &left, int &right, int &top, int &bottom) const
00195 {
00196     left = right = top = 0;
00197 
00198     const QFontMetrics fm(font);
00199     top = fm.ascent() - d_data->effectiveAscent(font);
00200     bottom = fm.descent() + 1;
00201 }
00202 
00213 void QwtPlainTextEngine::draw(QPainter *painter, const QRect &rect,
00214     int flags, const QString& text) const
00215 {
00216     QwtPainter::drawText(painter, rect, flags, text);
00217 }
00218 
00223 bool QwtPlainTextEngine::mightRender(const QString &) const
00224 {
00225     return true;
00226 }
00227 
00228 #ifndef QT_NO_RICHTEXT
00229 
00231 QwtRichTextEngine::QwtRichTextEngine()
00232 {
00233 }
00234 
00245 int QwtRichTextEngine::heightForWidth(const QFont& font, int flags,
00246         const QString& text, int width) const
00247 {
00248     QwtRichTextDocument doc(taggedText(text, flags), font);
00249 
00250 #if QT_VERSION < 0x040000
00251     doc.setWidth(width);
00252     const int h = doc.height();
00253 #else
00254     doc.setPageSize(QSize(width, QWIDGETSIZE_MAX));
00255     const int h = qRound(doc.documentLayout()->documentSize().height());
00256 #endif
00257     return h;
00258 }
00259 
00270 QSize QwtRichTextEngine::textSize(const QFont &font,
00271     int flags, const QString& text) const
00272 {
00273     QwtRichTextDocument doc(taggedText(text, flags), font);
00274 
00275 #if QT_VERSION < 0x040000
00276     doc.setWidth(QWIDGETSIZE_MAX);
00277 
00278     int w = doc.widthUsed();
00279     int h = doc.height();
00280 #else
00281 #if USE_LABEL 
00282     /*
00283       Unfortunately offering the bounding rect calculation in the
00284       API of QTextDocument has been forgotten in Qt <= 4.1.x. It
00285       is planned to come with Qt 4.2.x.
00286       In the meantime we need a hack with a temporary QLabel,
00287       to reengineer the internal calculations.
00288      */
00289 
00290     static int off = 0;
00291     static QLabel *label = NULL;
00292     if ( label == NULL )
00293     {
00294         label = new QLabel;
00295         label->hide();
00296 
00297         const char *s = "XXXXX";
00298         label->setText(s);
00299         int w1 = label->sizeHint().width();
00300         const QFontMetrics fm(label->font());
00301         int w2 = fm.width(s);
00302         off = w1 - w2;
00303     }
00304     label->setFont(doc.defaultFont());
00305     label->setText(text);
00306 
00307     int w = qwtMax(label->sizeHint().width() - off, 0);
00308     doc.setPageSize(QSize(w, QWIDGETSIZE_MAX));
00309     
00310     int h = qRound(doc.documentLayout()->documentSize().height());
00311 #else
00312     QTextLayout *layout = doc.begin().layout();
00313     layout->beginLayout();
00314     for(qreal y = 0;;)  
00315     {
00316         QTextLine line = layout->createLine();
00317         if (!line.isValid())
00318             break;
00319         line.setPosition(QPointF(0, y));
00320         y += line.height();
00321     }
00322     layout->endLayout();
00323 
00324     int w = qRound(layout->maximumWidth());
00325     int h = qRound(layout->boundingRect().height());
00326 
00327     h += QFontMetrics(font).descent() + 4;
00328     w += 2 * 4;
00329 #endif
00330 #endif
00331 
00332     return QSize(w, h);
00333 }
00334 
00343 void QwtRichTextEngine::draw(QPainter *painter, const QRect &rect,
00344     int flags, const QString& text) const
00345 {
00346     QwtRichTextDocument doc(taggedText(text, flags), painter->font());
00347     QwtPainter::drawSimpleRichText(painter, rect, flags, doc);
00348 }
00349 
00358 QString QwtRichTextEngine::taggedText(const QString &text, int flags) const
00359 {
00360     QString richText = text;
00361 
00362     // By default QSimpleRichText is Qt::AlignLeft
00363     if (flags & Qt::AlignJustify)
00364     {
00365         richText.prepend(QString::fromLatin1("<div align=\"justify\">"));
00366         richText.append(QString::fromLatin1("</div>"));
00367     }
00368     else if (flags & Qt::AlignRight)
00369     {
00370         richText.prepend(QString::fromLatin1("<div align=\"right\">"));
00371         richText.append(QString::fromLatin1("</div>"));
00372     }
00373     else if (flags & Qt::AlignHCenter)
00374     {
00375         richText.prepend(QString::fromLatin1("<div align=\"center\">"));
00376         richText.append(QString::fromLatin1("</div>"));
00377     }
00378 
00379     return richText;
00380 }
00381 
00388 bool QwtRichTextEngine::mightRender(const QString &text) const
00389 {
00390 #if QT_VERSION < 0x040000
00391     return QStyleSheet::mightBeRichText(text);
00392 #else
00393     return Qt::mightBeRichText(text);
00394 #endif
00395 }
00396 
00405 void QwtRichTextEngine::textMargins(const QFont &, const QString &,
00406     int &left, int &right, int &top, int &bottom) const
00407 {
00408     left = right = top = bottom = 0;
00409 }
00410 
00411 #endif // !QT_NO_RICHTEXT

Generated on Mon Feb 26 21:22:39 2007 for Qwt User's Guide by  doxygen 1.4.6