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

KDE's Doxygen guidelines are available online.