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