Panel.c 11.6 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
/*
2
htop - Panel.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
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

8
#include "Panel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9

Hisham Muhammad's avatar
Hisham Muhammad committed
10
11
#include "CRT.h"
#include "RichString.h"
12
#include "ListItem.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13
#include "String.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
14
15
16

#include <math.h>
#include <stdbool.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
17
18
19
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
20
#include <assert.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
21

Hisham Muhammad's avatar
Hisham Muhammad committed
22
23
24
//#link curses

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
25
26
#include "Object.h"
#include "Vector.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
27

28
typedef struct Panel_ Panel;
Hisham Muhammad's avatar
Hisham Muhammad committed
29
30
31
32
33
34
35

typedef enum HandlerResult_ {
   HANDLED,
   IGNORED,
   BREAK_LOOP
} HandlerResult;

36
37
#define EVENT_SETSELECTED -1

38
typedef HandlerResult(*Panel_EventHandler)(Panel*, int);
Hisham Muhammad's avatar
Hisham Muhammad committed
39

40
41
42
43
44
45
46
47
48
typedef struct PanelClass_ {
   const ObjectClass super;
   const Panel_EventHandler eventHandler;
} PanelClass;

#define As_Panel(this_)                ((PanelClass*)((this_)->super.klass))
#define Panel_eventHandlerFn(this_)    As_Panel(this_)->eventHandler
#define Panel_eventHandler(this_, ev_) As_Panel(this_)->eventHandler((Panel*)(this_), ev_)

49
struct Panel_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
50
   Object super;
51
   PanelClass* class;
Hisham Muhammad's avatar
Hisham Muhammad committed
52
53
   int x, y, w, h;
   WINDOW* window;
54
   Vector* items;
Hisham Muhammad's avatar
Hisham Muhammad committed
55
56
   int selected;
   int scrollV, scrollH;
57
   int scrollHAmount;
Hisham Muhammad's avatar
Hisham Muhammad committed
58
59
60
   int oldSelected;
   bool needsRedraw;
   RichString header;
61
   char* eventHandlerBuffer;
Hisham Muhammad's avatar
Hisham Muhammad committed
62
63
64
65
66
67
68
69
70
71
72
};

}*/

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif

73
74
75
76
#define KEY_CTRLN      0016            /* control-n key */
#define KEY_CTRLP      0020            /* control-p key */
#define KEY_CTRLF      0006            /* control-f key */
#define KEY_CTRLB      0002            /* control-b key */
Hisham Muhammad's avatar
Hisham Muhammad committed
77

78
79
80
81
82
83
84
85
86
PanelClass Panel_class = {
   .super = {
      .extends = Class(Object),
      .delete = Panel_delete
   },
   .eventHandler = Panel_selectByTyping
};

Panel* Panel_new(int x, int y, int w, int h, bool owner, ObjectClass* type) {
87
88
   Panel* this;
   this = malloc(sizeof(Panel));
89
   Object_setClass(this, Class(Panel));
90
   Panel_init(this, x, y, w, h, type, owner);
Hisham Muhammad's avatar
Hisham Muhammad committed
91
92
93
   return this;
}

94
95
96
void Panel_delete(Object* cast) {
   Panel* this = (Panel*)cast;
   Panel_done(this);
Hisham Muhammad's avatar
Hisham Muhammad committed
97
98
99
   free(this);
}

