blob: eb4ee92ad2b3170c503de3330898fe33e6800b04 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +010024static void back_lines(int n);
25static void print_page(WINDOW * win, int height, int width);
26static void print_line(WINDOW * win, int row, int width);
27static char *get_line(void);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020028static void print_position(WINDOW * win);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Sam Ravnborg2982de62006-07-27 22:10:27 +020030static int hscroll;
31static int begin_reached, end_reached, page_length;
32static const char *buf;
33static const char *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35/*
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020036 * refresh window content
37 */
38static 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/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 * Display text from a file in a dialog box.
Benjamin Poirier537ddae2012-08-23 14:55:04 -040050 *
51 * keys is a null-terminated array
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 */
Benjamin Poirier537ddae2012-08-23 14:55:04 -040053int dialog_textbox(const char *title, const char *tbuf, int initial_height,
54 int initial_width, int *keys)
Linus Torvalds1da177e2005-04-16 15:20:36 -070055{
Sam Ravnborg2982de62006-07-27 22:10:27 +020056 int i, x, y, cur_x, cur_y, key = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020057 int height, width, boxh, boxw;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020058 WINDOW *dialog, *box;
Benjamin Poirier537ddae2012-08-23 14:55:04 -040059 bool done = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Sam Ravnborg2982de62006-07-27 22:10:27 +020061 begin_reached = 1;
62 end_reached = 0;
63 page_length = 0;
64 hscroll = 0;
65 buf = tbuf;
66 page = buf; /* page is pointer to start of page to be displayed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020068do_resize:
69 getmaxyx(stdscr, height, width);
70 if (height < 8 || width < 8)
71 return -ERRDISPLAYTOOSMALL;
72 if (initial_height != 0)
73 height = initial_height;
74 else
75 if (height > 4)
76 height -= 4;
77 else
78 height = 0;
79 if (initial_width != 0)
80 width = initial_width;
81 else
82 if (width > 5)
83 width -= 5;
84 else
85 width = 0;
86
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +010087 /* center dialog box on screen */
88 x = (COLS - width) / 2;
89 y = (LINES - height) / 2;
90
91 draw_shadow(stdscr, y, x, height, width);
92
93 dialog = newwin(height, width, y, x);
94 keypad(dialog, TRUE);
95
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020096 /* Create window for box region, used for scrolling text */
97 boxh = height - 4;
98 boxw = width - 2;
99 box = subwin(dialog, boxh, boxw, y + 1, x + 1);
100 wattrset(box, dlg.dialog.atr);
101 wbkgdset(box, dlg.dialog.atr & A_COLOR);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100102
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200103 keypad(box, TRUE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100104
105 /* register the new window, along with its borders */
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200106 draw_box(dialog, 0, 0, height, width,
107 dlg.dialog.atr, dlg.border.atr);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100108
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200109 wattrset(dialog, dlg.border.atr);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100110 mvwaddch(dialog, height - 3, 0, ACS_LTEE);
111 for (i = 0; i < width - 2; i++)
112 waddch(dialog, ACS_HLINE);
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200113 wattrset(dialog, dlg.dialog.atr);
114 wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100115 waddch(dialog, ACS_RTEE);
116
Sam Ravnborgfa7009d2005-11-19 23:38:06 +0100117 print_title(dialog, title, width);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100118
EGRY Gabor75c0a8a2008-01-11 23:42:54 +0100119 print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100120 wnoutrefresh(dialog);
121 getyx(dialog, cur_y, cur_x); /* Save cursor position */
122
123 /* Print first page of text */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200124 attr_clear(box, boxh, boxw, dlg.dialog.atr);
125 refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100126
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400127 while (!done) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100128 key = wgetch(dialog);
129 switch (key) {
130 case 'E': /* Exit */
131 case 'e':
132 case 'X':
133 case 'x':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400134 case 'q':
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400135 case '\n':
136 done = true;
137 break;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100138 case 'g': /* First page */
139 case KEY_HOME:
140 if (!begin_reached) {
141 begin_reached = 1;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100142 page = buf;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200143 refresh_text_box(dialog, box, boxh, boxw,
144 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100145 }
146 break;
147 case 'G': /* Last page */
148 case KEY_END:
149
150 end_reached = 1;
Sam Ravnborg2982de62006-07-27 22:10:27 +0200151 /* point to last char in buf */
152 page = buf + strlen(buf);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200153 back_lines(boxh);
154 refresh_text_box(dialog, box, boxh, boxw,
155 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100156 break;
157 case 'K': /* Previous line */
158 case 'k':
159 case KEY_UP:
160 if (!begin_reached) {
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400161 int passed_end = 0;
162
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100163 back_lines(page_length + 1);
164
Sam Ravnborg2982de62006-07-27 22:10:27 +0200165 /* We don't call print_page() here but use
166 * scrolling to ensure faster screen update.
167 * However, 'end_reached' and 'page_length'
168 * should still be updated, and 'page' should
169 * point to start of next page. This is done
170 * by calling get_line() in the following
171 * 'for' loop. */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200172 scrollok(box, TRUE);
173 wscrl(box, -1); /* Scroll box region down one line */
174 scrollok(box, FALSE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100175 page_length = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200176 for (i = 0; i < boxh; i++) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100177 if (!i) {
178 /* print first line of page */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200179 print_line(box, 0, boxw);
180 wnoutrefresh(box);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100181 } else
182 /* Called to update 'end_reached' and 'page' */
183 get_line();
184 if (!passed_end)
185 page_length++;
186 if (end_reached && !passed_end)
187 passed_end = 1;
188 }
189
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200190 print_position(dialog);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100191 wmove(dialog, cur_y, cur_x); /* Restore cursor position */
192 wrefresh(dialog);
193 }
194 break;
195 case 'B': /* Previous page */
196 case 'b':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400197 case 'u':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100198 case KEY_PPAGE:
199 if (begin_reached)
200 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200201 back_lines(page_length + boxh);
202 refresh_text_box(dialog, box, boxh, boxw,
203 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100204 break;
205 case 'J': /* Next line */
206 case 'j':
207 case KEY_DOWN:
208 if (!end_reached) {
209 begin_reached = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200210 scrollok(box, TRUE);
211 scroll(box); /* Scroll box region up one line */
212 scrollok(box, FALSE);
213 print_line(box, boxh - 1, boxw);
214 wnoutrefresh(box);
215 print_position(dialog);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100216 wmove(dialog, cur_y, cur_x); /* Restore cursor position */
217 wrefresh(dialog);
218 }
219 break;
220 case KEY_NPAGE: /* Next page */
221 case ' ':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400222 case 'd':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100223 if (end_reached)
224 break;
225
226 begin_reached = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200227 refresh_text_box(dialog, box, boxh, boxw,
228 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100229 break;
230 case '0': /* Beginning of line */
231 case 'H': /* Scroll left */
232 case 'h':
233 case KEY_LEFT:
234 if (hscroll <= 0)
235 break;
236
237 if (key == '0')
238 hscroll = 0;
239 else
240 hscroll--;
241 /* Reprint current page to scroll horizontally */
242 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200243 refresh_text_box(dialog, box, boxh, boxw,
244 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100245 break;
246 case 'L': /* Scroll right */
247 case 'l':
248 case KEY_RIGHT:
249 if (hscroll >= MAX_LEN)
250 break;
251 hscroll++;
252 /* Reprint current page to scroll horizontally */
253 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200254 refresh_text_box(dialog, box, boxh, boxw,
255 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100256 break;
Sam Ravnborgf3cbcdc2006-07-28 23:57:48 +0200257 case KEY_ESC:
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400258 if (on_key_esc(dialog) == KEY_ESC)
259 done = true;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100260 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200261 case KEY_RESIZE:
262 back_lines(height);
263 delwin(box);
264 delwin(dialog);
265 on_key_resize();
266 goto do_resize;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400267 default:
268 for (i = 0; keys[i]; i++) {
269 if (key == keys[i]) {
270 done = true;
271 break;
272 }
273 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100274 }
275 }
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200276 delwin(box);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100277 delwin(dialog);
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400278 return key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
281/*
Sam Ravnborg2982de62006-07-27 22:10:27 +0200282 * Go back 'n' lines in text. Called by dialog_textbox().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 * 'page' will be updated to point to the desired line in 'buf'.
284 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100285static void back_lines(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200287 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100289 begin_reached = 0;
Sam Ravnborg2982de62006-07-27 22:10:27 +0200290 /* Go back 'n' lines */
291 for (i = 0; i < n; i++) {
292 if (*page == '\0') {
293 if (end_reached) {
294 end_reached = 0;
295 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200297 }
298 if (page == buf) {
299 begin_reached = 1;
300 return;
301 }
302 page--;
303 do {
304 if (page == buf) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100305 begin_reached = 1;
306 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200308 page--;
309 } while (*page != '\n');
310 page++;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
314/*
315 * Print a new page of text. Called by dialog_textbox().
316 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100317static void print_page(WINDOW * win, int height, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100319 int i, passed_end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100321 page_length = 0;
322 for (i = 0; i < height; i++) {
323 print_line(win, i, width);
324 if (!passed_end)
325 page_length++;
326 if (end_reached && !passed_end)
327 passed_end = 1;
328 }
329 wnoutrefresh(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
332/*
333 * Print a new line of text. Called by dialog_textbox() and print_page().
334 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100335static void print_line(WINDOW * win, int row, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100337 char *line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100339 line = get_line();
340 line += MIN(strlen(line), hscroll); /* Scroll horizontally */
341 wmove(win, row, 0); /* move cursor to correct line */
342 waddch(win, ' ');
343 waddnstr(win, line, MIN(strlen(line), width - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100345 /* Clear 'residue' of previous line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#if OLD_NCURSES
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100347 {
Lucas De Marchi702a9452011-08-20 02:28:53 -0300348 int x = getcurx(win);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100349 int i;
350 for (i = 0; i < width - x; i++)
351 waddch(win, ' ');
352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353#else
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100354 wclrtoeol(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355#endif
356}
357
358/*
359 * Return current line of text. Called by dialog_textbox() and print_line().
360 * 'page' should point to start of current line before calling, and will be
361 * updated to point to start of next line.
362 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100363static char *get_line(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200365 int i = 0;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100366 static char line[MAX_LEN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100368 end_reached = 0;
369 while (*page != '\n') {
370 if (*page == '\0') {
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400371 end_reached = 1;
372 break;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100373 } else if (i < MAX_LEN)
374 line[i++] = *(page++);
375 else {
376 /* Truncate lines longer than MAX_LEN characters */
377 if (i == MAX_LEN)
378 line[i++] = '\0';
379 page++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100382 if (i <= MAX_LEN)
383 line[i] = '\0';
384 if (!end_reached)
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400385 page++; /* move past '\n' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100387 return line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
390/*
391 * Print current position
392 */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200393static void print_position(WINDOW * win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200395 int percent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200397 wattrset(win, dlg.position_indicator.atr);
398 wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
Sam Ravnborg2982de62006-07-27 22:10:27 +0200399 percent = (page - buf) * 100 / strlen(buf);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200400 wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100401 wprintw(win, "(%3d%%)", percent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}