Panel.c 11.2 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
14
#include "String.h"
#include "debug.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
15
16
17

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

Hisham Muhammad's avatar
Hisham Muhammad committed
24
25
26
//#link curses

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

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

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

38
39
#define EVENT_SETSELECTED -1

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

42
struct Panel_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
43
44
45
   Object super;
   int x, y, w, h;
   WINDOW* window;
46
   Vector* items;
Hisham Muhammad's avatar
Hisham Muhammad committed
47
48
   int selected;
   int scrollV, scrollH;
49
   int scrollHAmount;
Hisham Muhammad's avatar
Hisham Muhammad committed
50
51
52
   int oldSelected;
   bool needsRedraw;
   RichString header;
53
   Panel_EventHandler eventHandler;
54
   char* eventHandlerBuffer;
Hisham Muhammad's avatar
Hisham Muhammad committed
55
56
57
58
59
60
61
62
63
64
65
};

}*/

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

66
#ifdef DEBUG
67
char* PANEL_CLASS = "Panel";
68
69
70
71
#else
#define PANEL_CLASS NULL
#endif

72
73
74
75
#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
76

77
Panel* Panel_new(int x, int y, int w, int h, char* type, bool owner, Object_Compare compare) {
78
79
80
   Panel* this;
   this = malloc(sizeof(Panel));
   Panel_init(this, x, y, w, h, type, owner);
81
   this->items->compare = compare;
Hisham Muhammad's avatar
Hisham Muhammad committed
82
83
84
   return this;
}

85
86
87
void Panel_delete(Object* cast) {
   Panel* this = (Panel*)cast;
   Panel_done(this);
Hisham Muhammad's avatar
Hisham Muhammad committed
88
89
90
   free(this);
}

91
void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner) {
Hisham Muhammad's avatar
Hisham Muhammad committed
92
   Object* super = (Object*) this;
93
   Object_setClass(this, PANEL_CLASS);
94
   super->delete = Panel_delete;
Hisham Muhammad's avatar
Hisham Muhammad committed
95
96
97
98
99
   this->x = x;
   this->y = y;
   this->w = w;
   this->h = h;
   this->eventHandler = NULL;
100
   this->eventHandlerBuffer = NULL;
101
   this->items = Vector_new(type, owner, DEFAULT_SIZE, ListItem_compare);
Hisham Muhammad's avatar
Hisham Muhammad committed
102
103
104
105
106
   this->scrollV = 0;
   this->scrollH = 0;
   this->selected = 0;
   this->oldSelected = 0;
   this->needsRedraw = true;
107
   RichString_beginAllocated(this->header);
108
   if (String_eq(CRT_termType, "linux"))
Hisham Muhammad's avatar
Hisham Muhammad committed
109
      this->scrollHAmount = 20;
110
111
   else
      this->scrollHAmount = 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
112
113
}

