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

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 #define USE_LABEL 1
00038 #ifdef USE_LABEL
00039 #include <qlabel.h>
00040 #else
00041 #include <qtextobject.h>
00042 #endif
00043 #include <qtextdocument.h>
00044 #include <qabstracttextdocumentlayout.h>
00045 
00046 class QwtRichTextDocument: public QTextDocument
00047 {
00048 public:
00049     QwtRichTextDocument(const QString &text, const QFont &font)
00050     {
00051         setUndoRedoEnabled(false);
00052         setDefaultFont(font);
00053         setHtml(text);
00054 
00055         // make sure we have a document layout
00056         (void)documentLayout();
00057     }
00058 };
00059 
00060 #endif
00061 
00062 class QwtPlainTextEngine::PrivateData
00063 {
00064 public:
00065     int effectiveAscent(const QFont &font) const
00066     {
00067         const QString fontKey = font.key();
00068 
00069         QMap<QString, int>::const_iterator it = 
00070             d_ascentCache.find(fontKey);
00071         if ( it == d_ascentCache.end() )
00072         {
00073             int ascent = findAscent(font);
00074             it = d_ascentCache.insert(fontKey, ascent);
00075         }
00076 
00077         return (*it);
00078     }
00079 
00080 private:
00081     int findAscent(const QFont &font) const
00082     {
00083         static const QString dummy("E");
00084         static const QColor white(Qt::white);
00085 
00086         const QFontMetrics fm(font);
00087         QPixmap pm(fm.width(dummy), fm.height()); 
00088         pm.fill(white);
00089 
00090         QPainter p(&pm);
00091         p.setFont(font);  
00092         p.drawText(0, 0,  pm.width(), pm.height(), 0, dummy);
00093         p.end();
00094 
00095     #if QT_VERSION < 0x040000
00096         const QImage img = pm.convertToImage();
00097     #else
00098         const QImage img = pm.toImage();
00099     #endif
00100 
00101         int row = 0;
00102         for ( row = 0; row < img.height(); row++ )
00103         {   
00104             const QRgb *line = (const QRgb *)img.scanLine(row);
00105 
00106             const int w = pm.width();
00107             for ( int col = 0; col < w; col++ )
00108             {   
00109                 if ( line[col] != white.rgb() )
00110                     return fm.ascent() - row + 1;
00111             }
00112         }
00113 
00114         return fm.ascent();
00115     }   
00116 
00117     mutable QMap<QString, int> d_ascentCache;
00118 };
00119 
00120 
00121 QwtTextEngine::QwtTextEngine()
00122 {
00123 }
00124 
00125 QwtTextEngine::~QwtTextEngine()
00126 {
00127 }
00128 
00129 void QwtTextEngine::textMargins(const QFont &, const QString &,
00130     int &left, int &right, int &top, int &bottom)
00131 {
00132     left = right = top = bottom = 0;
00133 }
00134 
00135 QwtPlainTextEngine::QwtPlainTextEngine()
00136 {
00137     d_data = new PrivateData;
00138 }
00139 
00140 QwtPlainTextEngine::~QwtPlainTextEngine()
00141 {
00142     delete d_data;
00143 }
00144 
00145 int QwtPlainTextEngine::heightForWidth(const QFont& font, int flags,
00146         const QString& text, int width) const
00147 {
00148     const QFontMetrics fm(font);
00149     const QRect rect = fm.boundingRect(
00150         0, 0, width, QWIDGETSIZE_MAX, flags, text);
00151 
00152     return rect.height();
00153 }
00154 
00155 QSize QwtPlainTextEngine::textSize(const QFont &font,
00156     int flags, const QString& text) const
00157 {
00158     const QFontMetrics fm(font);
00159     const QRect rect = fm.boundingRect(
00160         0, 0, QWIDGETSIZE_MAX, QWIDGETSIZE_MAX, flags, text);
00161 
00162     return rect.size();
00163 }
00164 
00165 void QwtPlainTextEngine::textMargins(const QFont &font, const QString &,
00166     int &left, int &right, int &top, int &bottom)
00167 {
00168     left = right = top = 0;
00169 
00170     const QFontMetrics fm(font);
00171     top = fm.ascent() - d_data->effectiveAscent(font);
00172     bottom = fm.descent() + 1;
00173 }
00174 
00175 void QwtPlainTextEngine::draw(QPainter *painter, const QRect &rect,
00176     int flags, const QString& text) const
00177 {
00178     QwtPainter::drawText(painter, rect, flags, text);
00179 }
00180 
00181 bool QwtPlainTextEngine::mightRender(const QString &) const
00182 {
00183     return true;
00184 }
00185 
00186 
00187 #ifndef QT_NO_RICHTEXT
00188 
00189 QwtRichTextEngine::QwtRichTextEngine()
00190 {
00191 }
00192 
00193 int QwtRichTextEngine::heightForWidth(const QFont& font, int flags,
00194         const QString& text, int width) const
00195 {
00196     QwtRichTextDocument doc(taggedText(text, flags), font);
00197 
00198 #if QT_VERSION < 0x040000
00199     doc.setWidth(width);
00200     const int h = doc.height();
00201 #else
00202     doc.setPageSize(QSize(width, QWIDGETSIZE_MAX));
00203     const int h = qRound(doc.documentLayout()->documentSize().height());
00204 #endif
00205     return h;
00206 }
00207 
00208 QSize QwtRichTextEngine::textSize(const QFont &font,
00209     int flags, const QString& text) const
00210 {
00211     QwtRichTextDocument doc(taggedText(text, flags), font);
00212 
00213 #if QT_VERSION < 0x040000
00214     doc.setWidth(QWIDGETSIZE_MAX);
00215 
00216     int w = doc.widthUsed();
00217     int h = doc.height();
00218 #else
00219 #if USE_LABEL 
00220     /*
00221       Unfortunately offering the bounding rect calculation in the
00222       API of QTextDocument has been forgotten in Qt <= 4.1.x. It
00223       is planned to come with Qt 4.2.x.
00224       In the meantime we need a hack with a temporary QLabel,
00225       to reengineer the internal calculations.
00226      */
00227 
00228     static int off = 0;
00229     static QLabel *label = NULL;
00230     if ( label == NULL )
00231     {
00232         label = new QLabel;
00233         label->hide();
00234 
00235         const char *s = "XXXXX";
00236         label->setText(s);
00237         int w1 = label->sizeHint().width();
00238         const QFontMetrics fm(label->font());
00239         int w2 = fm.width(s);
00240         off = w1 - w2;
00241     }
00242     label->setFont(doc.defaultFont());
00243     label->setText(text);
00244 
00245     int w = qwtMax(label->sizeHint().width() - off, 0);
00246     doc.setPageSize(QSize(w, QWIDGETSIZE_MAX));
00247     
00248     int h = qRound(doc.documentLayout()->documentSize().height());
00249 #else
00250     QTextLayout *layout = doc.begin().layout();
00251     layout->beginLayout();
00252     for(qreal y = 0;;)  
00253     {
00254         QTextLine line = layout->createLine();
00255         if (!line.isValid())
00256             break;
00257         line.setPosition(QPointF(0, y));
00258         y += line.height();
00259     }
00260     layout->endLayout();
00261 
00262     int w = qRound(layout->maximumWidth());
00263     int h = qRound(layout->boundingRect().height());
00264 
00265     h += QFontMetrics(font).descent() + 4;
00266     w += 2 * 4;
00267 #endif
00268 #endif
00269 
00270     return QSize(w, h);
00271 }
00272 
00273 void QwtRichTextEngine::draw(QPainter *painter, const QRect &rect,
00274     int flags, const QString& text) const
00275 {
00276     QwtRichTextDocument doc(taggedText(text, flags), painter->font());
00277     QwtPainter::drawSimpleRichText(painter, rect, flags, doc);
00278 }
00279 
00281 QString QwtRichTextEngine::taggedText(const QString &text, int flags) const
00282 {
00283     QString richText = text;
00284 
00285     // By default QSimpleRichText is Qt::AlignLeft
00286     if (flags & Qt::AlignJustify)
00287     {
00288         richText.prepend(QString::fromLatin1("<div align=\"justify\">"));
00289         richText.append(QString::fromLatin1("</div>"));
00290     }
00291     else if (flags & Qt::AlignRight)
00292     {
00293         richText.prepend(QString::fromLatin1("<div align=\"right\">"));
00294         richText.append(QString::fromLatin1("</div>"));
00295     }
00296     else if (flags & Qt::AlignHCenter)
00297     {
00298         richText.prepend(QString::fromLatin1("<div align=\"center\">"));
00299         richText.append(QString::fromLatin1("</div>"));
00300     }
00301 
00302     return richText;
00303 }
00304 
00305 bool QwtRichTextEngine::mightRender(const QString &text) const
00306 {
00307 #if QT_VERSION < 0x040000
00308     return QStyleSheet::mightBeRichText(text);
00309 #else
00310     return Qt::mightBeRichText(text);
00311 #endif
00312 }
00313 
00314 #endif // !QT_NO_RICHTEXT

Generated on Mon Jan 30 22:16:26 2006 for Qwt User's Guide by  doxygen 1.4.4