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