qwt_text.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 <qmap.h>
00013 #include <qfont.h>
00014 #include <qcolor.h>
00015 #include <qpen.h>
00016 #include <qbrush.h>
00017 #include <qpainter.h>
00018 #include "qwt_painter.h"
00019 #include "qwt_text_engine.h"
00020 #include "qwt_text.h"
00021 #if QT_VERSION >= 0x040000
00022 #include <qapplication.h>
00023 #include <qdesktopwidget.h>
00024 #endif
00025 
00026 class QwtTextEngineDict
00027 {
00028 public:
00029     QwtTextEngineDict();
00030     ~QwtTextEngineDict();
00031 
00032     void setTextEngine(QwtText::TextFormat, QwtTextEngine *);
00033     const QwtTextEngine *textEngine(QwtText::TextFormat) const;
00034     const QwtTextEngine *textEngine(const QString &, 
00035         QwtText::TextFormat) const;
00036 
00037 private:
00038     typedef QMap<int, QwtTextEngine *> EngineMap;
00039 
00040     inline const QwtTextEngine *engine(EngineMap::const_iterator &it) const 
00041     {
00042 #if QT_VERSION < 0x040000
00043         return it.data();
00044 #else
00045         return it.value();
00046 #endif
00047     }
00048 
00049     EngineMap d_map;
00050 };
00051 
00052 QwtTextEngineDict::QwtTextEngineDict()
00053 {
00054     d_map.insert(QwtText::PlainText, new QwtPlainTextEngine());
00055 #ifndef QT_NO_RICHTEXT
00056     d_map.insert(QwtText::RichText, new QwtRichTextEngine());
00057 #endif
00058 }
00059 
00060 QwtTextEngineDict::~QwtTextEngineDict()
00061 {
00062     for ( EngineMap::const_iterator it = d_map.begin(); 
00063         it != d_map.end(); ++it )
00064     {
00065         QwtTextEngine *textEngine = (QwtTextEngine *)engine(it);
00066         delete textEngine;
00067     }
00068 }
00069 
00070 const QwtTextEngine *QwtTextEngineDict::textEngine(const QString& text,
00071     QwtText::TextFormat format) const
00072 {
00073     if ( format == QwtText::AutoText )
00074     {
00075         for ( EngineMap::const_iterator it = d_map.begin(); 
00076             it != d_map.end(); ++it )
00077         {
00078             if ( it.key() != QwtText::PlainText )
00079             {
00080                 const QwtTextEngine *e = engine(it);
00081                 if ( e && e->mightRender(text) )
00082                     return (QwtTextEngine *)e;
00083             }
00084         }
00085     }
00086 
00087     EngineMap::const_iterator it = d_map.find(format);
00088     if ( it != d_map.end() )
00089     {
00090         const QwtTextEngine *e = engine(it);
00091         if ( e )
00092             return e;
00093     }
00094 
00095     it = d_map.find(QwtText::PlainText);
00096     return engine(it);
00097 }
00098 
00099 void QwtTextEngineDict::setTextEngine(QwtText::TextFormat format, 
00100     QwtTextEngine *engine)
00101 {
00102     if ( format == QwtText::AutoText )
00103         return;
00104 
00105     if ( format == QwtText::PlainText && engine == NULL )
00106         return;
00107 
00108     EngineMap::const_iterator it = d_map.find(format);
00109     if ( it != d_map.end() )
00110     {
00111         const QwtTextEngine *e = this->engine(it);
00112         if ( e )
00113             delete e;
00114 
00115         d_map.remove(format);
00116     }
00117 
00118     if ( engine != NULL )
00119         d_map.insert(format, engine);
00120 }
00121 
00122 const QwtTextEngine *QwtTextEngineDict::textEngine(
00123     QwtText::TextFormat format) const
00124 {
00125     const QwtTextEngine *e = NULL;
00126 
00127     EngineMap::const_iterator it = d_map.find(format);
00128     if ( it != d_map.end() )
00129         e = engine(it);
00130 
00131     return e;
00132 }
00133 
00134 static QwtTextEngineDict *engineDict = NULL;
00135 
00136 class QwtText::PrivateData
00137 {
00138 public:
00139     PrivateData():
00140         renderFlags(Qt::AlignCenter),
00141         backgroundPen(Qt::NoPen),
00142         backgroundBrush(Qt::NoBrush),
00143         paintAttributes(0),
00144         layoutAttributes(0),
00145         textEngine(NULL)
00146     {
00147     }
00148 
00149     int renderFlags;
00150     QString text;
00151     QFont font;
00152     QColor color;
00153     QPen backgroundPen;
00154     QBrush backgroundBrush;
00155 
00156     int paintAttributes;
00157     int layoutAttributes;
00158 
00159     const QwtTextEngine *textEngine;
00160 };
00161 
00162 class QwtText::LayoutCache
00163 {
00164 public:
00165     void invalidate()
00166     {
00167         textSize = QSize();
00168     }
00169 
00170     QFont font;
00171     QSize textSize;
00172 };
00173 
00180 QwtText::QwtText(const QString &text, QwtText::TextFormat textFormat)
00181 {
00182     d_data = new PrivateData;
00183     d_data->text = text;
00184     d_data->textEngine = textEngine(text, textFormat);
00185 
00186     d_layoutCache = new LayoutCache;
00187 }
00188 
00190 QwtText::QwtText(const QwtText &other)
00191 {
00192     d_data = new PrivateData;
00193     *d_data = *other.d_data;
00194 
00195     d_layoutCache = new LayoutCache;
00196     *d_layoutCache = *other.d_layoutCache;
00197 }
00198 
00200 QwtText::~QwtText() 
00201 {
00202     delete d_data;
00203     delete d_layoutCache;
00204 }
00205 
00207 QwtText &QwtText::operator=(const QwtText &other)
00208 {
00209     *d_data = *other.d_data;
00210     *d_layoutCache = *other.d_layoutCache;
00211     return *this;
00212 }
00213     
00214 int QwtText::operator==(const QwtText &other) const
00215 {
00216     return d_data->renderFlags == other.d_data->renderFlags &&
00217         d_data->text == other.d_data->text &&
00218         d_data->font == other.d_data->font &&
00219         d_data->color == other.d_data->color &&
00220         d_data->backgroundPen == other.d_data->backgroundPen &&
00221         d_data->backgroundBrush == other.d_data->backgroundBrush &&
00222         d_data->paintAttributes == other.d_data->paintAttributes &&
00223         d_data->textEngine == other.d_data->textEngine;
00224 }
00225 
00226 int QwtText::operator!=(const QwtText &other) const // invalidate
00227 {
00228    return !(other == *this);
00229 }
00230 
00237 void QwtText::setText(const QString &text, 
00238     QwtText::TextFormat textFormat) 
00239 { 
00240     d_data->text = text; 
00241     d_data->textEngine = textEngine(text, textFormat);
00242     d_layoutCache->invalidate();
00243 }
00244 
00249 QString QwtText::text() const 
00250 { 
00251     return d_data->text; 
00252 }
00253 
00264 void QwtText::setRenderFlags(int renderFlags) 
00265 { 
00266     if ( renderFlags != d_data->renderFlags )
00267     {
00268         d_data->renderFlags = renderFlags; 
00269         d_layoutCache->invalidate();
00270     }
00271 }
00272 
00277 int QwtText::renderFlags() const 
00278 { 
00279     return d_data->renderFlags; 
00280 }
00281 
00289 void QwtText::setFont(const QFont &font) 
00290 {
00291     d_data->font = font; 
00292     setPaintAttribute(PaintUsingTextFont);
00293 }
00294 
00296 QFont QwtText::font() const 
00297 { 
00298     return d_data->font; 
00299 }
00300 
00308 QFont QwtText::usedFont(const QFont &defaultFont) const
00309 {
00310     if ( d_data->paintAttributes & PaintUsingTextFont )
00311         return d_data->font;
00312 
00313     return defaultFont;
00314 }
00315 
00323 void QwtText::setColor(const QColor &color) 
00324 { 
00325     d_data->color = color; 
00326     setPaintAttribute(PaintUsingTextColor);
00327 }
00328 
00330 QColor QwtText::color() const 
00331 { 
00332     return d_data->color; 
00333 }
00334 
00342 QColor QwtText::usedColor(const QColor &defaultColor) const
00343 {
00344     if ( d_data->paintAttributes & PaintUsingTextColor )
00345         return d_data->color;
00346 
00347     return defaultColor;
00348 }
00349 
00356 void QwtText::setBackgroundPen(const QPen &pen) 
00357 { 
00358     d_data->backgroundPen = pen; 
00359     setPaintAttribute(PaintBackground);
00360 }
00361 
00366 QPen QwtText::backgroundPen() const 
00367 { 
00368     return d_data->backgroundPen; 
00369 }
00370 
00377 void QwtText::setBackgroundBrush(const QBrush &brush) 
00378 { 
00379     d_data->backgroundBrush = brush; 
00380     setPaintAttribute(PaintBackground);
00381 }
00382 
00387 QBrush QwtText::backgroundBrush() const 
00388 { 
00389     return d_data->backgroundBrush; 
00390 }
00391 
00401 void QwtText::setPaintAttribute(PaintAttribute attribute, bool on)
00402 {
00403     if ( on )
00404         d_data->paintAttributes |= attribute;
00405     else
00406         d_data->paintAttributes &= ~attribute;
00407 }
00408 
00417 bool QwtText::testPaintAttribute(PaintAttribute attribute) const
00418 {
00419     return d_data->paintAttributes & attribute;
00420 }
00421 
00429 void QwtText::setLayoutAttribute(LayoutAttribute attribute, bool on)
00430 {
00431     if ( on )
00432         d_data->layoutAttributes |= attribute;
00433     else
00434         d_data->layoutAttributes &= ~attribute;
00435 }
00436 
00445 bool QwtText::testLayoutAttribute(LayoutAttribute attribute) const
00446 {
00447     return d_data->layoutAttributes | attribute;
00448 }
00449 
00458 int QwtText::heightForWidth(int width, const QFont &defaultFont) const
00459 {
00460     const QwtMetricsMap map = QwtPainter::metricsMap();
00461     width = map.layoutToScreenX(width);
00462 
00463 #if QT_VERSION < 0x040000
00464     const QFont font = usedFont(defaultFont);
00465 #else
00466     // We want to calculate in screen metrics. So
00467     // we need a font that uses screen metrics
00468 
00469     const QFont font(usedFont(defaultFont), QApplication::desktop());
00470 #endif
00471 
00472     int h = 0;
00473 
00474     if ( d_data->layoutAttributes & MinimumLayout )
00475     {
00476         int left, right, top, bottom;
00477         d_data->textEngine->textMargins(font, d_data->text,
00478             left, right, top, bottom);
00479 
00480         h = d_data->textEngine->heightForWidth(
00481             font, d_data->renderFlags, d_data->text, 
00482             width + left + right);
00483 
00484         h -= top + bottom;
00485     }
00486     else
00487     {
00488         h = d_data->textEngine->heightForWidth(
00489             font, d_data->renderFlags, d_data->text, width);
00490     }
00491 
00492     h = map.screenToLayoutY(h);
00493     return h;
00494 }
00495 
00510 QSize QwtText::textSize(const QFont &defaultFont) const
00511 {
00512 #if QT_VERSION < 0x040000
00513     const QFont font(usedFont(defaultFont));
00514 #else
00515     // We want to calculate in screen metrics. So
00516     // we need a font that uses screen metrics
00517 
00518     const QFont font(usedFont(defaultFont), QApplication::desktop());
00519 #endif
00520 
00521     if ( !d_layoutCache->textSize.isValid() 
00522         || d_layoutCache->font != font )
00523     {
00524         d_layoutCache->textSize = d_data->textEngine->textSize(
00525             font, d_data->renderFlags, d_data->text);
00526         d_layoutCache->font = font;
00527     }
00528 
00529     QSize sz = d_layoutCache->textSize;
00530 
00531     const QwtMetricsMap map = QwtPainter::metricsMap();
00532 
00533     if ( d_data->layoutAttributes & MinimumLayout )
00534     {
00535         int left, right, top, bottom;
00536         d_data->textEngine->textMargins(font, d_data->text,
00537             left, right, top, bottom);
00538         sz -= QSize(left + right, top + bottom);
00539 #if QT_VERSION >= 0x040000
00540         if ( !map.isIdentity() )
00541         {
00542 #ifdef __GNUC__
00543 #warning Too small text size, when printing in high resolution
00544 #endif
00545             /*
00546                 When printing in high resolution, the tick labels
00547                 of are cut of. We need to find out why, but for
00548                 the moment we add a couple of pixels instead.
00549              */
00550             sz += QSize(3, 0);
00551         }
00552 #endif
00553     }
00554 
00555     sz = map.screenToLayout(sz);
00556     return sz;
00557 }
00558 
00565 void QwtText::draw(QPainter *painter, const QRect &rect) const
00566 {
00567     if ( d_data->paintAttributes & PaintBackground )
00568     {
00569         if ( d_data->backgroundPen != Qt::NoPen || 
00570             d_data->backgroundBrush != Qt::NoBrush )
00571         {
00572             painter->save();
00573             painter->setPen(d_data->backgroundPen);
00574             painter->setBrush(d_data->backgroundBrush);
00575             QwtPainter::drawRect(painter, rect);
00576             painter->restore();
00577         }
00578     }
00579 
00580     painter->save();
00581 
00582     if ( d_data->paintAttributes & PaintUsingTextFont )
00583     {
00584         painter->setFont(d_data->font);
00585     }
00586 
00587     if ( d_data->paintAttributes & PaintUsingTextColor )
00588     {
00589         if ( d_data->color.isValid() )
00590             painter->setPen(d_data->color);
00591     }
00592 
00593     QRect expandedRect = rect;
00594     if ( d_data->layoutAttributes & MinimumLayout )
00595     {
00596 #if QT_VERSION < 0x040000
00597         const QFont font(painter->font());
00598 #else
00599         // We want to calculate in screen metrics. So
00600         // we need a font that uses screen metrics
00601 
00602         const QFont font(painter->font(), QApplication::desktop());
00603 #endif
00604 
00605         int left, right, top, bottom;
00606         d_data->textEngine->textMargins(
00607             font, d_data->text,
00608             left, right, top, bottom);
00609 
00610         const QwtMetricsMap map = QwtPainter::metricsMap();
00611         left = map.screenToLayoutX(left);
00612         right = map.screenToLayoutX(right);
00613         top = map.screenToLayoutY(top);
00614         bottom = map.screenToLayoutY(bottom);
00615 
00616         expandedRect.setTop(rect.top() - top);
00617         expandedRect.setBottom(rect.bottom() + bottom);
00618         expandedRect.setLeft(rect.left() - left);
00619         expandedRect.setRight(rect.right() + right);
00620     }
00621 
00622     d_data->textEngine->draw(painter, expandedRect, 
00623         d_data->renderFlags, d_data->text);
00624 
00625     painter->restore();
00626 }
00627 
00641 const QwtTextEngine *QwtText::textEngine(const QString &text,
00642     QwtText::TextFormat format)
00643 {
00644     if ( engineDict == NULL )
00645         engineDict = new QwtTextEngineDict();
00646 
00647     return engineDict->textEngine(text, format);
00648 }
00649 
00668 void QwtText::setTextEngine(QwtText::TextFormat format, 
00669     QwtTextEngine *engine)
00670 {
00671     if ( engineDict == NULL )
00672         engineDict = new QwtTextEngineDict();
00673 
00674     engineDict->setTextEngine(format, engine);
00675 }
00676 
00688 const QwtTextEngine *QwtText::textEngine(QwtText::TextFormat format)
00689 {
00690     if ( engineDict == NULL )
00691         engineDict = new QwtTextEngineDict();
00692 
00693     return engineDict->textEngine(format);
00694 }

Generated on Sun Jul 22 11:26:54 2007 for Qwt User's Guide by  doxygen 1.5.2