# 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 }