Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

KDChartTextLabelCache.cpp

Go to the documentation of this file.
00001 #include <cmath>
00002 
00003 #include <QtDebug>
00004 #include <QImage>
00005 #include <QPixmap>
00006 #include <QPainter>
00007 #include <QApplication>
00008 
00009 #include "KDChartTextLabelCache.h"
00010 
00011 #ifndef NDEBUG
00012 int HitCount = 0;
00013 int MissCount = 0;
00014 #define INC_HIT_COUNT { ++HitCount; }
00015 #define INC_MISS_COUNT  { ++MissCount; }
00016 #define DUMP_CACHE_STATS \
00017     if ( HitCount != 0 && MissCount != 0 ) { \
00018         int total = HitCount + MissCount; \
00019         double hitQuote = ( 1.0 * HitCount ) / total; \
00020         qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
00021         << HitCount << "/" << MissCount << "/" << total \
00022                  << "(" << 100 * hitQuote << "% hits)"; \
00023     }
00024 #else
00025 #define INC_HIT_COUNT
00026 #define INC_MISS_COUNT
00027 #define DUMP_CACHE_STATS
00028 #endif
00029 
00030 PrerenderedElement::PrerenderedElement()
00031     : m_referencePoint( KDChartEnums::PositionNorthWest )
00032 {
00033 }
00034 
00035 void PrerenderedElement::setPosition( const QPointF& position )
00036 {   // this does not invalidate the element
00037     m_position = position;
00038 }
00039 
00040 const QPointF& PrerenderedElement::position() const
00041 {
00042     return m_position;
00043 }
00044 
00045 void PrerenderedElement::setReferencePoint( KDChartEnums::PositionValue point )
00046 {   // this does not invalidate the element
00047     m_referencePoint = point;
00048 }
00049 
00050 KDChartEnums::PositionValue PrerenderedElement::referencePoint() const
00051 {
00052     return m_referencePoint;
00053 }
00054 
00055 PrerenderedLabel::PrerenderedLabel()
00056     : PrerenderedElement()
00057     , m_dirty( true )
00058     , m_font( qApp->font() )
00059     , m_brush( Qt::black )
00060     , m_pen( Qt::black ) // do not use anything invisible
00061     , m_angle( 0.0 )
00062 {
00063 }
00064 
00065 PrerenderedLabel::~PrerenderedLabel()
00066 {
00067     DUMP_CACHE_STATS;
00068 }
00069 
00070 void PrerenderedLabel::invalidate() const
00071 {
00072     m_dirty = true;
00073 }
00074 
00075 void PrerenderedLabel::setFont( const QFont& font )
00076 {
00077     m_font = font;
00078     invalidate();
00079 }
00080 
00081 const QFont& PrerenderedLabel::font() const
00082 {
00083     return m_font;
00084 }
00085 
00086 void PrerenderedLabel::setText( const QString& text )
00087 {
00088     m_text = text;
00089     invalidate();
00090 }
00091 
00092 const QString& PrerenderedLabel::text() const
00093 {
00094     return m_text;
00095 }
00096 
00097 void PrerenderedLabel::setBrush( const QBrush& brush )
00098 {
00099     m_brush = brush;
00100     invalidate();
00101 }
00102 
00103 const QBrush& PrerenderedLabel::brush() const
00104 {
00105     return m_brush;
00106 }
00107 
00108 void PrerenderedLabel::setAngle( double angle )
00109 {
00110     m_angle = angle;
00111     invalidate();
00112 }
00113 
00114 double PrerenderedLabel::angle() const
00115 {
00116     return m_angle;
00117 }
00118 
00119 const QPixmap& PrerenderedLabel::pixmap() const
00120 {
00121     if ( m_dirty ) {
00122         INC_MISS_COUNT;
00123         paint();
00124     } else {
00125         INC_HIT_COUNT;
00126     }
00127     return m_pixmap;
00128 }
00129 
00130 void PrerenderedLabel::paint() const
00131 {
00132     // FIXME find a better value using font metrics of text (this
00133     // requires finding the diameter of the circle formed by rotating
00134     // the bounding rect around the center):
00135     const int Width = 1000;
00136     const int Height = Width;
00137 
00138     QRectF boundingRect;
00139     const QColor FullTransparent( 255, 255, 255, 0 );
00140 #ifdef Q_WS_X11
00141     QImage pixmap( Width, Height, QImage::Format_ARGB32_Premultiplied );
00142     qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
00143                << "to work around XRender/Qt4 bug.";
00144 #else
00145     QPixmap pixmap( Width, Height );
00146 #endif
00147     // pixmap.fill( FullTransparent );
00148     {
00149         static const QPointF Center ( 0.0, 0.0 );
00150         QPointF textBottomRight;
00151         QPainter painter( &pixmap );
00152         painter.setRenderHint(QPainter::TextAntialiasing, true );
00153         painter.setRenderHint(QPainter::Antialiasing, true );
00154 
00155         // QImage (X11 workaround) does not have fill():
00156         painter.setPen( FullTransparent );
00157         painter.setBrush( FullTransparent );
00158         painter.drawRect( 0, 0, Width, Height );
00159 
00160         QMatrix matrix;
00161         matrix.translate( 0.5 * Width,  0.5 * Height );
00162         matrix.rotate( m_angle );
00163 #if QT_VERSION > 0x040199
00164         painter.setWorldMatrix( matrix );
00165 #else
00166         painter.setMatrix( matrix );
00167 #endif
00168 
00169         painter.setPen( m_pen );
00170         painter.setBrush( m_brush );
00171         painter.setFont( m_font );
00172         QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
00173         painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
00174                           m_text, &boundingRect );
00175         m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
00176         textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
00177         m_textAscendVector = boundingRect.topRight() - textBottomRight;
00178         m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
00179 
00180         // FIXME translate topright by char height
00181         boundingRect = matrix.mapRect( boundingRect );
00182         m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
00183                                 - boundingRect.topLeft();
00184         textBottomRight = matrix.map( textBottomRight )
00185                           - boundingRect.topLeft();
00186         m_textAscendVector = matrix.map( m_textAscendVector )
00187                              - matrix.map( Center );
00188         m_textBaseLineVector = matrix.map( m_textBaseLineVector )
00189                             - matrix.map( Center );
00190     }
00191 
00192     m_dirty = false; // now all the calculation vectors are valid
00193 
00194     QPixmap temp( static_cast<int>( boundingRect.width() ),
00195                   static_cast<int>( boundingRect.height() ) );
00196     {
00197         temp.fill( FullTransparent );
00198         QPainter painter( &temp );
00199 #ifdef Q_WS_X11
00200         painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00201 #else
00202         painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
00203 #endif
00204 // #define PRERENDEREDLABEL_DEBUG
00205 #ifdef PRERENDEREDLABEL_DEBUG
00206         painter.setPen( QPen( Qt::red, 2 ) );
00207         painter.setBrush( Qt::red );
00208         // paint markers for the reference points
00209         QList<KDChartEnums::PositionValue> positions;
00210         positions << KDChartEnums::PositionCenter
00211                   << KDChartEnums::PositionNorthWest
00212                   << KDChartEnums::PositionNorth
00213                   << KDChartEnums::PositionNorthEast
00214                   << KDChartEnums::PositionEast
00215                   << KDChartEnums::PositionSouthEast
00216                   << KDChartEnums::PositionSouth
00217                   << KDChartEnums::PositionSouthWest
00218                   << KDChartEnums::PositionWest;
00219         Q_FOREACH( KDChartEnums::PositionValue position, positions ) {
00220             static const double Radius = 0.5;
00221             static const double Diameter = 2 * Radius;
00222 
00223             QPointF point ( referencePointLocation( position ) );
00224             painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
00225                                          QSizeF( Diameter, Diameter ) ) );
00226         }
00227 #endif
00228     }
00229 
00230     m_pixmap = temp;
00231 }
00232 
00233 QPointF PrerenderedLabel::referencePointLocation() const
00234 {
00235     return referencePointLocation( referencePoint() );
00236 }
00237 
00238 QPointF PrerenderedLabel::referencePointLocation( KDChartEnums::PositionValue position ) const
00239 {
00240     if ( m_dirty ) {
00241         INC_MISS_COUNT;
00242         paint();
00243     } else {
00244         INC_HIT_COUNT;
00245     }
00246 
00247     switch( position ) {
00248     case KDChartEnums::PositionCenter:
00249         return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
00250     case KDChartEnums::PositionNorthWest:
00251         return m_referenceBottomLeft + m_textAscendVector;
00252     case KDChartEnums::PositionNorth:
00253         return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
00254     case KDChartEnums::PositionNorthEast:
00255         return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
00256     case KDChartEnums::PositionEast:
00257         return m_referenceBottomLeft + 0.5 * m_textAscendVector;
00258     case KDChartEnums::PositionSouthEast:
00259         return m_referenceBottomLeft + m_textBaseLineVector;
00260     case KDChartEnums::PositionSouth:
00261         return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
00262     case KDChartEnums::PositionSouthWest:
00263         return m_referenceBottomLeft;
00264     case KDChartEnums::PositionWest:
00265         return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
00266 
00267     case KDChartEnums::PositionUnknown: // intentional fall-through
00268     case KDChartEnums::PositionFloating: // intentional fall-through
00269     default:
00270         return QPointF();
00271     }
00272 }
00273 

Generated on Thu May 10 11:06:25 2007 for KD Chart 2 by doxygen 1.3.6