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