Panel.c 11.5 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
31
32
33
34
35

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

36
37
#define EVENT_SETSELECTED -1

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

40
41
42
43
44
45
46
47
48
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_)

49
struct Panel_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
50
   Object super;
51
   PanelClass* class;
Hisham Muhammad's avatar
Hisham Muhammad committed
52
53
   int x, y, w, h;
   WINDOW* window;
54
   Vector* items;
Hisham Muhammad's avatar
Hisham Muhammad committed
55
56
   int selected;
   int oldSelected;
Hisham Muhammad's avatar
Hisham Muhammad committed
57
58
59
   char* eventHandlerBuffer;
   int scrollV;
   short scrollH;
Hisham Muhammad's avatar
Hisham Muhammad committed
60
61
62
63
64
65
66
67
68
69
70
71
72
   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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

198
Object* Panel_getSelected(Panel* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
199
   assert (this != NULL);
200
201
202
203
   if (Vector_size(this->items) > 0)
      return Vector_get(this->items, this->selected);
   else
      return NULL;
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
238
239
   selected = MIN(Vector_size(this->items) - 1, selected);
   if (selected < 0)
      selected = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
240
   this->selected = selected;
241
242
   if (Panel_eventHandlerFn(this)) {
      Panel_eventHandler(this, EVENT_SETSELECTED);
243
   }
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
   int first = this->scrollV;
253
254
255
256
257
   if (itemCount > this->h && first > itemCount - this->h) {
      first = itemCount - this->h;
      this->scrollV = first;
   }
   int last = MIN(itemCount, first + MIN(itemCount, this->h));
Hisham Muhammad's avatar
Hisham Muhammad committed
258
259
260
261
262
263
264
   if (this->selected < first) {
      first = this->selected;
      this->scrollV = first;
      this->needsRedraw = true;
   }
   if (this->selected >= last) {
      last = MIN(itemCount, this->selected + 1);
265
      first = last - this->h;
Hisham Muhammad's avatar
Hisham Muhammad committed
266
267
268
      this->scrollV = first;
      this->needsRedraw = true;
   }
269
270
271
272
   if (first < 0)
      first = 0;
   if (last > itemCount)
      last = itemCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
273

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

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

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


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