From ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeedu@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- libkdeedu/kdeeduplot/kplotwidget.cpp | 405 +++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 libkdeedu/kdeeduplot/kplotwidget.cpp (limited to 'libkdeedu/kdeeduplot/kplotwidget.cpp') diff --git a/libkdeedu/kdeeduplot/kplotwidget.cpp b/libkdeedu/kdeeduplot/kplotwidget.cpp new file mode 100644 index 00000000..e2103509 --- /dev/null +++ b/libkdeedu/kdeeduplot/kplotwidget.cpp @@ -0,0 +1,405 @@ +/*************************************************************************** + kplotwidget.cpp - A widget for plotting in KStars + ------------------- + begin : Sun 18 May 2003 + copyright : (C) 2003 by Jason Harris + email : kstars@30doradus.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include //for log10(), pow(), modf() +#include +#include +#include + +#include "kplotwidget.h" +#include "kplotwidget.moc" + +KPlotWidget::KPlotWidget( double x1, double x2, double y1, double y2, QWidget *parent, const char* name ) + : QWidget( parent, name, WNoAutoErase ), + dXtick(0.0), dYtick(0.0), + nmajX(0), nminX(0), nmajY(0), nminY(0), + ShowTickMarks( true ), ShowTickLabels( true ), ShowGrid( false ) + { + setBackgroundMode( QWidget::NoBackground ); + + //set DataRect + setLimits( x1, x2, y1, y2 ); + setDefaultPadding(); + + //Set PixRect (starts at (0,0) because we will translate by leftPadding(), topPadding() ) + PixRect = QRect( 0, 0, width() - leftPadding() - rightPadding(), + height() - topPadding() - bottomPadding() ); + + buffer = new QPixmap(); + + //default colors: + setBGColor( QColor( "black" ) ); + setFGColor( QColor( "white" ) ); + setGridColor( QColor( "grey" ) ); + + ObjectList.setAutoDelete( true ); +} + +KPlotWidget::~KPlotWidget() +{ + delete (buffer); +} + +void KPlotWidget::setLimits( double x1, double x2, double y1, double y2 ) { + double XA1, XA2, YA1, YA2; + if (x2resize( width(), height() ); +} + +void KPlotWidget::paintEvent( QPaintEvent* /* e */ ) { + QPainter p; + + p.begin( buffer ); + p.fillRect( 0, 0, width(), height(), bgColor() ); + p.translate( leftPadding(), topPadding() ); + + drawObjects( &p ); + drawBox( &p ); + + p.end(); + bitBlt( this, 0, 0, buffer ); +} + +void KPlotWidget::drawObjects( QPainter *p ) { + for ( KPlotObject *po = ObjectList.first(); po; po = ObjectList.next() ) { + + if ( po->points()->count() ) { + //draw the plot object + p->setPen( QColor( po->color() ) ); + + switch ( po->type() ) { + case KPlotObject::POINTS : + { + p->setBrush( QColor( po->color() ) ); + + for ( DPoint *dp = po->points()->first(); dp; dp = po->points()->next() ) { + QPoint q = dp->qpoint( PixRect, DataRect ); + int x1 = q.x() - po->size()/2; + int y1 = q.y() - po->size()/2; + + switch( po->param() ) { + case KPlotObject::CIRCLE : p->drawEllipse( x1, y1, po->size(), po->size() ); break; + case KPlotObject::SQUARE : p->drawRect( x1, y1, po->size(), po->size() ); break; + case KPlotObject::LETTER : p->drawText( q, po->name().left(1) ); break; + default: p->drawPoint( q ); + } + } + + p->setBrush( Qt::NoBrush ); + break; + } + + case KPlotObject::CURVE : + { + p->setPen( QPen( QColor( po->color() ), po->size(), (QPen::PenStyle)po->param() ) ); + DPoint *dp = po->points()->first(); + p->moveTo( dp->qpoint( PixRect, DataRect ) ); + for ( dp = po->points()->next(); dp; dp = po->points()->next() ) + p->lineTo( dp->qpoint( PixRect, DataRect ) ); + break; + } + + case KPlotObject::LABEL : //draw label centered at point in x, and slightly below point in y. + { + QPoint q = po->points()->first()->qpoint( PixRect, DataRect ); + p->drawText( q.x()-20, q.y()+6, 40, 10, Qt::AlignCenter | Qt::DontClip, po->name() ); + break; + } + + case KPlotObject::POLYGON : + { + p->setPen( QPen( QColor( po->color() ), po->size(), (QPen::PenStyle)po->param() ) ); + p->setBrush( po->color() ); + + QPointArray a( po->count() ); + + unsigned int i=0; + for ( DPoint *dp = po->points()->first(); dp; dp = po->points()->next() ) + a.setPoint( i++, dp->qpoint( PixRect, DataRect ) ); + + p->drawPolygon( a ); + break; + } + + case KPlotObject::UNKNOWN_TYPE : break; + } + } + } +} + +double KPlotWidget::dmod( double a, double b ) { return ( b * ( ( a / b ) - int( a / b ) ) ); } + +void KPlotWidget::drawBox( QPainter *p ) { + //First, fill in padding region with bgColor() to mask out-of-bounds plot data + p->setPen( bgColor() ); + p->setBrush( bgColor() ); + + //left padding ( don't forget: we have translated by XPADDING, YPADDING ) + p->drawRect( -leftPadding(), -topPadding(), leftPadding(), height() ); + + //right padding + p->drawRect( PixRect.width(), -topPadding(), rightPadding(), height() ); + + //top padding + p->drawRect( 0, -topPadding(), PixRect.width(), topPadding() ); + + //bottom padding + p->drawRect( 0, PixRect.height(), PixRect.width(), bottomPadding() ); + + if ( ShowGrid ) { + //Grid lines are placed at locations of primary axes' major tickmarks + p->setPen( gridColor() ); + + //vertical grid lines + double x0 = x() - dmod( x(), dXtick ); //zeropoint; x(i) is this plus i*dXtick1 + for ( int ix = 0; ix <= nmajX+1; ix++ ) { + int px = int( PixRect.width() * ( (x0 + ix*dXtick - x())/dataWidth() ) ); + p->drawLine( px, 0, px, PixRect.height() ); + } + + //horizontal grid lines + double y0 = y() - dmod( y(), dYtick ); //zeropoint; y(i) is this plus i*mX + for ( int iy = 0; iy <= nmajY+1; iy++ ) { + int py = PixRect.height() - int( PixRect.height() * ( (y0 + iy*dYtick - y())/dataHeight() ) ); + p->drawLine( 0, py, PixRect.width(), py ); + } + } + + p->setPen( fgColor() ); + p->setBrush( Qt::NoBrush ); + + if (BottomAxis.isVisible() || LeftAxis.isVisible()) p->drawRect( PixRect ); //box outline + + if ( ShowTickMarks ) { + //spacing between minor tickmarks (in data units) + double dminX = dXtick/nminX; + double dminY = dYtick/nminY; + + //set small font for tick labels + QFont f = p->font(); + int s = f.pointSize(); + f.setPointSize( s - 2 ); + p->setFont( f ); + + //--- Draw bottom X Axis ---// + if (BottomAxis.isVisible()) { + // Draw X tickmarks + double x0 = x() - dmod( x(), dXtick ); //zeropoint; tickmark i is this plus i*dXtick (in data units) + if ( x() < 0.0 ) x0 -= dXtick; + + for ( int ix = 0; ix <= nmajX+1; ix++ ) { + //position of tickmark i (in screen units) + int px = int( PixRect.width() * ( (x0 + ix*dXtick - x() )/dataWidth() ) ); + + if ( px > 0 && px < PixRect.width() ) { + p->drawLine( px, PixRect.height() - 2, px, PixRect.height() - BIGTICKSIZE - 2 ); + p->drawLine( px, 0, px, BIGTICKSIZE ); + } + + //tick label + if ( ShowTickLabels ) { + double lab = x0 + ix*dXtick; + if ( fabs(lab)/dXtick < 0.00001 ) lab = 0.0; //fix occassional roundoff error with "0.0" label + + QString str = QString( "%1" ).arg( lab, BottomAxis.labelFieldWidth(), BottomAxis.labelFmt(), BottomAxis.labelPrec() ); + if ( px > 0 && px < PixRect.width() ) { + QRect r( px - BIGTICKSIZE, PixRect.height()+BIGTICKSIZE, 2*BIGTICKSIZE, BIGTICKSIZE ); + p->drawText( r, Qt::AlignCenter | Qt::DontClip, str ); + } + } + + //draw minor ticks + for ( int j=0; j < nminX; j++ ) { + //position of minor tickmark j (in screen units) + int pmin = int( px + PixRect.width()*j*dminX/dataWidth() ); + + if ( pmin > 0 && pmin < PixRect.width() ) { + p->drawLine( pmin, PixRect.height() - 2, pmin, PixRect.height() - SMALLTICKSIZE - 2 ); + p->drawLine( pmin, 0, pmin, SMALLTICKSIZE ); + } + } + } // end draw X tickmarks + + // Draw X Axis Label + if ( ! BottomAxis.label().isEmpty() ) { + QRect r( 0, PixRect.height() + 2*YPADDING, PixRect.width(), YPADDING ); + p->drawText( r, Qt::AlignCenter, BottomAxis.label() ); + } + + } + + //--- Draw left Y Axis ---// + if (LeftAxis.isVisible()) { + // Draw Y tickmarks + double y0 = y() - dmod( y(), dYtick ); //zeropoint; tickmark i is this plus i*dYtick1 (in data units) + if ( y() < 0.0 ) y0 -= dYtick; + + for ( int iy = 0; iy <= nmajY+1; iy++ ) { + //position of tickmark i (in screen units) + int py = PixRect.height() - int( PixRect.height() * ( (y0 + iy*dYtick - y())/dataHeight() ) ); + if ( py > 0 && py < PixRect.height() ) { + p->drawLine( 0, py, BIGTICKSIZE, py ); + p->drawLine( PixRect.width()-2, py, PixRect.width()-BIGTICKSIZE-2, py ); + } + + //tick label + if ( ShowTickLabels ) { + double lab = y0 + iy*dYtick; + if ( fabs(lab)/dYtick < 0.00001 ) lab = 0.0; //fix occassional roundoff error with "0.0" label + + QString str = QString( "%1" ).arg( lab, LeftAxis.labelFieldWidth(), LeftAxis.labelFmt(), LeftAxis.labelPrec() ); + if ( py > 0 && py < PixRect.height() ) { + QRect r( -2*BIGTICKSIZE, py-SMALLTICKSIZE, 2*BIGTICKSIZE, 2*SMALLTICKSIZE ); + p->drawText( r, Qt::AlignCenter | Qt::DontClip, str ); + } + } + + //minor ticks + for ( int j=0; j < nminY; j++ ) { + //position of minor tickmark j (in screen units) + int pmin = int( py - PixRect.height()*j*dminY/dataHeight() ); + if ( pmin > 0 && pmin < PixRect.height() ) { + p->drawLine( 0, pmin, SMALLTICKSIZE, pmin ); + p->drawLine( PixRect.width()-2, pmin, PixRect.width()-SMALLTICKSIZE-2, pmin ); + } + } + } // end draw Y tickmarks + + //Draw Y Axis Label. We need to draw the text sideways. + if ( ! LeftAxis.label().isEmpty() ) { + //store current painter translation/rotation state + p->save(); + + //translate coord sys to left corner of axis label rectangle, then rotate 90 degrees. + p->translate( -3*XPADDING, PixRect.height() ); + p->rotate( -90.0 ); + + QRect r( 0, 0, PixRect.height(), XPADDING ); + p->drawText( r, Qt::AlignCenter, LeftAxis.label() ); //draw the label, now that we are sideways + + p->restore(); //restore translation/rotation state + } + } + + } //end if ( ShowTickMarks ) + + +} + +int KPlotWidget::leftPadding() const { + if ( LeftPadding >= 0 ) return LeftPadding; + if ( ! LeftAxis.label().isEmpty() && ShowTickLabels ) return 3*XPADDING; + if ( ! LeftAxis.label().isEmpty() || ShowTickLabels ) return 2*XPADDING; + return XPADDING; +} + +int KPlotWidget::rightPadding() const { + if ( RightPadding >= 0 ) return RightPadding; + return XPADDING; +} + +int KPlotWidget::topPadding() const { + if ( TopPadding >= 0 ) return TopPadding; + return YPADDING; +} + +int KPlotWidget::bottomPadding() const { + if ( BottomPadding >= 0 ) return BottomPadding; + if ( ! BottomAxis.label().isEmpty() && ShowTickLabels ) return 3*YPADDING; + if ( ! BottomAxis.label().isEmpty() || ShowTickLabels ) return 2*YPADDING; + return YPADDING; +} + -- cgit v1.2.3