KDChartTextLabelCache.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "KDChartTextLabelCache.h"
00024
00025 #include <cmath>
00026
00027 #include <QtDebug>
00028 #include <QImage>
00029 #include <QPixmap>
00030 #include <QPainter>
00031 #include <QApplication>
00032
00033 #ifndef NDEBUG
00034 int HitCount = 0;
00035 int MissCount = 0;
00036 #define INC_HIT_COUNT { ++HitCount; }
00037 #define INC_MISS_COUNT { ++MissCount; }
00038 #define DUMP_CACHE_STATS \
00039 if ( HitCount != 0 && MissCount != 0 ) { \
00040 int total = HitCount + MissCount; \
00041 double hitQuote = ( 1.0 * HitCount ) / total; \
00042 qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
00043 << HitCount << "/" << MissCount << "/" << total \
00044 << "(" << 100 * hitQuote << "% hits)"; \
00045 }
00046 #else
00047 #define INC_HIT_COUNT
00048 #define INC_MISS_COUNT
00049 #define DUMP_CACHE_STATS
00050 #endif
00051
00052 PrerenderedElement::PrerenderedElement()
00053 : m_referencePoint( KDChartEnums::PositionNorthWest )
00054 {
00055 }
00056
00057 void PrerenderedElement::setPosition( const QPointF& position )
00058 {
00059 m_position = position;
00060 }
00061
00062 const QPointF& PrerenderedElement::position() const
00063 {
00064 return m_position;
00065 }
00066
00067 void PrerenderedElement::setReferencePoint( KDChartEnums::PositionValue point )
00068 {
00069 m_referencePoint = point;
00070 }
00071
00072 KDChartEnums::PositionValue PrerenderedElement::referencePoint() const
00073 {
00074 return m_referencePoint;
00075 }
00076
00077 PrerenderedLabel::PrerenderedLabel()
00078 : PrerenderedElement()
00079 , m_dirty( true )
00080 , m_font( qApp->font() )
00081 , m_brush( Qt::black )
00082 , m_pen( Qt::black )
00083 , m_angle( 0.0 )
00084 {
00085 }
00086
00087 PrerenderedLabel::~PrerenderedLabel()
00088 {
00089 DUMP_CACHE_STATS;
00090 }
00091
00095 void PrerenderedLabel::invalidate() const
00096 {
00097 m_dirty = true;
00098 }
00099
00103 void PrerenderedLabel::setFont( const QFont& font )
00104 {
00105 m_font = font;
00106 invalidate();
00107 }
00108
00112 const QFont& PrerenderedLabel::font() const
00113 {
00114 return m_font;
00115 }
00116
00120 void PrerenderedLabel::setText( const QString& text )
00121 {
00122 m_text = text;
00123 invalidate();
00124 }
00125
00129 const QString& PrerenderedLabel::text() const
00130 {
00131 return m_text;
00132 }
00133
00137 void PrerenderedLabel::setBrush( const QBrush& brush )
00138 {
00139 m_brush = brush;
00140 invalidate();
00141 }
00142
00146 const QBrush& PrerenderedLabel::brush() const
00147 {
00148 return m_brush;
00149 }
00150
00154 void PrerenderedLabel::setAngle( double angle )
00155 {
00156 m_angle = angle;
00157 invalidate();
00158 }
00159
00163 double PrerenderedLabel::angle() const
00164 {
00165 return m_angle;
00166 }
00167
00168 const QPixmap& PrerenderedLabel::pixmap() const
00169 {
00170 if ( m_dirty ) {
00171 INC_MISS_COUNT;
00172 paint();
00173 } else {
00174 INC_HIT_COUNT;
00175 }
00176 return m_pixmap;
00177 }
00178
00179 void PrerenderedLabel::paint() const
00180 {
00181
00182
00183
00184 const int Width = 1000;
00185 const int Height = Width;
00186
00187 QRectF boundingRect;
00188 const QColor FullTransparent( 255, 255, 255, 0 );
00189 #ifdef Q_WS_X11
00190 QImage pixmap( Width, Height, QImage::Format_ARGB32_Premultiplied );
00191 qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
00192 << "to work around XRender/Qt4 bug.";
00193 #else
00194 QPixmap pixmap( Width, Height );
00195 #endif
00196
00197 {
00198 static const QPointF Center ( 0.0, 0.0 );
00199 QPointF textBottomRight;
00200 QPainter painter( &pixmap );
00201 painter.setRenderHint(QPainter::TextAntialiasing, true );
00202 painter.setRenderHint(QPainter::Antialiasing, true );
00203
00204
00205 painter.setPen( FullTransparent );
00206 painter.setBrush( FullTransparent );
00207 painter.drawRect( 0, 0, Width, Height );
00208
00209 QMatrix matrix;
00210 matrix.translate( 0.5 * Width, 0.5 * Height );
00211 matrix.rotate( m_angle );
00212 #if QT_VERSION > 0x040199
00213 painter.setWorldMatrix( matrix );
00214 #else
00215 painter.setMatrix( matrix );
00216 #endif
00217
00218 painter.setPen( m_pen );
00219 painter.setBrush( m_brush );
00220 painter.setFont( m_font );
00221 QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
00222 painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
00223 m_text, &boundingRect );
00224 m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
00225 textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
00226 m_textAscendVector = boundingRect.topRight() - textBottomRight;
00227 m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
00228
00229
00230 boundingRect = matrix.mapRect( boundingRect );
00231 m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
00232 - boundingRect.topLeft();
00233 textBottomRight = matrix.map( textBottomRight )
00234 - boundingRect.topLeft();
00235 m_textAscendVector = matrix.map( m_textAscendVector )
00236 - matrix.map( Center );
00237 m_textBaseLineVector = matrix.map( m_textBaseLineVector )
00238 - matrix.map( Center );
00239 }
00240
00241 m_dirty = false;
00242
00243 QPixmap temp( static_cast<int>( boundingRect.width() ),
00244 static_cast<int>( boundingRect.height() ) );
00245 {
00246 temp.fill( FullTransparent );
00247 QPainter painter( &temp );
00248 #ifdef Q_WS_X11
00249 painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00250 #else
00251 painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00252 #endif
00253
00254 #ifdef PRERENDEREDLABEL_DEBUG
00255 painter.setPen( QPen( Qt::red, 2 ) );
00256 painter.setBrush( Qt::red );
00257
00258 QList<KDChartEnums::PositionValue> positions;
00259 positions << KDChartEnums::PositionCenter
00260 << KDChartEnums::PositionNorthWest
00261 << KDChartEnums::PositionNorth
00262 << KDChartEnums::PositionNorthEast
00263 << KDChartEnums::PositionEast
00264 << KDChartEnums::PositionSouthEast
00265 << KDChartEnums::PositionSouth
00266 << KDChartEnums::PositionSouthWest
00267 << KDChartEnums::PositionWest;
00268 Q_FOREACH( KDChartEnums::PositionValue position, positions ) {
00269 static const double Radius = 0.5;
00270 static const double Diameter = 2 * Radius;
00271
00272 QPointF point ( referencePointLocation( position ) );
00273 painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
00274 QSizeF( Diameter, Diameter ) ) );
00275 }
00276 #endif
00277 }
00278
00279 m_pixmap = temp;
00280 }
00281
00282 QPointF PrerenderedLabel::referencePointLocation() const
00283 {
00284 return referencePointLocation( referencePoint() );
00285 }
00286
00287 QPointF PrerenderedLabel::referencePointLocation( KDChartEnums::PositionValue position ) const
00288 {
00289 if ( m_dirty ) {
00290 INC_MISS_COUNT;
00291 paint();
00292 } else {
00293 INC_HIT_COUNT;
00294 }
00295
00296 switch( position ) {
00297 case KDChartEnums::PositionCenter:
00298 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
00299 case KDChartEnums::PositionNorthWest:
00300 return m_referenceBottomLeft + m_textAscendVector;
00301 case KDChartEnums::PositionNorth:
00302 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
00303 case KDChartEnums::PositionNorthEast:
00304 return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
00305 case KDChartEnums::PositionEast:
00306 return m_referenceBottomLeft + 0.5 * m_textAscendVector;
00307 case KDChartEnums::PositionSouthEast:
00308 return m_referenceBottomLeft + m_textBaseLineVector;
00309 case KDChartEnums::PositionSouth:
00310 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
00311 case KDChartEnums::PositionSouthWest:
00312 return m_referenceBottomLeft;
00313 case KDChartEnums::PositionWest:
00314 return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
00315
00316 case KDChartEnums::PositionUnknown:
00317 case KDChartEnums::PositionFloating:
00318 default:
00319 return QPointF();
00320 }
00321 }