1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/kconfig/lxdialog/menubox.c Wed Jul 11 15:31:51 2007 +0000
1.3 @@ -0,0 +1,434 @@
1.4 +/*
1.5 + * menubox.c -- implements the menu box
1.6 + *
1.7 + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
1.8 + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@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 +/*
1.26 + * Changes by Clifford Wolf (god@clifford.at)
1.27 + *
1.28 + * [ 1998-06-13 ]
1.29 + *
1.30 + * *) A bugfix for the Page-Down problem
1.31 + *
1.32 + * *) Formerly when I used Page Down and Page Up, the cursor would be set
1.33 + * to the first position in the menu box. Now lxdialog is a bit
1.34 + * smarter and works more like other menu systems (just have a look at
1.35 + * it).
1.36 + *
1.37 + * *) Formerly if I selected something my scrolling would be broken because
1.38 + * lxdialog is re-invoked by the Menuconfig shell script, can't
1.39 + * remember the last scrolling position, and just sets it so that the
1.40 + * cursor is at the bottom of the box. Now it writes the temporary file
1.41 + * lxdialog.scrltmp which contains this information. The file is
1.42 + * deleted by lxdialog if the user leaves a submenu or enters a new
1.43 + * one, but it would be nice if Menuconfig could make another "rm -f"
1.44 + * just to be sure. Just try it out - you will recognise a difference!
1.45 + *
1.46 + * [ 1998-06-14 ]
1.47 + *
1.48 + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
1.49 + * and menus change their size on the fly.
1.50 + *
1.51 + * *) If for some reason the last scrolling position is not saved by
1.52 + * lxdialog, it sets the scrolling so that the selected item is in the
1.53 + * middle of the menu box, not at the bottom.
1.54 + *
1.55 + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
1.56 + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
1.57 + * This fixes a bug in Menuconfig where using ' ' to descend into menus
1.58 + * would leave mis-synchronized lxdialog.scrltmp files lying around,
1.59 + * fscanf would read in 'scroll', and eventually that value would get used.
1.60 + */
1.61 +
1.62 +#include "dialog.h"
1.63 +
1.64 +static int menu_width, item_x;
1.65 +
1.66 +/*
1.67 + * Print menu item
1.68 + */
1.69 +static void do_print_item(WINDOW * win, const char *item, int line_y,
1.70 + int selected, int hotkey)
1.71 +{
1.72 + int j;
1.73 + char *menu_item = malloc(menu_width + 1);
1.74 +
1.75 + strncpy(menu_item, item, menu_width - item_x);
1.76 + menu_item[menu_width - item_x] = '\0';
1.77 + j = first_alpha(menu_item, "YyNnMmHh");
1.78 +
1.79 + /* Clear 'residue' of last item */
1.80 + wattrset(win, dlg.menubox.atr);
1.81 + wmove(win, line_y, 0);
1.82 +#if OLD_NCURSES
1.83 + {
1.84 + int i;
1.85 + for (i = 0; i < menu_width; i++)
1.86 + waddch(win, ' ');
1.87 + }
1.88 +#else
1.89 + wclrtoeol(win);
1.90 +#endif
1.91 + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
1.92 + mvwaddstr(win, line_y, item_x, menu_item);
1.93 + if (hotkey) {
1.94 + wattrset(win, selected ? dlg.tag_key_selected.atr
1.95 + : dlg.tag_key.atr);
1.96 + mvwaddch(win, line_y, item_x + j, menu_item[j]);
1.97 + }
1.98 + if (selected) {
1.99 + wmove(win, line_y, item_x + 1);
1.100 + }
1.101 + free(menu_item);
1.102 + wrefresh(win);
1.103 +}
1.104 +
1.105 +#define print_item(index, choice, selected) \
1.106 +do { \
1.107 + item_set(index); \
1.108 + do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
1.109 +} while (0)
1.110 +
1.111 +/*
1.112 + * Print the scroll indicators.
1.113 + */
1.114 +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
1.115 + int height)
1.116 +{
1.117 + int cur_y, cur_x;
1.118 +
1.119 + getyx(win, cur_y, cur_x);
1.120 +
1.121 + wmove(win, y, x);
1.122 +
1.123 + if (scroll > 0) {
1.124 + wattrset(win, dlg.uarrow.atr);
1.125 + waddch(win, ACS_UARROW);
1.126 + waddstr(win, "(-)");
1.127 + } else {
1.128 + wattrset(win, dlg.menubox.atr);
1.129 + waddch(win, ACS_HLINE);
1.130 + waddch(win, ACS_HLINE);
1.131 + waddch(win, ACS_HLINE);
1.132 + waddch(win, ACS_HLINE);
1.133 + }
1.134 +
1.135 + y = y + height + 1;
1.136 + wmove(win, y, x);
1.137 + wrefresh(win);
1.138 +
1.139 + if ((height < item_no) && (scroll + height < item_no)) {
1.140 + wattrset(win, dlg.darrow.atr);
1.141 + waddch(win, ACS_DARROW);
1.142 + waddstr(win, "(+)");
1.143 + } else {
1.144 + wattrset(win, dlg.menubox_border.atr);
1.145 + waddch(win, ACS_HLINE);
1.146 + waddch(win, ACS_HLINE);
1.147 + waddch(win, ACS_HLINE);
1.148 + waddch(win, ACS_HLINE);
1.149 + }
1.150 +
1.151 + wmove(win, cur_y, cur_x);
1.152 + wrefresh(win);
1.153 +}
1.154 +
1.155 +/*
1.156 + * Display the termination buttons.
1.157 + */
1.158 +static void print_buttons(WINDOW * win, int height, int width, int selected)
1.159 +{
1.160 + int x = width / 2 - 16;
1.161 + int y = height - 2;
1.162 +
1.163 + print_button(win, "Select", y, x, selected == 0);
1.164 + print_button(win, " Exit ", y, x + 12, selected == 1);
1.165 + print_button(win, " Help ", y, x + 24, selected == 2);
1.166 +
1.167 + wmove(win, y, x + 1 + 12 * selected);
1.168 + wrefresh(win);
1.169 +}
1.170 +
1.171 +/* scroll up n lines (n may be negative) */
1.172 +static void do_scroll(WINDOW *win, int *scroll, int n)
1.173 +{
1.174 + /* Scroll menu up */
1.175 + scrollok(win, TRUE);
1.176 + wscrl(win, n);
1.177 + scrollok(win, FALSE);
1.178 + *scroll = *scroll + n;
1.179 + wrefresh(win);
1.180 +}
1.181 +
1.182 +/*
1.183 + * Display a menu for choosing among a number of options
1.184 + */
1.185 +int dialog_menu(const char *title, const char *prompt,
1.186 + const void *selected, int *s_scroll)
1.187 +{
1.188 + int i, j, x, y, box_x, box_y;
1.189 + int height, width, menu_height;
1.190 + int key = 0, button = 0, scroll = 0, choice = 0;
1.191 + int first_item = 0, max_choice;
1.192 + WINDOW *dialog, *menu;
1.193 +
1.194 +do_resize:
1.195 + height = getmaxy(stdscr);
1.196 + width = getmaxx(stdscr);
1.197 + if (height < 15 || width < 65)
1.198 + return -ERRDISPLAYTOOSMALL;
1.199 +
1.200 + height -= 4;
1.201 + width -= 5;
1.202 + menu_height = height - 10;
1.203 +
1.204 + max_choice = MIN(menu_height, item_count());
1.205 +
1.206 + /* center dialog box on screen */
1.207 + x = (COLS - width) / 2;
1.208 + y = (LINES - height) / 2;
1.209 +
1.210 + draw_shadow(stdscr, y, x, height, width);
1.211 +
1.212 + dialog = newwin(height, width, y, x);
1.213 + keypad(dialog, TRUE);
1.214 +
1.215 + draw_box(dialog, 0, 0, height, width,
1.216 + dlg.dialog.atr, dlg.border.atr);
1.217 + wattrset(dialog, dlg.border.atr);
1.218 + mvwaddch(dialog, height - 3, 0, ACS_LTEE);
1.219 + for (i = 0; i < width - 2; i++)
1.220 + waddch(dialog, ACS_HLINE);
1.221 + wattrset(dialog, dlg.dialog.atr);
1.222 + wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
1.223 + waddch(dialog, ACS_RTEE);
1.224 +
1.225 + print_title(dialog, title, width);
1.226 +
1.227 + wattrset(dialog, dlg.dialog.atr);
1.228 + print_autowrap(dialog, prompt, width - 2, 1, 3);
1.229 +
1.230 + menu_width = width - 6;
1.231 + box_y = height - menu_height - 5;
1.232 + box_x = (width - menu_width) / 2 - 1;
1.233 +
1.234 + /* create new window for the menu */
1.235 + menu = subwin(dialog, menu_height, menu_width,
1.236 + y + box_y + 1, x + box_x + 1);
1.237 + keypad(menu, TRUE);
1.238 +
1.239 + /* draw a box around the menu items */
1.240 + draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
1.241 + dlg.menubox_border.atr, dlg.menubox.atr);
1.242 +
1.243 + if (menu_width >= 80)
1.244 + item_x = (menu_width - 70) / 2;
1.245 + else
1.246 + item_x = 4;
1.247 +
1.248 + /* Set choice to default item */
1.249 + item_foreach()
1.250 + if (selected && (selected == item_data()))
1.251 + choice = item_n();
1.252 + /* get the saved scroll info */
1.253 + scroll = *s_scroll;
1.254 + if ((scroll <= choice) && (scroll + max_choice > choice) &&
1.255 + (scroll >= 0) && (scroll + max_choice <= item_count())) {
1.256 + first_item = scroll;
1.257 + choice = choice - scroll;
1.258 + } else {
1.259 + scroll = 0;
1.260 + }
1.261 + if ((choice >= max_choice)) {
1.262 + if (choice >= item_count() - max_choice / 2)
1.263 + scroll = first_item = item_count() - max_choice;
1.264 + else
1.265 + scroll = first_item = choice - max_choice / 2;
1.266 + choice = choice - scroll;
1.267 + }
1.268 +
1.269 + /* Print the menu */
1.270 + for (i = 0; i < max_choice; i++) {
1.271 + print_item(first_item + i, i, i == choice);
1.272 + }
1.273 +
1.274 + wnoutrefresh(menu);
1.275 +
1.276 + print_arrows(dialog, item_count(), scroll,
1.277 + box_y, box_x + item_x + 1, menu_height);
1.278 +
1.279 + print_buttons(dialog, height, width, 0);
1.280 + wmove(menu, choice, item_x + 1);
1.281 + wrefresh(menu);
1.282 +
1.283 + while (key != KEY_ESC) {
1.284 + key = wgetch(menu);
1.285 +
1.286 + if (key < 256 && isalpha(key))
1.287 + key = tolower(key);
1.288 +
1.289 + if (strchr("ynmh", key))
1.290 + i = max_choice;
1.291 + else {
1.292 + for (i = choice + 1; i < max_choice; i++) {
1.293 + item_set(scroll + i);
1.294 + j = first_alpha(item_str(), "YyNnMmHh");
1.295 + if (key == tolower(item_str()[j]))
1.296 + break;
1.297 + }
1.298 + if (i == max_choice)
1.299 + for (i = 0; i < max_choice; i++) {
1.300 + item_set(scroll + i);
1.301 + j = first_alpha(item_str(), "YyNnMmHh");
1.302 + if (key == tolower(item_str()[j]))
1.303 + break;
1.304 + }
1.305 + }
1.306 +
1.307 + if (i < max_choice ||
1.308 + key == KEY_UP || key == KEY_DOWN ||
1.309 + key == '-' || key == '+' ||
1.310 + key == KEY_PPAGE || key == KEY_NPAGE) {
1.311 + /* Remove highligt of current item */
1.312 + print_item(scroll + choice, choice, FALSE);
1.313 +
1.314 + if (key == KEY_UP || key == '-') {
1.315 + if (choice < 2 && scroll) {
1.316 + /* Scroll menu down */
1.317 + do_scroll(menu, &scroll, -1);
1.318 +
1.319 + print_item(scroll, 0, FALSE);
1.320 + } else
1.321 + choice = MAX(choice - 1, 0);
1.322 +
1.323 + } else if (key == KEY_DOWN || key == '+') {
1.324 + print_item(scroll+choice, choice, FALSE);
1.325 +
1.326 + if ((choice > max_choice - 3) &&
1.327 + (scroll + max_choice < item_count())) {
1.328 + /* Scroll menu up */
1.329 + do_scroll(menu, &scroll, 1);
1.330 +
1.331 + print_item(scroll+max_choice - 1,
1.332 + max_choice - 1, FALSE);
1.333 + } else
1.334 + choice = MIN(choice + 1, max_choice - 1);
1.335 +
1.336 + } else if (key == KEY_PPAGE) {
1.337 + scrollok(menu, TRUE);
1.338 + for (i = 0; (i < max_choice); i++) {
1.339 + if (scroll > 0) {
1.340 + do_scroll(menu, &scroll, -1);
1.341 + print_item(scroll, 0, FALSE);
1.342 + } else {
1.343 + if (choice > 0)
1.344 + choice--;
1.345 + }
1.346 + }
1.347 +
1.348 + } else if (key == KEY_NPAGE) {
1.349 + for (i = 0; (i < max_choice); i++) {
1.350 + if (scroll + max_choice < item_count()) {
1.351 + do_scroll(menu, &scroll, 1);
1.352 + print_item(scroll+max_choice-1,
1.353 + max_choice - 1, FALSE);
1.354 + } else {
1.355 + if (choice + 1 < max_choice)
1.356 + choice++;
1.357 + }
1.358 + }
1.359 + } else
1.360 + choice = i;
1.361 +
1.362 + print_item(scroll + choice, choice, TRUE);
1.363 +
1.364 + print_arrows(dialog, item_count(), scroll,
1.365 + box_y, box_x + item_x + 1, menu_height);
1.366 +
1.367 + wnoutrefresh(dialog);
1.368 + wrefresh(menu);
1.369 +
1.370 + continue; /* wait for another key press */
1.371 + }
1.372 +
1.373 + switch (key) {
1.374 + case KEY_LEFT:
1.375 + case TAB:
1.376 + case KEY_RIGHT:
1.377 + button = ((key == KEY_LEFT ? --button : ++button) < 0)
1.378 + ? 2 : (button > 2 ? 0 : button);
1.379 +
1.380 + print_buttons(dialog, height, width, button);
1.381 + wrefresh(menu);
1.382 + break;
1.383 + case ' ':
1.384 + case 's':
1.385 + case 'y':
1.386 + case 'n':
1.387 + case 'm':
1.388 + case '/':
1.389 + /* save scroll info */
1.390 + *s_scroll = scroll;
1.391 + delwin(menu);
1.392 + delwin(dialog);
1.393 + item_set(scroll + choice);
1.394 + item_set_selected(1);
1.395 + switch (key) {
1.396 + case 's':
1.397 + return 3;
1.398 + case 'y':
1.399 + return 3;
1.400 + case 'n':
1.401 + return 4;
1.402 + case 'm':
1.403 + return 5;
1.404 + case ' ':
1.405 + return 6;
1.406 + case '/':
1.407 + return 7;
1.408 + }
1.409 + return 0;
1.410 + case 'h':
1.411 + case '?':
1.412 + button = 2;
1.413 + case '\n':
1.414 + *s_scroll = scroll;
1.415 + delwin(menu);
1.416 + delwin(dialog);
1.417 + item_set(scroll + choice);
1.418 + item_set_selected(1);
1.419 + return button;
1.420 + case 'e':
1.421 + case 'x':
1.422 + key = KEY_ESC;
1.423 + break;
1.424 + case KEY_ESC:
1.425 + key = on_key_esc(menu);
1.426 + break;
1.427 + case KEY_RESIZE:
1.428 + on_key_resize();
1.429 + delwin(menu);
1.430 + delwin(dialog);
1.431 + goto do_resize;
1.432 + }
1.433 + }
1.434 + delwin(menu);
1.435 + delwin(dialog);
1.436 + return key; /* ESC pressed */
1.437 +}