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 <QPluginLoader>
00023 #include <qapplication.h>
00024 #include <qdesktopwidget.h>
00025 #include <qdir.h>
00026 #include "qwt_text_plugin.h"
00027 #endif
00028 
00029 class QwtTextEngineDict
00030 {
00031 public:
00032     QwtTextEngineDict();
00033     ~QwtTextEngineDict();
00034 
00035     const QwtTextEngine *textEngine(QwtText::TextFormat) const;
00036     const QwtTextEngine *textEngine(const QString &, 
00037         QwtText::TextFormat) const;
00038 
00039 private:
00040     typedef QMap<int, QwtTextEngine *> EngineMap;
00041 
00042     inline const QwtTextEngine *engine(EngineMap::const_iterator &it) const 
00043     {
00044 #if QT_VERSION < 0x040000
00045         return it.data();
00046 #else
00047         return it.value();
00048 #endif
00049     }
00050 
00051     EngineMap d_map;
00052 };
00053 
00054 QwtTextEngineDict::QwtTextEngineDict()
00055 {
00056     d_map.insert(QwtText::PlainText, new QwtPlainTextEngine());
00057 #ifndef QT_NO_RICHTEXT
00058     d_map.insert(QwtText::RichText, new QwtRichTextEngine());
00059 #endif
00060 
00061 #if QT_VERSION >= 0x040000
00062 
00063     // Plugins are not implemented for Qt 3
00064 
00065     const QStringList libPaths = QApplication::libraryPaths();
00066     foreach (QString path, QApplication::libraryPaths())
00067     {
00068         QDir pluginsDir(path);
00069         if ( !pluginsDir.cd("qwttextengines") )
00070             continue;
00071 
00072         foreach (QString fileName, pluginsDir.entryList(QDir::Files))
00073         {
00074             QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
00075 
00076             QwtTextPlugin *plugin = 
00077                 qobject_cast<QwtTextPlugin *>(loader.instance());
00078             if (plugin)
00079             {
00080                 if ( ::qgetenv("QWT_DEBUG_PLUGINS").toInt() > 0 )
00081                 {
00082                     qDebug("Qwt Text Plugin loaded: %s\n", 
00083                         qPrintable(loader.fileName()) );
00084                 }
00085                 EngineMap::iterator it = d_map.find(plugin->format());
00086                 if ( it == d_map.end() )
00087                     d_map.insert(plugin->format(), plugin->engine());
00088             }
00089         }
00090     }
00091 #endif // QT_VERSION >= 0x040000
00092 }
00093 
00094 QwtTextEngineDict::~QwtTextEngineDict()
00095 {
00096     for ( EngineMap::const_iterator it = d_map.begin(); 
00097         it != d_map.end(); ++it )
00098     {
00099         QwtTextEngine *textEngine = (QwtTextEngine *)engine(it);
00100         delete textEngine;
00101     }
00102 }
00103 
00104 const QwtTextEngine *QwtTextEngineDict::textEngine(const QString& text,
00105     QwtText::TextFormat format) const
00106 {
00107     if ( format == QwtText::AutoText )
00108     {
00109         for ( EngineMap::const_iterator it = d_map.begin(); 
00110             it != d_map.end(); ++it )
00111         {
00112             if ( it.key() != QwtText::PlainText )
00113             {
00114                 const QwtTextEngine *e = engine(it);
00115                 if ( e && e->mightRender(text) )
00116                     return (QwtTextEngine *)e;
00117             }
00118         }
00119     }
00120 
00121     EngineMap::const_iterator it = d_map.find(format);
00122     if ( it != d_map.end() )
00123     {
00124         const QwtTextEngine *e = engine(it);
00125         if ( e )
00126             return e;
00127     }
00128 
00129     it = d_map.find(QwtText::PlainText);
00130     return engine(it);
00131 }
00132 
00133 const QwtTextEngine *QwtTextEngineDict::textEngine(
00134     QwtText::TextFormat format) const
00135 {
00136     const QwtTextEngine *e = NULL;
00137 
00138     EngineMap::const_iterator it = d_map.find(format);
00139     if ( it != d_map.end() )
00140         e = engine(it);
00141 
00142     return e;
00143 }
00144 
00145 static QwtTextEngineDict *engineDict = NULL;
00146 
00147 class QwtText::PrivateData
00148 {
00149 public:
00150     PrivateData():
00151         renderFlags(Qt::AlignCenter),
00152         backgroundPen(Qt::NoPen),
00153         backgroundBrush(Qt::NoBrush),
00154         paintAttributes(0),
00155         layoutAttributes(0),
00156         textEngine(NULL)
00157     {
00158     }
00159 
00160     int renderFlags;
00161     QString text;
00162     QFont font;
00163     QColor color;
00164     QPen backgroundPen;
00165     QBrush backgroundBrush;
00166 
00167     int paintAttributes;
00168     int layoutAttributes;
00169 
00170     const QwtTextEngine *textEngine;
00171 };
00172 
00173 class QwtText::LayoutCache
00174 {
00175 public:
00176     void invalidate()
00177     {
00178         textSize = QSize();
00179     }
00180 
00181     QFont font;
00182     QSize textSize;
00183 };
00184 
00191 QwtText::QwtText(const QString &text, QwtText::TextFormat textFormat)
00192 {
00193     d_data = new PrivateData;
00194     d_data->text = text;
00195     d_data->textEngine = textEngine(text, textFormat);
00196 
00197     d_layoutCache = new LayoutCache;
00198 }
00199 
00201 QwtText::QwtText(const QwtText &other)
00202 {
00203     d_data = new PrivateData;
00204     *d_data = *other.d_data;
00205 
00206     d_layoutCache = new LayoutCache;
00207     *d_layoutCache = *other.d_layoutCache;
00208 }
00209 
00211 QwtText::~QwtText() 
00212 {
00213     delete d_data;
00214     delete d_layoutCache;
00215 }
00216 
00218 QwtText &QwtText::operator=(const QwtText &other)
00219 {
00220     *d_data = *other.d_data;
00221     *d_layoutCache = *other.d_layoutCache;
00222     return *this;
00223 }
00224     
00225 int QwtText::operator==(const QwtText &other) const
00226 {
00227     return d_data->renderFlags == other.d_data->renderFlags &&
00228         d_data->text == other.d_data->text &&
00229         d_data->font == other.d_data->font &&
00230         d_data->color == other.d_data->color &&
00231         d_data->backgroundPen == other.d_data->backgroundPen &&
00232         d_data->backgroundBrush == other.d_data->backgroundBrush &&
00233         d_data->paintAttributes == other.d_data->paintAttributes &&
00234         d_data->textEngine == other.d_data->textEngine;
00235 }
00236 
00237 int QwtText::operator!=(const QwtText &other) const // invalidate
00238 {
00239    return !(other == *this);
00240 }
00241 
00248 void QwtText::setText(const QString &text, 
00249     QwtText::TextFormat textFormat) 
00250 { 
00251     d_data->text = text; 
00252     d_data->textEngine = textEngine(text, textFormat);
00253     d_layoutCache->invalidate();
00254 }
00255 
00260 QString QwtText::text() const 
00261 { 
00262     return d_data->text; 
00263 }
00264 
00275 void QwtText::setRenderFlags(int renderFlags) 
00276 { 
00277     if ( renderFlags != d_data->renderFlags )
00278     {
00279         d_data->renderFlags = renderFlags; 
00280         d_layoutCache->invalidate();
00281     }
00282 }
00283 
00288 int QwtText::renderFlags() const 
00289 { 
00290     return d_data->renderFlags; 
00291 }
00292 
00300 void QwtText::setFont(const QFont &font) 
00301 {
00302     d_data->font = font; 
00303     setPaintAttribute(PaintUsingTextFont);
00304 }
00305 
00307 QFont QwtText::font() const 
00308 { 
00309     return d_data->font; 
00310 }
00311 
00319 QFont QwtText::usedFont(const QFont &defaultFont) const
00320 {
00321     if ( d_data->paintAttributes & PaintUsingTextFont )
00322         return d_data->font;
00323 
00324     return defaultFont;
00325 }
00326 
00334 void QwtText::setColor(const QColor &color) 
00335 { 
00336     d_data->color = color; 
00337     setPaintAttribute(PaintUsingTextColor);
00338 }
00339 
00341 QColor QwtText::color() const 
00342 { 
00343     return d_data->color; 
00344 }
00345 
00353 QColor QwtText::usedColor(const QColor &defaultColor) const
00354 {
00355     if ( d_data->paintAttributes & PaintUsingTextColor )
00356         return d_data->color;
00357 
00358     return defaultColor;
00359 }
00360 
00367 void QwtText::setBackgroundPen(const QPen &pen) 
00368 { 
00369     d_data->backgroundPen = pen; 
00370     setPaintAttribute(PaintBackground);
00371 }
00372 
00377 QPen QwtText::backgroundPen() const 
00378 { 
00379     return d_data->backgroundPen; 
00380 }
00381 
00388 void QwtText::setBackgroundBrush(const QBrush &brush) 
00389 { 
00390     d_data->backgroundBrush = brush; 
00391     setPaintAttribute(PaintBackground);
00392 }
00393 
00398 QBrush QwtText::backgroundBrush() const 
00399 { 
00400     return d_data->backgroundBrush; 
00401 }
00402 
00412 void QwtText::setPaintAttribute(PaintAttribute attribute, bool on)
00413 {
00414     if ( on )
00415         d_data->paintAttributes |= attribute;
00416     else
00417         d_data->paintAttributes &= ~attribute;
00418 }
00419 
00428 bool QwtText::testPaintAttribute(PaintAttribute attribute) const
00429 {
00430     return d_data->paintAttributes & attribute;
00431 }
00432 
00440 void QwtText::setLayoutAttribute(LayoutAttribute attribute, bool on)
00441 {
00442     if ( on )
00443         d_data->layoutAttributes |= attribute;
00444     else
00445         d_data->layoutAttributes &= ~attribute;
00446 }
00447 
00456 bool QwtText::testLayoutAttribute(LayoutAttribute attribute) const
00457 {
00458     return d_data->layoutAttributes | attribute;
00459 }
00460 
00469 int QwtText::heightForWidth(int width, const QFont &defaultFont) const
00470 {
00471     const QwtMetricsMap map = QwtPainter::metricsMap();
00472     width = map.layoutToScreenX(width);
00473 
00474 #if QT_VERSION < 0x040000
00475     const QFont font = usedFont(defaultFont);
00476 #else
00477     // We want to calculate in screen metrics. So
00478     // we need a font that uses screen metrics
00479 
00480     const QFont font(usedFont(defaultFont), QApplication::desktop());
00481 #endif
00482 
00483     int h = 0;
00484 
00485     if ( d_data->layoutAttributes & MinimumLayout )
00486     {
00487         int left, right, top, bottom;
00488         d_data->textEngine->textMargins(font, d_data->text,
00489             left, right, top, bottom);
00490 
00491         h = d_data->textEngine->heightForWidth(
00492             font, d_data->renderFlags, d_data->text, 
00493             width + left + right);
00494 
00495         h -= top + bottom;
00496     }
00497     else
00498     {
00499         h = d_data->textEngine->heightForWidth(
00500             font, d_data->renderFlags, d_data->text, width);
00501     }
00502 
00503     h = map.screenToLayoutY(h);
00504     return h;
00505 }
00506 
00521 QSize QwtText::textSize(const QFont &defaultFont) const
00522 {
00523 #if QT_VERSION < 0x040000
00524     const QFont font(usedFont(defaultFont));
00525 #else
00526     // We want to calculate in screen metrics. So
00527     // we need a font that uses screen metrics
00528 
00529     const QFont font(usedFont(defaultFont), QApplication::desktop());
00530 #endif
00531 
00532     if ( !d_layoutCache->textSize.isValid() 
00533         || d_layoutCache->font != font )
00534     {
00535         d_layoutCache->textSize = d_data->textEngine->textSize(
00536             font, d_data->renderFlags, d_data->text);
00537         d_layoutCache->font = font;
00538     }
00539 
00540     QSize sz = d_layoutCache->textSize;
00541 
00542     const QwtMetricsMap map = QwtPainter::metricsMap();
00543 
00544     if ( d_data->layoutAttributes & MinimumLayout )
00545     {
00546         int left, right, top, bottom;
00547         d_data->textEngine->textMargins(font, d_data->text,
00548             left, right, top, bottom);
00549         sz -= QSize(left + right, top + bottom);
00550 #if QT_VERSION >= 0x040000
00551         if ( !map.isIdentity() )
00552         {
00553 #ifdef __GNUC__
00554 #warning Too small text size, when printing in high resolution
00555 #endif
00556             /*
00557                 When printing in high resolution, the tick labels
00558                 of are cut of. We need to find out why, but for
00559                 the moment we add a couple of pixels instead.
00560              */
00561             sz += QSize(3, 0);
00562         }
00563 #endif
00564     }
00565 
00566     sz = map.screenToLayout(sz);
00567     return sz;
00568 }
00569 
00576 void QwtText::draw(QPainter *painter, const QRect &rect) const
00577 {
00578     if ( d_data->paintAttributes & PaintBackground )
00579     {
00580         if ( d_data->backgroundPen != Qt::NoPen || 
00581             d_data->backgroundBrush != Qt::NoBrush )
00582         {
00583             painter->save();
00584             painter->setPen(d_data->backgroundPen);
00585             painter->setBrush(d_data->backgroundBrush);
00586             QwtPainter::drawRect(painter, rect);
00587             painter->restore();
00588         }
00589     }
00590 
00591     painter->save();
00592 
00593     if ( d_data->paintAttributes & PaintUsingTextFont )
00594     {
00595         painter->setFont(d_data->font);
00596     }
00597 
00598     if ( d_data->paintAttributes & PaintUsingTextColor )
00599     {
00600         if ( d_data->color.isValid() )
00601             painter->setPen(d_data->color);
00602     }
00603 
00604     QRect expandedRect = rect;
00605     if ( d_data->layoutAttributes & MinimumLayout )
00606     {
00607 #if QT_VERSION < 0x040000
00608         const QFont font(painter->font());
00609 #else
00610         // We want to calculate in screen metrics. So
00611         // we need a font that uses screen metrics
00612 
00613         const QFont font(painter->font(), QApplication::desktop());
00614 #endif
00615 
00616         int left, right, top, bottom;
00617         d_data->textEngine->textMargins(
00618             font, d_data->text,
00619             left, right, top, bottom);
00620 
00621         const QwtMetricsMap map = QwtPainter::metricsMap();
00622         left = map.screenToLayoutX(left);
00623         right = map.screenToLayoutX(right);
00624         top = map.screenToLayoutY(top);
00625         bottom = map.screenToLayoutY(bottom);
00626 
00627         expandedRect.setTop(rect.top() - top);
00628         expandedRect.setBottom(rect.bottom() + bottom);
00629         expandedRect.setLeft(rect.left() - left);
00630         expandedRect.setRight(rect.right() + right);
00631     }
00632 
00633     d_data->textEngine->draw(painter, expandedRect, 
00634         d_data->renderFlags, d_data->text);
00635 
00636     painter->restore();
00637 }
00638 
00652 const QwtTextEngine *QwtText::textEngine(const QString &text,
00653     QwtText::TextFormat format)
00654 {
00655     if ( engineDict == NULL )
00656         engineDict = new QwtTextEngineDict();
00657 
00658     return engineDict->textEngine(text, format);
00659 }
00660 
00672 const QwtTextEngine *QwtText::textEngine(QwtText::TextFormat format)
00673 {
00674     if ( engineDict == NULL )
00675         engineDict = new QwtTextEngineDict();
00676 
00677     return engineDict->textEngine(format);
00678 }

Generated on Mon Nov 6 20:32:57 2006 for Qwt User's Guide by  doxygen 1.4.6