Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  textbox.c -- implements the text box
0004  *
0005  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
0006  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
0007  */
0008 
0009 #include "dialog.h"
0010 
0011 static void back_lines(int n);
0012 static void print_page(WINDOW *win, int height, int width, update_text_fn
0013                update_text, void *data);
0014 static void print_line(WINDOW *win, int row, int width);
0015 static char *get_line(void);
0016 static void print_position(WINDOW * win);
0017 
0018 static int hscroll;
0019 static int begin_reached, end_reached, page_length;
0020 static char *buf;
0021 static char *page;
0022 
0023 /*
0024  * refresh window content
0025  */
0026 static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
0027                  int cur_y, int cur_x, update_text_fn update_text,
0028                  void *data)
0029 {
0030     print_page(box, boxh, boxw, update_text, data);
0031     print_position(dialog);
0032     wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
0033     wrefresh(dialog);
0034 }
0035 
0036 
0037 /*
0038  * Display text from a file in a dialog box.
0039  *
0040  * keys is a null-terminated array
0041  * update_text() may not add or remove any '\n' or '\0' in tbuf
0042  */
0043 int dialog_textbox(const char *title, char *tbuf, int initial_height,
0044            int initial_width, int *keys, int *_vscroll, int *_hscroll,
0045            update_text_fn update_text, void *data)
0046 {
0047     int i, x, y, cur_x, cur_y, key = 0;
0048     int height, width, boxh, boxw;
0049     WINDOW *dialog, *box;
0050     bool done = false;
0051 
0052     begin_reached = 1;
0053     end_reached = 0;
0054     page_length = 0;
0055     hscroll = 0;
0056     buf = tbuf;
0057     page = buf; /* page is pointer to start of page to be displayed */
0058 
0059     if (_vscroll && *_vscroll) {
0060         begin_reached = 0;
0061 
0062         for (i = 0; i < *_vscroll; i++)
0063             get_line();
0064     }
0065     if (_hscroll)
0066         hscroll = *_hscroll;
0067 
0068 do_resize:
0069     getmaxyx(stdscr, height, width);
0070     if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
0071         return -ERRDISPLAYTOOSMALL;
0072     if (initial_height != 0)
0073         height = initial_height;
0074     else
0075         if (height > 4)
0076             height -= 4;
0077         else
0078             height = 0;
0079     if (initial_width != 0)
0080         width = initial_width;
0081     else
0082         if (width > 5)
0083             width -= 5;
0084         else
0085             width = 0;
0086 
0087     /* center dialog box on screen */
0088     x = (getmaxx(stdscr) - width) / 2;
0089     y = (getmaxy(stdscr) - height) / 2;
0090 
0091     draw_shadow(stdscr, y, x, height, width);
0092 
0093     dialog = newwin(height, width, y, x);
0094     keypad(dialog, TRUE);
0095 
0096     /* Create window for box region, used for scrolling text */
0097     boxh = height - 4;
0098     boxw = width - 2;
0099     box = subwin(dialog, boxh, boxw, y + 1, x + 1);
0100     wattrset(box, dlg.dialog.atr);
0101     wbkgdset(box, dlg.dialog.atr & A_COLOR);
0102 
0103     keypad(box, TRUE);
0104 
0105     /* register the new window, along with its borders */
0106     draw_box(dialog, 0, 0, height, width,
0107          dlg.dialog.atr, dlg.border.atr);
0108 
0109     wattrset(dialog, dlg.border.atr);
0110     mvwaddch(dialog, height - 3, 0, ACS_LTEE);
0111     for (i = 0; i < width - 2; i++)
0112         waddch(dialog, ACS_HLINE);
0113     wattrset(dialog, dlg.dialog.atr);
0114     wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
0115     waddch(dialog, ACS_RTEE);
0116 
0117     print_title(dialog, title, width);
0118 
0119     print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
0120     wnoutrefresh(dialog);
0121     getyx(dialog, cur_y, cur_x);    /* Save cursor position */
0122 
0123     /* Print first page of text */
0124     attr_clear(box, boxh, boxw, dlg.dialog.atr);
0125     refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
0126              data);
0127 
0128     while (!done) {
0129         key = wgetch(dialog);
0130         switch (key) {
0131         case 'E':   /* Exit */
0132         case 'e':
0133         case 'X':
0134         case 'x':
0135         case 'q':
0136         case '\n':
0137             done = true;
0138             break;
0139         case 'g':   /* First page */
0140         case KEY_HOME:
0141             if (!begin_reached) {
0142                 begin_reached = 1;
0143                 page = buf;
0144                 refresh_text_box(dialog, box, boxh, boxw,
0145                          cur_y, cur_x, update_text,
0146                          data);
0147             }
0148             break;
0149         case 'G':   /* Last page */
0150         case KEY_END:
0151 
0152             end_reached = 1;
0153             /* point to last char in buf */
0154             page = buf + strlen(buf);
0155             back_lines(boxh);
0156             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0157                      cur_x, update_text, data);
0158             break;
0159         case 'K':   /* Previous line */
0160         case 'k':
0161         case KEY_UP:
0162             if (begin_reached)
0163                 break;
0164 
0165             back_lines(page_length + 1);
0166             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0167                      cur_x, update_text, data);
0168             break;
0169         case 'B':   /* Previous page */
0170         case 'b':
0171         case 'u':
0172         case KEY_PPAGE:
0173             if (begin_reached)
0174                 break;
0175             back_lines(page_length + boxh);
0176             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0177                      cur_x, update_text, data);
0178             break;
0179         case 'J':   /* Next line */
0180         case 'j':
0181         case KEY_DOWN:
0182             if (end_reached)
0183                 break;
0184 
0185             back_lines(page_length - 1);
0186             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0187                      cur_x, update_text, data);
0188             break;
0189         case KEY_NPAGE: /* Next page */
0190         case ' ':
0191         case 'd':
0192             if (end_reached)
0193                 break;
0194 
0195             begin_reached = 0;
0196             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0197                      cur_x, update_text, data);
0198             break;
0199         case '0':   /* Beginning of line */
0200         case 'H':   /* Scroll left */
0201         case 'h':
0202         case KEY_LEFT:
0203             if (hscroll <= 0)
0204                 break;
0205 
0206             if (key == '0')
0207                 hscroll = 0;
0208             else
0209                 hscroll--;
0210             /* Reprint current page to scroll horizontally */
0211             back_lines(page_length);
0212             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0213                      cur_x, update_text, data);
0214             break;
0215         case 'L':   /* Scroll right */
0216         case 'l':
0217         case KEY_RIGHT:
0218             if (hscroll >= MAX_LEN)
0219                 break;
0220             hscroll++;
0221             /* Reprint current page to scroll horizontally */
0222             back_lines(page_length);
0223             refresh_text_box(dialog, box, boxh, boxw, cur_y,
0224                      cur_x, update_text, data);
0225             break;
0226         case KEY_ESC:
0227             if (on_key_esc(dialog) == KEY_ESC)
0228                 done = true;
0229             break;
0230         case KEY_RESIZE:
0231             back_lines(height);
0232             delwin(box);
0233             delwin(dialog);
0234             on_key_resize();
0235             goto do_resize;
0236         default:
0237             for (i = 0; keys[i]; i++) {
0238                 if (key == keys[i]) {
0239                     done = true;
0240                     break;
0241                 }
0242             }
0243         }
0244     }
0245     delwin(box);
0246     delwin(dialog);
0247     if (_vscroll) {
0248         const char *s;
0249 
0250         s = buf;
0251         *_vscroll = 0;
0252         back_lines(page_length);
0253         while (s < page && (s = strchr(s, '\n'))) {
0254             (*_vscroll)++;
0255             s++;
0256         }
0257     }
0258     if (_hscroll)
0259         *_hscroll = hscroll;
0260     return key;
0261 }
0262 
0263 /*
0264  * Go back 'n' lines in text. Called by dialog_textbox().
0265  * 'page' will be updated to point to the desired line in 'buf'.
0266  */
0267 static void back_lines(int n)
0268 {
0269     int i;
0270 
0271     begin_reached = 0;
0272     /* Go back 'n' lines */
0273     for (i = 0; i < n; i++) {
0274         if (*page == '\0') {
0275             if (end_reached) {
0276                 end_reached = 0;
0277                 continue;
0278             }
0279         }
0280         if (page == buf) {
0281             begin_reached = 1;
0282             return;
0283         }
0284         page--;
0285         do {
0286             if (page == buf) {
0287                 begin_reached = 1;
0288                 return;
0289             }
0290             page--;
0291         } while (*page != '\n');
0292         page++;
0293     }
0294 }
0295 
0296 /*
0297  * Print a new page of text.
0298  */
0299 static void print_page(WINDOW *win, int height, int width, update_text_fn
0300                update_text, void *data)
0301 {
0302     int i, passed_end = 0;
0303 
0304     if (update_text) {
0305         char *end;
0306 
0307         for (i = 0; i < height; i++)
0308             get_line();
0309         end = page;
0310         back_lines(height);
0311         update_text(buf, page - buf, end - buf, data);
0312     }
0313 
0314     page_length = 0;
0315     for (i = 0; i < height; i++) {
0316         print_line(win, i, width);
0317         if (!passed_end)
0318             page_length++;
0319         if (end_reached && !passed_end)
0320             passed_end = 1;
0321     }
0322     wnoutrefresh(win);
0323 }
0324 
0325 /*
0326  * Print a new line of text.
0327  */
0328 static void print_line(WINDOW * win, int row, int width)
0329 {
0330     char *line;
0331 
0332     line = get_line();
0333     line += MIN(strlen(line), hscroll); /* Scroll horizontally */
0334     wmove(win, row, 0); /* move cursor to correct line */
0335     waddch(win, ' ');
0336     waddnstr(win, line, MIN(strlen(line), width - 2));
0337 
0338     /* Clear 'residue' of previous line */
0339 #if OLD_NCURSES
0340     {
0341         int x = getcurx(win);
0342         int i;
0343         for (i = 0; i < width - x; i++)
0344             waddch(win, ' ');
0345     }
0346 #else
0347     wclrtoeol(win);
0348 #endif
0349 }
0350 
0351 /*
0352  * Return current line of text. Called by dialog_textbox() and print_line().
0353  * 'page' should point to start of current line before calling, and will be
0354  * updated to point to start of next line.
0355  */
0356 static char *get_line(void)
0357 {
0358     int i = 0;
0359     static char line[MAX_LEN + 1];
0360 
0361     end_reached = 0;
0362     while (*page != '\n') {
0363         if (*page == '\0') {
0364             end_reached = 1;
0365             break;
0366         } else if (i < MAX_LEN)
0367             line[i++] = *(page++);
0368         else {
0369             /* Truncate lines longer than MAX_LEN characters */
0370             if (i == MAX_LEN)
0371                 line[i++] = '\0';
0372             page++;
0373         }
0374     }
0375     if (i <= MAX_LEN)
0376         line[i] = '\0';
0377     if (!end_reached)
0378         page++;     /* move past '\n' */
0379 
0380     return line;
0381 }
0382 
0383 /*
0384  * Print current position
0385  */
0386 static void print_position(WINDOW * win)
0387 {
0388     int percent;
0389 
0390     wattrset(win, dlg.position_indicator.atr);
0391     wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
0392     percent = (page - buf) * 100 / strlen(buf);
0393     wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
0394     wprintw(win, "(%3d%%)", percent);
0395 }