Root/scripts/kconfig/nconf.gui.c

1/*
2 * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
3 * Released under the terms of the GNU GPL v2.0.
4 *
5 * Derived from menuconfig.
6 *
7 */
8#include "nconf.h"
9
10/* a list of all the different widgets we use */
11attributes_t attributes[ATTR_MAX+1] = {0};
12
13/* available colors:
14   COLOR_BLACK 0
15   COLOR_RED 1
16   COLOR_GREEN 2
17   COLOR_YELLOW 3
18   COLOR_BLUE 4
19   COLOR_MAGENTA 5
20   COLOR_CYAN 6
21   COLOR_WHITE 7
22   */
23static void set_normal_colors(void)
24{
25    init_pair(NORMAL, -1, -1);
26    init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
27
28    /* FORE is for the selected item */
29    init_pair(MAIN_MENU_FORE, -1, -1);
30    /* BACK for all the rest */
31    init_pair(MAIN_MENU_BACK, -1, -1);
32    init_pair(MAIN_MENU_GREY, -1, -1);
33    init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
34    init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
35
36    init_pair(SCROLLWIN_TEXT, -1, -1);
37    init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
38    init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
39
40    init_pair(DIALOG_TEXT, -1, -1);
41    init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
42    init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
43    init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
44
45    init_pair(INPUT_BOX, COLOR_YELLOW, -1);
46    init_pair(INPUT_HEADING, COLOR_GREEN, -1);
47    init_pair(INPUT_TEXT, -1, -1);
48    init_pair(INPUT_FIELD, -1, -1);
49
50    init_pair(FUNCTION_HIGHLIGHT, -1, -1);
51    init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
52}
53
54/* available attributes:
55   A_NORMAL Normal display (no highlight)
56   A_STANDOUT Best highlighting mode of the terminal.
57   A_UNDERLINE Underlining
58   A_REVERSE Reverse video
59   A_BLINK Blinking
60   A_DIM Half bright
61   A_BOLD Extra bright or bold
62   A_PROTECT Protected mode
63   A_INVIS Invisible or blank mode
64   A_ALTCHARSET Alternate character set
65   A_CHARTEXT Bit-mask to extract a character
66   COLOR_PAIR(n) Color-pair number n
67   */
68static void normal_color_theme(void)
69{
70    /* automatically add color... */
71#define mkattr(name, attr) do { \
72attributes[name] = attr | COLOR_PAIR(name); } while (0)
73    mkattr(NORMAL, NORMAL);
74    mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
75
76    mkattr(MAIN_MENU_FORE, A_REVERSE);
77    mkattr(MAIN_MENU_BACK, A_NORMAL);
78    mkattr(MAIN_MENU_GREY, A_NORMAL);
79    mkattr(MAIN_MENU_HEADING, A_BOLD);
80    mkattr(MAIN_MENU_BOX, A_NORMAL);
81
82    mkattr(SCROLLWIN_TEXT, A_NORMAL);
83    mkattr(SCROLLWIN_HEADING, A_BOLD);
84    mkattr(SCROLLWIN_BOX, A_BOLD);
85
86    mkattr(DIALOG_TEXT, A_BOLD);
87    mkattr(DIALOG_BOX, A_BOLD);
88    mkattr(DIALOG_MENU_FORE, A_STANDOUT);
89    mkattr(DIALOG_MENU_BACK, A_NORMAL);
90
91    mkattr(INPUT_BOX, A_NORMAL);
92    mkattr(INPUT_HEADING, A_BOLD);
93    mkattr(INPUT_TEXT, A_NORMAL);
94    mkattr(INPUT_FIELD, A_UNDERLINE);
95
96    mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
97    mkattr(FUNCTION_TEXT, A_REVERSE);
98}
99
100static void no_colors_theme(void)
101{
102    /* automatically add highlight, no color */
103#define mkattrn(name, attr) { attributes[name] = attr; }
104
105    mkattrn(NORMAL, NORMAL);
106    mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
107
108    mkattrn(MAIN_MENU_FORE, A_STANDOUT);
109    mkattrn(MAIN_MENU_BACK, A_NORMAL);
110    mkattrn(MAIN_MENU_GREY, A_NORMAL);
111    mkattrn(MAIN_MENU_HEADING, A_BOLD);
112    mkattrn(MAIN_MENU_BOX, A_NORMAL);
113
114    mkattrn(SCROLLWIN_TEXT, A_NORMAL);
115    mkattrn(SCROLLWIN_HEADING, A_BOLD);
116    mkattrn(SCROLLWIN_BOX, A_BOLD);
117
118    mkattrn(DIALOG_TEXT, A_NORMAL);
119    mkattrn(DIALOG_BOX, A_BOLD);
120    mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
121    mkattrn(DIALOG_MENU_BACK, A_NORMAL);
122
123    mkattrn(INPUT_BOX, A_BOLD);
124    mkattrn(INPUT_HEADING, A_BOLD);
125    mkattrn(INPUT_TEXT, A_NORMAL);
126    mkattrn(INPUT_FIELD, A_UNDERLINE);
127
128    mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
129    mkattrn(FUNCTION_TEXT, A_REVERSE);
130}
131
132void set_colors()
133{
134    start_color();
135    use_default_colors();
136    set_normal_colors();
137    if (has_colors()) {
138        normal_color_theme();
139    } else {
140        /* give defaults */
141        no_colors_theme();
142    }
143}
144
145
146/* this changes the windows attributes !!! */
147void print_in_middle(WINDOW *win,
148        int starty,
149        int startx,
150        int width,
151        const char *string,
152        chtype color)
153{ int length, x, y;
154    float temp;
155
156
157    if (win == NULL)
158        win = stdscr;
159    getyx(win, y, x);
160    if (startx != 0)
161        x = startx;
162    if (starty != 0)
163        y = starty;
164    if (width == 0)
165        width = 80;
166
167    length = strlen(string);
168    temp = (width - length) / 2;
169    x = startx + (int)temp;
170    (void) wattrset(win, color);
171    mvwprintw(win, y, x, "%s", string);
172    refresh();
173}
174
175int get_line_no(const char *text)
176{
177    int i;
178    int total = 1;
179
180    if (!text)
181        return 0;
182
183    for (i = 0; text[i] != '\0'; i++)
184        if (text[i] == '\n')
185            total++;
186    return total;
187}
188
189const char *get_line(const char *text, int line_no)
190{
191    int i;
192    int lines = 0;
193
194    if (!text)
195        return 0;
196
197    for (i = 0; text[i] != '\0' && lines < line_no; i++)
198        if (text[i] == '\n')
199            lines++;
200    return text+i;
201}
202
203int get_line_length(const char *line)
204{
205    int res = 0;
206    while (*line != '\0' && *line != '\n') {
207        line++;
208        res++;
209    }
210    return res;
211}
212
213/* print all lines to the window. */
214void fill_window(WINDOW *win, const char *text)
215{
216    int x, y;
217    int total_lines = get_line_no(text);
218    int i;
219
220    getmaxyx(win, y, x);
221    /* do not go over end of line */
222    total_lines = min(total_lines, y);
223    for (i = 0; i < total_lines; i++) {
224        char tmp[x+10];
225        const char *line = get_line(text, i);
226        int len = get_line_length(line);
227        strncpy(tmp, line, min(len, x));
228        tmp[len] = '\0';
229        mvwprintw(win, i, 0, "%s", tmp);
230    }
231}
232
233/* get the message, and buttons.
234 * each button must be a char*
235 * return the selected button
236 *
237 * this dialog is used for 2 different things:
238 * 1) show a text box, no buttons.
239 * 2) show a dialog, with horizontal buttons
240 */
241int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
242{
243    va_list ap;
244    char *btn;
245    int btns_width = 0;
246    int msg_lines = 0;
247    int msg_width = 0;
248    int total_width;
249    int win_rows = 0;
250    WINDOW *win;
251    WINDOW *msg_win;
252    WINDOW *menu_win;
253    MENU *menu;
254    ITEM *btns[btn_num+1];
255    int i, x, y;
256    int res = -1;
257
258
259    va_start(ap, btn_num);
260    for (i = 0; i < btn_num; i++) {
261        btn = va_arg(ap, char *);
262        btns[i] = new_item(btn, "");
263        btns_width += strlen(btn)+1;
264    }
265    va_end(ap);
266    btns[btn_num] = NULL;
267
268    /* find the widest line of msg: */
269    msg_lines = get_line_no(msg);
270    for (i = 0; i < msg_lines; i++) {
271        const char *line = get_line(msg, i);
272        int len = get_line_length(line);
273        if (msg_width < len)
274            msg_width = len;
275    }
276
277    total_width = max(msg_width, btns_width);
278    /* place dialog in middle of screen */
279    y = (LINES-(msg_lines+4))/2;
280    x = (COLS-(total_width+4))/2;
281
282
283    /* create the windows */
284    if (btn_num > 0)
285        win_rows = msg_lines+4;
286    else
287        win_rows = msg_lines+2;
288
289    win = newwin(win_rows, total_width+4, y, x);
290    keypad(win, TRUE);
291    menu_win = derwin(win, 1, btns_width, win_rows-2,
292            1+(total_width+2-btns_width)/2);
293    menu = new_menu(btns);
294    msg_win = derwin(win, win_rows-2, msg_width, 1,
295            1+(total_width+2-msg_width)/2);
296
297    set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
298    set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
299
300    (void) wattrset(win, attributes[DIALOG_BOX]);
301    box(win, 0, 0);
302
303    /* print message */
304    (void) wattrset(msg_win, attributes[DIALOG_TEXT]);
305    fill_window(msg_win, msg);
306
307    set_menu_win(menu, win);
308    set_menu_sub(menu, menu_win);
309    set_menu_format(menu, 1, btn_num);
310    menu_opts_off(menu, O_SHOWDESC);
311    menu_opts_off(menu, O_SHOWMATCH);
312    menu_opts_on(menu, O_ONEVALUE);
313    menu_opts_on(menu, O_NONCYCLIC);
314    set_menu_mark(menu, "");
315    post_menu(menu);
316
317
318    touchwin(win);
319    refresh_all_windows(main_window);
320    while ((res = wgetch(win))) {
321        switch (res) {
322        case KEY_LEFT:
323            menu_driver(menu, REQ_LEFT_ITEM);
324            break;
325        case KEY_RIGHT:
326            menu_driver(menu, REQ_RIGHT_ITEM);
327            break;
328        case 10: /* ENTER */
329        case 27: /* ESCAPE */
330        case ' ':
331        case KEY_F(F_BACK):
332        case KEY_F(F_EXIT):
333            break;
334        }
335        touchwin(win);
336        refresh_all_windows(main_window);
337
338        if (res == 10 || res == ' ') {
339            res = item_index(current_item(menu));
340            break;
341        } else if (res == 27 || res == KEY_F(F_BACK) ||
342                res == KEY_F(F_EXIT)) {
343            res = KEY_EXIT;
344            break;
345        }
346    }
347
348    unpost_menu(menu);
349    free_menu(menu);
350    for (i = 0; i < btn_num; i++)
351        free_item(btns[i]);
352
353    delwin(win);
354    return res;
355}
356
357int dialog_inputbox(WINDOW *main_window,
358        const char *title, const char *prompt,
359        const char *init, char *result, int result_len)
360{
361    int prompt_lines = 0;
362    int prompt_width = 0;
363    WINDOW *win;
364    WINDOW *prompt_win;
365    WINDOW *form_win;
366    PANEL *panel;
367    int i, x, y;
368    int res = -1;
369    int cursor_position = strlen(init);
370
371
372    /* find the widest line of msg: */
373    prompt_lines = get_line_no(prompt);
374    for (i = 0; i < prompt_lines; i++) {
375        const char *line = get_line(prompt, i);
376        int len = get_line_length(line);
377        prompt_width = max(prompt_width, len);
378    }
379
380    if (title)
381        prompt_width = max(prompt_width, strlen(title));
382
383    /* place dialog in middle of screen */
384    y = (LINES-(prompt_lines+4))/2;
385    x = (COLS-(prompt_width+4))/2;
386
387    strncpy(result, init, result_len);
388
389    /* create the windows */
390    win = newwin(prompt_lines+6, prompt_width+7, y, x);
391    prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
392    form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
393    keypad(form_win, TRUE);
394
395    (void) wattrset(form_win, attributes[INPUT_FIELD]);
396
397    (void) wattrset(win, attributes[INPUT_BOX]);
398    box(win, 0, 0);
399    (void) wattrset(win, attributes[INPUT_HEADING]);
400    if (title)
401        mvwprintw(win, 0, 3, "%s", title);
402
403    /* print message */
404    (void) wattrset(prompt_win, attributes[INPUT_TEXT]);
405    fill_window(prompt_win, prompt);
406
407    mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
408    mvwprintw(form_win, 0, 0, "%s", result);
409
410    /* create panels */
411    panel = new_panel(win);
412
413    /* show the cursor */
414    curs_set(1);
415
416    touchwin(win);
417    refresh_all_windows(main_window);
418    while ((res = wgetch(form_win))) {
419        int len = strlen(result);
420        switch (res) {
421        case 10: /* ENTER */
422        case 27: /* ESCAPE */
423        case KEY_F(F_HELP):
424        case KEY_F(F_EXIT):
425        case KEY_F(F_BACK):
426            break;
427        case 127:
428        case KEY_BACKSPACE:
429            if (cursor_position > 0) {
430                memmove(&result[cursor_position-1],
431                        &result[cursor_position],
432                        len-cursor_position+1);
433                cursor_position--;
434            }
435            break;
436        case KEY_DC:
437            if (cursor_position >= 0 && cursor_position < len) {
438                memmove(&result[cursor_position],
439                        &result[cursor_position+1],
440                        len-cursor_position+1);
441            }
442            break;
443        case KEY_UP:
444        case KEY_RIGHT:
445            if (cursor_position < len &&
446                cursor_position < min(result_len, prompt_width))
447                cursor_position++;
448            break;
449        case KEY_DOWN:
450        case KEY_LEFT:
451            if (cursor_position > 0)
452                cursor_position--;
453            break;
454        default:
455            if ((isgraph(res) || isspace(res)) &&
456                    len-2 < result_len) {
457                /* insert the char at the proper position */
458                memmove(&result[cursor_position+1],
459                        &result[cursor_position],
460                        len+1);
461                result[cursor_position] = res;
462                cursor_position++;
463            } else {
464                mvprintw(0, 0, "unknow key: %d\n", res);
465            }
466            break;
467        }
468        wmove(form_win, 0, 0);
469        wclrtoeol(form_win);
470        mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
471        mvwprintw(form_win, 0, 0, "%s", result);
472        wmove(form_win, 0, cursor_position);
473        touchwin(win);
474        refresh_all_windows(main_window);
475
476        if (res == 10) {
477            res = 0;
478            break;
479        } else if (res == 27 || res == KEY_F(F_BACK) ||
480                res == KEY_F(F_EXIT)) {
481            res = KEY_EXIT;
482            break;
483        } else if (res == KEY_F(F_HELP)) {
484            res = 1;
485            break;
486        }
487    }
488
489    /* hide the cursor */
490    curs_set(0);
491    del_panel(panel);
492    delwin(prompt_win);
493    delwin(form_win);
494    delwin(win);
495    return res;
496}
497
498/* refresh all windows in the correct order */
499void refresh_all_windows(WINDOW *main_window)
500{
501    update_panels();
502    touchwin(main_window);
503    refresh();
504}
505
506/* layman's scrollable window... */
507void show_scroll_win(WINDOW *main_window,
508        const char *title,
509        const char *text)
510{
511    int res;
512    int total_lines = get_line_no(text);
513    int x, y;
514    int start_x = 0, start_y = 0;
515    int text_lines = 0, text_cols = 0;
516    int total_cols = 0;
517    int win_cols = 0;
518    int win_lines = 0;
519    int i = 0;
520    WINDOW *win;
521    WINDOW *pad;
522    PANEL *panel;
523
524    /* find the widest line of msg: */
525    total_lines = get_line_no(text);
526    for (i = 0; i < total_lines; i++) {
527        const char *line = get_line(text, i);
528        int len = get_line_length(line);
529        total_cols = max(total_cols, len+2);
530    }
531
532    /* create the pad */
533    pad = newpad(total_lines+10, total_cols+10);
534    (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
535    fill_window(pad, text);
536
537    win_lines = min(total_lines+4, LINES-2);
538    win_cols = min(total_cols+2, COLS-2);
539    text_lines = max(win_lines-4, 0);
540    text_cols = max(win_cols-2, 0);
541
542    /* place window in middle of screen */
543    y = (LINES-win_lines)/2;
544    x = (COLS-win_cols)/2;
545
546    win = newwin(win_lines, win_cols, y, x);
547    keypad(win, TRUE);
548    /* show the help in the help window, and show the help panel */
549    (void) wattrset(win, attributes[SCROLLWIN_BOX]);
550    box(win, 0, 0);
551    (void) wattrset(win, attributes[SCROLLWIN_HEADING]);
552    mvwprintw(win, 0, 3, " %s ", title);
553    panel = new_panel(win);
554
555    /* handle scrolling */
556    do {
557
558        copywin(pad, win, start_y, start_x, 2, 2, text_lines,
559                text_cols, 0);
560        print_in_middle(win,
561                text_lines+2,
562                0,
563                text_cols,
564                "<OK>",
565                attributes[DIALOG_MENU_FORE]);
566        wrefresh(win);
567
568        res = wgetch(win);
569        switch (res) {
570        case KEY_NPAGE:
571        case ' ':
572            start_y += text_lines-2;
573            break;
574        case KEY_PPAGE:
575            start_y -= text_lines+2;
576            break;
577        case KEY_HOME:
578            start_y = 0;
579            break;
580        case KEY_END:
581            start_y = total_lines-text_lines;
582            break;
583        case KEY_DOWN:
584        case 'j':
585            start_y++;
586            break;
587        case KEY_UP:
588        case 'k':
589            start_y--;
590            break;
591        case KEY_LEFT:
592        case 'h':
593            start_x--;
594            break;
595        case KEY_RIGHT:
596        case 'l':
597            start_x++;
598            break;
599        }
600        if (res == 10 || res == 27 || res == 'q'
601            || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
602            break;
603        }
604        if (start_y < 0)
605            start_y = 0;
606        if (start_y >= total_lines-text_lines)
607            start_y = total_lines-text_lines;
608        if (start_x < 0)
609            start_x = 0;
610        if (start_x >= total_cols-text_cols)
611            start_x = total_cols-text_cols;
612    } while (res);
613
614    del_panel(panel);
615    delwin(win);
616    refresh_all_windows(main_window);
617}
618

Archive Download this file



interactive