blob: 506a095c387cbd8116fdc31a48d2a4972b3a1ad7 [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,
Benjamin Poirier1d1e2ca2012-08-23 14:55:05 -040054 int initial_width, int *keys, int *_vscroll, int *_hscroll)
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
Benjamin Poirier1d1e2ca2012-08-23 14:55:05 -040068 if (_vscroll && *_vscroll) {
69 begin_reached = 0;
70
71 for (i = 0; i < *_vscroll; i++)
72 get_line();
73 }
74 if (_hscroll)
75 hscroll = *_hscroll;
76
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +020077do_resize:
78 getmaxyx(stdscr, height, width);
79 if (height < 8 || width < 8)
80 return -ERRDISPLAYTOOSMALL;
81 if (initial_height != 0)
82 height = initial_height;
83 else
84 if (height > 4)
85 height -= 4;
86 else
87 height = 0;
88 if (initial_width != 0)
89 width = initial_width;
90 else
91 if (width > 5)
92 width -= 5;
93 else
94 width = 0;
95
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +010096 /* center dialog box on screen */
97 x = (COLS - width) / 2;
98 y = (LINES - height) / 2;
99
100 draw_shadow(stdscr, y, x, height, width);
101
102 dialog = newwin(height, width, y, x);
103 keypad(dialog, TRUE);
104
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200105 /* Create window for box region, used for scrolling text */
106 boxh = height - 4;
107 boxw = width - 2;
108 box = subwin(dialog, boxh, boxw, y + 1, x + 1);
109 wattrset(box, dlg.dialog.atr);
110 wbkgdset(box, dlg.dialog.atr & A_COLOR);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100111
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200112 keypad(box, TRUE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100113
114 /* register the new window, along with its borders */
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200115 draw_box(dialog, 0, 0, height, width,
116 dlg.dialog.atr, dlg.border.atr);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100117
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200118 wattrset(dialog, dlg.border.atr);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100119 mvwaddch(dialog, height - 3, 0, ACS_LTEE);
120 for (i = 0; i < width - 2; i++)
121 waddch(dialog, ACS_HLINE);
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200122 wattrset(dialog, dlg.dialog.atr);
123 wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100124 waddch(dialog, ACS_RTEE);
125
Sam Ravnborgfa7009d2005-11-19 23:38:06 +0100126 print_title(dialog, title, width);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100127
EGRY Gabor75c0a8a2008-01-11 23:42:54 +0100128 print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100129 wnoutrefresh(dialog);
130 getyx(dialog, cur_y, cur_x); /* Save cursor position */
131
132 /* Print first page of text */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200133 attr_clear(box, boxh, boxw, dlg.dialog.atr);
134 refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100135
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400136 while (!done) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100137 key = wgetch(dialog);
138 switch (key) {
139 case 'E': /* Exit */
140 case 'e':
141 case 'X':
142 case 'x':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400143 case 'q':
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400144 case '\n':
145 done = true;
146 break;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100147 case 'g': /* First page */
148 case KEY_HOME:
149 if (!begin_reached) {
150 begin_reached = 1;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100151 page = buf;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200152 refresh_text_box(dialog, box, boxh, boxw,
153 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100154 }
155 break;
156 case 'G': /* Last page */
157 case KEY_END:
158
159 end_reached = 1;
Sam Ravnborg2982de62006-07-27 22:10:27 +0200160 /* point to last char in buf */
161 page = buf + strlen(buf);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200162 back_lines(boxh);
163 refresh_text_box(dialog, box, boxh, boxw,
164 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100165 break;
166 case 'K': /* Previous line */
167 case 'k':
168 case KEY_UP:
169 if (!begin_reached) {
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400170 int passed_end = 0;
171
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100172 back_lines(page_length + 1);
173
Sam Ravnborg2982de62006-07-27 22:10:27 +0200174 /* We don't call print_page() here but use
175 * scrolling to ensure faster screen update.
176 * However, 'end_reached' and 'page_length'
177 * should still be updated, and 'page' should
178 * point to start of next page. This is done
179 * by calling get_line() in the following
180 * 'for' loop. */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200181 scrollok(box, TRUE);
182 wscrl(box, -1); /* Scroll box region down one line */
183 scrollok(box, FALSE);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100184 page_length = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200185 for (i = 0; i < boxh; i++) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100186 if (!i) {
187 /* print first line of page */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200188 print_line(box, 0, boxw);
189 wnoutrefresh(box);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100190 } else
191 /* Called to update 'end_reached' and 'page' */
192 get_line();
193 if (!passed_end)
194 page_length++;
195 if (end_reached && !passed_end)
196 passed_end = 1;
197 }
198
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200199 print_position(dialog);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100200 wmove(dialog, cur_y, cur_x); /* Restore cursor position */
201 wrefresh(dialog);
202 }
203 break;
204 case 'B': /* Previous page */
205 case 'b':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400206 case 'u':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100207 case KEY_PPAGE:
208 if (begin_reached)
209 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200210 back_lines(page_length + boxh);
211 refresh_text_box(dialog, box, boxh, boxw,
212 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100213 break;
214 case 'J': /* Next line */
215 case 'j':
216 case KEY_DOWN:
217 if (!end_reached) {
218 begin_reached = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200219 scrollok(box, TRUE);
220 scroll(box); /* Scroll box region up one line */
221 scrollok(box, FALSE);
222 print_line(box, boxh - 1, boxw);
223 wnoutrefresh(box);
224 print_position(dialog);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100225 wmove(dialog, cur_y, cur_x); /* Restore cursor position */
226 wrefresh(dialog);
227 }
228 break;
229 case KEY_NPAGE: /* Next page */
230 case ' ':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400231 case 'd':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100232 if (end_reached)
233 break;
234
235 begin_reached = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200236 refresh_text_box(dialog, box, boxh, boxw,
237 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100238 break;
239 case '0': /* Beginning of line */
240 case 'H': /* Scroll left */
241 case 'h':
242 case KEY_LEFT:
243 if (hscroll <= 0)
244 break;
245
246 if (key == '0')
247 hscroll = 0;
248 else
249 hscroll--;
250 /* Reprint current page to scroll horizontally */
251 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200252 refresh_text_box(dialog, box, boxh, boxw,
253 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100254 break;
255 case 'L': /* Scroll right */
256 case 'l':
257 case KEY_RIGHT:
258 if (hscroll >= MAX_LEN)
259 break;
260 hscroll++;
261 /* Reprint current page to scroll horizontally */
262 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200263 refresh_text_box(dialog, box, boxh, boxw,
264 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100265 break;
Sam Ravnborgf3cbcdc2006-07-28 23:57:48 +0200266 case KEY_ESC:
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400267 if (on_key_esc(dialog) == KEY_ESC)
268 done = true;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100269 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200270 case KEY_RESIZE:
271 back_lines(height);
272 delwin(box);
273 delwin(dialog);
274 on_key_resize();
275 goto do_resize;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400276 default:
277 for (i = 0; keys[i]; i++) {
278 if (key == keys[i]) {
279 done = true;
280 break;
281 }
282 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100283 }
284 }
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200285 delwin(box);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100286 delwin(dialog);
Benjamin Poirier1d1e2ca2012-08-23 14:55:05 -0400287 if (_vscroll) {
288 const char *s;
289
290 s = buf;
291 *_vscroll = 0;
292 back_lines(page_length);
293 while (s < page && (s = strchr(s, '\n'))) {
294 (*_vscroll)++;
295 s++;
296 }
297 }
298 if (_hscroll)
299 *_hscroll = hscroll;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400300 return key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303/*
Sam Ravnborg2982de62006-07-27 22:10:27 +0200304 * Go back 'n' lines in text. Called by dialog_textbox().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 * 'page' will be updated to point to the desired line in 'buf'.
306 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100307static void back_lines(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200309 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100311 begin_reached = 0;
Sam Ravnborg2982de62006-07-27 22:10:27 +0200312 /* Go back 'n' lines */
313 for (i = 0; i < n; i++) {
314 if (*page == '\0') {
315 if (end_reached) {
316 end_reached = 0;
317 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200319 }
320 if (page == buf) {
321 begin_reached = 1;
322 return;
323 }
324 page--;
325 do {
326 if (page == buf) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100327 begin_reached = 1;
328 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200330 page--;
331 } while (*page != '\n');
332 page++;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336/*
337 * Print a new page of text. Called by dialog_textbox().
338 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100339static void print_page(WINDOW * win, int height, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100341 int i, passed_end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100343 page_length = 0;
344 for (i = 0; i < height; i++) {
345 print_line(win, i, width);
346 if (!passed_end)
347 page_length++;
348 if (end_reached && !passed_end)
349 passed_end = 1;
350 }
351 wnoutrefresh(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
354/*
355 * Print a new line of text. Called by dialog_textbox() and print_page().
356 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100357static void print_line(WINDOW * win, int row, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100359 char *line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100361 line = get_line();
362 line += MIN(strlen(line), hscroll); /* Scroll horizontally */
363 wmove(win, row, 0); /* move cursor to correct line */
364 waddch(win, ' ');
365 waddnstr(win, line, MIN(strlen(line), width - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100367 /* Clear 'residue' of previous line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368#if OLD_NCURSES
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100369 {
Lucas De Marchi702a9452011-08-20 02:28:53 -0300370 int x = getcurx(win);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100371 int i;
372 for (i = 0; i < width - x; i++)
373 waddch(win, ' ');
374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375#else
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100376 wclrtoeol(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377#endif
378}
379
380/*
381 * Return current line of text. Called by dialog_textbox() and print_line().
382 * 'page' should point to start of current line before calling, and will be
383 * updated to point to start of next line.
384 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100385static char *get_line(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200387 int i = 0;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100388 static char line[MAX_LEN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100390 end_reached = 0;
391 while (*page != '\n') {
392 if (*page == '\0') {
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400393 end_reached = 1;
394 break;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100395 } else if (i < MAX_LEN)
396 line[i++] = *(page++);
397 else {
398 /* Truncate lines longer than MAX_LEN characters */
399 if (i == MAX_LEN)
400 line[i++] = '\0';
401 page++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100404 if (i <= MAX_LEN)
405 line[i] = '\0';
406 if (!end_reached)
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400407 page++; /* move past '\n' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100409 return line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
412/*
413 * Print current position
414 */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200415static void print_position(WINDOW * win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200417 int percent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200419 wattrset(win, dlg.position_indicator.atr);
420 wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
Sam Ravnborg2982de62006-07-27 22:10:27 +0200421 percent = (page - buf) * 100 / strlen(buf);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200422 wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100423 wprintw(win, "(%3d%%)", percent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424}