2 * radiolist.c -- implements the radiolist box
4 * AUTHOR: Stuart Herbert - S.Herbert@sheffield.ac.uk
5 * (from checklist.c by Savio Lam (lam836@cs.cuhk.hk))
7 * Substantial rennovation: 12/18/95, Jordan K. Hubbard
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * $FreeBSD: src/gnu/lib/libdialog/radiolist.c,v 1.36.2.2 2001/08/31 03:04:59 eric Exp $
24 * $DragonFly: src/gnu/lib/libdialog/radiolist.c,v 1.2 2003/06/17 04:25:43 dillon Exp $
28 #include "dialog.priv.h"
31 static void print_item(WINDOW
*win
, char *tag
, char *item
, int status
, int choice
, int selected
, dialogMenuItem
*me
);
33 #define DREF(di, item) ((di) ? &((di)[(item)]) : NULL)
35 static int list_width
, check_x
, item_x
;
39 * Display a dialog box with a list of options that can be turned on or off
42 dialog_radiolist(unsigned char *title
, unsigned char *prompt
, int height
, int width
, int list_height
,
43 int cnt
, void *it
, unsigned char *result
)
45 int i
, j
, x
, y
, cur_x
, cur_y
, old_x
, old_y
, box_x
, box_y
, key
= 0, button
,
46 choice
, l
, k
, scroll
, max_choice
, *status
, item_no
= 0, was_on
= 0;
47 int redraw_menu
= FALSE
, cursor_reset
= FALSE
;
48 int rval
= 0, onlist
= 1, ok_space
, cancel_space
;
49 char okButton
, cancelButton
;
50 WINDOW
*dialog
, *list
;
51 unsigned char **items
= NULL
;
52 dialogMenuItem
*ditems
;
54 /* Allocate space for storing item on/off status */
55 if ((status
= alloca(sizeof(int) * abs(cnt
))) == NULL
) {
57 fprintf(stderr
, "\nCan't allocate memory in dialog_radiolist().\n");
62 button
= choice
= scroll
= 0;
63 /* Previous calling syntax, e.g. just a list of strings? */
68 /* Initializes status */
69 for (i
= 0; i
< item_no
; i
++) {
70 status
[i
] = !strcasecmp(items
[i
*3 + 2], "on");
79 /* It's the new specification format - fake the rest of the code out */
84 items
= (unsigned char **)alloca((item_no
* 3) * sizeof(unsigned char *));
85 /* Initializes status */
86 for (i
= 0; i
< item_no
; i
++) {
87 status
[i
] = ditems
[i
].checked
? ditems
[i
].checked(&ditems
[i
]) : FALSE
;
94 items
[i
*3] = ditems
[i
].prompt
;
95 items
[i
*3 + 1] = ditems
[i
].title
;
96 items
[i
*3 + 2] = status
[i
] ? "on" : "off";
99 max_choice
= MIN(list_height
, item_no
);
103 /* Find length of longest item in order to center radiolist */
104 for (i
= 0; i
< item_no
; i
++) {
105 l
= strlen(items
[i
* 3]);
106 for (j
= 0; j
< item_no
; j
++) {
107 k
= strlen(items
[j
* 3 + 1]);
108 check_x
= MAX(check_x
, l
+ k
+ 6);
110 item_x
= MAX(item_x
, l
);
113 height
= strheight(prompt
) + list_height
+ 4 + 2;
115 i
= strwidth(prompt
);
116 j
= ((title
!= NULL
) ? strwidth(title
) : 0);
118 width
= MAX(width
, check_x
+ 4) + 4;
120 width
= MAX(width
, 24);
126 /* center dialog box on screen */
127 x
= DialogX
? DialogX
: (COLS
- width
) / 2;
128 y
= DialogY
? DialogY
: (LINES
- height
) / 2;
132 draw_shadow(stdscr
, y
, x
, height
, width
);
134 dialog
= newwin(height
, width
, y
, x
);
135 if (dialog
== NULL
) {
137 fprintf(stderr
, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height
, width
, y
, x
);
140 keypad(dialog
, TRUE
);
142 draw_box(dialog
, 0, 0, height
, width
, dialog_attr
, border_attr
);
143 wattrset(dialog
, border_attr
);
144 wmove(dialog
, height
- 3, 0);
145 waddch(dialog
, ACS_LTEE
);
146 for (i
= 0; i
< width
- 2; i
++)
147 waddch(dialog
, ACS_HLINE
);
148 wattrset(dialog
, dialog_attr
);
149 waddch(dialog
, ACS_RTEE
);
150 wmove(dialog
, height
- 2, 1);
151 for (i
= 0; i
< width
- 2; i
++)
155 wattrset(dialog
, title_attr
);
156 wmove(dialog
, 0, (width
- strlen(title
)) / 2 - 1);
158 waddstr(dialog
, title
);
161 wattrset(dialog
, dialog_attr
);
163 print_autowrap(dialog
, prompt
, height
- 1, width
- 2, width
, 1, 2, TRUE
, FALSE
);
165 list_width
= width
- 6;
166 getyx(dialog
, cur_y
, cur_x
);
168 box_x
= (width
- list_width
) / 2 - 1;
170 /* create new window for the list */
171 list
= subwin(dialog
, list_height
, list_width
, y
+ box_y
+ 1, x
+ box_x
+ 1);
175 fprintf(stderr
, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height
, list_width
,
176 y
+ box_y
+ 1,x
+ box_x
+ 1);
181 /* draw a box around the list items */
182 draw_box(dialog
, box_y
, box_x
, list_height
+2, list_width
+2, menubox_border_attr
, menubox_attr
);
184 check_x
= (list_width
- check_x
) / 2;
185 item_x
= check_x
+ item_x
+ 6;
188 for (i
= 0; i
< max_choice
; i
++)
189 print_item(list
, items
[i
* 3], items
[i
* 3 + 1], status
[i
], i
, i
== choice
, DREF(ditems
, i
));
191 print_arrows(dialog
, scroll
, list_height
, item_no
, box_x
, box_y
, check_x
+ 4, cur_x
, cur_y
);
193 display_helpline(dialog
, height
-1, width
);
197 if (ditems
&& result
) {
198 cancelButton
= toupper(ditems
[CANCEL_BUTTON
].prompt
[0]);
199 print_button(dialog
, ditems
[CANCEL_BUTTON
].prompt
, y
, x
+ strlen(ditems
[OK_BUTTON
].prompt
) + 5,
200 ditems
[CANCEL_BUTTON
].checked
? ditems
[CANCEL_BUTTON
].checked(&ditems
[CANCEL_BUTTON
]) : FALSE
);
201 okButton
= toupper(ditems
[OK_BUTTON
].prompt
[0]);
202 print_button(dialog
, ditems
[OK_BUTTON
].prompt
, y
, x
,
203 ditems
[OK_BUTTON
].checked
? ditems
[OK_BUTTON
].checked(&ditems
[OK_BUTTON
]) : TRUE
);
207 print_button(dialog
, "Cancel", y
, x
+ 14, FALSE
);
209 print_button(dialog
, " OK ", y
, x
, TRUE
);
211 wnoutrefresh(dialog
);
212 wmove(list
, choice
, check_x
+1);
216 key
= wgetch(dialog
);
218 /* See if its the short-cut to "OK" */
219 if (toupper(key
) == okButton
) {
221 if (result
&& ditems
[OK_BUTTON
].fire
) {
225 save
= dupwin(newscr
);
226 st
= ditems
[OK_BUTTON
].fire(&ditems
[OK_BUTTON
]);
227 if (st
& DITEM_RESTORE
) {
236 for (i
= 0; i
< item_no
; i
++) {
238 strcat(result
, items
[i
*3]);
248 /* Shortcut to cancel */
249 if (toupper(key
) == cancelButton
) {
250 if (ditems
&& result
&& ditems
[CANCEL_BUTTON
].fire
) {
254 save
= dupwin(newscr
);
255 st
= ditems
[CANCEL_BUTTON
].fire(&ditems
[CANCEL_BUTTON
]);
256 if (st
& DITEM_RESTORE
) {
267 /* Check if key pressed matches first character of any item tag in list */
268 for (i
= 0; i
< max_choice
; i
++)
269 if (key
!= ' ' && toupper(key
) == toupper(items
[(scroll
+ i
) * 3][0]))
272 if (i
< max_choice
|| (key
>= '1' && key
<= MIN('9', '0' + max_choice
)) ||
273 KEY_IS_UP(key
) || KEY_IS_DOWN(key
) || ((key
== ' ' || key
== '\r' || key
== '\n') && onlist
== 1)) {
275 /* if moving from buttons to the list, reset and redraw buttons */
280 if (ditems
&& result
) {
281 print_button(dialog
, ditems
[CANCEL_BUTTON
].prompt
, y
, x
+ strlen(ditems
[OK_BUTTON
].prompt
) + 5,
282 ditems
[CANCEL_BUTTON
].checked
? ditems
[CANCEL_BUTTON
].checked(&ditems
[CANCEL_BUTTON
]) : button
);
283 print_button(dialog
, ditems
[OK_BUTTON
].prompt
, y
, x
,
284 ditems
[OK_BUTTON
].checked
? ditems
[OK_BUTTON
].checked(&ditems
[OK_BUTTON
]) : !button
);
287 print_button(dialog
, "Cancel", y
, x
+ 14, button
);
288 print_button(dialog
, " OK ", y
, x
, !button
);
291 wmove(list
, choice
, check_x
+1);
292 wnoutrefresh(dialog
);
295 if (key
>= '1' && key
<= MIN('9', '0' + max_choice
))
297 else if (KEY_IS_UP(key
)) {
300 /* Scroll list down */
301 getyx(dialog
, cur_y
, cur_x
); /* Save cursor position */
302 if (list_height
> 1) {
303 /* De-highlight current first item before scrolling down */
304 print_item(list
, items
[scroll
*3], items
[scroll
*3 + 1], status
[scroll
], 0,
305 FALSE
, DREF(ditems
, scroll
));
306 scrollok(list
, TRUE
);
308 scrollok(list
, FALSE
);
311 print_item(list
, items
[scroll
*3], items
[scroll
*3 + 1], status
[scroll
], 0,
312 TRUE
, DREF(ditems
, scroll
));
313 print_arrows(dialog
, scroll
, list_height
, item_no
, box_x
, box_y
, check_x
+ 4, cur_x
, cur_y
);
314 wmove(list
, choice
, check_x
+1);
315 wnoutrefresh(dialog
);
318 continue; /* wait for another key press */
323 else if (KEY_IS_DOWN(key
)) {
324 if (choice
== max_choice
- 1) {
325 if (scroll
+ choice
< item_no
- 1) {
327 getyx(dialog
, cur_y
, cur_x
); /* Save cursor position */
328 if (list_height
> 1) {
329 /* De-highlight current last item before scrolling up */
330 print_item(list
, items
[(scroll
+ max_choice
- 1) * 3],
331 items
[(scroll
+ max_choice
- 1) * 3 + 1],
332 status
[scroll
+ max_choice
- 1], max_choice
- 1,
333 FALSE
, DREF(ditems
, scroll
+ max_choice
- 1));
334 scrollok(list
, TRUE
);
336 scrollok(list
, FALSE
);
339 print_item(list
, items
[(scroll
+ max_choice
- 1) * 3],
340 items
[(scroll
+ max_choice
- 1) * 3 + 1],
341 status
[scroll
+ max_choice
- 1], max_choice
- 1,
342 TRUE
, DREF(ditems
, scroll
+ max_choice
- 1));
343 print_arrows(dialog
, scroll
, list_height
, item_no
, box_x
, box_y
, check_x
+ 4, cur_x
, cur_y
);
344 wmove(list
, choice
, check_x
+1);
345 wnoutrefresh(dialog
);
348 continue; /* wait for another key press */
353 else if ((key
== ' ' || key
== '\r' || key
== '\n') && onlist
) { /* Toggle item status */
354 getyx(list
, old_y
, old_x
); /* Save cursor position */
355 if (status
[scroll
+ choice
])
358 if (ditems
[scroll
+ choice
].fire
) {
362 save
= dupwin(newscr
);
363 st
= ditems
[scroll
+ choice
].fire(&ditems
[scroll
+ choice
]);
364 if (st
& DITEM_RESTORE
) {
369 if (st
& DITEM_REDRAW
) {
371 for (i
= 0; i
< item_no
; i
++)
372 status
[i
] = ditems
[i
].checked
? ditems
[i
].checked(&ditems
[i
]) : FALSE
;
374 for (i
= 0; i
< max_choice
; i
++) {
375 print_item(list
, items
[(scroll
+ i
) * 3], items
[(scroll
+ i
) * 3 + 1],
376 status
[scroll
+ i
], i
, i
== choice
,
377 DREF(ditems
, scroll
+ i
));
379 /* wmove(list, old_y, old_x);*/ /* Restore cursor to previous position */
380 /* wrefresh(list); */
382 if (st
& DITEM_LEAVE_MENU
) {
383 /* Allow a fire action to take us out of the menu */
387 else if (st
& DITEM_RECREATE
) {
394 for (i
= 0; i
< item_no
; i
++)
395 status
[i
] = ditems
[i
].checked
? ditems
[i
].checked(&ditems
[i
]) : FALSE
;
398 for (i
= 0; i
< item_no
; i
++)
400 status
[scroll
+ choice
] = TRUE
;
402 for (i
= 0; i
< max_choice
; i
++)
403 print_item(list
, items
[(scroll
+ i
) * 3], items
[(scroll
+ i
) * 3 + 1],
404 status
[scroll
+ i
], i
, i
== choice
, DREF(ditems
, scroll
+ i
));
405 wmove(list
, choice
, check_x
+1); /* Restore cursor position */
407 continue; /* wait for another key press */
411 /* De-highlight current item */
412 print_item(list
, items
[(scroll
+ choice
) * 3], items
[(scroll
+ choice
) * 3 +1],
413 status
[scroll
+ choice
], choice
, FALSE
, DREF(ditems
, scroll
+ choice
));
414 /* Highlight new item */
416 print_item(list
, items
[(scroll
+ choice
) * 3], items
[(scroll
+ choice
) * 3 + 1],
417 status
[scroll
+ choice
], choice
, TRUE
, DREF(ditems
, scroll
+ choice
));
418 wmove(list
, choice
, check_x
+1); /* Restore cursor position */
421 continue; /* wait for another key press */
426 if (scroll
> height
-4) /* can we go up? */
427 scroll
-= (height
-4);
438 if (scroll
+ list_height
>= item_no
-1 - list_height
) { /* can we go down a full page? */
439 scroll
= item_no
- list_height
;
444 scroll
+= list_height
;
461 scroll
= item_no
- list_height
;
464 choice
= max_choice
- 1;
472 /* move to next component */
473 if (onlist
) { /* on list, next is ok button */
475 if (ditems
&& result
)
479 wmove(dialog
, y
, x
+ ok_space
);
483 else if (button
) { /* on cancel button, next is list */
489 /* on ok button, next is cancel button, same as left/right case */
495 if (ditems
&& result
) {
496 print_button(dialog
, ditems
[CANCEL_BUTTON
].prompt
, y
, x
+ strlen(ditems
[OK_BUTTON
].prompt
) + 5,
497 ditems
[CANCEL_BUTTON
].checked
? ditems
[CANCEL_BUTTON
].checked(&ditems
[CANCEL_BUTTON
]) : button
);
498 print_button(dialog
, ditems
[OK_BUTTON
].prompt
, y
, x
,
499 ditems
[OK_BUTTON
].checked
? ditems
[OK_BUTTON
].checked(&ditems
[OK_BUTTON
]) : !button
);
501 cancel_space
= strlen(ditems
[OK_BUTTON
].prompt
) + 6;
504 print_button(dialog
, "Cancel", y
, x
+ 14, button
);
505 print_button(dialog
, " OK ", y
, x
, !button
);
510 wmove(dialog
, y
, x
+ cancel_space
);
512 wmove(dialog
, y
, x
+ ok_space
);
521 if (result
&& ditems
[button
? CANCEL_BUTTON
: OK_BUTTON
].fire
) {
525 save
= dupwin(newscr
);
526 st
= ditems
[button
? CANCEL_BUTTON
: OK_BUTTON
].fire(&ditems
[button
? CANCEL_BUTTON
: OK_BUTTON
]);
527 if (st
& DITEM_RESTORE
) {
536 for (i
= 0; i
< item_no
; i
++) {
538 strcpy(result
, items
[i
*3]);
559 getyx(list
, old_y
, old_x
);
561 for (i
= 0; i
< max_choice
; i
++)
562 print_item(list
, items
[(scroll
+ i
) * 3], items
[(scroll
+ i
) * 3 + 1], status
[scroll
+ i
],
563 i
, i
== choice
, DREF(ditems
, scroll
+ i
));
564 print_arrows(dialog
, scroll
, list_height
, item_no
, box_x
, box_y
, check_x
+ 4, cur_x
, cur_y
);
566 /* redraw buttons to fix highlighting */
567 if (ditems
&& result
) {
568 print_button(dialog
, ditems
[CANCEL_BUTTON
].prompt
, y
, x
+ strlen(ditems
[OK_BUTTON
].prompt
) + 5,
569 ditems
[CANCEL_BUTTON
].checked
? ditems
[CANCEL_BUTTON
].checked(&ditems
[CANCEL_BUTTON
]) : button
);
570 print_button(dialog
, ditems
[OK_BUTTON
].prompt
, y
, x
,
571 ditems
[OK_BUTTON
].checked
? ditems
[OK_BUTTON
].checked(&ditems
[OK_BUTTON
]) : !button
);
574 print_button(dialog
, "Cancel", y
, x
+ 14, button
);
575 print_button(dialog
, " OK ", y
, x
, !button
);
577 wnoutrefresh(dialog
);
579 wmove(list
, choice
, check_x
+1);
580 cursor_reset
= FALSE
;
583 wmove(list
, old_y
, old_x
);
592 return rval
; /* ESC pressed */
599 print_item(WINDOW
*win
, char *tag
, char *item
, int status
, int choice
, int selected
, dialogMenuItem
*me
)
603 /* Clear 'residue' of last item */
604 wattrset(win
, menubox_attr
);
605 wmove(win
, choice
, 0);
606 for (i
= 0; i
< list_width
; i
++)
608 wmove(win
, choice
, check_x
);
609 wattrset(win
, selected
? check_selected_attr
: check_attr
);
610 wprintw(win
, "%c%c%c", me
&& me
->lbra
? me
->lbra
: '(',
611 status
? me
&& me
->mark
? me
->mark
: '*' : ' ',
612 me
&& me
->rbra
? me
->rbra
: ')');
613 wattrset(win
, menubox_attr
);
615 wattrset(win
, selected
? tag_key_selected_attr
: tag_key_attr
);
617 wattrset(win
, selected
? tag_selected_attr
: tag_attr
);
618 waddstr(win
, tag
+ 1);
619 wmove(win
, choice
, item_x
);
620 wattrset(win
, selected
? item_selected_attr
: item_attr
);
622 /* If have a selection handler for this, call it */
623 if (me
&& me
->selected
) {
625 me
->selected(me
, selected
);
628 /* End of print_item() */