|
|
1.1 root 1: /*
2: * util.c
3: *
4: * ORIGINAL AUTHOR: Savio Lam ([email protected])
5: * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
6: *
7: * This program is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU General Public License
9: * as published by the Free Software Foundation; either version 2
10: * of the License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public License
18: * along with this program; if not, write to the Free Software
19: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20: */
21:
22: #include <stdarg.h>
23:
24: #include "dialog.h"
25:
26: struct dialog_info dlg;
27:
28: static void set_mono_theme(void)
29: {
30: dlg.screen.atr = A_NORMAL;
31: dlg.shadow.atr = A_NORMAL;
32: dlg.dialog.atr = A_NORMAL;
33: dlg.title.atr = A_BOLD;
34: dlg.border.atr = A_NORMAL;
35: dlg.button_active.atr = A_REVERSE;
36: dlg.button_inactive.atr = A_DIM;
37: dlg.button_key_active.atr = A_REVERSE;
38: dlg.button_key_inactive.atr = A_BOLD;
39: dlg.button_label_active.atr = A_REVERSE;
40: dlg.button_label_inactive.atr = A_NORMAL;
41: dlg.inputbox.atr = A_NORMAL;
42: dlg.inputbox_border.atr = A_NORMAL;
43: dlg.searchbox.atr = A_NORMAL;
44: dlg.searchbox_title.atr = A_BOLD;
45: dlg.searchbox_border.atr = A_NORMAL;
46: dlg.position_indicator.atr = A_BOLD;
47: dlg.menubox.atr = A_NORMAL;
48: dlg.menubox_border.atr = A_NORMAL;
49: dlg.item.atr = A_NORMAL;
50: dlg.item_selected.atr = A_REVERSE;
51: dlg.tag.atr = A_BOLD;
52: dlg.tag_selected.atr = A_REVERSE;
53: dlg.tag_key.atr = A_BOLD;
54: dlg.tag_key_selected.atr = A_REVERSE;
55: dlg.check.atr = A_BOLD;
56: dlg.check_selected.atr = A_REVERSE;
57: dlg.uarrow.atr = A_BOLD;
58: dlg.darrow.atr = A_BOLD;
59: }
60:
61: #define DLG_COLOR(dialog, f, b, h) \
62: do { \
63: dlg.dialog.fg = (f); \
64: dlg.dialog.bg = (b); \
65: dlg.dialog.hl = (h); \
66: } while (0)
67:
68: static void set_classic_theme(void)
69: {
70: DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
71: DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
72: DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
73: DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
74: DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
75: DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
76: DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
77: DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
78: DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
79: DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
80: DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
81: DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
82: DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
83: DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
84: DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
85: DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
86: DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
87: DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
88: DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
89: DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
90: DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
91: DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
92: DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
93: DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
94: DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
95: DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
96: DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
97: DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
98: DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
99: }
100:
101: static void set_blackbg_theme(void)
102: {
103: DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
104: DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
105: DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
106: DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
107: DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
108:
109: DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
110: DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
111: DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
112: DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
113: DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
114: DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
115:
116: DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
117: DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
118:
119: DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
120: DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
121: DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
122:
123: DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
124:
125: DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
126: DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
127:
128: DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
129: DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
130:
131: DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
132: DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
133: DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
134: DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
135:
136: DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
137: DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
138:
139: DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
140: DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
141: }
142:
143: static void set_bluetitle_theme(void)
144: {
145: set_classic_theme();
146: DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
147: DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
148: DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
149: DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
150: DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
151: DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
152: DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
153:
154: }
155:
156: /*
157: * Select color theme
158: */
159: static int set_theme(const char *theme)
160: {
161: int use_color = 1;
162: if (!theme)
163: set_bluetitle_theme();
164: else if (strcmp(theme, "classic") == 0)
165: set_classic_theme();
166: else if (strcmp(theme, "bluetitle") == 0)
167: set_bluetitle_theme();
168: else if (strcmp(theme, "blackbg") == 0)
169: set_blackbg_theme();
170: else if (strcmp(theme, "mono") == 0)
171: use_color = 0;
172:
173: return use_color;
174: }
175:
176: static void init_one_color(struct dialog_color *color)
177: {
178: static int pair = 0;
179:
180: pair++;
181: init_pair(pair, color->fg, color->bg);
182: if (color->hl)
183: color->atr = A_BOLD | COLOR_PAIR(pair);
184: else
185: color->atr = COLOR_PAIR(pair);
186: }
187:
188: static void init_dialog_colors(void)
189: {
190: init_one_color(&dlg.screen);
191: init_one_color(&dlg.shadow);
192: init_one_color(&dlg.dialog);
193: init_one_color(&dlg.title);
194: init_one_color(&dlg.border);
195: init_one_color(&dlg.button_active);
196: init_one_color(&dlg.button_inactive);
197: init_one_color(&dlg.button_key_active);
198: init_one_color(&dlg.button_key_inactive);
199: init_one_color(&dlg.button_label_active);
200: init_one_color(&dlg.button_label_inactive);
201: init_one_color(&dlg.inputbox);
202: init_one_color(&dlg.inputbox_border);
203: init_one_color(&dlg.searchbox);
204: init_one_color(&dlg.searchbox_title);
205: init_one_color(&dlg.searchbox_border);
206: init_one_color(&dlg.position_indicator);
207: init_one_color(&dlg.menubox);
208: init_one_color(&dlg.menubox_border);
209: init_one_color(&dlg.item);
210: init_one_color(&dlg.item_selected);
211: init_one_color(&dlg.tag);
212: init_one_color(&dlg.tag_selected);
213: init_one_color(&dlg.tag_key);
214: init_one_color(&dlg.tag_key_selected);
215: init_one_color(&dlg.check);
216: init_one_color(&dlg.check_selected);
217: init_one_color(&dlg.uarrow);
218: init_one_color(&dlg.darrow);
219: }
220:
221: /*
222: * Setup for color display
223: */
224: static void color_setup(const char *theme)
225: {
226: int use_color;
227:
228: use_color = set_theme(theme);
229: if (use_color && has_colors()) {
230: start_color();
231: init_dialog_colors();
232: } else
233: set_mono_theme();
234: }
235:
236: /*
237: * Set window to attribute 'attr'
238: */
239: void attr_clear(WINDOW * win, int height, int width, chtype attr)
240: {
241: int i, j;
242:
243: wattrset(win, attr);
244: for (i = 0; i < height; i++) {
245: wmove(win, i, 0);
246: for (j = 0; j < width; j++)
247: waddch(win, ' ');
248: }
249: touchwin(win);
250: }
251:
252: void dialog_clear(void)
253: {
254: attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
255: /* Display background title if it exists ... - SLH */
256: if (dlg.backtitle != NULL) {
257: int i;
258:
259: wattrset(stdscr, dlg.screen.atr);
260: mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
261: wmove(stdscr, 1, 1);
262: for (i = 1; i < COLS - 1; i++)
263: waddch(stdscr, ACS_HLINE);
264: }
265: wnoutrefresh(stdscr);
266: }
267:
268: /*
269: * Do some initialization for dialog
270: */
271: int init_dialog(const char *backtitle)
272: {
273: int height, width;
274:
275: initscr(); /* Init curses */
276: getmaxyx(stdscr, height, width);
277: if (height < 19 || width < 80) {
278: endwin();
279: return -ERRDISPLAYTOOSMALL;
280: }
281:
282: dlg.backtitle = backtitle;
283: color_setup(getenv("MENUCONFIG_COLOR"));
284:
285: keypad(stdscr, TRUE);
286: cbreak();
287: noecho();
288: dialog_clear();
289:
290: return 0;
291: }
292:
293: void set_dialog_backtitle(const char *backtitle)
294: {
295: dlg.backtitle = backtitle;
296: }
297:
298: /*
299: * End using dialog functions.
300: */
301: void end_dialog(int x, int y)
302: {
303: /* move cursor back to original position */
304: move(y, x);
305: refresh();
306: endwin();
307: }
308:
309: /* Print the title of the dialog. Center the title and truncate
310: * tile if wider than dialog (- 2 chars).
311: **/
312: void print_title(WINDOW *dialog, const char *title, int width)
313: {
314: if (title) {
315: int tlen = MIN(width - 2, strlen(title));
316: wattrset(dialog, dlg.title.atr);
317: mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
318: mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
319: waddch(dialog, ' ');
320: }
321: }
322:
323: /*
324: * Print a string of text in a window, automatically wrap around to the
325: * next line if the string is too long to fit on one line. Newline
326: * characters '\n' are replaced by spaces. We start on a new line
327: * if there is no room for at least 4 nonblanks following a double-space.
328: */
329: void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
330: {
331: int newl, cur_x, cur_y;
332: int i, prompt_len, room, wlen;
333: char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
334:
335: strcpy(tempstr, prompt);
336:
337: prompt_len = strlen(tempstr);
338:
339: /*
340: * Remove newlines
341: */
342: for (i = 0; i < prompt_len; i++) {
343: if (tempstr[i] == '\n')
344: tempstr[i] = ' ';
345: }
346:
347: if (prompt_len <= width - x * 2) { /* If prompt is short */
348: wmove(win, y, (width - prompt_len) / 2);
349: waddstr(win, tempstr);
350: } else {
351: cur_x = x;
352: cur_y = y;
353: newl = 1;
354: word = tempstr;
355: while (word && *word) {
356: sp = strchr(word, ' ');
357: if (sp)
358: *sp++ = 0;
359:
360: /* Wrap to next line if either the word does not fit,
361: or it is the first word of a new sentence, and it is
362: short, and the next word does not fit. */
363: room = width - cur_x;
364: wlen = strlen(word);
365: if (wlen > room ||
366: (newl && wlen < 4 && sp
367: && wlen + 1 + strlen(sp) > room
368: && (!(sp2 = strchr(sp, ' '))
369: || wlen + 1 + (sp2 - sp) > room))) {
370: cur_y++;
371: cur_x = x;
372: }
373: wmove(win, cur_y, cur_x);
374: waddstr(win, word);
375: getyx(win, cur_y, cur_x);
376: cur_x++;
377: if (sp && *sp == ' ') {
378: cur_x++; /* double space */
379: while (*++sp == ' ') ;
380: newl = 1;
381: } else
382: newl = 0;
383: word = sp;
384: }
385: }
386: }
387:
388: /*
389: * Print a button
390: */
391: void print_button(WINDOW * win, const char *label, int y, int x, int selected)
392: {
393: int i, temp;
394:
395: wmove(win, y, x);
396: wattrset(win, selected ? dlg.button_active.atr
397: : dlg.button_inactive.atr);
398: waddstr(win, "<");
399: temp = strspn(label, " ");
400: label += temp;
401: wattrset(win, selected ? dlg.button_label_active.atr
402: : dlg.button_label_inactive.atr);
403: for (i = 0; i < temp; i++)
404: waddch(win, ' ');
405: wattrset(win, selected ? dlg.button_key_active.atr
406: : dlg.button_key_inactive.atr);
407: waddch(win, label[0]);
408: wattrset(win, selected ? dlg.button_label_active.atr
409: : dlg.button_label_inactive.atr);
410: waddstr(win, (char *)label + 1);
411: wattrset(win, selected ? dlg.button_active.atr
412: : dlg.button_inactive.atr);
413: waddstr(win, ">");
414: wmove(win, y, x + temp + 1);
415: }
416:
417: /*
418: * Draw a rectangular box with line drawing characters
419: */
420: void
421: draw_box(WINDOW * win, int y, int x, int height, int width,
422: chtype box, chtype border)
423: {
424: int i, j;
425:
426: wattrset(win, 0);
427: for (i = 0; i < height; i++) {
428: wmove(win, y + i, x);
429: for (j = 0; j < width; j++)
430: if (!i && !j)
431: waddch(win, border | ACS_ULCORNER);
432: else if (i == height - 1 && !j)
433: waddch(win, border | ACS_LLCORNER);
434: else if (!i && j == width - 1)
435: waddch(win, box | ACS_URCORNER);
436: else if (i == height - 1 && j == width - 1)
437: waddch(win, box | ACS_LRCORNER);
438: else if (!i)
439: waddch(win, border | ACS_HLINE);
440: else if (i == height - 1)
441: waddch(win, box | ACS_HLINE);
442: else if (!j)
443: waddch(win, border | ACS_VLINE);
444: else if (j == width - 1)
445: waddch(win, box | ACS_VLINE);
446: else
447: waddch(win, box | ' ');
448: }
449: }
450:
451: /*
452: * Draw shadows along the right and bottom edge to give a more 3D look
453: * to the boxes
454: */
455: void draw_shadow(WINDOW * win, int y, int x, int height, int width)
456: {
457: int i;
458:
459: if (has_colors()) { /* Whether terminal supports color? */
460: wattrset(win, dlg.shadow.atr);
461: wmove(win, y + height, x + 2);
462: for (i = 0; i < width; i++)
463: waddch(win, winch(win) & A_CHARTEXT);
464: for (i = y + 1; i < y + height + 1; i++) {
465: wmove(win, i, x + width);
466: waddch(win, winch(win) & A_CHARTEXT);
467: waddch(win, winch(win) & A_CHARTEXT);
468: }
469: wnoutrefresh(win);
470: }
471: }
472:
473: /*
474: * Return the position of the first alphabetic character in a string.
475: */
476: int first_alpha(const char *string, const char *exempt)
477: {
478: int i, in_paren = 0, c;
479:
480: for (i = 0; i < strlen(string); i++) {
481: c = tolower(string[i]);
482:
483: if (strchr("<[(", c))
484: ++in_paren;
485: if (strchr(">])", c) && in_paren > 0)
486: --in_paren;
487:
488: if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
489: return i;
490: }
491:
492: return 0;
493: }
494:
495: /*
496: * ncurses uses ESC to detect escaped char sequences. This resutl in
497: * a small timeout before ESC is actually delivered to the application.
498: * lxdialog suggest <ESC> <ESC> which is correctly translated to two
499: * times esc. But then we need to ignore the second esc to avoid stepping
500: * out one menu too much. Filter away all escaped key sequences since
501: * keypad(FALSE) turn off ncurses support for escape sequences - and thats
502: * needed to make notimeout() do as expected.
503: */
504: int on_key_esc(WINDOW *win)
505: {
506: int key;
507: int key2;
508: int key3;
509:
510: nodelay(win, TRUE);
511: keypad(win, FALSE);
512: key = wgetch(win);
513: key2 = wgetch(win);
514: do {
515: key3 = wgetch(win);
516: } while (key3 != ERR);
517: nodelay(win, FALSE);
518: keypad(win, TRUE);
519: if (key == KEY_ESC && key2 == ERR)
520: return KEY_ESC;
521: else if (key != ERR && key != KEY_ESC && key2 == ERR)
522: ungetch(key);
523:
524: return -1;
525: }
526:
527: /* redraw screen in new size */
528: int on_key_resize(void)
529: {
530: dialog_clear();
531: return KEY_RESIZE;
532: }
533:
534: struct dialog_list *item_cur;
535: struct dialog_list item_nil;
536: struct dialog_list *item_head;
537:
538: void item_reset(void)
539: {
540: struct dialog_list *p, *next;
541:
542: for (p = item_head; p; p = next) {
543: next = p->next;
544: free(p);
545: }
546: item_head = NULL;
547: item_cur = &item_nil;
548: }
549:
550: void item_make(const char *fmt, ...)
551: {
552: va_list ap;
553: struct dialog_list *p = malloc(sizeof(*p));
554:
555: if (item_head)
556: item_cur->next = p;
557: else
558: item_head = p;
559: item_cur = p;
560: memset(p, 0, sizeof(*p));
561:
562: va_start(ap, fmt);
563: vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
564: va_end(ap);
565: }
566:
567: void item_add_str(const char *fmt, ...)
568: {
569: va_list ap;
570: size_t avail;
571:
572: avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
573:
574: va_start(ap, fmt);
575: vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
576: avail, fmt, ap);
577: item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
578: va_end(ap);
579: }
580:
581: void item_set_tag(char tag)
582: {
583: item_cur->node.tag = tag;
584: }
585: void item_set_data(void *ptr)
586: {
587: item_cur->node.data = ptr;
588: }
589:
590: void item_set_selected(int val)
591: {
592: item_cur->node.selected = val;
593: }
594:
595: int item_activate_selected(void)
596: {
597: item_foreach()
598: if (item_is_selected())
599: return 1;
600: return 0;
601: }
602:
603: void *item_data(void)
604: {
605: return item_cur->node.data;
606: }
607:
608: char item_tag(void)
609: {
610: return item_cur->node.tag;
611: }
612:
613: int item_count(void)
614: {
615: int n = 0;
616: struct dialog_list *p;
617:
618: for (p = item_head; p; p = p->next)
619: n++;
620: return n;
621: }
622:
623: void item_set(int n)
624: {
625: int i = 0;
626: item_foreach()
627: if (i++ == n)
628: return;
629: }
630:
631: int item_n(void)
632: {
633: int n = 0;
634: struct dialog_list *p;
635:
636: for (p = item_head; p; p = p->next) {
637: if (p == item_cur)
638: return n;
639: n++;
640: }
641: return 0;
642: }
643:
644: const char *item_str(void)
645: {
646: return item_cur->node.str;
647: }
648:
649: int item_is_selected(void)
650: {
651: return (item_cur->node.selected != 0);
652: }
653:
654: int item_is_tag(char tag)
655: {
656: return (item_cur->node.tag == tag);
657: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.