qwt_text.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
  2. * Qwt Widget Library
  3. * Copyright (C) 1997 Josef Wilgen
  4. * Copyright (C) 2003 Uwe Rathmann
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Qwt License, Version 1.0
  8. *****************************************************************************/
  9. #include "qwt_text.h"
  10. #include "qwt_painter.h"
  11. #include "qwt_text_engine.h"
  12. #include <qmap.h>
  13. #include <qfont.h>
  14. #include <qcolor.h>
  15. #include <qpen.h>
  16. #include <qbrush.h>
  17. #include <qpainter.h>
  18. #include <qapplication.h>
  19. #include <qdesktopwidget.h>
  20. #include <qmath.h>
  21. class QwtTextEngineDict
  22. {
  23. public:
  24. static QwtTextEngineDict &dict();
  25. void setTextEngine( QwtText::TextFormat, QwtTextEngine * );
  26. const QwtTextEngine *textEngine( QwtText::TextFormat ) const;
  27. const QwtTextEngine *textEngine( const QString &,
  28. QwtText::TextFormat ) const;
  29. private:
  30. QwtTextEngineDict();
  31. ~QwtTextEngineDict();
  32. typedef QMap<int, QwtTextEngine *> EngineMap;
  33. inline const QwtTextEngine *engine( EngineMap::const_iterator &it ) const
  34. {
  35. return it.value();
  36. }
  37. EngineMap d_map;
  38. };
  39. QwtTextEngineDict &QwtTextEngineDict::dict()
  40. {
  41. static QwtTextEngineDict engineDict;
  42. return engineDict;
  43. }
  44. QwtTextEngineDict::QwtTextEngineDict()
  45. {
  46. d_map.insert( QwtText::PlainText, new QwtPlainTextEngine() );
  47. #ifndef QT_NO_RICHTEXT
  48. d_map.insert( QwtText::RichText, new QwtRichTextEngine() );
  49. #endif
  50. }
  51. QwtTextEngineDict::~QwtTextEngineDict()
  52. {
  53. for ( EngineMap::const_iterator it = d_map.begin();
  54. it != d_map.end(); ++it )
  55. {
  56. const QwtTextEngine *textEngine = engine( it );
  57. delete textEngine;
  58. }
  59. }
  60. const QwtTextEngine *QwtTextEngineDict::textEngine( const QString& text,
  61. QwtText::TextFormat format ) const
  62. {
  63. if ( format == QwtText::AutoText )
  64. {
  65. for ( EngineMap::const_iterator it = d_map.begin();
  66. it != d_map.end(); ++it )
  67. {
  68. if ( it.key() != QwtText::PlainText )
  69. {
  70. const QwtTextEngine *e = engine( it );
  71. if ( e && e->mightRender( text ) )
  72. return e;
  73. }
  74. }
  75. }
  76. EngineMap::const_iterator it = d_map.find( format );
  77. if ( it != d_map.end() )
  78. {
  79. const QwtTextEngine *e = engine( it );
  80. if ( e )
  81. return e;
  82. }
  83. it = d_map.find( QwtText::PlainText );
  84. return engine( it );
  85. }
  86. void QwtTextEngineDict::setTextEngine( QwtText::TextFormat format,
  87. QwtTextEngine *engine )
  88. {
  89. if ( format == QwtText::AutoText )
  90. return;
  91. if ( format == QwtText::PlainText && engine == NULL )
  92. return;
  93. EngineMap::const_iterator it = d_map.find( format );
  94. if ( it != d_map.end() )
  95. {
  96. const QwtTextEngine *e = this->engine( it );
  97. if ( e )
  98. delete e;
  99. d_map.remove( format );
  100. }
  101. if ( engine != NULL )
  102. d_map.insert( format, engine );
  103. }
  104. const QwtTextEngine *QwtTextEngineDict::textEngine(
  105. QwtText::TextFormat format ) const
  106. {
  107. const QwtTextEngine *e = NULL;
  108. EngineMap::const_iterator it = d_map.find( format );
  109. if ( it != d_map.end() )
  110. e = engine( it );
  111. return e;
  112. }
  113. class QwtText::PrivateData
  114. {
  115. public:
  116. PrivateData():
  117. renderFlags( Qt::AlignCenter ),
  118. backgroundPen( Qt::NoPen ),
  119. backgroundBrush( Qt::NoBrush ),
  120. paintAttributes( 0 ),
  121. layoutAttributes( 0 ),
  122. textEngine( NULL )
  123. {
  124. }
  125. int renderFlags;
  126. QString text;
  127. QFont font;
  128. QColor color;
  129. QPen backgroundPen;
  130. QBrush backgroundBrush;
  131. int paintAttributes;
  132. int layoutAttributes;
  133. const QwtTextEngine *textEngine;
  134. };
  135. class QwtText::LayoutCache
  136. {
  137. public:
  138. void invalidate()
  139. {
  140. textSize = QSizeF();
  141. }
  142. QFont font;
  143. QSizeF textSize;
  144. };
  145. /*!
  146. Constructor
  147. \param text Text content
  148. \param textFormat Text format
  149. */
  150. QwtText::QwtText( const QString &text, QwtText::TextFormat textFormat )
  151. {
  152. d_data = new PrivateData;
  153. d_data->text = text;
  154. d_data->textEngine = textEngine( text, textFormat );
  155. d_layoutCache = new LayoutCache;
  156. }
  157. //! Copy constructor
  158. QwtText::QwtText( const QwtText &other )
  159. {
  160. d_data = new PrivateData;
  161. *d_data = *other.d_data;
  162. d_layoutCache = new LayoutCache;
  163. *d_layoutCache = *other.d_layoutCache;
  164. }
  165. //! Destructor
  166. QwtText::~QwtText()
  167. {
  168. delete d_data;
  169. delete d_layoutCache;
  170. }
  171. //! Assignment operator
  172. QwtText &QwtText::operator=( const QwtText & other )
  173. {
  174. *d_data = *other.d_data;
  175. *d_layoutCache = *other.d_layoutCache;
  176. return *this;
  177. }
  178. //! Relational operator
  179. bool QwtText::operator==( const QwtText &other ) const
  180. {
  181. return d_data->renderFlags == other.d_data->renderFlags &&
  182. d_data->text == other.d_data->text &&
  183. d_data->font == other.d_data->font &&
  184. d_data->color == other.d_data->color &&
  185. d_data->backgroundPen == other.d_data->backgroundPen &&
  186. d_data->backgroundBrush == other.d_data->backgroundBrush &&
  187. d_data->paintAttributes == other.d_data->paintAttributes &&
  188. d_data->textEngine == other.d_data->textEngine;
  189. }
  190. //! Relational operator
  191. bool QwtText::operator!=( const QwtText &other ) const // invalidate
  192. {
  193. return !( other == *this );
  194. }
  195. /*!
  196. Assign a new text content
  197. \param text Text content
  198. \param textFormat Text format
  199. \sa text()
  200. */
  201. void QwtText::setText( const QString &text,
  202. QwtText::TextFormat textFormat )
  203. {
  204. d_data->text = text;
  205. d_data->textEngine = textEngine( text, textFormat );
  206. d_layoutCache->invalidate();
  207. }
  208. /*!
  209. Return the text.
  210. \sa setText()
  211. */
  212. QString QwtText::text() const
  213. {
  214. return d_data->text;
  215. }
  216. /*!
  217. \brief Change the render flags
  218. The default setting is Qt::AlignCenter
  219. \param renderFlags Bitwise OR of the flags used like in QPainter::drawText
  220. \sa renderFlags(), QwtTextEngine::draw()
  221. \note Some renderFlags might have no effect, depending on the text format.
  222. */
  223. void QwtText::setRenderFlags( int renderFlags )
  224. {
  225. if ( renderFlags != d_data->renderFlags )
  226. {
  227. d_data->renderFlags = renderFlags;
  228. d_layoutCache->invalidate();
  229. }
  230. }
  231. /*!
  232. \return Render flags
  233. \sa setRenderFlags()
  234. */
  235. int QwtText::renderFlags() const
  236. {
  237. return d_data->renderFlags;
  238. }
  239. /*!
  240. Set the font.
  241. \param font Font
  242. \note Setting the font might have no effect, when
  243. the text contains control sequences for setting fonts.
  244. */
  245. void QwtText::setFont( const QFont &font )
  246. {
  247. d_data->font = font;
  248. setPaintAttribute( PaintUsingTextFont );
  249. }
  250. //! Return the font.
  251. QFont QwtText::font() const
  252. {
  253. return d_data->font;
  254. }
  255. /*!
  256. Return the font of the text, if it has one.
  257. Otherwise return defaultFont.
  258. \param defaultFont Default font
  259. \sa setFont(), font(), PaintAttributes
  260. */
  261. QFont QwtText::usedFont( const QFont &defaultFont ) const
  262. {
  263. if ( d_data->paintAttributes & PaintUsingTextFont )
  264. return d_data->font;
  265. return defaultFont;
  266. }
  267. /*!
  268. Set the pen color used for painting the text.
  269. \param color Color
  270. \note Setting the color might have no effect, when
  271. the text contains control sequences for setting colors.
  272. */
  273. void QwtText::setColor( const QColor &color )
  274. {
  275. d_data->color = color;
  276. setPaintAttribute( PaintUsingTextColor );
  277. }
  278. //! Return the pen color, used for painting the text
  279. QColor QwtText::color() const
  280. {
  281. return d_data->color;
  282. }
  283. /*!
  284. Return the color of the text, if it has one.
  285. Otherwise return defaultColor.
  286. \param defaultColor Default color
  287. \sa setColor(), color(), PaintAttributes
  288. */
  289. QColor QwtText::usedColor( const QColor &defaultColor ) const
  290. {
  291. if ( d_data->paintAttributes & PaintUsingTextColor )
  292. return d_data->color;
  293. return defaultColor;
  294. }
  295. /*!
  296. Set the background pen
  297. \param pen Background pen
  298. \sa backgroundPen(), setBackgroundBrush()
  299. */
  300. void QwtText::setBackgroundPen( const QPen &pen )
  301. {
  302. d_data->backgroundPen = pen;
  303. setPaintAttribute( PaintBackground );
  304. }
  305. /*!
  306. \return Background pen
  307. \sa setBackgroundPen(), backgroundBrush()
  308. */
  309. QPen QwtText::backgroundPen() const
  310. {
  311. return d_data->backgroundPen;
  312. }
  313. /*!
  314. Set the background brush
  315. \param brush Background brush
  316. \sa backgroundBrush(), setBackgroundPen()
  317. */
  318. void QwtText::setBackgroundBrush( const QBrush &brush )
  319. {
  320. d_data->backgroundBrush = brush;
  321. setPaintAttribute( PaintBackground );
  322. }
  323. /*!
  324. \return Background brush
  325. \sa setBackgroundBrush(), backgroundPen()
  326. */
  327. QBrush QwtText::backgroundBrush() const
  328. {
  329. return d_data->backgroundBrush;
  330. }
  331. /*!
  332. Change a paint attribute
  333. \param attribute Paint attribute
  334. \param on On/Off
  335. \note Used by setFont(), setColor(),
  336. setBackgroundPen() and setBackgroundBrush()
  337. \sa testPaintAttribute()
  338. */
  339. void QwtText::setPaintAttribute( PaintAttribute attribute, bool on )
  340. {
  341. if ( on )
  342. d_data->paintAttributes |= attribute;
  343. else
  344. d_data->paintAttributes &= ~attribute;
  345. }
  346. /*!
  347. Test a paint attribute
  348. \param attribute Paint attribute
  349. \return true, if attribute is enabled
  350. \sa setPaintAttribute()
  351. */
  352. bool QwtText::testPaintAttribute( PaintAttribute attribute ) const
  353. {
  354. return d_data->paintAttributes & attribute;
  355. }
  356. /*!
  357. Change a layout attribute
  358. \param attribute Layout attribute
  359. \param on On/Off
  360. \sa testLayoutAttribute()
  361. */
  362. void QwtText::setLayoutAttribute( LayoutAttribute attribute, bool on )
  363. {
  364. if ( on )
  365. d_data->layoutAttributes |= attribute;
  366. else
  367. d_data->layoutAttributes &= ~attribute;
  368. }
  369. /*!
  370. Test a layout attribute
  371. \param attribute Layout attribute
  372. \return true, if attribute is enabled
  373. \sa setLayoutAttribute()
  374. */
  375. bool QwtText::testLayoutAttribute( LayoutAttribute attribute ) const
  376. {
  377. return d_data->layoutAttributes | attribute;
  378. }
  379. /*!
  380. Find the height for a given width
  381. \param defaultFont Font, used for the calculation if the text has no font
  382. \param width Width
  383. \return Calculated height
  384. */
  385. double QwtText::heightForWidth( double width, const QFont &defaultFont ) const
  386. {
  387. // We want to calculate in screen metrics. So
  388. // we need a font that uses screen metrics
  389. const QFont font( usedFont( defaultFont ), QApplication::desktop() );
  390. double h = 0;
  391. if ( d_data->layoutAttributes & MinimumLayout )
  392. {
  393. double left, right, top, bottom;
  394. d_data->textEngine->textMargins( font, d_data->text,
  395. left, right, top, bottom );
  396. h = d_data->textEngine->heightForWidth(
  397. font, d_data->renderFlags, d_data->text,
  398. width + left + right );
  399. h -= top + bottom;
  400. }
  401. else
  402. {
  403. h = d_data->textEngine->heightForWidth(
  404. font, d_data->renderFlags, d_data->text, width );
  405. }
  406. return h;
  407. }
  408. /*!
  409. Find the height for a given width
  410. \param defaultFont Font, used for the calculation if the text has no font
  411. \return Calculated height
  412. */
  413. /*!
  414. Returns the size, that is needed to render text
  415. \param defaultFont Font of the text
  416. \return Caluclated size
  417. */
  418. QSizeF QwtText::textSize( const QFont &defaultFont ) const
  419. {
  420. // We want to calculate in screen metrics. So
  421. // we need a font that uses screen metrics
  422. const QFont font( usedFont( defaultFont ), QApplication::desktop() );
  423. if ( !d_layoutCache->textSize.isValid()
  424. || d_layoutCache->font != font )
  425. {
  426. d_layoutCache->textSize = d_data->textEngine->textSize(
  427. font, d_data->renderFlags, d_data->text );
  428. d_layoutCache->font = font;
  429. }
  430. QSizeF sz = d_layoutCache->textSize;
  431. if ( d_data->layoutAttributes & MinimumLayout )
  432. {
  433. double left, right, top, bottom;
  434. d_data->textEngine->textMargins( font, d_data->text,
  435. left, right, top, bottom );
  436. sz -= QSizeF( left + right, top + bottom );
  437. }
  438. return sz;
  439. }
  440. /*!
  441. Draw a text into a rectangle
  442. \param painter Painter
  443. \param rect Rectangle
  444. */
  445. void QwtText::draw( QPainter *painter, const QRectF &rect ) const
  446. {
  447. if ( d_data->paintAttributes & PaintBackground )
  448. {
  449. if ( d_data->backgroundPen != Qt::NoPen ||
  450. d_data->backgroundBrush != Qt::NoBrush )
  451. {
  452. painter->save();
  453. painter->setPen( d_data->backgroundPen );
  454. painter->setBrush( d_data->backgroundBrush );
  455. QwtPainter::drawRect( painter, rect );
  456. painter->restore();
  457. }
  458. }
  459. painter->save();
  460. if ( d_data->paintAttributes & PaintUsingTextFont )
  461. {
  462. painter->setFont( d_data->font );
  463. }
  464. if ( d_data->paintAttributes & PaintUsingTextColor )
  465. {
  466. if ( d_data->color.isValid() )
  467. painter->setPen( d_data->color );
  468. }
  469. QRectF expandedRect = rect;
  470. if ( d_data->layoutAttributes & MinimumLayout )
  471. {
  472. // We want to calculate in screen metrics. So
  473. // we need a font that uses screen metrics
  474. const QFont font( painter->font(), QApplication::desktop() );
  475. double left, right, top, bottom;
  476. d_data->textEngine->textMargins(
  477. font, d_data->text, left, right, top, bottom );
  478. expandedRect.setTop( rect.top() - top );
  479. expandedRect.setBottom( rect.bottom() + bottom );
  480. expandedRect.setLeft( rect.left() - left );
  481. expandedRect.setRight( rect.right() + right );
  482. }
  483. d_data->textEngine->draw( painter, expandedRect,
  484. d_data->renderFlags, d_data->text );
  485. painter->restore();
  486. }
  487. /*!
  488. Find the text engine for a text format
  489. In case of QwtText::AutoText the first text engine
  490. (beside QwtPlainTextEngine) is returned, where QwtTextEngine::mightRender
  491. returns true. If there is none QwtPlainTextEngine is returnd.
  492. If no text engine is registered for the format QwtPlainTextEngine
  493. is returnd.
  494. \param text Text, needed in case of AutoText
  495. \param format Text format
  496. */
  497. const QwtTextEngine *QwtText::textEngine( const QString &text,
  498. QwtText::TextFormat format )
  499. {
  500. return QwtTextEngineDict::dict().textEngine( text, format );
  501. }
  502. /*!
  503. Assign/Replace a text engine for a text format
  504. With setTextEngine it is possible to extend Qwt with
  505. other types of text formats.
  506. For QwtText::PlainText it is not allowed to assign a engine == NULL.
  507. \param format Text format
  508. \param engine Text engine
  509. \sa QwtMathMLTextEngine
  510. \warning Using QwtText::AutoText does nothing.
  511. */
  512. void QwtText::setTextEngine( QwtText::TextFormat format,
  513. QwtTextEngine *engine )
  514. {
  515. QwtTextEngineDict::dict().setTextEngine( format, engine );
  516. }
  517. /*!
  518. \brief Find the text engine for a text format
  519. textEngine can be used to find out if a text format is supported.
  520. \param format Text format
  521. \return The text engine, or NULL if no engine is available.
  522. */
  523. const QwtTextEngine *QwtText::textEngine( QwtText::TextFormat format )
  524. {
  525. return QwtTextEngineDict::dict().textEngine( format );
  526. }