Back to index

tetex-bin  3.0
menubox.c
Go to the documentation of this file.
00001 /*
00002  *  menubox.c -- implements the menu box
00003  *
00004  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 
00022 #include "dialog.h"
00023 
00024 
00025 static void print_item(WINDOW *win, char *tag, char *item, int choice, int selected);
00026 
00027 
00028 static int menu_width, tag_x, item_x;
00029 
00030 
00031 /*
00032  * Display a menu for choosing among a number of options
00033  */
00034 int dialog_menu(char *title, char *prompt, int height, int width, int menu_height, int item_no, char **items)
00035 {
00036   int i, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0,
00037       scrolli = 0, max_choice;
00038   WINDOW *dialog, *menu;
00039 
00040   max_choice = MIN(menu_height, item_no);
00041 
00042   /* center dialog box on screen */
00043   x = (COLS - width)/2;
00044   y = (LINES - height)/2;
00045   
00046 #ifdef HAVE_NCURSES
00047   if (use_shadow)
00048     draw_shadow(stdscr, y, x, height, width);
00049 #endif
00050   dialog = newwin(height, width, y, x);
00051   keypad(dialog, TRUE);
00052 
00053   draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
00054   wattrset(dialog, border_attr);
00055   wmove(dialog, height-3, 0);
00056   waddch(dialog, ACS_LTEE);
00057   for (i = 0; i < width-2; i++)
00058     waddch(dialog, ACS_HLINE);
00059   wattrset(dialog, dialog_attr);
00060   waddch(dialog, ACS_RTEE);
00061   wmove(dialog, height-2, 1);
00062   for (i = 0; i < width-2; i++)
00063     waddch(dialog, ' ');
00064 
00065   if (title != NULL) {
00066     wattrset(dialog, title_attr);
00067     wmove(dialog, 0, (width - strlen(title))/2 - 1);
00068     waddch(dialog, ' ');
00069     waddstr(dialog, title);
00070     waddch(dialog, ' ');
00071   }
00072   wattrset(dialog, dialog_attr);
00073   print_autowrap(dialog, prompt, width, 1, 3);
00074 
00075   menu_width = width-6;
00076   getyx(dialog, cur_y, cur_x);
00077   box_y = cur_y + 1;
00078   box_x = (width - menu_width)/2 - 1;
00079 
00080   /* create new window for the menu */
00081   menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
00082   keypad(menu, TRUE);
00083 
00084   /* draw a box around the menu items */
00085   draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr);
00086 
00087   tag_x = 0;
00088   item_x = 0;
00089   /* Find length of longest item in order to center menu */
00090   for (i = 0; i < item_no; i++) {
00091     tag_x = MAX(tag_x, strlen(items[i*2]) + strlen(items[i*2 + 1]) + 2);
00092     item_x = MAX(item_x, strlen(items[i*2]));
00093   }
00094   tag_x = (menu_width - tag_x) / 2;
00095   item_x = tag_x + item_x + 2;
00096 
00097   /* Print the menu */
00098   for (i = 0; i < max_choice; i++)
00099     print_item(menu, items[i*2], items[i*2 + 1], i, i == choice);
00100   wnoutrefresh(menu);
00101 
00102   if (menu_height < item_no) {
00103     wattrset(dialog, darrow_attr);
00104     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
00105     waddch(dialog, ACS_DARROW);
00106     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
00107     waddstr(dialog,"(+)");
00108   }
00109 
00110   x = width/2-11;
00111   y = height-2;
00112   print_button(dialog, "Cancel", y, x+14, FALSE);
00113   print_button(dialog, "  OK  ", y, x, TRUE);
00114   wrefresh(dialog);
00115 
00116   while (key != ESC) {
00117     key = wgetch(dialog);
00118     /* Check if key pressed matches first character of any item tag in menu */
00119     for (i = 0; i < max_choice; i++)
00120       if (toupper(key) == toupper(items[(scrolli+i)*2][0]))
00121         break;
00122 /*    i = (choice+scrolli+1) % max_choice ;
00123     while (i != choice+scrolli) {
00124       if (toupper(key) == toupper(items[i*2][0]))
00125          break;
00126       i = (i + 1) % max_choice;
00127     }
00128     */
00129 
00130     if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || 
00131         key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') {
00132       if (key >= '1' && key <= MIN('9', '0'+max_choice))
00133         i = key - '1';
00134       else if (key == KEY_UP || key == '-') {
00135         if (!choice) {
00136           if (scrolli) {
00137 #ifdef BROKEN_WSCRL
00138     /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
00139        violation when scrolling windows of height = 4, so scrolling is not
00140        used for now */
00141             scrolli--;
00142             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00143             /* Reprint menu to scroll down */
00144             for (i = 0; i < max_choice; i++)
00145               print_item(menu, items[(scrolli+i)*2], items[(scrolli+i)*2 + 1], i, i == choice);
00146 
00147 #else
00148 
00149             /* Scroll menu down */
00150             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00151             if (menu_height > 1) {
00152               /* De-highlight current first item before scrolling down */
00153               print_item(menu, items[scrolli*2], items[scrolli*2 + 1], 0, FALSE);
00154               scrollok(menu, TRUE);
00155               wscrl(menu, -1);
00156               scrollok(menu, FALSE);
00157             }
00158             scrolli--;
00159             print_item(menu, items[scrolli*2], items[scrolli*2 + 1], 0, TRUE);
00160 #endif
00161             wnoutrefresh(menu);
00162 
00163             /* print the up/down arrows */
00164             wmove(dialog, box_y, box_x + tag_x + 1);
00165             wattrset(dialog, scrolli ? uarrow_attr : menubox_attr);
00166             waddch(dialog, scrolli ? ACS_UARROW : ACS_HLINE);
00167             wmove(dialog, box_y, box_x + tag_x + 2);
00168             waddch(dialog, scrolli ? '(' : ACS_HLINE);
00169             wmove(dialog, box_y, box_x + tag_x + 3);
00170             waddch(dialog, scrolli ? '-' : ACS_HLINE);
00171             wmove(dialog, box_y, box_x + tag_x + 4);
00172             waddch(dialog, scrolli ? ')' : ACS_HLINE);
00173             wattrset(dialog, darrow_attr);
00174             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
00175             waddch(dialog, ACS_DARROW);
00176             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
00177             waddstr(dialog,"(+)");
00178             wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
00179             wrefresh(dialog);
00180           }
00181           continue;    /* wait for another key press */
00182         }
00183         else
00184           i = choice - 1;
00185       }
00186       else if (key == KEY_DOWN || key == '+')
00187         if (choice == max_choice - 1) {
00188           if (scrolli+choice < item_no-1) {
00189 #ifdef BROKEN_WSCRL
00190     /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
00191        violation when scrolling windows of height = 4, so scrolling is not
00192        used for now */
00193             scrolli++;
00194             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00195             /* Reprint menu to scroll up */
00196             for (i = 0; i < max_choice; i++)
00197               print_item(menu, items[(scrolli+i)*2], items[(scrolli+i)*2 + 1], i, i == choice);
00198 
00199 #else
00200 
00201             /* Scroll menu up */
00202             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00203             if (menu_height > 1) {
00204               /* De-highlight current last item before scrolling up */
00205               print_item(menu, items[(scrolli+max_choice-1)*2], items[(scrolli+max_choice-1)*2 + 1], max_choice-1, FALSE);
00206               scrollok(menu, TRUE);
00207               scroll(menu);
00208               scrollok(menu, FALSE);
00209             }
00210             scrolli++;
00211               print_item(menu, items[(scrolli+max_choice-1)*2], items[(scrolli+max_choice-1)*2 + 1], max_choice-1, TRUE);
00212 #endif
00213             wnoutrefresh(menu);
00214 
00215             /* print the up/down arrows */
00216             wattrset(dialog, uarrow_attr);
00217             wmove(dialog, box_y, box_x + tag_x + 1);
00218             waddch(dialog, ACS_UARROW);
00219             wmove(dialog, box_y, box_x + tag_x + 2);
00220             waddstr(dialog,"(-)");
00221             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
00222             wattrset(dialog, scrolli+choice < item_no-1 ? darrow_attr : menubox_border_attr);
00223             waddch(dialog, scrolli+choice < item_no-1 ? ACS_DARROW : ACS_HLINE);
00224             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
00225             waddch(dialog, scrolli+choice < item_no-1 ? '(' : ACS_HLINE);
00226             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 3);
00227             waddch(dialog, scrolli+choice < item_no-1 ? '+' : ACS_HLINE);
00228             wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 4);
00229             waddch(dialog, scrolli+choice < item_no-1 ? ')' : ACS_HLINE);
00230             wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
00231             wrefresh(dialog);
00232           }
00233           continue;    /* wait for another key press */
00234         }
00235         else
00236           i = choice + 1;
00237 
00238       if (i != choice) {
00239         /* De-highlight current item */
00240         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00241         print_item(menu, items[(scrolli+choice)*2], items[(scrolli+choice)*2 + 1], choice, FALSE);
00242 
00243         /* Highlight new item */
00244         choice = i;
00245         print_item(menu, items[(scrolli+choice)*2], items[(scrolli+choice)*2 + 1], choice, TRUE);
00246         wnoutrefresh(menu);
00247         wmove(dialog, cur_y, cur_x);  /* Restore cursor to previous position */
00248         wrefresh(dialog);
00249       }
00250       continue;    /* wait for another key press */
00251     }
00252 
00253     switch (key) {
00254       case 'O':
00255       case 'o':
00256         delwin(dialog);
00257         fprintf(stderr, items[(scrolli+choice)*2]);
00258         return 0;
00259       case 'C':
00260       case 'c':
00261         delwin(dialog);
00262         return 1;
00263       case TAB:
00264       case KEY_LEFT:
00265       case KEY_RIGHT:
00266         if (!button) {
00267           button = 1;    /* Indicates "Cancel" button is selected */
00268           print_button(dialog, "  OK  ", y, x, FALSE);
00269           print_button(dialog, "Cancel", y, x+14, TRUE);
00270         }
00271         else {
00272           button = 0;    /* Indicates "OK" button is selected */
00273           print_button(dialog, "Cancel", y, x+14, FALSE);
00274           print_button(dialog, "  OK  ", y, x, TRUE);
00275         }
00276         wrefresh(dialog);
00277         break;
00278       case ' ':
00279       case '\n':
00280         delwin(dialog);
00281         if (!button)
00282           fprintf(stderr, items[(scrolli+choice)*2]);
00283         return button;
00284       case ESC:
00285         break;
00286     }
00287   }
00288 
00289   delwin(dialog);
00290   return -1;    /* ESC pressed */
00291 }
00292 /* End of dialog_menu() */
00293 
00294 
00295 /*
00296  * Print menu item
00297  */
00298 static void print_item(WINDOW *win, char *tag, char *item, int choice, int selected)
00299 {
00300   int i;
00301 
00302   /* Clear 'residue' of last item */
00303   wattrset(win, menubox_attr);
00304   wmove(win, choice, 0);
00305   for (i = 0; i < menu_width; i++)
00306     waddch(win, ' ');
00307   wmove(win, choice, tag_x);
00308   wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
00309   waddch(win, tag[0]);
00310   wattrset(win, selected ? tag_selected_attr : tag_attr);
00311   waddstr(win, tag + 1);
00312   wmove(win, choice, item_x);
00313   wattrset(win, selected ? item_selected_attr : item_attr);
00314   waddstr(win, item);
00315 }
00316 /* End of print_item() */