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