home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / scripts / kconfig / lxdialog / menubox.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  10.9 KB  |  435 lines

  1. /*
  2.  *  menubox.c -- implements the menu box
  3.  *
  4.  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
  5.  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
  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 (god@clifford.at)
  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 (mec@shout.net)
  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.             /* save scroll info */
  387.             *s_scroll = scroll;
  388.             delwin(menu);
  389.             delwin(dialog);
  390.             item_set(scroll + choice);
  391.             item_set_selected(1);
  392.             switch (key) {
  393.             case 's':
  394.                 return 3;
  395.             case 'y':
  396.                 return 3;
  397.             case 'n':
  398.                 return 4;
  399.             case 'm':
  400.                 return 5;
  401.             case ' ':
  402.                 return 6;
  403.             case '/':
  404.                 return 7;
  405.             }
  406.             return 0;
  407.         case 'h':
  408.         case '?':
  409.             button = 2;
  410.         case '\n':
  411.             *s_scroll = scroll;
  412.             delwin(menu);
  413.             delwin(dialog);
  414.             item_set(scroll + choice);
  415.             item_set_selected(1);
  416.             return button;
  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. }
  435.