//
// Copyright (c) 1994, 1995, 2006 by Mike Romberg ( mike.romberg@noaa.gov )
//
// This file may be distributed under terms of the GPL
//
//
// $Id$
//
#ifdef HAVE_IOSTREAM
#include <iostream>
#else
#include <iostream.h>
#endif
#ifdef HAVE_FSTREAM
#include <fstream>
#else
#include <fstream>
#endif
#include <stdlib.h>
#include "snprintf.h"
#include "general.h"
#include "fieldmeter.h"
#include "xosview.h"
CVSID("$Id$");
CVSID_DOT_H(FIELDMETER_H_CVSID);
FieldMeter::FieldMeter( XOSView *parent, int numfields, const char *title,
const char *legend, int docaptions, int dolegends,
int dousedlegends )
: Meter(parent, title, legend, docaptions, dolegends, dousedlegends){
/* We need to set print_ to something valid -- the meters
* apparently get drawn before the meters have a chance to call
* CheckResources() themselves. */
numWarnings_ = printedZeroTotalMesg_ = 0;
print_ = PERCENT;
used_ = 0;
lastused_ = -1;
fields_ = NULL;
colors_ = NULL;
lastvals_ = NULL;
lastx_ = NULL;
setNumFields(numfields);
}
void
FieldMeter::disableMeter ( )
{
setNumFields(1);
setfieldcolor (0, "gray");
Meter::legend ("Disabled");
// And specify the total of 1.0, so the meter is grayed out.
total_ = 1.0;
fields_[0] = 1.0;
}
FieldMeter::~FieldMeter( void ){
delete[] fields_;
delete[] colors_;
delete[] lastvals_;
delete[] lastx_;
}
void FieldMeter::checkResources( void ){
Meter::checkResources();
usedcolor_ = parent_->allocColor( parent_->getResource( "usedLabelColor") );
}
void FieldMeter::SetUsedFormat ( const char * const fmt ) {
/* Do case-insensitive compares. */
if (!strncasecmp (fmt, "percent", 8))
print_ = PERCENT;
else if (!strncasecmp (fmt, "autoscale", 10))
print_ = AUTOSCALE;
else if (!strncasecmp (fmt, "float", 6))
print_ = FLOAT;
else
{
fprintf (stderr, "Error: could not parse format of '%s'\n", fmt);
fprintf (stderr, " I expected one of 'percent', 'bytes', or 'float'\n");
fprintf (stderr, " (Case-insensitive)\n");
exit(1);
}
}
void FieldMeter::setUsed (float val, float total)
{
if (print_ == FLOAT)
used_ = val;
else if (print_ == PERCENT)
{
if (total != 0.0)
used_ = val / total * 100.0;
else
{
if (!printedZeroTotalMesg_) {
printedZeroTotalMesg_ = 1;
fprintf(stderr, "Warning: %s meter had a zero total "
"field! Would have caused a div-by-zero "
"exception.\n", name());
}
used_ = 0.0;
}
}
else if (print_ == AUTOSCALE)
used_ = val;
else {
fprintf (stderr, "Error in %s: I can't handle a "
"UsedType enum value of %d!\n", name(), print_);
exit(1);
}
}
void FieldMeter::reset( void ){
for ( int i = 0 ; i < numfields_ ; i++ )
lastvals_[i] = lastx_[i] = -1;
}
void FieldMeter::setfieldcolor( int field, const char *color ){
colors_[field] = parent_->allocColor( color );
}
void FieldMeter::setfieldcolor( int field, unsigned long color ) {
colors_[field] = color;
}
void FieldMeter::draw( void ){
/* Draw the outline for the fieldmeter. */
parent_->setForeground( parent_->foreground() );
parent_->drawRectangle( x_ - 1, y_ - 1, width_ + 2, height_ + 2 );
if ( dolegends_ ){
parent_->setForeground( textcolor_ );
int offset;
if ( dousedlegends_ )
offset = parent_->textWidth( "XXXXXXXXX" );
else
offset = parent_->textWidth( "XXXXX" );
parent_->drawString( x_ - offset + 1, y_ + height_, title_ );
if(docaptions_)
drawlegend();
}
drawfields( 1 );
}
void FieldMeter::drawlegend( void ){
char *tmp1, *tmp2, buff[100];
int n, x = x_;
tmp1 = tmp2 = legend_;
for ( int i = 0 ; i < numfields_ ; i++ ){
n = 0;
while ( (*tmp2 != '/') && (*tmp2 != '\0') ){
tmp2++;
n++;
}
tmp2++;
strncpy( buff, tmp1, n );
buff[n] = '\0';
parent_->setStippleN(i%4);
parent_->setForeground( colors_[i] );
parent_->drawString( x, y_ - 5, buff );
x += parent_->textWidth( buff, n );
parent_->setForeground( parent_->foreground() );
if ( i != numfields_ - 1 )
parent_->drawString( x, y_ - 5, "/" );
x += parent_->textWidth( "/", 1 );
tmp1 = tmp2;
}
parent_->setStippleN(0); /* Restore default all-bits stipple. */
}
void FieldMeter::drawused( int manditory ){
if ( !manditory )
if ( (lastused_ == used_) )
return;
parent_->setStippleN(0); /* Use all-bits stipple. */
static const int onechar = parent_->textWidth( "X" );
static int xoffset = parent_->textWidth( "XXXXX" );
char buf[10];
if (print_ == PERCENT){
snprintf( buf, 10, "%d%%", (int)used_ );
}
else if (print_ == AUTOSCALE){
char scale;
float scaled_used;
/* Unfortunately, we have to do our comparisons by 1000s (otherwise
* a value of 1020, which is smaller than 1K, could end up
* being printed as 1020, which is wider than what can fit) */
/* However, we do divide by 1024, so a K really is a K, and not
* 1000. */
/* In addition, we need to compare against 999.5*1000, because
* 999.5, if not rounded up to 1.0 K, will be rounded by the
* %.0f to be 1000, which is too wide. So anything at or above
* 999.5 needs to be bumped up. */
if (used_ >= 999.5*1000*1000*1000*1000*1000*1000)
{scale='E'; scaled_used = used_/1024/1024/1024/1024/1024/1024;}
else if (used_ >= 999.5*1000*1000*1000*1000)
{scale='P'; scaled_used = used_/1024/1024/1024/1024/1024;}
else if (used_ >= 999.5*1000*1000*1000)
{scale='T'; scaled_used = used_/1024/1024/1024/1024;}
else if (used_ >= 999.5*1000*1000)
{scale='G'; scaled_used = used_/1024/1024/1024;}
else if (used_ >= 999.5*1000)
{scale='M'; scaled_used = used_/1024/1024;}
else if (used_ >= 999.5)
{scale='K'; scaled_used = used_/1024;}
else {scale=' '; scaled_used = used_;}
/* For now, we can only print 3 characters, plus the optional
* suffix, without overprinting the legends. Thus, we can
* print 965, or we can print 34, but we can't print 34.7 (the
* decimal point takes up one character). bgrayson */
/* Also check for negative values, and just print "-" for
* them. */
if (scaled_used < 0)
snprintf (buf, 10, "-");
else if (scaled_used == 0.0)
snprintf (buf, 10, "0");
else if (scaled_used < 9.95) // 9.95 or above would get
// rounded to 10.0, which is too wide.
snprintf (buf, 10, "%.1f%c", scaled_used, scale);
/* We don't need to check against 99.5 -- it all gets %.0f. */
/*else if (scaled_used < 99.5)*/
/*snprintf (buf, 10, "%.0f%c", scaled_used, scale);*/
else
snprintf (buf, 10, "%.0f%c", scaled_used, scale);
}
else {
snprintf( buf, 10, "%.1f", used_ );
}
parent_->clear( x_ - xoffset, y_ + height_ - parent_->textHeight(),
xoffset - onechar / 2, parent_->textHeight() + 1 );
parent_->setForeground( usedcolor_ );
parent_->drawString( x_ - (strlen( buf ) + 1 ) * onechar + 2,
y_ + height_, buf );
lastused_ = used_;
}
void FieldMeter::drawfields( int manditory ){
int twidth, x = x_;
if ( total_ == 0 )
return;
for ( int i = 0 ; i < numfields_ ; i++ ){
/* Look for bogus values. */
if (fields_[i] < 0.0) {
/* Only print a warning 5 times per meter, followed by a
* message about no more warnings. */
numWarnings_ ++;
if (numWarnings_ < 5)
fprintf(stderr, "Warning: meter %s had a negative "
"value of %f for field %d\n", name(), fields_[i], i);
if (numWarnings_ == 5)
fprintf(stderr, "Future warnings from the %s meter "
"will not be displayed.\n", name());
}
twidth = (int) ((width_ * (float) fields_[i]) / total_);
// twidth = (int)((fields_[i] * width_) / total_);
if ( (i == numfields_ - 1) && ((x + twidth) != (x_ + width_)) )
twidth = width_ + x_ - x;
if ( manditory || (twidth != lastvals_[i]) || (x != lastx_[i]) ){
parent_->setForeground( colors_[i] );
parent_->setStippleN(i%4);
parent_->drawFilledRectangle( x, y_, twidth, height_ );
parent_->setStippleN(0); /* Restore all-bits stipple. */
lastvals_[i] = twidth;
lastx_[i] = x;
if ( dousedlegends_ )
drawused( manditory );
}
x += twidth;
}
//parent_->flush();
}
void FieldMeter::checkevent( void ){
drawfields();
}
void FieldMeter::setNumFields(int n){
numfields_ = n;
delete[] fields_;
delete[] colors_;
delete[] lastvals_;
delete[] lastx_;
fields_ = new float[numfields_];
colors_ = new unsigned long[numfields_];
lastvals_ = new int[numfields_];
lastx_ = new int[numfields_];
total_ = 0;
for ( int i = 0 ; i < numfields_ ; i++ ){
fields_[i] = 0.0; /* egcs 2.91.66 bug !? don't do this and */
lastvals_[i] = lastx_[i] = 0; /* that in a single statement or it'll */
/* overwrite too much with 0 ... */
/* Thomas Waldmann ( tw@com-ma.de ) */
}
}
bool FieldMeter::checkX(int x, int width) const {
if ((x < x_) || (x + width < x_)
|| (x > x_ + width_) || (x + width > x_ + width_)){
std::cerr << "FieldMeter::checkX() : bad horiz values for meter : "
<< name() << std::endl;
std::cerr <<"value "<<x<<", width "<<width<<", total_ = "<<total_<<std::endl;
for (int i = 0 ; i < numfields_ ; i++)
std::cerr <<"fields_[" <<i <<"] = " <<fields_[i] <<",";
std::cerr <<std::endl;
return false;
}
return true;
}
syntax highlighted by Code2HTML, v. 0.9.1