blob: 3b3c5c470bf864ac7ad8c4afcd9ba2115720248f [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:
Benjamin Poirier1a374ae2012-08-23 14:55:07 -0400169 if (begin_reached)
170 break;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400171
Benjamin Poirier1a374ae2012-08-23 14:55:07 -0400172 back_lines(page_length + 1);
173 refresh_text_box(dialog, box, boxh, boxw, cur_y,
174 cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100175 break;
176 case 'B': /* Previous page */
177 case 'b':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400178 case 'u':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100179 case KEY_PPAGE:
180 if (begin_reached)
181 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200182 back_lines(page_length + boxh);
183 refresh_text_box(dialog, box, boxh, boxw,
184 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100185 break;
186 case 'J': /* Next line */
187 case 'j':
188 case KEY_DOWN:
Benjamin Poirier1a374ae2012-08-23 14:55:07 -0400189 if (end_reached)
190 break;
191
192 back_lines(page_length - 1);
193 refresh_text_box(dialog, box, boxh, boxw, cur_y,
194 cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100195 break;
196 case KEY_NPAGE: /* Next page */
197 case ' ':
Benjamin Poirier9d4792c2012-07-24 16:12:02 -0400198 case 'd':
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100199 if (end_reached)
200 break;
201
202 begin_reached = 0;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200203 refresh_text_box(dialog, box, boxh, boxw,
204 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100205 break;
206 case '0': /* Beginning of line */
207 case 'H': /* Scroll left */
208 case 'h':
209 case KEY_LEFT:
210 if (hscroll <= 0)
211 break;
212
213 if (key == '0')
214 hscroll = 0;
215 else
216 hscroll--;
217 /* Reprint current page to scroll horizontally */
218 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200219 refresh_text_box(dialog, box, boxh, boxw,
220 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100221 break;
222 case 'L': /* Scroll right */
223 case 'l':
224 case KEY_RIGHT:
225 if (hscroll >= MAX_LEN)
226 break;
227 hscroll++;
228 /* Reprint current page to scroll horizontally */
229 back_lines(page_length);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200230 refresh_text_box(dialog, box, boxh, boxw,
231 cur_y, cur_x);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100232 break;
Sam Ravnborgf3cbcdc2006-07-28 23:57:48 +0200233 case KEY_ESC:
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400234 if (on_key_esc(dialog) == KEY_ESC)
235 done = true;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100236 break;
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200237 case KEY_RESIZE:
238 back_lines(height);
239 delwin(box);
240 delwin(dialog);
241 on_key_resize();
242 goto do_resize;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400243 default:
244 for (i = 0; keys[i]; i++) {
245 if (key == keys[i]) {
246 done = true;
247 break;
248 }
249 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100250 }
251 }
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200252 delwin(box);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100253 delwin(dialog);
Benjamin Poirier1d1e2ca2012-08-23 14:55:05 -0400254 if (_vscroll) {
255 const char *s;
256
257 s = buf;
258 *_vscroll = 0;
259 back_lines(page_length);
260 while (s < page && (s = strchr(s, '\n'))) {
261 (*_vscroll)++;
262 s++;
263 }
264 }
265 if (_hscroll)
266 *_hscroll = hscroll;
Benjamin Poirier537ddae2012-08-23 14:55:04 -0400267 return key;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
270/*
Sam Ravnborg2982de62006-07-27 22:10:27 +0200271 * Go back 'n' lines in text. Called by dialog_textbox().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 * 'page' will be updated to point to the desired line in 'buf'.
273 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100274static void back_lines(int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200276 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100278 begin_reached = 0;
Sam Ravnborg2982de62006-07-27 22:10:27 +0200279 /* Go back 'n' lines */
280 for (i = 0; i < n; i++) {
281 if (*page == '\0') {
282 if (end_reached) {
283 end_reached = 0;
284 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200286 }
287 if (page == buf) {
288 begin_reached = 1;
289 return;
290 }
291 page--;
292 do {
293 if (page == buf) {
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100294 begin_reached = 1;
295 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
Sam Ravnborg2982de62006-07-27 22:10:27 +0200297 page--;
298 } while (*page != '\n');
299 page++;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303/*
304 * Print a new page of text. Called by dialog_textbox().
305 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100306static void print_page(WINDOW * win, int height, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100308 int i, passed_end = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100310 page_length = 0;
311 for (i = 0; i < height; i++) {
312 print_line(win, i, width);
313 if (!passed_end)
314 page_length++;
315 if (end_reached && !passed_end)
316 passed_end = 1;
317 }
318 wnoutrefresh(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
321/*
322 * Print a new line of text. Called by dialog_textbox() and print_page().
323 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100324static void print_line(WINDOW * win, int row, int width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100326 char *line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100328 line = get_line();
329 line += MIN(strlen(line), hscroll); /* Scroll horizontally */
330 wmove(win, row, 0); /* move cursor to correct line */
331 waddch(win, ' ');
332 waddnstr(win, line, MIN(strlen(line), width - 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100334 /* Clear 'residue' of previous line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335#if OLD_NCURSES
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100336 {
Lucas De Marchi702a9452011-08-20 02:28:53 -0300337 int x = getcurx(win);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100338 int i;
339 for (i = 0; i < width - x; i++)
340 waddch(win, ' ');
341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342#else
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100343 wclrtoeol(win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344#endif
345}
346
347/*
348 * Return current line of text. Called by dialog_textbox() and print_line().
349 * 'page' should point to start of current line before calling, and will be
350 * updated to point to start of next line.
351 */
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100352static char *get_line(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200354 int i = 0;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100355 static char line[MAX_LEN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100357 end_reached = 0;
358 while (*page != '\n') {
359 if (*page == '\0') {
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400360 end_reached = 1;
361 break;
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100362 } 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++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100371 if (i <= MAX_LEN)
372 line[i] = '\0';
373 if (!end_reached)
Benjamin Poirierb9d29ab2012-08-23 14:55:03 -0400374 page++; /* move past '\n' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100376 return line;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
379/*
380 * Print current position
381 */
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200382static void print_position(WINDOW * win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
Sam Ravnborg2982de62006-07-27 22:10:27 +0200384 int percent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Sam Ravnborg98e5a152006-07-24 21:40:46 +0200386 wattrset(win, dlg.position_indicator.atr);
387 wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
Sam Ravnborg2982de62006-07-27 22:10:27 +0200388 percent = (page - buf) * 100 / strlen(buf);
Sam Ravnborgc8dc68a2006-07-29 22:48:57 +0200389 wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
Sam Ravnborgb1c5f1c2005-11-19 19:13:34 +0100390 wprintw(win, "(%3d%%)", percent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391}