/[gentoo-src]/ufed/ufed-curses.c
Gentoo

Contents of /ufed/ufed-curses.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.29 - (show annotations) (download) (as text)
Fri Mar 17 15:19:30 2006 UTC (8 years, 6 months ago) by truedfx
Branch: MAIN
CVS Tags: HEAD
Changes since 1.28: +2 -2 lines
File MIME type: text/x-csrc
Don't assume *addch at end-of-line places the cursor on the next

1 #include "ufed-curses.h"
2
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <locale.h>
8
9 struct window window[wCount] = {
10 { NULL, 0, 0, 5, 0 }, /* Top */
11 { NULL, 5, 0, -8, 3 }, /* Left */
12 { NULL, 5, 3, -9, -6 }, /* List */
13 { NULL, -4, 3, 1, -6 }, /* Input */
14 { NULL, 5, -3, -8, 1 }, /* Scrollbar */
15 { NULL, 5, -2, -8, 2 }, /* Right */
16 { NULL, -3, 0, 3, 0 }, /* Bottom */
17 };
18
19 static const char *subtitle;
20
21 static const struct key *keys;
22
23 static struct item *items, *currentitem;
24 int topy, minheight, minwidth;
25
26 static void checktermsize(void);
27
28 void initcurses(void) {
29 setlocale(LC_CTYPE, "");
30 initscr();
31 start_color();
32 cbreak();
33 noecho();
34 keypad(stdscr, TRUE);
35 init_pair(1, COLOR_CYAN, COLOR_BLUE);
36 init_pair(2, COLOR_WHITE, COLOR_WHITE);
37 init_pair(3, COLOR_BLACK, COLOR_WHITE);
38 init_pair(4, COLOR_RED, COLOR_WHITE);
39 #ifdef NCURSES_MOUSE_VERSION
40 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON1_PRESSED | BUTTON1_RELEASED, NULL);
41 #endif
42 checktermsize();
43 { enum win w; for(w = (enum win) 0; w != wCount; w++) {
44 window[w].win = newwin(wHeight(w), wWidth(w), wTop(w), wLeft(w));
45 } }
46 }
47
48 void cursesdone(void) {
49 enum win w;
50 for(w = (enum win) 0; w != wCount; w++)
51 delwin(window[w].win);
52 endwin();
53 }
54
55 static void checktermsize(void) {
56 while(wHeight(List) < minheight
57 || wWidth(List) < minwidth) {
58 #ifdef KEY_RESIZE
59 clear();
60 attrset(0);
61 mvaddstr(0, 0, "Your screen is too small. Press Ctrl+C to exit.");
62 while(getch()!=KEY_RESIZE) {}
63 #else
64 cursesdone();
65 fputs("Your screen is too small.\n", stderr);
66 exit(-1);
67 #endif
68 }
69 }
70
71 static void (*drawitem)(struct item *, bool);
72
73 static void drawitems(void) {
74 struct item *item;
75 int y;
76
77 item = currentitem;
78 while((y=item->top-topy) > 0)
79 item = item->prev;
80
81 for(;;) {
82 if(item!=currentitem)
83 (*drawitem)(item, FALSE);
84 y += item->height;
85 item = item->next;
86 if(y>=wHeight(List))
87 break;
88 if(item==items) {
89 #if C99
90 char buf[wWidth(List)];
91 #else
92 char *buf = __builtin_alloca(wWidth(List));
93 #endif
94 memset(buf, ' ', wWidth(List));
95 buf[wWidth(List)] = '\0';
96 wmove(win(List), y, 0);
97 wattrset(win(List), COLOR_PAIR(3));
98 while(y++ < wHeight(List))
99 waddstr(win(List), buf);
100 break;
101 }
102 }
103 (*drawitem)(currentitem, TRUE);
104 wnoutrefresh(win(List));
105 }
106
107 static void drawscrollbar(void) {
108 WINDOW *w = win(Scrollbar);
109 wattrset(w, COLOR_PAIR(3) | A_BOLD);
110 mvwaddch(w, 0, 0, ACS_UARROW);
111 mvwvline(w, 1, 0, ACS_CKBOARD, wHeight(Scrollbar)-3);
112 mvwaddch(w, 1+(wHeight(Scrollbar)-3)*topy/(items->prev->top+items->prev->height-(wHeight(List)-1)), 0, ACS_BLOCK);
113 mvwaddch(w, wHeight(Scrollbar)-2, 0, ACS_DARROW);
114 mvwaddch(w, wHeight(Scrollbar)-1, 0, ACS_VLINE);
115 wnoutrefresh(w);
116 }
117
118 static void draw(void) {
119 #if C99
120 char buf[COLS+1];
121 #else
122 char *buf = __builtin_alloca(COLS+1);
123 #endif
124 WINDOW *w;
125
126 wnoutrefresh(stdscr);
127
128 w = win(Top);
129
130 wattrset(w, COLOR_PAIR(1) | A_BOLD);
131 sprintf(buf, "%-*.*s", wWidth(Top), wWidth(Top), "Gentoo USE flags editor 0.40");
132 mvwaddstr(w, 0, 0, buf);
133
134 mvwhline(w, 1, 0, ACS_HLINE, wWidth(Top));
135
136 wattrset(w, COLOR_PAIR(2) | A_BOLD);
137 mvwaddch(w, 2, 0, ACS_ULCORNER);
138 whline(w, ACS_HLINE, wWidth(Top)-2);
139 mvwaddch(w, 2, wWidth(Top)-1, ACS_URCORNER);
140
141 waddch(w, ACS_VLINE);
142 wattrset(w, COLOR_PAIR(3));
143 sprintf(buf, " %-*.*s ", wWidth(Top)-4, wWidth(Top)-4, subtitle);
144 waddstr(w, buf);
145 wattrset(w, COLOR_PAIR(2) | A_BOLD);
146 waddch(w, ACS_VLINE);
147
148 /* maybe this should be based on List? */
149 waddch(w, ACS_VLINE);
150 wattrset(w, COLOR_PAIR(3));
151 waddch(w, ' ');
152 waddch(w, ACS_ULCORNER);
153 whline(w, ACS_HLINE, wWidth(Top)-6);
154 mvwaddch(w, 4, wWidth(Top)-3, ACS_URCORNER);
155 waddch(w, ' ');
156 wattrset(w, COLOR_PAIR(2) | A_BOLD);
157 waddch(w, ACS_VLINE);
158
159 wnoutrefresh(w);
160
161 w = win(Left);
162 wattrset(w, COLOR_PAIR(2) | A_BOLD);
163 mvwvline(w, 0, 0, ACS_VLINE, wHeight(Left));
164 wattrset(w, COLOR_PAIR(3));
165 mvwvline(w, 0, 1, ' ', wHeight(Left));
166 mvwvline(w, 0, 2, ACS_VLINE, wHeight(Left));
167 wnoutrefresh(w);
168
169 w = win(Right);
170 wattrset(w, COLOR_PAIR(2) | A_BOLD);
171 mvwvline(w, 0, 0, ' ', wHeight(Right));
172 mvwvline(w, 0, 1, ACS_VLINE, wHeight(Right));
173 wnoutrefresh(w);
174
175 w = win(Bottom);
176
177 wattrset(w, COLOR_PAIR(2) | A_BOLD);
178 mvwaddch(w, 0, 0, ACS_VLINE);
179 wattrset(w, COLOR_PAIR(3));
180 waddch(w, ' ');
181 waddch(w, ACS_LLCORNER);
182 whline(w, ACS_HLINE, wWidth(Bottom)-6);
183 mvwaddch(w, 0, wWidth(Bottom)-3, ACS_LRCORNER);
184 waddch(w, ' ');
185 wattrset(w, COLOR_PAIR(2) | A_BOLD);
186 waddch(w, ACS_VLINE);
187
188 waddch(w, ACS_VLINE);
189 wattrset(w, COLOR_PAIR(3));
190 {
191 char *p = buf;
192 const struct key *key;
193 *p++ = ' ';
194 for(key=keys; key->key!='\0'; key++) {
195 int n = (buf+wWidth(Bottom)-3) - p;
196 if(n > key->length)
197 n = key->length;
198 memcpy(p, key->descr, n);
199 p += n;
200 *p++ = ' ';
201 if(p == buf+wWidth(Bottom)-3)
202 break;
203 }
204 memset(p, ' ', buf+wWidth(Bottom)-2-p);
205 buf[wWidth(Bottom)-2] = '\0';
206 }
207 waddstr(w, buf);
208 wattrset(w, COLOR_PAIR(2) | A_BOLD);
209 waddch(w, ACS_VLINE);
210
211 waddch(w, ACS_LLCORNER);
212 whline(w, ACS_HLINE, wWidth(Bottom)-2);
213 mvwhline(w, 2, wWidth(Bottom)-1, ACS_LRCORNER, 1);
214
215 wnoutrefresh(w);
216
217 w = win(Input);
218 wattrset(w, COLOR_PAIR(3));
219 mvwhline(w, 0, 0, ' ', wWidth(Input));
220 wnoutrefresh(w);
221
222 drawitems();
223 drawscrollbar();
224
225 wrefresh(win(List));
226 }
227
228 void scrollcurrent(void) {
229 int oldtopy = topy;
230 if(currentitem->top < topy)
231 topy = currentitem->top;
232 else if(currentitem->top+currentitem->height > topy+wHeight(List))
233 topy = currentitem->top+currentitem->height-wHeight(List);
234 else
235 return;
236 if(abs(topy-oldtopy)>wHeight(List)) {
237 drawitems();
238 } else {
239 struct item *item = currentitem;
240 scrollok(win(List), TRUE);
241 wscrl(win(List), topy-oldtopy);
242 scrollok(win(List), FALSE);
243 if(topy<oldtopy)
244 while((item=item->next)!=items
245 && item->top < oldtopy
246 && item->top < topy + wHeight(List))
247 (*drawitem)(item, FALSE);
248 else
249 while((item=item->prev)->next!=items
250 && item->top > oldtopy
251 && item->top + item->height-1 >= topy)
252 (*drawitem)(item, FALSE);
253 mvwhline(win(List), wHeight(List), 0, ' ', wWidth(List));
254 }
255 drawscrollbar();
256 }
257
258 bool yesno(const char *prompt) {
259 wattrset(win(Input), COLOR_PAIR(4) | A_BOLD | A_REVERSE);
260 mvwhline(win(Input), 0, 0, ' ', wWidth(Input));
261 waddstr(win(Input), prompt);
262 whline(win(Input), 'Y', 1);
263 wrefresh(win(Input));
264 for(;;) switch(getch()) {
265 case '\n': case KEY_ENTER:
266 case 'Y': case 'y':
267 return TRUE;
268 case '\033':
269 case 'N': case 'n':
270 wattrset(win(Input), COLOR_PAIR(3));
271 mvwhline(win(Input), 0, 0, ' ', wWidth(Input));
272 wnoutrefresh(win(Input));
273 wrefresh(win(List));
274 return FALSE;
275 #ifdef KEY_RESIZE
276 case KEY_RESIZE:
277 resizeterm(LINES, COLS);
278 checktermsize();
279 { enum win w; for(w = (enum win) 0; w != wCount; w++) {
280 delwin(window[w].win);
281 window[w].win = newwin(wHeight(w), wWidth(w), wTop(w), wLeft(w));
282 } }
283 /* this won't work for the help viewer, but it doesn't use yesno() */
284 currentitem = items;
285 topy = 0;
286 draw();
287 wattrset(win(Input), COLOR_PAIR(4) | A_BOLD | A_REVERSE);
288 mvwhline(win(Input), 0, 0, ' ', wWidth(Input));
289 waddstr(win(Input), prompt);
290 whline(win(Input), 'Y', 1);
291 wrefresh(win(Input));
292 break;
293 #endif
294 }
295 }
296
297 int maineventloop(
298 const char *_subtitle,
299 int(*_callback)(struct item **, int),
300 void(*_drawitem)(struct item *, bool),
301 struct item *_items,
302 const struct key *_keys) {
303 int result;
304
305 { const char *temp = subtitle;
306 subtitle=_subtitle;
307 _subtitle=temp; }
308 { void(*temp)(struct item *, bool) = drawitem;
309 drawitem=_drawitem;
310 _drawitem=temp; }
311 { struct item *temp=items;
312 items=_items;
313 _items=temp; }
314 { const struct key *temp=keys;
315 keys=_keys;
316 _keys=temp; }
317
318 currentitem = items;
319 topy = 0;
320
321 draw();
322
323 for(;;) {
324 int c = getch();
325 #ifndef NCURSES_MOUSE_VERSION
326 if(c==ERR)
327 continue;
328 #else
329 static int mousekey = ERR;
330 if(c==ERR) {
331 if(errno!=EINTR && mousekey!=ERR)
332 c = mousekey;
333 else
334 continue;
335 }
336
337 check_key:
338 if(c==KEY_MOUSE) {
339 MEVENT event;
340 if(getmouse(&event)==OK) {
341 if(mousekey != ERR && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON1_RELEASED)) {
342 cbreak();
343 mousekey = ERR;
344 if(!(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)))
345 continue;
346 }
347 if(wmouse_trafo(win(List), &event.y, &event.x, FALSE)) {
348 if(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)) {
349 struct item *item = currentitem;
350 if(currentitem->top-topy > event.y) {
351 do item = item->prev;
352 while((item==items ? item=NULL, 0 : 1)
353 && item->top-topy > event.y);
354 } else if(currentitem->top-topy+currentitem->height-1 < event.y) {
355 do item = item->next;
356 while((item->next==items ? item=NULL, 0 : 1)
357 && item->top-topy+item->height-1 < event.y);
358 }
359 if(item==NULL)
360 continue;
361 (*drawitem)(currentitem, FALSE);
362 currentitem = item;
363 if(event.bstate & BUTTON1_DOUBLE_CLICKED) {
364 result=(*_callback)(&currentitem, KEY_MOUSE);
365 if(result>=0)
366 goto exit;
367 }
368 scrollcurrent();
369 (*drawitem)(currentitem, TRUE);
370 }
371 } else if(wmouse_trafo(win(Scrollbar), &event.y, &event.x, FALSE)) {
372 if(event.bstate & (BUTTON1_PRESSED | BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)
373 && event.y < wHeight(Scrollbar)-1) {
374 halfdelay(1);
375
376 #define SIM(key) \
377 { \
378 c = KEY_ ## key; \
379 if(event.bstate & BUTTON1_PRESSED) \
380 mousekey = c; \
381 goto check_key; \
382 }
383 if(event.y == 0)
384 SIM(UP)
385 else if(event.y == wHeight(Scrollbar)-2)
386 SIM(DOWN)
387 else if(event.y-1 < (wHeight(Scrollbar)-3)*topy/(items->prev->top+items->prev->height-(wHeight(List)-1)))
388 SIM(PPAGE)
389 else if(event.y-1 > (wHeight(Scrollbar)-3)*topy/(items->prev->top+items->prev->height-(wHeight(List)-1)))
390 SIM(NPAGE)
391 #undef SIM
392 else
393 if(event.bstate & BUTTON1_PRESSED) {
394 for(;;) {
395 c = getch();
396 switch(c) {
397 default:
398 goto check_key;
399 case ERR:
400 continue;
401 case KEY_MOUSE:
402 if(getmouse(&event)==OK) {
403 event.y -= wTop(Scrollbar)+1;
404 if(event.y>=0 && event.y<wHeight(Scrollbar)-3) {
405 topy = (event.y*(items->prev->top+items->prev->height-(wHeight(List)-1))+(wHeight(Scrollbar)-4))/(wHeight(Scrollbar)-3);
406 while(currentitem!=items
407 && currentitem->prev->top >= topy)
408 currentitem = currentitem->prev;
409 while(currentitem->next!=items
410 && currentitem->top < topy)
411 currentitem = currentitem->next;
412 if(currentitem->top+currentitem->height > topy+wHeight(List))
413 topy = currentitem->top+currentitem->height - wHeight(List);
414 drawitems();
415 drawscrollbar();
416 wrefresh(win(List));
417 }
418 }
419 }
420 break;
421 }
422 }
423 }
424 } else if(wmouse_trafo(win(Bottom), &event.y, &event.x, FALSE)) {
425 if(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)
426 && event.y == 1) {
427 const struct key *key;
428 int x = event.x;
429 if(x < 2)
430 continue;
431 x -= 2;
432 for(key = keys; key->key!='\0'; key++) {
433 if(x < key->length) {
434 event.x -= x;
435 wattrset(win(Bottom), COLOR_PAIR(3) | A_BOLD | A_REVERSE);
436 mvwaddstr(win(Bottom), event.y, event.x, key->descr);
437 wmove(win(Bottom), event.y, event.x);
438 wrefresh(win(Bottom));
439 usleep(100000);
440 wattrset(win(Bottom), COLOR_PAIR(3));
441 waddstr(win(Bottom), key->descr);
442 wnoutrefresh(win(Bottom));
443 c = key->key;
444 goto check_key;
445 }
446 x -= key->length;
447 if(x == 0)
448 break;
449 x--;
450 }
451 }
452 }
453 }
454 } else
455 #endif
456 {
457 result=(*_callback)(&currentitem, c);
458 if(result>=0)
459 goto exit;
460
461 switch(c) {
462 case KEY_UP:
463 if(currentitem!=items) {
464 (*drawitem)(currentitem, FALSE);
465 currentitem = currentitem->prev;
466 scrollcurrent();
467 (*drawitem)(currentitem, TRUE);
468 }
469 break;
470
471 case KEY_DOWN:
472 if(currentitem->next!=items) {
473 (*drawitem)(currentitem, FALSE);
474 currentitem = currentitem->next;
475 scrollcurrent();
476 (*drawitem)(currentitem, TRUE);
477 }
478 break;
479
480 case KEY_PPAGE:
481 if(currentitem!=items) {
482 struct item *olditem = currentitem;
483 (*drawitem)(currentitem, FALSE);
484 while(currentitem!=items
485 && olditem->top - currentitem->prev->top <= wHeight(List))
486 currentitem = currentitem->prev;
487 scrollcurrent();
488 (*drawitem)(currentitem, TRUE);
489 }
490 break;
491
492 case KEY_NPAGE:
493 if(currentitem->next!=items) {
494 struct item *olditem = currentitem;
495 (*drawitem)(currentitem, FALSE);
496 while(currentitem->next!=items
497 && (currentitem->next->top + currentitem->next->height)
498 - (olditem->top + olditem->height) <= wHeight(List))
499 currentitem = currentitem->next;
500 scrollcurrent();
501 (*drawitem)(currentitem, TRUE);
502 }
503 break;
504
505 case KEY_HOME:
506 if(currentitem!=items) {
507 (*drawitem)(currentitem, FALSE);
508 currentitem = items;
509 scrollcurrent();
510 (*drawitem)(currentitem, TRUE);
511 }
512 break;
513
514 case KEY_END:
515 if(currentitem->next!=items) {
516 (*drawitem)(currentitem, FALSE);
517 currentitem = items->prev;
518 scrollcurrent();
519 (*drawitem)(currentitem, TRUE);
520 }
521 break;
522
523 #ifdef KEY_RESIZE
524 case KEY_RESIZE:
525 resizeterm(LINES, COLS);
526 checktermsize();
527 { enum win w; for(w = (enum win) 0; w != wCount; w++) {
528 delwin(window[w].win);
529 window[w].win = newwin(wHeight(w), wWidth(w), wTop(w), wLeft(w));
530 } }
531 if(result==-1)
532 currentitem = items;
533 else
534 items = currentitem;
535 topy = 0;
536 draw();
537 break;
538 #endif
539 }
540 }
541 doupdate();
542 }
543 exit:
544 { const char *temp = subtitle;
545 subtitle=_subtitle;
546 _subtitle=temp; }
547 { void(*temp)(struct item *, bool) = drawitem;
548 drawitem=_drawitem;
549 _drawitem=temp; }
550 { struct item *temp=items;
551 items=_items;
552 _items=temp; }
553 { const struct key *temp=keys;
554 keys=_keys;
555 _keys=temp; }
556
557 if(items!=NULL) {
558 currentitem = items;
559 topy = 0;
560 draw();
561 }
562
563 return result;
564 }

  ViewVC Help
Powered by ViewVC 1.1.20