kconfig/lxdialog/menubox.c
author "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
Mon Apr 16 15:25:36 2012 +0200 (2012-04-16)
changeset 2941 13e40098fffc
parent 943 1cca90ce0481
permissions -rw-r--r--
cc/gcc: update Linaro GCC revisions to 2012.04

Update Linaro GCC with the latest available revisions.

The 4.7 revision is also released, but the infrastructure is not yet ready for
it in CT-NG.

Signed-off-by: "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
yann@1
     1
/*
yann@1
     2
 *  menubox.c -- implements the menu 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 (roadcapw@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
/*
yann@1
    23
 *  Changes by Clifford Wolf (god@clifford.at)
yann@1
    24
 *
yann@1
    25
 *  [ 1998-06-13 ]
yann@1
    26
 *
yann@1
    27
 *    *)  A bugfix for the Page-Down problem
yann@1
    28
 *
yann@1
    29
 *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
yann@1
    30
 *        to the first position in the menu box.  Now lxdialog is a bit
yann@1
    31
 *        smarter and works more like other menu systems (just have a look at
yann@1
    32
 *        it).
yann@1
    33
 *
yann@1
    34
 *    *)  Formerly if I selected something my scrolling would be broken because
yann@1
    35
 *        lxdialog is re-invoked by the Menuconfig shell script, can't
yann@1
    36
 *        remember the last scrolling position, and just sets it so that the
yann@1
    37
 *        cursor is at the bottom of the box.  Now it writes the temporary file
yann@1
    38
 *        lxdialog.scrltmp which contains this information. The file is
yann@1
    39
 *        deleted by lxdialog if the user leaves a submenu or enters a new
yann@1
    40
 *        one, but it would be nice if Menuconfig could make another "rm -f"
yann@1
    41
 *        just to be sure.  Just try it out - you will recognise a difference!
yann@1
    42
 *
yann@1
    43
 *  [ 1998-06-14 ]
yann@1
    44
 *
yann@1
    45
 *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
yann@1
    46
 *        and menus change their size on the fly.
yann@1
    47
 *
yann@1
    48
 *    *)  If for some reason the last scrolling position is not saved by
yann@1
    49
 *        lxdialog, it sets the scrolling so that the selected item is in the
yann@1
    50
 *        middle of the menu box, not at the bottom.
yann@1
    51
 *
yann@1
    52
 * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
yann@1
    53
 * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
yann@1
    54
 * This fixes a bug in Menuconfig where using ' ' to descend into menus
yann@1
    55
 * would leave mis-synchronized lxdialog.scrltmp files lying around,
yann@1
    56
 * fscanf would read in 'scroll', and eventually that value would get used.
yann@1
    57
 */
yann@1
    58
yann@1
    59
#include "dialog.h"
yann@1
    60
yann@1
    61
static int menu_width, item_x;
yann@1
    62
yann@1
    63
/*
yann@1
    64
 * Print menu item
yann@1
    65
 */
yann@1
    66
static void do_print_item(WINDOW * win, const char *item, int line_y,
yann@1
    67
                          int selected, int hotkey)
yann@1
    68
{
yann@1
    69
	int j;
yann@1
    70
	char *menu_item = malloc(menu_width + 1);
yann@1
    71
yann@1
    72
	strncpy(menu_item, item, menu_width - item_x);
yann@1
    73
	menu_item[menu_width - item_x] = '\0';
yann@1
    74
	j = first_alpha(menu_item, "YyNnMmHh");
yann@1
    75
yann@1
    76
	/* Clear 'residue' of last item */
yann@1
    77
	wattrset(win, dlg.menubox.atr);
yann@1
    78
	wmove(win, line_y, 0);
yann@1
    79
#if OLD_NCURSES
yann@1
    80
	{
yann@1
    81
		int i;
yann@1
    82
		for (i = 0; i < menu_width; i++)
yann@1
    83
			waddch(win, ' ');
yann@1
    84
	}
yann@1
    85
#else
yann@1
    86
	wclrtoeol(win);
yann@1
    87
#endif
yann@1
    88
	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
yann@1
    89
	mvwaddstr(win, line_y, item_x, menu_item);
yann@1
    90
	if (hotkey) {
yann@1
    91
		wattrset(win, selected ? dlg.tag_key_selected.atr
yann@1
    92
			 : dlg.tag_key.atr);
yann@1
    93
		mvwaddch(win, line_y, item_x + j, menu_item[j]);
yann@1
    94
	}
yann@1
    95
	if (selected) {
yann@1
    96
		wmove(win, line_y, item_x + 1);
yann@1
    97
	}
yann@1
    98
	free(menu_item);
yann@1
    99
	wrefresh(win);
yann@1
   100
}
yann@1
   101
