Panel.c 11.3 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
   assert (this != NULL);
202
203
204
205
   if (Vector_size(this->items) > 0)
      return Vector_get(this->items, this->selected);
   else
      return NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
206
207
}

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

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

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

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

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

   return this->selected;
}

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

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

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

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

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

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

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

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

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


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