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