Panel.c 11 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

typedef enum HandlerResult_ {
31
32
33
   HANDLED     = 0x01,
   IGNORED     = 0x02,
   BREAK_LOOP  = 0x04,
34
35
   REDRAW      = 0x08,
   RESCAN      = 0x10,
36
   SYNTH_KEY   = 0x20,
Hisham Muhammad's avatar
Hisham Muhammad committed
37
38
} HandlerResult;

39
40
#define EVENT_SETSELECTED -1

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

43
44
45
46
47
48
49
50
51
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_)

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

}*/

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

76
77
78
79
#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
80

81
82
83
84
85
86
87
88
89
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) {
90
91
   Panel* this;
   this = malloc(sizeof(Panel));
92
   Object_setClass(this, Class(Panel));
93
   Panel_init(this, x, y, w, h, type, owner);
Hisham Muhammad's avatar
Hisham Muhammad committed
94
95
96
   return this;
}

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

103
void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool owner) {
Hisham Muhammad's avatar
Hisham Muhammad committed
104
105
106
107
   this->x = x;
   this->y = y;
   this->w = w;
   this->h = h;
Hisham Muhammad's avatar
Hisham Muhammad committed
108
   this->eventHandlerState = NULL;
109
   this->items = Vector_new(type, owner, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
110
111
112
113
114
   this->scrollV = 0;
   this->scrollH = 0;
   this->selected = 0;
   this->oldSelected = 0;
   this->needsRedraw = true;
115
   RichString_beginAllocated(this->header);
Hisham Muhammad's avatar
Hisham Muhammad committed
116
117
}

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

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

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

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

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

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

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

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

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

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

   return this->selected;
}

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

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
252
   int size = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
253
   int scrollH = this->scrollH;
Hisham Muhammad's avatar
Hisham Muhammad committed
254
255
256
   int y = this->y;
   int x = this->x;
   int h = this->h;
Hisham Muhammad's avatar
Hisham Muhammad committed
257

258
259
   int headerLen = RichString_sizeVal(this->header);
   if (headerLen > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
260
261
262
263
264
      int attr = focus
               ? CRT_colors[PANEL_HEADER_FOCUS]
               : CRT_colors[PANEL_HEADER_UNFOCUS];
      attrset(attr);
      mvhline(y, x, ' ', this->w);
265
      if (scrollH < headerLen) {
266
         RichString_printoffnVal(this->header, y, x, scrollH,
267
            MIN(headerLen - scrollH, this->w));
Hisham Muhammad's avatar
Hisham Muhammad committed
268
269
270
271
      }
      attrset(CRT_colors[RESET_COLOR]);
      y++;
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

   // ensure scroll area is on screen
   if (this->scrollV < 0) {
      this->scrollV = 0;
      this->needsRedraw = true;
   } else if (this->scrollV >= size) {
      this->scrollV = MAX(size - 1, 0);
      this->needsRedraw = true;
   }
   // ensure selection is on screen
   if (this->selected < this->scrollV) {
      this->scrollV = this->selected;
      this->needsRedraw = true;
   } else if (this->selected >= this->scrollV + h) {
      this->scrollV = this->selected - h + 1;
      this->needsRedraw = true;
   }

   int first = this->scrollV;
   int upTo = MIN(first + h, size);

Hisham Muhammad's avatar
Hisham Muhammad committed
293
294
295
296
297
   int highlight = focus
                 ? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
                 : CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
353
bool Panel_onKey(Panel* this, int key) {
Hisham Muhammad's avatar
Hisham Muhammad committed
354
   assert (this != NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
355
356
   
   int size = Vector_size(this->items);
Hisham Muhammad's avatar
Hisham Muhammad committed
357
358
   switch (key) {
   case KEY_DOWN:
359
   case KEY_CTRLN:
Hisham Muhammad's avatar
Hisham Muhammad committed
360
361
      this->selected++;
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
362
   case KEY_UP:
363
   case KEY_CTRLP:
Hisham Muhammad's avatar
Hisham Muhammad committed
364
365
      this->selected--;
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
366
367
   #ifdef KEY_C_DOWN
   case KEY_C_DOWN:
Hisham Muhammad's avatar
Hisham Muhammad committed
368
369
      this->selected++;
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
370
371
372
   #endif
   #ifdef KEY_C_UP
   case KEY_C_UP:
Hisham Muhammad's avatar
Hisham Muhammad committed
373
374
      this->selected--;
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
375
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
376
   case KEY_LEFT:
377
   case KEY_CTRLB:
Hisham Muhammad's avatar
Hisham Muhammad committed
378
      if (this->scrollH > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
379
         this->scrollH -= CRT_scrollHAmount;
Hisham Muhammad's avatar
Hisham Muhammad committed
380
381
         this->needsRedraw = true;
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
382
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
383
   case KEY_RIGHT:
384
   case KEY_CTRLF:
Hisham Muhammad's avatar
Hisham Muhammad committed
385
      this->scrollH += CRT_scrollHAmount;
Hisham Muhammad's avatar
Hisham Muhammad committed
386
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
387
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
388
   case KEY_PPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
389
390
391
      this->selected -= (this->h - 1);
      this->scrollV -= (this->h - 1);
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
392
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
393
   case KEY_NPAGE:
Hisham Muhammad's avatar
Hisham Muhammad committed
394
395
396
      this->selected += (this->h - 1);
      this->scrollV += (this->h - 1);
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
397
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
398
399
   case KEY_HOME:
      this->selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
400
      break;
Hisham Muhammad's avatar
Hisham Muhammad committed
401
   case KEY_END:
Hisham Muhammad's avatar
Hisham Muhammad committed
402
403
404
405
406
407
408
409
410
411
412
413
414
      this->selected = size - 1;
      break;
   default:
      return false;
   }

   // ensure selection within bounds
   if (this->selected < 0) {
      this->selected = 0;
      this->needsRedraw = true;
   } else if (this->selected >= size) {   
      this->selected = size - 1;
      this->needsRedraw = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
415
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
416
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
417
}
418
419
420
421


HandlerResult Panel_selectByTyping(Panel* this, int ch) {
   int size = Panel_size(this);
Hisham Muhammad's avatar
Hisham Muhammad committed
422
423
424
   if (!this->eventHandlerState)
      this->eventHandlerState = calloc(100, 1);
   char* buffer = this->eventHandlerState;
425
426

   if (isalnum(ch)) {
Hisham Muhammad's avatar
Hisham Muhammad committed
427
      int len = strlen(buffer);
428
      if (len < 99) {
Hisham Muhammad's avatar
Hisham Muhammad committed
429
430
         buffer[len] = ch;
         buffer[len+1] = '\0';
431
432
      }
      for (int try = 0; try < 2; try++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
433
         len = strlen(buffer);
434
435
436
         for (int i = 0; i < size; i++) {
            char* cur = ((ListItem*) Panel_get(this, i))->value;
            while (*cur == ' ') cur++;
Hisham Muhammad's avatar
Hisham Muhammad committed
437
            if (strncasecmp(cur, buffer, len) == 0) {
438
439
440
441
               Panel_setSelected(this, i);
               return HANDLED;
            }
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
442
443
444
445
         // if current word did not match,
         // retry considering the character the start of a new word.
         buffer[0] = ch;
         buffer[1] = '\0';
446
447
448
      }
      return HANDLED;
   } else if (ch != ERR) {
Hisham Muhammad's avatar
Hisham Muhammad committed
449
      buffer[0] = '\0';
450
451
452
453
454
455
   }
   if (ch == 13) {
      return BREAK_LOOP;
   }
   return IGNORED;
}