]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
b1c5f1c6 SR |
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); | |
c8dc68ad | 28 | static void print_position(WINDOW * win); |
1da177e4 | 29 | |
2982de69 SR |
30 | static int hscroll; |
31 | static int begin_reached, end_reached, page_length; | |
32 | static const char *buf; | |
33 | static const char *page; | |
1da177e4 | 34 | |
c8dc68ad SR |
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 | ||
1da177e4 LT |
48 | /* |
49 | * Display text from a file in a dialog box. | |
50 | */ | |
c8dc68ad SR |
51 | int dialog_textbox(const char *title, const char *tbuf, |
52 | int initial_height, int initial_width) | |
1da177e4 | 53 | { |
2982de69 | 54 | int i, x, y, cur_x, cur_y, key = 0; |
c8dc68ad | 55 | int height, width, boxh, boxw; |
b1c5f1c6 | 56 | int passed_end; |
c8dc68ad | 57 | WINDOW *dialog, *box; |
b1c5f1c6 | 58 | |
2982de69 SR |
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 */ | |
b1c5f1c6 | 65 | |
c8dc68ad SR |
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 | ||
b1c5f1c6 SR |
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 | ||
c8dc68ad SR |
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); | |
b1c5f1c6 | 100 | |
c8dc68ad | 101 | keypad(box, TRUE); |
b1c5f1c6 SR |
102 | |
103 | /* register the new window, along with its borders */ | |
98e5a157 SR |
104 | draw_box(dialog, 0, 0, height, width, |
105 | dlg.dialog.atr, dlg.border.atr); | |
b1c5f1c6 | 106 | |
98e5a157 | 107 | wattrset(dialog, dlg.border.atr); |
b1c5f1c6 SR |
108 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); |
109 | for (i = 0; i < width - 2; i++) | |
110 | waddch(dialog, ACS_HLINE); | |
98e5a157 SR |
111 | wattrset(dialog, dlg.dialog.atr); |
112 | wbkgdset(dialog, dlg.dialog.atr & A_COLOR); | |
b1c5f1c6 SR |
113 | waddch(dialog, ACS_RTEE); |
114 | ||
fa7009d5 | 115 | print_title(dialog, title, width); |
1da177e4 | 116 | |
75c0a8a5 | 117 | print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); |
b1c5f1c6 SR |
118 | wnoutrefresh(dialog); |
119 | getyx(dialog, cur_y, cur_x); /* Save cursor position */ | |
120 | ||
121 | /* Print first page of text */ | |
c8dc68ad SR |
122 | attr_clear(box, boxh, boxw, dlg.dialog.atr); |
123 | refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); | |
b1c5f1c6 | 124 | |
f3cbcdc9 | 125 | while ((key != KEY_ESC) && (key != '\n')) { |
b1c5f1c6 SR |
126 | key = wgetch(dialog); |
127 | switch (key) { | |
128 | case 'E': /* Exit */ | |
129 | case 'e': | |
130 | case 'X': | |
131 | case 'x': | |
c8dc68ad | 132 | delwin(box); |
b1c5f1c6 | 133 | delwin(dialog); |
b1c5f1c6 SR |
134 | return 0; |
135 | case 'g': /* First page */ | |
136 | case KEY_HOME: | |
137 | if (!begin_reached) { | |
138 | begin_reached = 1; | |
b1c5f1c6 | 139 | page = buf; |
c8dc68ad SR |
140 | refresh_text_box(dialog, box, boxh, boxw, |
141 | cur_y, cur_x); | |
b1c5f1c6 SR |
142 | } |
143 | break; | |
144 | case 'G': /* Last page */ | |
145 | case KEY_END: | |
146 | ||
147 | end_reached = 1; | |
2982de69 SR |
148 | /* point to last char in buf */ |
149 | page = buf + strlen(buf); | |
c8dc68ad SR |
150 | back_lines(boxh); |
151 | refresh_text_box(dialog, box, boxh, boxw, | |
152 | cur_y, cur_x); | |
b1c5f1c6 SR |
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 | ||
2982de69 SR |
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. */ | |
c8dc68ad SR |
167 | scrollok(box, TRUE); |
168 | wscrl(box, -1); /* Scroll box region down one line */ | |
169 | scrollok(box, FALSE); | |
b1c5f1c6 SR |
170 | page_length = 0; |
171 | passed_end = 0; | |
c8dc68ad | 172 | for (i = 0; i < boxh; i++) { |
b1c5f1c6 SR |
173 | if (!i) { |
174 | /* print first line of page */ | |
c8dc68ad SR |
175 | print_line(box, 0, boxw); |
176 | wnoutrefresh(box); | |
b1c5f1c6 SR |
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 | ||
c8dc68ad | 186 | print_position(dialog); |
b1c5f1c6 SR |
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; | |
c8dc68ad SR |
196 | back_lines(page_length + boxh); |
197 | refresh_text_box(dialog, box, boxh, boxw, | |
198 | cur_y, cur_x); | |
b1c5f1c6 SR |
199 | break; |
200 | case 'J': /* Next line */ | |
201 | case 'j': | |
202 | case KEY_DOWN: | |
203 | if (!end_reached) { | |
204 | begin_reached = 0; | |
c8dc68ad SR |
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); | |
b1c5f1c6 SR |
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; | |
c8dc68ad SR |
221 | refresh_text_box(dialog, box, boxh, boxw, |
222 | cur_y, cur_x); | |
b1c5f1c6 SR |
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); | |
c8dc68ad SR |
237 | refresh_text_box(dialog, box, boxh, boxw, |
238 | cur_y, cur_x); | |
b1c5f1c6 SR |
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); | |
c8dc68ad SR |
248 | refresh_text_box(dialog, box, boxh, boxw, |
249 | cur_y, cur_x); | |
b1c5f1c6 | 250 | break; |
f3cbcdc9 SR |
251 | case KEY_ESC: |
252 | key = on_key_esc(dialog); | |
b1c5f1c6 | 253 | break; |
c8dc68ad SR |
254 | case KEY_RESIZE: |
255 | back_lines(height); | |
256 | delwin(box); | |
257 | delwin(dialog); | |
258 | on_key_resize(); | |
259 | goto do_resize; | |
b1c5f1c6 | 260 | } |
1da177e4 | 261 | } |
c8dc68ad | 262 | delwin(box); |
b1c5f1c6 | 263 | delwin(dialog); |
f3cbcdc9 | 264 | return key; /* ESC pressed */ |
1da177e4 LT |
265 | } |
266 | ||
267 | /* | |
2982de69 | 268 | * Go back 'n' lines in text. Called by dialog_textbox(). |
1da177e4 LT |
269 | * 'page' will be updated to point to the desired line in 'buf'. |
270 | */ | |
b1c5f1c6 | 271 | static void back_lines(int n) |
1da177e4 | 272 | { |
2982de69 | 273 | int i; |
b1c5f1c6 SR |
274 | |
275 | begin_reached = 0; | |
2982de69 SR |
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; | |
b1c5f1c6 | 282 | } |
1da177e4 | 283 | } |
2982de69 SR |
284 | if (page == buf) { |
285 | begin_reached = 1; | |
286 | return; | |
1da177e4 | 287 | } |
2982de69 | 288 | page--; |
b1c5f1c6 SR |
289 | do { |
290 | if (page == buf) { | |
2982de69 SR |
291 | begin_reached = 1; |
292 | return; | |
1da177e4 | 293 | } |
2982de69 SR |
294 | page--; |
295 | } while (*page != '\n'); | |
296 | page++; | |
297 | } | |
1da177e4 LT |
298 | } |
299 | ||
300 | /* | |
301 | * Print a new page of text. Called by dialog_textbox(). | |
302 | */ | |
b1c5f1c6 | 303 | static void print_page(WINDOW * win, int height, int width) |
1da177e4 | 304 | { |
b1c5f1c6 SR |
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); | |
1da177e4 LT |
316 | } |
317 | ||
318 | /* | |
319 | * Print a new line of text. Called by dialog_textbox() and print_page(). | |
320 | */ | |
b1c5f1c6 | 321 | static void print_line(WINDOW * win, int row, int width) |
1da177e4 | 322 | { |
b1c5f1c6 SR |
323 | int y, x; |
324 | char *line; | |
1da177e4 | 325 | |
b1c5f1c6 SR |
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)); | |
1da177e4 | 331 | |
b1c5f1c6 SR |
332 | getyx(win, y, x); |
333 | /* Clear 'residue' of previous line */ | |
1da177e4 | 334 | #if OLD_NCURSES |
b1c5f1c6 SR |
335 | { |
336 | int i; | |
337 | for (i = 0; i < width - x; i++) | |
338 | waddch(win, ' '); | |
339 | } | |
1da177e4 | 340 | #else |
b1c5f1c6 | 341 | wclrtoeol(win); |
1da177e4 LT |
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 | */ | |
b1c5f1c6 | 350 | static char *get_line(void) |
1da177e4 | 351 | { |
2982de69 | 352 | int i = 0; |
b1c5f1c6 SR |
353 | static char line[MAX_LEN + 1]; |
354 | ||
355 | end_reached = 0; | |
356 | while (*page != '\n') { | |
357 | if (*page == '\0') { | |
2982de69 SR |
358 | if (!end_reached) { |
359 | end_reached = 1; | |
b1c5f1c6 SR |
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++; | |
1da177e4 | 369 | } |
1da177e4 | 370 | } |
b1c5f1c6 SR |
371 | if (i <= MAX_LEN) |
372 | line[i] = '\0'; | |
373 | if (!end_reached) | |
374 | page++; /* move pass '\n' */ | |
1da177e4 | 375 | |
b1c5f1c6 | 376 | return line; |
1da177e4 LT |
377 | } |
378 | ||
379 | /* | |
380 | * Print current position | |
381 | */ | |
c8dc68ad | 382 | static void print_position(WINDOW * win) |
1da177e4 | 383 | { |
2982de69 | 384 | int percent; |
b1c5f1c6 | 385 | |
98e5a157 SR |
386 | wattrset(win, dlg.position_indicator.atr); |
387 | wbkgdset(win, dlg.position_indicator.atr & A_COLOR); | |
2982de69 | 388 | percent = (page - buf) * 100 / strlen(buf); |
c8dc68ad | 389 | wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); |
b1c5f1c6 | 390 | wprintw(win, "(%3d%%)", percent); |
1da177e4 | 391 | } |