yann@1
   102
#define print_item(index, choice, selected)				\
yann@1
   103
do {									\
yann@1
   104
	item_set(index);						\
yann@1
   105
	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
yann@1
   106
} while (0)
yann@1
   107
yann@1
   108
/*
yann@1
   109
 * Print the scroll indicators.
yann@1
   110
 */
yann@1
   111
static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
yann@1
   112
			 int height)
yann@1
   113
{
yann@1
   114
	int cur_y, cur_x;
yann@1
   115
yann@1
   116
	getyx(win, cur_y, cur_x);
yann@1
   117
yann@1
   118
	wmove(win, y, x);
yann@1
   119
yann@1
   120
	if (scroll > 0) {
yann@1
   121
		wattrset(win, dlg.uarrow.atr);
yann@1
   122
		waddch(win, ACS_UARROW);
yann@1
   123
		waddstr(win, "(-)");
yann@1
   124
	} else {
yann@1
   125
		wattrset(win, dlg.menubox.atr);
yann@1
   126
		waddch(win, ACS_HLINE);
yann@1
   127
		waddch(win, ACS_HLINE);
yann@1
   128
		waddch(win, ACS_HLINE);
yann@1
   129
		waddch(win, ACS_HLINE);
yann@1
   130
	}
yann@1
   131
yann@1
   132
	y = y + height + 1;
yann@1
   133
	wmove(win, y, x);
yann@1
   134
	wrefresh(win);
yann@1
   135
yann@1
   136
	if ((height < item_no) && (scroll + height < item_no)) {
yann@1
   137
		wattrset(win, dlg.darrow.atr);
yann@1
   138
		waddch(win, ACS_DARROW);
yann@1
   139
		waddstr(win, "(+)");
yann@1
   140
	} else {
yann@1
   141
		wattrset(win, dlg.menubox_border.atr);
yann@1
   142
		waddch(win, ACS_HLINE);
yann@1
   143
		waddch(win, ACS_HLINE);
yann@1
   144
		waddch(win, ACS_HLINE);
yann@1
   145
		waddch(win, ACS_HLINE);
yann@1
   146
	}
yann@1
   147
yann@1
   148
	wmove(win, cur_y, cur_x);
yann@1
   149
	wrefresh(win);
yann@1
   150
}
yann@1
   151
yann@1
   152
/*
yann@1
   153
 * Display the termination buttons.
yann@1
   154
 */
yann@1
   155
static void print_buttons(WINDOW * win, int height, int width, int selected)
yann@1
   156
{
yann@1
   157
	int x = width / 2 - 16;
yann@1
   158
	int y = height - 2;
yann@1
   159
yann@943
   160
	print_button(win, gettext("Select"), y, x, selected == 0);
yann@943
   161
	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
yann@943
   162
	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
yann@1
   163
yann@1
   164
	wmove(win, y, x + 1 + 12 * selected);
yann@1
   165
	wrefresh(win);
yann@1
   166
}
yann@1
   167
yann@1
   168
/* scroll up n lines (n may be negative) */
yann@1
   169
static void do_scroll(WINDOW *win, int *scroll, int n)
yann@1
   170
{
yann@1
   171
	/* Scroll menu up */
yann@1
   172
	scrollok(win, TRUE);
yann@1
   173
	wscrl(win, n);
yann@1
   174
	scrollok(win, FALSE);
yann@1
   175
	*scroll = *scroll + n;
yann@1
   176
	wrefresh(win);
yann@1
   177
}
yann@1
   178
