Meter.c 14.2 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - Meter.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2004-2011 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
8
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "Meter.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9
10

#include "RichString.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
11
12
#include "Object.h"
#include "CRT.h"
David Hunt's avatar
David Hunt committed
13
#include "StringUtils.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
14
#include "ListItem.h"
15
#include "Settings.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17
18
19
20

#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
21
#include <assert.h>
22
#include <sys/time.h>
23

Hisham Muhammad's avatar
Hisham Muhammad committed
24
#define METER_BUFFER_LEN 256
Hisham Muhammad's avatar
Hisham Muhammad committed
25

26
27
#define GRAPH_DELAY (DEFAULT_DELAY/2)

28
29
#define GRAPH_HEIGHT 4 /* Unit: rows (lines) */

Hisham Muhammad's avatar
Hisham Muhammad committed
30
/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
31
#include "ListItem.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
32
33

#include <sys/time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
34
35
36

typedef struct Meter_ Meter;

37
38
39
typedef void(*Meter_Init)(Meter*);
typedef void(*Meter_Done)(Meter*);
typedef void(*Meter_UpdateMode)(Meter*, int);
40
typedef void(*Meter_UpdateValues)(Meter*, char*, int);
Hisham Muhammad's avatar
Hisham Muhammad committed
41
42
typedef void(*Meter_Draw)(Meter*, int, int, int);

43
44
45
46
47
48
typedef struct MeterClass_ {
   ObjectClass super;
   const Meter_Init init;
   const Meter_Done done;
   const Meter_UpdateMode updateMode;
   const Meter_Draw draw;
49
   const Meter_UpdateValues updateValues;
50
51
52
   const int defaultMode;
   const double total;
   const int* attributes;
Hisham Muhammad's avatar
Hisham Muhammad committed
53
54
55
   const char* name;
   const char* uiName;
   const char* caption;
56
   const char* description;
57
58
   const char maxItems;
   char curItems;
59
60
61
62
63
64
65
66
67
68
} MeterClass;

#define As_Meter(this_)                ((MeterClass*)((this_)->super.klass))
#define Meter_initFn(this_)            As_Meter(this_)->init
#define Meter_init(this_)              As_Meter(this_)->init((Meter*)(this_))
#define Meter_done(this_)              As_Meter(this_)->done((Meter*)(this_))
#define Meter_updateModeFn(this_)      As_Meter(this_)->updateMode
#define Meter_updateMode(this_, m_)    As_Meter(this_)->updateMode((Meter*)(this_), m_)
#define Meter_drawFn(this_)            As_Meter(this_)->draw
#define Meter_doneFn(this_)            As_Meter(this_)->done
69
70
#define Meter_updateValues(this_, buf_, sz_) \
                                       As_Meter(this_)->updateValues((Meter*)(this_), buf_, sz_)
71
#define Meter_defaultMode(this_)       As_Meter(this_)->defaultMode
72
73
#define Meter_getItems(this_)          As_Meter(this_)->curItems
#define Meter_setItems(this_, n_)      As_Meter(this_)->curItems = (n_)
74
75
76
#define Meter_attributes(this_)        As_Meter(this_)->attributes
#define Meter_name(this_)              As_Meter(this_)->name
#define Meter_uiName(this_)            As_Meter(this_)->uiName
77
78
79

struct Meter_ {
   Object super;
80
81
   Meter_Draw draw;
   
82
83
84
   char* caption;
   int mode;
   int param;
85
   void* drawData;
86
   int h;
Hisham Muhammad's avatar
Hisham Muhammad committed
87
   struct ProcessList_* pl;
Hisham Muhammad's avatar
Hisham Muhammad committed
88
89
90
91
   double* values;
   double total;
};

92
93
94
95
96
typedef struct MeterMode_ {
   Meter_Draw draw;
   const char* uiName;
   int h;
} MeterMode;
97

