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 != 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 KEY_ESC: 232 key = on_key_esc(dialog); 233 break; 234 } 235 } 236 delwin(text); 237 delwin(dialog); 238 return key; /* ESC pressed */ 239 } 240 241 /* 242 * Go back 'n' lines in text. Called by dialog_textbox(). 243 * 'page' will be updated to point to the desired line in 'buf'. 244 */ 245 static void back_lines(int n) 246 { 247 int i; 248 249 begin_reached = 0; 250 /* Go back 'n' lines */ 251 for (i = 0; i < n; i++) { 252 if (*page == '\0') { 253 if (end_reached) { 254 end_reached = 0; 255 continue; 256 } 257 } 258 if (page == buf) { 259 begin_reached = 1; 260 return; 261 } 262 page--; 263 do { 264 if (page == buf) { 265 begin_reached = 1; 266 return; 267 } 268 page--; 269 } while (*page != '\n'); 270 page++; 271 } 272 } 273 274 /* 275 * Print a new page of text. Called by dialog_textbox(). 276 */ 277 static void print_page(WINDOW * win, int height, int width) 278 { 279 int i, passed_end = 0; 280 281 page_length = 0; 282 for (i = 0; i < height; i++) { 283 print_line(win, i, width); 284 if (!passed_end) 285 page_length++; 286 if (end_reached && !passed_end) 287 passed_end = 1; 288 } 289 wnoutrefresh(win); 290 } 291 292 /* 293 * Print a new line of text. Called by dialog_textbox() and print_page(). 294 */ 295 static void print_line(WINDOW * win, int row, int width) 296 { 297 int y, x; 298 char *line; 299 300 line = get_line(); 301 line += MIN(strlen(line), hscroll); /* Scroll horizontally */ 302 wmove(win, row, 0); /* move cursor to correct line */ 303 waddch(win, ' '); 304 waddnstr(win, line, MIN(strlen(line), width - 2)); 305 306 getyx(win, y, x); 307 /* Clear 'residue' of previous line */ 308 #if OLD_NCURSES 309 { 310 int i; 311 for (i = 0; i < width - x; i++) 312 waddch(win, ' '); 313 } 314 #else 315 wclrtoeol(win); 316 #endif 317 } 318 319 /* 320 * Return current line of text. Called by dialog_textbox() and print_line(). 321 * 'page' should point to start of current line before calling, and will be 322 * updated to point to start of next line. 323 */ 324 static char *get_line(void) 325 { 326 int i = 0; 327 static char line[MAX_LEN + 1]; 328 329 end_reached = 0; 330 while (*page != '\n') { 331 if (*page == '\0') { 332 if (!end_reached) { 333 end_reached = 1; 334 break; 335 } 336 } else if (i < MAX_LEN) 337 line[i++] = *(page++); 338 else { 339 /* Truncate lines longer than MAX_LEN characters */ 340 if (i == MAX_LEN) 341 line[i++] = '\0'; 342 page++; 343 } 344 } 345 if (i <= MAX_LEN) 346 line[i] = '\0'; 347 if (!end_reached) 348 page++; /* move pass '\n' */ 349 350 return line; 351 } 352 353 /* 354 * Print current position 355 */ 356 static void print_position(WINDOW * win, int height, int width) 357 { 358 int percent; 359 360 wattrset(win, dlg.position_indicator.atr); 361 wbkgdset(win, dlg.position_indicator.atr & A_COLOR); 362 percent = (page - buf) * 100 / strlen(buf); 363 wmove(win, height - 3, width - 9); 364 wprintw(win, "(%3d%%)", percent); 365 } 366