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
8
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

#include "Object.h"
9
#include "Panel.h"
10
#include "Vector.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
11
12
#include "CRT.h"
#include "RichString.h"
13
#include "ListItem.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
14
15
16
17
18
19
20
21
22
23
24
25

#include <math.h>
#include <stdbool.h>

#include "debug.h"
#include <assert.h>

#include <curses.h>
//#link curses

/*{

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

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

34
35
#define EVENT_SETSELECTED -1

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

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

}*/

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

62
#ifdef DEBUG
63
char* PANEL_CLASS = "Panel";
64
65
66
67
#else
#define PANEL_CLASS NULL
#endif

68
69
70
71
#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
72

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

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

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

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

117
RichString* Panel_getHeader(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
118
119
120
   assert (this != NULL);

   this->needsRedraw = true;
121
   return &(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
122
123
}

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

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

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

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

141
void Panel_resize(Panel* this, int w, int h) {
Hisham Muhammad's avatar
Hisham Muhammad committed
142
143
   assert (this != NULL);

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

151
void Panel_prune(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
152
153
   assert (this != NULL);

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

161
void Panel_add(Panel* this, Object* o) {
Hisham Muhammad's avatar
Hisham Muhammad committed
162
163
   assert (this != NULL);

164
   Vector_add(this->items, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
165
166
167
   this->needsRedraw = true;
}

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

171
   Vector_insert(this->items, i, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
172
173
174
   this->needsRedraw = true;
}

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

178
   Vector_set(this->items, i, o);
Hisham Muhammad's avatar
Hisham Muhammad committed
179
180
}

181
Object* Panel_get(Panel* this, int i) {
Hisham Muhammad's avatar
Hisham Muhammad committed
182
183
   assert (this != NULL);

184
   return Vector_get(this->items, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
185
186
}

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

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

197
Object* Panel_getSelected(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
198
199
   assert (this != NULL);

200
   return Vector_get(this->items, this->selected);
Hisham Muhammad's avatar
Hisham Muhammad committed
201
202
}

203
void Panel_moveSelectedUp(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
204
205
   assert (this != NULL);

206
   Vector_moveUp(this->items, this->selected);
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
209
210
   if (this->selected > 0)
      this->selected--;
}

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

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

219
int Panel_getSelectedIndex(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
220
221
222
223
224
   assert (this != NULL);

   return this->selected;
}

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

228
   return Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
229
230
}

231
void Panel_setSelected(Panel* this, int selected) {
Hisham Muhammad's avatar
Hisham Muhammad committed
232
233
   assert (this != NULL);

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

241
void Panel_draw(Panel* this, bool focus) {
Hisham Muhammad's avatar
Hisham Muhammad committed
242
243
   assert (this != NULL);

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

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

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

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


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