98
99
100
101
102
103
104
105
106
typedef enum {
   CUSTOM_METERMODE = 0,
   BAR_METERMODE,
   TEXT_METERMODE,
   GRAPH_METERMODE,
   LED_METERMODE,
   LAST_METERMODE
} MeterModeId;

107
108
109
110
111
typedef struct GraphData_ {
   struct timeval time;
   double values[METER_BUFFER_LEN];
} GraphData;

Hisham Muhammad's avatar
Hisham Muhammad committed
112
113
114
115
116
}*/

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
117
118
119
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
120
121
122
#ifndef CLAMP
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
123

124
125
126
127
128
MeterClass Meter_class = {
   .super = {
      .extends = Class(Object)
   }
};
Hisham Muhammad's avatar
Hisham Muhammad committed
129

Hisham Muhammad's avatar
Hisham Muhammad committed
130
Meter* Meter_new(struct ProcessList_* pl, int param, MeterClass* type) {
Hisham's avatar
Hisham committed
131
   Meter* this = xCalloc(1, sizeof(Meter));
132
   Object_setClass(this, type);
133
134
135
   this->h = 1;
   this->param = param;
   this->pl = pl;
136
137
   type->curItems = type->maxItems;
   this->values = xCalloc(type->maxItems, sizeof(double));
138
   this->total = type->total;
Hisham's avatar
Hisham committed
139
   this->caption = xStrdup(type->caption);
140
141
142
   if (Meter_initFn(this))
      Meter_init(this);
   Meter_setMode(this, type->defaultMode);
143
   return this;
Hisham Muhammad's avatar
Hisham Muhammad committed
144
145
}

Christian Hesse's avatar
Christian Hesse committed
146
int Meter_humanUnit(char* buffer, unsigned long int value, int size) {
Hisham Muhammad's avatar
Hisham Muhammad committed
147
148
149
   const char * prefix = "KMGTPEZY";
   unsigned long int powi = 1;
   unsigned int written, powj = 1, precision = 2;
Christian Hesse's avatar
Christian Hesse committed
150

Hisham Muhammad's avatar
Hisham Muhammad committed
151
152
153
   for(;;) {
      if (value / 1024 < powi)
         break;
Christian Hesse's avatar
Christian Hesse committed
154

Hisham Muhammad's avatar
Hisham Muhammad committed
155
156
      if (prefix[1] == 0)
         break;
Christian Hesse's avatar
Christian Hesse committed
157

Hisham Muhammad's avatar
Hisham Muhammad committed
158
159
160
      powi *= 1024;
      ++prefix;
   }
Christian Hesse's avatar
Christian Hesse committed
161

162
163
164
   if (*prefix == 'K')
      precision = 0;

Hisham Muhammad's avatar
Hisham Muhammad committed
165
166
167
168
169
   for (; precision > 0; precision--) {
      powj *= 10;
      if (value / powi < powj)
         break;
   }
Christian Hesse's avatar
Christian Hesse committed
170

Hisham Muhammad's avatar
Hisham Muhammad committed
171
172
   written = snprintf(buffer, size, "%.*f%c",
      precision, (double) value / powi, *prefix);
Christian Hesse's avatar
Christian Hesse committed
173

Hisham Muhammad's avatar
Hisham Muhammad committed
174
   return written;
Christian Hesse's avatar
Christian Hesse committed
175
176
}

Hisham Muhammad's avatar
Hisham Muhammad committed
177
void Meter_delete(Object* cast) {
178
179
   if (!cast)
      return;
Hisham Muhammad's avatar
Hisham Muhammad committed
180
   Meter* this = (Meter*) cast;
181
182
   if (Meter_doneFn(this)) {
      Meter_done(this);
183
   }
184
   free(this->drawData);
185
186
   free(this->caption);
   free(this->values);
Hisham Muhammad's avatar
Hisham Muhammad committed
187
188
189
   free(this);
}

