source: ntrip/trunk/BNC/qwt/qwt_text.cpp@ 8127

Last change on this file since 8127 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 15.5 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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 <qmap.h>
14#include <qfont.h>
15#include <qcolor.h>
16#include <qpen.h>
17#include <qbrush.h>
18#include <qpainter.h>
19#include <qapplication.h>
20#include <qdesktopwidget.h>
21#include <qmath.h>
22
23class QwtTextEngineDict
24{
25public:
26 static QwtTextEngineDict &dict();
27
28 void setTextEngine( QwtText::TextFormat, QwtTextEngine * );
29
30 const QwtTextEngine *textEngine( QwtText::TextFormat ) const;
31 const QwtTextEngine *textEngine( const QString &,
32 QwtText::TextFormat ) const;
33
34private:
35 QwtTextEngineDict();
36 ~QwtTextEngineDict();
37
38 typedef QMap<int, QwtTextEngine *> EngineMap;
39
40 inline const QwtTextEngine *engine( EngineMap::const_iterator &it ) const
41 {
42 return it.value();
43 }
44
45 EngineMap d_map;
46};
47
48QwtTextEngineDict &QwtTextEngineDict::dict()
49{
50 static QwtTextEngineDict engineDict;
51 return engineDict;
52}
53
54QwtTextEngineDict::QwtTextEngineDict()
55{
56 d_map.insert( QwtText::PlainText, new QwtPlainTextEngine() );
57#ifndef QT_NO_RICHTEXT
58 d_map.insert( QwtText::RichText, new QwtRichTextEngine() );
59#endif
60}
61
62QwtTextEngineDict::~QwtTextEngineDict()
63{
64 for ( EngineMap::const_iterator it = d_map.begin();
65 it != d_map.end(); ++it )
66 {
67 const QwtTextEngine *textEngine = engine( it );
68 delete textEngine;
69 }
70}
71
72const QwtTextEngine *QwtTextEngineDict::textEngine( const QString& text,
73 QwtText::TextFormat format ) const
74{
75 if ( format == QwtText::AutoText )
76 {
77 for ( EngineMap::const_iterator it = d_map.begin();
78 it != d_map.end(); ++it )
79 {
80 if ( it.key() != QwtText::PlainText )
81 {
82 const QwtTextEngine *e = engine( it );
83 if ( e && e->mightRender( text ) )
84 return e;
85 }
86 }
87 }
88
89 EngineMap::const_iterator it = d_map.find( format );
90 if ( it != d_map.end() )
91 {
92 const QwtTextEngine *e = engine( it );
93 if ( e )
94 return e;
95 }
96
97 it = d_map.find( QwtText::PlainText );
98 return engine( it );
99}
100
101void QwtTextEngineDict::setTextEngine( QwtText::TextFormat format,
102 QwtTextEngine *engine )
103{
104 if ( format == QwtText::AutoText )
105 return;
106
107 if ( format == QwtText::PlainText && engine == NULL )
108 return;
109
110 EngineMap::const_iterator it = d_map.find( format );
111 if ( it != d_map.end() )
112 {
113 const QwtTextEngine *e = this->engine( it );
114 if ( e )
115 delete e;
116
117 d_map.remove( format );
118 }
119
120 if ( engine != NULL )
121 d_map.insert( format, engine );
122}
123
124const QwtTextEngine *QwtTextEngineDict::textEngine(
125 QwtText::TextFormat format ) const
126{
127 const QwtTextEngine *e = NULL;
128
129 EngineMap::const_iterator it = d_map.find( format );
130 if ( it != d_map.end() )
131 e = engine( it );
132
133 return e;
134}
135
136class QwtText::PrivateData
137{
138public:
139 PrivateData():
140 renderFlags( Qt::AlignCenter ),
141 borderRadius( 0 ),
142 borderPen( Qt::NoPen ),
143 backgroundBrush( Qt::NoBrush ),
144 paintAttributes( 0 ),
145 layoutAttributes( 0 ),
146 textEngine( NULL )
147 {
148 }
149
150 int renderFlags;
151 QString text;
152 QFont font;
153 QColor color;
154 double borderRadius;
155 QPen borderPen;
156 QBrush backgroundBrush;
157
158 QwtText::PaintAttributes paintAttributes;
159 QwtText::LayoutAttributes layoutAttributes;
160
161 const QwtTextEngine *textEngine;
162};
163
164class QwtText::LayoutCache
165{
166public:
167 void invalidate()
168 {
169 textSize = QSizeF();
170 }
171
172 QFont font;
173 QSizeF textSize;
174};
175
176/*!
177 Constructor
178
179 \param text Text content
180 \param textFormat Text format
181*/
182QwtText::QwtText( const QString &text, QwtText::TextFormat textFormat )
183{
184 d_data = new PrivateData;
185 d_data->text = text;
186 d_data->textEngine = textEngine( text, textFormat );
187
188 d_layoutCache = new LayoutCache;
189}
190
191//! Copy constructor
192QwtText::QwtText( const QwtText &other )
193{
194 d_data = new PrivateData;
195 *d_data = *other.d_data;
196
197 d_layoutCache = new LayoutCache;
198 *d_layoutCache = *other.d_layoutCache;
199}
200
201//! Destructor
202QwtText::~QwtText()
203{
204 delete d_data;
205 delete d_layoutCache;
206}
207
208//! Assignment operator
209QwtText &QwtText::operator=( const QwtText & other )
210{
211 *d_data = *other.d_data;
212 *d_layoutCache = *other.d_layoutCache;
213 return *this;
214}
215
216//! Relational operator
217bool QwtText::operator==( const QwtText &other ) const
218{
219 return d_data->renderFlags == other.d_data->renderFlags &&
220 d_data->text == other.d_data->text &&
221 d_data->font == other.d_data->font &&
222 d_data->color == other.d_data->color &&
223 d_data->borderRadius == other.d_data->borderRadius &&
224 d_data->borderPen == other.d_data->borderPen &&
225 d_data->backgroundBrush == other.d_data->backgroundBrush &&
226 d_data->paintAttributes == other.d_data->paintAttributes &&
227 d_data->textEngine == other.d_data->textEngine;
228}
229
230//! Relational operator
231bool QwtText::operator!=( const QwtText &other ) const // invalidate
232{
233 return !( other == *this );
234}
235
236/*!
237 Assign a new text content
238
239 \param text Text content
240 \param textFormat Text format
241
242 \sa text()
243*/
244void QwtText::setText( const QString &text,
245 QwtText::TextFormat textFormat )
246{
247 d_data->text = text;
248 d_data->textEngine = textEngine( text, textFormat );
249 d_layoutCache->invalidate();
250}
251
252/*!
253 \return Text as QString.
254 \sa setText()
255*/
256QString QwtText::text() const
257{
258 return d_data->text;
259}
260
261/*!
262 \brief Change the render flags
263
264 The default setting is Qt::AlignCenter
265
266 \param renderFlags Bitwise OR of the flags used like in QPainter::drawText()
267
268 \sa renderFlags(), QwtTextEngine::draw()
269 \note Some renderFlags might have no effect, depending on the text format.
270*/
271void QwtText::setRenderFlags( int renderFlags )
272{
273 if ( renderFlags != d_data->renderFlags )
274 {
275 d_data->renderFlags = renderFlags;
276 d_layoutCache->invalidate();
277 }
278}
279
280/*!
281 \return Render flags
282 \sa setRenderFlags()
283*/
284int QwtText::renderFlags() const
285{
286 return d_data->renderFlags;
287}
288
289/*!
290 Set the font.
291
292 \param font Font
293 \note Setting the font might have no effect, when
294 the text contains control sequences for setting fonts.
295*/
296void QwtText::setFont( const QFont &font )
297{
298 d_data->font = font;
299 setPaintAttribute( PaintUsingTextFont );
300}
301
302//! Return the font.
303QFont QwtText::font() const
304{
305 return d_data->font;
306}
307
308/*!
309 Return the font of the text, if it has one.
310 Otherwise return defaultFont.
311
312 \param defaultFont Default font
313 \return Font used for drawing the text
314
315 \sa setFont(), font(), PaintAttributes
316*/
317QFont QwtText::usedFont( const QFont &defaultFont ) const
318{
319 if ( d_data->paintAttributes & PaintUsingTextFont )
320 return d_data->font;
321
322 return defaultFont;
323}
324
325/*!
326 Set the pen color used for drawing the text.
327
328 \param color Color
329 \note Setting the color might have no effect, when
330 the text contains control sequences for setting colors.
331*/
332void QwtText::setColor( const QColor &color )
333{
334 d_data->color = color;
335 setPaintAttribute( PaintUsingTextColor );
336}
337
338//! Return the pen color, used for painting the text
339QColor QwtText::color() const
340{
341 return d_data->color;
342}
343
344/*!
345 Return the color of the text, if it has one.
346 Otherwise return defaultColor.
347
348 \param defaultColor Default color
349 \return Color used for drawing the text
350
351 \sa setColor(), color(), PaintAttributes
352*/
353QColor QwtText::usedColor( const QColor &defaultColor ) const
354{
355 if ( d_data->paintAttributes & PaintUsingTextColor )
356 return d_data->color;
357
358 return defaultColor;
359}
360
361/*!
362 Set the radius for the corners of the border frame
363
364 \param radius Radius of a rounded corner
365 \sa borderRadius(), setBorderPen(), setBackgroundBrush()
366*/
367void QwtText::setBorderRadius( double radius )
368{
369 d_data->borderRadius = qMax( 0.0, radius );
370}
371
372/*!
373 \return Radius for the corners of the border frame
374 \sa setBorderRadius(), borderPen(), backgroundBrush()
375*/
376double QwtText::borderRadius() const
377{
378 return d_data->borderRadius;
379}
380
381/*!
382 Set the background pen
383
384 \param pen Background pen
385 \sa borderPen(), setBackgroundBrush()
386*/
387void QwtText::setBorderPen( const QPen &pen )
388{
389 d_data->borderPen = pen;
390 setPaintAttribute( PaintBackground );
391}
392
393/*!
394 \return Background pen
395 \sa setBorderPen(), backgroundBrush()
396*/
397QPen QwtText::borderPen() const
398{
399 return d_data->borderPen;
400}
401
402/*!
403 Set the background brush
404
405 \param brush Background brush
406 \sa backgroundBrush(), setBorderPen()
407*/
408void QwtText::setBackgroundBrush( const QBrush &brush )
409{
410 d_data->backgroundBrush = brush;
411 setPaintAttribute( PaintBackground );
412}
413
414/*!
415 \return Background brush
416 \sa setBackgroundBrush(), borderPen()
417*/
418QBrush QwtText::backgroundBrush() const
419{
420 return d_data->backgroundBrush;
421}
422
423/*!
424 Change a paint attribute
425
426 \param attribute Paint attribute
427 \param on On/Off
428
429 \note Used by setFont(), setColor(),
430 setBorderPen() and setBackgroundBrush()
431 \sa testPaintAttribute()
432*/
433void QwtText::setPaintAttribute( PaintAttribute attribute, bool on )
434{
435 if ( on )
436 d_data->paintAttributes |= attribute;
437 else
438 d_data->paintAttributes &= ~attribute;
439}
440
441/*!
442 Test a paint attribute
443
444 \param attribute Paint attribute
445 \return true, if attribute is enabled
446
447 \sa setPaintAttribute()
448*/
449bool QwtText::testPaintAttribute( PaintAttribute attribute ) const
450{
451 return d_data->paintAttributes & attribute;
452}
453
454/*!
455 Change a layout attribute
456
457 \param attribute Layout attribute
458 \param on On/Off
459 \sa testLayoutAttribute()
460*/
461void QwtText::setLayoutAttribute( LayoutAttribute attribute, bool on )
462{
463 if ( on )
464 d_data->layoutAttributes |= attribute;
465 else
466 d_data->layoutAttributes &= ~attribute;
467}
468
469/*!
470 Test a layout attribute
471
472 \param attribute Layout attribute
473 \return true, if attribute is enabled
474
475 \sa setLayoutAttribute()
476*/
477bool QwtText::testLayoutAttribute( LayoutAttribute attribute ) const
478{
479 return d_data->layoutAttributes | attribute;
480}
481
482/*!
483 Find the height for a given width
484
485 \param defaultFont Font, used for the calculation if the text has no font
486 \param width Width
487
488 \return Calculated height
489*/
490double QwtText::heightForWidth( double width, const QFont &defaultFont ) const
491{
492 // We want to calculate in screen metrics. So
493 // we need a font that uses screen metrics
494
495 const QFont font( usedFont( defaultFont ), QApplication::desktop() );
496
497 double h = 0;
498
499 if ( d_data->layoutAttributes & MinimumLayout )
500 {
501 double left, right, top, bottom;
502 d_data->textEngine->textMargins( font, d_data->text,
503 left, right, top, bottom );
504
505 h = d_data->textEngine->heightForWidth(
506 font, d_data->renderFlags, d_data->text,
507 width + left + right );
508
509 h -= top + bottom;
510 }
511 else
512 {
513 h = d_data->textEngine->heightForWidth(
514 font, d_data->renderFlags, d_data->text, width );
515 }
516
517 return h;
518}
519
520/*!
521 Returns the size, that is needed to render text
522
523 \param defaultFont Font of the text
524 \return Calculated size
525*/
526QSizeF QwtText::textSize( const QFont &defaultFont ) const
527{
528 // We want to calculate in screen metrics. So
529 // we need a font that uses screen metrics
530
531 const QFont font( usedFont( defaultFont ), QApplication::desktop() );
532
533 if ( !d_layoutCache->textSize.isValid()
534 || d_layoutCache->font != font )
535 {
536 d_layoutCache->textSize = d_data->textEngine->textSize(
537 font, d_data->renderFlags, d_data->text );
538 d_layoutCache->font = font;
539 }
540
541 QSizeF sz = d_layoutCache->textSize;
542
543 if ( d_data->layoutAttributes & MinimumLayout )
544 {
545 double left, right, top, bottom;
546 d_data->textEngine->textMargins( font, d_data->text,
547 left, right, top, bottom );
548 sz -= QSizeF( left + right, top + bottom );
549 }
550
551 return sz;
552}
553
554/*!
555 Draw a text into a rectangle
556
557 \param painter Painter
558 \param rect Rectangle
559*/
560void QwtText::draw( QPainter *painter, const QRectF &rect ) const
561{
562 if ( d_data->paintAttributes & PaintBackground )
563 {
564 if ( d_data->borderPen != Qt::NoPen ||
565 d_data->backgroundBrush != Qt::NoBrush )
566 {
567 painter->save();
568
569 painter->setPen( d_data->borderPen );
570 painter->setBrush( d_data->backgroundBrush );
571
572 if ( d_data->borderRadius == 0 )
573 {
574 QwtPainter::drawRect( painter, rect );
575 }
576 else
577 {
578 painter->setRenderHint( QPainter::Antialiasing, true );
579 painter->drawRoundedRect( rect,
580 d_data->borderRadius, d_data->borderRadius );
581 }
582
583 painter->restore();
584 }
585 }
586
587 painter->save();
588
589 if ( d_data->paintAttributes & PaintUsingTextFont )
590 {
591 painter->setFont( d_data->font );
592 }
593
594 if ( d_data->paintAttributes & PaintUsingTextColor )
595 {
596 if ( d_data->color.isValid() )
597 painter->setPen( d_data->color );
598 }
599
600 QRectF expandedRect = rect;
601 if ( d_data->layoutAttributes & MinimumLayout )
602 {
603 // We want to calculate in screen metrics. So
604 // we need a font that uses screen metrics
605
606 const QFont font( painter->font(), QApplication::desktop() );
607
608 double left, right, top, bottom;
609 d_data->textEngine->textMargins(
610 font, d_data->text, left, right, top, bottom );
611
612 expandedRect.setTop( rect.top() - top );
613 expandedRect.setBottom( rect.bottom() + bottom );
614 expandedRect.setLeft( rect.left() - left );
615 expandedRect.setRight( rect.right() + right );
616 }
617
618 d_data->textEngine->draw( painter, expandedRect,
619 d_data->renderFlags, d_data->text );
620
621 painter->restore();
622}
623
624/*!
625 Find the text engine for a text format
626
627 In case of QwtText::AutoText the first text engine
628 (beside QwtPlainTextEngine) is returned, where QwtTextEngine::mightRender
629 returns true. If there is none QwtPlainTextEngine is returned.
630
631 If no text engine is registered for the format QwtPlainTextEngine
632 is returnd.
633
634 \param text Text, needed in case of AutoText
635 \param format Text format
636
637 \return Corresponding text engine
638*/
639const QwtTextEngine *QwtText::textEngine( const QString &text,
640 QwtText::TextFormat format )
641{
642 return QwtTextEngineDict::dict().textEngine( text, format );
643}
644
645/*!
646 Assign/Replace a text engine for a text format
647
648 With setTextEngine it is possible to extend Qwt with
649 other types of text formats.
650
651 For QwtText::PlainText it is not allowed to assign a engine == NULL.
652
653 \param format Text format
654 \param engine Text engine
655
656 \sa QwtMathMLTextEngine
657 \warning Using QwtText::AutoText does nothing.
658*/
659void QwtText::setTextEngine( QwtText::TextFormat format,
660 QwtTextEngine *engine )
661{
662 QwtTextEngineDict::dict().setTextEngine( format, engine );
663}
664
665/*!
666 \brief Find the text engine for a text format
667
668 textEngine can be used to find out if a text format is supported.
669
670 \param format Text format
671 \return The text engine, or NULL if no engine is available.
672*/
673const QwtTextEngine *QwtText::textEngine( QwtText::TextFormat format )
674{
675 return QwtTextEngineDict::dict().textEngine( format );
676}
Note: See TracBrowser for help on using the repository browser.