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 #if QT_VERSION < 0x040000
00575             QwtPainter::drawRect(painter, rect);
00576 #else
00577             const QRect r(rect.x(), rect.y(), 
00578                 rect.width() - 1, rect.height() - 1);
00579             QwtPainter::drawRect(painter, r);
00580 #endif
00581             painter->restore();
00582         }
00583     }
00584 
00585     painter->save();
00586 
00587     if ( d_data->paintAttributes & PaintUsingTextFont )
00588     {
00589         painter->setFont(d_data->font);
00590     }
00591 
00592     if ( d_data->paintAttributes & PaintUsingTextColor )
00593     {
00594         if ( d_data->color.isValid() )
00595             painter->setPen(d_data->color);
00596     }
00597 
00598     QRect expandedRect = rect;
00599     if ( d_data->layoutAttributes & MinimumLayout )
00600     {
00601 #if QT_VERSION < 0x040000
00602         const QFont font(painter->font());
00603 #else
00604         // We want to calculate in screen metrics. So
00605         // we need a font that uses screen metrics
00606 
00607         const QFont font(painter->font(), QApplication::desktop());
00608 #endif
00609 
00610         int left, right, top, bottom;
00611         d_data->textEngine->textMargins(
00612             font, d_data->text,
00613             left, right, top, bottom);
00614 
00615         const QwtMetricsMap map = QwtPainter::metricsMap();
00616         left = map.screenToLayoutX(left);
00617         right = map.screenToLayoutX(right);
00618         top = map.screenToLayoutY(top);
00619         bottom = map.screenToLayoutY(bottom);
00620 
00621         expandedRect.setTop(rect.top() - top);
00622         expandedRect.setBottom(rect.bottom() + bottom);
00623         expandedRect.setLeft(rect.left() - left);
00624         expandedRect.setRight(rect.right() + right);
00625     }
00626 
00627     d_data->textEngine->draw(painter, expandedRect, 
00628         d_data->renderFlags, d_data->text);
00629 
00630     painter->restore();
00631 }
00632 
00646 const QwtTextEngine *QwtText::textEngine(const QString &text,
00647     QwtText::TextFormat format)
00648 {
00649     if ( engineDict == NULL )
00650     {
00651         /*
00652           Note: engineDict is allocated, the first time it is used, 
00653                 but never deleted, because there is no known last access time.
00654                 So don't be irritated, if it is reported as a memory leak
00655                 from your memory profiler.
00656          */
00657         engineDict = new QwtTextEngineDict();
00658     }
00659 
00660     return engineDict->textEngine(text, format);
00661 }
00662 
00681 void QwtText::setTextEngine(QwtText::TextFormat format, 
00682     QwtTextEngine *engine)
00683 {
00684     if ( engineDict == NULL )
00685         engineDict = new QwtTextEngineDict();
00686 
00687     engineDict->setTextEngine(format, engine);
00688 }
00689 
00701 const QwtTextEngine *QwtText::textEngine(QwtText::TextFormat format)
00702 {
00703     if ( engineDict == NULL )
00704         engineDict = new QwtTextEngineDict();
00705 
00706     return engineDict->textEngine(format);
00707 }

Generated on Sat May 24 18:47:40 2008 for Qwt User's Guide by  doxygen 1.5.0