Hisham Muhammad's avatar
Hisham Muhammad committed
190
void Meter_setCaption(Meter* this, const char* caption) {
191
   free(this->caption);
Hisham's avatar
Hisham committed
192
   this->caption = xStrdup(caption);
193
194
}

195
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
196
197
   if (Object_displayFn(this)) {
      Object_display(this, out);
198
   } else {
199
      RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
200
   }
201
202
203
}

void Meter_setMode(Meter* this, int modeIndex) {
Hisham Muhammad's avatar
Hisham Muhammad committed
204
   if (modeIndex > 0 && modeIndex == this->mode)
205
206
207
208
      return;
   if (!modeIndex)
      modeIndex = 1;
   assert(modeIndex < LAST_METERMODE);
209
210
211
212
   if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
      this->draw = Meter_drawFn(this);
      if (Meter_updateModeFn(this))
         Meter_updateMode(this, modeIndex);
213
   } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
214
      assert(modeIndex >= 1);
215
      free(this->drawData);
216
      this->drawData = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
217
218
219
220

      MeterMode* mode = Meter_modes[modeIndex];
      this->draw = mode->draw;
      this->h = mode->h;
Hisham Muhammad's avatar
Hisham Muhammad committed
221
   }
222
   this->mode = modeIndex;
Hisham Muhammad's avatar
Hisham Muhammad committed
223
224
}

225
ListItem* Meter_toListItem(Meter* this, bool moving) {
226
227
228
229
230
231
232
233
234
235
236
   char mode[21];
   if (this->mode)
      snprintf(mode, 20, " [%s]", Meter_modes[this->mode]->uiName);
   else
      mode[0] = '\0';
   char number[11];
   if (this->param > 0)
      snprintf(number, 10, " %d", this->param);
   else
      number[0] = '\0';
   char buffer[51];
237
   snprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
238
239
240
   ListItem* li = ListItem_new(buffer, 0);
   li->moving = moving;
   return li;
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
}

243
244
/* ---------- TextMeterMode ---------- */

245
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
246
   char buffer[METER_BUFFER_LEN];
247
   Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
248
   (void) w;
249
250
251
252
253
254

   attrset(CRT_colors[METER_TEXT]);
   mvaddstr(y, x, this->caption);
   int captionLen = strlen(this->caption);
   x += captionLen;
   attrset(CRT_colors[RESET_COLOR]);
255
256
257
258
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
   RichString_printVal(out, y, x);
   RichString_end(out);
259
260
261
262
}

/* ---------- BarMeterMode ---------- */

263
static char BarMeterMode_characters[] = "|#*@$%&.";
264

265
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
266
   char buffer[METER_BUFFER_LEN];
267
   Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
268

Hisham Muhammad's avatar
Hisham Muhammad committed
269
270
   w -= 2;
   attrset(CRT_colors[METER_TEXT]);
Hisham Muhammad's avatar
Hisham Muhammad committed
271
272
   int captionLen = 3;
   mvaddnstr(y, x, this->caption, captionLen);
Hisham Muhammad's avatar
Hisham Muhammad committed
273
274
275
276
277
278
279
280
   x += captionLen;
   w -= captionLen;
   attrset(CRT_colors[BAR_BORDER]);
   mvaddch(y, x, '[');
   mvaddch(y, x + w, ']');
   
   w--;
   x++;
281
282
283
284
285
286

   if (w < 1) {
      attrset(CRT_colors[RESET_COLOR]);
      return;
   }
   char bar[w + 1];
Hisham Muhammad's avatar
Hisham Muhammad committed
287
288
289
   
   int blockSizes[10];

