You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
706 lines
20 KiB
706 lines
20 KiB
/* |
|
KSysGuard, the KDE System Guard |
|
|
|
Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> |
|
|
|
This program is free software; you can redistribute it and/or |
|
modify it under the terms of version 2 of the GNU General Public |
|
License as published by the Free Software Foundation |
|
|
|
This program 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 General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program; if not, write to the Free Software |
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
|
|
KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. |
|
Please do not commit any changes without consulting me first. Thanks! |
|
|
|
$Id: SignalPlotter.cc,v 1.7 2004/01/04 13:43:48 waba Exp $ |
|
*/ |
|
|
|
#include <math.h> |
|
#include <string.h> |
|
|
|
#include <tqpainter.h> |
|
#include <tqpixmap.h> |
|
|
|
#include <kdebug.h> |
|
#include <kconfig.h> |
|
|
|
#include "signalplotter.h" |
|
|
|
static inline int min( int a, int b ) |
|
{ |
|
return ( a < b ? a : b ); |
|
} |
|
|
|
SignalPlotter::SignalPlotter( TQWidget *parent, const char *name ) |
|
: TQDialog( parent, name ), |
|
mPosInitialized( false ), |
|
mName( name ) |
|
{ |
|
// Auto deletion does not work for pointer to arrays. |
|
mBeamData.setAutoDelete( false ); |
|
|
|
setBackgroundMode( NoBackground ); |
|
|
|
mSamples = 0; |
|
mMinValue = mMaxValue = 0.0; |
|
mUseAutoRange = true; |
|
|
|
mGraphStyle = GRAPH_POLYGON; |
|
|
|
// Anything smaller than this does not make sense. |
|
setMinimumSize( 16, 16 ); |
|
setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, |
|
TQSizePolicy::Expanding, false ) ); |
|
|
|
mShowVerticalLines = true; |
|
mVerticalLinesColor = TQColor( 0x04FB1D ); |
|
mVerticalLinesDistance = 30; |
|
mVerticalLinesScroll = true; |
|
mVerticalLinesOffset = 0; |
|
mHorizontalScale = 1; |
|
|
|
mShowHorizontalLines = true; |
|
mHorizontalLinesColor = TQColor( 0x04FB1D ); |
|
mHorizontalLinesCount = 5; |
|
|
|
mShowLabels = true; |
|
mShowTopBar = false; |
|
mFontSize = 8; |
|
|
|
mBackgroundColor = TQColor( 0x313031 ); |
|
|
|
// Restore window size and position. |
|
TDEConfig* config = new TDEConfig( "knemorc", false ); |
|
if ( config->hasGroup( "Interface_" + mName ) ) |
|
{ |
|
config->setGroup( "Interface_" + mName ); |
|
if ( config->hasKey( "PlotterX" ) && config->hasKey( "PlotterY" ) ) |
|
{ |
|
mPos.setX( config->readNumEntry( "PlotterX" ) ); |
|
mPos.setY( config->readNumEntry( "PlotterY" ) ); |
|
mPosInitialized = true; |
|
} |
|
if ( config->hasKey( "PlotterWidth" ) && config->hasKey( "PlotterHeight" ) ) |
|
resize( config->readNumEntry( "PlotterWidth" ), |
|
config->readNumEntry( "PlotterHeight" ) ); |
|
} |
|
delete config; |
|
} |
|
|
|
SignalPlotter::~SignalPlotter() |
|
{ |
|
for ( double* p = mBeamData.first(); p; p = mBeamData.next() ) |
|
delete [] p; |
|
|
|
// Store window size and position. |
|
TDEConfig* config = new TDEConfig( "knemorc", false ); |
|
if ( config->hasGroup( "Interface_" + mName ) ) |
|
{ |
|
config->setGroup( "Interface_" + mName ); |
|
config->writeEntry( "PlotterX", x() ); |
|
config->writeEntry( "PlotterY", y() ); |
|
config->writeEntry( "PlotterWidth", width() ); |
|
config->writeEntry( "PlotterHeight", height() ); |
|
config->sync(); |
|
} |
|
delete config; |
|
} |
|
|
|
void SignalPlotter::hide() |
|
{ |
|
mPos = pos(); |
|
mPosInitialized = true; |
|
TQDialog::hide(); |
|
} |
|
|
|
void SignalPlotter::show() |
|
{ |
|
TQDialog::show(); |
|
/** |
|
* mPosInitialized should always be true, except when |
|
* starting KNemo for the very first time. |
|
*/ |
|
if ( mPosInitialized ) |
|
move( mPos ); |
|
} |
|
|
|
bool SignalPlotter::addBeam( const TQColor &color ) |
|
{ |
|
double* d = new double[ mSamples ]; |
|
memset( d, 0, sizeof(double) * mSamples ); |
|
mBeamData.append( d ); |
|
mBeamColor.append( color ); |
|
|
|
return true; |
|
} |
|
|
|
void SignalPlotter::addSample( const TQValueList<double>& sampleBuf ) |
|
{ |
|
if ( mBeamData.count() != sampleBuf.count() ) |
|
return; |
|
|
|
double* d; |
|
if ( mUseAutoRange ) { |
|
double sum = 0; |
|
for ( d = mBeamData.first(); d; d = mBeamData.next() ) { |
|
sum += d[ 0 ]; |
|
if ( sum < mMinValue ) |
|
mMinValue = sum; |
|
if ( sum > mMaxValue ) |
|
mMaxValue = sum; |
|
} |
|
} |
|
|
|
/* If the vertical lines are scrolling, increment the offset |
|
* so they move with the data. The vOffset / hScale confusion |
|
* is because v refers toQt::Vertical Lines, and h to the horizontal |
|
* distance between the vertical lines. */ |
|
if ( mVerticalLinesScroll ) { |
|
mVerticalLinesOffset = ( mVerticalLinesOffset + mHorizontalScale) |
|
% mVerticalLinesDistance; |
|
} |
|
|
|
// Shift data buffers one sample down and insert new samples. |
|
TQValueList<double>::ConstIterator s; |
|
for ( d = mBeamData.first(), s = sampleBuf.begin(); d; d = mBeamData.next(), ++s ) { |
|
memmove( d, d + 1, ( mSamples - 1 ) * sizeof( double ) ); |
|
d[ mSamples - 1 ] = *s; |
|
} |
|
|
|
update(); |
|
} |
|
|
|
void SignalPlotter::changeRange( int beam, double min, double max ) |
|
{ |
|
// Only the first beam affects range calculation. |
|
if ( beam > 1 ) |
|
return; |
|
|
|
mMinValue = min; |
|
mMaxValue = max; |
|
} |
|
|
|
TQValueList<TQColor> &SignalPlotter::beamColors() |
|
{ |
|
return mBeamColor; |
|
} |
|
|
|
void SignalPlotter::removeBeam( uint pos ) |
|
{ |
|
mBeamColor.remove( mBeamColor.at( pos ) ); |
|
mBeamData.remove( pos ); |
|
} |
|
|
|
void SignalPlotter::setTitle( const TQString &title ) |
|
{ |
|
mTitle = title; |
|
} |
|
|
|
TQString SignalPlotter::title() const |
|
{ |
|
return mTitle; |
|
} |
|
|
|
void SignalPlotter::setUseAutoRange( bool value ) |
|
{ |
|
mUseAutoRange = value; |
|
} |
|
|
|
bool SignalPlotter::useAutoRange() const |
|
{ |
|
return mUseAutoRange; |
|
} |
|
|
|
void SignalPlotter::setMinValue( double min ) |
|
{ |
|
mMinValue = min; |
|
} |
|
|
|
double SignalPlotter::minValue() const |
|
{ |
|
return ( mUseAutoRange ? 0 : mMinValue ); |
|
} |
|
|
|
void SignalPlotter::setMaxValue( double max ) |
|
{ |
|
mMaxValue = max; |
|
} |
|
|
|
double SignalPlotter::maxValue() const |
|
{ |
|
return ( mUseAutoRange ? 0 : mMaxValue ); |
|
} |
|
|
|
void SignalPlotter::setGraphStyle( uint style ) |
|
{ |
|
mGraphStyle = style; |
|
} |
|
|
|
uint SignalPlotter::graphStyle() const |
|
{ |
|
return mGraphStyle; |
|
} |
|
|
|
void SignalPlotter::setHorizontalScale( uint scale ) |
|
{ |
|
if (scale == mHorizontalScale) |
|
return; |
|
|
|
mHorizontalScale = scale; |
|
if (isVisible()) |
|
updateDataBuffers(); |
|
} |
|
|
|
uint SignalPlotter::horizontalScale() const |
|
{ |
|
return mHorizontalScale; |
|
} |
|
|
|
void SignalPlotter::setShowVerticalLines( bool value ) |
|
{ |
|
mShowVerticalLines = value; |
|
} |
|
|
|
bool SignalPlotter::showVerticalLines() const |
|
{ |
|
return mShowVerticalLines; |
|
} |
|
|
|
void SignalPlotter::setVerticalLinesColor( const TQColor &color ) |
|
{ |
|
mVerticalLinesColor = color; |
|
} |
|
|
|
TQColor SignalPlotter::verticalLinesColor() const |
|
{ |
|
return mVerticalLinesColor; |
|
} |
|
|
|
void SignalPlotter::setVerticalLinesDistance( int distance ) |
|
{ |
|
mVerticalLinesDistance = distance; |
|
} |
|
|
|
int SignalPlotter::verticalLinesDistance() const |
|
{ |
|
return mVerticalLinesDistance; |
|
} |
|
|
|
void SignalPlotter::setVerticalLinesScroll( bool value ) |
|
{ |
|
mVerticalLinesScroll = value; |
|
} |
|
|
|
bool SignalPlotter::verticalLinesScroll() const |
|
{ |
|
return mVerticalLinesScroll; |
|
} |
|
|
|
void SignalPlotter::setShowHorizontalLines( bool value ) |
|
{ |
|
mShowHorizontalLines = value; |
|
} |
|
|
|
bool SignalPlotter::showHorizontalLines() const |
|
{ |
|
return mShowHorizontalLines; |
|
} |
|
|
|
void SignalPlotter::setHorizontalLinesColor( const TQColor &color ) |
|
{ |
|
mHorizontalLinesColor = color; |
|
} |
|
|
|
TQColor SignalPlotter::horizontalLinesColor() const |
|
{ |
|
return mHorizontalLinesColor; |
|
} |
|
|
|
void SignalPlotter::setHorizontalLinesCount( int count ) |
|
{ |
|
mHorizontalLinesCount = count; |
|
} |
|
|
|
int SignalPlotter::horizontalLinesCount() const |
|
{ |
|
return mHorizontalLinesCount; |
|
} |
|
|
|
void SignalPlotter::setShowLabels( bool value ) |
|
{ |
|
mShowLabels = value; |
|
} |
|
|
|
bool SignalPlotter::showLabels() const |
|
{ |
|
return mShowLabels; |
|
} |
|
|
|
void SignalPlotter::setShowTopBar( bool value ) |
|
{ |
|
mShowTopBar = value; |
|
} |
|
|
|
bool SignalPlotter::showTopBar() const |
|
{ |
|
return mShowTopBar; |
|
} |
|
|
|
void SignalPlotter::setFontSize( int size ) |
|
{ |
|
mFontSize = size; |
|
} |
|
|
|
int SignalPlotter::fontSize() const |
|
{ |
|
return mFontSize; |
|
} |
|
|
|
void SignalPlotter::setBackgroundColor( const TQColor &color ) |
|
{ |
|
mBackgroundColor = color; |
|
} |
|
|
|
TQColor SignalPlotter::backgroundColor() const |
|
{ |
|
return mBackgroundColor; |
|
} |
|
|
|
void SignalPlotter::resizeEvent( TQResizeEvent* ) |
|
{ |
|
Q_ASSERT( width() > 2 ); |
|
|
|
updateDataBuffers(); |
|
} |
|
|
|
void SignalPlotter::updateDataBuffers() |
|
{ |
|
/* Since the data buffers for the beams are equal in size to the |
|
* width of the widget minus 2 we have to enlarge or shrink the |
|
* buffers accordingly when a resize occures. To have a nicer |
|
* display we try to keep as much data as possible. Data that is |
|
* lost due to shrinking the buffers cannot be recovered on |
|
* enlarging though. */ |
|
|
|
/* Determine new number of samples first. |
|
* +0.5 to ensure rounding up |
|
* +2 for extra data points so there is |
|
* 1) no wasted space and |
|
* 2) no loss of precision when drawing the first data point. */ |
|
uint newSampleNum = static_cast<uint>( ( ( width() - 2 ) / |
|
mHorizontalScale ) + 2.5 ); |
|
|
|
// overlap between the old and the new buffers. |
|
int overlap = min( mSamples, newSampleNum ); |
|
|
|
for ( uint i = 0; i < mBeamData.count(); ++i ) { |
|
double* nd = new double[ newSampleNum ]; |
|
|
|
// initialize new part of the new buffer |
|
if ( newSampleNum > (uint)overlap ) |
|
memset( nd, 0, sizeof( double ) * ( newSampleNum - overlap ) ); |
|
|
|
// copy overlap from old buffer to new buffer |
|
memcpy( nd + ( newSampleNum - overlap ), mBeamData.at( i ) + |
|
( mSamples - overlap ), overlap * sizeof( double ) ); |
|
|
|
mBeamData.remove( i ); |
|
mBeamData.insert( i, nd ); |
|
} |
|
|
|
mSamples = newSampleNum; |
|
} |
|
|
|
void SignalPlotter::paintEvent( TQPaintEvent* ) |
|
{ |
|
uint w = width(); |
|
uint h = height(); |
|
|
|
/* Do not do repaints when the widget is not yet setup properly. */ |
|
if ( w <= 2 ) |
|
return; |
|
|
|
TQPixmap pm( w, h ); |
|
TQPainter p; |
|
p.begin( TQT_TQPAINTDEVICE(&pm), this ); |
|
|
|
pm.fill( mBackgroundColor ); |
|
/* Draw white line along the bottom and the right side of the |
|
* widget to create a 3D like look. */ |
|
p.setPen( TQColor( colorGroup().light() ) ); |
|
p.drawLine( 0, h - 1, w - 1, h - 1 ); |
|
p.drawLine( w - 1, 0, w - 1, h - 1 ); |
|
|
|
p.setClipRect( 1, 1, w - 2, h - 2 ); |
|
double range = mMaxValue - mMinValue; |
|
|
|
/* If the range is too small we will force it to 1.0 since it |
|
* looks a lot nicer. */ |
|
if ( range < 0.000001 ) |
|
range = 1.0; |
|
|
|
double minValue = mMinValue; |
|
if ( mUseAutoRange ) { |
|
if ( mMinValue != 0.0 ) { |
|
double dim = pow( 10, floor( log10( fabs( mMinValue ) ) ) ) / 2; |
|
if ( mMinValue < 0.0 ) |
|
minValue = dim * floor( mMinValue / dim ); |
|
else |
|
minValue = dim * ceil( mMinValue / dim ); |
|
range = mMaxValue - minValue; |
|
if ( range < 0.000001 ) |
|
range = 1.0; |
|
} |
|
// Massage the range so that the grid shows some nice values. |
|
double step = range / mHorizontalLinesCount; |
|
double dim = pow( 10, floor( log10( step ) ) ) / 2; |
|
range = dim * ceil( step / dim ) * mHorizontalLinesCount; |
|
} |
|
double maxValue = minValue + range; |
|
|
|
int top = 0; |
|
if ( mShowTopBar && h > ( mFontSize + 2 + mHorizontalLinesCount * 10 ) ) { |
|
/* Draw horizontal bar with current sensor values at top of display. */ |
|
p.setPen( mHorizontalLinesColor ); |
|
int x0 = w / 2; |
|
p.setFont( TQFont( p.font().family(), mFontSize ) ); |
|
top = p.fontMetrics().height(); |
|
h -= top; |
|
int h0 = top - 2; |
|
|
|
// JJ 2005-07-18: show numerical in/out values in the top bar ---> |
|
double *d1 = mBeamData.first(); |
|
double UploadSpeed = 0; |
|
if(d1) |
|
UploadSpeed = d1[ w - 3 ]; // read value from graph data |
|
|
|
double *d2 = mBeamData.next(); |
|
double DownloadSpeed = 0; |
|
if(d2) |
|
DownloadSpeed = d2[ w - 3 ]; // read value from graph data |
|
|
|
// The left side of the top bar is now divided into three sections: |
|
// - name of interface (original title) |
|
// - download speed (numerically, from the value shown by the bar on the right) |
|
// - upload speed (numerically, from the value shown by the bar on the right) |
|
|
|
// title |
|
p.drawText(0, 0, x0/3, top - 2, TQt::AlignCenter, mTitle ); |
|
|
|
TQValueList<TQColor>::Iterator col_speeds; |
|
col_speeds = mBeamColor.begin(); |
|
TQColor UploadColor = *(col_speeds++); |
|
TQColor DownloadColor = *(col_speeds); |
|
|
|
// download speed |
|
TQString DownloadSpeedText; |
|
DownloadSpeedText.sprintf("in: %0.2f KB/s", DownloadSpeed); |
|
p.setPen( DownloadColor ); |
|
p.drawText(x0/3, 0, x0/3, top - 2, TQt::AlignCenter, DownloadSpeedText ); |
|
|
|
// upload speed |
|
TQString UploadSpeedText; |
|
UploadSpeedText.sprintf("out: %0.2f KB/s", UploadSpeed); |
|
p.setPen( UploadColor ); |
|
p.drawText(2*x0/3, 0, x0/3, top - 2, TQt::AlignCenter, UploadSpeedText ); |
|
|
|
// restore correct pen color for the separator lines |
|
p.setPen( mHorizontalLinesColor ); |
|
// <--- JJ 2005-07-18 |
|
|
|
p.drawLine( x0 - 1, 1, x0 - 1, h0 ); |
|
p.drawLine( 0, top - 1, w - 2, top - 1 ); |
|
|
|
double bias = -minValue; |
|
double scaleFac = ( w - x0 - 2 ) / range; |
|
TQValueList<TQColor>::Iterator col; |
|
col = mBeamColor.begin(); |
|
for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { |
|
int start = x0 + (int)( bias * scaleFac ); |
|
int end = x0 + (int)( ( bias += d[ w - 3 ] ) * scaleFac ); |
|
/* If the rect is wider than 2 pixels we draw only the last |
|
* pixels with the bright color. The rest is painted with |
|
* a 50% darker color. */ |
|
if ( end - start > 1 ) { |
|
p.setPen( (*col).dark( 150 ) ); |
|
p.setBrush( (*col).dark( 150 ) ); |
|
p.drawRect( start, 1, end - start, h0 ); |
|
p.setPen( *col ); |
|
p.drawLine( end, 1, end, h0 ); |
|
} else if ( start - end > 1 ) { |
|
p.setPen( (*col).dark( 150 ) ); |
|
p.setBrush( (*col).dark( 150 ) ); |
|
p.drawRect( end, 1, start - end, h0 ); |
|
p.setPen( *col ); |
|
p.drawLine( end, 1, end, h0 ); |
|
} else { |
|
p.setPen( *col ); |
|
p.drawLine( start, 1, start, h0 ); |
|
} |
|
} |
|
} |
|
|
|
/* Draw scope-like grid vertical lines */ |
|
if ( mShowVerticalLines && w > 60 ) { |
|
p.setPen( mVerticalLinesColor ); |
|
for ( uint x = mVerticalLinesOffset; x < ( w - 2 ); x += mVerticalLinesDistance ) |
|
p.drawLine( w - x, top, w - x, h + top - 2 ); |
|
} |
|
|
|
/* In autoRange mode we determine the range and plot the values in |
|
* one go. This is more efficiently than running through the |
|
* buffers twice but we do react on recently discarded samples as |
|
* well as new samples one plot too late. So the range is not |
|
* correct if the recently discarded samples are larger or smaller |
|
* than the current extreme values. But we can probably live with |
|
* this. */ |
|
if ( mUseAutoRange ) |
|
mMinValue = mMaxValue = 0.0; |
|
|
|
/* Plot stacked values */ |
|
double scaleFac = ( h - 2 ) / range; |
|
if ( mGraphStyle == GRAPH_ORIGINAL ) { |
|
int xPos = 0; |
|
for ( int i = 0; i < mSamples; i++, xPos += mHorizontalScale ) { |
|
double bias = -minValue; |
|
TQValueList<TQColor>::Iterator col; |
|
col = mBeamColor.begin(); |
|
double sum = 0.0; |
|
for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { |
|
if ( mUseAutoRange ) { |
|
sum += d[ i ]; |
|
if ( sum < mMinValue ) |
|
mMinValue = sum; |
|
if ( sum > mMaxValue ) |
|
mMaxValue = sum; |
|
} |
|
int start = top + h - 2 - (int)( bias * scaleFac ); |
|
int end = top + h - 2 - (int)( ( bias + d[ i ] ) * scaleFac ); |
|
bias += d[ i ]; |
|
/* If the line is longer than 2 pixels we draw only the last |
|
* 2 pixels with the bright color. The rest is painted with |
|
* a 50% darker color. */ |
|
if ( end - start > 2 ) { |
|
p.fillRect( xPos, start, mHorizontalScale, end - start - 1, (*col).dark( 150 ) ); |
|
p.fillRect( xPos, end - 1, mHorizontalScale, 2, *col ); |
|
} else if ( start - end > 2 ) { |
|
p.fillRect( xPos, start, mHorizontalScale, end - start + 1, (*col).dark( 150 ) ); |
|
p.fillRect( xPos, end + 1, mHorizontalScale, 2, *col ); |
|
} else |
|
p.fillRect( xPos, start, mHorizontalScale, end - start, *col ); |
|
|
|
} |
|
} |
|
} else if ( mGraphStyle == GRAPH_POLYGON ) { |
|
int *prevVals = new int[ mBeamData.count() ]; |
|
int hack[ 4 ] = { 0, 0, 0, 0 }; |
|
int x1 = w - ( ( mSamples + 1 ) * mHorizontalScale ); |
|
|
|
for ( int i = 0; i < mSamples; i++ ) { |
|
TQValueList<TQColor>::Iterator col; |
|
col = mBeamColor.begin(); |
|
double sum = 0.0; |
|
int y = top + h - 2; |
|
int oldY = top + h; |
|
int oldPrevY = oldY; |
|
int height = 0; |
|
int j = 0; |
|
int jMax = mBeamData.count() - 1; |
|
x1 += mHorizontalScale; |
|
int x2 = x1 + mHorizontalScale; |
|
|
|
for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col, j++ ) { |
|
if ( mUseAutoRange ) { |
|
sum += d[ i ]; |
|
if ( sum < mMinValue ) |
|
mMinValue = sum; |
|
if ( sum > mMaxValue ) |
|
mMaxValue = sum; |
|
} |
|
height = (int)( ( d[ i ] - minValue ) * scaleFac ); |
|
y -= height; |
|
|
|
/* If the line is longer than 2 pixels we draw only the last |
|
* 2 pixels with the bright color. The rest is painted with |
|
* a 50% darker color. */ |
|
TQPen lastPen = TQPen( p.pen() ); |
|
p.setPen( (*col).dark( 150 ) ); |
|
p.setBrush( (*col).dark( 150 ) ); |
|
TQPointArray pa( 4 ); |
|
int prevY = ( i == 0 ) ? y : prevVals[ j ]; |
|
pa.putPoints( 0, 1, x1, prevY ); |
|
pa.putPoints( 1, 1, x2, y ); |
|
pa.putPoints( 2, 1, x2, oldY ); |
|
pa.putPoints( 3, 1, x1, oldPrevY ); |
|
p.drawPolygon( pa ); |
|
p.setPen( lastPen ); |
|
if ( jMax == 0 ) { |
|
// draw as normal, no deferred drawing req'd. |
|
p.setPen( *col ); |
|
p.drawLine( x1, prevY, x2, y ); |
|
} else if ( j == jMax ) { |
|
// draw previous values and current values |
|
p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); |
|
p.setPen( *col ); |
|
p.drawLine( x1, prevY, x2, y ); |
|
} else if ( j == 0 ) { |
|
// save values only |
|
hack[ 0 ] = x1; |
|
hack[ 1 ] = prevY; |
|
hack[ 2 ] = x2; |
|
hack[ 3 ] = y; |
|
p.setPen( *col ); |
|
} else { |
|
p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); |
|
hack[ 0 ] = x1; |
|
hack[ 1 ] = prevY; |
|
hack[ 2 ] = x2; |
|
hack[ 3 ] = y; |
|
p.setPen( *col ); |
|
} |
|
|
|
prevVals[ j ] = y; |
|
oldY = y; |
|
oldPrevY = prevY; |
|
} |
|
} |
|
|
|
delete[] prevVals; |
|
} |
|
|
|
/* Draw horizontal lines and values. Lines are drawn when the |
|
* height is greater than 10 times hCount + 1, values are shown |
|
* when width is greater than 60 */ |
|
if ( mShowHorizontalLines && h > ( 10 * ( mHorizontalLinesCount + 1 ) ) ) { |
|
p.setPen( mHorizontalLinesColor ); |
|
p.setFont( TQFont( p.font().family(), mFontSize ) ); |
|
TQString val; |
|
for ( uint y = 1; y < mHorizontalLinesCount; y++ ) { |
|
p.drawLine( 0, top + y * ( h / mHorizontalLinesCount ), w - 2, |
|
top + y * ( h / mHorizontalLinesCount ) ); |
|
if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) |
|
&& w > 60 ) { |
|
val = TQString( "%1" ).arg( maxValue - y * ( range / mHorizontalLinesCount ) ); |
|
p.drawText( 6, top + y * ( h / mHorizontalLinesCount ) - 1, val ); |
|
} |
|
} |
|
|
|
if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) |
|
&& w > 60 ) { |
|
val = TQString( "%1" ).arg( minValue ); |
|
p.drawText( 6, top + h - 2, val ); |
|
} |
|
} |
|
|
|
p.end(); |
|
bitBlt( this, 0, 0, &pm ); |
|
} |
|
|
|
#include "signalplotter.moc"
|
|
|