root/scripts/kconfig/lxdialog/textbox.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. refresh_text_box
  2. dialog_textbox
  3. back_lines
  4. print_page
  5. print_line
  6. get_line
  7. print_position

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  *  textbox.c -- implements the text box
   4  *
   5  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
   6  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
   7  */
   8 
   9 #include "dialog.h"
  10 
  11 static void back_lines(int n);
  12 static void print_page(WINDOW *win, int height, int width, update_text_fn
  13                        update_text, void *data);
  14 static void print_line(WINDOW *win, int row, int width);
  15 static char *get_line(void);
  16 static void print_position(WINDOW * win);
  17 
  18 static int hscroll;
  19 static int begin_reached, end_reached, page_length;
  20 static char *buf;
  21 static char *page;
  22 
  23 /*
  24  * refresh window content
  25  */
  26 static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
  27                              int cur_y, int cur_x, update_text_fn update_text,
  28                              void *data)
  29 {
  30         print_page(box, boxh, boxw, update_text, data);
  31         print_position(dialog);
  32         wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
  33         wrefresh(dialog);
  34 }
  35 
  36 
  37 /*
  38  * Display text from a file in a dialog box.
  39  *
  40  * keys is a null-terminated array
  41  * update_text() may not add or remove any '\n' or '\0' in tbuf
  42  */
  43 int dialog_textbox(const char *title, char *tbuf, int initial_height,
  44                    int initial_width, int *keys, int *_vscroll, int *_hscroll,
  45                    update_text_fn update_text, void *data)
  46 {
  47         int i, x, y, cur_x, cur_y, key = 0;
  48         int height, width, boxh, boxw;
  49         WINDOW *dialog, *box;
  50         bool done = false;
  51 
  52         begin_reached = 1;
  53         end_reached = 0;
  54         page_length = 0;
  55         hscroll = 0;
  56         buf = tbuf;
  57         page = buf;     /* page is pointer to start of page to be displayed */
  58 
  59         if (_vscroll && *_vscroll) {
  60                 begin_reached = 0;
  61 
  62                 for (i = 0; i < *_vscroll; i++)
  63                         get_line();
  64         }
  65         if (_hscroll)
  66                 hscroll = *_hscroll;
  67 
  68 do_resize:
  69         getmaxyx(stdscr, height, width);
  70         if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
  71                 return -ERRDISPLAYTOOSMALL;
  72         if (initial_height != 0)
  73                 height = initial_height;
  74         else
  75                 if (height > 4)
  76                         height -= 4;
  77                 else
  78                         height = 0;
  79         if (initial_width != 0)
  80                 width = initial_width;
  81         else
  82                 if (width > 5)
  83                         width -= 5;
  84                 else
  85                         width = 0;
  86 
  87         /* center dialog box on screen */
  88         x = (getmaxx(stdscr) - width) / 2;
  89         y = (getmaxy(stdscr) - height) / 2;
  90 
  91         draw_shadow(stdscr, y, x, height, width);
  92 
  93         dialog = newwin(height, width, y, x);
  94         keypad(dialog, TRUE);
  95 
  96         /* Create window for box region, used for scrolling text */
  97         boxh = height - 4;
  98         boxw = width - 2;
  99         box = subwin(dialog, boxh, boxw, y + 1, x + 1);
 100         wattrset(box, dlg.dialog.atr);
 101         wbkgdset(box, dlg.dialog.atr & A_COLOR);
 102 
 103         keypad(box, TRUE);
 104 
 105         /* register the new window, along with its borders */
 106         draw_box(dialog, 0, 0, height, width,
 107                  dlg.dialog.atr, dlg.border.atr);
 108 
 109         wattrset(dialog, dlg.border.atr);
 110         mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 111         for (i = 0; i < width - 2; i++)
 112                 waddch(dialog, ACS_HLINE);
 113         wattrset(dialog, dlg.dialog.atr);
 114         wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
 115         waddch(dialog, ACS_RTEE);
 116 
 117         print_title(dialog, title, width);
 118 
 119         print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
 120         wnoutrefresh(dialog);
 121         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
 122 
 123         /* Print first page of text */
 124         attr_clear(box, boxh, boxw, dlg.dialog.atr);
 125         refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
 126                          data);
 127 
 128         while (!done) {
 129                 key = wgetch(dialog);
 130                 switch (key) {
 131                 case 'E':       /* Exit */
 132                 case 'e':
 133                 case 'X':
 134                 case 'x':
 135                 case 'q':
 136                 case '\n':
 137                         done = true;
 138                         break;
 139                 case 'g':       /* First page */
 140                 case KEY_HOME:
 141                         if (!begin_reached) {
 142                                 begin_reached = 1;
 143                                 page = buf;
 144                                 refresh_text_box(dialog, box, boxh, boxw,
 145                                                  cur_y, cur_x, update_text,
 146                                                  data);
 147                         }
 148                         break;
 149                 case 'G':       /* Last page */
 150                 case KEY_END:
 151 
 152                         end_reached = 1;
 153                         /* point to last char in buf */
 154                         page = buf + strlen(buf);
 155                         back_lines(boxh);
 156                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 157                                          cur_x, update_text, data);
 158                         break;
 159                 case 'K':       /* Previous line */
 160                 case 'k':
 161                 case KEY_UP:
 162                         if (begin_reached)
 163                                 break;
 164 
 165                         back_lines(page_length + 1);
 166                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 167                                          cur_x, update_text, data);
 168                         break;
 169                 case 'B':       /* Previous page */
 170                 case 'b':
 171                 case 'u':
 172                 case KEY_PPAGE:
 173                         if (begin_reached)
 174                                 break;
 175                         back_lines(page_length + boxh);
 176                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 177                                          cur_x, update_text, data);
 178                         break;
 179                 case 'J':       /* Next line */
 180                 case 'j':
 181                 case KEY_DOWN:
 182                         if (end_reached)
 183                                 break;
 184 
 185                         back_lines(page_length - 1);
 186                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 187                                          cur_x, update_text, data);
 188                         break;
 189                 case KEY_NPAGE: /* Next page */
 190                 case ' ':
 191                 case 'd':
 192                         if (end_reached)
 193                                 break;
 194 
 195                         begin_reached = 0;
 196                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 197                                          cur_x, update_text, data);
 198                         break;
 199                 case '0':       /* Beginning of line */
 200                 case 'H':       /* Scroll left */
 201                 case 'h':
 202                 case KEY_LEFT:
 203                         if (hscroll <= 0)
 204                                 break;
 205 
 206                         if (key == '0')
 207                                 hscroll = 0;
 208                         else
 209                                 hscroll--;
 210                         /* Reprint current page to scroll horizontally */
 211                         back_lines(page_length);
 212                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 213                                          cur_x, update_text, data);
 214                         break;
 215                 case 'L':       /* Scroll right */
 216                 case 'l':
 217                 case KEY_RIGHT:
 218                         if (hscroll >= MAX_LEN)
 219                                 break;
 220                         hscroll++;
 221                         /* Reprint current page to scroll horizontally */
 222                         back_lines(page_length);
 223                         refresh_text_box(dialog, box, boxh, boxw, cur_y,
 224                                          cur_x, update_text, data);
 225                         break;
 226                 case KEY_ESC:
 227                         if (on_key_esc(dialog) == KEY_ESC)
 228                                 done = true;
 229                         break;
 230                 case KEY_RESIZE:
 231                         back_lines(height);
 232                         delwin(box);
 233                         delwin(dialog);
 234                         on_key_resize();
 235                         goto do_resize;
 236                 default:
 237                         for (i = 0; keys[i]; i++) {
 238                                 if (key == keys[i]) {
 239                                         done = true;
 240                                         break;
 241                                 }
 242                         }
 243                 }
 244         }
 245         delwin(box);
 246         delwin(dialog);
 247         if (_vscroll) {
 248                 const char *s;
 249 
 250                 s = buf;
 251                 *_vscroll = 0;
 252                 back_lines(page_length);
 253                 while (s < page && (s = strchr(s, '\n'))) {
 254                         (*_vscroll)++;
 255                         s++;
 256                 }
 257         }
 258         if (_hscroll)
 259                 *_hscroll = hscroll;
 260         return key;
 261 }
 262 
 263 /*
 264  * Go back 'n' lines in text. Called by dialog_textbox().
 265  * 'page' will be updated to point to the desired line in 'buf'.
 266  */
 267 static void back_lines(int n)
 268 {
 269         int i;
 270 
 271         begin_reached = 0;
 272         /* Go back 'n' lines */
 273         for (i = 0; i < n; i++) {
 274                 if (*page == '\0') {
 275                         if (end_reached) {
 276                                 end_reached = 0;
 277                                 continue;
 278                         }
 279                 }
 280                 if (page == buf) {
 281                         begin_reached = 1;
 282                         return;
 283                 }
 284                 page--;
 285                 do {
 286                         if (page == buf) {
 287                                 begin_reached = 1;
 288                                 return;
 289                         }
 290                         page--;
 291                 } while (*page != '\n');
 292                 page++;
 293         }
 294 }
 295 
 296 /*
 297  * Print a new page of text.
 298  */
 299 static void print_page(WINDOW *win, int height, int width, update_text_fn
 300                        update_text, void *data)
 301 {
 302         int i, passed_end = 0;
 303 
 304         if (update_text) {
 305                 char *end;
 306 
 307                 for (i = 0; i < height; i++)
 308                         get_line();
 309                 end = page;
 310                 back_lines(height);
 311                 update_text(buf, page - buf, end - buf, data);
 312         }
 313 
 314         page_length = 0;
 315         for (i = 0; i < height; i++) {
 316                 print_line(win, i, width);
 317                 if (!passed_end)
 318                         page_length++;
 319                 if (end_reached && !passed_end)
 320                         passed_end = 1;
 321         }
 322         wnoutrefresh(win);
 323 }
 324 
 325 /*
 326  * Print a new line of text.
 327  */
 328 static void print_line(WINDOW * win, int row, int width)
 329 {
 330         char *line;
 331 
 332         line = get_line();
 333         line += MIN(strlen(line), hscroll);     /* Scroll horizontally */
 334         wmove(win, row, 0);     /* move cursor to correct line */
 335         waddch(win, ' ');
 336         waddnstr(win, line, MIN(strlen(line), width - 2));
 337 
 338         /* Clear 'residue' of previous line */
 339 #if OLD_NCURSES
 340         {
 341                 int x = getcurx(win);
 342                 int i;
 343                 for (i = 0; i < width - x; i++)
 344                         waddch(win, ' ');
 345         }
 346 #else
 347         wclrtoeol(win);
 348 #endif
 349 }
 350 
 351 /*
 352  * Return current line of text. Called by dialog_textbox() and print_line().
 353  * 'page' should point to start of current line before calling, and will be
 354  * updated to point to start of next line.
 355  */
 356 static char *get_line(void)
 357 {
 358         int i = 0;
 359         static char line[MAX_LEN + 1];
 360 
 361         end_reached = 0;
 362         while (*page != '\n') {
 363                 if (*page == '\0') {
 364                         end_reached = 1;
 365                         break;
 366                 } else if (i < MAX_LEN)
 367                         line[i++] = *(page++);
 368                 else {
 369                         /* Truncate lines longer than MAX_LEN characters */
 370                         if (i == MAX_LEN)
 371                                 line[i++] = '\0';
 372                         page++;
 373                 }
 374         }
 375         if (i <= MAX_LEN)
 376                 line[i] = '\0';
 377         if (!end_reached)
 378                 page++;         /* move past '\n' */
 379 
 380         return line;
 381 }
 382 
 383 /*
 384  * Print current position
 385  */
 386 static void print_position(WINDOW * win)
 387 {
 388         int percent;
 389 
 390         wattrset(win, dlg.position_indicator.atr);
 391         wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
 392         percent = (page - buf) * 100 / strlen(buf);
 393         wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
 394         wprintw(win, "(%3d%%)", percent);
 395 }

/* [<][>][^][v][top][bottom][index][help] */