yann@1
   179
/*
yann@1
   180
 * Display a menu for choosing among a number of options
yann@1
   181
 */
yann@1
   182
int dialog_menu(const char *title, const char *prompt,
yann@1
   183
                const void *selected, int *s_scroll)
yann@1
   184
{
yann@1
   185
	int i, j, x, y, box_x, box_y;
yann@1
   186
	int height, width, menu_height;
yann@1
   187
	int key = 0, button = 0, scroll = 0, choice = 0;
yann@1
   188
	int first_item =  0, max_choice;
yann@1
   189
	WINDOW *dialog, *menu;
yann@1
   190
yann@1
   191
do_resize:
yann@1
   192
	height = getmaxy(stdscr);
yann@1
   193
	width = getmaxx(stdscr);
yann@1
   194
	if (height < 15 || width < 65)
yann@1
   195
		return -ERRDISPLAYTOOSMALL;
yann@1
   196
yann@1
   197
	height -= 4;
yann@1
   198
	width  -= 5;
yann@1
   199
	menu_height = height - 10;
yann@1
   200
yann@1
   201
	max_choice = MIN(menu_height, item_count());
yann@1
   202
yann@1
   203
	/* center dialog box on screen */
yann@1
   204
	x = (COLS - width) / 2;
yann@1
   205
	y = (LINES - height) / 2;
yann@1
   206
yann@1
   207
	draw_shadow(stdscr, y, x, height, width);
yann@1
   208
yann@1
   209
	dialog = newwin(height, width, y, x);
yann@1
   210
	keypad(dialog, TRUE);
yann@1
   211
yann@1
   212
	draw_box(dialog, 0, 0, height, width,
yann@1
   213
		 dlg.dialog.atr, dlg.border.atr);
yann@1
   214
	wattrset(dialog, dlg.border.atr);
yann@1
   215
	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
yann@1
   216
	for (i = 0; i < width - 2; i++)
yann@1
   217
		waddch(dialog, ACS_HLINE);
yann@1
   218
	wattrset(dialog, dlg.dialog.atr);
yann@1
   219
	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
yann@1
   220
	waddch(dialog, ACS_RTEE);
yann@1
   221
yann@1
   222
	print_title(dialog, title, width);
yann@1
   223
yann@1
   224
	wattrset(dialog, dlg.dialog.atr);
yann@1
   225
	print_autowrap(dialog, prompt, width - 2, 1, 3);
yann@1
   226
yann@1
   227
	menu_width = width - 6;
yann@1
   228
	box_y = height - menu_height - 5;
yann@1
   229
	box_x = (width - menu_width) / 2 - 1;
yann@1
   230
yann@1
   231
	/* create new window for the menu */
yann@1
   232
	menu = subwin(dialog, menu_height, menu_width,
yann@1
   233
		      y + box_y + 1, x + box_x + 1);
yann@1
   234
	keypad(menu, TRUE);
yann@1
   235
yann@1
   236
	/* draw a box around the menu items */
yann@1
   237
	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
yann@1
   238
		 dlg.menubox_border.atr, dlg.menubox.atr);
yann@1
   239
yann@1
   240
	if (menu_width >= 80)
yann@1
   241
		item_x = (menu_width - 70) / 2;
yann@1
   242
	else
yann@1
   243
		item_x = 4;
yann@1
   244
yann@1
   245
	/* Set choice to default item */
yann@1
   246
	item_foreach()
yann@1
   247
		if (selected && (selected == item_data()))
yann@1
   248
			choice = item_n();
yann@1
   249
	/* get the saved scroll info */
yann@1
   250
	scroll = *s_scroll;
yann@1
   251
	if ((scroll <= choice) && (scroll + max_choice > choice) &&
yann@1
   252
	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
yann@1
   253
		first_item = scroll;
yann@1
   254
		choice = choice - scroll;
yann@1
   255
	} else {
yann@1
   256
		scroll = 0;
yann@1
   257
	}
