kconfig/lxdialog/menubox.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Aug 23 21:11:26 2011 +0200 (2011-08-23)
changeset 2891 f176fee535a0
parent 943 1cca90ce0481
permissions -rw-r--r--
cc/gcc: add 'cflags' paramater to the core backend

As the core backend is used to generate the bare-metal compiler,
we need to pass it the host CFLAGS.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
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
}