KD Chart 2  [rev.2.7]
KDChartTextLabelCache.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "KDChartTextLabelCache.h"
24 
25 #include <cmath>
26 
27 #include <QtDebug>
28 #include <QImage>
29 #include <QPixmap>
30 #include <QPainter>
31 #include <QApplication>
32 
33 #ifndef NDEBUG
34 int HitCount = 0;
35 int MissCount = 0;
36 #define INC_HIT_COUNT { ++HitCount; }
37 #define INC_MISS_COUNT { ++MissCount; }
38 #define DUMP_CACHE_STATS \
39  if ( HitCount != 0 && MissCount != 0 ) { \
40  int total = HitCount + MissCount; \
41  qreal hitQuote = ( 1.0 * HitCount ) / total; \
42  qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
43  << HitCount << "/" << MissCount << "/" << total \
44  << "(" << 100 * hitQuote << "% hits)"; \
45  }
46 #else
47 #define INC_HIT_COUNT
48 #define INC_MISS_COUNT
49 #define DUMP_CACHE_STATS
50 #endif
51 
53  : m_referencePoint( KDChartEnums::PositionNorthWest )
54 {
55 }
56 
58 { // this does not invalidate the element
59  m_position = position;
60 }
61 
62 const QPointF& PrerenderedElement::position() const
63 {
64  return m_position;
65 }
66 
68 { // this does not invalidate the element
69  m_referencePoint = point;
70 }
71 
73 {
74  return m_referencePoint;
75 }
76 
79  , m_dirty( true )
80  , m_font( qApp->font() )
81  , m_brush( Qt::black )
82  , m_pen( Qt::black ) // do not use anything invisible
83  , m_angle( 0.0 )
84 {
85 }
86 
88 {
90 }
91 
96 {
97  m_dirty = true;
98 }
99 
103 void PrerenderedLabel::setFont( const QFont& font )
104 {
105  m_font = font;
106  invalidate();
107 }
108 
112 const QFont& PrerenderedLabel::font() const
113 {
114  return m_font;
115 }
116 
120 void PrerenderedLabel::setText( const QString& text )
121 {
122  m_text = text;
123  invalidate();
124 }
125 
129 const QString& PrerenderedLabel::text() const
130 {
131  return m_text;
132 }
133 
137 void PrerenderedLabel::setBrush( const QBrush& brush )
138 {
139  m_brush = brush;
140  invalidate();
141 }
142 
146 const QBrush& PrerenderedLabel::brush() const
147 {
148  return m_brush;
149 }
150 
155 {
156  m_angle = angle;
157  invalidate();
158 }
159 
164 {
165  return m_angle;
166 }
167 
168 const QPixmap& PrerenderedLabel::pixmap() const
169 {
170  if ( m_dirty ) {
172  paint();
173  } else {
175  }
176  return m_pixmap;
177 }
178 
179 void PrerenderedLabel::paint() const
180 {
181  // FIXME find a better value using font metrics of text (this
182  // requires finding the diameter of the circle formed by rotating
183  // the bounding rect around the center):
184  const int Width = 1000;
185  const int Height = Width;
186 
187  QRectF boundingRect;
188  const QColor FullTransparent( 255, 255, 255, 0 );
189 #ifdef Q_WS_X11
190  QImage pixmap( Width, Height, QImage::Format_ARGB32_Premultiplied );
191  qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
192  << "to work around XRender/Qt4 bug.";
193 #else
194  QPixmap pixmap( Width, Height );
195 #endif
196  // pixmap.fill( FullTransparent );
197  {
198  static const QPointF Center ( 0.0, 0.0 );
199  QPointF textBottomRight;
200  QPainter painter( &pixmap );
201  painter.setRenderHint(QPainter::TextAntialiasing, true );
202  painter.setRenderHint(QPainter::Antialiasing, true );
203 
204  // QImage (X11 workaround) does not have fill():
205  painter.setPen( FullTransparent );
206  painter.setBrush( FullTransparent );
207  QPainter::CompositionMode mode = painter.compositionMode();
208  painter.setCompositionMode( QPainter::CompositionMode_Clear );
209  painter.drawRect( 0, 0, Width, Height );
210  painter.setCompositionMode( mode );
211 
212  QMatrix matrix;
213  matrix.translate( 0.5 * Width, 0.5 * Height );
214  matrix.rotate( m_angle );
215 #if QT_VERSION > 0x040199
216  painter.setWorldMatrix( matrix );
217 #else
218  painter.setMatrix( matrix );
219 #endif
220 
221  painter.setPen( m_pen );
222  painter.setBrush( m_brush );
223  painter.setFont( m_font );
224  QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
225  painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
226  m_text, &boundingRect );
227  m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
228  textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
229  m_textAscendVector = boundingRect.topRight() - textBottomRight;
230  m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
231 
232  // FIXME translate topright by char height
233  boundingRect = matrix.mapRect( boundingRect );
234  m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
235  - boundingRect.topLeft();
236  textBottomRight = matrix.map( textBottomRight )
237  - boundingRect.topLeft();
238  m_textAscendVector = matrix.map( m_textAscendVector )
239  - matrix.map( Center );
240  m_textBaseLineVector = matrix.map( m_textBaseLineVector )
241  - matrix.map( Center );
242  }
243 
244  m_dirty = false; // now all the calculation vectors are valid
245 
246  QPixmap temp( static_cast<int>( boundingRect.width() ),
247  static_cast<int>( boundingRect.height() ) );
248  {
249  temp.fill( FullTransparent );
250  QPainter painter( &temp );
251 #ifdef Q_WS_X11
252  painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
253 #else
254  painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
255 #endif
256 // #define PRERENDEREDLABEL_DEBUG
257 #ifdef PRERENDEREDLABEL_DEBUG
258  painter.setPen( QPen( Qt::red, 2 ) );
259  painter.setBrush( Qt::red );
260  // paint markers for the reference points
262  positions << KDChartEnums::PositionCenter
271  Q_FOREACH( KDChartEnums::PositionValue position, positions ) { //krazy:exclude=foreach
272  static const double Radius = 0.5;
273  static const double Diameter = 2 * Radius;
274 
275  QPointF point ( referencePointLocation( position ) );
276  painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
277  QSizeF( Diameter, Diameter ) ) );
278  }
279 #endif
280  }
281 
282  m_pixmap = temp;
283 }
284 
286 {
288 }
289 
291 {
292  if ( m_dirty ) {
294  paint();
295  } else {
297  }
298 
299  switch ( position ) {
301  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
303  return m_referenceBottomLeft + m_textAscendVector;
305  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
307  return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
309  return m_referenceBottomLeft + 0.5 * m_textAscendVector;
311  return m_referenceBottomLeft + m_textBaseLineVector;
313  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
315  return m_referenceBottomLeft;
317  return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
318 
319  case KDChartEnums::PositionUnknown: // intentional fall-through
320  case KDChartEnums::PositionFloating: // intentional fall-through
321  return QPointF();
322  }
323 
324  return QPointF();
325 }
const QString & text() const
Project global class providing some enums needed both by KDChartParams and by KDChartCustomBox.
Definition: KDChartEnums.h:40
int MissCount
const QPixmap & pixmap() const override
Returns the rendered element.
void setBrush(const QBrush &brush)
Sets the label&#39;s brush to brush.
const QPointF & position() const
Get the position of the element.
#define DUMP_CACHE_STATS
const QFont & font() const
void setFont(const QFont &font)
Sets the label&#39;s font to font.
KDChartEnums::PositionValue referencePoint() const
Get the reference point of the element.
int HitCount
#define INC_HIT_COUNT
base class for prerendered elements like labels, pixmaps, markers, etc.
void setReferencePoint(KDChartEnums::PositionValue)
Set the reference point of the element.
void setText(const QString &text)
Sets the label&#39;s text to text.
void invalidate() const override
Invalidates the preredendered data, forces re-rendering.
PositionValue
Numerical values of the static KDChart::Position instances, for using a Position::value() with a swit...
Definition: KDChartEnums.h:192
void setPosition(const QPointF &position)
Set the position of the element.
void setAngle(qreal angle)
Sets the angle of the label to angle degrees.
const QBrush & brush() const
#define INC_MISS_COUNT
QPointF referencePointLocation() const

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/