Remove kerberosIV from the build.
[dragonfly.git] / gnu / lib / libdialog / checklist.c
1 /*
2  *  checklist.c -- implements the checklist box
3  *
4  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5  *
6  *      Substantial rennovation:  12/18/95, Jordan K. Hubbard
7  *
8  *  This program is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU General Public License
10  *  as published by the Free Software Foundation; either version 2
11  *  of the License, or (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $FreeBSD: src/gnu/lib/libdialog/checklist.c,v 1.35.2.2 2001/08/31 03:04:59 eric Exp $
23  * $DragonFly: src/gnu/lib/libdialog/checklist.c,v 1.2 2003/06/17 04:25:43 dillon Exp $
24  */
25
26 #include <dialog.h>
27 #include "dialog.priv.h"
28
29
30 static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected, dialogMenuItem *me, int list_width, int item_x, int check_x);
31
32 #define DREF(di, item)          ((di) ? &((di)[(item)]) : NULL)
33
34 /*
35  * Display a dialog box with a list of options that can be turned on or off
36  */
37 int
38 dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width,
39                  int list_height, int cnt, void *it, unsigned char *result)
40 {
41     int i, j, x, y, cur_x, cur_y, old_x, old_y, box_x, box_y, key = 0, button,
42         choice, l, k, scroll, max_choice, item_no = 0, *status;
43     int redraw_menu = FALSE, cursor_reset = FALSE;
44     int rval = 0, onlist = 1, ok_space, cancel_space;
45     char okButton, cancelButton;
46     WINDOW *dialog, *list;
47     unsigned char **items = NULL;
48     dialogMenuItem *ditems;
49     int list_width, check_x, item_x;
50
51     /* Allocate space for storing item on/off status */
52     if ((status = alloca(sizeof(int) * abs(cnt))) == NULL) {
53         endwin();
54         fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n");
55         exit(-1);
56     }
57     
58 draw:
59     choice = scroll = button = 0;
60     /* Previous calling syntax, e.g. just a list of strings? */
61     if (cnt >= 0) {
62         items = it;
63         ditems = NULL;
64         item_no = cnt;
65         /* Initializes status */
66         for (i = 0; i < item_no; i++)
67             status[i] = !strcasecmp(items[i*3 + 2], "on");
68     }
69     /* It's the new specification format - fake the rest of the code out */
70     else {
71         item_no = abs(cnt);
72         ditems = it;
73         if (!items)
74             items = (unsigned char **)alloca((item_no * 3) * sizeof(unsigned char *));
75         
76         /* Initializes status */
77         for (i = 0; i < item_no; i++) {
78             status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
79             items[i*3] = ditems[i].prompt;
80             items[i*3 + 1] = ditems[i].title;
81             items[i*3 + 2] = status[i] ? "on" : "off";
82         }
83     }
84     max_choice = MIN(list_height, item_no);
85     
86     check_x = 0;
87     item_x = 0;
88     /* Find length of longest item in order to center checklist */
89     for (i = 0; i < item_no; i++) {
90         l = strlen(items[i*3]);
91         for (j = 0; j < item_no; j++) {
92             k = strlen(items[j*3 + 1]);
93             check_x = MAX(check_x, l + k + 6);
94         }
95         item_x = MAX(item_x, l);
96     }
97     if (height < 0)
98         height = strheight(prompt)+list_height+4+2;
99     if (width < 0) {
100         i = strwidth(prompt);
101         j = ((title != NULL) ? strwidth(title) : 0);
102         width = MAX(i,j);
103         width = MAX(width,check_x+4)+4;
104     }
105     width = MAX(width,24);
106     
107     if (width > COLS)
108         width = COLS;
109     if (height > LINES)
110         height = LINES;
111     /* center dialog box on screen */
112     x = (COLS - width)/2;
113     y = (LINES - height)/2;
114
115 #ifdef HAVE_NCURSES
116     if (use_shadow)
117         draw_shadow(stdscr, y, x, height, width);
118 #endif
119     dialog = newwin(height, width, y, x);
120     if (dialog == NULL) {
121         endwin();
122         fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width, y, x);
123         return -1;
124     }
125     keypad(dialog, TRUE);
126     
127     draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
128     wattrset(dialog, border_attr);
129     wmove(dialog, height-3, 0);
130     waddch(dialog, ACS_LTEE);
131     for (i = 0; i < width-2; i++)
132         waddch(dialog, ACS_HLINE);
133     wattrset(dialog, dialog_attr);
134     waddch(dialog, ACS_RTEE);
135     wmove(dialog, height-2, 1);
136     for (i = 0; i < width-2; i++)
137         waddch(dialog, ' ');
138     
139     if (title != NULL) {
140         wattrset(dialog, title_attr);
141         wmove(dialog, 0, (width - strlen(title))/2 - 1);
142         waddch(dialog, ' ');
143         waddstr(dialog, title);
144         waddch(dialog, ' ');
145     }
146     wattrset(dialog, dialog_attr);
147     wmove(dialog, 1, 2);
148     print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE);
149     
150     list_width = width - 6;
151     getyx(dialog, cur_y, cur_x);
152     box_y = cur_y + 1;
153     box_x = (width - list_width) / 2 - 1;
154     
155     /* create new window for the list */
156     list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1);
157     if (list == NULL) {
158         delwin(dialog);
159         endwin();
160         fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height, list_width,
161                 y + box_y + 1, x + box_x + 1);
162         return -1;
163     }
164     keypad(list, TRUE);
165     
166     /* draw a box around the list items */
167     draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);
168     
169     check_x = (list_width - check_x) / 2;
170     item_x = check_x + item_x + 6;
171     
172     /* Print the list */
173     for (i = 0; i < max_choice; i++)
174         print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x);
175     wnoutrefresh(list);
176     print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
177     
178     display_helpline(dialog, height - 1, width);
179     
180     x = width / 2 - 11;
181     y = height - 2;
182     /* Is this a fancy new style argument string where we get to override
183      * the buttons, or an old style one where they're fixed?
184      */
185     if (ditems && result) {
186         cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]);
187         print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE);
188         okButton = toupper(ditems[OK_BUTTON].prompt[0]);
189         print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE);
190     }
191     else {
192         cancelButton = 'C';
193         print_button(dialog, "Cancel", y, x + 14, FALSE);
194         okButton = 'O';
195         print_button(dialog, "  OK  ", y, x, TRUE);
196     }
197     wnoutrefresh(dialog);
198     wmove(list, choice, check_x+1);
199     wrefresh(list);
200     
201     while (key != ESC) {
202         key = wgetch(dialog);
203         
204         /* Shortcut to OK? */
205         if (toupper(key) == okButton) {
206             if (ditems) {
207                 if (result && ditems[OK_BUTTON].fire) {
208                     int st;
209                     WINDOW *save;
210
211                     save = dupwin(newscr);
212                     st = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]);
213                     if (st & DITEM_RESTORE) {
214                         touchwin(save);
215                         wrefresh(save);
216                     }
217                     delwin(save);
218                 }
219             }
220             else if (result) {
221                 *result = '\0';
222                 for (i = 0; i < item_no; i++) {
223                     if (status[i]) {
224                         strcat(result, items[i*3]);
225                         strcat(result, "\n");
226                     }
227                 }
228             }
229             rval = 0;
230             key = ESC;  /* Lemme out! */
231             break;
232         }
233
234         /* Shortcut to cancel? */
235         if (toupper(key) == cancelButton) {
236             if (ditems && result && ditems[CANCEL_BUTTON].fire) {
237                 int st;
238                 WINDOW *save;
239
240                 save = dupwin(newscr);
241                 st = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]);
242                 if (st & DITEM_RESTORE) {
243                     touchwin(save);
244                     wrefresh(save);
245                     wmove(dialog, cur_y, cur_x);
246                 }
247                 delwin(save);
248             }
249             rval = 1;
250             key = ESC;  /* I gotta go! */
251             break;
252         }
253         
254         /* Check if key pressed matches first character of any item tag in list */
255         for (i = 0; i < max_choice; i++)
256             if (key != ' ' && key < 0x100 && toupper(key) == toupper(items[(scroll+i)*3][0]))
257                 break;
258
259         if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) ||
260             KEY_IS_UP(key) || KEY_IS_DOWN(key) || ((key == ' ' || key == '\n' ||
261             key == '\r') && onlist)) {
262
263             /* if moving from buttons to the list, reset and redraw buttons */
264             if (!onlist) {
265                 onlist = 1;
266                 button = 0;
267
268                 if (ditems && result) {
269                     print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
270                     print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
271                 }
272                 else {
273                     print_button(dialog, "Cancel", y, x + 14, button);
274                     print_button(dialog, "  OK  ", y, x, !button);
275                 }
276                 wmove(list, choice, check_x+1);
277                 wnoutrefresh(dialog);
278                 wrefresh(list);
279             }
280
281             if (key >= '1' && key <= MIN('9', '0'+max_choice))
282                 i = key - '1';
283             
284             else if (KEY_IS_UP(key)) {
285                 if (!choice) {
286                     if (scroll) {
287                         /* Scroll list down */
288                         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
289                         if (list_height > 1) {
290                             /* De-highlight current first item before scrolling down */
291                             print_item(list, items[scroll * 3], items[scroll * 3 + 1], status[scroll], 0,
292                                        FALSE, DREF(ditems, scroll), list_width, item_x, check_x);
293                             scrollok(list, TRUE);
294                             wscrl(list, -1);
295                             scrollok(list, FALSE);
296                         }
297                         scroll--;
298                         print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0,
299                                    TRUE, DREF(ditems, scroll), list_width, item_x, check_x);
300                         print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
301                         wmove(list, choice, check_x+1);
302                         wnoutrefresh(dialog);
303                         wrefresh(list);
304                     }
305                     continue;    /* wait for another key press */
306                 }
307                 else
308                     i = choice - 1;
309             }
310             else if (KEY_IS_DOWN(key)) {
311                 if (choice == max_choice - 1) {
312                     if (scroll + choice < item_no - 1) {
313                         /* Scroll list up */
314                         getyx(dialog, cur_y, cur_x);    /* Save cursor position */
315                         if (list_height > 1) {
316                             /* De-highlight current last item before scrolling up */
317                             print_item(list, items[(scroll + max_choice - 1) * 3],
318                                        items[(scroll + max_choice - 1) * 3 + 1],
319                                        status[scroll + max_choice - 1], max_choice - 1,
320                                        FALSE, DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
321                             scrollok(list, TRUE);
322                             scroll(list);
323                             scrollok(list, FALSE);
324                         }
325                         scroll++;
326                         print_item(list, items[(scroll + max_choice - 1) * 3],
327                                    items[(scroll + max_choice - 1) * 3 + 1],
328                                    status[scroll + max_choice - 1], max_choice - 1, TRUE,
329                                    DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
330                         print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
331                         wmove(list, choice, check_x+1);
332                         wnoutrefresh(dialog);
333                         wrefresh(list);
334                     }
335                     continue;    /* wait for another key press */
336                 }
337                 else
338                     i = choice + 1;
339             }
340             else if ((key == ' ' || key == '\n' || key == '\r') && onlist) {    /* Toggle item status */
341                 char lbra = 0, rbra = 0, mark = 0;
342
343                 getyx(list, old_y, old_x);    /* Save cursor position */
344                 
345                 if (ditems) {
346                     if (ditems[scroll + choice].fire) {
347                         int st;
348                         WINDOW *save;
349
350                         save = dupwin(newscr);
351                         st = ditems[scroll + choice].fire(&ditems[scroll + choice]);    /* Call "fire" action */
352                         if (st & DITEM_RESTORE) {
353                             touchwin(save);
354                             wrefresh(save);
355                         }
356                         delwin(save);
357                         if (st & DITEM_REDRAW) {
358                             wclear(list);
359                             for (i = 0; i < item_no; i++)
360                                 status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
361                             for (i = 0; i < max_choice; i++) {
362                                 print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1],
363                                            status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
364                             }
365                             wnoutrefresh(list);
366                             print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4,
367                                          cur_x, cur_y);
368                             wrefresh(dialog);
369                         }
370                         if (st & DITEM_LEAVE_MENU) {
371                             /* Allow a fire action to take us out of the menu */
372                             key = ESC;
373                             rval = 0;
374                             break;
375                         }
376                         else if (st & DITEM_RECREATE) {
377                             delwin(list);
378                             delwin(dialog);
379                             dialog_clear();
380                             goto draw;
381                         }
382                     }
383                     status[scroll + choice] = ditems[scroll + choice].checked ?
384                         ditems[scroll + choice].checked(&ditems[scroll + choice]) : FALSE;
385                     lbra = ditems[scroll + choice].lbra;
386                     rbra = ditems[scroll + choice].rbra;
387                     mark = ditems[scroll + choice].mark;
388                 }
389                 else
390                     status[scroll + choice] = !status[scroll + choice];
391                 wmove(list, choice, check_x);
392                 wattrset(list, check_selected_attr);
393                 if (!lbra)
394                     lbra = '[';
395                 if (!rbra)
396                     rbra = ']';
397                 if (!mark)
398                     mark = 'X';
399                 wprintw(list, "%c%c%c", lbra, status[scroll + choice] ? mark : ' ', rbra);
400                 wmove(list, old_y, old_x);  /* Restore cursor to previous position */
401                 wrefresh(list);
402                 continue;    /* wait for another key press */
403             }
404             
405             if (i != choice) {
406                 /* De-highlight current item */
407                 getyx(dialog, cur_y, cur_x);    /* Save cursor position */
408                 print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1],
409                            status[scroll + choice], choice, FALSE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
410                 
411                 /* Highlight new item */
412                 choice = i;
413                 print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
414                 wmove(list, choice, check_x+1);   /* Restore cursor to previous position */
415                 wrefresh(list);
416             }
417             continue;    /* wait for another key press */
418         }
419         
420         switch (key) {
421         case KEY_PPAGE: /* can we go up? */
422             if (scroll > height - 4)
423                 scroll -= (height-4);
424             else
425                 scroll = 0;
426             redraw_menu = TRUE;
427             if (!onlist) {
428                 onlist = 1;
429                 button = 0;
430             }
431             break;
432             
433         case KEY_NPAGE:      /* can we go down a full page? */
434             if (scroll + list_height >= item_no-1 - list_height) {
435                 scroll = item_no - list_height;
436                 if (scroll < 0)
437                     scroll = 0;
438             }
439             else
440                 scroll += list_height;
441             redraw_menu = TRUE;
442             if (!onlist) {
443                 onlist = 1;
444                 button = 0;
445             }
446             break;
447             
448         case KEY_HOME:      /* go to the top */
449             scroll = 0;
450             choice = 0;
451             redraw_menu = TRUE;
452             cursor_reset = TRUE;
453             onlist = 1;
454             break;
455             
456         case KEY_END:      /* Go to the bottom */
457             scroll = item_no - list_height;
458             if (scroll < 0)
459                 scroll = 0;
460             choice = max_choice - 1;
461             redraw_menu = TRUE;
462             cursor_reset = TRUE;
463             onlist = 1;
464             break;
465             
466         case TAB:
467         case KEY_BTAB:
468             /* move to next component */
469             if (onlist) {       /* on list, next is ok button */
470                 onlist = 0;
471                 if (ditems && result) {
472                     print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
473                     print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
474                     ok_space = 1;
475                     cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
476                 }
477                 else {
478                     print_button(dialog, "Cancel", y, x + 14, button);
479                     print_button(dialog, "  OK  ", y, x, !button);
480                     ok_space = 3;
481                     cancel_space = 15;
482                 }
483                 if (button)
484                     wmove(dialog, y, x + cancel_space);
485                 else
486                     wmove(dialog, y, x + ok_space);
487                 wrefresh(dialog);
488                 break;
489             }
490             else if (button) {     /* on cancel button, next is list */
491                 button = 0;
492                 onlist = 1;
493                 redraw_menu = TRUE;
494                 break; 
495             }
496             /* on ok button, next is cancel button, same as left/right case */
497
498         case KEY_LEFT:
499         case KEY_RIGHT:
500             onlist = 0;
501             button = !button;
502             if (ditems && result) {
503                 print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
504                 print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ?  ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
505                 ok_space = 1;
506                 cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
507             }
508             else {
509                 print_button(dialog, "Cancel", y, x + 14, button);
510                 print_button(dialog, "  OK  ", y, x, !button);
511                 ok_space = 3;
512                 cancel_space = 15;
513             }
514             if (button)
515                 wmove(dialog, y, x + cancel_space);
516             else
517                 wmove(dialog, y, x + ok_space);
518             wrefresh(dialog);
519             break;
520
521         case ' ':
522         case '\n':
523         case '\r':
524             if (!onlist) {
525                 if (ditems) {
526                     if (result && ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire) {
527                         int st;
528                         WINDOW *save = dupwin(newscr);
529
530                         st = ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire(&ditems[button ? CANCEL_BUTTON : OK_BUTTON]);
531                         if (st & DITEM_RESTORE) {
532                             touchwin(save);
533                             wrefresh(save);
534                         }
535                         delwin(save);
536                         if (st == DITEM_FAILURE)
537                         continue;
538                     }
539                 }
540                 else if (result) {
541                     *result = '\0';
542                     for (i = 0; i < item_no; i++) {
543                         if (status[i]) {
544                             strcat(result, items[i*3]);
545                             strcat(result, "\n");
546                         }
547                     }
548                 }
549                 rval = button;
550                 key = ESC;      /* Bail out! */
551                 break;
552             }
553             
554             /* Let me outta here! */
555         case ESC:
556             rval = -1;
557             break;
558             
559             /* Help! */
560         case KEY_F(1):
561         case '?':
562             display_helpfile();
563             break;
564         }
565         
566         if (redraw_menu) {
567             getyx(list, old_y, old_x);
568             wclear(list);
569             for (i = 0; i < max_choice; i++)
570                 print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
571             print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
572
573             /* redraw buttons to fix highlighting */
574             if (ditems && result) {
575                 print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
576                 print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
577             }
578             else {
579                 print_button(dialog, "Cancel", y, x + 14, button);
580                 print_button(dialog, "  OK  ", y, x, !button);
581             }
582             wnoutrefresh(dialog);
583             if (cursor_reset) {
584                 wmove(list, choice, check_x+1);
585                 cursor_reset = FALSE;
586             }
587             else {
588                 wmove(list, old_y, old_x);
589             }
590             wrefresh(list);
591             redraw_menu = FALSE;
592         }
593     }
594     delwin(list);
595     delwin(dialog);
596     return rval;
597 }
598
599
600 /*
601  * Print list item
602  */
603 static void
604 print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected, dialogMenuItem *me, int list_width, int item_x, int check_x)
605 {
606     int i;
607     
608     /* Clear 'residue' of last item */
609     wattrset(win, menubox_attr);
610     wmove(win, choice, 0);
611     for (i = 0; i < list_width; i++)
612         waddch(win, ' ');
613     wmove(win, choice, check_x);
614     wattrset(win, selected ? check_selected_attr : check_attr);
615     wprintw(win, "%c%c%c",  me && me->lbra ? me->lbra : '[',
616             status ? me && me->mark ? me->mark : 'X' : ' ',
617             me && me->rbra ? me->rbra : ']');
618     wattrset(win, menubox_attr);
619     waddch(win, ' ');
620     wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
621     waddch(win, tag[0]);
622     wattrset(win, selected ? tag_selected_attr : tag_attr);
623     waddstr(win, tag + 1);
624     wmove(win, choice, item_x);
625     wattrset(win, selected ? item_selected_attr : item_attr);
626     waddstr(win, item);
627     /* If have a selection handler for this, call it */
628     if (me && me->selected) {
629         wrefresh(win);
630         me->selected(me, selected);
631     }
632 }
633 /* End of print_item() */