1*10465441SEvalZero /*
2*10465441SEvalZero * textbox.c -- implements the text box
3*10465441SEvalZero *
4*10465441SEvalZero * ORIGINAL AUTHOR: Savio Lam ([email protected])
5*10465441SEvalZero * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
6*10465441SEvalZero *
7*10465441SEvalZero * This program is free software; you can redistribute it and/or
8*10465441SEvalZero * modify it under the terms of the GNU General Public License
9*10465441SEvalZero * as published by the Free Software Foundation; either version 2
10*10465441SEvalZero * of the License, or (at your option) any later version.
11*10465441SEvalZero *
12*10465441SEvalZero * This program is distributed in the hope that it will be useful,
13*10465441SEvalZero * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*10465441SEvalZero * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*10465441SEvalZero * GNU General Public License for more details.
16*10465441SEvalZero *
17*10465441SEvalZero * You should have received a copy of the GNU General Public License
18*10465441SEvalZero * along with this program; if not, write to the Free Software
19*10465441SEvalZero * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*10465441SEvalZero */
21*10465441SEvalZero
22*10465441SEvalZero #include "dialog.h"
23*10465441SEvalZero
24*10465441SEvalZero static void back_lines(int n);
25*10465441SEvalZero static void print_page(WINDOW *win, int height, int width, update_text_fn
26*10465441SEvalZero update_text, void *data);
27*10465441SEvalZero static void print_line(WINDOW *win, int row, int width);
28*10465441SEvalZero static char *get_line(void);
29*10465441SEvalZero static void print_position(WINDOW * win);
30*10465441SEvalZero
31*10465441SEvalZero static int hscroll;
32*10465441SEvalZero static int begin_reached, end_reached, page_length;
33*10465441SEvalZero static char *buf;
34*10465441SEvalZero static char *page;
35*10465441SEvalZero
36*10465441SEvalZero /*
37*10465441SEvalZero * refresh window content
38*10465441SEvalZero */
refresh_text_box(WINDOW * dialog,WINDOW * box,int boxh,int boxw,int cur_y,int cur_x,update_text_fn update_text,void * data)39*10465441SEvalZero static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
40*10465441SEvalZero int cur_y, int cur_x, update_text_fn update_text,
41*10465441SEvalZero void *data)
42*10465441SEvalZero {
43*10465441SEvalZero print_page(box, boxh, boxw, update_text, data);
44*10465441SEvalZero print_position(dialog);
45*10465441SEvalZero wmove(dialog, cur_y, cur_x); /* Restore cursor position */
46*10465441SEvalZero wrefresh(dialog);
47*10465441SEvalZero }
48*10465441SEvalZero
49*10465441SEvalZero
50*10465441SEvalZero /*
51*10465441SEvalZero * Display text from a file in a dialog box.
52*10465441SEvalZero *
53*10465441SEvalZero * keys is a null-terminated array
54*10465441SEvalZero * update_text() may not add or remove any '\n' or '\0' in tbuf
55*10465441SEvalZero */
dialog_textbox(const char * title,char * tbuf,int initial_height,int initial_width,int * keys,int * _vscroll,int * _hscroll,update_text_fn update_text,void * data)56*10465441SEvalZero int dialog_textbox(const char *title, char *tbuf, int initial_height,
57*10465441SEvalZero int initial_width, int *keys, int *_vscroll, int *_hscroll,
58*10465441SEvalZero update_text_fn update_text, void *data)
59*10465441SEvalZero {
60*10465441SEvalZero int i, x, y, cur_x, cur_y, key = 0;
61*10465441SEvalZero int height, width, boxh, boxw;
62*10465441SEvalZero WINDOW *dialog, *box;
63*10465441SEvalZero bool done = false;
64*10465441SEvalZero
65*10465441SEvalZero begin_reached = 1;
66*10465441SEvalZero end_reached = 0;
67*10465441SEvalZero page_length = 0;
68*10465441SEvalZero hscroll = 0;
69*10465441SEvalZero buf = tbuf;
70*10465441SEvalZero page = buf; /* page is pointer to start of page to be displayed */
71*10465441SEvalZero
72*10465441SEvalZero if (_vscroll && *_vscroll) {
73*10465441SEvalZero begin_reached = 0;
74*10465441SEvalZero
75*10465441SEvalZero for (i = 0; i < *_vscroll; i++)
76*10465441SEvalZero get_line();
77*10465441SEvalZero }
78*10465441SEvalZero if (_hscroll)
79*10465441SEvalZero hscroll = *_hscroll;
80*10465441SEvalZero
81*10465441SEvalZero do_resize:
82*10465441SEvalZero getmaxyx(stdscr, height, width);
83*10465441SEvalZero if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
84*10465441SEvalZero return -ERRDISPLAYTOOSMALL;
85*10465441SEvalZero if (initial_height != 0)
86*10465441SEvalZero height = initial_height;
87*10465441SEvalZero else
88*10465441SEvalZero if (height > 4)
89*10465441SEvalZero height -= 4;
90*10465441SEvalZero else
91*10465441SEvalZero height = 0;
92*10465441SEvalZero if (initial_width != 0)
93*10465441SEvalZero width = initial_width;
94*10465441SEvalZero else
95*10465441SEvalZero if (width > 5)
96*10465441SEvalZero width -= 5;
97*10465441SEvalZero else
98*10465441SEvalZero width = 0;
99*10465441SEvalZero
100*10465441SEvalZero /* center dialog box on screen */
101*10465441SEvalZero x = (getmaxx(stdscr) - width) / 2;
102*10465441SEvalZero y = (getmaxy(stdscr) - height) / 2;
103*10465441SEvalZero
104*10465441SEvalZero draw_shadow(stdscr, y, x, height, width);
105*10465441SEvalZero
106*10465441SEvalZero dialog = newwin(height, width, y, x);
107*10465441SEvalZero keypad(dialog, TRUE);
108*10465441SEvalZero
109*10465441SEvalZero /* Create window for box region, used for scrolling text */
110*10465441SEvalZero boxh = height - 4;
111*10465441SEvalZero boxw = width - 2;
112*10465441SEvalZero box = subwin(dialog, boxh, boxw, y + 1, x + 1);
113*10465441SEvalZero wattrset(box, dlg.dialog.atr);
114*10465441SEvalZero wbkgdset(box, dlg.dialog.atr & A_COLOR);
115*10465441SEvalZero
116*10465441SEvalZero keypad(box, TRUE);
117*10465441SEvalZero
118*10465441SEvalZero /* register the new window, along with its borders */
119*10465441SEvalZero draw_box(dialog, 0, 0, height, width,
120*10465441SEvalZero dlg.dialog.atr, dlg.border.atr);
121*10465441SEvalZero
122*10465441SEvalZero wattrset(dialog, dlg.border.atr);
123*10465441SEvalZero mvwaddch(dialog, height - 3, 0, ACS_LTEE);
124*10465441SEvalZero for (i = 0; i < width - 2; i++)
125*10465441SEvalZero waddch(dialog, ACS_HLINE);
126*10465441SEvalZero wattrset(dialog, dlg.dialog.atr);
127*10465441SEvalZero wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
128*10465441SEvalZero waddch(dialog, ACS_RTEE);
129*10465441SEvalZero
130*10465441SEvalZero print_title(dialog, title, width);
131*10465441SEvalZero
132*10465441SEvalZero print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
133*10465441SEvalZero wnoutrefresh(dialog);
134*10465441SEvalZero getyx(dialog, cur_y, cur_x); /* Save cursor position */
135*10465441SEvalZero
136*10465441SEvalZero /* Print first page of text */
137*10465441SEvalZero attr_clear(box, boxh, boxw, dlg.dialog.atr);
138*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
139*10465441SEvalZero data);
140*10465441SEvalZero
141*10465441SEvalZero while (!done) {
142*10465441SEvalZero key = wgetch(dialog);
143*10465441SEvalZero switch (key) {
144*10465441SEvalZero case 'E': /* Exit */
145*10465441SEvalZero case 'e':
146*10465441SEvalZero case 'X':
147*10465441SEvalZero case 'x':
148*10465441SEvalZero case 'q':
149*10465441SEvalZero case '\n':
150*10465441SEvalZero done = true;
151*10465441SEvalZero break;
152*10465441SEvalZero case 'g': /* First page */
153*10465441SEvalZero case KEY_HOME:
154*10465441SEvalZero if (!begin_reached) {
155*10465441SEvalZero begin_reached = 1;
156*10465441SEvalZero page = buf;
157*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw,
158*10465441SEvalZero cur_y, cur_x, update_text,
159*10465441SEvalZero data);
160*10465441SEvalZero }
161*10465441SEvalZero break;
162*10465441SEvalZero case 'G': /* Last page */
163*10465441SEvalZero case KEY_END:
164*10465441SEvalZero
165*10465441SEvalZero end_reached = 1;
166*10465441SEvalZero /* point to last char in buf */
167*10465441SEvalZero page = buf + strlen(buf);
168*10465441SEvalZero back_lines(boxh);
169*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
170*10465441SEvalZero cur_x, update_text, data);
171*10465441SEvalZero break;
172*10465441SEvalZero case 'K': /* Previous line */
173*10465441SEvalZero case 'k':
174*10465441SEvalZero case KEY_UP:
175*10465441SEvalZero if (begin_reached)
176*10465441SEvalZero break;
177*10465441SEvalZero
178*10465441SEvalZero back_lines(page_length + 1);
179*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
180*10465441SEvalZero cur_x, update_text, data);
181*10465441SEvalZero break;
182*10465441SEvalZero case 'B': /* Previous page */
183*10465441SEvalZero case 'b':
184*10465441SEvalZero case 'u':
185*10465441SEvalZero case KEY_PPAGE:
186*10465441SEvalZero if (begin_reached)
187*10465441SEvalZero break;
188*10465441SEvalZero back_lines(page_length + boxh);
189*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
190*10465441SEvalZero cur_x, update_text, data);
191*10465441SEvalZero break;
192*10465441SEvalZero case 'J': /* Next line */
193*10465441SEvalZero case 'j':
194*10465441SEvalZero case KEY_DOWN:
195*10465441SEvalZero if (end_reached)
196*10465441SEvalZero break;
197*10465441SEvalZero
198*10465441SEvalZero back_lines(page_length - 1);
199*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
200*10465441SEvalZero cur_x, update_text, data);
201*10465441SEvalZero break;
202*10465441SEvalZero case KEY_NPAGE: /* Next page */
203*10465441SEvalZero case ' ':
204*10465441SEvalZero case 'd':
205*10465441SEvalZero if (end_reached)
206*10465441SEvalZero break;
207*10465441SEvalZero
208*10465441SEvalZero begin_reached = 0;
209*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
210*10465441SEvalZero cur_x, update_text, data);
211*10465441SEvalZero break;
212*10465441SEvalZero case '0': /* Beginning of line */
213*10465441SEvalZero case 'H': /* Scroll left */
214*10465441SEvalZero case 'h':
215*10465441SEvalZero case KEY_LEFT:
216*10465441SEvalZero if (hscroll <= 0)
217*10465441SEvalZero break;
218*10465441SEvalZero
219*10465441SEvalZero if (key == '0')
220*10465441SEvalZero hscroll = 0;
221*10465441SEvalZero else
222*10465441SEvalZero hscroll--;
223*10465441SEvalZero /* Reprint current page to scroll horizontally */
224*10465441SEvalZero back_lines(page_length);
225*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
226*10465441SEvalZero cur_x, update_text, data);
227*10465441SEvalZero break;
228*10465441SEvalZero case 'L': /* Scroll right */
229*10465441SEvalZero case 'l':
230*10465441SEvalZero case KEY_RIGHT:
231*10465441SEvalZero if (hscroll >= MAX_LEN)
232*10465441SEvalZero break;
233*10465441SEvalZero hscroll++;
234*10465441SEvalZero /* Reprint current page to scroll horizontally */
235*10465441SEvalZero back_lines(page_length);
236*10465441SEvalZero refresh_text_box(dialog, box, boxh, boxw, cur_y,
237*10465441SEvalZero cur_x, update_text, data);
238*10465441SEvalZero break;
239*10465441SEvalZero case KEY_ESC:
240*10465441SEvalZero if (on_key_esc(dialog) == KEY_ESC)
241*10465441SEvalZero done = true;
242*10465441SEvalZero break;
243*10465441SEvalZero case KEY_RESIZE:
244*10465441SEvalZero back_lines(height);
245*10465441SEvalZero delwin(box);
246*10465441SEvalZero delwin(dialog);
247*10465441SEvalZero on_key_resize();
248*10465441SEvalZero goto do_resize;
249*10465441SEvalZero default:
250*10465441SEvalZero for (i = 0; keys[i]; i++) {
251*10465441SEvalZero if (key == keys[i]) {
252*10465441SEvalZero done = true;
253*10465441SEvalZero break;
254*10465441SEvalZero }
255*10465441SEvalZero }
256*10465441SEvalZero }
257*10465441SEvalZero }
258*10465441SEvalZero delwin(box);
259*10465441SEvalZero delwin(dialog);
260*10465441SEvalZero if (_vscroll) {
261*10465441SEvalZero const char *s;
262*10465441SEvalZero
263*10465441SEvalZero s = buf;
264*10465441SEvalZero *_vscroll = 0;
265*10465441SEvalZero back_lines(page_length);
266*10465441SEvalZero while (s < page && (s = strchr(s, '\n'))) {
267*10465441SEvalZero (*_vscroll)++;
268*10465441SEvalZero s++;
269*10465441SEvalZero }
270*10465441SEvalZero }
271*10465441SEvalZero if (_hscroll)
272*10465441SEvalZero *_hscroll = hscroll;
273*10465441SEvalZero return key;
274*10465441SEvalZero }
275*10465441SEvalZero
276*10465441SEvalZero /*
277*10465441SEvalZero * Go back 'n' lines in text. Called by dialog_textbox().
278*10465441SEvalZero * 'page' will be updated to point to the desired line in 'buf'.
279*10465441SEvalZero */
back_lines(int n)280*10465441SEvalZero static void back_lines(int n)
281*10465441SEvalZero {
282*10465441SEvalZero int i;
283*10465441SEvalZero
284*10465441SEvalZero begin_reached = 0;
285*10465441SEvalZero /* Go back 'n' lines */
286*10465441SEvalZero for (i = 0; i < n; i++) {
287*10465441SEvalZero if (*page == '\0') {
288*10465441SEvalZero if (end_reached) {
289*10465441SEvalZero end_reached = 0;
290*10465441SEvalZero continue;
291*10465441SEvalZero }
292*10465441SEvalZero }
293*10465441SEvalZero if (page == buf) {
294*10465441SEvalZero begin_reached = 1;
295*10465441SEvalZero return;
296*10465441SEvalZero }
297*10465441SEvalZero page--;
298*10465441SEvalZero do {
299*10465441SEvalZero if (page == buf) {
300*10465441SEvalZero begin_reached = 1;
301*10465441SEvalZero return;
302*10465441SEvalZero }
303*10465441SEvalZero page--;
304*10465441SEvalZero } while (*page != '\n');
305*10465441SEvalZero page++;
306*10465441SEvalZero }
307*10465441SEvalZero }
308*10465441SEvalZero
309*10465441SEvalZero /*
310*10465441SEvalZero * Print a new page of text.
311*10465441SEvalZero */
print_page(WINDOW * win,int height,int width,update_text_fn update_text,void * data)312*10465441SEvalZero static void print_page(WINDOW *win, int height, int width, update_text_fn
313*10465441SEvalZero update_text, void *data)
314*10465441SEvalZero {
315*10465441SEvalZero int i, passed_end = 0;
316*10465441SEvalZero
317*10465441SEvalZero if (update_text) {
318*10465441SEvalZero char *end;
319*10465441SEvalZero
320*10465441SEvalZero for (i = 0; i < height; i++)
321*10465441SEvalZero get_line();
322*10465441SEvalZero end = page;
323*10465441SEvalZero back_lines(height);
324*10465441SEvalZero update_text(buf, page - buf, end - buf, data);
325*10465441SEvalZero }
326*10465441SEvalZero
327*10465441SEvalZero page_length = 0;
328*10465441SEvalZero for (i = 0; i < height; i++) {
329*10465441SEvalZero print_line(win, i, width);
330*10465441SEvalZero if (!passed_end)
331*10465441SEvalZero page_length++;
332*10465441SEvalZero if (end_reached && !passed_end)
333*10465441SEvalZero passed_end = 1;
334*10465441SEvalZero }
335*10465441SEvalZero wnoutrefresh(win);
336*10465441SEvalZero }
337*10465441SEvalZero
338*10465441SEvalZero /*
339*10465441SEvalZero * Print a new line of text.
340*10465441SEvalZero */
print_line(WINDOW * win,int row,int width)341*10465441SEvalZero static void print_line(WINDOW * win, int row, int width)
342*10465441SEvalZero {
343*10465441SEvalZero char *line;
344*10465441SEvalZero
345*10465441SEvalZero line = get_line();
346*10465441SEvalZero line += MIN(strlen(line), hscroll); /* Scroll horizontally */
347*10465441SEvalZero wmove(win, row, 0); /* move cursor to correct line */
348*10465441SEvalZero waddch(win, ' ');
349*10465441SEvalZero waddnstr(win, line, MIN(strlen(line), width - 2));
350*10465441SEvalZero
351*10465441SEvalZero /* Clear 'residue' of previous line */
352*10465441SEvalZero #if OLD_NCURSES
353*10465441SEvalZero {
354*10465441SEvalZero int x = getcurx(win);
355*10465441SEvalZero int i;
356*10465441SEvalZero for (i = 0; i < width - x; i++)
357*10465441SEvalZero waddch(win, ' ');
358*10465441SEvalZero }
359*10465441SEvalZero #else
360*10465441SEvalZero wclrtoeol(win);
361*10465441SEvalZero #endif
362*10465441SEvalZero }
363*10465441SEvalZero
364*10465441SEvalZero /*
365*10465441SEvalZero * Return current line of text. Called by dialog_textbox() and print_line().
366*10465441SEvalZero * 'page' should point to start of current line before calling, and will be
367*10465441SEvalZero * updated to point to start of next line.
368*10465441SEvalZero */
get_line(void)369*10465441SEvalZero static char *get_line(void)
370*10465441SEvalZero {
371*10465441SEvalZero int i = 0;
372*10465441SEvalZero static char line[MAX_LEN + 1];
373*10465441SEvalZero
374*10465441SEvalZero end_reached = 0;
375*10465441SEvalZero while (*page != '\n') {
376*10465441SEvalZero if (*page == '\0') {
377*10465441SEvalZero end_reached = 1;
378*10465441SEvalZero break;
379*10465441SEvalZero } else if (i < MAX_LEN)
380*10465441SEvalZero line[i++] = *(page++);
381*10465441SEvalZero else {
382*10465441SEvalZero /* Truncate lines longer than MAX_LEN characters */
383*10465441SEvalZero if (i == MAX_LEN)
384*10465441SEvalZero line[i++] = '\0';
385*10465441SEvalZero page++;
386*10465441SEvalZero }
387*10465441SEvalZero }
388*10465441SEvalZero if (i <= MAX_LEN)
389*10465441SEvalZero line[i] = '\0';
390*10465441SEvalZero if (!end_reached)
391*10465441SEvalZero page++; /* move past '\n' */
392*10465441SEvalZero
393*10465441SEvalZero return line;
394*10465441SEvalZero }
395*10465441SEvalZero
396*10465441SEvalZero /*
397*10465441SEvalZero * Print current position
398*10465441SEvalZero */
print_position(WINDOW * win)399*10465441SEvalZero static void print_position(WINDOW * win)
400*10465441SEvalZero {
401*10465441SEvalZero int percent;
402*10465441SEvalZero
403*10465441SEvalZero wattrset(win, dlg.position_indicator.atr);
404*10465441SEvalZero wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
405*10465441SEvalZero percent = (page - buf) * 100 / strlen(buf);
406*10465441SEvalZero wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
407*10465441SEvalZero wprintw(win, "(%3d%%)", percent);
408*10465441SEvalZero }
409