KChart

KChartTextLabelCache.cpp
1 /*
2  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "KChartTextLabelCache.h"
10 
11 #include <cmath>
12 
13 #include <QtDebug>
14 #include <QImage>
15 #include <QPainter>
16 #include <QApplication>
17 
18 #ifndef NDEBUG
19 int HitCount = 0;
20 int MissCount = 0;
21 #define INC_HIT_COUNT { ++HitCount; }
22 #define INC_MISS_COUNT { ++MissCount; }
23 #define DUMP_CACHE_STATS \
24  if ( HitCount != 0 && MissCount != 0 ) { \
25  int total = HitCount + MissCount; \
26  qreal hitQuote = ( 1.0 * HitCount ) / total; \
27  qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
28  << HitCount << "/" << MissCount << "/" << total \
29  << "(" << 100 * hitQuote << "% hits)"; \
30  }
31 #else
32 #define INC_HIT_COUNT
33 #define INC_MISS_COUNT
34 #define DUMP_CACHE_STATS
35 #endif
36 
37 PrerenderedElement::PrerenderedElement()
38  : m_referencePoint( KChartEnums::PositionNorthWest )
39 {
40 }
41 
43 { // this does not invalidate the element
44  m_position = position;
45 }
46 
48 {
49  return m_position;
50 }
51 
53 { // this does not invalidate the element
54  m_referencePoint = point;
55 }
56 
58 {
59  return m_referencePoint;
60 }
61 
62 PrerenderedLabel::PrerenderedLabel()
64  , m_dirty( true )
65  , m_font( qApp->font() )
66  , m_brush( Qt::black )
67  , m_pen( Qt::black ) // do not use anything invisible
68  , m_angle( 0.0 )
69 {
70 }
71 
72 PrerenderedLabel::~PrerenderedLabel()
73 {
74  DUMP_CACHE_STATS;
75 }
76 
78 {
79  m_dirty = true;
80 }
81 
82 void PrerenderedLabel::setFont( const QFont& font )
83 {
84  m_font = font;
85  invalidate();
86 }
87 
89 {
90  return m_font;
91 }
92 
94 {
95  m_text = text;
96  invalidate();
97 }
98 
100 {
101  return m_text;
102 }
103 
104 void PrerenderedLabel::setBrush( const QBrush& brush )
105 {
106  m_brush = brush;
107  invalidate();
108 }
109 
111 {
112  return m_brush;
113 }
114 
115 void PrerenderedLabel::setAngle( qreal angle )
116 {
117  m_angle = angle;
118  invalidate();
119 }
120 
122 {
123  return m_angle;
124 }
125 
127 {
128  if ( m_dirty ) {
129  INC_MISS_COUNT;
130  paint();
131  } else {
132  INC_HIT_COUNT;
133  }
134  return m_pixmap;
135 }
136 
137 void PrerenderedLabel::paint() const
138 {
139  // FIXME find a better value using font metrics of text (this
140  // requires finding the diameter of the circle formed by rotating
141  // the bounding rect around the center):
142  const int Width = 1000;
143  const int Height = Width;
144 
145  QRectF boundingRect;
146  const QColor FullTransparent( 255, 255, 255, 0 );
147 #ifdef Q_WS_X11
149  qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
150  << "to work around XRender/Qt4 bug.";
151 #else
152  QPixmap pixmap( Width, Height );
153 #endif
154  // pixmap.fill( FullTransparent );
155  {
156  static const QPointF Center ( 0.0, 0.0 );
157  QPointF textBottomRight;
158  QPainter painter( &pixmap );
159  painter.setRenderHint(QPainter::TextAntialiasing, true );
160  painter.setRenderHint(QPainter::Antialiasing, true );
161 
162  // QImage (X11 workaround) does not have fill():
163  painter.setPen( FullTransparent );
164  painter.setBrush( FullTransparent );
165  QPainter::CompositionMode mode = painter.compositionMode();
166  painter.setCompositionMode( QPainter::CompositionMode_Clear );
167  painter.drawRect( 0, 0, Width, Height );
168  painter.setCompositionMode( mode );
169 
170  QTransform matrix;
171  matrix.translate( 0.5 * Width, 0.5 * Height );
172  matrix.rotate( m_angle );
173  painter.setWorldTransform( matrix );
174 
175  painter.setPen( m_pen );
176  painter.setBrush( m_brush );
177  painter.setFont( m_font );
178  QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
179  painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
180  m_text, &boundingRect );
181  m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
182  textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
183  m_textAscendVector = boundingRect.topRight() - textBottomRight;
184  m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
185 
186  // FIXME translate topright by char height
187  boundingRect = matrix.mapRect( boundingRect );
188  m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
189  - boundingRect.topLeft();
190  textBottomRight = matrix.map( textBottomRight )
191  - boundingRect.topLeft();
192  m_textAscendVector = matrix.map( m_textAscendVector )
193  - matrix.map( Center );
194  m_textBaseLineVector = matrix.map( m_textBaseLineVector )
195  - matrix.map( Center );
196  }
197 
198  m_dirty = false; // now all the calculation vectors are valid
199 
200  QPixmap temp( static_cast<int>( boundingRect.width() ),
201  static_cast<int>( boundingRect.height() ) );
202  {
203  temp.fill( FullTransparent );
204  QPainter painter( &temp );
205 #ifdef Q_WS_X11
206  painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
207 #else
208  painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
209 #endif
210 // #define PRERENDEREDLABEL_DEBUG
211 #ifdef PRERENDEREDLABEL_DEBUG
212  painter.setPen( QPen( Qt::red, 2 ) );
213  painter.setBrush( Qt::red );
214  // paint markers for the reference points
216  positions << KChartEnums::PositionCenter
217  << KChartEnums::PositionNorthWest
218  << KChartEnums::PositionNorth
219  << KChartEnums::PositionNorthEast
220  << KChartEnums::PositionEast
221  << KChartEnums::PositionSouthEast
222  << KChartEnums::PositionSouth
223  << KChartEnums::PositionSouthWest
224  << KChartEnums::PositionWest;
225  for ( KChartEnums::PositionValue position : qAsConst(positions) ) { //krazy:exclude=foreach
226  static const double Radius = 0.5;
227  static const double Diameter = 2 * Radius;
228 
230  painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
231  QSizeF( Diameter, Diameter ) ) );
232  }
233 #endif
234  }
235 
236  m_pixmap = temp;
237 }
238 
240 {
242 }
243 
245 {
246  if ( m_dirty ) {
247  INC_MISS_COUNT;
248  paint();
249  } else {
250  INC_HIT_COUNT;
251  }
252 
253  switch ( position ) {
254  case KChartEnums::PositionCenter:
255  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
256  case KChartEnums::PositionNorthWest:
257  return m_referenceBottomLeft + m_textAscendVector;
258  case KChartEnums::PositionNorth:
259  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
260  case KChartEnums::PositionNorthEast:
261  return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
262  case KChartEnums::PositionEast:
263  return m_referenceBottomLeft + 0.5 * m_textAscendVector;
264  case KChartEnums::PositionSouthEast:
265  return m_referenceBottomLeft + m_textBaseLineVector;
266  case KChartEnums::PositionSouth:
267  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
268  case KChartEnums::PositionSouthWest:
269  return m_referenceBottomLeft;
270  case KChartEnums::PositionWest:
271  return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
272 
273  case KChartEnums::PositionUnknown: // intentional fall-through
274  case KChartEnums::PositionFloating: // intentional fall-through
275  return QPointF();
276  }
277 
278  return QPointF();
279 }
QPoint map(const QPoint &point) const const
AlignHCenter
Project global class providing some enums needed both by KChartParams and by KChartCustomBox.
Definition: KChartEnums.h:26
Format_ARGB32_Premultiplied
QTransform & rotate(qreal angle, Qt::Axis axis)
void setAngle(qreal angle)
Sets the angle of the label to angle degrees.
const QBrush & brush() const
QPointF bottomLeft() const const
void setPosition(const QPointF &position)
Set the position of the element.
QPointF topLeft() const const
void invalidate() const override
Invalidates the preredendered data, forces re-rendering.
QTransform & translate(qreal dx, qreal dy)
QPointF bottomRight() const const
void setText(const QString &text)
Sets the label's text to text.
void setBrush(const QBrush &brush)
Sets the label's brush to brush.
const QFont & font() const
const QPointF & position() const
Get the position of the element.
void setReferencePoint(KChartEnums::PositionValue)
Set the reference point of the element.
Width
qreal x() const const
qreal width() const const
KChartEnums::PositionValue referencePoint() const
Get the reference point of the element.
void setFont(const QFont &font)
Sets the label's font to font.
base class for prerendered elements like labels, pixmaps, markers, etc.
QRect mapRect(const QRect &rectangle) const const
Height
PositionValue
Numerical values of the static KChart::Position instances, for using a Position::value() with a switc...
Definition: KChartEnums.h:180
const QString & text() const
QPointF topRight() const const
QPointF referencePointLocation(KChartEnums::PositionValue position) const override
Return the location of the reference point relatively to the pixmap's origin.
const QPixmap & pixmap() const override
Returns the rendered element.
qreal height() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Jul 1 2022 05:09:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.