Add lib/libkdchart

This commit is contained in:
2012-02-11 14:34:29 +01:00
parent 67e00fcaa1
commit 9e1686bd6e
278 changed files with 221 additions and 13 deletions

View File

@@ -0,0 +1,321 @@
/****************************************************************************
** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB. All rights reserved.
**
** This file is part of the KD Chart library.
**
** Licensees holding valid commercial KD Chart licenses may use this file in
** accordance with the KD Chart Commercial License Agreement provided with
** the Software.
**
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 and version 3 as published by the
** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** Contact info@kdab.com if any conditions of this licensing are not
** clear to you.
**
**********************************************************************/
#include "KDChartTextLabelCache.h"
#include <cmath>
#include <QtDebug>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QApplication>
#ifndef NDEBUG
int HitCount = 0;
int MissCount = 0;
#define INC_HIT_COUNT { ++HitCount; }
#define INC_MISS_COUNT { ++MissCount; }
#define DUMP_CACHE_STATS \
if ( HitCount != 0 && MissCount != 0 ) { \
int total = HitCount + MissCount; \
double hitQuote = ( 1.0 * HitCount ) / total; \
qDebug() << "PrerenderedLabel dtor: hits/misses/total:" \
<< HitCount << "/" << MissCount << "/" << total \
<< "(" << 100 * hitQuote << "% hits)"; \
}
#else
#define INC_HIT_COUNT
#define INC_MISS_COUNT
#define DUMP_CACHE_STATS
#endif
PrerenderedElement::PrerenderedElement()
: m_referencePoint( KDChartEnums::PositionNorthWest )
{
}
void PrerenderedElement::setPosition( const QPointF& position )
{ // this does not invalidate the element
m_position = position;
}
const QPointF& PrerenderedElement::position() const
{
return m_position;
}
void PrerenderedElement::setReferencePoint( KDChartEnums::PositionValue point )
{ // this does not invalidate the element
m_referencePoint = point;
}
KDChartEnums::PositionValue PrerenderedElement::referencePoint() const
{
return m_referencePoint;
}
PrerenderedLabel::PrerenderedLabel()
: PrerenderedElement()
, m_dirty( true )
, m_font( qApp->font() )
, m_brush( Qt::black )
, m_pen( Qt::black ) // do not use anything invisible
, m_angle( 0.0 )
{
}
PrerenderedLabel::~PrerenderedLabel()
{
DUMP_CACHE_STATS;
}
/**
* Invalidates the preredendered data, forces re-rendering.
*/
void PrerenderedLabel::invalidate() const
{
m_dirty = true;
}
/**
* Sets the label's font to \a font.
*/
void PrerenderedLabel::setFont( const QFont& font )
{
m_font = font;
invalidate();
}
/**
* @return the label's font.
*/
const QFont& PrerenderedLabel::font() const
{
return m_font;
}
/**
* Sets the label's text to \a text
*/
void PrerenderedLabel::setText( const QString& text )
{
m_text = text;
invalidate();
}
/**
* @return the label's text
*/
const QString& PrerenderedLabel::text() const
{
return m_text;
}
/**
* Sets the label's brush to \a brush
*/
void PrerenderedLabel::setBrush( const QBrush& brush )
{
m_brush = brush;
invalidate();
}
/**
* @return the label's brush
*/
const QBrush& PrerenderedLabel::brush() const
{
return m_brush;
}
/**
* Sets the angle of the label to \a angle degrees
*/
void PrerenderedLabel::setAngle( double angle )
{
m_angle = angle;
invalidate();
}
/**
* @return the label's angle in degrees
*/
double PrerenderedLabel::angle() const
{
return m_angle;
}
const QPixmap& PrerenderedLabel::pixmap() const
{
if ( m_dirty ) {
INC_MISS_COUNT;
paint();
} else {
INC_HIT_COUNT;
}
return m_pixmap;
}
void PrerenderedLabel::paint() const
{
// FIXME find a better value using font metrics of text (this
// requires finding the diameter of the circle formed by rotating
// the bounding rect around the center):
const int Width = 1000;
const int Height = Width;
QRectF boundingRect;
const QColor FullTransparent( 255, 255, 255, 0 );
#ifdef Q_WS_X11
QImage pixmap( Width, Height, QImage::Format_ARGB32_Premultiplied );
qWarning() << "PrerenderedLabel::paint: using QImage for prerendered labels "
<< "to work around XRender/Qt4 bug.";
#else
QPixmap pixmap( Width, Height );
#endif
// pixmap.fill( FullTransparent );
{
static const QPointF Center ( 0.0, 0.0 );
QPointF textBottomRight;
QPainter painter( &pixmap );
painter.setRenderHint(QPainter::TextAntialiasing, true );
painter.setRenderHint(QPainter::Antialiasing, true );
// QImage (X11 workaround) does not have fill():
painter.setPen( FullTransparent );
painter.setBrush( FullTransparent );
painter.drawRect( 0, 0, Width, Height );
QMatrix matrix;
matrix.translate( 0.5 * Width, 0.5 * Height );
matrix.rotate( m_angle );
#if QT_VERSION > 0x040199
painter.setWorldMatrix( matrix );
#else
painter.setMatrix( matrix );
#endif
painter.setPen( m_pen );
painter.setBrush( m_brush );
painter.setFont( m_font );
QRectF container( -0.5 * Width, -0.5 * Height, Width, 0.5 * Height );
painter.drawText( container, Qt::AlignHCenter | Qt::AlignBottom,
m_text, &boundingRect );
m_referenceBottomLeft = QPointF( boundingRect.bottomLeft().x(), 0.0 );
textBottomRight = QPointF( boundingRect.bottomRight().x(), 0.0 );
m_textAscendVector = boundingRect.topRight() - textBottomRight;
m_textBaseLineVector = textBottomRight - m_referenceBottomLeft;
// FIXME translate topright by char height
boundingRect = matrix.mapRect( boundingRect );
m_referenceBottomLeft = matrix.map( m_referenceBottomLeft )
- boundingRect.topLeft();
textBottomRight = matrix.map( textBottomRight )
- boundingRect.topLeft();
m_textAscendVector = matrix.map( m_textAscendVector )
- matrix.map( Center );
m_textBaseLineVector = matrix.map( m_textBaseLineVector )
- matrix.map( Center );
}
m_dirty = false; // now all the calculation vectors are valid
QPixmap temp( static_cast<int>( boundingRect.width() ),
static_cast<int>( boundingRect.height() ) );
{
temp.fill( FullTransparent );
QPainter painter( &temp );
#ifdef Q_WS_X11
painter.drawImage( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
#else
painter.drawPixmap( QPointF( 0.0, 0.0 ), pixmap, boundingRect );
#endif
// #define PRERENDEREDLABEL_DEBUG
#ifdef PRERENDEREDLABEL_DEBUG
painter.setPen( QPen( Qt::red, 2 ) );
painter.setBrush( Qt::red );
// paint markers for the reference points
QList<KDChartEnums::PositionValue> positions;
positions << KDChartEnums::PositionCenter
<< KDChartEnums::PositionNorthWest
<< KDChartEnums::PositionNorth
<< KDChartEnums::PositionNorthEast
<< KDChartEnums::PositionEast
<< KDChartEnums::PositionSouthEast
<< KDChartEnums::PositionSouth
<< KDChartEnums::PositionSouthWest
<< KDChartEnums::PositionWest;
Q_FOREACH( KDChartEnums::PositionValue position, positions ) {
static const double Radius = 0.5;
static const double Diameter = 2 * Radius;
QPointF point ( referencePointLocation( position ) );
painter.drawEllipse( QRectF( point - QPointF( Radius, Radius ),
QSizeF( Diameter, Diameter ) ) );
}
#endif
}
m_pixmap = temp;
}
QPointF PrerenderedLabel::referencePointLocation() const
{
return referencePointLocation( referencePoint() );
}
QPointF PrerenderedLabel::referencePointLocation( KDChartEnums::PositionValue position ) const
{
if ( m_dirty ) {
INC_MISS_COUNT;
paint();
} else {
INC_HIT_COUNT;
}
switch( position ) {
case KDChartEnums::PositionCenter:
return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + 0.5 * m_textAscendVector;
case KDChartEnums::PositionNorthWest:
return m_referenceBottomLeft + m_textAscendVector;
case KDChartEnums::PositionNorth:
return m_referenceBottomLeft + 0.5 * m_textBaseLineVector + m_textAscendVector;
case KDChartEnums::PositionNorthEast:
return m_referenceBottomLeft + m_textBaseLineVector + m_textAscendVector;
case KDChartEnums::PositionEast:
return m_referenceBottomLeft + 0.5 * m_textAscendVector;
case KDChartEnums::PositionSouthEast:
return m_referenceBottomLeft + m_textBaseLineVector;
case KDChartEnums::PositionSouth:
return m_referenceBottomLeft + 0.5 * m_textBaseLineVector;
case KDChartEnums::PositionSouthWest:
return m_referenceBottomLeft;
case KDChartEnums::PositionWest:
return m_referenceBottomLeft + m_textBaseLineVector + 0.5 * m_textAscendVector;
case KDChartEnums::PositionUnknown: // intentional fall-through
case KDChartEnums::PositionFloating: // intentional fall-through
default:
return QPointF();
}
}

View File

@@ -0,0 +1,148 @@
/****************************************************************************
** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB. All rights reserved.
**
** This file is part of the KD Chart library.
**
** Licensees holding valid commercial KD Chart licenses may use this file in
** accordance with the KD Chart Commercial License Agreement provided with
** the Software.
**
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 and version 3 as published by the
** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** Contact info@kdab.com if any conditions of this licensing are not
** clear to you.
**
**********************************************************************/
#ifndef KDCHARTTEXTLABELCACHE_H
#define KDCHARTTEXTLABELCACHE_H
#include <QPixmap>
#include <QFont>
#include <QBrush>
#include <QPen>
#include "KDChartEnums.h"
/**
* @brief base class for prerendered elements like labels, pixmaps, markers, etc.
*/
class PrerenderedElement {
public:
PrerenderedElement();
virtual ~PrerenderedElement() {}
/** Returns the rendered element.
If any of the properties have change, the element will be
regenerated. */
virtual const QPixmap& pixmap() const = 0;
/** Return the location of the reference point relatively to the
pixmap's origin. */
virtual QPointF referencePointLocation( KDChartEnums::PositionValue ) const = 0;
/** Set the position of the element. */
void setPosition( const QPointF& position );
/** Get the position of the element. */
const QPointF& position() const;
/** Set the reference point of the element.
Every element has nine possible reference points (all compass
directions, plus the center.
*/
void setReferencePoint( KDChartEnums::PositionValue );
/** Get the reference point of the element. */
KDChartEnums::PositionValue referencePoint() const;
protected:
/** invalidate() needs to be called if any of the properties that
determine the visual appearance of the prerendered element
change.
It can be called for a const object, as objects may need to
force recalculation of the pixmap.
*/
virtual void invalidate() const = 0;
private:
QPointF m_position;
KDChartEnums::PositionValue m_referencePoint;
};
/**
@brief PrerenderedLabel is an internal KDChart class that simplifies creation
and caching of cached text labels.
It provides referenze points to anchor the text to other
elements. Reference points use the positions defined in
KDChartEnums.
Usage:
<pre>
double angle = 90.0;
CachedLabel label;
label.paint( font, tr("Label"), angle );
</pre>
*/
// FIXME this is merely a prototype
// FIXME caching could be done by a second layer that can be used to,
// e.g., query for a prerendered element by id or name, or by changing
// the pixmap() method to do lazy evaluation.
class PrerenderedLabel : public PrerenderedElement
{
public:
PrerenderedLabel();
~PrerenderedLabel();
void setFont( const QFont& font );
const QFont& font() const;
void setText( const QString& text );
const QString& text() const;
void setBrush( const QBrush& brush );
const QBrush& brush() const;
void setPen( const QPen& );
const QPen& pen() const;
void setAngle( double angle );
double angle() const;
// reimpl PrerenderedElement:
const QPixmap& pixmap() const;
QPointF referencePointLocation( KDChartEnums::PositionValue position ) const;
// overload: return location of referencePoint():
QPointF referencePointLocation() const;
protected:
void invalidate() const;
private:
/** Create a label with the given text and the given rotation
angle. Needs to be const, otherwise the pixmap() method cannot
update when needed. */
void paint() const;
// store the settings (these are used for the painting):
mutable bool m_dirty;
QFont m_font;
QString m_text;
QBrush m_brush;
QPen m_pen;
double m_angle;
// these are valid once the label has been rendered:
mutable QPixmap m_pixmap;
mutable QPointF m_referenceBottomLeft;
mutable QPointF m_textBaseLineVector;
mutable QPointF m_textAscendVector;
};
#endif