mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
392 lines
11 KiB
C++
392 lines
11 KiB
C++
/* -*- C++ -*-
|
|
This file is part of the KDE libraries
|
|
Copyright (C) 2003 Jason Harris <kstars@30doradus.org>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kplotobject.h"
|
|
|
|
#include <QtCore/qalgorithms.h>
|
|
#include <QPainter>
|
|
#include <QPen>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "kplotpoint.h"
|
|
#include "kplotwidget.h"
|
|
|
|
class KPlotObject::Private
|
|
{
|
|
public:
|
|
Private( KPlotObject * qq )
|
|
: q( qq )
|
|
{
|
|
}
|
|
|
|
~Private()
|
|
{
|
|
qDeleteAll( pList );
|
|
}
|
|
|
|
KPlotObject *q;
|
|
|
|
QList<KPlotPoint*> pList;
|
|
PlotTypes type;
|
|
PointStyle pointStyle;
|
|
double size;
|
|
QPen pen, linePen, barPen, labelPen;
|
|
QBrush brush, barBrush;
|
|
};
|
|
|
|
KPlotObject::KPlotObject( const QColor &c, PlotType t, double size, PointStyle ps )
|
|
: d( new Private( this ) )
|
|
{
|
|
//By default, all pens and brushes are set to the given color
|
|
setBrush( c );
|
|
setBarBrush( c );
|
|
setPen( QPen( brush(), 1 ) );
|
|
setLinePen( pen() );
|
|
setBarPen( pen() );
|
|
setLabelPen( pen() );
|
|
|
|
d->type |= t;
|
|
setSize( size );
|
|
setPointStyle( ps );
|
|
}
|
|
|
|
KPlotObject::~KPlotObject()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
KPlotObject::PlotTypes KPlotObject::plotTypes() const
|
|
{
|
|
return d->type;
|
|
}
|
|
|
|
void KPlotObject::setShowPoints( bool b )
|
|
{
|
|
if ( b )
|
|
{
|
|
d->type |= KPlotObject::Points;
|
|
}
|
|
else
|
|
{
|
|
d->type &= ~KPlotObject::Points;
|
|
}
|
|
}
|
|
|
|
void KPlotObject::setShowLines( bool b )
|
|
{
|
|
if ( b )
|
|
{
|
|
d->type |= KPlotObject::Lines;
|
|
}
|
|
else
|
|
{
|
|
d->type &= ~KPlotObject::Lines;
|
|
}
|
|
}
|
|
|
|
void KPlotObject::setShowBars( bool b )
|
|
{
|
|
if ( b )
|
|
{
|
|
d->type |= KPlotObject::Bars;
|
|
}
|
|
else
|
|
{
|
|
d->type &= ~KPlotObject::Bars;
|
|
}
|
|
}
|
|
|
|
double KPlotObject::size() const
|
|
{
|
|
return d->size;
|
|
}
|
|
|
|
void KPlotObject::setSize( double s )
|
|
{
|
|
d->size = s;
|
|
}
|
|
|
|
KPlotObject::PointStyle KPlotObject::pointStyle() const
|
|
{
|
|
return d->pointStyle;
|
|
}
|
|
|
|
void KPlotObject::setPointStyle( PointStyle p )
|
|
{
|
|
d->pointStyle = p;
|
|
}
|
|
|
|
const QPen& KPlotObject::pen() const
|
|
{
|
|
return d->pen;
|
|
}
|
|
|
|
void KPlotObject::setPen( const QPen &p )
|
|
{
|
|
d->pen = p;
|
|
}
|
|
|
|
const QPen& KPlotObject::linePen() const
|
|
{
|
|
return d->linePen;
|
|
}
|
|
|
|
void KPlotObject::setLinePen( const QPen &p )
|
|
{
|
|
d->linePen = p;
|
|
}
|
|
|
|
const QPen& KPlotObject::barPen() const
|
|
{
|
|
return d->barPen;
|
|
}
|
|
|
|
void KPlotObject::setBarPen( const QPen &p )
|
|
{
|
|
d->barPen = p;
|
|
}
|
|
|
|
const QPen& KPlotObject::labelPen() const
|
|
{
|
|
return d->labelPen;
|
|
}
|
|
|
|
void KPlotObject::setLabelPen( const QPen &p )
|
|
{
|
|
d->labelPen = p;
|
|
}
|
|
|
|
const QBrush KPlotObject::brush() const
|
|
{
|
|
return d->brush;
|
|
}
|
|
|
|
void KPlotObject::setBrush( const QBrush &b )
|
|
{
|
|
d->brush = b;
|
|
}
|
|
|
|
const QBrush KPlotObject::barBrush() const
|
|
{
|
|
return d->barBrush;
|
|
}
|
|
|
|
void KPlotObject::setBarBrush( const QBrush &b )
|
|
{
|
|
d->barBrush = b;
|
|
}
|
|
|
|
QList< KPlotPoint* > KPlotObject::points() const
|
|
{
|
|
return d->pList;
|
|
}
|
|
|
|
void KPlotObject::addPoint( const QPointF &p, const QString &label, double barWidth )
|
|
{
|
|
addPoint( new KPlotPoint( p.x(), p.y(), label, barWidth ) );
|
|
}
|
|
|
|
void KPlotObject::addPoint( KPlotPoint *p )
|
|
{
|
|
if ( !p )
|
|
return;
|
|
d->pList.append( p );
|
|
}
|
|
|
|
void KPlotObject::addPoint( double x, double y, const QString &label, double barWidth )
|
|
{
|
|
addPoint( new KPlotPoint( x, y, label, barWidth ) );
|
|
}
|
|
|
|
void KPlotObject::removePoint( int index ) {
|
|
if ( ( index < 0 ) || ( index >= d->pList.count() ) ) {
|
|
kWarning() << "KPlotObject::removePoint(): index " << index << " out of range!";
|
|
return;
|
|
}
|
|
|
|
d->pList.removeAt( index );
|
|
}
|
|
|
|
void KPlotObject::clearPoints()
|
|
{
|
|
qDeleteAll( d->pList );
|
|
d->pList.clear();
|
|
}
|
|
|
|
void KPlotObject::draw( QPainter *painter, KPlotWidget *pw ) {
|
|
//Order of drawing determines z-distance: Bars in the back, then lines,
|
|
//then points, then labels.
|
|
|
|
if ( d->type & Bars ) {
|
|
painter->setPen( barPen() );
|
|
painter->setBrush( barBrush() );
|
|
|
|
double w = 0;
|
|
for ( int i=0; i<d->pList.size(); ++i ) {
|
|
if ( d->pList[i]->barWidth() == 0.0 ) {
|
|
if ( i<d->pList.size()-1 )
|
|
w = d->pList[i+1]->x() - d->pList[i]->x();
|
|
//For the last bin, we'll just keep the previous width
|
|
|
|
} else {
|
|
w = d->pList[i]->barWidth();
|
|
}
|
|
|
|
QPointF pp = d->pList[i]->position();
|
|
QPointF p1( pp.x() - 0.5*w, 0.0 );
|
|
QPointF p2( pp.x() + 0.5*w, pp.y() );
|
|
QPointF sp1 = pw->mapToWidget( p1 );
|
|
QPointF sp2 = pw->mapToWidget( p2 );
|
|
|
|
QRectF barRect = QRectF( sp1.x(), sp1.y(), sp2.x()-sp1.x(), sp2.y()-sp1.y() ).normalized();
|
|
painter->drawRect( barRect );
|
|
pw->maskRect( barRect, 0.25 );
|
|
}
|
|
}
|
|
|
|
//Draw lines:
|
|
if ( d->type & Lines ) {
|
|
painter->setPen( linePen() );
|
|
|
|
QPointF Previous = QPointF(); //Initialize to null
|
|
|
|
foreach ( KPlotPoint *pp, d->pList ) {
|
|
//q is the position of the point in screen pixel coordinates
|
|
QPointF q = pw->mapToWidget( pp->position() );
|
|
|
|
if ( ! Previous.isNull() ) {
|
|
painter->drawLine( Previous, q );
|
|
pw->maskAlongLine( Previous, q );
|
|
}
|
|
|
|
Previous = q;
|
|
}
|
|
}
|
|
|
|
//Draw points:
|
|
if ( d->type & Points ) {
|
|
|
|
foreach( KPlotPoint *pp, d->pList ) {
|
|
//q is the position of the point in screen pixel coordinates
|
|
QPointF q = pw->mapToWidget( pp->position() );
|
|
if ( pw->pixRect().contains( q.toPoint(), false ) ) {
|
|
double x1 = q.x() - size();
|
|
double y1 = q.y() - size();
|
|
QRectF qr = QRectF( x1, y1, 2*size(), 2*size() );
|
|
|
|
//Mask out this rect in the plot for label avoidance
|
|
pw->maskRect( qr, 2.0 );
|
|
|
|
painter->setPen( pen() );
|
|
painter->setBrush( brush() );
|
|
|
|
switch ( pointStyle() ) {
|
|
case Circle:
|
|
painter->drawEllipse( qr );
|
|
break;
|
|
|
|
case Letter:
|
|
painter->drawText( qr, Qt::AlignCenter, pp->label().left(1) );
|
|
break;
|
|
|
|
case Triangle:
|
|
{
|
|
QPolygonF tri;
|
|
tri << QPointF( q.x() - size(), q.y() + size() )
|
|
<< QPointF( q.x(), q.y() - size() )
|
|
<< QPointF( q.x() + size(), q.y() + size() );
|
|
painter->drawPolygon( tri );
|
|
break;
|
|
}
|
|
|
|
case Square:
|
|
painter->drawRect( qr );
|
|
break;
|
|
|
|
case Pentagon:
|
|
{
|
|
QPolygonF pent;
|
|
pent << QPointF( q.x(), q.y() - size() )
|
|
<< QPointF( q.x() + size(), q.y() - 0.309*size() )
|
|
<< QPointF( q.x() + 0.588*size(), q.y() + size() )
|
|
<< QPointF( q.x() - 0.588*size(), q.y() + size() )
|
|
<< QPointF( q.x() - size(), q.y() - 0.309*size() );
|
|
painter->drawPolygon( pent );
|
|
break;
|
|
}
|
|
|
|
case Hexagon:
|
|
{
|
|
QPolygonF hex;
|
|
hex << QPointF( q.x(), q.y() + size() )
|
|
<< QPointF( q.x() + size(), q.y() + 0.5*size() )
|
|
<< QPointF( q.x() + size(), q.y() - 0.5*size() )
|
|
<< QPointF( q.x(), q.y() - size() )
|
|
<< QPointF( q.x() - size(), q.y() + 0.5*size() )
|
|
<< QPointF( q.x() - size(), q.y() - 0.5*size() );
|
|
painter->drawPolygon( hex );
|
|
break;
|
|
}
|
|
|
|
case Asterisk:
|
|
painter->drawLine( q, QPointF( q.x(), q.y() + size() ) );
|
|
painter->drawLine( q, QPointF( q.x() + size(), q.y() + 0.5*size() ) );
|
|
painter->drawLine( q, QPointF( q.x() + size(), q.y() - 0.5*size() ) );
|
|
painter->drawLine( q, QPointF( q.x(), q.y() - size() ) );
|
|
painter->drawLine( q, QPointF( q.x() - size(), q.y() + 0.5*size() ) );
|
|
painter->drawLine( q, QPointF( q.x() - size(), q.y() - 0.5*size() ) );
|
|
break;
|
|
|
|
case Star:
|
|
{
|
|
QPolygonF star;
|
|
star << QPointF( q.x(), q.y() - size() )
|
|
<< QPointF( q.x() + 0.2245*size(), q.y() - 0.309*size() )
|
|
<< QPointF( q.x() + size(), q.y() - 0.309*size() )
|
|
<< QPointF( q.x() + 0.363*size(), q.y() + 0.118*size() )
|
|
<< QPointF( q.x() + 0.588*size(), q.y() + size() )
|
|
<< QPointF( q.x(), q.y() + 0.382*size() )
|
|
<< QPointF( q.x() - 0.588*size(), q.y() + size() )
|
|
<< QPointF( q.x() - 0.363*size(), q.y() + 0.118*size() )
|
|
<< QPointF( q.x() - size(), q.y() - 0.309*size() )
|
|
<< QPointF( q.x() - 0.2245*size(), q.y() - 0.309*size() );
|
|
painter->drawPolygon( star );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Draw labels
|
|
painter->setPen( labelPen() );
|
|
|
|
foreach ( KPlotPoint *pp, d->pList ) {
|
|
QPoint q = pw->mapToWidget( pp->position() ).toPoint();
|
|
if ( pw->pixRect().contains(q, false) && ! pp->label().isEmpty() ) {
|
|
pw->placeLabel( painter, pp );
|
|
}
|
|
}
|
|
|
|
}
|