114
void Panel_done(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
115
   assert (this != NULL);
116
   free(this->eventHandlerBuffer);
117
   Vector_delete(this->items);
118
   RichString_end(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
119
120
}

121
RichString* Panel_getHeader(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
122
123
124
   assert (this != NULL);

   this->needsRedraw = true;
125
   return &(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
126
127
}

Hisham Muhammad's avatar
Hisham Muhammad committed
128
inline void Panel_setHeader(Panel* this, const char* header) {
129
130
   RichString_write(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
   this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
131
132
}

133
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) {
Hisham Muhammad's avatar
Hisham Muhammad committed
134
135
136
   this->eventHandler = eh;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

201
Object* Panel_getSelected(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
202
203
   assert (this != NULL);

204
   return Vector_get(this->items, this->selected);
Hisham Muhammad's avatar
Hisham Muhammad committed
205
206
}

207
void Panel_moveSelectedUp(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
208
209
   assert (this != NULL);

210
   Vector_moveUp(this->items, this->selected);
Hisham Muhammad's avatar
Hisham Muhammad committed
211
212
213
214
   if (this->selected > 0)
      this->selected--;
}

215
void Panel_moveSelectedDown(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
216
217
   assert (this != NULL);

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

223
int Panel_getSelectedIndex(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
224
225
226
227
228
   assert (this != NULL);

   return this->selected;
}

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

232
   return Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
}

235
void Panel_setSelected(Panel* this, int selected) {
Hisham Muhammad's avatar
Hisham Muhammad committed
236
237
   assert (this != NULL);

238
   selected = MAX(0, MIN(Vector_size(this->items) - 1, selected));
Hisham Muhammad's avatar
Hisham Muhammad committed
239
   this->selected = selected;
240
241
242
   if (this->eventHandler) {
      this->eventHandler(this, EVENT_SETSELECTED);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
243
244
}

245
void Panel_draw(Panel* this, bool focus) {
Hisham Muhammad's avatar
Hisham Muhammad committed
246
247
   assert (this != NULL);

248
   int itemCount = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
249
250
   int scrollH = this->scrollH;
   int y = this->y; int x = this->x;
251
252
   int first = this->scrollV;
   int last = MIN(itemCount, this->scrollV + MIN(itemCount, this->h));
Hisham Muhammad's avatar
Hisham Muhammad committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
   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);

267
268
   int headerLen = RichString_sizeVal(this->header);
   if (headerLen > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
269
270
271
272
273
      int attr = focus
               ? CRT_colors[PANEL_HEADER_FOCUS]
               : CRT_colors[PANEL_HEADER_UNFOCUS];
      attrset(attr);
      mvhline(y, x, ' ', this->w);
274
      if (scrollH < headerLen) {
275
         RichString_printoffnVal(this->header, y, x, scrollH,
276
            MIN(headerLen - scrollH, this->w));
Hisham Muhammad's avatar
Hisham Muhammad committed
277
278
279
280
281
282
283
284
285
286
287
288
      }
      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++) {
289
         Object* itemObj = Vector_get(this->items, i);
290
291
292
293
         RichString_begin(item);
         itemObj->display(itemObj, &item);
         int itemLen = RichString_sizeVal(item);
         int amt = MIN(itemLen - scrollH, this->w);
Hisham Muhammad's avatar
Hisham Muhammad committed
294
295
         if (i == this->selected) {
            attrset(highlight);
296
            RichString_setAttr(&item, highlight);
Hisham Muhammad's avatar
Hisham Muhammad committed
297
298
            mvhline(y + j, x+0, ' ', this->w);
            if (amt > 0)
299
               RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
Hisham Muhammad's avatar
Hisham Muhammad committed
300
301
302
303
            attrset(CRT_colors[RESET_COLOR]);
         } else {
            mvhline(y+j, x+0, ' ', this->w);
            if (amt > 0)
304
               RichString_printoffnVal(item, y+j, x+0, scrollH, amt);
Hisham Muhammad's avatar
Hisham Muhammad committed
305
         }
306
         RichString_end(item);
Hisham Muhammad's avatar
Hisham Muhammad committed
307
308
309
310
311
312
      }
      for (int i = y + (last - first); i < y + this->h; i++)
         mvhline(i, x+0, ' ', this->w);
      this->needsRedraw = false;

   } else {
313
      Object* oldObj = Vector_get(this->items, this->oldSelected);
314
315
316
      RichString_begin(old);
      oldObj->display(oldObj, &old);
      int oldLen = RichString_sizeVal(old);
317
      Object* newObj = Vector_get(this->items, this->selected);
318
319
320
      RichString_begin(new);
      newObj->display(newObj, &new);
      int newLen = RichString_sizeVal(new);
Hisham Muhammad's avatar
Hisham Muhammad committed
321
      mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
322
323
324
      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
325
326
      attrset(highlight);
      mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
327
328
329
330
      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
331
      attrset(CRT_colors[RESET_COLOR]);
332
333
      RichString_end(new);
      RichString_end(old);
Hisham Muhammad's avatar
Hisham Muhammad committed
334
335
336
337
338
   }
   this->oldSelected = this->selected;
   move(0, 0);
}

Hisham Muhammad's avatar
Hisham Muhammad committed
339
bool Panel_onKey(Panel* this, int key) {
Hisham Muhammad's avatar
Hisham Muhammad committed
340
341
342
   assert (this != NULL);
   switch (key) {
   case KEY_DOWN:
343
   case KEY_CTRLN:
344
      if (this->selected + 1 < Vector_size(this->items))
Hisham Muhammad's avatar
Hisham Muhammad committed
345
         this->selected++;
Hisham Muhammad's avatar
Hisham Muhammad committed
346
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
347
   case KEY_UP:
348
   case KEY_CTRLP:
Hisham Muhammad's avatar
Hisham Muhammad committed
349
350
      if (this->selected > 0)
         this->selected--;
Hisham Muhammad's avatar
Hisham Muhammad committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
      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
374
   case KEY_LEFT:
375
   case KEY_CTRLB:
Hisham Muhammad's avatar
Hisham Muhammad committed
376
      if (this->scrollH > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
377
         this->scrollH -= 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
378
379
         this->needsRedraw = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
380
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
381
   case KEY_RIGHT:
382
   case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
383
      this->scrollH += 5;
Hisham Muhammad's avatar
Hisham Muhammad committed
384
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
385
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
386
   case KEY_PPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
387
388
      this->selected -= (this->h - 1);
      this->scrollV -= (this->h - 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
389
390
      if (this->selected < 0)
         this->selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
391
392
393
394
      if (this->scrollV < 0)
         this->scrollV = 0;
      this->needsRedraw = true;
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
395
   case KEY_NPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
396
      this->selected += (this->h - 1);
397
      int size = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
398
399
      if (this->selected >= size)
         this->selected = size - 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
400
401
402
403
404
      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
405
406
   case KEY_HOME:
      this->selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
407
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
408
   case KEY_END:
409
      this->selected = Vector_size(this->items) - 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
410
      return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
411
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
412
   return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
413
}
414
415
416
417
418
419
420
421
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


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;
}