Meter.c 13.7 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
Hisham Muhammad's avatar
Hisham Muhammad committed
117

118
119
120
121
122
MeterClass Meter_class = {
   .super = {
      .extends = Class(Object)
   }
};
Hisham Muhammad's avatar
Hisham Muhammad committed
123

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

void Meter_delete(Object* cast) {
145
146
   if (!cast)
      return;
Hisham Muhammad's avatar
Hisham Muhammad committed
147
   Meter* this = (Meter*) cast;
148
149
   if (Meter_doneFn(this)) {
      Meter_done(this);
150
   }
151
152
   if (this->drawData)
      free(this->drawData);
153
154
   free(this->caption);
   free(this->values);
Hisham Muhammad's avatar
Hisham Muhammad committed
155
156
157
   free(this);
}

Hisham Muhammad's avatar
Hisham Muhammad committed
158
void Meter_setCaption(Meter* this, const char* caption) {
159
160
161
162
   free(this->caption);
   this->caption = strdup(caption);
}

163
static inline void Meter_displayBuffer(Meter* this, char* buffer, RichString* out) {
164
165
   if (Object_displayFn(this)) {
      Object_display(this, out);
166
   } else {
167
      RichString_write(out, CRT_colors[Meter_attributes(this)[0]], buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
168
   }
169
170
171
}

void Meter_setMode(Meter* this, int modeIndex) {
Hisham Muhammad's avatar
Hisham Muhammad committed
172
   if (modeIndex > 0 && modeIndex == this->mode)
173
174
175
176
      return;
   if (!modeIndex)
      modeIndex = 1;
   assert(modeIndex < LAST_METERMODE);
177
178
179
180
   if (Meter_defaultMode(this) == CUSTOM_METERMODE) {
      this->draw = Meter_drawFn(this);
      if (Meter_updateModeFn(this))
         Meter_updateMode(this, modeIndex);
181
   } else {
Hisham Muhammad's avatar
Hisham Muhammad committed
182
      assert(modeIndex >= 1);
183
184
185
      if (this->drawData)
         free(this->drawData);
      this->drawData = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
186
187
188
189

      MeterMode* mode = Meter_modes[modeIndex];
      this->draw = mode->draw;
      this->h = mode->h;
Hisham Muhammad's avatar
Hisham Muhammad committed
190
   }
191
   this->mode = modeIndex;
Hisham Muhammad's avatar
Hisham Muhammad committed
192
193
}

194
ListItem* Meter_toListItem(Meter* this, bool moving) {
195
196
197
198
199
200
201
202
203
204
205
   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];
206
   snprintf(buffer, 50, "%s%s%s", Meter_uiName(this), number, mode);
207
208
209
   ListItem* li = ListItem_new(buffer, 0);
   li->moving = moving;
   return li;
Hisham Muhammad's avatar
Hisham Muhammad committed
210
211
}

212
213
/* ---------- TextMeterMode ---------- */

214
static void TextMeterMode_draw(Meter* this, int x, int y, int w) {
215
   char buffer[METER_BUFFER_LEN];
216
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
217
   (void) w;
218
219
220
221
222
223
224

   attrset(CRT_colors[METER_TEXT]);
   mvaddstr(y, x, this->caption);
   int captionLen = strlen(this->caption);
   x += captionLen;
   mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]);
   attrset(CRT_colors[RESET_COLOR]);
225
226
227
228
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
   RichString_printVal(out, y, x);
   RichString_end(out);
229
230
231
232
}

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

233
static char BarMeterMode_characters[] = "|#*@$%&";
234

235
static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
236
   char buffer[METER_BUFFER_LEN];
237
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
238

Hisham Muhammad's avatar
Hisham Muhammad committed
239
240
   w -= 2;
   attrset(CRT_colors[METER_TEXT]);
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
   int captionLen = 3;
   mvaddnstr(y, x, this->caption, captionLen);
Hisham Muhammad's avatar
Hisham Muhammad committed
243
244
245
246
247
248
249
250
   x += captionLen;
   w -= captionLen;
   attrset(CRT_colors[BAR_BORDER]);
   mvaddch(y, x, '[');
   mvaddch(y, x + w, ']');
   
   w--;
   x++;
251
252
253
254
255
256

   if (w < 1) {
      attrset(CRT_colors[RESET_COLOR]);
      return;
   }
   char bar[w + 1];
Hisham Muhammad's avatar
Hisham Muhammad committed
257
258
259
260
261
   
   int blockSizes[10];
   for (int i = 0; i < w; i++)
      bar[i] = ' ';

262
   const size_t barOffset = w - MIN((int)strlen(buffer), w);
263
   snprintf(bar + barOffset, w - barOffset + 1, "%s", buffer);
Hisham Muhammad's avatar
Hisham Muhammad committed
264
265
266

   // First draw in the bar[] buffer...
   int offset = 0;