290
   snprintf(bar, w + 1, "%*s", w, buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
291
292
293

   // First draw in the bar[] buffer...
   int offset = 0;
294
295
   int items = Meter_getItems(this);
   for (int i = 0; i < items; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
296
      double value = this->values[i];
297
      value = CLAMP(value, 0.0, this->total);
Hisham Muhammad's avatar
Hisham Muhammad committed
298
299
300
301
302
303
304
      if (value > 0) {
         blockSizes[i] = ceil((value/this->total) * w);
      } else {
         blockSizes[i] = 0;
      }
      int nextOffset = offset + blockSizes[i];
      // (Control against invalid values)
305
      nextOffset = CLAMP(nextOffset, 0, w);
Hisham Muhammad's avatar
Hisham Muhammad committed
306
307
308
      for (int j = offset; j < nextOffset; j++)
         if (bar[j] == ' ') {
            if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
309
               bar[j] = BarMeterMode_characters[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
310
311
312
313
314
315
316
317
318
            } else {
               bar[j] = '|';
            }
         }
      offset = nextOffset;
   }

   // ...then print the buffer.
   offset = 0;
319
320
   for (int i = 0; i < items; i++) {
      attrset(CRT_colors[Meter_attributes(this)[i]]);
Hisham Muhammad's avatar
Hisham Muhammad committed
321
322
      mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
      offset += blockSizes[i];
323
      offset = CLAMP(offset, 0, w);
Hisham Muhammad's avatar
Hisham Muhammad committed
324
325
326
327
328
329
330
331
332
333
   }
   if (offset < w) {
      attrset(CRT_colors[BAR_SHADOW]);
      mvaddnstr(y, x + offset, bar + offset, w - offset);
   }

   move(y, x + w + 1);
   attrset(CRT_colors[RESET_COLOR]);
}

334
335
/* ---------- GraphMeterMode ---------- */

336
337
#ifdef HAVE_LIBNCURSESW

Christian Hesse's avatar
Christian Hesse committed
338
339
#define PIXPERROW_UTF8 4
static const char* GraphMeterMode_dotsUtf8[] = {
340
   /*00*/" ", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸",
Christian Hesse's avatar
Christian Hesse committed
341
342
343
344
   /*10*/"⡀", /*11*/"⣀", /*12*/"⣠", /*13*/"⣰", /*14*/ "⣸",
   /*20*/"⡄", /*21*/"⣄", /*22*/"⣤", /*23*/"⣴", /*24*/ "⣼",
   /*30*/"⡆", /*31*/"⣆", /*32*/"⣦", /*33*/"⣶", /*34*/ "⣾",
   /*40*/"⡇", /*41*/"⣇", /*42*/"⣧", /*43*/"⣷", /*44*/ "⣿"
Hisham Muhammad's avatar
Hisham Muhammad committed
345
};
346

347
348
#endif

Christian Hesse's avatar
Christian Hesse committed
349
350
351
352
353
#define PIXPERROW_ASCII 2
static const char* GraphMeterMode_dotsAscii[] = {
   /*00*/" ", /*01*/".", /*02*/":",
   /*10*/".", /*11*/".", /*12*/":",
   /*20*/":", /*21*/":", /*22*/":"
354
355
};

Christian Hesse's avatar
Christian Hesse committed
356
static const char** GraphMeterMode_dots;
Hisham Muhammad's avatar
Hisham Muhammad committed
357
static int GraphMeterMode_pixPerRow;
358

359
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
360

Hisham's avatar
Hisham committed
361
   if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
Hisham Muhammad's avatar
Hisham Muhammad committed
362
    GraphData* data = (GraphData*) this->drawData;
363
   const int nValues = METER_BUFFER_LEN;
Hisham Muhammad's avatar
Hisham Muhammad committed
364

365
#ifdef HAVE_LIBNCURSESW
Hisham Muhammad's avatar
Hisham Muhammad committed
366
367
   if (CRT_utf8) {
      GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
Hisham Muhammad's avatar
Hisham Muhammad committed
368
      GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
369
370
371
   } else
