KChart

KChartTextLabelCache.cpp
1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "KChartTextLabelCache.h"
21 
22 #include <cmath>
23 
24 #include <QtDebug>
25 #include <QImage>
26 #include <QPixmap>
27 #include <QPainter>
28 #include <QApplication>
29 
30 #ifndef NDEBUG
31 int HitCount = 0;
32 int MissCount = 0;
33 #define INC_HIT_COUNT { ++HitCount; }
34 #define INC_MISS_COUNT { ++MissCount; }
35 #define DUMP_CACHE_STATS \
36  if ( HitCount != 0 && MissCount != 0 ) { \
37  int total = HitCount + MissCount; \
38  qreal hitQuote = ( 1.0 * HitCount ) / total; \
39  qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
40  << HitCount << "/" << MissCount << "/" << total \
41  << "(" << 100 * hitQuote << "% hits)"; \
42  }
43 #else
44 #define INC_HIT_COUNT
45 #define INC_MISS_COUNT
46 #define DUMP_CACHE_STATS
47 #endif
48 
49 PrerenderedElement::PrerenderedElement()
50  : m_referencePoint( KChartEnums::PositionNorthWest )
51 {
52 }
53 
55 { // this does not invalidate the element
56  m_position = position;
57 }
58 
60 {
61  return m_position;
62 }
63 
65 { // this does not invalidate the element
66  m_referencePoint = point;
67 }
68 
70 {
71  return m_referencePoint;
72 }
73 
74 PrerenderedLabel::PrerenderedLabel()
76  , m_dirty( true )
77  , m_font( qApp->font() )
78  , m_brush( Qt::black )
79  , m_pen( Qt::black ) // do not use anything invisible
80  , m_angle( 0.0 )
81 {
82 }
83 
84 PrerenderedLabel::~PrerenderedLabel()
85 {
86  DUMP_CACHE_STATS;
87 }
88 
90 {
91  m_dirty = true;
92 }
93 
95 {
96  m_font = font;
97  invalidate();
98 }
99 
101 {
102  return m_font;
103 }
104 
106 {
107  m_text = text;
108  invalidate();
109 }
110 
112 {
113  return m_text;
114 }
115 
116 void PrerenderedLabel::setBrush( const QBrush& brush )
117 {
118  m_brush = brush;
119  invalidate();
120 }
121 
123 {
124  return m_brush;
125 }
126 
127 void PrerenderedLabel::setAngle( qreal angle )
128 {
129  m_angle = angle;
130  invalidate();
131 }
132 
134 {
135  return m_angle;
136 }
137 
139 {
140  if ( m_dirty ) {
141  INC_MISS_COUNT;
142  paint();
143  } else {
144  INC_HIT_COUNT;
145  }
146  return m_pixmap;
147 }
148 
149 void PrerenderedLabel::paint() const
150 {
151  // FIXME find a better value using font metrics of text (this
152  // requires finding the diameter of the circle formed by rotating
153  // the bounding rect around the center):
154  const int Width = 1000;
155  const int Height = Width;
156 
157  QRectF boundingRect;
158  const QColor FullTransparent( 255, 255, 255, 0 );
159 #ifdef Q_WS_X11
160  QImage pixmap( Width, Height, QImage::Format_ARGB32_Premultiplied );
161  qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
162  << "to work around XRender/Qt4 bug.";
163 #else
164  QPixmap pixmap( Width, Height );
165 #endif
166  // pixmap.fill( FullTransparent );
167  {
168  static const QPointF Center ( 0.0, 0.0 );
169  QPointF textBottomRight;
170  QPainter painter( &pixmap );
172  painter.setRenderHint(QPainter::Antialiasing, true );
173 
174  // QImage (X11 workaround) does not have fill():
175  painter.setPen( FullTransparent );
176  painter.setBrush( FullTransparent );
179  painter.drawRect( 0, 0, Width, Height );
180  painter.setCompositionMode( mode );
181 
182  QMatrix matrix;
183  matrix.translate( 0.5 * Width, 0.5 * Height );
184  matrix.rotate( m_angle );
185  painter.setWorldMatrix( matrix );
186 
187  painter.setPen( m_pen );
188  painter.setBrush( m_brush );
189  painter.setFont( m_font );
190  QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
191  painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
192  m_text, &boundingRect );
193  m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
194  textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
195  m_textAscendVector = boundingRect.topRight() - textBottomRight;
196  m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
197 
198  // FIXME translate topright by char height
199  boundingRect = matrix.mapRect( boundingRect );
200  m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
201  - boundingRect.topLeft();
202  textBottomRight = matrix.map( textBottomRight )
203  - boundingRect.topLeft();
204  m_textAscendVector = matrix.map( m_textAscendVector )
205  - matrix.map( Center );
206  m_textBaseLineVector = matrix.map( m_textBaseLineVector )
207  - matrix.map( Center );
208  }
209 
210  m_dirty = false; // now all the calculation vectors are valid
211 
212  QPixmap temp( static_cast<int>( boundingRect.width() ),
213  static_cast<int>( boundingRect.height() ) );
214  {
215  temp.fill( FullTransparent );
216  QPainter painter( &temp );
217 #ifdef Q_WS_X11
218  painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
219 #else
220  painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
221 #endif
222 // #define PRERENDEREDLABEL_DEBUG
223 #ifdef PRERENDEREDLABEL_DEBUG
224  painter.setPen( QPen( Qt::red, 2 ) );
225  painter.setBrush( Qt::red );
226  // paint markers for the reference points
228  positions << KChartEnums::PositionCenter
229  << KChartEnums::PositionNorthWest
230  << KChartEnums::PositionNorth
231  << KChartEnums::PositionNorthEast
232  << KChartEnums::PositionEast
233  << KChartEnums::PositionSouthEast
234  << KChartEnums::PositionSouth
235  << KChartEnums::PositionSouthWest
236  << KChartEnums::PositionWest;
237  Q_FOREACH( KChartEnums::PositionValue position, positions ) { //krazy:exclude=foreach
238  static const double Radius = 0.5;
239  static const double Diameter = 2 * Radius;
240 
241  QPointF point ( referencePointLocation( position ) );
242  painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
243  QSizeF( Diameter, Diameter ) ) );
244  }
245 #endif
246  }
247 
248  m_pixmap = temp;
249 }
250 
252 {
253  return referencePointLocation( referencePoint() );
254 }
255 
257 {
258  if ( m_dirty ) {
259  INC_MISS_COUNT;
260  paint();
261  } else {
262  INC_HIT_COUNT;
263  }
264 
265  switch ( position ) {
266  case KChartEnums::PositionCenter:
267  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
268  case KChartEnums::PositionNorthWest:
269  return m_referenceBottomLeft + m_textAscendVector;
270  case KChartEnums::PositionNorth:
271  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
272  case KChartEnums::PositionNorthEast:
273  return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
274  case KChartEnums::PositionEast:
275  return m_referenceBottomLeft + 0.5 * m_textAscendVector;
276  case KChartEnums::PositionSouthEast:
277  return m_referenceBottomLeft + m_textBaseLineVector;
278  case KChartEnums::PositionSouth:
279  return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
280  case KChartEnums::PositionSouthWest:
281  return m_referenceBottomLeft;
282  case KChartEnums::PositionWest:
283  return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
284 
285  case KChartEnums::PositionUnknown: // intentional fall-through
286  case KChartEnums::PositionFloating: // intentional fall-through
287  return QPointF();
288  }
289 
290  return QPointF();
291 }
const QBrush & brush() const
PositionValue
Numerical values of the static KChart::Position instances, for using a Position::value() with a switc...
Definition: KChartEnums.h:189
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:37
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-2020 The KDE developers.
Generated on Thu Sep 24 2020 22:36:58 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.