yann@1
   258
	if ((choice >= max_choice)) {
yann@1
   259
		if (choice >= item_count() - max_choice / 2)
yann@1
   260
			scroll = first_item = item_count() - max_choice;
yann@1
   261
		else
yann@1
   262
			scroll = first_item = choice - max_choice / 2;
yann@1
   263
		choice = choice - scroll;
yann@1
   264
	}
yann@1
   265
yann@1
   266
	/* Print the menu */
yann@1
   267
	for (i = 0; i < max_choice; i++) {
yann@1
   268
		print_item(first_item + i, i, i == choice);
yann@1
   269
	}
yann@1
   270
yann@1
   271
	wnoutrefresh(menu);
yann@1
   272
yann@1
   273
	print_arrows(dialog, item_count(), scroll,
yann@1
   274
		     box_y, box_x + item_x + 1, menu_height);
yann@1
   275
yann@1
   276
	print_buttons(dialog, height, width, 0);
yann@1
   277
	wmove(menu, choice, item_x + 1);
yann@1
   278
	wrefresh(menu);
yann@1
   279
yann@1
   280
	while (key != KEY_ESC) {
yann@1
   281
		key = wgetch(menu);
yann@1
   282
yann@1
   283
		if (key < 256 && isalpha(key))
yann@1
   284
			key = tolower(key);
yann@1
   285
yann@1
   286
		if (strchr("ynmh", key))
yann@1
   287
			i = max_choice;
yann@1
   288
		else {
yann@1
   289
			for (i = choice + 1; i < max_choice; i++) {
yann@1
   290
				item_set(scroll + i);
yann@1
   291
				j = first_alpha(item_str(), "YyNnMmHh");
yann@1
   292
				if (key == tolower(item_str()[j]))
yann@1
   293
					break;
yann@1
   294
			}
yann@1
   295
			if (i == max_choice)
yann@1
   296
				for (i = 0; i < max_choice; i++) {
yann@1
   297
					item_set(scroll + i);
yann@1
   298
					j = first_alpha(item_str(), "YyNnMmHh");
yann@1
   299
					if (key == tolower(item_str()[j]))
yann@1
   300
						break;
yann@1
   301
				}
yann@1
   302
		}
yann@1
   303
yann@1
   304
		if (i < max_choice ||
yann@1
   305
		    key == KEY_UP || key == KEY_DOWN ||
yann@1
   306
		    key == '-' || key == '+' ||
yann@1
   307
		    key == KEY_PPAGE || key == KEY_NPAGE) {
yann@1
   308
			/* Remove highligt of current item */
yann@1
   309
			print_item(scroll + choice, choice, FALSE);
yann@1
   310
yann@1
   311
			if (key == KEY_UP || key == '-') {
yann@1
   312
				if (choice < 2 && scroll) {
yann@1
   313
					/* Scroll menu down */
yann@1
   314
					do_scroll(menu, &scroll, -1);
yann@1
   315
yann@1
   316
					print_item(scroll, 0, FALSE);
yann@1
   317
				} else
yann@1
   318
					choice = MAX(choice - 1, 0);
yann@1
   319
yann@1
   320
			} else if (key == KEY_DOWN || key == '+') {
yann@1
   321
				print_item(scroll+choice, choice, FALSE);
yann@1
   322
yann@1
   323
				if ((choice > max_choice - 3) &&
yann@1
   324
				    (scroll + max_choice < item_count())) {
yann@1
   325
					/* Scroll menu up */
yann@1
   326
					do_scroll(menu, &scroll, 1);
yann@1
   327
yann@1
   328
					print_item(scroll+max_choice - 1,
yann@1
   329
						   max_choice - 1, FALSE);
yann@1
   330
				} else
yann@1
   331
					choice = MIN(choice + 1, max_choice - 1);
yann@1
   332
yann@1
   333
			} else if (key == KEY_PPAGE) {
yann@1
   334
				scrollok(menu, TRUE);
yann@1
   335
				for (i = 0; (i < max_choice); i++) {
yann@1
   336
					if (scroll > 0) {
yann@1
   337
						do_scroll(menu, &scroll, -1);
yann@1
   338
						print_item(scroll, 0, FALSE);
yann@1
   339
					} else {
yann@1
   340
						if (choice > 0)
yann@1
   341
							choice--;
yann@1
   342
					}
yann@1
   343
				}
yann@1
   344
yann@1
   345
			} else if (key == KEY_NPAGE) {
yann@1
   346
				for (i = 0; (i < max_choice); i++) {
yann@1
   347
					if (scroll + max_choice < item_count()) {
yann@1
   348
						do_scroll(menu, &scroll, 1);
yann@1
   349
						print_item(scroll+max_choice-1,
yann@1
   350
							   max_choice - 1, FALSE);
yann@1
   351
					} else {
yann@1
   352
						if (choice + 1 < max_choice)
yann@1
   353
							choice++;
yann@1
   354
					}
yann@1
   355
				}
yann@1
   356
			} else
yann@1
   357
				choice = i;
yann@1
   358
yann@1
   359
			print_item(scroll + choice, choice, TRUE);
yann@1
   360
yann@1
   361
			print_arrows(dialog, item_count(), scroll,
yann@1
   362
				     box_y, box_x + item_x + 1, menu_height);
yann@1
   363
yann@1
   364
			wnoutrefresh(dialog);
yann@1
   365
			wrefresh(menu);
yann@1
   366
yann@1
   367
			continue;	/* wait for another key press */
yann@1
   368
		}
yann@1
   369
yann@1
   370
		switch (key) {
yann@1
   371
		case KEY_LEFT:
yann@1
   372
		case TAB:
yann@1
   373
		case KEY_RIGHT:
yann@1
   374
			button = ((key == KEY_LEFT ? --button : ++button) < 0)
yann@1
   375
			    ? 2 : (button > 2 ? 0 : button);
yann@1
   376
yann@1
   377
			print_buttons(dialog, height, width, button);
yann@1
   378
			wrefresh(menu);
yann@1
   379
			break;
yann@1
   380
		case ' ':
yann@1
   381
		case 's':
yann@1
   382
		case 'y':
yann@1
   383
		case 'n':
yann@1
   384
		case 'm':
yann@1
   385
		case '/':
yann@2448
   386
		case 'h':
yann@2448
   387
		case '?':
yann@2448
   388
		case 'z':
yann@2448
   389
		case '\n':
yann@1
   390
			/* save scroll info */
yann@1
   391
			*s_scroll = scroll;
yann@1
   392
			delwin(menu);
yann@1
   393
			delwin(dialog);
yann@1
   394
			item_set(scroll + choice);
yann@1
   395
			item_set_selected(1);
yann@1
   396
			switch (key) {
yann@2448
   397
			case 'h':
yann@2448
   398
			case '?':
yann@2448
   399
				return 2;
yann@1
   400
			case 's':
yann@1
   401
			case 'y':
yann@1
   402
				return 3;
yann@1
   403
			case 'n':
yann@1
   404
				return 4;
yann@1
   405
			case 'm':
yann@1
   406
				return 5;
yann@1
   407
			case ' ':
yann@1
   408
				return 6;
yann@1
   409
			case '/':
yann@1
   410
				return 7;
yann@2448
   411
			case 'z':
yann@2448
   412
				return 8;
yann@2448
   413
			case '\n':
yann@2448
   414
				return button;
yann@1
   415
			}
yann@1
   416
			return 0;
yann@1
   417
		case 'e':
yann@1
   418
		case 'x':
yann@1
   419
			key = KEY_ESC;
yann@1
   420
			break;
yann@1
   421
		case KEY_ESC:
yann@1
   422
			key = on_key_esc(menu);
yann@1
   423
			break;
yann@1
   424
		case KEY_RESIZE:
yann@1
   425
			on_key_resize();
yann@1
   426
			delwin(menu);
yann@1
   427
			delwin(dialog);
yann@1
   428
			goto do_resize;
yann@1
   429
		}
yann@1
   430
	}
yann@1
   431
	delwin(menu);
yann@1
   432
	delwin(dialog);
yann@1
   433
	return key;		/* ESC pressed */
yann@1
   434
}