Qwt User's Guide  6.2.0
qwt_text.cpp
1 /******************************************************************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 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 
10 #include "qwt_text.h"
11 #include "qwt_painter.h"
12 #include "qwt_text_engine.h"
13 #include "qwt_math.h"
14 
15 #include <qmap.h>
16 #include <qfont.h>
17 #include <qcolor.h>
18 #include <qpen.h>
19 #include <qbrush.h>
20 #include <qpainter.h>
21 
22 #if QT_VERSION >= 0x050200
23 
24 static QwtText qwtStringToText( const QString& text )
25 {
26  return QwtText( text );
27 }
28 
29 #endif
30 
31 namespace
32 {
33  static const struct RegisterQwtText
34  {
35  inline RegisterQwtText()
36  {
37  qRegisterMetaType< QwtText >();
38 
39 #if QT_VERSION >= 0x050200
40  QMetaType::registerConverter< QString, QwtText >( qwtStringToText );
41 #endif
42  }
43 
44  } qwtRegisterQwtText;
45 }
46 
47 namespace
48 {
49  class TextEngineDict
50  {
51  public:
52  static TextEngineDict& dict();
53 
54  void setTextEngine( QwtText::TextFormat, QwtTextEngine* );
55 
56  const QwtTextEngine* textEngine( QwtText::TextFormat ) const;
57  const QwtTextEngine* textEngine( const QString&,
58  QwtText::TextFormat ) const;
59 
60  private:
61  TextEngineDict();
62  ~TextEngineDict();
63 
64  typedef QMap< int, QwtTextEngine* > EngineMap;
65 
66  inline const QwtTextEngine* engine( EngineMap::const_iterator& it ) const
67  {
68  return it.value();
69  }
70 
71  EngineMap m_map;
72  };
73 
74  TextEngineDict& TextEngineDict::dict()
75  {
76  static TextEngineDict engineDict;
77  return engineDict;
78  }
79 
80  TextEngineDict::TextEngineDict()
81  {
82  m_map.insert( QwtText::PlainText, new QwtPlainTextEngine() );
83  #ifndef QT_NO_RICHTEXT
84  m_map.insert( QwtText::RichText, new QwtRichTextEngine() );
85  #endif
86  }
87 
88  TextEngineDict::~TextEngineDict()
89  {
90  for ( EngineMap::const_iterator it = m_map.constBegin();
91  it != m_map.constEnd(); ++it )
92  {
93  const QwtTextEngine* textEngine = engine( it );
94  delete textEngine;
95  }
96  }
97 
98  const QwtTextEngine* TextEngineDict::textEngine( const QString& text,
99  QwtText::TextFormat format ) const
100  {
101  if ( format == QwtText::AutoText )
102  {
103  for ( EngineMap::const_iterator it = m_map.begin();
104  it != m_map.end(); ++it )
105  {
106  if ( it.key() != QwtText::PlainText )
107  {
108  const QwtTextEngine* e = engine( it );
109  if ( e && e->mightRender( text ) )
110  return e;
111  }
112  }
113  }
114 
115  EngineMap::const_iterator it = m_map.find( format );
116  if ( it != m_map.end() )
117  {
118  const QwtTextEngine* e = engine( it );
119  if ( e )
120  return e;
121  }
122 
123  it = m_map.find( QwtText::PlainText );
124  return engine( it );
125  }
126 
127  void TextEngineDict::setTextEngine( QwtText::TextFormat format,
128  QwtTextEngine* engine )
129  {
130  if ( format == QwtText::AutoText )
131  return;
132 
133  if ( format == QwtText::PlainText && engine == NULL )
134  return;
135 
136  EngineMap::const_iterator it = m_map.constFind( format );
137  if ( it != m_map.constEnd() )
138  {
139  delete this->engine( it );
140  m_map.remove( format );
141  }
142 
143  if ( engine != NULL )
144  m_map.insert( format, engine );
145  }
146 
147  const QwtTextEngine* TextEngineDict::textEngine(
148  QwtText::TextFormat format ) const
149  {
150  const QwtTextEngine* e = NULL;
151 
152  EngineMap::const_iterator it = m_map.find( format );
153  if ( it != m_map.end() )
154  e = engine( it );
155 
156  return e;
157  }
158 }
159 
160 class QwtText::PrivateData
161 {
162  public:
163  PrivateData():
164  renderFlags( Qt::AlignCenter ),
165  borderRadius( 0 ),
166  borderPen( Qt::NoPen ),
167  backgroundBrush( Qt::NoBrush ),
168  textEngine( NULL )
169  {
170  }
171 
172  int renderFlags;
173  QString text;
174  QFont font;
175  QColor color;
176  double borderRadius;
177  QPen borderPen;
178  QBrush backgroundBrush;
179 
180  QwtText::PaintAttributes paintAttributes;
181  QwtText::LayoutAttributes layoutAttributes;
182 
183  const QwtTextEngine* textEngine;
184 };
185 
186 class QwtText::LayoutCache
187 {
188  public:
189  void invalidate()
190  {
191  textSize = QSizeF();
192  }
193 
194  QFont font;
195  QSizeF textSize;
196 };
197 
202 {
203  m_data = new PrivateData;
204  m_data->textEngine = textEngine( m_data->text, PlainText );
205 
206  m_layoutCache = new LayoutCache;
207 }
208 
215 QwtText::QwtText( const QString& text, QwtText::TextFormat textFormat )
216 {
217  m_data = new PrivateData;
218  m_data->text = text;
219  m_data->textEngine = textEngine( text, textFormat );
220 
221  m_layoutCache = new LayoutCache;
222 }
223 
225 QwtText::QwtText( const QwtText& other )
226 {
227  m_data = new PrivateData;
228  *m_data = *other.m_data;
229 
230  m_layoutCache = new LayoutCache;
231  *m_layoutCache = *other.m_layoutCache;
232 }
233 
236 {
237  delete m_data;
238  delete m_layoutCache;
239 }
240 
243 {
244  *m_data = *other.m_data;
245  *m_layoutCache = *other.m_layoutCache;
246  return *this;
247 }
248 
250 bool QwtText::operator==( const QwtText& other ) const
251 {
252  return m_data->renderFlags == other.m_data->renderFlags &&
253  m_data->text == other.m_data->text &&
254  m_data->font == other.m_data->font &&
255  m_data->color == other.m_data->color &&
256  m_data->borderRadius == other.m_data->borderRadius &&
257  m_data->borderPen == other.m_data->borderPen &&
258  m_data->backgroundBrush == other.m_data->backgroundBrush &&
259  m_data->paintAttributes == other.m_data->paintAttributes &&
260  m_data->textEngine == other.m_data->textEngine;
261 }
262 
264 bool QwtText::operator!=( const QwtText& other ) const // invalidate
265 {
266  return !( other == *this );
267 }
268 
277 void QwtText::setText( const QString& text,
278  QwtText::TextFormat textFormat )
279 {
280  m_data->text = text;
281  m_data->textEngine = textEngine( text, textFormat );
282  m_layoutCache->invalidate();
283 }
284 
289 QString QwtText::text() const
290 {
291  return m_data->text;
292 }
293 
304 void QwtText::setRenderFlags( int renderFlags )
305 {
306  if ( renderFlags != m_data->renderFlags )
307  {
308  m_data->renderFlags = renderFlags;
309  m_layoutCache->invalidate();
310  }
311 }
312 
318 {
319  return m_data->renderFlags;
320 }
321 
329 void QwtText::setFont( const QFont& font )
330 {
331  m_data->font = font;
333 }
334 
336 QFont QwtText::font() const
337 {
338  return m_data->font;
339 }
340 
350 QFont QwtText::usedFont( const QFont& defaultFont ) const
351 {
352  if ( m_data->paintAttributes & PaintUsingTextFont )
353  return m_data->font;
354 
355  return defaultFont;
356 }
357 
365 void QwtText::setColor( const QColor& color )
366 {
367  m_data->color = color;
369 }
370 
372 QColor QwtText::color() const
373 {
374  return m_data->color;
375 }
376 
386 QColor QwtText::usedColor( const QColor& defaultColor ) const
387 {
388  if ( m_data->paintAttributes & PaintUsingTextColor )
389  return m_data->color;
390 
391  return defaultColor;
392 }
393 
400 void QwtText::setBorderRadius( double radius )
401 {
402  m_data->borderRadius = qwtMaxF( 0.0, radius );
403 }
404 
409 double QwtText::borderRadius() const
410 {
411  return m_data->borderRadius;
412 }
413 
420 void QwtText::setBorderPen( const QPen& pen )
421 {
422  m_data->borderPen = pen;
424 }
425 
430 QPen QwtText::borderPen() const
431 {
432  return m_data->borderPen;
433 }
434 
441 void QwtText::setBackgroundBrush( const QBrush& brush )
442 {
443  m_data->backgroundBrush = brush;
445 }
446 
452 {
453  return m_data->backgroundBrush;
454 }
455 
466 void QwtText::setPaintAttribute( PaintAttribute attribute, bool on )
467 {
468  if ( on )
469  m_data->paintAttributes |= attribute;
470  else
471  m_data->paintAttributes &= ~attribute;
472 }
473 
483 {
484  return m_data->paintAttributes & attribute;
485 }
486 
495 {
496  if ( on )
497  m_data->layoutAttributes |= attribute;
498  else
499  m_data->layoutAttributes &= ~attribute;
500 }
501 
511 {
512  return m_data->layoutAttributes | attribute;
513 }
514 
522 double QwtText::heightForWidth( double width ) const
523 {
524  return heightForWidth( width, QFont() );
525 }
526 
535 double QwtText::heightForWidth( double width, const QFont& defaultFont ) const
536 {
537  // We want to calculate in screen metrics. So
538  // we need a font that uses screen metrics
539 
540  const QFont font = QwtPainter::scaledFont( usedFont( defaultFont ) );
541 
542  double h = 0;
543 
544  if ( m_data->layoutAttributes & MinimumLayout )
545  {
546  double left, right, top, bottom;
547  m_data->textEngine->textMargins( font, m_data->text,
548  left, right, top, bottom );
549 
550  h = m_data->textEngine->heightForWidth(
551  font, m_data->renderFlags, m_data->text,
552  width + left + right );
553 
554  h -= top + bottom;
555  }
556  else
557  {
558  h = m_data->textEngine->heightForWidth(
559  font, m_data->renderFlags, m_data->text, width );
560  }
561 
562  return h;
563 }
564 
570 QSizeF QwtText::textSize() const
571 {
572  return textSize( QFont() );
573 }
574 
581 QSizeF QwtText::textSize( const QFont& defaultFont ) const
582 {
583  // We want to calculate in screen metrics. So
584  // we need a font that uses screen metrics
585 
586  const QFont font = QwtPainter::scaledFont( usedFont( defaultFont ) );
587 
588  if ( !m_layoutCache->textSize.isValid()
589  || m_layoutCache->font != font )
590  {
591  m_layoutCache->textSize = m_data->textEngine->textSize(
592  font, m_data->renderFlags, m_data->text );
593  m_layoutCache->font = font;
594  }
595 
596  QSizeF sz = m_layoutCache->textSize;
597 
598  if ( m_data->layoutAttributes & MinimumLayout )
599  {
600  double left, right, top, bottom;
601  m_data->textEngine->textMargins( font, m_data->text,
602  left, right, top, bottom );
603  sz -= QSizeF( left + right, top + bottom );
604  }
605 
606  return sz;
607 }
608 
615 void QwtText::draw( QPainter* painter, const QRectF& rect ) const
616 {
617  if ( m_data->paintAttributes & PaintBackground )
618  {
619  if ( m_data->borderPen != Qt::NoPen ||
620  m_data->backgroundBrush != Qt::NoBrush )
621  {
622  painter->save();
623 
624  painter->setPen( m_data->borderPen );
625  painter->setBrush( m_data->backgroundBrush );
626 
627  if ( m_data->borderRadius == 0 )
628  {
629  QwtPainter::drawRect( painter, rect );
630  }
631  else
632  {
633  painter->setRenderHint( QPainter::Antialiasing, true );
634  painter->drawRoundedRect( rect,
635  m_data->borderRadius, m_data->borderRadius );
636  }
637 
638  painter->restore();
639  }
640  }
641 
642  painter->save();
643 
644  if ( m_data->paintAttributes & PaintUsingTextFont )
645  {
646  painter->setFont( m_data->font );
647  }
648 
649  if ( m_data->paintAttributes & PaintUsingTextColor )
650  {
651  if ( m_data->color.isValid() )
652  painter->setPen( m_data->color );
653  }
654 
655  QRectF expandedRect = rect;
656  if ( m_data->layoutAttributes & MinimumLayout )
657  {
658  // We want to calculate in screen metrics. So
659  // we need a font that uses screen metrics
660 
661  const QFont font = QwtPainter::scaledFont( painter->font() );
662 
663  double left, right, top, bottom;
664  m_data->textEngine->textMargins(
665  font, m_data->text, left, right, top, bottom );
666 
667  expandedRect.setTop( rect.top() - top );
668  expandedRect.setBottom( rect.bottom() + bottom );
669  expandedRect.setLeft( rect.left() - left );
670  expandedRect.setRight( rect.right() + right );
671  }
672 
673  m_data->textEngine->draw( painter, expandedRect,
674  m_data->renderFlags, m_data->text );
675 
676  painter->restore();
677 }
678 
694 const QwtTextEngine* QwtText::textEngine( const QString& text,
695  QwtText::TextFormat format )
696 {
697  return TextEngineDict::dict().textEngine( text, format );
698 }
699 
714  QwtTextEngine* engine )
715 {
716  TextEngineDict::dict().setTextEngine( format, engine );
717 }
718 
728 {
729  return TextEngineDict::dict().textEngine( format );
730 }
731 
733 bool QwtText::isNull() const
734 {
735  return m_data->text.isNull();
736 }
737 
739 bool QwtText::isEmpty() const
740 {
741  return m_data->text.isEmpty();
742 }
743 
static void drawRect(QPainter *, qreal x, qreal y, qreal w, qreal h)
Wrapper for QPainter::drawRect()
static QFont scaledFont(const QFont &, const QPaintDevice *=nullptr)
A text engine for plain texts.
A text engine for Qt rich texts.
Abstract base class for rendering text strings.
virtual bool mightRender(const QString &text) const =0
A class representing a text.
Definition: qwt_text.h:52
static const QwtTextEngine * textEngine(const QString &text, QwtText::TextFormat=AutoText)
Definition: qwt_text.cpp:694
LayoutAttribute
Layout Attributes The layout attributes affects some aspects of the layout of the text.
Definition: qwt_text.h:133
@ MinimumLayout
Definition: qwt_text.h:140
bool operator==(const QwtText &) const
Relational operator.
Definition: qwt_text.cpp:250
QBrush backgroundBrush() const
Definition: qwt_text.cpp:451
QColor usedColor(const QColor &) const
Definition: qwt_text.cpp:386
void setLayoutAttribute(LayoutAttribute, bool on=true)
Definition: qwt_text.cpp:494
bool testPaintAttribute(PaintAttribute) const
Definition: qwt_text.cpp:482
QSizeF textSize() const
Definition: qwt_text.cpp:570
int renderFlags() const
Definition: qwt_text.cpp:317
double borderRadius() const
Definition: qwt_text.cpp:409
TextFormat
Text format.
Definition: qwt_text.h:65
@ AutoText
Definition: qwt_text.h:72
@ RichText
Use the Scribe framework (Qt Rich Text) to render the text.
Definition: qwt_text.h:78
@ PlainText
Draw the text as it is, using a QwtPlainTextEngine.
Definition: qwt_text.h:75
QFont font() const
Return the font.
Definition: qwt_text.cpp:336
QColor color() const
Return the pen color, used for painting the text.
Definition: qwt_text.cpp:372
void setBorderRadius(double)
Definition: qwt_text.cpp:400
QFlags< LayoutAttribute > LayoutAttributes
Definition: qwt_text.h:143
PaintAttribute
Paint Attributes.
Definition: qwt_text.h:115
@ PaintUsingTextColor
The text has an individual color.
Definition: qwt_text.h:120
@ PaintBackground
The text has an individual background.
Definition: qwt_text.h:123
@ PaintUsingTextFont
The text has an individual font.
Definition: qwt_text.h:117
void setText(const QString &, QwtText::TextFormat textFormat=AutoText)
Definition: qwt_text.cpp:277
bool isEmpty() const
Definition: qwt_text.cpp:739
void setPaintAttribute(PaintAttribute, bool on=true)
Definition: qwt_text.cpp:466
bool operator!=(const QwtText &) const
Relational operator.
Definition: qwt_text.cpp:264
~QwtText()
Destructor.
Definition: qwt_text.cpp:235
void setColor(const QColor &)
Definition: qwt_text.cpp:365
void setBorderPen(const QPen &)
Definition: qwt_text.cpp:420
void setFont(const QFont &)
Definition: qwt_text.cpp:329
QwtText & operator=(const QwtText &)
Assignment operator.
Definition: qwt_text.cpp:242
bool testLayoutAttribute(LayoutAttribute) const
Definition: qwt_text.cpp:510
void draw(QPainter *painter, const QRectF &rect) const
Definition: qwt_text.cpp:615
QString text() const
Definition: qwt_text.cpp:289
bool isNull() const
Definition: qwt_text.cpp:733
QFlags< PaintAttribute > PaintAttributes
Definition: qwt_text.h:126
static void setTextEngine(QwtText::TextFormat, QwtTextEngine *)
Definition: qwt_text.cpp:713
void setBackgroundBrush(const QBrush &)
Definition: qwt_text.cpp:441
QPen borderPen() const
Definition: qwt_text.cpp:430
double heightForWidth(double width) const
Definition: qwt_text.cpp:522
void setRenderFlags(int)
Change the render flags.
Definition: qwt_text.cpp:304
QFont usedFont(const QFont &) const
Definition: qwt_text.cpp:350