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
#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
21
#include <assert.h>
#include <curses.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
22

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

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

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

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

37
38
#define EVENT_SETSELECTED -1

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

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

}*/

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   return this->selected;
}

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

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

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

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

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

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

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

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

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


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