100
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner) {
Hisham Muhammad's avatar
Hisham Muhammad committed
101
102
103
104
   this->x = x;
   this->y = y;
   this->w = w;
   this->h = h;
105
   this->eventHandlerBuffer = NULL;
106
   this->items = Vector_new(type, owner, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
107
108
109
110
111
   this->scrollV = 0;
   this->scrollH = 0;
   this->selected = 0;
   this->oldSelected = 0;
   this->needsRedraw = true;
112
   RichString_beginAllocated(this->header);
113
   if (String_eq(CRT_termType, "linux"))
Hisham Muhammad's avatar
Hisham Muhammad committed
114
      this->scrollHAmount = 20;
115
116
   else
      this->scrollHAmount = 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
117
118
}

119
void Panel_done(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
120
   assert (this != NULL);
121
   free(this->eventHandlerBuffer);
122
   Vector_delete(this->items);
123
   RichString_end(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
124
125
}

126
RichString* Panel_getHeader(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
127
128
129
   assert (this != NULL);

   this->needsRedraw = true;
130
   return &(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
131
132
}

Hisham Muhammad's avatar
Hisham Muhammad committed
133
inline void Panel_setHeader(Panel* this, const char* header) {
134
135
   RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
   this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
136
137
}

138
void Panel_move(Panel* this, int x, int y) {
Hisham Muhammad's avatar
Hisham Muhammad committed
139
140
141
142
143
144
145
   assert (this != NULL);

   this->x = x;
   this->y = y;
   this->needsRedraw = true;
}

146
void Panel_resize(Panel* this, int w, int h) {
Hisham Muhammad's avatar
Hisham Muhammad committed
147
148
   assert (this != NULL);

149
   if (RichString_sizeVal(this->header) > 0)
Hisham Muhammad's avatar
Hisham Muhammad committed
150
151
152
153
154
155
      h--;
   this->w = w;
   this->h = h;
   this->needsRedraw = true;
}

156
void Panel_prune(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
157
158
   assert (this != NULL);

159
   Vector_prune(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
160
161
162
163
164
165
   this->scrollV = 0;
   this->selected = 0;
   this->oldSelected = 0;
   this->needsRedraw = true;
}

166
void Panel_add(Panel* this, Object* o) {
Hisham Muhammad's avatar
Hisham Muhammad committed
167
168
   assert (this != NULL);

169
   Vector_add(this->items, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
170
171
172
   this->needsRedraw = true;
}

173
void Panel_insert(Panel* this, int i, Object* o) {
Hisham Muhammad's avatar
Hisham Muhammad committed
174
175
   assert (this != NULL);

176
   Vector_insert(this->items, i, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
177
178
179
   this->needsRedraw = true;
}

180
void Panel_set(Panel* this, int i, Object* o) {
Hisham Muhammad's avatar
Hisham Muhammad committed
181
182
   assert (this != NULL);

183
   Vector_set(this->items, i, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
184
185
}

186
Object* Panel_get(Panel* this, int i) {
Hisham Muhammad's avatar
Hisham Muhammad committed
187
188
   assert (this != NULL);

189
   return Vector_get(this->items, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
190
191
}

192
Object* Panel_remove(Panel* this, int i) {
Hisham Muhammad's avatar
Hisham Muhammad committed
193
194
195
   assert (this != NULL);

   this->needsRedraw = true;
196
197
   Object* removed = Vector_remove(this->items, i);
   if (this->selected > 0 && this->selected >= Vector_size(this->items))
Hisham Muhammad's avatar
Hisham Muhammad committed
198
199
200
201
      this->selected--;
   return removed;
}

202
Object* Panel_getSelected(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
203
   assert (this != NULL);
204
205
206
207
   if (Vector_size(this->items) > 0)
      return Vector_get(this->items, this->selected);
   else
      return NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
208
209
}

210
void Panel_moveSelectedUp(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
211
212
   assert (this != NULL);

213
   Vector_moveUp(this->items, this->selected);
Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
216
217
   if (this->selected > 0)
      this->selected--;
}

218
void Panel_moveSelectedDown(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
219
220
   assert (this != NULL);

221
222
   Vector_moveDown(this->items, this->selected);
   if (this->selected + 1 < Vector_size(this->items))
Hisham Muhammad's avatar
Hisham Muhammad committed
223
224
225
      this->selected++;
}

226
int Panel_getSelectedIndex(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
227
228
229
230
231
   assert (this != NULL);

   return this->selected;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
232
int Panel_size(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
   assert (this != NULL);

235
   return Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
236
237
}

238
void Panel_setSelected(Panel* this, int selected) {
Hisham Muhammad's avatar
Hisham Muhammad committed
239
240
   assert (this != NULL);

241
   selected = MAX(0, MIN(Vector_size(this->items) - 1, selected));
Hisham Muhammad's avatar
Hisham Muhammad committed
242
   this->selected = selected;
243
244
   if (Panel_eventHandlerFn(this)) {
      Panel_eventHandler(this, EVENT_SETSELECTED);
245
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
246
247
}

248
void Panel_draw(Panel* this, bool focus) {
Hisham Muhammad's avatar
Hisham Muhammad committed
249
250
   assert (this != NULL);

251
   int itemCount = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
252
253
   int scrollH = this->scrollH;
   int y = this->y; int x = this->x;
254
   int first = this->scrollV;
255
256
257
258
259
   if (itemCount > this->h && first > itemCount - this->h) {
      first = itemCount - this->h;
      this->scrollV = first;
   }
   int last = MIN(itemCount, first + MIN(itemCount, this->h));
Hisham Muhammad's avatar
Hisham Muhammad committed
260
261
262
263
264
265
266
267
268
269
270
271
272
273
   if (this->selected < first) {
      first = this->selected;
      this->scrollV = first;
      this->needsRedraw = true;
   }
   if (this->selected >= last) {
      last = MIN(itemCount, this->selected + 1);
      first = MAX(0, last - this->h);
      this->scrollV = first;
      this->needsRedraw = true;
   }
   assert(first >= 0);
   assert(last <= itemCount);

274
275
   int headerLen = RichString_sizeVal(this->header);
   if (headerLen > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
276
277
278
279
280
      int attr = focus
               ? CRT_colors[PANEL_HEADER_FOCUS]
               : CRT_colors[PANEL_HEADER_UNFOCUS];
      attrset(attr);
      mvhline(y, x, ' ', this->w);
281
      if (scrollH < headerLen) {
282
         RichString_printoffnVal(this->header, y, x, scrollH,
283
            MIN(headerLen - scrollH, this->w));
Hisham Muhammad's avatar
Hisham Muhammad committed
284
285
286
287
288
289
290
291
292
293
294
295
      }
      attrset(CRT_colors[RESET_COLOR]);
      y++;
   }
   
   int highlight = focus
                 ? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
                 : CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];

   if (this->needsRedraw) {

      for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
296
         Object* itemObj = Vector_get(this->items, i);
297
         assert(itemObj); if(!itemObj) continue;
298
         RichString_begin(item);
299
         Object_display(itemObj, &item);
300
301
         int itemLen = RichString_sizeVal(item);
         int amt = MIN(itemLen - scrollH, this->w);
Hisham Muhammad's avatar
Hisham Muhammad committed
302
303
         if (i == this->selected) {
            attrset(highlight);
304
            RichString_setAttr(&item, highlight);
Hisham Muhammad's avatar
Hisham Muhammad committed
305
306
            mvhline(y + j, x+0, ' ', this->w);
            if (amt > 0)
307
               RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
Hisham Muhammad's avatar
Hisham Muhammad committed
308
309
310
311
            attrset(CRT_colors[RESET_COLOR]);
         } else {
            mvhline(y+j, x+0, ' ', this->w);
            if (amt > 0)
312
               RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
Hisham Muhammad's avatar
Hisham Muhammad committed
313
         }
314
         RichString_end(item);
Hisham Muhammad's avatar
Hisham Muhammad committed
315
316
317
318
319
320
      }
      for (int i = y + (last - first); i < y + this->h; i++)
         mvhline(i, x+0, ' ', this->w);
      this->needsRedraw = false;

   } else {
321
      Object* oldObj = Vector_get(this->items, this->oldSelected);
322
      assert(oldObj);
323
      RichString_begin(old);
324
      Object_display(oldObj, &old);
325
      int oldLen = RichString_sizeVal(old);
326
      Object* newObj = Vector_get(this->items, this->selected);
327
      RichString_begin(new);
328
      Object_display(newObj, &new);
329
      int newLen = RichString_sizeVal(new);
Hisham Muhammad's avatar
Hisham Muhammad committed
330
      mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
331
332
333
      if (scrollH < oldLen)
         RichString_printoffnVal(old, y+this->oldSelected - this->scrollV, x,
            this->scrollH, MIN(oldLen - scrollH, this->w));
Hisham Muhammad's avatar
Hisham Muhammad committed
334
335
      attrset(highlight);
      mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
336
337
338
339
      RichString_setAttr(&new, highlight);
      if (scrollH < newLen)
         RichString_printoffnVal(new, y+this->selected - this->scrollV, x,
            this->scrollH, MIN(newLen - scrollH, this->w));
Hisham Muhammad's avatar
Hisham Muhammad committed
340
      attrset(CRT_colors[RESET_COLOR]);
341
342
      RichString_end(new);
      RichString_end(old);
Hisham Muhammad's avatar
Hisham Muhammad committed
343
344
345
346
347
   }
   this->oldSelected = this->selected;
   move(0, 0);
}

Hisham Muhammad's avatar
Hisham Muhammad committed
348
bool Panel_onKey(Panel* this, int key) {
Hisham Muhammad's avatar
Hisham Muhammad committed
349
350
351
   assert (this != NULL);
   switch (key) {
   case KEY_DOWN:
352
   case KEY_CTRLN:
353
      if (this->selected + 1 < Vector_size(this->items))
Hisham Muhammad's avatar
Hisham Muhammad committed
354
         this->selected++;
Hisham Muhammad's avatar
Hisham Muhammad committed
355
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
356
   case KEY_UP:
357
   case KEY_CTRLP:
Hisham Muhammad's avatar
Hisham Muhammad committed
358
359
      if (this->selected > 0)
         this->selected--;
Hisham Muhammad's avatar
Hisham Muhammad committed
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
      return true;
   #ifdef KEY_C_DOWN
   case KEY_C_DOWN:
      if (this->selected + 1 < Vector_size(this->items)) {
         this->selected++;
         if (this->scrollV < Vector_size(this->items) - this->h) {
            this->scrollV++;
            this->needsRedraw = true;
         }
      }
      return true;
   #endif
   #ifdef KEY_C_UP
   case KEY_C_UP:
      if (this->selected > 0) {
         this->selected--;
         if (this->scrollV > 0) {
            this->scrollV--;
            this->needsRedraw = true;
         }
      }
      return true;
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
383
   case KEY_LEFT:
384
   case KEY_CTRLB:
Hisham Muhammad's avatar
Hisham Muhammad committed
385
      if (this->scrollH > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
386
         this->scrollH -= 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
387
388
         this->needsRedraw = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
389
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
390
   case KEY_RIGHT:
391
   case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
392
      this->scrollH += 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
393
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
394
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
395
   case KEY_PPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
396
397
      this->selected -= (this->h - 1);
      this->scrollV -= (this->h - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
398
399
      if (this->selected < 0)
         this->selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
400
401
402
403
      if (this->scrollV < 0)
         this->scrollV = 0;
      this->needsRedraw = true;
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
404
   case KEY_NPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
405
      this->selected += (this->h - 1);
406
      int size = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
407
408
      if (this->selected >= size)
         this->selected = size - 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
409
410
411
412
413
      this->scrollV += (this->h - 1);
      if (this->scrollV >= MAX(0, size - this->h))
         this->scrollV = MAX(0, size - this->h - 1);
      this->needsRedraw = true;
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
414
415
   case KEY_HOME:
      this->selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
416
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
417
   case KEY_END:
418
      this->selected = Vector_size(this->items) - 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
419
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
420
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
421
   return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
422
}
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457


HandlerResult Panel_selectByTyping(Panel* this, int ch) {
   int size = Panel_size(this);
   if (!this->eventHandlerBuffer)
      this->eventHandlerBuffer = calloc(100, 1);

   if (isalnum(ch)) {
      int len = strlen(this->eventHandlerBuffer);
      if (len < 99) {
         this->eventHandlerBuffer[len] = ch;
         this->eventHandlerBuffer[len+1] = '\0';
      }
      for (int try = 0; try < 2; try++) {
         len = strlen(this->eventHandlerBuffer);
         for (int i = 0; i < size; i++) {
            char* cur = ((ListItem*) Panel_get(this, i))->value;
            while (*cur == ' ') cur++;
            if (strncasecmp(cur, this->eventHandlerBuffer, len) == 0) {
               Panel_setSelected(this, i);
               return HANDLED;
            }
         }
         this->eventHandlerBuffer[0] = ch;
         this->eventHandlerBuffer[1] = '\0';
      }
      return HANDLED;
   } else if (ch != ERR) {
      this->eventHandlerBuffer[0] = '\0';
   }
   if (ch == 13) {
      return BREAK_LOOP;
   }
   return IGNORED;
}