#endif
   {
Hisham Muhammad's avatar
Hisham Muhammad committed
372
      GraphMeterMode_dots = GraphMeterMode_dotsAscii;
Hisham Muhammad's avatar
Hisham Muhammad committed
373
      GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
Hisham Muhammad's avatar
Hisham Muhammad committed
374
375
376
377
378
379
380
   }

   attrset(CRT_colors[METER_TEXT]);
   int captionLen = 3;
   mvaddnstr(y, x, this->caption, captionLen);
   x += captionLen;
   w -= captionLen;
381
   
382
383
384
   struct timeval now;
   gettimeofday(&now, NULL);
   if (!timercmp(&now, &(data->time), <)) {
385
      struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
386
      timeradd(&now, &delay, &(data->time));
387

388
389
390
391
      for (int i = 0; i < nValues - 1; i++)
         data->values[i] = data->values[i+1];
   
      char buffer[nValues];
392
      Meter_updateValues(this, buffer, nValues - 1);
393
394
   
      double value = 0.0;
395
396
      int items = Meter_getItems(this);
      for (int i = 0; i < items; i++)
397
398
399
400
401
         value += this->values[i];
      value /= this->total;
      data->values[nValues - 1] = value;
   }
   
Hisham's avatar
Hisham committed
402
403
404
405
406
407
   int i = nValues - (w*2) + 2, k = 0;
   if (i < 0) {
      k = -i/2;
      i = 0;
   }
   for (; i < nValues; i+=2, k++) {
408
409
410
      int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT;
      int v1 = CLAMP(data->values[i] * pix, 1, pix);
      int v2 = CLAMP(data->values[i+1] * pix, 1, pix);
Christian Hesse's avatar
Christian Hesse committed
411

Hisham Muhammad's avatar
Hisham Muhammad committed
412
      int colorIdx = GRAPH_1;
413
414
415
      for (int line = 0; line < GRAPH_HEIGHT; line++) {
         int line1 = CLAMP(v1 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
         int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (GRAPH_HEIGHT - 1 - line)), 0, GraphMeterMode_pixPerRow);
Christian Hesse's avatar
Christian Hesse committed
416

Hisham Muhammad's avatar
Hisham Muhammad committed
417
         attrset(CRT_colors[colorIdx]);
Hisham Muhammad's avatar
Hisham Muhammad committed
418
         mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
Hisham Muhammad's avatar
Hisham Muhammad committed
419
420
         colorIdx = GRAPH_2;
      }
421
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
422
423
424
   attrset(CRT_colors[RESET_COLOR]);
}

425
426
/* ---------- LEDMeterMode ---------- */

Christian Hesse's avatar
Christian Hesse committed
427
428
429
430
static const char* LEDMeterMode_digitsAscii[] = {
   " __ ","    "," __ "," __ ","    "," __ "," __ "," __ "," __ "," __ ",
   "|  |","   |"," __|"," __|","|__|","|__ ","|__ ","   |","|__|","|__|",
   "|__|","   |","|__ "," __|","   |"," __|","|__|","   |","|__|"," __|"
431
};
Hisham Muhammad's avatar
Hisham Muhammad committed
432

433
434
#ifdef HAVE_LIBNCURSESW

Christian Hesse's avatar
Christian Hesse committed
435
436
437
438
static const char* LEDMeterMode_digitsUtf8[] = {
   "┌──┐","  ┐ ","╶──┐","╶──┐","╷  ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
   "│  │","  │ ","┌──┘"," ──┤","└──┤","└──┐","├──┐","   │","├──┤","└──┤",
   "└──┘","  ╵ ","└──╴","╶──┘","   ╵","╶──┘","└──┘","   ╵","└──┘"," ──┘"
439
440
};

441
442
#endif

Christian Hesse's avatar
Christian Hesse committed
443
static const char** LEDMeterMode_digits;
Hisham Muhammad's avatar
Hisham Muhammad committed
444

