00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kplotwidget.h"
00022 #include "kplotwidget.moc"
00023
00024 #include <math.h>
00025 #include <kdebug.h>
00026
00027 #include <QtGui/QActionEvent>
00028 #include <QHash>
00029 #include <QPainter>
00030 #include <QPixmap>
00031 #include <QToolTip>
00032 #include <QtAlgorithms>
00033
00034 #include "kplotaxis.h"
00035 #include "kplotpoint.h"
00036 #include "kplotobject.h"
00037
00038 #define XPADDING 20
00039 #define YPADDING 20
00040 #define BIGTICKSIZE 10
00041 #define SMALLTICKSIZE 4
00042 #define TICKOFFSET 0
00043
00044 class KPlotWidget::Private
00045 {
00046 public:
00047 Private( KPlotWidget *qq )
00048 : q( qq ),
00049 cBackground( Qt::black ), cForeground( Qt::white ), cGrid( Qt::gray ),
00050 showGrid( false ), showObjectToolTip( true ), useAntialias( false )
00051 {
00052
00053 KPlotAxis *leftAxis = new KPlotAxis();
00054 leftAxis->setTickLabelsShown( true );
00055 axes.insert( LeftAxis, leftAxis );
00056 KPlotAxis *bottomAxis = new KPlotAxis();
00057 bottomAxis->setTickLabelsShown( true );
00058 axes.insert( BottomAxis, bottomAxis );
00059 KPlotAxis *rightAxis = new KPlotAxis();
00060 axes.insert( RightAxis, rightAxis );
00061 KPlotAxis *topAxis = new KPlotAxis();
00062 axes.insert( TopAxis, topAxis );
00063 }
00064
00065 ~Private()
00066 {
00067 qDeleteAll( objectList );
00068 qDeleteAll( axes );
00069 }
00070
00071 KPlotWidget *q;
00072
00073 void calcDataRectLimits( double x1, double x2, double y1, double y2 );
00082 float rectCost( const QRectF &r ) const;
00083
00084
00085 QColor cBackground, cForeground, cGrid;
00086
00087 bool showGrid : 1;
00088 bool showObjectToolTip : 1;
00089 bool useAntialias : 1;
00090
00091 int leftPadding, rightPadding, topPadding, bottomPadding;
00092
00093 QHash<Axis, KPlotAxis*> axes;
00094
00095 QList<KPlotObject*> objectList;
00096
00097 QRectF dataRect, secondDataRect;
00098
00099 QRect pixRect;
00100
00101 QImage plotMask;
00102 };
00103
00104 KPlotWidget::KPlotWidget( QWidget * parent )
00105 : QFrame( parent ), d( new Private( this ) )
00106 {
00107 setAttribute( Qt::WA_OpaquePaintEvent );
00108 setAttribute( Qt::WA_NoSystemBackground );
00109
00110 d->secondDataRect = QRectF();
00111
00112 d->calcDataRectLimits( 0.0, 1.0, 0.0, 1.0 );
00113
00114 setDefaultPaddings();
00115
00116 setMinimumSize( 150, 150 );
00117 resize( minimumSizeHint() );
00118 }
00119
00120 KPlotWidget::~KPlotWidget()
00121 {
00122 delete d;
00123 }
00124
00125 QSize KPlotWidget::minimumSizeHint() const
00126 {
00127 return QSize( 150, 150 );
00128 }
00129
00130 QSize KPlotWidget::sizeHint() const
00131 {
00132 return size();
00133 }
00134
00135 void KPlotWidget::setLimits( double x1, double x2, double y1, double y2 )
00136 {
00137 d->calcDataRectLimits( x1, x2, y1, y2 );
00138 update();
00139 }
00140
00141 void KPlotWidget::Private::calcDataRectLimits( double x1, double x2, double y1, double y2 )
00142 {
00143 double XA1, XA2, YA1, YA2;
00144 if (x2<x1) { XA1=x2; XA2=x1; }
00145 else { XA1=x1; XA2=x2; }
00146 if ( y2<y1) { YA1=y2; YA2=y1; }
00147 else { YA1=y1; YA2=y2; }
00148
00149 if ( XA2 == XA1 ) {
00150 kWarning() << "x1 and x2 cannot be equal. Setting x2 = x1 + 1.0";
00151 XA2 = XA1 + 1.0;
00152 }
00153 if ( YA2 == YA1 ) {
00154 kWarning() << "y1 and y2 cannot be equal. Setting y2 = y1 + 1.0";
00155 YA2 = YA1 + 1.0;
00156 }
00157 dataRect = QRectF( XA1, YA1, XA2 - XA1, YA2 - YA1 );
00158
00159 q->axis( LeftAxis )->setTickMarks( dataRect.y(), dataRect.height() );
00160 q->axis( BottomAxis )->setTickMarks( dataRect.x(), dataRect.width() );
00161
00162 if ( secondDataRect.isNull() )
00163 {
00164 q->axis( RightAxis )->setTickMarks( dataRect.y(), dataRect.height() );
00165 q->axis( TopAxis )->setTickMarks( dataRect.x(), dataRect.width() );
00166 }
00167 }
00168
00169 void KPlotWidget::setSecondaryLimits( double x1, double x2, double y1, double y2 ) {
00170 double XA1, XA2, YA1, YA2;
00171 if (x2<x1) { XA1=x2; XA2=x1; }
00172 else { XA1=x1; XA2=x2; }
00173 if ( y2<y1) { YA1=y2; YA2=y1; }
00174 else { YA1=y1; YA2=y2; }
00175
00176 if ( XA2 == XA1 ) {
00177 kWarning() << "x1 and x2 cannot be equal. Setting x2 = x1 + 1.0";
00178 XA2 = XA1 + 1.0;
00179 }
00180 if ( YA2 == YA1 ) {
00181 kWarning() << "y1 and y2 cannot be equal. Setting y2 = y1 + 1.0";
00182 YA2 = YA1 + 1.0;
00183 }
00184 d->secondDataRect = QRectF( XA1, YA1, XA2-XA1, YA2-YA1 );
00185
00186 axis(RightAxis)->setTickMarks( d->secondDataRect.y(), d->secondDataRect.height() );
00187 axis(TopAxis)->setTickMarks( d->secondDataRect.x(), d->secondDataRect.width() );
00188
00189 update();
00190 }
00191
00192 void KPlotWidget::clearSecondaryLimits() {
00193 d->secondDataRect = QRectF();
00194 axis(RightAxis)->setTickMarks( d->dataRect.y(), d->dataRect.height() );
00195 axis(TopAxis)->setTickMarks( d->dataRect.x(), d->dataRect.width() );
00196
00197 update();
00198 }
00199
00200 QRectF KPlotWidget::dataRect() const
00201 {
00202 return d->dataRect;
00203 }
00204
00205 QRectF KPlotWidget::secondaryDataRect() const
00206 {
00207 return d->secondDataRect;
00208 }
00209
00210 void KPlotWidget::addPlotObject( KPlotObject *object )
00211 {
00212
00213 if ( !object )
00214 return;
00215 d->objectList.append( object );
00216 update();
00217 }
00218
00219 void KPlotWidget::addPlotObjects( const QList< KPlotObject* >& objects )
00220 {
00221 bool addedsome = false;
00222 foreach ( KPlotObject *o, objects )
00223 {
00224 if ( !o )
00225 continue;
00226
00227 d->objectList.append( o );
00228 addedsome = true;
00229 }
00230 if ( addedsome )
00231 update();
00232 }
00233
00234 QList< KPlotObject* > KPlotWidget::plotObjects() const
00235 {
00236 return d->objectList;
00237 }
00238
00239 void KPlotWidget::removeAllPlotObjects()
00240 {
00241 if ( d->objectList.isEmpty() )
00242 return;
00243
00244 qDeleteAll( d->objectList );
00245 d->objectList.clear();
00246 update();
00247 }
00248
00249 void KPlotWidget::resetPlotMask() {
00250 d->plotMask = QImage( pixRect().size(), QImage::Format_ARGB32 );
00251 QColor fillColor = Qt::black;
00252 fillColor.setAlpha( 128 );
00253 d->plotMask.fill( fillColor.rgb() );
00254 }
00255
00256 void KPlotWidget::resetPlot() {
00257 qDeleteAll( d->objectList );
00258 d->objectList.clear();
00259 clearSecondaryLimits();
00260 d->calcDataRectLimits( 0.0, 1.0, 0.0, 1.0 );
00261 KPlotAxis *a = axis( RightAxis );
00262 a->setLabel( QString() );
00263 a->setTickLabelsShown( false );
00264 a = axis( TopAxis );
00265 a->setLabel( QString() );
00266 a->setTickLabelsShown( false );
00267 axis(KPlotWidget::LeftAxis)->setLabel( QString() );
00268 axis(KPlotWidget::BottomAxis)->setLabel( QString() );
00269 resetPlotMask();
00270 }
00271
00272 void KPlotWidget::replacePlotObject( int i, KPlotObject *o )
00273 {
00274
00275 if ( !o || i < 0 || i >= d->objectList.count() )
00276 return;
00277 d->objectList.replace( i, o );
00278 update();
00279 }
00280
00281 QColor KPlotWidget::backgroundColor() const
00282 {
00283 return d->cBackground;
00284 }
00285
00286 QColor KPlotWidget::foregroundColor() const
00287 {
00288 return d->cForeground;
00289 }
00290
00291 QColor KPlotWidget::gridColor() const
00292 {
00293 return d->cGrid;
00294 }
00295
00296 void KPlotWidget::setBackgroundColor( const QColor &bg ) {
00297 d->cBackground = bg;
00298 update();
00299 }
00300
00301 void KPlotWidget::setForegroundColor( const QColor &fg )
00302 {
00303 d->cForeground = fg;
00304 update();
00305 }
00306
00307 void KPlotWidget::setGridColor( const QColor &gc )
00308 {
00309 d->cGrid = gc;
00310 update();
00311 }
00312
00313 bool KPlotWidget::isGridShown() const
00314 {
00315 return d->showGrid;
00316 }
00317
00318 bool KPlotWidget::isObjectToolTipShown() const
00319 {
00320 return d->showObjectToolTip;
00321 }
00322
00323 bool KPlotWidget::antialiasing() const
00324 {
00325 return d->useAntialias;
00326 }
00327
00328 void KPlotWidget::setAntialiasing( bool b )
00329 {
00330 d->useAntialias = b;
00331 update();
00332 }
00333
00334 void KPlotWidget::setShowGrid( bool show ) {
00335 d->showGrid = show;
00336 update();
00337 }
00338
00339 void KPlotWidget::setObjectToolTipShown( bool show )
00340 {
00341 d->showObjectToolTip = show;
00342 }
00343
00344
00345 KPlotAxis* KPlotWidget::axis( Axis type )
00346 {
00347 QHash<Axis, KPlotAxis*>::Iterator it = d->axes.find( type );
00348 return it != d->axes.end() ? it.value() : 0;
00349 }
00350
00351 const KPlotAxis* KPlotWidget::axis( Axis type ) const
00352 {
00353 QHash<Axis, KPlotAxis*>::ConstIterator it = d->axes.constFind( type );
00354 return it != d->axes.constEnd() ? it.value() : 0;
00355 }
00356
00357 QRect KPlotWidget::pixRect() const
00358 {
00359 return d->pixRect;
00360 }
00361
00362 QList<KPlotPoint*> KPlotWidget::pointsUnderPoint( const QPoint& p ) const {
00363 QList<KPlotPoint*> pts;
00364 foreach ( KPlotObject *po, d->objectList ) {
00365 foreach ( KPlotPoint *pp, po->points() ) {
00366 if ( ( p - mapToWidget( pp->position() ).toPoint() ).manhattanLength() <= 4 )
00367 pts << pp;
00368 }
00369 }
00370
00371 return pts;
00372 }
00373
00374
00375 bool KPlotWidget::event( QEvent* e ) {
00376 if ( e->type() == QEvent::ToolTip ) {
00377 if ( d->showObjectToolTip )
00378 {
00379 QHelpEvent *he = static_cast<QHelpEvent*>( e );
00380 QList<KPlotPoint*> pts = pointsUnderPoint( he->pos() - QPoint( leftPadding(), topPadding() ) - contentsRect().topLeft() );
00381 if ( pts.count() > 0 ) {
00382 QToolTip::showText( he->globalPos(), pts.front()->label(), this );
00383 }
00384 }
00385 e->accept();
00386 return true;
00387 }
00388 else
00389 return QFrame::event( e );
00390 }
00391
00392 void KPlotWidget::resizeEvent( QResizeEvent* e ) {
00393 QFrame::resizeEvent( e );
00394 setPixRect();
00395 resetPlotMask();
00396 }
00397
00398 void KPlotWidget::setPixRect() {
00399 int newWidth = contentsRect().width() - leftPadding() - rightPadding();
00400 int newHeight = contentsRect().height() - topPadding() - bottomPadding();
00401
00402 d->pixRect = QRect( 0, 0, newWidth, newHeight );
00403 }
00404
00405 QPointF KPlotWidget::mapToWidget( const QPointF& p ) const
00406 {
00407 float px = d->pixRect.left() + d->pixRect.width() * ( p.x() - d->dataRect.x() ) / d->dataRect.width();
00408 float py = d->pixRect.top() + d->pixRect.height() * ( d->dataRect.y() + d->dataRect.height() - p.y() ) / d->dataRect.height();
00409 return QPointF( px, py );
00410 }
00411
00412 void KPlotWidget::maskRect( const QRectF& rf, float fvalue ) {
00413 QRect r = rf.toRect().intersected( d->pixRect );
00414 int value = int( fvalue );
00415 QColor newColor;
00416 for ( int ix=r.left(); ix<r.right(); ++ix ) {
00417 for ( int iy=r.top(); iy<r.bottom(); ++iy ) {
00418 newColor = QColor( d->plotMask.pixel(ix,iy) );
00419 newColor.setAlpha( 200 );
00420 newColor.setRed( qMin( newColor.red() + value, 255 ) );
00421 d->plotMask.setPixel( ix, iy, newColor.rgba() );
00422 }
00423 }
00424
00425 }
00426
00427 void KPlotWidget::maskAlongLine( const QPointF &p1, const QPointF &p2, float fvalue ) {
00428 if ( ! d->pixRect.contains( p1.toPoint() ) && ! d->pixRect.contains( p2.toPoint() ) ) {
00429 return;
00430 }
00431
00432 int value = int( fvalue );
00433
00434
00435 double m = (p2.y() - p1.y())/(p2.x() - p1.x());
00436 double y0 = p1.y() - m*p1.x();
00437 QColor newColor;
00438
00439
00440 if ( m > 1.0 || m < -1.0 ) {
00441 int y1 = int( p1.y() );
00442 int y2 = int( p2.y() );
00443 if ( y1 > y2 ) {
00444 y1 = int( p2.y() );
00445 y2 = int( p1.y() );
00446 }
00447
00448 for ( int y=y1; y<=y2; ++y ) {
00449 int x = int( (y - y0)/m );
00450 if ( d->pixRect.contains( x, y ) ) {
00451 newColor = QColor( d->plotMask.pixel(x,y) );
00452 newColor.setAlpha( 100 );
00453 newColor.setRed( qMin( newColor.red() + value, 255 ) );
00454 d->plotMask.setPixel( x, y, newColor.rgba() );
00455 }
00456 }
00457
00458 } else {
00459 int x1 = int( p1.x() );
00460 int x2 = int( p2.x() );
00461 if ( x1 > x2 ) {
00462 x1 = int( p2.x() );
00463 x2 = int( p1.x() );
00464 }
00465
00466 for ( int x=x1; x<=x2; ++x ) {
00467 int y = int( y0 + m*x );
00468 if ( d->pixRect.contains( x, y ) ) {
00469 newColor = QColor( d->plotMask.pixel(x,y) );
00470 newColor.setAlpha( 100 );
00471 newColor.setRed( qMin( newColor.red() + value, 255 ) );
00472 d->plotMask.setPixel( x, y, newColor.rgba() );
00473 }
00474 }
00475 }
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 void KPlotWidget::placeLabel( QPainter *painter, KPlotPoint *pp ) {
00490 int textFlags = Qt::TextSingleLine | Qt::AlignCenter;
00491
00492 QPointF pos = mapToWidget( pp->position() );
00493 if ( ! d->pixRect.contains( pos.toPoint() ) ) return;
00494
00495 QFontMetricsF fm( painter->font(), painter->device() );
00496 QRectF bestRect = fm.boundingRect( QRectF( pos.x(), pos.y(), 1, 1 ), textFlags, pp->label() );
00497 float xStep = 0.5*bestRect.width();
00498 float yStep = 0.5*bestRect.height();
00499 float maxCost = 0.05 * bestRect.width() * bestRect.height();
00500 float bestCost = d->rectCost( bestRect );
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 int iter = 0;
00512 QList<int> TriedPathIndex;
00513 float bestBadCost = 10000;
00514 QRectF bestBadRect;
00515
00516
00517 bool flagStop = false;
00518
00519 while ( bestCost > maxCost ) {
00520
00521
00522 QRectF upRect = bestRect;
00523 upRect.moveTop( upRect.top() + yStep );
00524 float upCost = d->rectCost( upRect );
00525 QRectF downRect = bestRect;
00526 downRect.moveTop( downRect.top() - yStep );
00527 float downCost = d->rectCost( downRect );
00528 QRectF leftRect = bestRect;
00529 leftRect.moveLeft( leftRect.left() - xStep );
00530 float leftCost = d->rectCost( leftRect );
00531 QRectF rightRect = bestRect;
00532 rightRect.moveLeft( rightRect.left() + xStep );
00533 float rightCost = d->rectCost( rightRect );
00534
00535
00536 QList<float> costList;
00537 costList << upCost << downCost << leftCost << rightCost;
00538 int imin = -1;
00539 for ( int i=0; i<costList.size(); ++i ) {
00540 if ( iter == 0 && TriedPathIndex.contains( i ) ) {
00541 continue;
00542 }
00543
00544
00545
00546 if ( iter == 0 && costList[i] >= bestCost ) {
00547 TriedPathIndex.append( i );
00548 continue;
00549 }
00550
00551 if ( costList[i] < bestCost && (imin < 0 || costList[i] < costList[imin]) ) {
00552
00553 imin = i;
00554 }
00555 }
00556
00557
00558 if ( iter == 0 && imin >= 0 ) {
00559 TriedPathIndex.append( imin );
00560 }
00561
00562
00563 switch ( imin ) {
00564 case 0:
00565 bestRect.moveTop( upRect.top() );
00566 bestCost = upCost;
00567 break;
00568 case 1:
00569 bestRect.moveTop( downRect.top() );
00570 bestCost = downCost;
00571 break;
00572 case 2:
00573 bestRect.moveLeft( leftRect.left() );
00574 bestCost = leftCost;
00575 break;
00576 case 3:
00577 bestRect.moveLeft( rightRect.left() );
00578 bestCost = rightCost;
00579 break;
00580 case -1:
00581
00582 if ( bestCost < bestBadCost ) {
00583 bestBadCost = bestCost;
00584 bestBadRect = bestRect;
00585 }
00586
00587
00588
00589 if ( TriedPathIndex.size() == 4 ) {
00590 bestRect = bestBadRect;
00591 flagStop = true;
00592 break;
00593 }
00594
00595
00596 if ( TriedPathIndex.size() < 4 ) {
00597 iter = -1;
00598 bestRect = fm.boundingRect( QRectF( pos.x(), pos.y(), 1, 1 ), textFlags, pp->label() );
00599 bestCost = d->rectCost( bestRect );
00600 }
00601 break;
00602 }
00603
00604
00605
00606
00607 if ( flagStop ) {
00608 break;
00609 }
00610
00611 ++iter;
00612 }
00613
00614 painter->drawText( bestRect, textFlags, pp->label() );
00615
00616
00617 float deltax = pos.x() - bestRect.center().x();
00618 float deltay = pos.y() - bestRect.center().y();
00619 float rbest = sqrt( deltax*deltax + deltay*deltay );
00620 if ( rbest > 20.0 ) {
00621
00622 painter->setBrush( QBrush() );
00623
00624
00625
00626 painter->drawRoundRect( bestRect );
00627
00628
00629
00630 float xline = bestRect.center().x();
00631 if ( bestRect.left() > pos.x() )
00632 xline = bestRect.left();
00633 if ( bestRect.right() < pos.x() )
00634 xline = bestRect.right();
00635
00636 float yline = bestRect.center().y();
00637 if ( bestRect.top() > pos.y() )
00638 yline = bestRect.top();
00639 if ( bestRect.bottom() < pos.y() )
00640 yline = bestRect.bottom();
00641
00642 painter->drawLine( QPointF( xline, yline ), pos );
00643 }
00644
00645
00646 maskRect( bestRect );
00647 }
00648
00649 float KPlotWidget::Private::rectCost( const QRectF &r ) const
00650 {
00651 if ( ! plotMask.rect().contains( r.toRect() ) ) {
00652 return 10000.;
00653 }
00654
00655
00656 QImage subMask = plotMask.copy( r.toRect() );
00657 int cost = 0;
00658 for ( int ix=0; ix<subMask.width(); ++ix ) {
00659 for ( int iy=0; iy<subMask.height(); ++iy ) {
00660 cost += QColor( subMask.pixel( ix, iy ) ).red();
00661 }
00662 }
00663
00664 return float(cost);
00665 }
00666
00667 void KPlotWidget::paintEvent( QPaintEvent *e ) {
00668
00669 QFrame::paintEvent( e );
00670 QPainter p;
00671
00672 p.begin( this );
00673 p.setRenderHint( QPainter::Antialiasing, d->useAntialias );
00674 p.fillRect( rect(), backgroundColor() );
00675 p.translate( leftPadding() + 0.5, topPadding() + 0.5 );
00676
00677 setPixRect();
00678 p.setClipRect( d->pixRect );
00679 p.setClipping( true );
00680
00681 resetPlotMask();
00682
00683 foreach( KPlotObject *po, d->objectList )
00684 po->draw( &p, this );
00685
00686
00687
00688
00689 p.setClipping( false );
00690 drawAxes( &p );
00691
00692 p.end();
00693 }
00694
00695 void KPlotWidget::drawAxes( QPainter *p ) {
00696 if ( d->showGrid ) {
00697 p->setPen( gridColor() );
00698
00699
00700
00701 foreach ( double xx, axis(BottomAxis)->majorTickMarks() ) {
00702 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
00703 p->drawLine( QPointF( px, 0.0 ), QPointF( px, double(d->pixRect.height()) ) );
00704 }
00705
00706 foreach( double yy, axis(LeftAxis)->majorTickMarks() ) {
00707 double py = d->pixRect.height() * (yy - d->dataRect.y()) / d->dataRect.height();
00708 p->drawLine( QPointF( 0.0, py ), QPointF( double(d->pixRect.width()), py ) );
00709 }
00710 }
00711
00712 p->setPen( foregroundColor() );
00713 p->setBrush( Qt::NoBrush );
00714
00715
00716 QFont f = p->font();
00717 int s = f.pointSize();
00718 f.setPointSize( s - 2 );
00719 p->setFont( f );
00720
00721
00722 KPlotAxis *a = axis(BottomAxis);
00723 if (a->isVisible()) {
00724
00725 p->drawLine( 0, d->pixRect.height(), d->pixRect.width(), d->pixRect.height() );
00726
00727
00728 foreach( double xx, a->majorTickMarks() ) {
00729 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
00730 if ( px > 0 && px < d->pixRect.width() ) {
00731 p->drawLine( QPointF( px, double(d->pixRect.height() - TICKOFFSET)),
00732 QPointF( px, double(d->pixRect.height() - BIGTICKSIZE - TICKOFFSET)) );
00733
00734
00735 if ( a->areTickLabelsShown() ) {
00736 QRect r( int(px) - BIGTICKSIZE, d->pixRect.height()+BIGTICKSIZE, 2*BIGTICKSIZE, BIGTICKSIZE );
00737 p->drawText( r, Qt::AlignCenter | Qt::TextDontClip, a->tickLabel( xx ) );
00738 }
00739 }
00740 }
00741
00742
00743 foreach ( double xx, a->minorTickMarks() ) {
00744 double px = d->pixRect.width() * (xx - d->dataRect.x()) / d->dataRect.width();
00745 if ( px > 0 && px < d->pixRect.width() ) {
00746 p->drawLine( QPointF( px, double(d->pixRect.height() - TICKOFFSET)),
00747 QPointF( px, double(d->pixRect.height() - SMALLTICKSIZE -TICKOFFSET)) );
00748 }
00749 }
00750
00751
00752 if ( ! a->label().isEmpty() ) {
00753 QRect r( 0, d->pixRect.height() + 2*YPADDING, d->pixRect.width(), YPADDING );
00754 p->drawText( r, Qt::AlignCenter, a->label() );
00755 }
00756 }
00757
00758
00759 a = axis(LeftAxis);
00760 if (a->isVisible()) {
00761
00762 p->drawLine( 0, 0, 0, d->pixRect.height() );
00763
00764
00765 foreach( double yy, a->majorTickMarks() ) {
00766 double py = d->pixRect.height() * ( 1.0 - (yy - d->dataRect.y()) / d->dataRect.height() );
00767 if ( py > 0 && py < d->pixRect.height() ) {
00768 p->drawLine( QPointF( TICKOFFSET, py ), QPointF( double(TICKOFFSET + BIGTICKSIZE), py ) );
00769
00770
00771 if ( a->areTickLabelsShown() ) {
00772 QRect r( -2*BIGTICKSIZE-SMALLTICKSIZE, int(py)-SMALLTICKSIZE, 2*BIGTICKSIZE, 2*SMALLTICKSIZE );
00773 p->drawText( r, Qt::AlignRight | Qt::AlignVCenter | Qt::TextDontClip, a->tickLabel( yy ) );
00774 }
00775 }
00776 }
00777
00778
00779 foreach ( double yy, a->minorTickMarks() ) {
00780 double py = d->pixRect.height() * ( 1.0 - (yy - d->dataRect.y()) / d->dataRect.height() );
00781 if ( py > 0 && py < d->pixRect.height() ) {
00782 p->drawLine( QPointF( TICKOFFSET, py ), QPointF( double(TICKOFFSET + SMALLTICKSIZE), py ) );
00783 }
00784 }
00785
00786
00787 if ( ! a->label().isEmpty() ) {
00788
00789 p->save();
00790
00791
00792 p->translate( -3*XPADDING, d->pixRect.height() );
00793 p->rotate( -90.0 );
00794
00795 QRect r( 0, 0, d->pixRect.height(), XPADDING );
00796 p->drawText( r, Qt::AlignCenter, a->label() );
00797
00798 p->restore();
00799 }
00800 }
00801
00802
00803 double x0 = d->dataRect.x();
00804 double y0 = d->dataRect.y();
00805 double dw = d->dataRect.width();
00806 double dh = d->dataRect.height();
00807 if ( secondaryDataRect().isValid() ) {
00808 x0 = secondaryDataRect().x();
00809 y0 = secondaryDataRect().y();
00810 dw = secondaryDataRect().width();
00811 dh = secondaryDataRect().height();
00812 }
00813
00814
00815 a = axis(TopAxis);
00816 if (a->isVisible()) {
00817
00818 p->drawLine( 0, 0, d->pixRect.width(), 0 );
00819
00820
00821 foreach( double xx, a->majorTickMarks() ) {
00822 double px = d->pixRect.width() * (xx - x0) / dw;
00823 if ( px > 0 && px < d->pixRect.width() ) {
00824 p->drawLine( QPointF( px, TICKOFFSET ), QPointF( px, double(BIGTICKSIZE + TICKOFFSET)) );
00825
00826
00827 if ( a->areTickLabelsShown() ) {
00828 QRect r( int(px) - BIGTICKSIZE, (int)-1.5*BIGTICKSIZE, 2*BIGTICKSIZE, BIGTICKSIZE );
00829 p->drawText( r, Qt::AlignCenter | Qt::TextDontClip, a->tickLabel( xx ) );
00830 }
00831 }
00832 }
00833
00834
00835 foreach ( double xx, a->minorTickMarks() ) {
00836 double px = d->pixRect.width() * (xx - x0) / dw;
00837 if ( px > 0 && px < d->pixRect.width() ) {
00838 p->drawLine( QPointF( px, TICKOFFSET ), QPointF( px, double(SMALLTICKSIZE + TICKOFFSET)) );
00839 }
00840 }
00841
00842
00843 if ( ! a->label().isEmpty() ) {
00844 QRect r( 0, 0 - 3*YPADDING, d->pixRect.width(), YPADDING );
00845 p->drawText( r, Qt::AlignCenter, a->label() );
00846 }
00847 }
00848
00849
00850 a = axis(RightAxis);
00851 if (a->isVisible()) {
00852
00853 p->drawLine( d->pixRect.width(), 0, d->pixRect.width(), d->pixRect.height() );
00854
00855
00856 foreach( double yy, a->majorTickMarks() ) {
00857 double py = d->pixRect.height() * ( 1.0 - (yy - y0) / dh );
00858 if ( py > 0 && py < d->pixRect.height() ) {
00859 p->drawLine( QPointF( double(d->pixRect.width() - TICKOFFSET), py ),
00860 QPointF( double(d->pixRect.width() - TICKOFFSET - BIGTICKSIZE), py ) );
00861
00862
00863 if ( a->areTickLabelsShown() ) {
00864 QRect r( d->pixRect.width() + SMALLTICKSIZE, int(py)-SMALLTICKSIZE, 2*BIGTICKSIZE, 2*SMALLTICKSIZE );
00865 p->drawText( r, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, a->tickLabel( yy ) );
00866 }
00867 }
00868 }
00869
00870
00871 foreach ( double yy, a->minorTickMarks() ) {
00872 double py = d->pixRect.height() * ( 1.0 - (yy - y0) / dh );
00873 if ( py > 0 && py < d->pixRect.height() ) {
00874 p->drawLine( QPointF( double(d->pixRect.width() - 0.0), py ),
00875 QPointF( double(d->pixRect.width() - 0.0 - SMALLTICKSIZE), py ) );
00876 }
00877 }
00878
00879
00880 if ( ! a->label().isEmpty() ) {
00881
00882 p->save();
00883
00884
00885 p->translate( d->pixRect.width() + 2*XPADDING, d->pixRect.height() );
00886 p->rotate( -90.0 );
00887
00888 QRect r( 0, 0, d->pixRect.height(), XPADDING );
00889 p->drawText( r, Qt::AlignCenter, a->label() );
00890
00891 p->restore();
00892 }
00893 }
00894 }
00895
00896 int KPlotWidget::leftPadding() const
00897 {
00898 if ( d->leftPadding >= 0 )
00899 return d->leftPadding;
00900 const KPlotAxis *a = axis( LeftAxis );
00901 if ( a && a->isVisible() && a->areTickLabelsShown() )
00902 {
00903 return !a->label().isEmpty() ? 3 * XPADDING : 2 * XPADDING;
00904 }
00905 return XPADDING;
00906 }
00907
00908 int KPlotWidget::rightPadding() const
00909 {
00910 if ( d->rightPadding >= 0 )
00911 return d->rightPadding;
00912 const KPlotAxis *a = axis( RightAxis );
00913 if ( a && a->isVisible() && a->areTickLabelsShown() )
00914 {
00915 return !a->label().isEmpty() ? 3 * XPADDING : 2 * XPADDING;
00916 }
00917 return XPADDING;
00918 }
00919
00920 int KPlotWidget::topPadding() const
00921 {
00922 if ( d->topPadding >= 0 )
00923 return d->topPadding;
00924 const KPlotAxis *a = axis( TopAxis );
00925 if ( a && a->isVisible() && a->areTickLabelsShown() )
00926 {
00927 return !a->label().isEmpty() ? 3 * YPADDING : 2 * YPADDING;
00928 }
00929 return YPADDING;
00930 }
00931
00932 int KPlotWidget::bottomPadding() const
00933 {
00934 if ( d->bottomPadding >= 0 )
00935 return d->bottomPadding;
00936 const KPlotAxis *a = axis( BottomAxis );
00937 if ( a && a->isVisible() && a->areTickLabelsShown() )
00938 {
00939 return !a->label().isEmpty() ? 3 * YPADDING : 2 * YPADDING;
00940 }
00941 return YPADDING;
00942 }
00943
00944 void KPlotWidget::setLeftPadding( int padding )
00945 {
00946 d->leftPadding = padding;
00947 }
00948
00949 void KPlotWidget::setRightPadding( int padding )
00950 {
00951 d->rightPadding = padding;
00952 }
00953
00954 void KPlotWidget::setTopPadding( int padding )
00955 {
00956 d->topPadding = padding;
00957 }
00958
00959 void KPlotWidget::setBottomPadding( int padding )
00960 {
00961 d->bottomPadding = padding;
00962 }
00963
00964 void KPlotWidget::setDefaultPaddings()
00965 {
00966 d->leftPadding = -1;
00967 d->rightPadding = -1;
00968 d->topPadding = -1;
00969 d->bottomPadding = -1;
00970 }
00971