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 QPainter::CompositionMode mode = painter.compositionMode();
00208 painter.setCompositionMode( QPainter::CompositionMode_Clear );
00209 painter.drawRect( 0, 0, Width, Height );
00210 painter.setCompositionMode( mode );
00211
00212 QMatrix matrix;
00213 matrix.translate( 0.5 * Width, 0.5 * Height );
00214 matrix.rotate( m_angle );
00215 #if QT_VERSION > 0x040199
00216 painter.setWorldMatrix( matrix );
00217 #else
00218 painter.setMatrix( matrix );
00219 #endif
00220
00221 painter.setPen( m_pen );
00222 painter.setBrush( m_brush );
00223 painter.setFont( m_font );
00224 QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
00225 painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
00226 m_text, &boundingRect );
00227 m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
00228 textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
00229 m_textAscendVector = boundingRect.topRight() - textBottomRight;
00230 m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
00231
00232
00233 boundingRect = matrix.mapRect( boundingRect );
00234 m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
00235 - boundingRect.topLeft();
00236 textBottomRight = matrix.map( textBottomRight )
00237 - boundingRect.topLeft();
00238 m_textAscendVector = matrix.map( m_textAscendVector )
00239 - matrix.map( Center );
00240 m_textBaseLineVector = matrix.map( m_textBaseLineVector )
00241 - matrix.map( Center );
00242 }
00243
00244 m_dirty = false;
00245
00246 QPixmap temp( static_cast<int>( boundingRect.width() ),
00247 static_cast<int>( boundingRect.height() ) );
00248 {
00249 temp.fill( FullTransparent );
00250 QPainter painter( &temp );
00251 #ifdef Q_WS_X11
00252 painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00253 #else
00254 painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00255 #endif
00256
00257 #ifdef PRERENDEREDLABEL_DEBUG
00258 painter.setPen( QPen( Qt::red, 2 ) );
00259 painter.setBrush( Qt::red );
00260
00261 QList<KDChartEnums::PositionValue> positions;
00262 positions << KDChartEnums::PositionCenter
00263 << KDChartEnums::PositionNorthWest
00264 << KDChartEnums::PositionNorth
00265 << KDChartEnums::PositionNorthEast
00266 << KDChartEnums::PositionEast
00267 << KDChartEnums::PositionSouthEast
00268 << KDChartEnums::PositionSouth
00269 << KDChartEnums::PositionSouthWest
00270 << KDChartEnums::PositionWest;
00271 Q_FOREACH( KDChartEnums::PositionValue position, positions ) {
00272 static const double Radius = 0.5;
00273 static const double Diameter = 2 * Radius;
00274
00275 QPointF point ( referencePointLocation( position ) );
00276 painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
00277 QSizeF( Diameter, Diameter ) ) );
00278 }
00279 #endif
00280 }
00281
00282 m_pixmap = temp;
00283 }
00284
00285 QPointF PrerenderedLabel::referencePointLocation() const
00286 {
00287 return referencePointLocation( referencePoint() );
00288 }
00289
00290 QPointF PrerenderedLabel::referencePointLocation( KDChartEnums::PositionValue position ) const
00291 {
00292 if ( m_dirty ) {
00293 INC_MISS_COUNT;
00294 paint();
00295 } else {
00296 INC_HIT_COUNT;
00297 }
00298
00299 switch( position ) {
00300 case KDChartEnums::PositionCenter:
00301 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
00302 case KDChartEnums::PositionNorthWest:
00303 return m_referenceBottomLeft + m_textAscendVector;
00304 case KDChartEnums::PositionNorth:
00305 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
00306 case KDChartEnums::PositionNorthEast:
00307 return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
00308 case KDChartEnums::PositionEast:
00309 return m_referenceBottomLeft + 0.5 * m_textAscendVector;
00310 case KDChartEnums::PositionSouthEast:
00311 return m_referenceBottomLeft + m_textBaseLineVector;
00312 case KDChartEnums::PositionSouth:
00313 return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
00314 case KDChartEnums::PositionSouthWest:
00315 return m_referenceBottomLeft;
00316 case KDChartEnums::PositionWest:
00317 return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
00318
00319 case KDChartEnums::PositionUnknown:
00320 case KDChartEnums::PositionFloating:
00321 default:
00322 return QPointF();
00323 }
00324 }