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