home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6 / scripts / kconfig / lxdialog / menubox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-21  |  10.9 KB  |  427 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 choice,
  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] = 0;
  74.     j = first_alpha(menu_item, "YyNnMmHh");
  75.  
  76.     /* Clear 'residue' of last item */
  77.     wattrset(win, menubox_attr);
  78.     wmove(win, choice, 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 ? item_selected_attr : item_attr);
  89.     mvwaddstr(win, choice, item_x, menu_item);
  90.     if (hotkey) {
  91.         wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
  92.         mvwaddch(win, choice, item_x + j, menu_item[j]);
  93.     }
  94.     if (selected) {
  95.         wmove(win, choice, item_x + 1);
  96.     }
  97.     free(menu_item);
  98.     wrefresh(win);
  99. }
  100.  
  101. #define print_item(index, choice, selected) \
  102. do {\
  103.     int hotkey = (items[(index) * 2][0] != ':'); \
  104.     do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
  105. } while (0)
  106.  
  107. /*
  108.  * Print the scroll indicators.
  109.  */
  110. static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
  111.              int height)
  112. {
  113.     int cur_y, cur_x;
  114.  
  115.     getyx(win, cur_y, cur_x);
  116.  
  117.     wmove(win, y, x);
  118.  
  119.     if (scroll > 0) {
  120.         wattrset(win, uarrow_attr);
  121.         waddch(win, ACS_UARROW);
  122.         waddstr(win, "(-)");
  123.     } else {
  124.         wattrset(win, menubox_attr);
  125.         waddch(win, ACS_HLINE);
  126.         waddch(win, ACS_HLINE);
  127.         waddch(win, ACS_HLINE);
  128.         waddch(win, ACS_HLINE);
  129.     }
  130.  
  131.     y = y + height + 1;
  132.     wmove(win, y, x);
  133.     wrefresh(win);
  134.  
  135.     if ((height < item_no) && (scroll + height < item_no)) {
  136.         wattrset(win, darrow_attr);
  137.         waddch(win, ACS_DARROW);
  138.         waddstr(win, "(+)");
  139.     } else {
  140.         wattrset(win, menubox_border_attr);
  141.         waddch(win, ACS_HLINE);
  142.         waddch(win, ACS_HLINE);
  143.         waddch(win, ACS_HLINE);
  144.         waddch(win, ACS_HLINE);
  145.     }
  146.  
  147.     wmove(win, cur_y, cur_x);
  148.     wrefresh(win);
  149. }
  150.  
  151. /*
  152.  * Display the termination buttons.
  153.  */
  154. static void print_buttons(WINDOW * win, int height, int width, int selected)
  155. {
  156.     int x = width / 2 - 16;
  157.     int y = height - 2;
  158.  
  159.     print_button(win, "Select", y, x, selected == 0);
  160.     print_button(win, " Exit ", y, x + 12, selected == 1);
  161.     print_button(win, " Help ", y, x + 24, selected == 2);
  162.  
  163.     wmove(win, y, x + 1 + 12 * selected);
  164.     wrefresh(win);
  165. }
  166.  
  167. /* scroll up n lines (n may be negative) */
  168. static void do_scroll(WINDOW *win, int *scroll, int n)
  169. {
  170.     /* Scroll menu up */
  171.     scrollok(win, TRUE);
  172.     wscrl(win, n);
  173.     scrollok(win, FALSE);
  174.     *scroll = *scroll + n;
  175.     wrefresh(win);
  176. }
  177.  
  178. /*
  179.  * Display a menu for choosing among a number of options
  180.  */
  181. int dialog_menu(const char *title, const char *prompt, int height, int width,
  182.                 int menu_height, const char *current, int item_no,
  183.                 const char *const *items)
  184. {
  185.     int i, j, x, y, box_x, box_y;
  186.     int key = 0, button = 0, scroll = 0, choice = 0;
  187.     int first_item =  0, max_choice;
  188.     WINDOW *dialog, *menu;
  189.     FILE *f;
  190.  
  191.     max_choice = MIN(menu_height, item_no);
  192.  
  193.     /* center dialog box on screen */
  194.     x = (COLS - width) / 2;
  195.     y = (LINES - height) / 2;
  196.  
  197.     draw_shadow(stdscr, y, x, height, width);
  198.  
  199.     dialog = newwin(height, width, y, x);
  200.     keypad(dialog, TRUE);
  201.  
  202.     draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
  203.     wattrset(dialog, border_attr);
  204.     mvwaddch(dialog, height - 3, 0, ACS_LTEE);
  205.     for (i = 0; i < width - 2; i++)
  206.         waddch(dialog, ACS_HLINE);
  207.     wattrset(dialog, dialog_attr);
  208.     wbkgdset(dialog, dialog_attr & A_COLOR);
  209.     waddch(dialog, ACS_RTEE);
  210.  
  211.     print_title(dialog, title, width);
  212.  
  213.     wattrset(dialog, dialog_attr);
  214.     print_autowrap(dialog, prompt, width - 2, 1, 3);
  215.  
  216.     menu_width = width - 6;
  217.     box_y = height - menu_height - 5;
  218.     box_x = (width - menu_width) / 2 - 1;
  219.  
  220.     /* create new window for the menu */
  221.     menu = subwin(dialog, menu_height, menu_width,
  222.               y + box_y + 1, x + box_x + 1);
  223.     keypad(menu, TRUE);
  224.  
  225.     /* draw a box around the menu items */
  226.     draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
  227.          menubox_border_attr, menubox_attr);
  228.  
  229.     item_x = (menu_width - 70) / 2;
  230.  
  231.     /* Set choice to default item */
  232.     for (i = 0; i < item_no; i++)
  233.         if (strcmp(current, items[i * 2]) == 0)
  234.             choice = i;
  235.  
  236.     /* get the scroll info from the temp file */
  237.     if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) {
  238.         if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) &&
  239.             (scroll + max_choice > choice) && (scroll >= 0) &&
  240.             (scroll + max_choice <= item_no)) {
  241.             first_item = scroll;
  242.             choice = choice - scroll;
  243.             fclose(f);
  244.         } else {
  245.             scroll = 0;
  246.             remove("lxdialog.scrltmp");
  247.             fclose(f);
  248.             f = NULL;
  249.         }
  250.     }
  251.     if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) {
  252.         if (choice >= item_no - max_choice / 2)
  253.             scroll = first_item = item_no - max_choice;
  254.         else
  255.             scroll = first_item = choice - max_choice / 2;
  256.         choice = choice - scroll;
  257.     }
  258.  
  259.     /* Print the menu */
  260.     for (i = 0; i < max_choice; i++) {
  261.         print_item(first_item + i, i, i == choice);
  262.     }
  263.  
  264.     wnoutrefresh(menu);
  265.  
  266.     print_arrows(dialog, item_no, scroll,
  267.              box_y, box_x + item_x + 1, menu_height);
  268.  
  269.     print_buttons(dialog, height, width, 0);
  270.     wmove(menu, choice, item_x + 1);
  271.     wrefresh(menu);
  272.  
  273.     while (key != ESC) {
  274.         key = wgetch(menu);
  275.  
  276.         if (key < 256 && isalpha(key))
  277.             key = tolower(key);
  278.  
  279.         if (strchr("ynmh", key))
  280.             i = max_choice;
  281.         else {
  282.             for (i = choice + 1; i < max_choice; i++) {
  283.                 j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh");
  284.                 if (key == tolower(items[(scroll + i) * 2 + 1][j]))
  285.                     break;
  286.             }
  287.             if (i == max_choice)
  288.                 for (i = 0; i < max_choice; i++) {
  289.                     j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh");
  290.                     if (key == tolower(items[(scroll + i) * 2 + 1][j]))
  291.                         break;
  292.                 }
  293.         }
  294.  
  295.         if (i < max_choice ||
  296.             key == KEY_UP || key == KEY_DOWN ||
  297.             key == '-' || key == '+' ||
  298.             key == KEY_PPAGE || key == KEY_NPAGE) {
  299.             /* Remove highligt of current item */
  300.             print_item(scroll + choice, choice, FALSE);
  301.  
  302.             if (key == KEY_UP || key == '-') {
  303.                 if (choice < 2 && scroll) {
  304.                     /* Scroll menu down */
  305.                     do_scroll(menu, &scroll, -1);
  306.  
  307.                     print_item(scroll, 0, FALSE);
  308.                 } else
  309.                     choice = MAX(choice - 1, 0);
  310.  
  311.             } else if (key == KEY_DOWN || key == '+') {
  312.                 print_item(scroll+choice, choice, FALSE);
  313.  
  314.                 if ((choice > max_choice - 3) &&
  315.                     (scroll + max_choice < item_no)) {
  316.                     /* Scroll menu up */
  317.                     do_scroll(menu, &scroll, 1);
  318.  
  319.                     print_item(scroll+max_choice - 1,
  320.                            max_choice - 1, FALSE);
  321.                 } else
  322.                     choice = MIN(choice + 1, max_choice - 1);
  323.  
  324.             } else if (key == KEY_PPAGE) {
  325.                 scrollok(menu, TRUE);
  326.                 for (i = 0; (i < max_choice); i++) {
  327.                     if (scroll > 0) {
  328.                         do_scroll(menu, &scroll, -1);
  329.                         print_item(scroll, 0, FALSE);
  330.                     } else {
  331.                         if (choice > 0)
  332.                             choice--;
  333.                     }
  334.                 }
  335.  
  336.             } else if (key == KEY_NPAGE) {
  337.                 for (i = 0; (i < max_choice); i++) {
  338.                     if (scroll + max_choice < item_no) {
  339.                         do_scroll(menu, &scroll, 1);
  340.                         print_item(scroll+max_choice-1,
  341.                                max_choice - 1, FALSE);
  342.                     } else {
  343.                         if (choice + 1 < max_choice)
  344.                             choice++;
  345.                     }
  346.                 }
  347.             } else
  348.                 choice = i;
  349.  
  350.             print_item(scroll + choice, choice, TRUE);
  351.  
  352.             print_arrows(dialog, item_no, scroll,
  353.                      box_y, box_x + item_x + 1, menu_height);
  354.  
  355.             wnoutrefresh(dialog);
  356.             wrefresh(menu);
  357.  
  358.             continue;    /* wait for another key press */
  359.         }
  360.  
  361.         switch (key) {
  362.         case KEY_LEFT:
  363.         case TAB:
  364.         case KEY_RIGHT:
  365.             button = ((key == KEY_LEFT ? --button : ++button) < 0)
  366.                 ? 2 : (button > 2 ? 0 : button);
  367.  
  368.             print_buttons(dialog, height, width, button);
  369.             wrefresh(menu);
  370.             break;
  371.         case ' ':
  372.         case 's':
  373.         case 'y':
  374.         case 'n':
  375.         case 'm':
  376.         case '/':
  377.             /* save scroll info */
  378.             if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
  379.                 fprintf(f, "%d\n", scroll);
  380.                 fclose(f);
  381.             }
  382.             delwin(dialog);
  383.             fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
  384.             switch (key) {
  385.             case 's':
  386.                 return 3;
  387.             case 'y':
  388.                 return 3;
  389.             case 'n':
  390.                 return 4;
  391.             case 'm':
  392.                 return 5;
  393.             case ' ':
  394.                 return 6;
  395.             case '/':
  396.                 return 7;
  397.             }
  398.             return 0;
  399.         case 'h':
  400.         case '?':
  401.             button = 2;
  402.         case '\n':
  403.             delwin(dialog);
  404.             if (button == 2)
  405.                 fprintf(stderr, "%s \"%s\"\n",
  406.                     items[(scroll + choice) * 2],
  407.                     items[(scroll + choice) * 2 + 1] +
  408.                     first_alpha(items [(scroll + choice) * 2 + 1], ""));
  409.             else
  410.                 fprintf(stderr, "%s\n",
  411.                     items[(scroll + choice) * 2]);
  412.  
  413.             remove("lxdialog.scrltmp");
  414.             return button;
  415.         case 'e':
  416.         case 'x':
  417.             key = ESC;
  418.         case ESC:
  419.             break;
  420.         }
  421.     }
  422.  
  423.     delwin(dialog);
  424.     remove("lxdialog.scrltmp");
  425.     return -1;        /* ESC pressed */
  426. }
  427.