Meter.c 14.3 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_SetValues)(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
49
50
51
52
typedef struct MeterClass_ {
   ObjectClass super;
   const Meter_Init init;
   const Meter_Done done;
   const Meter_UpdateMode updateMode;
   const Meter_Draw draw;
   const Meter_SetValues setValues;
   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
69
70
} 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
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_)
#define Meter_defaultMode(this_)       As_Meter(this_)->defaultMode
71
72
#define Meter_getItems(this_)          As_Meter(this_)->curItems
#define Meter_setItems(this_, n_)      As_Meter(this_)->curItems = (n_)
73
74
75
#define Meter_attributes(this_)        As_Meter(this_)->attributes
#define Meter_name(this_)              As_Meter(this_)->name
#define Meter_uiName(this_)            As_Meter(this_)->uiName
76
77
78

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

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

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

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

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

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
156
   for(;;) {
      if (value / 1024 < powi)
         break;
Christian Hesse's avatar
Christian Hesse committed
157

Hisham Muhammad's avatar
Hisham Muhammad committed
158
159
      if (prefix[1] == 0)
         break;
Christian Hesse's avatar
Christian Hesse committed
160

Hisham Muhammad's avatar
Hisham Muhammad committed
161
162
163
      powi *= 1024;
      ++prefix;
   }
Christian Hesse's avatar
Christian Hesse committed
164

165
166
167
   if (*prefix == 'K')
      precision = 0;

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
177
   return written;
Christian Hesse's avatar
Christian Hesse committed
178
179
}

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

Hisham Muhammad's avatar
Hisham Muhammad committed
194
void Meter_setCaption(Meter* this, const char* caption) {
195
   free(this->caption);
Hisham's avatar
Hisham committed
196
   this->caption = xStrdup(caption);
197
198
}

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

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

      MeterMode* mode = Meter_modes[modeIndex];
      this->draw = mode->draw;
      this->h = mode->h;
Hisham Muhammad's avatar
Hisham Muhammad committed
226
   }
227
   this->mode = modeIndex;
Hisham Muhammad's avatar
Hisham Muhammad committed
228
229
}

230
ListItem* Meter_toListItem(Meter* this, bool moving) {
231
232
233
234
235
236
237
238
239
240
241
   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];
242
   snprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
243
244
245
   ListItem* li = ListItem_new(buffer, 0);
   li->moving = moving;
   return li;
Hisham Muhammad's avatar
Hisham Muhammad committed
246
247
}

248
249
/* ---------- TextMeterMode ---------- */

250
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
251
   char buffer[METER_BUFFER_LEN];
252
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
253
   (void) w;
254
255
256
257
258
259

   attrset(CRT_colors[METER_TEXT]);
   mvaddstr(y, x, this->caption);
   int captionLen = strlen(this->caption);
   x += captionLen;
   attrset(CRT_colors[RESET_COLOR]);
260
261
262
263
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
   RichString_printVal(out, y, x);
   RichString_end(out);
264
265
266
267
}

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

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

270
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
271
   char buffer[METER_BUFFER_LEN];
272
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
273

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

   if (w < 1) {
      attrset(CRT_colors[RESET_COLOR]);
      return;
   }
   char bar[w + 1];
Hisham Muhammad's avatar
Hisham Muhammad committed
292
293
294
295
296
   
   int blockSizes[10];
   for (int i = 0; i < w; i++)
      bar[i] = ' ';

297
   const size_t barOffset = w - MIN((int)strlen(buffer), w);
298
   snprintf(bar + barOffset, w - barOffset + 1, "%s", buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
299
300
301

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

   // ...then print the buffer.
   offset = 0;
327
328
   for (int i = 0; i < items; i++) {
      attrset(CRT_colors[Meter_attributes(this)[i]]);
Hisham Muhammad's avatar
Hisham Muhammad committed
329
330
      mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
      offset += blockSizes[i];
331
      offset = CLAMP(offset, 0, w);
Hisham Muhammad's avatar
Hisham Muhammad committed
332
333
334
335
336
337
338
339
340
341
   }
   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]);
}

342
343
/* ---------- GraphMeterMode ---------- */

344
345
#ifdef HAVE_LIBNCURSESW

