1 /* 2 * textbox.c -- implements the text box 3 * 4 * ORIGINAL AUTHOR: Savio Lam (lam836 (at) cs.cuhk.hk) 5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap (at) 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, " 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 delwin(box); 133 delwin(dialog); 134 return 0; 135 case 'g': /* First page */ 136 case KEY_HOME: 137 if (!begin_reached) { 138 begin_reached = 1; 139 page = buf; 140 refresh_text_box(dialog, box, boxh, boxw, 141 cur_y, cur_x); 142 } 143 break; 144 case 'G': /* Last page */ 145 case KEY_END: 146 147 end_reached = 1; 148 /* point to last char in buf */ 149 page = buf + strlen(buf); 150 back_lines(boxh); 151 refresh_text_box(dialog, box, boxh, boxw, 152 cur_y, cur_x); 153 break; 154 case 'K': /* Previous line */ 155 case 'k': 156 case KEY_UP: 157 if (!begin_reached) { 158 back_lines(page_length + 1); 159 160 /* We don't call print_page() here but use 161 * scrolling to ensure faster screen update. 162 * However, 'end_reached' and 'page_length' 163 * should still be updated, and 'page' should 164 * point to start of next page. This is done 165 * by calling get_line() in the following 166 * 'for' loop. */ 167 scrollok(box, TRUE); 168 wscrl(box, -1); /* Scroll box region down one line */ 169 scrollok(box, FALSE); 170 page_length = 0; 171 passed_end = 0; 172 for (i = 0; i < boxh; i++) { 173 if (!i) { 174 /* print first line of page */ 175 print_line(box, 0, boxw); 176 wnoutrefresh(box); 177 } else 178 /* Called to update 'end_reached' and 'page' */ 179 get_line(); 180 if (!passed_end) 181 page_length++; 182 if (end_reached && !passed_end) 183 passed_end = 1; 184 } 185 186 print_position(dialog); 187 wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 188 wrefresh(dialog); 189 } 190 break; 191 case 'B': /* Previous page */ 192 case 'b': 193 case KEY_PPAGE: 194 if (begin_reached) 195 break; 196 back_lines(page_length + boxh); 197 refresh_text_box(dialog, box, boxh, boxw, 198 cur_y, cur_x); 199 break; 200 case 'J': /* Next line */ 201 case 'j': 202 case KEY_DOWN: 203 if (!end_reached) { 204 begin_reached = 0; 205 scrollok(box, TRUE); 206 scroll(box); /* Scroll box region up one line */ 207 scrollok(box, FALSE); 208 print_line(box, boxh - 1, boxw); 209 wnoutrefresh(box); 210 print_position(dialog); 211 wmove(dialog, cur_y, cur_x); /* Restore cursor position */ 212 wrefresh(dialog); 213 } 214 break; 215 case KEY_NPAGE: /* Next page */ 216 case ' ': 217 if (end_reached) 218 break; 219 220 begin_reached = 0; 221 refresh_text_box(dialog, box, boxh, boxw, 222 cur_y, cur_x); 223 break; 224 case '0': /* Beginning of line */ 225 case 'H': /* Scroll left */ 226 case 'h': 227 case KEY_LEFT: 228 if (hscroll <= 0) 229 break; 230 231 if (key == '0') 232 hscroll = 0; 233 else 234 hscroll--; 235 /* Reprint current page to scroll horizontally */ 236 back_lines(page_length); 237 refresh_text_box(dialog, box, boxh, boxw, 238 cur_y, cur_x); 239 break; 240 case 'L': /* Scroll right */ 241 case 'l': 242 case KEY_RIGHT: 243 if (hscroll >= MAX_LEN) 244 break; 245 hscroll++; 246 /* Reprint current page to scroll horizontally */ 247 back_lines(page_length); 248 refresh_text_box(dialog, box, boxh, boxw, 249 cur_y, cur_x); 250 break; 251 case KEY_ESC: 252 key = on_key_esc(dialog); 253 break; 254 case KEY_RESIZE: 255 back_lines(height); 256 delwin(box); 257 delwin(dialog); 258 on_key_resize(); 259 goto do_resize; 260 } 261 } 262 delwin(box); 263 delwin(dialog); 264 return key; /* ESC pressed */ 265 } 266 267 /* 268 * Go back 'n' lines in text. Called by dialog_textbox(). 269 * 'page' will be updated to point to the desired line in 'buf'. 270 */ 271 static void back_lines(int n) 272 { 273 int i; 274 275 begin_reached = 0; 276 /* Go back 'n' lines */ 277 for (i = 0; i < n; i++) { 278 if (*page == '\0') { 279 if (end_reached) { 280 end_reached = 0; 281 continue; 282 } 283 } 284 if (page == buf) { 285 begin_reached = 1; 286 return; 287 } 288 page--; 289 do { 290 if (page == buf) { 291 begin_reached = 1; 292 return; 293 } 294 page--; 295 } while (*page != '\n'); 296 page++; 297 } 298 } 299 300 /* 301 * Print a new page of text. Called by dialog_textbox(). 302 */ 303 static void print_page(WINDOW * win, int height, int width) 304 { 305 int i, passed_end = 0; 306 307 page_length = 0; 308 for (i = 0; i < height; i++) { 309 print_line(win, i, width); 310 if (!passed_end) 311 page_length++; 312 if (end_reached && !passed_end) 313 passed_end = 1; 314 } 315 wnoutrefresh(win); 316 } 317 318 /* 319 * Print a new line of text. Called by dialog_textbox() and print_page(). 320 */ 321 static void print_line(WINDOW * win, int row, int width) 322 { 323 int y, x; 324 char *line; 325 326 line = get_line(); 327 line += MIN(strlen(line), hscroll); /* Scroll horizontally */ 328 wmove(win, row, 0); /* move cursor to correct line */ 329 waddch(win, ' '); 330 waddnstr(win, line, MIN(strlen(line), width - 2)); 331 332 getyx(win, y, x); 333 /* Clear 'residue' of previous line */ 334 #if OLD_NCURSES 335 { 336 int i; 337 for (i = 0; i < width - x; i++) 338 waddch(win, ' '); 339 } 340 #else 341 wclrtoeol(win); 342 #endif 343 } 344 345 /* 346 * Return current line of text. Called by dialog_textbox() and print_line(). 347 * 'page' should point to start of current line before calling, and will be 348 * updated to point to start of next line. 349 */ 350 static char *get_line(void) 351 { 352 int i = 0; 353 static char line[MAX_LEN + 1]; 354 355 end_reached = 0; 356 while (*page != '\n') { 357 if (*page == '\0') { 358 if (!end_reached) { 359 end_reached = 1; 360 break; 361 } 362 } else if (i < MAX_LEN) 363 line[i++] = *(page++); 364 else { 365 /* Truncate lines longer than MAX_LEN characters */ 366 if (i == MAX_LEN) 367 line[i++] = '\0'; 368 page++; 369 } 370 } 371 if (i <= MAX_LEN) 372 line[i] = '\0'; 373 if (!end_reached) 374 page++; /* move pass '\n' */ 375 376 return line; 377 } 378 379 /* 380 * Print current position 381 */ 382 static void print_position(WINDOW * win) 383 { 384 int percent; 385 386 wattrset(win, dlg.position_indicator.atr); 387 wbkgdset(win, dlg.position_indicator.atr & A_COLOR); 388 percent = (page - buf) * 100 / strlen(buf); 389 wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); 390 wprintw(win, "(%3d%%)", percent); 391 } 392