kconfig/lxdialog/textbox.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jan 17 23:06:02 2010 +0100 (2010-01-17)
changeset 1740 c57458bb354d
parent 1 eeea35fbf182
permissions -rw-r--r--
configure: do not require hg when configuring in an hg clone

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