Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
0004  *
0005  * Derived from menuconfig.
0006  */
0007 #include "nconf.h"
0008 #include "lkc.h"
0009 
0010 int attr_normal;
0011 int attr_main_heading;
0012 int attr_main_menu_box;
0013 int attr_main_menu_fore;
0014 int attr_main_menu_back;
0015 int attr_main_menu_grey;
0016 int attr_main_menu_heading;
0017 int attr_scrollwin_text;
0018 int attr_scrollwin_heading;
0019 int attr_scrollwin_box;
0020 int attr_dialog_text;
0021 int attr_dialog_menu_fore;
0022 int attr_dialog_menu_back;
0023 int attr_dialog_box;
0024 int attr_input_box;
0025 int attr_input_heading;
0026 int attr_input_text;
0027 int attr_input_field;
0028 int attr_function_text;
0029 int attr_function_highlight;
0030 
0031 #define COLOR_ATTR(_at, _fg, _bg, _hl) \
0032     { .attr = &(_at), .has_color = true, .color_fg = _fg, .color_bg = _bg, .highlight = _hl }
0033 #define NO_COLOR_ATTR(_at, _hl) \
0034     { .attr = &(_at), .has_color = false, .highlight = _hl }
0035 #define COLOR_DEFAULT       -1
0036 
0037 struct nconf_attr_param {
0038     int *attr;
0039     bool has_color;
0040     int color_fg;
0041     int color_bg;
0042     int highlight;
0043 };
0044 
0045 static const struct nconf_attr_param color_theme_params[] = {
0046     COLOR_ATTR(attr_normal,         COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL),
0047     COLOR_ATTR(attr_main_heading,       COLOR_MAGENTA,  COLOR_DEFAULT,  A_BOLD | A_UNDERLINE),
0048     COLOR_ATTR(attr_main_menu_box,      COLOR_YELLOW,   COLOR_DEFAULT,  A_NORMAL),
0049     COLOR_ATTR(attr_main_menu_fore,     COLOR_DEFAULT,  COLOR_DEFAULT,  A_REVERSE),
0050     COLOR_ATTR(attr_main_menu_back,     COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL),
0051     COLOR_ATTR(attr_main_menu_grey,     COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL),
0052     COLOR_ATTR(attr_main_menu_heading,  COLOR_GREEN,    COLOR_DEFAULT,  A_BOLD),
0053     COLOR_ATTR(attr_scrollwin_text,     COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL),
0054     COLOR_ATTR(attr_scrollwin_heading,  COLOR_GREEN,    COLOR_DEFAULT,  A_BOLD),
0055     COLOR_ATTR(attr_scrollwin_box,      COLOR_YELLOW,   COLOR_DEFAULT,  A_BOLD),
0056     COLOR_ATTR(attr_dialog_text,        COLOR_DEFAULT,  COLOR_DEFAULT,  A_BOLD),
0057     COLOR_ATTR(attr_dialog_menu_fore,   COLOR_RED,  COLOR_DEFAULT,  A_STANDOUT),
0058     COLOR_ATTR(attr_dialog_menu_back,   COLOR_YELLOW,   COLOR_DEFAULT,  A_NORMAL),
0059     COLOR_ATTR(attr_dialog_box,     COLOR_YELLOW,   COLOR_DEFAULT,  A_BOLD),
0060     COLOR_ATTR(attr_input_box,      COLOR_YELLOW,   COLOR_DEFAULT,  A_NORMAL),
0061     COLOR_ATTR(attr_input_heading,      COLOR_GREEN,    COLOR_DEFAULT,  A_BOLD),
0062     COLOR_ATTR(attr_input_text,     COLOR_DEFAULT,  COLOR_DEFAULT,  A_NORMAL),
0063     COLOR_ATTR(attr_input_field,        COLOR_DEFAULT,  COLOR_DEFAULT,  A_UNDERLINE),
0064     COLOR_ATTR(attr_function_text,      COLOR_YELLOW,   COLOR_DEFAULT,  A_REVERSE),
0065     COLOR_ATTR(attr_function_highlight, COLOR_DEFAULT,  COLOR_DEFAULT,  A_BOLD),
0066     { /* sentinel */ }
0067 };
0068 
0069 static const struct nconf_attr_param no_color_theme_params[] = {
0070     NO_COLOR_ATTR(attr_normal,      A_NORMAL),
0071     NO_COLOR_ATTR(attr_main_heading,    A_BOLD | A_UNDERLINE),
0072     NO_COLOR_ATTR(attr_main_menu_box,   A_NORMAL),
0073     NO_COLOR_ATTR(attr_main_menu_fore,  A_STANDOUT),
0074     NO_COLOR_ATTR(attr_main_menu_back,  A_NORMAL),
0075     NO_COLOR_ATTR(attr_main_menu_grey,  A_NORMAL),
0076     NO_COLOR_ATTR(attr_main_menu_heading,   A_BOLD),
0077     NO_COLOR_ATTR(attr_scrollwin_text,  A_NORMAL),
0078     NO_COLOR_ATTR(attr_scrollwin_heading,   A_BOLD),
0079     NO_COLOR_ATTR(attr_scrollwin_box,   A_BOLD),
0080     NO_COLOR_ATTR(attr_dialog_text,     A_NORMAL),
0081     NO_COLOR_ATTR(attr_dialog_menu_fore,    A_STANDOUT),
0082     NO_COLOR_ATTR(attr_dialog_menu_back,    A_NORMAL),
0083     NO_COLOR_ATTR(attr_dialog_box,      A_BOLD),
0084     NO_COLOR_ATTR(attr_input_box,       A_BOLD),
0085     NO_COLOR_ATTR(attr_input_heading,   A_BOLD),
0086     NO_COLOR_ATTR(attr_input_text,      A_NORMAL),
0087     NO_COLOR_ATTR(attr_input_field,     A_UNDERLINE),
0088     NO_COLOR_ATTR(attr_function_text,   A_REVERSE),
0089     NO_COLOR_ATTR(attr_function_highlight,  A_BOLD),
0090     { /* sentinel */ }
0091 };
0092 
0093 void set_colors(void)
0094 {
0095     const struct nconf_attr_param *p;
0096     int pair = 0;
0097 
0098     if (has_colors()) {
0099         start_color();
0100         use_default_colors();
0101         p = color_theme_params;
0102     } else {
0103         p = no_color_theme_params;
0104     }
0105 
0106     for (; p->attr; p++) {
0107         int attr = p->highlight;
0108 
0109         if (p->has_color) {
0110             pair++;
0111             init_pair(pair, p->color_fg, p->color_bg);
0112             attr |= COLOR_PAIR(pair);
0113         }
0114 
0115         *p->attr = attr;
0116     }
0117 }
0118 
0119 /* this changes the windows attributes !!! */
0120 void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs)
0121 {
0122     wattrset(win, attrs);
0123     mvwprintw(win, y, (width - strlen(str)) / 2, "%s", str);
0124 }
0125 
0126 int get_line_no(const char *text)
0127 {
0128     int i;
0129     int total = 1;
0130 
0131     if (!text)
0132         return 0;
0133 
0134     for (i = 0; text[i] != '\0'; i++)
0135         if (text[i] == '\n')
0136             total++;
0137     return total;
0138 }
0139 
0140 const char *get_line(const char *text, int line_no)
0141 {
0142     int i;
0143     int lines = 0;
0144 
0145     if (!text)
0146         return NULL;
0147 
0148     for (i = 0; text[i] != '\0' && lines < line_no; i++)
0149         if (text[i] == '\n')
0150             lines++;
0151     return text+i;
0152 }
0153 
0154 int get_line_length(const char *line)
0155 {
0156     int res = 0;
0157     while (*line != '\0' && *line != '\n') {
0158         line++;
0159         res++;
0160     }
0161     return res;
0162 }
0163 
0164 /* print all lines to the window. */
0165 void fill_window(WINDOW *win, const char *text)
0166 {
0167     int x, y;
0168     int total_lines = get_line_no(text);
0169     int i;
0170 
0171     getmaxyx(win, y, x);
0172     /* do not go over end of line */
0173     total_lines = min(total_lines, y);
0174     for (i = 0; i < total_lines; i++) {
0175         char tmp[x+10];
0176         const char *line = get_line(text, i);
0177         int len = get_line_length(line);
0178         strncpy(tmp, line, min(len, x));
0179         tmp[len] = '\0';
0180         mvwprintw(win, i, 0, "%s", tmp);
0181     }
0182 }
0183 
0184 /* get the message, and buttons.
0185  * each button must be a char*
0186  * return the selected button
0187  *
0188  * this dialog is used for 2 different things:
0189  * 1) show a text box, no buttons.
0190  * 2) show a dialog, with horizontal buttons
0191  */
0192 int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
0193 {
0194     va_list ap;
0195     char *btn;
0196     int btns_width = 0;
0197     int msg_lines = 0;
0198     int msg_width = 0;
0199     int total_width;
0200     int win_rows = 0;
0201     WINDOW *win;
0202     WINDOW *msg_win;
0203     WINDOW *menu_win;
0204     MENU *menu;
0205     ITEM *btns[btn_num+1];
0206     int i, x, y;
0207     int res = -1;
0208 
0209 
0210     va_start(ap, btn_num);
0211     for (i = 0; i < btn_num; i++) {
0212         btn = va_arg(ap, char *);
0213         btns[i] = new_item(btn, "");
0214         btns_width += strlen(btn)+1;
0215     }
0216     va_end(ap);
0217     btns[btn_num] = NULL;
0218 
0219     /* find the widest line of msg: */
0220     msg_lines = get_line_no(msg);
0221     for (i = 0; i < msg_lines; i++) {
0222         const char *line = get_line(msg, i);
0223         int len = get_line_length(line);
0224         if (msg_width < len)
0225             msg_width = len;
0226     }
0227 
0228     total_width = max(msg_width, btns_width);
0229     /* place dialog in middle of screen */
0230     y = (getmaxy(stdscr)-(msg_lines+4))/2;
0231     x = (getmaxx(stdscr)-(total_width+4))/2;
0232 
0233 
0234     /* create the windows */
0235     if (btn_num > 0)
0236         win_rows = msg_lines+4;
0237     else
0238         win_rows = msg_lines+2;
0239 
0240     win = newwin(win_rows, total_width+4, y, x);
0241     keypad(win, TRUE);
0242     menu_win = derwin(win, 1, btns_width, win_rows-2,
0243             1+(total_width+2-btns_width)/2);
0244     menu = new_menu(btns);
0245     msg_win = derwin(win, win_rows-2, msg_width, 1,
0246             1+(total_width+2-msg_width)/2);
0247 
0248     set_menu_fore(menu, attr_dialog_menu_fore);
0249     set_menu_back(menu, attr_dialog_menu_back);
0250 
0251     wattrset(win, attr_dialog_box);
0252     box(win, 0, 0);
0253 
0254     /* print message */
0255     wattrset(msg_win, attr_dialog_text);
0256     fill_window(msg_win, msg);
0257 
0258     set_menu_win(menu, win);
0259     set_menu_sub(menu, menu_win);
0260     set_menu_format(menu, 1, btn_num);
0261     menu_opts_off(menu, O_SHOWDESC);
0262     menu_opts_off(menu, O_SHOWMATCH);
0263     menu_opts_on(menu, O_ONEVALUE);
0264     menu_opts_on(menu, O_NONCYCLIC);
0265     set_menu_mark(menu, "");
0266     post_menu(menu);
0267 
0268 
0269     touchwin(win);
0270     refresh_all_windows(main_window);
0271     while ((res = wgetch(win))) {
0272         switch (res) {
0273         case KEY_LEFT:
0274             menu_driver(menu, REQ_LEFT_ITEM);
0275             break;
0276         case KEY_RIGHT:
0277             menu_driver(menu, REQ_RIGHT_ITEM);
0278             break;
0279         case 10: /* ENTER */
0280         case 27: /* ESCAPE */
0281         case ' ':
0282         case KEY_F(F_BACK):
0283         case KEY_F(F_EXIT):
0284             break;
0285         }
0286         touchwin(win);
0287         refresh_all_windows(main_window);
0288 
0289         if (res == 10 || res == ' ') {
0290             res = item_index(current_item(menu));
0291             break;
0292         } else if (res == 27 || res == KEY_F(F_BACK) ||
0293                 res == KEY_F(F_EXIT)) {
0294             res = KEY_EXIT;
0295             break;
0296         }
0297     }
0298 
0299     unpost_menu(menu);
0300     free_menu(menu);
0301     for (i = 0; i < btn_num; i++)
0302         free_item(btns[i]);
0303 
0304     delwin(win);
0305     return res;
0306 }
0307 
0308 int dialog_inputbox(WINDOW *main_window,
0309         const char *title, const char *prompt,
0310         const char *init, char **resultp, int *result_len)
0311 {
0312     int prompt_lines = 0;
0313     int prompt_width = 0;
0314     WINDOW *win;
0315     WINDOW *prompt_win;
0316     WINDOW *form_win;
0317     PANEL *panel;
0318     int i, x, y, lines, columns, win_lines, win_cols;
0319     int res = -1;
0320     int cursor_position = strlen(init);
0321     int cursor_form_win;
0322     char *result = *resultp;
0323 
0324     getmaxyx(stdscr, lines, columns);
0325 
0326     if (strlen(init)+1 > *result_len) {
0327         *result_len = strlen(init)+1;
0328         *resultp = result = xrealloc(result, *result_len);
0329     }
0330 
0331     /* find the widest line of msg: */
0332     prompt_lines = get_line_no(prompt);
0333     for (i = 0; i < prompt_lines; i++) {
0334         const char *line = get_line(prompt, i);
0335         int len = get_line_length(line);
0336         prompt_width = max(prompt_width, len);
0337     }
0338 
0339     if (title)
0340         prompt_width = max(prompt_width, strlen(title));
0341 
0342     win_lines = min(prompt_lines+6, lines-2);
0343     win_cols = min(prompt_width+7, columns-2);
0344     prompt_lines = max(win_lines-6, 0);
0345     prompt_width = max(win_cols-7, 0);
0346 
0347     /* place dialog in middle of screen */
0348     y = (lines-win_lines)/2;
0349     x = (columns-win_cols)/2;
0350 
0351     strncpy(result, init, *result_len);
0352 
0353     /* create the windows */
0354     win = newwin(win_lines, win_cols, y, x);
0355     prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
0356     form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
0357     keypad(form_win, TRUE);
0358 
0359     wattrset(form_win, attr_input_field);
0360 
0361     wattrset(win, attr_input_box);
0362     box(win, 0, 0);
0363     wattrset(win, attr_input_heading);
0364     if (title)
0365         mvwprintw(win, 0, 3, "%s", title);
0366 
0367     /* print message */
0368     wattrset(prompt_win, attr_input_text);
0369     fill_window(prompt_win, prompt);
0370 
0371     mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
0372     cursor_form_win = min(cursor_position, prompt_width-1);
0373     mvwprintw(form_win, 0, 0, "%s",
0374           result + cursor_position-cursor_form_win);
0375 
0376     /* create panels */
0377     panel = new_panel(win);
0378 
0379     /* show the cursor */
0380     curs_set(1);
0381 
0382     touchwin(win);
0383     refresh_all_windows(main_window);
0384     while ((res = wgetch(form_win))) {
0385         int len = strlen(result);
0386         switch (res) {
0387         case 10: /* ENTER */
0388         case 27: /* ESCAPE */
0389         case KEY_F(F_HELP):
0390         case KEY_F(F_EXIT):
0391         case KEY_F(F_BACK):
0392             break;
0393         case 8:   /* ^H */
0394         case 127: /* ^? */
0395         case KEY_BACKSPACE:
0396             if (cursor_position > 0) {
0397                 memmove(&result[cursor_position-1],
0398                         &result[cursor_position],
0399                         len-cursor_position+1);
0400                 cursor_position--;
0401                 cursor_form_win--;
0402                 len--;
0403             }
0404             break;
0405         case KEY_DC:
0406             if (cursor_position >= 0 && cursor_position < len) {
0407                 memmove(&result[cursor_position],
0408                         &result[cursor_position+1],
0409                         len-cursor_position+1);
0410                 len--;
0411             }
0412             break;
0413         case KEY_UP:
0414         case KEY_RIGHT:
0415             if (cursor_position < len) {
0416                 cursor_position++;
0417                 cursor_form_win++;
0418             }
0419             break;
0420         case KEY_DOWN:
0421         case KEY_LEFT:
0422             if (cursor_position > 0) {
0423                 cursor_position--;
0424                 cursor_form_win--;
0425             }
0426             break;
0427         case KEY_HOME:
0428             cursor_position = 0;
0429             cursor_form_win = 0;
0430             break;
0431         case KEY_END:
0432             cursor_position = len;
0433             cursor_form_win = min(cursor_position, prompt_width-1);
0434             break;
0435         default:
0436             if ((isgraph(res) || isspace(res))) {
0437                 /* one for new char, one for '\0' */
0438                 if (len+2 > *result_len) {
0439                     *result_len = len+2;
0440                     *resultp = result = realloc(result,
0441                                 *result_len);
0442                 }
0443                 /* insert the char at the proper position */
0444                 memmove(&result[cursor_position+1],
0445                         &result[cursor_position],
0446                         len-cursor_position+1);
0447                 result[cursor_position] = res;
0448                 cursor_position++;
0449                 cursor_form_win++;
0450                 len++;
0451             } else {
0452                 mvprintw(0, 0, "unknown key: %d\n", res);
0453             }
0454             break;
0455         }
0456         if (cursor_form_win < 0)
0457             cursor_form_win = 0;
0458         else if (cursor_form_win > prompt_width-1)
0459             cursor_form_win = prompt_width-1;
0460 
0461         wmove(form_win, 0, 0);
0462         wclrtoeol(form_win);
0463         mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
0464         mvwprintw(form_win, 0, 0, "%s",
0465             result + cursor_position-cursor_form_win);
0466         wmove(form_win, 0, cursor_form_win);
0467         touchwin(win);
0468         refresh_all_windows(main_window);
0469 
0470         if (res == 10) {
0471             res = 0;
0472             break;
0473         } else if (res == 27 || res == KEY_F(F_BACK) ||
0474                 res == KEY_F(F_EXIT)) {
0475             res = KEY_EXIT;
0476             break;
0477         } else if (res == KEY_F(F_HELP)) {
0478             res = 1;
0479             break;
0480         }
0481     }
0482 
0483     /* hide the cursor */
0484     curs_set(0);
0485     del_panel(panel);
0486     delwin(prompt_win);
0487     delwin(form_win);
0488     delwin(win);
0489     return res;
0490 }
0491 
0492 /* refresh all windows in the correct order */
0493 void refresh_all_windows(WINDOW *main_window)
0494 {
0495     update_panels();
0496     touchwin(main_window);
0497     refresh();
0498 }
0499 
0500 /* layman's scrollable window... */
0501 void show_scroll_win(WINDOW *main_window,
0502         const char *title,
0503         const char *text)
0504 {
0505     int res;
0506     int total_lines = get_line_no(text);
0507     int x, y, lines, columns;
0508     int start_x = 0, start_y = 0;
0509     int text_lines = 0, text_cols = 0;
0510     int total_cols = 0;
0511     int win_cols = 0;
0512     int win_lines = 0;
0513     int i = 0;
0514     WINDOW *win;
0515     WINDOW *pad;
0516     PANEL *panel;
0517 
0518     getmaxyx(stdscr, lines, columns);
0519 
0520     /* find the widest line of msg: */
0521     total_lines = get_line_no(text);
0522     for (i = 0; i < total_lines; i++) {
0523         const char *line = get_line(text, i);
0524         int len = get_line_length(line);
0525         total_cols = max(total_cols, len+2);
0526     }
0527 
0528     /* create the pad */
0529     pad = newpad(total_lines+10, total_cols+10);
0530     wattrset(pad, attr_scrollwin_text);
0531     fill_window(pad, text);
0532 
0533     win_lines = min(total_lines+4, lines-2);
0534     win_cols = min(total_cols+2, columns-2);
0535     text_lines = max(win_lines-4, 0);
0536     text_cols = max(win_cols-2, 0);
0537 
0538     /* place window in middle of screen */
0539     y = (lines-win_lines)/2;
0540     x = (columns-win_cols)/2;
0541 
0542     win = newwin(win_lines, win_cols, y, x);
0543     keypad(win, TRUE);
0544     /* show the help in the help window, and show the help panel */
0545     wattrset(win, attr_scrollwin_box);
0546     box(win, 0, 0);
0547     wattrset(win, attr_scrollwin_heading);
0548     mvwprintw(win, 0, 3, " %s ", title);
0549     panel = new_panel(win);
0550 
0551     /* handle scrolling */
0552     do {
0553 
0554         copywin(pad, win, start_y, start_x, 2, 2, text_lines,
0555                 text_cols, 0);
0556         print_in_middle(win,
0557                 text_lines+2,
0558                 text_cols,
0559                 "<OK>",
0560                 attr_dialog_menu_fore);
0561         wrefresh(win);
0562 
0563         res = wgetch(win);
0564         switch (res) {
0565         case KEY_NPAGE:
0566         case ' ':
0567         case 'd':
0568             start_y += text_lines-2;
0569             break;
0570         case KEY_PPAGE:
0571         case 'u':
0572             start_y -= text_lines+2;
0573             break;
0574         case KEY_HOME:
0575             start_y = 0;
0576             break;
0577         case KEY_END:
0578             start_y = total_lines-text_lines;
0579             break;
0580         case KEY_DOWN:
0581         case 'j':
0582             start_y++;
0583             break;
0584         case KEY_UP:
0585         case 'k':
0586             start_y--;
0587             break;
0588         case KEY_LEFT:
0589         case 'h':
0590             start_x--;
0591             break;
0592         case KEY_RIGHT:
0593         case 'l':
0594             start_x++;
0595             break;
0596         }
0597         if (res == 10 || res == 27 || res == 'q' ||
0598             res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
0599             res == KEY_F(F_EXIT))
0600             break;
0601         if (start_y < 0)
0602             start_y = 0;
0603         if (start_y >= total_lines-text_lines)
0604             start_y = total_lines-text_lines;
0605         if (start_x < 0)
0606             start_x = 0;
0607         if (start_x >= total_cols-text_cols)
0608             start_x = total_cols-text_cols;
0609     } while (res);
0610 
0611     del_panel(panel);
0612     delwin(win);
0613     refresh_all_windows(main_window);
0614 }