Back to index

tetex-bin  3.0
checklist.c
Go to the documentation of this file.
00001 /*
00002  *  checklist.c -- implements the checklist 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 status, int choice, int selected);
00026 
00027 
00028 static int list_width, check_x, item_x;
00029 
00030 
00031 /*
00032  * Display a dialog box with a list of options that can be turned on or off
00033  */
00034 int dialog_checklist(char *title, char *prompt, int height, int width, int list_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, *status;
00038   WINDOW *dialog, *list;
00039 
00040   /* Allocate space for storing item on/off status */
00041   if ((status = malloc(sizeof(int)*item_no)) == NULL) {
00042     endwin();
00043     fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n");
00044     exit(-1);
00045   }
00046   /* Initializes status */
00047   for (i = 0; i < item_no; i++)
00048     status[i] = !strcasecmp(items[i*3 + 2], "on");
00049 
00050   max_choice = MIN(list_height, item_no);
00051 
00052   /* center dialog box on screen */
00053   x = (COLS - width)/2;
00054   y = (LINES - height)/2;
00055   
00056 #ifdef HAVE_NCURSES
00057   if (use_shadow)
00058     draw_shadow(stdscr, y, x, height, width);
00059 #endif
00060   dialog = newwin(height, width, y, x);
00061   keypad(dialog, TRUE);
00062 
00063   draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
00064   wattrset(dialog, border_attr);
00065   wmove(dialog, height-3, 0);
00066   waddch(dialog, ACS_LTEE);
00067   for (i = 0; i < width-2; i++)
00068     waddch(dialog, ACS_HLINE);
00069   wattrset(dialog, dialog_attr);
00070   waddch(dialog, ACS_RTEE);
00071   wmove(dialog, height-2, 1);
00072   for (i = 0; i < width-2; i++)
00073     waddch(dialog, ' ');
00074 
00075   if (title != NULL) {
00076     wattrset(dialog, title_attr);
00077     wmove(dialog, 0, (width - strlen(title))/2 - 1);
00078     waddch(dialog, ' ');
00079     waddstr(dialog, title);
00080     waddch(dialog, ' ');
00081   }
00082   wattrset(dialog, dialog_attr);
00083   print_autowrap(dialog, prompt, width, 1, 3);
00084 
00085   list_width = width-6;
00086   getyx(dialog, cur_y, cur_x);
00087   box_y = cur_y + 1;
00088   box_x = (width - list_width)/2 - 1;
00089 
00090   /* create new window for the list */
00091   list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1);
00092   keypad(list, TRUE);
00093 
00094   /* draw a box around the list items */
00095   draw_box(dialog, box_y, box_x, list_height+2, list_width+2, menubox_border_attr, menubox_attr);
00096 
00097   check_x = 0;
00098   item_x = 0;
00099   /* Find length of longest item in order to center checklist */
00100   for (i = 0; i < item_no; i++) {
00101     check_x = MAX(check_x, strlen(items[i*3]) + strlen(items[i*3 + 1]) + 6);
00102     item_x = MAX(item_x, strlen(items[i*3]));
00103   }
00104   check_x = (list_width - check_x) / 2;
00105   item_x = check_x + item_x + 6;
00106 
00107   /* Print the list */
00108   for (i = 0; i < max_choice; i++)
00109     print_item(list, items[i*3], items[i*3 + 1], status[i], i, i == choice);
00110   wnoutrefresh(list);
00111 
00112   if (list_height < item_no) {
00113     wattrset(dialog, darrow_attr);
00114     wmove(dialog, box_y + list_height + 1, box_x + check_x + 5);
00115     waddch(dialog, ACS_DARROW);
00116     wmove(dialog, box_y + list_height + 1, box_x + check_x + 6);
00117     waddstr(dialog, "(+)");
00118   }
00119 
00120   x = width/2-11;
00121   y = height-2;
00122   print_button(dialog, "Cancel", y, x+14, FALSE);
00123   print_button(dialog, "  OK  ", y, x, TRUE);
00124   wrefresh(dialog);
00125 
00126   while (key != ESC) {
00127     key = wgetch(dialog);
00128     /* Check if key pressed matches first character of any item tag in list */
00129     for (i = 0; i < max_choice; i++)
00130       if (toupper(key) == toupper(items[(scrolli+i)*3][0]))
00131         break;
00132 
00133     if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || 
00134         key == KEY_UP || key == KEY_DOWN || key == ' ' ||
00135         key == '+' || key == '-' ) {
00136       if (key >= '1' && key <= MIN('9', '0'+max_choice))
00137         i = key - '1';
00138       else if (key == KEY_UP || key == '-') {
00139         if (!choice) {
00140           if (scrolli) {
00141 #ifdef BROKEN_WSCRL
00142     /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
00143        violation when scrolling windows of height = 4, so scrolling is not
00144        used for now */
00145             scrolli--;
00146             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00147             /* Reprint list to scroll down */
00148             for (i = 0; i < max_choice; i++)
00149               print_item(list, items[(scrolli+i)*3], items[(scrolli+i)*3 + 1], status[scrolli+i], i, i == choice);
00150 
00151 #else
00152 
00153             /* Scroll list down */
00154             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00155             if (list_height > 1) {
00156               /* De-highlight current first item before scrolling down */
00157               print_item(list, items[scrolli*3], items[scrolli*3 + 1], status[scrolli], 0, FALSE);
00158               scrollok(list, TRUE);
00159               wscrl(list, -1);
00160               scrollok(list, FALSE);
00161             }
00162             scrolli--;
00163             print_item(list, items[scrolli*3], items[scrolli*3 + 1], status[scrolli], 0, TRUE);
00164 #endif
00165             wnoutrefresh(list);
00166 
00167             /* print the up/down arrows */
00168             wmove(dialog, box_y, box_x + check_x + 5);
00169             wattrset(dialog, scrolli ? uarrow_attr : menubox_attr);
00170             waddch(dialog, scrolli ? ACS_UARROW : ACS_HLINE);
00171             wmove(dialog, box_y, box_x + check_x + 6);
00172             waddch(dialog, scrolli ? '(' : ACS_HLINE);
00173             wmove(dialog, box_y, box_x + check_x + 7);
00174             waddch(dialog, scrolli ? '-' : ACS_HLINE);
00175             wmove(dialog, box_y, box_x + check_x + 8);
00176             waddch(dialog, scrolli ? ')' : ACS_HLINE);
00177             wattrset(dialog, darrow_attr);
00178             wmove(dialog, box_y + list_height + 1, box_x + check_x + 5);
00179             waddch(dialog, ACS_DARROW);
00180             wmove(dialog, box_y + list_height + 1, box_x + check_x + 6);
00181             waddch(dialog, '(');
00182             wmove(dialog, box_y + list_height + 1, box_x + check_x + 7);
00183             waddch(dialog, '+');
00184             wmove(dialog, box_y + list_height + 1, box_x + check_x + 8);
00185             waddch(dialog, ')');
00186             wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
00187             wrefresh(dialog);
00188           }
00189           continue;    /* wait for another key press */
00190         }
00191         else
00192           i = choice - 1;
00193       }
00194       else if (key == KEY_DOWN || key == '+') {
00195         if (choice == max_choice - 1) {
00196           if (scrolli+choice < item_no-1) {
00197 #ifdef BROKEN_WSCRL
00198     /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
00199        violation when scrolling windows of height = 4, so scrolling is not
00200        used for now */
00201             scrolli++;
00202             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00203             /* Reprint list to scroll up */
00204             for (i = 0; i < max_choice; i++)
00205               print_item(list, items[(scrolli+i)*3], items[(scrolli+i)*3 + 1], status[scrolli+i], i, i == choice);
00206 
00207 #else
00208 
00209             /* Scroll list up */
00210             getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00211             if (list_height > 1) {
00212               /* De-highlight current last item before scrolling up */
00213               print_item(list, items[(scrolli+max_choice-1)*3], items[(scrolli+max_choice-1)*3 + 1], status[scrolli+max_choice-1], max_choice-1, FALSE);
00214               scrollok(list, TRUE);
00215               scroll(list);
00216               scrollok(list, FALSE);
00217             }
00218             scrolli++;
00219             print_item(list, items[(scrolli+max_choice-1)*3], items[(scrolli+max_choice-1)*3 + 1], status[scrolli+max_choice-1], max_choice-1, TRUE);
00220 #endif
00221             wnoutrefresh(list);
00222 
00223             /* print the up/down arrows */
00224             wattrset(dialog, uarrow_attr);
00225             wmove(dialog, box_y, box_x + check_x + 5);
00226             waddch(dialog, ACS_UARROW);
00227             wmove(dialog, box_y, box_x + check_x + 6);
00228             waddstr(dialog, "(-)");
00229             wmove(dialog, box_y + list_height + 1, box_x + check_x + 5);
00230             wattrset(dialog, scrolli+choice < item_no-1 ? darrow_attr : menubox_border_attr);
00231             waddch(dialog, scrolli+choice < item_no-1 ? ACS_DARROW : ACS_HLINE);
00232             wmove(dialog, box_y + list_height + 1, box_x + check_x + 6);
00233             waddch(dialog, scrolli+choice < item_no-1 ? '(' : ACS_HLINE);
00234             wmove(dialog, box_y + list_height + 1, box_x + check_x + 7);
00235             waddch(dialog, scrolli+choice < item_no-1 ? '+' : ACS_HLINE);
00236             wmove(dialog, box_y + list_height + 1, box_x + check_x + 8);
00237             waddch(dialog, scrolli+choice < item_no-1 ? ')' : ACS_HLINE);
00238             wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
00239             wrefresh(dialog);
00240           }
00241           continue;    /* wait for another key press */
00242         }
00243         else
00244           i = choice + 1;
00245       }
00246       else if (key == ' ') {    /* Toggle item status */
00247         status[scrolli+choice] = !status[scrolli+choice];
00248         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00249         wmove(list, choice, check_x);
00250         wattrset(list, check_selected_attr);
00251         wprintw(list, "[%c]", status[scrolli+choice] ? 'X' : ' ');
00252         wnoutrefresh(list);
00253         wmove(dialog, cur_y, cur_x);  /* Restore cursor to previous position */
00254         wrefresh(dialog);
00255         continue;    /* wait for another key press */
00256       }
00257 
00258       if (i != choice) {
00259         /* De-highlight current item */
00260         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
00261         print_item(list, items[(scrolli+choice)*3], items[(scrolli+choice)*3 + 1], status[scrolli+choice], choice, FALSE);
00262 
00263         /* Highlight new item */
00264         choice = i;
00265         print_item(list, items[(scrolli+choice)*3], items[(scrolli+choice)*3 + 1], status[scrolli+choice], choice, TRUE);
00266         wnoutrefresh(list);
00267         wmove(dialog, cur_y, cur_x);  /* Restore cursor to previous position */
00268         wrefresh(dialog);
00269       }
00270       continue;    /* wait for another key press */
00271     }
00272 
00273     switch (key) {
00274       case 'O':
00275       case 'o':
00276         delwin(dialog);
00277         for (i = 0; i < item_no; i++)
00278            if (status[i]) {
00279               if (separate_output) {
00280                   fprintf(stderr, "%s\n", items[i*3]);
00281               } else {
00282                   fprintf(stderr, "\"%s\" ", items[i*3]);
00283               }
00284            }
00285         free(status);
00286         return 0;
00287       case 'C':
00288       case 'c':
00289         delwin(dialog);
00290         free(status);
00291         return 1;
00292       case TAB:
00293       case KEY_LEFT:
00294       case KEY_RIGHT:
00295         if (!button) {
00296           button = 1;    /* Indicates "Cancel" button is selected */
00297           print_button(dialog, "  OK  ", y, x, FALSE);
00298           print_button(dialog, "Cancel", y, x+14, TRUE);
00299         }
00300         else {
00301           button = 0;    /* Indicates "OK" button is selected */
00302           print_button(dialog, "Cancel", y, x+14, FALSE);
00303           print_button(dialog, "  OK  ", y, x, TRUE);
00304         }
00305         wrefresh(dialog);
00306         break;
00307       case ' ':
00308       case '\n':
00309         delwin(dialog);
00310         if (!button)
00311           for (i = 0; i < item_no; i++)
00312              if (status[i]) {
00313                 if (separate_output) {
00314                     fprintf(stderr, "%s\n", items[i*3]);
00315                 } else {
00316                     fprintf(stderr, "\"%s\" ", items[i*3]);
00317                 }
00318              }
00319         free(status);
00320         return button;
00321       case ESC:
00322         break;
00323     }
00324   }
00325 
00326   delwin(dialog);
00327   free(status);
00328   return -1;    /* ESC pressed */
00329 }
00330 /* End of dialog_checklist() */
00331 
00332 
00333 /*
00334  * Print list item
00335  */
00336 static void print_item(WINDOW *win, char *tag, char *item, int status, int choice, int selected)
00337 {
00338   int i;
00339 
00340   /* Clear 'residue' of last item */
00341   wattrset(win, menubox_attr);
00342   wmove(win, choice, 0);
00343   for (i = 0; i < list_width; i++)
00344     waddch(win, ' ');
00345   wmove(win, choice, check_x);
00346   wattrset(win, selected ? check_selected_attr : check_attr);
00347   wprintw(win, "[%c]", status ? 'X' : ' ');
00348   wattrset(win, menubox_attr);
00349   waddch(win, ' ');
00350   wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
00351   waddch(win, tag[0]);
00352   wattrset(win, selected ? tag_selected_attr : tag_attr);
00353   waddstr(win, tag + 1);
00354   wmove(win, choice, item_x);
00355   wattrset(win, selected ? item_selected_attr : item_attr);
00356   waddstr(win, item);
00357 }
00358 /* End of print_item() */