Christian Hesse's avatar
Christian Hesse committed
346
347
#define PIXPERROW_UTF8 4
static const char* GraphMeterMode_dotsUtf8[] = {
348
   /*00*/" ", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸",
Christian Hesse's avatar
Christian Hesse committed
349
350
351
352
   /*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
353
};
354

355
356
#endif

Christian Hesse's avatar
Christian Hesse committed
357
358
359
360
361
#define PIXPERROW_ASCII 2
static const char* GraphMeterMode_dotsAscii[] = {
   /*00*/" ", /*01*/".", /*02*/":",
   /*10*/".", /*11*/".", /*12*/":",
   /*20*/":", /*21*/":", /*22*/":"
362
363
};

Christian Hesse's avatar
Christian Hesse committed
364
static const char** GraphMeterMode_dots;
Hisham Muhammad's avatar
Hisham Muhammad committed
365
static int GraphMeterMode_pixPerRow;
366

367
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
368

Hisham's avatar
Hisham committed
369
   if (!this->drawData) this->drawData = xCalloc(1, sizeof(GraphData));
Hisham Muhammad's avatar
Hisham Muhammad committed
370
    GraphData* data = (GraphData*) this->drawData;
371
   const int nValues = METER_BUFFER_LEN;
Hisham Muhammad's avatar
Hisham Muhammad committed
372

373
#ifdef HAVE_LIBNCURSESW
Hisham Muhammad's avatar
Hisham Muhammad committed
374
375
   if (CRT_utf8) {
      GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
Hisham Muhammad's avatar
Hisham Muhammad committed
376
      GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
377
378
379
   } else
#endif
   {
Hisham Muhammad's avatar
Hisham Muhammad committed
380
      GraphMeterMode_dots = GraphMeterMode_dotsAscii;
Hisham Muhammad's avatar
Hisham Muhammad committed
381
      GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
Hisham Muhammad's avatar
Hisham Muhammad committed
382
383
384
385
386
387
388
   }

   attrset(CRT_colors[METER_TEXT]);
   int captionLen = 3;
   mvaddnstr(y, x, this->caption, captionLen);
   x += captionLen;
   w -= captionLen;
389
   
390
391
392
   struct timeval now;
   gettimeofday(&now, NULL);
   if (!timercmp(&now, &(data->time), <)) {
393
      struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
394
      timeradd(&now, &delay, &(data->time));
395

396
397
398
399
      for (int i = 0; i < nValues - 1; i++)
         data->values[i] = data->values[i+1];
   
      char buffer[nValues];
400
      Meter_setValues(this, buffer, nValues - 1);
401
402
   
      double value = 0.0;
403
404
      int items = Meter_getItems(this);
      for (int i = 0; i < items; i++)
405
406
407
408
409
         value += this->values[i];
      value /= this->total;
      data->values[nValues - 1] = value;
   }
   
Hisham Muhammad's avatar
Hisham Muhammad committed
410
   for (int i = nValues - (w*2) + 2, k = 0; i < nValues; i+=2, k++) {
411
412
413
      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
414

Hisham Muhammad's avatar
Hisham Muhammad committed
415
      int colorIdx = GRAPH_1;
416
417
418
      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
419

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

428
429
/* ---------- LEDMeterMode ---------- */

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

436
437
#ifdef HAVE_LIBNCURSESW

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

444
445
#endif

Christian Hesse's avatar
Christian Hesse committed
446
static const char** LEDMeterMode_digits;
Hisham Muhammad's avatar
Hisham Muhammad committed
447

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

453
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
Hisham Muhammad's avatar
Hisham Muhammad committed
454
   (void) w;
Hisham Muhammad's avatar
Hisham Muhammad committed
455

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

463
   char buffer[METER_BUFFER_LEN];
464
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
465
466
467
   
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
468

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

492
493
494
495
496
497
498
499
500
501
502
503
504
505
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",
506
   .h = GRAPH_HEIGHT,
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
   .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
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

/* Blank meter */

static void BlankMeter_setValues(Meter* this, char* buffer, int size) {
   (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,
   },
   .setValues = BlankMeter_setValues,
   .defaultMode = TEXT_METERMODE,
   .total = 100.0,
   .attributes = BlankMeter_attributes,
   .name = "Blank",
   .uiName = "Blank",
   .caption = ""
};