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)

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

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

typedef struct Meter_ Meter;

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

41
42
43
44
45
46
47
48
49
50
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
51
52
53
   const char* name;
   const char* uiName;
   const char* caption;
54
   const char* description;
55
56
   const char maxItems;
   char curItems;
57
58
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
#define Meter_setValues(this_, c_, i_) As_Meter(this_)->setValues((Meter*)(this_), c_, i_)
#define Meter_defaultMode(this_)       As_Meter(this_)->defaultMode
69
70
#define Meter_getItems(this_)          As_Meter(this_)->curItems
#define Meter_setItems(this_, n_)      As_Meter(this_)->curItems = (n_)
71
72
73
#define Meter_attributes(this_)        As_Meter(this_)->attributes
#define Meter_name(this_)              As_Meter(this_)->name
#define Meter_uiName(this_)            As_Meter(this_)->uiName
74
75
76

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
109
110
111
112
113
}*/

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

246
247
/* ---------- TextMeterMode ---------- */

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

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

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

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

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

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

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

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

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

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

340
341
/* ---------- GraphMeterMode ---------- */

342
343
#ifdef HAVE_LIBNCURSESW

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

353
354
#endif

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

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

365
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
366

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

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

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

394
395
396
397
      for (int i = 0; i < nValues - 1; i++)
         data->values[i] = data->values[i+1];
   
      char buffer[nValues];
398
      Meter_setValues(this, buffer, nValues - 1);
399
400
   
      double value = 0.0;
401
402
      int items = Meter_getItems(this);
      for (int i = 0; i < items; i++)
403
404
405
406
407
         value += this->values[i];
      value /= this->total;
      data->values[nValues - 1] = value;
   }
   
Hisham Muhammad's avatar
Hisham Muhammad committed
408
   for (int i = nValues - (w*2) + 2, k = 0; i < nValues; i+=2, k++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
409
      const double dot = (1.0 / (GraphMeterMode_pixPerRow * 4));
410
411
      int v1 = CLAMP(data->values[i] / dot, 1, GraphMeterMode_pixPerRow * 4);
      int v2 = CLAMP(data->values[i+1] / dot, 1, GraphMeterMode_pixPerRow * 4);
Christian Hesse's avatar
Christian Hesse committed
412

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

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

426
427
/* ---------- LEDMeterMode ---------- */

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

434
435
#ifdef HAVE_LIBNCURSESW

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

442
443
#endif

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

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

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

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

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

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

490
491
492
493
494
495
496
497
498
499
500
501
502
503
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",
Hisham Muhammad's avatar
Hisham Muhammad committed
504
   .h = 4,
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
   .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
522
523
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

/* 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 = ""
};