00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_text.h"
00011 #include "qwt_painter.h"
00012 #include "qwt_text_engine.h"
00013 #include <qmap.h>
00014 #include <qfont.h>
00015 #include <qcolor.h>
00016 #include <qpen.h>
00017 #include <qbrush.h>
00018 #include <qpainter.h>
00019 #include <qapplication.h>
00020 #include <qdesktopwidget.h>
00021 #include <qmath.h>
00022
00023 class QwtTextEngineDict
00024 {
00025 public:
00026 static QwtTextEngineDict &dict();
00027
00028 void setTextEngine( QwtText::TextFormat, QwtTextEngine * );
00029
00030 const QwtTextEngine *textEngine( QwtText::TextFormat ) const;
00031 const QwtTextEngine *textEngine( const QString &,
00032 QwtText::TextFormat ) const;
00033
00034 private:
00035 QwtTextEngineDict();
00036 ~QwtTextEngineDict();
00037
00038 typedef QMap<int, QwtTextEngine *> EngineMap;
00039
00040 inline const QwtTextEngine *engine( EngineMap::const_iterator &it ) const
00041 {
00042 return it.value();
00043 }
00044
00045 EngineMap d_map;
00046 };
00047
00048 QwtTextEngineDict &QwtTextEngineDict::dict()
00049 {
00050 static QwtTextEngineDict engineDict;
00051 return engineDict;
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
00062 QwtTextEngineDict::~QwtTextEngineDict()
00063 {
00064 for ( EngineMap::const_iterator it = d_map.begin();
00065 it != d_map.end(); ++it )
00066 {
00067 const QwtTextEngine *textEngine = engine( it );
00068 delete textEngine;
00069 }
00070 }
00071
00072 const QwtTextEngine *QwtTextEngineDict::textEngine( const QString& text,
00073 QwtText::TextFormat format ) const
00074 {
00075 if ( format == QwtText::AutoText )
00076 {
00077 for ( EngineMap::const_iterator it = d_map.begin();
00078 it != d_map.end(); ++it )
00079 {
00080 if ( it.key() != QwtText::PlainText )
00081 {
00082 const QwtTextEngine *e = engine( it );
00083 if ( e && e->mightRender( text ) )
00084 return e;
00085 }
00086 }
00087 }
00088
00089 EngineMap::const_iterator it = d_map.find( format );
00090 if ( it != d_map.end() )
00091 {
00092 const QwtTextEngine *e = engine( it );
00093 if ( e )
00094 return e;
00095 }
00096
00097 it = d_map.find( QwtText::PlainText );
00098 return engine( it );
00099 }
00100
00101 void QwtTextEngineDict::setTextEngine( QwtText::TextFormat format,
00102 QwtTextEngine *engine )
00103 {
00104 if ( format == QwtText::AutoText )
00105 return;
00106
00107 if ( format == QwtText::PlainText && engine == NULL )
00108 return;
00109
00110 EngineMap::const_iterator it = d_map.find( format );
00111 if ( it != d_map.end() )
00112 {
00113 const QwtTextEngine *e = this->engine( it );
00114 if ( e )
00115 delete e;
00116
00117 d_map.remove( format );
00118 }
00119
00120 if ( engine != NULL )
00121 d_map.insert( format, engine );
00122 }
00123
00124 const QwtTextEngine *QwtTextEngineDict::textEngine(
00125 QwtText::TextFormat format ) const
00126 {
00127 const QwtTextEngine *e = NULL;
00128
00129 EngineMap::const_iterator it = d_map.find( format );
00130 if ( it != d_map.end() )
00131 e = engine( it );
00132
00133 return e;
00134 }
00135
00136 class QwtText::PrivateData
00137 {
00138 public:
00139 PrivateData():
00140 renderFlags( Qt::AlignCenter ),
00141 borderRadius( 0 ),
00142 borderPen( Qt::NoPen ),
00143 backgroundBrush( Qt::NoBrush ),
00144 paintAttributes( 0 ),
00145 layoutAttributes( 0 ),
00146 textEngine( NULL )
00147 {
00148 }
00149
00150 int renderFlags;
00151 QString text;
00152 QFont font;
00153 QColor color;
00154 double borderRadius;
00155 QPen borderPen;
00156 QBrush backgroundBrush;
00157
00158 QwtText::PaintAttributes paintAttributes;
00159 QwtText::LayoutAttributes layoutAttributes;
00160
00161 const QwtTextEngine *textEngine;
00162 };
00163
00164 class QwtText::LayoutCache
00165 {
00166 public:
00167 void invalidate()
00168 {
00169 textSize = QSizeF();
00170 }
00171
00172 QFont font;
00173 QSizeF textSize;
00174 };
00175
00182 QwtText::QwtText( const QString &text, QwtText::TextFormat textFormat )
00183 {
00184 d_data = new PrivateData;
00185 d_data->text = text;
00186 d_data->textEngine = textEngine( text, textFormat );
00187
00188 d_layoutCache = new LayoutCache;
00189 }
00190
00192 QwtText::QwtText( const QwtText &other )
00193 {
00194 d_data = new PrivateData;
00195 *d_data = *other.d_data;
00196
00197 d_layoutCache = new LayoutCache;
00198 *d_layoutCache = *other.d_layoutCache;
00199 }
00200
00202 QwtText::~QwtText()
00203 {
00204 delete d_data;
00205 delete d_layoutCache;
00206 }
00207
00209 QwtText &QwtText::operator=( const QwtText & other )
00210 {
00211 *d_data = *other.d_data;
00212 *d_layoutCache = *other.d_layoutCache;
00213 return *this;
00214 }
00215
00217 bool QwtText::operator==( const QwtText &other ) const
00218 {
00219 return d_data->renderFlags == other.d_data->renderFlags &&
00220 d_data->text == other.d_data->text &&
00221 d_data->font == other.d_data->font &&
00222 d_data->color == other.d_data->color &&
00223 d_data->borderRadius == other.d_data->borderRadius &&
00224 d_data->borderPen == other.d_data->borderPen &&
00225 d_data->backgroundBrush == other.d_data->backgroundBrush &&
00226 d_data->paintAttributes == other.d_data->paintAttributes &&
00227 d_data->textEngine == other.d_data->textEngine;
00228 }
00229
00231 bool QwtText::operator!=( const QwtText &other ) const
00232 {
00233 return !( other == *this );
00234 }
00235
00244 void QwtText::setText( const QString &text,
00245 QwtText::TextFormat textFormat )
00246 {
00247 d_data->text = text;
00248 d_data->textEngine = textEngine( text, textFormat );
00249 d_layoutCache->invalidate();
00250 }
00251
00256 QString QwtText::text() const
00257 {
00258 return d_data->text;
00259 }
00260
00271 void QwtText::setRenderFlags( int renderFlags )
00272 {
00273 if ( renderFlags != d_data->renderFlags )
00274 {
00275 d_data->renderFlags = renderFlags;
00276 d_layoutCache->invalidate();
00277 }
00278 }
00279
00284 int QwtText::renderFlags() const
00285 {
00286 return d_data->renderFlags;
00287 }
00288
00296 void QwtText::setFont( const QFont &font )
00297 {
00298 d_data->font = font;
00299 setPaintAttribute( PaintUsingTextFont );
00300 }
00301
00303 QFont QwtText::font() const
00304 {
00305 return d_data->font;
00306 }
00307
00317 QFont QwtText::usedFont( const QFont &defaultFont ) const
00318 {
00319 if ( d_data->paintAttributes & PaintUsingTextFont )
00320 return d_data->font;
00321
00322 return defaultFont;
00323 }
00324
00332 void QwtText::setColor( const QColor &color )
00333 {
00334 d_data->color = color;
00335 setPaintAttribute( PaintUsingTextColor );
00336 }
00337
00339 QColor QwtText::color() const
00340 {
00341 return d_data->color;
00342 }
00343
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::setBorderRadius( double radius )
00368 {
00369 d_data->borderRadius = qMax( 0.0, radius );
00370 }
00371
00376 double QwtText::borderRadius() const
00377 {
00378 return d_data->borderRadius;
00379 }
00380
00387 void QwtText::setBorderPen( const QPen &pen )
00388 {
00389 d_data->borderPen = pen;
00390 setPaintAttribute( PaintBackground );
00391 }
00392
00397 QPen QwtText::borderPen() const
00398 {
00399 return d_data->borderPen;
00400 }
00401
00408 void QwtText::setBackgroundBrush( const QBrush &brush )
00409 {
00410 d_data->backgroundBrush = brush;
00411 setPaintAttribute( PaintBackground );
00412 }
00413
00418 QBrush QwtText::backgroundBrush() const
00419 {
00420 return d_data->backgroundBrush;
00421 }
00422
00433 void QwtText::setPaintAttribute( PaintAttribute attribute, bool on )
00434 {
00435 if ( on )
00436 d_data->paintAttributes |= attribute;
00437 else
00438 d_data->paintAttributes &= ~attribute;
00439 }
00440
00449 bool QwtText::testPaintAttribute( PaintAttribute attribute ) const
00450 {
00451 return d_data->paintAttributes & attribute;
00452 }
00453
00461 void QwtText::setLayoutAttribute( LayoutAttribute attribute, bool on )
00462 {
00463 if ( on )
00464 d_data->layoutAttributes |= attribute;
00465 else
00466 d_data->layoutAttributes &= ~attribute;
00467 }
00468
00477 bool QwtText::testLayoutAttribute( LayoutAttribute attribute ) const
00478 {
00479 return d_data->layoutAttributes | attribute;
00480 }
00481
00490 double QwtText::heightForWidth( double width, const QFont &defaultFont ) const
00491 {
00492
00493
00494
00495 const QFont font( usedFont( defaultFont ), QApplication::desktop() );
00496
00497 double h = 0;
00498
00499 if ( d_data->layoutAttributes & MinimumLayout )
00500 {
00501 double left, right, top, bottom;
00502 d_data->textEngine->textMargins( font, d_data->text,
00503 left, right, top, bottom );
00504
00505 h = d_data->textEngine->heightForWidth(
00506 font, d_data->renderFlags, d_data->text,
00507 width + left + right );
00508
00509 h -= top + bottom;
00510 }
00511 else
00512 {
00513 h = d_data->textEngine->heightForWidth(
00514 font, d_data->renderFlags, d_data->text, width );
00515 }
00516
00517 return h;
00518 }
00519
00526 QSizeF QwtText::textSize( const QFont &defaultFont ) const
00527 {
00528
00529
00530
00531 const QFont font( usedFont( defaultFont ), QApplication::desktop() );
00532
00533 if ( !d_layoutCache->textSize.isValid()
00534 || d_layoutCache->font != font )
00535 {
00536 d_layoutCache->textSize = d_data->textEngine->textSize(
00537 font, d_data->renderFlags, d_data->text );
00538 d_layoutCache->font = font;
00539 }
00540
00541 QSizeF sz = d_layoutCache->textSize;
00542
00543 if ( d_data->layoutAttributes & MinimumLayout )
00544 {
00545 double left, right, top, bottom;
00546 d_data->textEngine->textMargins( font, d_data->text,
00547 left, right, top, bottom );
00548 sz -= QSizeF( left + right, top + bottom );
00549 }
00550
00551 return sz;
00552 }
00553
00560 void QwtText::draw( QPainter *painter, const QRectF &rect ) const
00561 {
00562 if ( d_data->paintAttributes & PaintBackground )
00563 {
00564 if ( d_data->borderPen != Qt::NoPen ||
00565 d_data->backgroundBrush != Qt::NoBrush )
00566 {
00567 painter->save();
00568
00569 painter->setPen( d_data->borderPen );
00570 painter->setBrush( d_data->backgroundBrush );
00571
00572 if ( d_data->borderRadius == 0 )
00573 {
00574 QwtPainter::drawRect( painter, rect );
00575 }
00576 else
00577 {
00578 painter->setRenderHint( QPainter::Antialiasing, true );
00579 painter->drawRoundedRect( rect,
00580 d_data->borderRadius, d_data->borderRadius );
00581 }
00582
00583 painter->restore();
00584 }
00585 }
00586
00587 painter->save();
00588
00589 if ( d_data->paintAttributes & PaintUsingTextFont )
00590 {
00591 painter->setFont( d_data->font );
00592 }
00593
00594 if ( d_data->paintAttributes & PaintUsingTextColor )
00595 {
00596 if ( d_data->color.isValid() )
00597 painter->setPen( d_data->color );
00598 }
00599
00600 QRectF expandedRect = rect;
00601 if ( d_data->layoutAttributes & MinimumLayout )
00602 {
00603
00604
00605
00606 const QFont font( painter->font(), QApplication::desktop() );
00607
00608 double left, right, top, bottom;
00609 d_data->textEngine->textMargins(
00610 font, d_data->text, left, right, top, bottom );
00611
00612 expandedRect.setTop( rect.top() - top );
00613 expandedRect.setBottom( rect.bottom() + bottom );
00614 expandedRect.setLeft( rect.left() - left );
00615 expandedRect.setRight( rect.right() + right );
00616 }
00617
00618 d_data->textEngine->draw( painter, expandedRect,
00619 d_data->renderFlags, d_data->text );
00620
00621 painter->restore();
00622 }
00623
00639 const QwtTextEngine *QwtText::textEngine( const QString &text,
00640 QwtText::TextFormat format )
00641 {
00642 return QwtTextEngineDict::dict().textEngine( text, format );
00643 }
00644
00659 void QwtText::setTextEngine( QwtText::TextFormat format,
00660 QwtTextEngine *engine )
00661 {
00662 QwtTextEngineDict::dict().setTextEngine( format, engine );
00663 }
00664
00673 const QwtTextEngine *QwtText::textEngine( QwtText::TextFormat format )
00674 {
00675 return QwtTextEngineDict::dict().textEngine( format );
00676 }