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 #endif
00544             /*
00545                 When printing in high resolution, the tick labels
00546                 of are cut of. We need to find out why, but for
00547                 the moment we add a couple of pixels instead.
00548              */
00549             sz += QSize(3, 0);
00550         }
00551 #endif
00552     }
00553 
00554     sz = map.screenToLayout(sz);
00555     return sz;
00556 }
00557 
00564 void QwtText::draw(QPainter *painter, const QRect &rect) const
00565 {
00566     if ( d_data->paintAttributes & PaintBackground )
00567     {
00568         if ( d_data->backgroundPen != Qt::NoPen || 
00569             d_data->backgroundBrush != Qt::NoBrush )
00570         {
00571             painter->save();
00572             painter->setPen(d_data->backgroundPen);
00573             painter->setBrush(d_data->backgroundBrush);
00574             QwtPainter::drawRect(painter, rect);
00575             painter->restore();
00576         }
00577     }
00578 
00579     painter->save();
00580 
00581     if ( d_data->paintAttributes & PaintUsingTextFont )
00582     {
00583         painter->setFont(d_data->font);
00584     }
00585 
00586     if ( d_data->paintAttributes & PaintUsingTextColor )
00587     {
00588         if ( d_data->color.isValid() )
00589             painter->setPen(d_data->color);
00590     }
00591 
00592     QRect expandedRect = rect;
00593     if ( d_data->layoutAttributes & MinimumLayout )
00594     {
00595 #if QT_VERSION < 0x040000
00596         const QFont font(painter->font());
00597 #else
00598         // We want to calculate in screen metrics. So
00599         // we need a font that uses screen metrics
00600 
00601         const QFont font(painter->font(), QApplication::desktop());
00602 #endif
00603 
00604         int left, right, top, bottom;
00605         d_data->textEngine->textMargins(
00606             font, d_data->text,
00607             left, right, top, bottom);
00608 
00609         const QwtMetricsMap map = QwtPainter::metricsMap();
00610         left = map.screenToLayoutX(left);
00611         right = map.screenToLayoutX(right);
00612         top = map.screenToLayoutY(top);
00613         bottom = map.screenToLayoutY(bottom);
00614 
00615         expandedRect.setTop(rect.top() - top);
00616         expandedRect.setBottom(rect.bottom() + bottom);
00617         expandedRect.setLeft(rect.left() - left);
00618         expandedRect.setRight(rect.right() + right);
00619     }
00620 
00621     d_data->textEngine->draw(painter, expandedRect, 
00622         d_data->renderFlags, d_data->text);
00623 
00624     painter->restore();
00625 }
00626 
00640 const QwtTextEngine *QwtText::textEngine(const QString &text,
00641     QwtText::TextFormat format)
00642 {
00643     if ( engineDict == NULL )
00644         engineDict = new QwtTextEngineDict();
00645 
00646     return engineDict->textEngine(text, format);
00647 }
00648 
00667 void QwtText::setTextEngine(QwtText::TextFormat format, 
00668     QwtTextEngine *engine)
00669 {
00670     if ( engineDict == NULL )
00671         engineDict = new QwtTextEngineDict();
00672 
00673     engineDict->setTextEngine(format, engine);
00674 }
00675 
00687 const QwtTextEngine *QwtText::textEngine(QwtText::TextFormat format)
00688 {
00689     if ( engineDict == NULL )
00690         engineDict = new QwtTextEngineDict();
00691 
00692     return engineDict->textEngine(format);
00693 }

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