267
268
   int items = Meter_getItems(this);
   for (int i = 0; i < items; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
269
      double value = this->values[i];
270
271
      value = MAX(value, 0);
      value = MIN(value, this->total);
Hisham Muhammad's avatar
Hisham Muhammad committed
272
273
274
275
276
277
278
      if (value > 0) {
         blockSizes[i] = ceil((value/this->total) * w);
      } else {
         blockSizes[i] = 0;
      }
      int nextOffset = offset + blockSizes[i];
      // (Control against invalid values)
279
      nextOffset = MIN(MAX(nextOffset, 0), w);
Hisham Muhammad's avatar
Hisham Muhammad committed
280
281
282
      for (int j = offset; j < nextOffset; j++)
         if (bar[j] == ' ') {
            if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
283
               bar[j] = BarMeterMode_characters[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
284
285
286
287
288
289
290
291
292
            } else {
               bar[j] = '|';
            }
         }
      offset = nextOffset;
   }

   // ...then print the buffer.
   offset = 0;
293
294
   for (int i = 0; i < items; i++) {
      attrset(CRT_colors[Meter_attributes(this)[i]]);
Hisham Muhammad's avatar
Hisham Muhammad committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
      mvaddnstr(y, x + offset, bar + offset, blockSizes[i]);
      offset += blockSizes[i];
      offset = MAX(offset, 0);
      offset = MIN(offset, w);
   }
   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]);
}

309
310
/* ---------- GraphMeterMode ---------- */

311
312
#ifdef HAVE_LIBNCURSESW

Christian Hesse's avatar
Christian Hesse committed
313
314
315
316
317
318
319
#define PIXPERROW_UTF8 4
static const char* GraphMeterMode_dotsUtf8[] = {
   /*00*/"⠀", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸",
   /*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
320
};
321

322
323
#endif

Christian Hesse's avatar
Christian Hesse committed
324
325
326
327
328
#define PIXPERROW_ASCII 2
static const char* GraphMeterMode_dotsAscii[] = {
   /*00*/" ", /*01*/".", /*02*/":",
   /*10*/".", /*11*/".", /*12*/":",
   /*20*/":", /*21*/":", /*22*/":"
329
330
};

Christian Hesse's avatar
Christian Hesse committed
331
static const char** GraphMeterMode_dots;
Hisham Muhammad's avatar
Hisham Muhammad committed
332
static int GraphMeterMode_pixPerRow;
333

334
static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
335

336
   if (!this->drawData) this->drawData = calloc(1, sizeof(GraphData));
Hisham Muhammad's avatar
Hisham Muhammad committed
337
    GraphData* data = (GraphData*) this->drawData;
338
   const int nValues = METER_BUFFER_LEN;
Hisham Muhammad's avatar
Hisham Muhammad committed
339

340
#ifdef HAVE_LIBNCURSESW
Hisham Muhammad's avatar
Hisham Muhammad committed
341
342
   if (CRT_utf8) {
      GraphMeterMode_dots = GraphMeterMode_dotsUtf8;
Hisham Muhammad's avatar
Hisham Muhammad committed
343
      GraphMeterMode_pixPerRow = PIXPERROW_UTF8;
344
345
346
   } else
#endif
   {
Hisham Muhammad's avatar
Hisham Muhammad committed
347
      GraphMeterMode_dots = GraphMeterMode_dotsAscii;
Hisham Muhammad's avatar
Hisham Muhammad committed
348
      GraphMeterMode_pixPerRow = PIXPERROW_ASCII;
Hisham Muhammad's avatar
Hisham Muhammad committed
349
350
351
352
353
354
355
   }

   attrset(CRT_colors[METER_TEXT]);
   int captionLen = 3;
   mvaddnstr(y, x, this->caption, captionLen);
   x += captionLen;
   w -= captionLen;
356
   
357
358
359
   struct timeval now;
   gettimeofday(&now, NULL);
   if (!timercmp(&now, &(data->time), <)) {
360
      struct timeval delay = { .tv_sec = (int)(CRT_delay/10), .tv_usec = (CRT_delay-((int)(CRT_delay/10)*10)) * 100000 };
361
      timeradd(&now, &delay, &(data->time));
362

363
364
365
366
      for (int i = 0; i < nValues - 1; i++)
         data->values[i] = data->values[i+1];
   
      char buffer[nValues];
367
      Meter_setValues(this, buffer, nValues - 1);
368
369
   
      double value = 0.0;
370
371
      int items = Meter_getItems(this);
      for (int i = 0; i < items; i++)
372
373
374
375
376
         value += this->values[i];
      value /= this->total;
      data->values[nValues - 1] = value;
   }
   
