Back to index

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