kconfig/lxdialog/textbox.c
changeset 1 eeea35fbf182
child 943 1cca90ce0481
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/kconfig/lxdialog/textbox.c	Sat Feb 24 11:00:05 2007 +0000
     1.3 @@ -0,0 +1,391 @@
     1.4 +/*
     1.5 + *  textbox.c -- implements the text box
     1.6 + *
     1.7 + *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
     1.8 + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
     1.9 + *
    1.10 + *  This program is free software; you can redistribute it and/or
    1.11 + *  modify it under the terms of the GNU General Public License
    1.12 + *  as published by the Free Software Foundation; either version 2
    1.13 + *  of the License, or (at your option) any later version.
    1.14 + *
    1.15 + *  This program is distributed in the hope that it will be useful,
    1.16 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.17 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.18 + *  GNU General Public License for more details.
    1.19 + *
    1.20 + *  You should have received a copy of the GNU General Public License
    1.21 + *  along with this program; if not, write to the Free Software
    1.22 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    1.23 + */
    1.24 +
    1.25 +#include "dialog.h"
    1.26 +
    1.27 +static void back_lines(int n);
    1.28 +static void print_page(WINDOW * win, int height, int width);
    1.29 +static void print_line(WINDOW * win, int row, int width);
    1.30 +static char *get_line(void);
    1.31 +static void print_position(WINDOW * win);
    1.32 +
    1.33 +static int hscroll;
    1.34 +static int begin_reached, end_reached, page_length;
    1.35 +static const char *buf;
    1.36 +static const char *page;
    1.37 +
    1.38 +/*
    1.39 + * refresh window content
    1.40 + */
    1.41 +static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
    1.42 +							  int cur_y, int cur_x)
    1.43 +{
    1.44 +	print_page(box, boxh, boxw);
    1.45 +	print_position(dialog);
    1.46 +	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
    1.47 +	wrefresh(dialog);
    1.48 +}
    1.49 +
    1.50 +
    1.51 +/*
    1.52 + * Display text from a file in a dialog box.
    1.53 + */
    1.54 +int dialog_textbox(const char *title, const char *tbuf,
    1.55 +		   int initial_height, int initial_width)
    1.56 +{
    1.57 +	int i, x, y, cur_x, cur_y, key = 0;
    1.58 +	int height, width, boxh, boxw;
    1.59 +	int passed_end;
    1.60 +	WINDOW *dialog, *box;
    1.61 +
    1.62 +	begin_reached = 1;
    1.63 +	end_reached = 0;
    1.64 +	page_length = 0;
    1.65 +	hscroll = 0;
    1.66 +	buf = tbuf;
    1.67 +	page = buf;	/* page is pointer to start of page to be displayed */
    1.68 +
    1.69 +do_resize:
    1.70 +	getmaxyx(stdscr, height, width);
    1.71 +	if (height < 8 || width < 8)
    1.72 +		return -ERRDISPLAYTOOSMALL;
    1.73 +	if (initial_height != 0)
    1.74 +		height = initial_height;
    1.75 +	else
    1.76 +		if (height > 4)
    1.77 +			height -= 4;
    1.78 +		else
    1.79 +			height = 0;
    1.80 +	if (initial_width != 0)
    1.81 +		width = initial_width;
    1.82 +	else
    1.83 +		if (width > 5)
    1.84 +			width -= 5;
    1.85 +		else
    1.86 +			width = 0;
    1.87 +
    1.88 +	/* center dialog box on screen */
    1.89 +	x = (COLS - width) / 2;
    1.90 +	y = (LINES - height) / 2;
    1.91 +
    1.92 +	draw_shadow(stdscr, y, x, height, width);
    1.93 +
    1.94 +	dialog = newwin(height, width, y, x);
    1.95 +	keypad(dialog, TRUE);
    1.96 +
    1.97 +	/* Create window for box region, used for scrolling text */
    1.98 +	boxh = height - 4;
    1.99 +	boxw = width - 2;
   1.100 +	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
   1.101 +	wattrset(box, dlg.dialog.atr);
   1.102 +	wbkgdset(box, dlg.dialog.atr & A_COLOR);
   1.103 +
   1.104 +	keypad(box, TRUE);
   1.105 +
   1.106 +	/* register the new window, along with its borders */
   1.107 +	draw_box(dialog, 0, 0, height, width,
   1.108 +		 dlg.dialog.atr, dlg.border.atr);
   1.109 +
   1.110 +	wattrset(dialog, dlg.border.atr);
   1.111 +	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
   1.112 +	for (i = 0; i < width - 2; i++)
   1.113 +		waddch(dialog, ACS_HLINE);
   1.114 +	wattrset(dialog, dlg.dialog.atr);
   1.115 +	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
   1.116 +	waddch(dialog, ACS_RTEE);
   1.117 +
   1.118 +	print_title(dialog, title, width);
   1.119 +
   1.120 +	print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
   1.121 +	wnoutrefresh(dialog);
   1.122 +	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
   1.123 +
   1.124 +	/* Print first page of text */
   1.125 +	attr_clear(box, boxh, boxw, dlg.dialog.atr);
   1.126 +	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
   1.127 +
   1.128 +	while ((key != KEY_ESC) && (key != '\n')) {
   1.129 +		key = wgetch(dialog);
   1.130 +		switch (key) {
   1.131 +		case 'E':	/* Exit */
   1.132 +		case 'e':
   1.133 +		case 'X':
   1.134 +		case 'x':
   1.135 +			delwin(box);
   1.136 +			delwin(dialog);
   1.137 +			return 0;
   1.138 +		case 'g':	/* First page */
   1.139 +		case KEY_HOME:
   1.140 +			if (!begin_reached) {
   1.141 +				begin_reached = 1;
   1.142 +				page = buf;
   1.143 +				refresh_text_box(dialog, box, boxh, boxw,
   1.144 +						 cur_y, cur_x);
   1.145 +			}
   1.146 +			break;
   1.147 +		case 'G':	/* Last page */
   1.148 +		case KEY_END:
   1.149 +
   1.150 +			end_reached = 1;
   1.151 +			/* point to last char in buf */
   1.152 +			page = buf + strlen(buf);
   1.153 +			back_lines(boxh);
   1.154 +			refresh_text_box(dialog, box, boxh, boxw,
   1.155 +					 cur_y, cur_x);
   1.156 +			break;
   1.157 +		case 'K':	/* Previous line */
   1.158 +		case 'k':
   1.159 +		case KEY_UP:
   1.160 +			if (!begin_reached) {
   1.161 +				back_lines(page_length + 1);
   1.162 +
   1.163 +				/* We don't call print_page() here but use
   1.164 +				 * scrolling to ensure faster screen update.
   1.165 +				 * However, 'end_reached' and 'page_length'
   1.166 +				 * should still be updated, and 'page' should
   1.167 +				 * point to start of next page. This is done
   1.168 +				 * by calling get_line() in the following
   1.169 +				 * 'for' loop. */
   1.170 +				scrollok(box, TRUE);
   1.171 +				wscrl(box, -1);	/* Scroll box region down one line */
   1.172 +				scrollok(box, FALSE);
   1.173 +				page_length = 0;
   1.174 +				passed_end = 0;
   1.175 +				for (i = 0; i < boxh; i++) {
   1.176 +					if (!i) {
   1.177 +						/* print first line of page */
   1.178 +						print_line(box, 0, boxw);
   1.179 +						wnoutrefresh(box);
   1.180 +					} else
   1.181 +						/* Called to update 'end_reached' and 'page' */
   1.182 +						get_line();
   1.183 +					if (!passed_end)
   1.184 +						page_length++;
   1.185 +					if (end_reached && !passed_end)
   1.186 +						passed_end = 1;
   1.187 +				}
   1.188 +
   1.189 +				print_position(dialog);
   1.190 +				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
   1.191 +				wrefresh(dialog);
   1.192 +			}
   1.193 +			break;
   1.194 +		case 'B':	/* Previous page */
   1.195 +		case 'b':
   1.196 +		case KEY_PPAGE:
   1.197 +			if (begin_reached)
   1.198 +				break;
   1.199 +			back_lines(page_length + boxh);
   1.200 +			refresh_text_box(dialog, box, boxh, boxw,
   1.201 +					 cur_y, cur_x);
   1.202 +			break;
   1.203 +		case 'J':	/* Next line */
   1.204 +		case 'j':
   1.205 +		case KEY_DOWN:
   1.206 +			if (!end_reached) {
   1.207 +				begin_reached = 0;
   1.208 +				scrollok(box, TRUE);
   1.209 +				scroll(box);	/* Scroll box region up one line */
   1.210 +				scrollok(box, FALSE);
   1.211 +				print_line(box, boxh - 1, boxw);
   1.212 +				wnoutrefresh(box);
   1.213 +				print_position(dialog);
   1.214 +				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
   1.215 +				wrefresh(dialog);
   1.216 +			}
   1.217 +			break;
   1.218 +		case KEY_NPAGE:	/* Next page */
   1.219 +		case ' ':
   1.220 +			if (end_reached)
   1.221 +				break;
   1.222 +
   1.223 +			begin_reached = 0;
   1.224 +			refresh_text_box(dialog, box, boxh, boxw,
   1.225 +					 cur_y, cur_x);
   1.226 +			break;
   1.227 +		case '0':	/* Beginning of line */
   1.228 +		case 'H':	/* Scroll left */
   1.229 +		case 'h':
   1.230 +		case KEY_LEFT:
   1.231 +			if (hscroll <= 0)
   1.232 +				break;
   1.233 +
   1.234 +			if (key == '0')
   1.235 +				hscroll = 0;
   1.236 +			else
   1.237 +				hscroll--;
   1.238 +			/* Reprint current page to scroll horizontally */
   1.239 +			back_lines(page_length);
   1.240 +			refresh_text_box(dialog, box, boxh, boxw,
   1.241 +					 cur_y, cur_x);
   1.242 +			break;
   1.243 +		case 'L':	/* Scroll right */
   1.244 +		case 'l':
   1.245 +		case KEY_RIGHT:
   1.246 +			if (hscroll >= MAX_LEN)
   1.247 +				break;
   1.248 +			hscroll++;
   1.249 +			/* Reprint current page to scroll horizontally */
   1.250 +			back_lines(page_length);
   1.251 +			refresh_text_box(dialog, box, boxh, boxw,
   1.252 +					 cur_y, cur_x);
   1.253 +			break;
   1.254 +		case KEY_ESC:
   1.255 +			key = on_key_esc(dialog);
   1.256 +			break;
   1.257 +		case KEY_RESIZE:
   1.258 +			back_lines(height);
   1.259 +			delwin(box);
   1.260 +			delwin(dialog);
   1.261 +			on_key_resize();
   1.262 +			goto do_resize;
   1.263 +		}
   1.264 +	}
   1.265 +	delwin(box);
   1.266 +	delwin(dialog);
   1.267 +	return key;		/* ESC pressed */
   1.268 +}
   1.269 +
   1.270 +/*
   1.271 + * Go back 'n' lines in text. Called by dialog_textbox().
   1.272 + * 'page' will be updated to point to the desired line in 'buf'.
   1.273 + */
   1.274 +static void back_lines(int n)
   1.275 +{
   1.276 +	int i;
   1.277 +
   1.278 +	begin_reached = 0;
   1.279 +	/* Go back 'n' lines */
   1.280 +	for (i = 0; i < n; i++) {
   1.281 +		if (*page == '\0') {
   1.282 +			if (end_reached) {
   1.283 +				end_reached = 0;
   1.284 +				continue;
   1.285 +			}
   1.286 +		}
   1.287 +		if (page == buf) {
   1.288 +			begin_reached = 1;
   1.289 +			return;
   1.290 +		}
   1.291 +		page--;
   1.292 +		do {
   1.293 +			if (page == buf) {
   1.294 +				begin_reached = 1;
   1.295 +				return;
   1.296 +			}
   1.297 +			page--;
   1.298 +		} while (*page != '\n');
   1.299 +		page++;
   1.300 +	}
   1.301 +}
   1.302 +
   1.303 +/*
   1.304 + * Print a new page of text. Called by dialog_textbox().
   1.305 + */
   1.306 +static void print_page(WINDOW * win, int height, int width)
   1.307 +{
   1.308 +	int i, passed_end = 0;
   1.309 +
   1.310 +	page_length = 0;
   1.311 +	for (i = 0; i < height; i++) {
   1.312 +		print_line(win, i, width);
   1.313 +		if (!passed_end)
   1.314 +			page_length++;
   1.315 +		if (end_reached && !passed_end)
   1.316 +			passed_end = 1;
   1.317 +	}
   1.318 +	wnoutrefresh(win);
   1.319 +}
   1.320 +
   1.321 +/*
   1.322 + * Print a new line of text. Called by dialog_textbox() and print_page().
   1.323 + */
   1.324 +static void print_line(WINDOW * win, int row, int width)
   1.325 +{
   1.326 +	int y, x;
   1.327 +	char *line;
   1.328 +
   1.329 +	line = get_line();
   1.330 +	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
   1.331 +	wmove(win, row, 0);	/* move cursor to correct line */
   1.332 +	waddch(win, ' ');
   1.333 +	waddnstr(win, line, MIN(strlen(line), width - 2));
   1.334 +
   1.335 +	getyx(win, y, x);
   1.336 +	/* Clear 'residue' of previous line */
   1.337 +#if OLD_NCURSES
   1.338 +	{
   1.339 +		int i;
   1.340 +		for (i = 0; i < width - x; i++)
   1.341 +			waddch(win, ' ');
   1.342 +	}
   1.343 +#else
   1.344 +	wclrtoeol(win);
   1.345 +#endif
   1.346 +}
   1.347 +
   1.348 +/*
   1.349 + * Return current line of text. Called by dialog_textbox() and print_line().
   1.350 + * 'page' should point to start of current line before calling, and will be
   1.351 + * updated to point to start of next line.
   1.352 + */
   1.353 +static char *get_line(void)
   1.354 +{
   1.355 +	int i = 0;
   1.356 +	static char line[MAX_LEN + 1];
   1.357 +
   1.358 +	end_reached = 0;
   1.359 +	while (*page != '\n') {
   1.360 +		if (*page == '\0') {
   1.361 +			if (!end_reached) {
   1.362 +				end_reached = 1;
   1.363 +				break;
   1.364 +			}
   1.365 +		} else if (i < MAX_LEN)
   1.366 +			line[i++] = *(page++);
   1.367 +		else {
   1.368 +			/* Truncate lines longer than MAX_LEN characters */
   1.369 +			if (i == MAX_LEN)
   1.370 +				line[i++] = '\0';
   1.371 +			page++;
   1.372 +		}
   1.373 +	}
   1.374 +	if (i <= MAX_LEN)
   1.375 +		line[i] = '\0';
   1.376 +	if (!end_reached)
   1.377 +		page++;		/* move pass '\n' */
   1.378 +
   1.379 +	return line;
   1.380 +}
   1.381 +
   1.382 +/*
   1.383 + * Print current position
   1.384 + */
   1.385 +static void print_position(WINDOW * win)
   1.386 +{
   1.387 +	int percent;
   1.388 +
   1.389 +	wattrset(win, dlg.position_indicator.atr);
   1.390 +	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
   1.391 +	percent = (page - buf) * 100 / strlen(buf);
   1.392 +	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
   1.393 +	wprintw(win, "(%3d%%)", percent);
   1.394 +}