Hisham Muhammad's avatar
Hisham Muhammad committed
377
   for (int i = nValues - (w*2) + 2, k = 0; i < nValues; i+=2, k++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
378
379
380
      const double dot = (1.0 / (GraphMeterMode_pixPerRow * 4));
      int v1 = MIN(GraphMeterMode_pixPerRow * 4, MAX(1, data->values[i] / dot));
      int v2 = MIN(GraphMeterMode_pixPerRow * 4, MAX(1, data->values[i+1] / dot));
Christian Hesse's avatar
Christian Hesse committed
381

Hisham Muhammad's avatar
Hisham Muhammad committed
382
383
      int colorIdx = GRAPH_1;
      for (int line = 0; line < 4; line++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
384
385
         int line1 = MIN(GraphMeterMode_pixPerRow, MAX(0, v1 - (GraphMeterMode_pixPerRow * (3 - line))));
         int line2 = MIN(GraphMeterMode_pixPerRow, MAX(0, v2 - (GraphMeterMode_pixPerRow * (3 - line))));
Christian Hesse's avatar
Christian Hesse committed
386

Hisham Muhammad's avatar
Hisham Muhammad committed
387
         attrset(CRT_colors[colorIdx]);
Hisham Muhammad's avatar
Hisham Muhammad committed
388
         mvaddstr(y+line, x+k, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]);
Hisham Muhammad's avatar
Hisham Muhammad committed
389
390
         colorIdx = GRAPH_2;
      }
391
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
392
393
394
   attrset(CRT_colors[RESET_COLOR]);
}

395
396
/* ---------- LEDMeterMode ---------- */

Christian Hesse's avatar
Christian Hesse committed
397
398
399
400
static const char* LEDMeterMode_digitsAscii[] = {
   " __ ","    "," __ "," __ ","    "," __ "," __ "," __ "," __ "," __ ",
   "|  |","   |"," __|"," __|","|__|","|__ ","|__ ","   |","|__|","|__|",
   "|__|","   |","|__ "," __|","   |"," __|","|__|","   |","|__|"," __|"
401
};
Hisham Muhammad's avatar
Hisham Muhammad committed
402

403
404
#ifdef HAVE_LIBNCURSESW

Christian Hesse's avatar
Christian Hesse committed
405
406
407
408
static const char* LEDMeterMode_digitsUtf8[] = {
   "┌──┐","  ┐ ","╶──┐","╶──┐","╷  ╷","┌──╴","┌──╴","╶──┐","┌──┐","┌──┐",
   "│  │","  │ ","┌──┘"," ──┤","└──┤","└──┐","├──┐","   │","├──┤","└──┤",
   "└──┘","  ╵ ","└──╴","╶──┘","   ╵","╶──┘","└──┘","   ╵","└──┘"," ──┘"
409
410
};

411
412
#endif

Christian Hesse's avatar
Christian Hesse committed
413
static const char** LEDMeterMode_digits;
Hisham Muhammad's avatar
Hisham Muhammad committed
414

415
static void LEDMeterMode_drawDigit(int x, int y, int n) {
Hisham Muhammad's avatar
Hisham Muhammad committed
416
   for (int i = 0; i < 3; i++)
Christian Hesse's avatar
Christian Hesse committed
417
      mvaddstr(y+i, x, LEDMeterMode_digits[i * 10 + n]);
418
419
}

420
static void LEDMeterMode_draw(Meter* this, int x, int y, int w) {
Hisham Muhammad's avatar
Hisham Muhammad committed
421
   (void) w;
Hisham Muhammad's avatar
Hisham Muhammad committed
422

423
424
#ifdef HAVE_LIBNCURSESW
   if (CRT_utf8)
Hisham Muhammad's avatar
Hisham Muhammad committed
425
      LEDMeterMode_digits = LEDMeterMode_digitsUtf8;
426
427
   else
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
428
429
      LEDMeterMode_digits = LEDMeterMode_digitsAscii;

430
   char buffer[METER_BUFFER_LEN];
431
   Meter_setValues(this, buffer, METER_BUFFER_LEN - 1);
432
433
434
   
   RichString_begin(out);
   Meter_displayBuffer(this, buffer, &out);
435

436
437
438
439
440
   int yText =
#ifdef HAVE_LIBNCURSESW
	   CRT_utf8 ? y+1 :
#endif
	   y+2;
Hisham Muhammad's avatar
Hisham Muhammad committed
441
   attrset(CRT_colors[LED_COLOR]);
442
   mvaddstr(yText, x, this->caption);
Hisham Muhammad's avatar
Hisham Muhammad committed
443
   int xx = x + strlen(this->caption);
444
445
446
   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
447
      if (c >= '0' && c <= '9') {
448
449
         LEDMeterMode_drawDigit(xx, y, c-48);
         xx += 4;
Hisham Muhammad's avatar
Hisham Muhammad committed
450
      } else {
451
         mvaddch(yText, xx, c);
Hisham Muhammad's avatar
Hisham Muhammad committed
452
453
454
455
         xx += 1;
      }
   }
   attrset(CRT_colors[RESET_COLOR]);
456
   RichString_end(out);
Hisham Muhammad's avatar
Hisham Muhammad committed
457
458
}

459
460
461
462
463
464
465
466
467
468
469
470
471
472
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
473
   .h = 4,
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
   .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
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520

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