2
// Copyright (c) 1999, 2006 Thomas Waldmann ( ThomasWaldmann@gmx.de )
3
// based on work of Mike Romberg ( mike.romberg@noaa.gov )
5
// This file may be distributed under terms of the GPL
16
#include "bitfieldmeter.h"
20
BitFieldMeter::BitFieldMeter( XOSView *parent, int numBits, int numfields,
22
const char *bitslegend, const char *FieldLegend,
23
int docaptions, int dolegends, int dousedlegends )
24
: Meter(parent, title, bitslegend, docaptions, dolegends, dousedlegends){
25
/* We need to set print_ to something valid -- the meters
26
* apparently get drawn before the meters have a chance to call
27
* CheckResources() themselves. */
30
numWarnings_ = printedZeroTotalMesg_ = 0;
40
setfieldlegend(FieldLegend);
41
setNumFields(numfields);
45
BitFieldMeter::disableMeter ( )
48
setfieldcolor (0, "grey");
49
setfieldlegend ("Disabled");
50
total_ = fields_[0] = 1.0;
52
offColor_ = onColor_ = parent_->allocColor("grey");
56
BitFieldMeter::~BitFieldMeter( void ){
65
void BitFieldMeter::checkResources( void ){
66
Meter::checkResources();
67
usedcolor_ = parent_->allocColor( parent_->getResource( "usedLabelColor") );
71
void BitFieldMeter::setNumBits(int n){
76
bits_ = new char[numbits_];
77
lastbits_ = new char[numbits_];
79
for ( int i = 0 ; i < numbits_ ; i++ )
80
bits_[i] = lastbits_[i] = 0;
83
void BitFieldMeter::SetUsedFormat ( const char * const fmt ) {
84
/* Do case-insensitive compares. */
85
if (!strncasecmp (fmt, "percent", 8))
87
else if (!strncasecmp (fmt, "autoscale", 10))
89
else if (!strncasecmp (fmt, "float", 6))
93
fprintf (stderr, "Error: could not parse format of '%s'\n", fmt);
94
fprintf (stderr, " I expected one of 'percent', 'bytes', or 'float'\n");
95
fprintf (stderr, " (Case-insensitive)\n");
100
void BitFieldMeter::setUsed (float val, float total)
104
else if (print_ == PERCENT)
107
used_ = val / total * 100.0;
110
if (!printedZeroTotalMesg_) {
111
printedZeroTotalMesg_ = 1;
112
fprintf(stderr, "Warning: %s meter had a zero total "
113
"field! Would have caused a div-by-zero "
114
"exception.\n", name());
119
else if (print_ == AUTOSCALE)
122
fprintf (stderr, "Error in %s: I can't handle a "
123
"UsedType enum value of %d!\n", name(), print_);
128
void BitFieldMeter::reset( void ){
129
for ( int i = 0 ; i < numfields_ ; i++ )
130
lastvals_[i] = lastx_[i] = -1;
133
void BitFieldMeter::setfieldcolor( int field, const char *color ){
134
colors_[field] = parent_->allocColor( color );
137
void BitFieldMeter::setfieldcolor( int field, unsigned long color ) {
138
colors_[field] = color;
142
void BitFieldMeter::draw( void ){
143
/* Draw the outline for the fieldmeter. */
144
parent_->setForeground( parent_->foreground() );
145
parent_->lineWidth( 1 );
146
parent_->drawFilledRectangle( x_ - 1, y_ - 1, width_/2 + 2, height_ + 2 );
148
// ?? parent_->lineWidth( 0 );
150
parent_->drawRectangle( x_ + width_/2 +3, y_ - 1, width_/2 - 2, height_ + 2 );
152
parent_->setForeground( textcolor_ );
155
if ( dousedlegends_ )
156
offset = parent_->textWidth( "XXXXXXXXX" );
158
offset = parent_->textWidth( "XXXXX" );
160
parent_->drawString( x_ - offset + 1, y_ + height_, title_ );
163
parent_->setForeground( onColor_ );
164
parent_->drawString( x_, y_ - 5, legend_ );
172
void BitFieldMeter::drawfieldlegend( void ){
173
char *tmp1, *tmp2, buff[100];
174
int n, x = x_ + width_/2 + 4;
176
tmp1 = tmp2 = fieldLegend_;
177
for ( int i = 0 ; i < numfields_ ; i++ ){
179
while ( (*tmp2 != '/') && (*tmp2 != '\0') ){
184
strncpy( buff, tmp1, n );
186
parent_->setStippleN(i%4);
187
parent_->setForeground( colors_[i] );
188
parent_->drawString( x, y_ - 5, buff );
189
x += parent_->textWidth( buff, n );
190
parent_->setForeground( parent_->foreground() );
191
if ( i != numfields_ - 1 )
192
parent_->drawString( x, y_ - 5, "/" );
193
x += parent_->textWidth( "/", 1 );
196
parent_->setStippleN(0); /* Restore default all-bits stipple. */
199
void BitFieldMeter::drawused( int manditory ){
201
if ( (lastused_ == used_) )
204
parent_->setStippleN(0); /* Use all-bits stipple. */
205
static const int onechar = parent_->textWidth( "X" );
206
static int xoffset = parent_->textWidth( "XXXXX" );
210
if (print_ == PERCENT){
211
snprintf( buf, 10, "%d%%", (int)used_ );
213
else if (print_ == AUTOSCALE){
216
/* Unfortunately, we have to do our comparisons by 1000s (otherwise
217
* a value of 1020, which is smaller than 1K, could end up
218
* being printed as 1020, which is wider than what can fit) */
219
/* However, we do divide by 1024, so a K really is a K, and not
221
/* In addition, we need to compare against 999.5*1000, because
222
* 999.5, if not rounded up to 1.0 K, will be rounded by the
223
* %.0f to be 1000, which is too wide. So anything at or above
224
* 999.5 needs to be bumped up. */
225
if (used_ >= 999.5*1000*1000*1000*1000*1000*1000)
226
{scale='E'; scaled_used = used_/1024/1024/1024/1024/1024/1024;}
227
else if (used_ >= 999.5*1000*1000*1000*1000)
228
{scale='P'; scaled_used = used_/1024/1024/1024/1024/1024;}
229
else if (used_ >= 999.5*1000*1000*1000)
230
{scale='T'; scaled_used = used_/1024/1024/1024/1024;}
231
else if (used_ >= 999.5*1000*1000)
232
{scale='G'; scaled_used = used_/1024/1024/1024;}
233
else if (used_ >= 999.5*1000)
234
{scale='M'; scaled_used = used_/1024/1024;}
235
else if (used_ >= 999.5)
236
{scale='K'; scaled_used = used_/1024;}
237
else {scale=' '; scaled_used = used_;}
238
/* For now, we can only print 3 characters, plus the optional
239
* suffix, without overprinting the legends. Thus, we can
240
* print 965, or we can print 34, but we can't print 34.7 (the
241
* decimal point takes up one character). bgrayson */
242
if (scaled_used == 0.0)
243
snprintf (buf, 10, "0");
244
else if (scaled_used < 9.95) // 9.95 or above would get
245
// rounded to 10.0, which is too wide.
246
snprintf (buf, 10, "%.1f%c", scaled_used, scale);
247
/* We don't need to check against 99.5 -- it all gets %.0f. */
248
/*else if (scaled_used < 99.5)*/
249
/*snprintf (buf, 10, "%.0f%c", scaled_used, scale);*/
251
snprintf (buf, 10, "%.0f%c", scaled_used, scale);
254
snprintf( buf, 10, "%.1f", used_ );
257
parent_->clear( x_ - xoffset, y_ + height_ - parent_->textHeight(),
258
xoffset - onechar / 2, parent_->textHeight() + 1 );
259
parent_->setForeground( usedcolor_ );
260
parent_->drawString( x_ - (strlen( buf ) + 1 ) * onechar + 2,
266
void BitFieldMeter::drawBits( int manditory ){
269
// pass = (pass + 1) % 2;
273
w = (width_/2 - (numbits_+1)) / numbits_;
275
for ( int i = 0 ; i < numbits_ ; i++ ){
276
if ( (bits_[i] != lastbits_[i]) || manditory ){
277
if ( bits_[i] && pass )
278
parent_->setForeground( onColor_ );
280
parent_->setForeground( offColor_ );
281
parent_->drawFilledRectangle( x1, y_, w, height_);
284
lastbits_[i] = bits_[i];
290
void BitFieldMeter::drawfields( int manditory ){
291
int twidth, x = x_ + width_/2 + 4;
296
for ( int i = 0 ; i < numfields_ ; i++ ){
297
/* Look for bogus values. */
298
if (fields_[i] < 0.0) {
299
/* Only print a warning 5 times per meter, followed by a
300
* message about no more warnings. */
302
if (numWarnings_ < 5)
303
fprintf(stderr, "Warning: meter %s had a negative "
304
"value of %f for field %d\n", name(), fields_[i], i);
305
if (numWarnings_ == 5)
306
fprintf(stderr, "Future warnings from the %s meter "
307
"will not be displayed.\n", name());
310
twidth = (int) (((width_/2 - 3) * (float) fields_[i]) / total_);
311
// twidth = (int)((fields_[i] * width_) / total_);
312
if ( (i == numfields_ - 1) && ((x + twidth) != (x_ + width_)) )
313
twidth = width_ + x_ - x;
315
if ( manditory || (twidth != lastvals_[i]) || (x != lastx_[i]) ){
316
parent_->setForeground( colors_[i] );
317
parent_->setStippleN(i%4);
318
parent_->drawFilledRectangle( x, y_, twidth, height_ );
319
parent_->setStippleN(0); /* Restore all-bits stipple. */
320
lastvals_[i] = twidth;
323
if ( dousedlegends_ )
324
drawused( manditory );
332
void BitFieldMeter::checkevent( void ){
337
void BitFieldMeter::setBits(int startbit, unsigned char values){
338
unsigned char mask = 1;
339
for (int i = startbit ; i < startbit + 8 ; i++){
340
bits_[i] = values & mask;
345
void BitFieldMeter::setNumFields(int n){
351
fields_ = new float[numfields_];
352
colors_ = new unsigned long[numfields_];
353
lastvals_ = new int[numfields_];
354
lastx_ = new int[numfields_];
357
for ( int i = 0 ; i < numfields_ ; i++ ){
358
fields_[i] = 0.0; /* egcs 2.91.66 bug !? don't do this and */
359
lastvals_[i] = lastx_[i] = 0; /* that in a single statement or it'll */
360
/* overwrite too much with 0 ... */
361
/* Thomas Waldmann ( tw@com-ma.de ) */
365
bool BitFieldMeter::checkX(int x, int width) const {
366
if ((x < x_) || (x + width < x_)
367
|| (x > x_ + width_) || (x + width > x_ + width_)){
368
std::cerr << "BitFieldMeter::checkX() : bad horiz values for meter : "
369
<< name() << std::endl;
371
std::cerr <<"value "<<x<<", width "<<width<<", total_ = "<<total_<<std::endl;
373
for (int i = 0 ; i < numfields_ ; i++)
374
std::cerr <<"fields_[" <<i <<"] = " <<fields_[i] <<",";
375
std::cerr <<std::endl;
384
void BitFieldMeter::setfieldlegend( const char *fieldlegend ){
385
delete[] fieldLegend_;
386
int len = strlen(fieldlegend);
387
fieldLegend_ = new char[len + 1];
388
strncpy( fieldLegend_, fieldlegend, len );
389
fieldLegend_[len] = '\0'; // strncpy() will not null terminate if s2 > len