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