445
static void LEDMeterMode_drawDigit(int x, int y, int n) {
Hisham Muhammad's avatar
Hisham Muhammad committed
446
   for (int i = 0; i < 3; i++)
Christian Hesse's avatar
Christian Hesse committed
447
      mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]);
448
449
}

450
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
Hisham Muhammad's avatar
Hisham Muhammad committed
451
   (void) w;
Hisham Muhammad's avatar
Hisham Muhammad committed
452

453
454
#ifdef HAVE_LIBNCURSESW
   if (CRT_utf8)
Hisham Muhammad's avatar
Hisham Muhammad committed
455
      LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
456
457
   else
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
458
459
      LEDMeterMode_digits = LEDMeterMode_digitsAscii;

460
   char buffer[METER_BUFFER_LEN];
461
   Meter_updateValues(this, buffer, METER_BUFFER_LEN - 1);
462
463
464
   
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
465

466
467
   int yText =
#ifdef HAVE_LIBNCURSESW
Hisham Muhammad's avatar
Hisham Muhammad committed
468
      CRT_utf8 ? y+1 :
469
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
470
      y+2;
Hisham Muhammad's avatar
Hisham Muhammad committed
471
   attrset(CRT_colors[LED_COLOR]);
472
   mvaddstr(yText, x, this->caption);
Hisham Muhammad's avatar
Hisham Muhammad committed
473
   int xx = x + strlen(this->caption);
474
475
476
   int len = RichString_sizeVal(out);
   for (int i = 0; i < len; i++) {
      char c = RichString_getCharVal(out, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
477
      if (c >= '0' && c <= '9') {
478
479
         LEDMeterMode_drawDigit(xx, y, c-48);
         xx += 4;
Hisham Muhammad's avatar
Hisham Muhammad committed
480
      } else {
481
         mvaddch(yText, xx, c);
Hisham Muhammad's avatar
Hisham Muhammad committed
482
483
484
485
         xx += 1;
      }
   }
   attrset(CRT_colors[RESET_COLOR]);
486
   RichString_end(out);
Hisham Muhammad's avatar
Hisham Muhammad committed
487
488
}

489
490
491
492
493
494
495
496
497
498
499
500
501
502
static MeterMode BarMeterMode = {
   .uiName = "Bar",
   .h = 1,
   .draw = BarMeterMode_draw,
};

static MeterMode TextMeterMode = {
   .uiName = "Text",
   .h = 1,
   .draw = TextMeterMode_draw,
};

static MeterMode GraphMeterMode = {
   .uiName = "Graph",
503
   .h = GRAPH_HEIGHT,
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
   .draw = GraphMeterMode_draw,
};

static MeterMode LEDMeterMode = {
   .uiName = "LED",
   .h = 3,
   .draw = LEDMeterMode_draw,
};

MeterMode* Meter_modes[] = {
   NULL,
   &BarMeterMode,
   &TextMeterMode,
   &GraphMeterMode,
   &LEDMeterMode,
   NULL
};
Hisham Muhammad's avatar
Hisham Muhammad committed
521
522
523

/* Blank meter */

524
static void BlankMeter_updateValues(Meter* this, char* buffer, int size) {
Hisham Muhammad's avatar
Hisham Muhammad committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
   (void) this; (void) buffer; (void) size;
}

static void BlankMeter_display(Object* cast, RichString* out) {
   (void) cast;
   RichString_prune(out);
}

int BlankMeter_attributes[] = {
   DEFAULT_COLOR
};

MeterClass BlankMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete,
      .display = BlankMeter_display,
   },
543
   .updateValues = BlankMeter_updateValues,
Hisham Muhammad's avatar
Hisham Muhammad committed
544
   .defaultMode = TEXT_METERMODE,
545
   .maxItems = 0,
Hisham Muhammad's avatar
Hisham Muhammad committed
546
547
548
549
550
551
   .total = 100.0,
   .attributes = BlankMeter_attributes,
   .name = "Blank",
   .uiName = "Blank",
   .caption = ""
};