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
19int HitCount = 0;
20int 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
37PrerenderedElement::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
62PrerenderedLabel::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
72PrerenderedLabel::~PrerenderedLabel()
73{
74 DUMP_CACHE_STATS;
75}
76
78{
79 m_dirty = true;
80}
81
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
105{
106 m_brush = brush;
107 invalidate();
108}
109
111{
112 return m_brush;
113}
114
115void 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
137void 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 : std::as_const(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}
Project global class providing some enums needed both by KChartParams and by KChartCustomBox.
Definition KChartEnums.h:27
PositionValue
Numerical values of the static KChart::Position instances, for using a Position::value() with a switc...
base class for prerendered elements like labels, pixmaps, markers, etc.
void setPosition(const QPointF &position)
Set the position of the element.
void setReferencePoint(KChartEnums::PositionValue)
Set the reference point of the element.
KChartEnums::PositionValue referencePoint() const
Get the reference point of the element.
const QPointF & position() const
Get the position of the element.
void setAngle(qreal angle)
Sets the angle of the label to angle degrees.
const QString & text() const
void setFont(const QFont &font)
Sets the label's font to font.
const QBrush & brush() const
void invalidate() const override
Invalidates the preredendered data, forces re-rendering.
const QFont & font() const
void setBrush(const QBrush &brush)
Sets the label's brush to brush.
const QPixmap & pixmap() const override
Returns the rendered element.
QPointF referencePointLocation(KChartEnums::PositionValue position) const override
Return the location of the reference point relatively to the pixmap's origin.
void setText(const QString &text)
Sets the label's text to text.
Format_ARGB32_Premultiplied
qreal x() const const
QPointF bottomLeft() const const
QPointF bottomRight() const const
qreal height() const const
QPointF topLeft() const const
QPointF topRight() const const
qreal width() const const
AlignHCenter
QLine map(const QLine &l) const const
QRect mapRect(const QRect &rectangle) const const
QTransform & rotate(qreal a, Qt::Axis axis)
QTransform & translate(qreal dx, qreal dy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:02:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.