xref: /freebsd/contrib/bsddialog/lib/menubox.c (revision d93b4d32)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4c76f0793SBaptiste Daroussin  * Copyright (c) 2021 Alfonso Sabato Siciliano
5c76f0793SBaptiste Daroussin  *
6c76f0793SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
7c76f0793SBaptiste Daroussin  * modification, are permitted provided that the following conditions
8c76f0793SBaptiste Daroussin  * are met:
9c76f0793SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
10c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
11c76f0793SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
12c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
13c76f0793SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
14c76f0793SBaptiste Daroussin  *
15c76f0793SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c76f0793SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c76f0793SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c76f0793SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c76f0793SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c76f0793SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c76f0793SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c76f0793SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c76f0793SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c76f0793SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c76f0793SBaptiste Daroussin  * SUCH DAMAGE.
26c76f0793SBaptiste Daroussin  */
27c76f0793SBaptiste Daroussin 
28c76f0793SBaptiste Daroussin #include <sys/param.h>
29c76f0793SBaptiste Daroussin 
30c76f0793SBaptiste Daroussin #include <ctype.h>
31c76f0793SBaptiste Daroussin #ifdef PORTNCURSES
328c4f4028SBaptiste Daroussin #include <ncurses/ncurses.h>
33c76f0793SBaptiste Daroussin #else
348c4f4028SBaptiste Daroussin #include <ncurses.h>
35c76f0793SBaptiste Daroussin #endif
36*d93b4d32SBaptiste Daroussin #include <string.h>
37*d93b4d32SBaptiste Daroussin 
38c76f0793SBaptiste Daroussin 
39c76f0793SBaptiste Daroussin #include "bsddialog.h"
40c76f0793SBaptiste Daroussin #include "lib_util.h"
41c76f0793SBaptiste Daroussin #include "bsddialog_theme.h"
42c76f0793SBaptiste Daroussin 
43f499134dSBaptiste Daroussin /* "Menu": checklist - menu - mixedlist - radiolist - buildlist */
44c76f0793SBaptiste Daroussin 
45c76f0793SBaptiste Daroussin #define DEPTHSPACE	4
46c76f0793SBaptiste Daroussin #define MIN_HEIGHT	VBORDERS + 6 /* 2 buttons 1 text 3 menu */
47c76f0793SBaptiste Daroussin 
48c76f0793SBaptiste Daroussin extern struct bsddialog_theme t;
49c76f0793SBaptiste Daroussin 
50c76f0793SBaptiste Daroussin enum menumode {
51c76f0793SBaptiste Daroussin 	BUILDLISTMODE,
52c76f0793SBaptiste Daroussin 	CHECKLISTMODE,
53c76f0793SBaptiste Daroussin 	MENUMODE,
54c76f0793SBaptiste Daroussin 	MIXEDLISTMODE,
55c76f0793SBaptiste Daroussin 	RADIOLISTMODE,
56c76f0793SBaptiste Daroussin 	SEPARATORMODE
57c76f0793SBaptiste Daroussin };
58c76f0793SBaptiste Daroussin 
59c76f0793SBaptiste Daroussin struct lineposition {
60c76f0793SBaptiste Daroussin 	unsigned int maxsepstr;
61c76f0793SBaptiste Daroussin 	unsigned int maxprefix;
62c76f0793SBaptiste Daroussin 	unsigned int xselector;
63c76f0793SBaptiste Daroussin 	unsigned int selectorlen;
64c76f0793SBaptiste Daroussin 	unsigned int maxdepth;
65c76f0793SBaptiste Daroussin 	unsigned int xname;
66c76f0793SBaptiste Daroussin 	unsigned int maxname;
67c76f0793SBaptiste Daroussin 	unsigned int xdesc;
68c76f0793SBaptiste Daroussin 	unsigned int maxdesc;
69c76f0793SBaptiste Daroussin 	unsigned int line;
70c76f0793SBaptiste Daroussin };
71c76f0793SBaptiste Daroussin 
72c76f0793SBaptiste Daroussin static int checkradiolist(int nitems, struct bsddialog_menuitem *items)
73c76f0793SBaptiste Daroussin {
74c76f0793SBaptiste Daroussin 	int i, error;
75c76f0793SBaptiste Daroussin 
76c76f0793SBaptiste Daroussin 	error = 0;
77c76f0793SBaptiste Daroussin 	for (i=0; i<nitems; i++) {
78c76f0793SBaptiste Daroussin 		if (error > 0)
79c76f0793SBaptiste Daroussin 			items[i].on = false;
80c76f0793SBaptiste Daroussin 
81c76f0793SBaptiste Daroussin 		if (items[i].on == true)
82c76f0793SBaptiste Daroussin 			error++;
83c76f0793SBaptiste Daroussin 	}
84c76f0793SBaptiste Daroussin 
85c76f0793SBaptiste Daroussin 	return (error == 0 ? 0 : -1);
86c76f0793SBaptiste Daroussin }
87c76f0793SBaptiste Daroussin 
88c76f0793SBaptiste Daroussin static int checkmenu(int nitems, struct bsddialog_menuitem *items) // useful?
89c76f0793SBaptiste Daroussin {
90c76f0793SBaptiste Daroussin 	int i, error;
91c76f0793SBaptiste Daroussin 
92c76f0793SBaptiste Daroussin 	error = 0;
93c76f0793SBaptiste Daroussin 	for (i=0; i<nitems; i++) {
94c76f0793SBaptiste Daroussin 		if (items[i].on == true)
95c76f0793SBaptiste Daroussin 			error++;
96c76f0793SBaptiste Daroussin 
97c76f0793SBaptiste Daroussin 		items[i].on = false;
98c76f0793SBaptiste Daroussin 	}
99c76f0793SBaptiste Daroussin 
100c76f0793SBaptiste Daroussin 	return (error == 0 ? 0 : -1);
101c76f0793SBaptiste Daroussin }
102c76f0793SBaptiste Daroussin 
103c76f0793SBaptiste Daroussin static void
104c76f0793SBaptiste Daroussin getfirst(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
105c76f0793SBaptiste Daroussin     int *rel)
106c76f0793SBaptiste Daroussin {
107c76f0793SBaptiste Daroussin 	int i, a;
108c76f0793SBaptiste Daroussin 
109c76f0793SBaptiste Daroussin 	*abs = *rel = *group = -1;
110c76f0793SBaptiste Daroussin 	a = 0;
111c76f0793SBaptiste Daroussin 	for (i=0; i<ngroups; i++) {
112c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
113c76f0793SBaptiste Daroussin 			a += groups[i].nitems;
114c76f0793SBaptiste Daroussin 			continue;
115c76f0793SBaptiste Daroussin 		}
116c76f0793SBaptiste Daroussin 		if (groups[i].nitems != 0) {
117c76f0793SBaptiste Daroussin 			*group = i;
118c76f0793SBaptiste Daroussin 			*abs = a;
119c76f0793SBaptiste Daroussin 			*rel = 0;
120c76f0793SBaptiste Daroussin 			break;
121c76f0793SBaptiste Daroussin 		}
122c76f0793SBaptiste Daroussin 	}
123c76f0793SBaptiste Daroussin }
124c76f0793SBaptiste Daroussin 
125c76f0793SBaptiste Daroussin static void
126f499134dSBaptiste Daroussin getfirst_with_default(struct bsddialog_conf *conf, int ngroups,
127c76f0793SBaptiste Daroussin     struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
128c76f0793SBaptiste Daroussin {
129c76f0793SBaptiste Daroussin 	int i, j, a;
130c76f0793SBaptiste Daroussin 	struct bsddialog_menuitem *item;
131c76f0793SBaptiste Daroussin 
132c76f0793SBaptiste Daroussin 	getfirst(ngroups, groups, abs, group, rel);
133c76f0793SBaptiste Daroussin 	if (*abs < 0)
134c76f0793SBaptiste Daroussin 		return;
135c76f0793SBaptiste Daroussin 
136c76f0793SBaptiste Daroussin 	a = *abs;
137c76f0793SBaptiste Daroussin 
138c76f0793SBaptiste Daroussin 	for (i=*group; i<ngroups; i++) {
139c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
140c76f0793SBaptiste Daroussin 			a += groups[i].nitems;
141c76f0793SBaptiste Daroussin 			continue;
142c76f0793SBaptiste Daroussin 		}
143c76f0793SBaptiste Daroussin 		for (j = 0; j < (int) groups[i].nitems; j++) {
144c76f0793SBaptiste Daroussin 			item = &groups[i].items[j];
145f499134dSBaptiste Daroussin 			if (conf->menu.default_item != NULL && item->name != NULL) {
146f499134dSBaptiste Daroussin 				if (strcmp(item->name, conf->menu.default_item) == 0) {
147c76f0793SBaptiste Daroussin 					*abs = a;
148c76f0793SBaptiste Daroussin 					*group = i;
149c76f0793SBaptiste Daroussin 					*rel = j;
150c76f0793SBaptiste Daroussin 					return;
151c76f0793SBaptiste Daroussin 				}
152c76f0793SBaptiste Daroussin 			}
153c76f0793SBaptiste Daroussin 			a++;
154c76f0793SBaptiste Daroussin 		}
155c76f0793SBaptiste Daroussin 	}
156c76f0793SBaptiste Daroussin }
157c76f0793SBaptiste Daroussin 
158c76f0793SBaptiste Daroussin static void
159c76f0793SBaptiste Daroussin getlast(int totnitems, int ngroups, struct bsddialog_menugroup *groups,
160c76f0793SBaptiste Daroussin     int *abs, int *group, int *rel)
161c76f0793SBaptiste Daroussin {
162c76f0793SBaptiste Daroussin 	int i, a;
163c76f0793SBaptiste Daroussin 
164c76f0793SBaptiste Daroussin 	a = totnitems - 1;
165c76f0793SBaptiste Daroussin 	for (i = ngroups-1; i>=0; i--) {
166c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
167c76f0793SBaptiste Daroussin 			a -= groups[i].nitems;
168c76f0793SBaptiste Daroussin 			continue;
169c76f0793SBaptiste Daroussin 		}
170c76f0793SBaptiste Daroussin 		if (groups[i].nitems != 0) {
171c76f0793SBaptiste Daroussin 			*group = i;
172c76f0793SBaptiste Daroussin 			*abs = a;
173c76f0793SBaptiste Daroussin 			*rel = groups[i].nitems - 1;
174c76f0793SBaptiste Daroussin 			break;
175c76f0793SBaptiste Daroussin 		}
176c76f0793SBaptiste Daroussin 	}
177c76f0793SBaptiste Daroussin }
178c76f0793SBaptiste Daroussin 
179c76f0793SBaptiste Daroussin static void
180c76f0793SBaptiste Daroussin getnext(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
181c76f0793SBaptiste Daroussin     int *rel)
182c76f0793SBaptiste Daroussin {
183c76f0793SBaptiste Daroussin 	int i, a;
184c76f0793SBaptiste Daroussin 
185c76f0793SBaptiste Daroussin 	if (*abs < 0 || *group < 0 || *rel < 0)
186c76f0793SBaptiste Daroussin 		return;
187c76f0793SBaptiste Daroussin 
188c76f0793SBaptiste Daroussin 	if (*rel + 1 < (int) groups[*group].nitems) {
189c76f0793SBaptiste Daroussin 		*rel = *rel + 1;
190c76f0793SBaptiste Daroussin 		*abs = *abs + 1;
191c76f0793SBaptiste Daroussin 		return;
192c76f0793SBaptiste Daroussin 	}
193c76f0793SBaptiste Daroussin 
194c76f0793SBaptiste Daroussin 	if (*group + 1 > ngroups)
195c76f0793SBaptiste Daroussin 		return;
196c76f0793SBaptiste Daroussin 
197c76f0793SBaptiste Daroussin 	a = *abs;
198c76f0793SBaptiste Daroussin 	for (i = *group + 1; i < ngroups; i++) {
199c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
200c76f0793SBaptiste Daroussin 			a += groups[i].nitems;
201c76f0793SBaptiste Daroussin 			continue;
202c76f0793SBaptiste Daroussin 		}
203c76f0793SBaptiste Daroussin 		if (groups[i].nitems != 0) {
204c76f0793SBaptiste Daroussin 			*group = i;
205c76f0793SBaptiste Daroussin 			*abs = a + 1;
206c76f0793SBaptiste Daroussin 			*rel = 0;
207c76f0793SBaptiste Daroussin 			break;
208c76f0793SBaptiste Daroussin 		}
209c76f0793SBaptiste Daroussin 	}
210c76f0793SBaptiste Daroussin }
211c76f0793SBaptiste Daroussin 
212c76f0793SBaptiste Daroussin static void
213c76f0793SBaptiste Daroussin getfastnext(int menurows, int ngroups, struct bsddialog_menugroup *groups,
214c76f0793SBaptiste Daroussin     int *abs, int *group, int *rel)
215c76f0793SBaptiste Daroussin {
216c76f0793SBaptiste Daroussin 	int a, start, i;
217c76f0793SBaptiste Daroussin 
218c76f0793SBaptiste Daroussin 	start = *abs;
219c76f0793SBaptiste Daroussin 	i = menurows;
220c76f0793SBaptiste Daroussin 	do {
221c76f0793SBaptiste Daroussin 		a = *abs;
222c76f0793SBaptiste Daroussin 		getnext(ngroups, groups, abs, group, rel);
223c76f0793SBaptiste Daroussin 		i--;
224c76f0793SBaptiste Daroussin 	} while (*abs != a && *abs < start + menurows && i > 0);
225c76f0793SBaptiste Daroussin }
226c76f0793SBaptiste Daroussin 
227c76f0793SBaptiste Daroussin static void
228c76f0793SBaptiste Daroussin getprev(struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
229c76f0793SBaptiste Daroussin {
230c76f0793SBaptiste Daroussin 	int i, a;
231c76f0793SBaptiste Daroussin 
232c76f0793SBaptiste Daroussin 	if (*abs < 0 || *group < 0 || *rel < 0)
233c76f0793SBaptiste Daroussin 		return;
234c76f0793SBaptiste Daroussin 
235c76f0793SBaptiste Daroussin 	if (*rel > 0) {
236c76f0793SBaptiste Daroussin 		*rel = *rel - 1;
237c76f0793SBaptiste Daroussin 		*abs = *abs - 1;
238c76f0793SBaptiste Daroussin 		return;
239c76f0793SBaptiste Daroussin 	}
240c76f0793SBaptiste Daroussin 
241c76f0793SBaptiste Daroussin 	if (*group - 1 < 0)
242c76f0793SBaptiste Daroussin 		return;
243c76f0793SBaptiste Daroussin 
244c76f0793SBaptiste Daroussin 	a = *abs;
245c76f0793SBaptiste Daroussin 	for (i = *group - 1; i >= 0; i--) {
246c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
247c76f0793SBaptiste Daroussin 			a -= (int) groups[i].nitems;
248c76f0793SBaptiste Daroussin 			continue;
249c76f0793SBaptiste Daroussin 		}
250c76f0793SBaptiste Daroussin 		if (groups[i].nitems != 0) {
251c76f0793SBaptiste Daroussin 			*group = i;
252c76f0793SBaptiste Daroussin 			*abs = a - 1;
253c76f0793SBaptiste Daroussin 			*rel = (int) groups[i].nitems - 1;
254c76f0793SBaptiste Daroussin 			break;
255c76f0793SBaptiste Daroussin 		}
256c76f0793SBaptiste Daroussin 	}
257c76f0793SBaptiste Daroussin }
258c76f0793SBaptiste Daroussin 
259c76f0793SBaptiste Daroussin static void
260c76f0793SBaptiste Daroussin getfastprev(int menurows, struct bsddialog_menugroup *groups, int *abs,
261c76f0793SBaptiste Daroussin     int *group, int *rel)
262c76f0793SBaptiste Daroussin {
263c76f0793SBaptiste Daroussin 	int a, start, i;
264c76f0793SBaptiste Daroussin 
265c76f0793SBaptiste Daroussin 	start = *abs;
266c76f0793SBaptiste Daroussin 	i = menurows;
267c76f0793SBaptiste Daroussin 	do {
268c76f0793SBaptiste Daroussin 		a = *abs;
269c76f0793SBaptiste Daroussin 		getprev(groups, abs, group, rel);
270c76f0793SBaptiste Daroussin 		i--;
271c76f0793SBaptiste Daroussin 	} while (*abs != a && *abs > start - menurows && i > 0);
272c76f0793SBaptiste Daroussin }
273c76f0793SBaptiste Daroussin 
2748c4f4028SBaptiste Daroussin static bool
2758c4f4028SBaptiste Daroussin getnextshortcut(struct bsddialog_conf *conf, enum menumode mode, int ngroups,
2768c4f4028SBaptiste Daroussin     struct bsddialog_menugroup *groups, int *abs, int *group, int *rel,
2778c4f4028SBaptiste Daroussin     int key)
2788c4f4028SBaptiste Daroussin {
2798c4f4028SBaptiste Daroussin 	int i, j, a, ch, ng, nr, na;
2808c4f4028SBaptiste Daroussin 	bool mainloop;
2818c4f4028SBaptiste Daroussin 
2828c4f4028SBaptiste Daroussin 	if (*abs < 0 || ngroups < 0 || *rel < 0 || mode == BUILDLISTMODE)
2838c4f4028SBaptiste Daroussin 		return false;
2848c4f4028SBaptiste Daroussin 
2858c4f4028SBaptiste Daroussin 	na = a = -1;
2868c4f4028SBaptiste Daroussin 	mainloop = true;
2878c4f4028SBaptiste Daroussin 	for (i = 0; i < ngroups && mainloop; i++) {
2888c4f4028SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
2898c4f4028SBaptiste Daroussin 			a += groups[i].nitems;
2908c4f4028SBaptiste Daroussin 			continue;
2918c4f4028SBaptiste Daroussin 		}
2928c4f4028SBaptiste Daroussin 		for (j = 0; j < (int)groups[i].nitems; j++) {
2938c4f4028SBaptiste Daroussin 			a++;
2948c4f4028SBaptiste Daroussin 			if (a == *abs)
2958c4f4028SBaptiste Daroussin 				continue;
2968c4f4028SBaptiste Daroussin 
2978c4f4028SBaptiste Daroussin 			if (conf->menu.no_name)
2988c4f4028SBaptiste Daroussin 				ch = groups[i].items[j].desc[0];
2998c4f4028SBaptiste Daroussin 			else
3008c4f4028SBaptiste Daroussin 				ch = groups[i].items[j].name[0];
3018c4f4028SBaptiste Daroussin 
3028c4f4028SBaptiste Daroussin 			if (ch == key) {
3038c4f4028SBaptiste Daroussin 				if (a < *abs && na == -1) {
3048c4f4028SBaptiste Daroussin 					na = a;
3058c4f4028SBaptiste Daroussin 					ng = i;
3068c4f4028SBaptiste Daroussin 					nr = j;
3078c4f4028SBaptiste Daroussin 				}
3088c4f4028SBaptiste Daroussin 				if (a > *abs) {
3098c4f4028SBaptiste Daroussin 					na = a;
3108c4f4028SBaptiste Daroussin 					ng = i;
3118c4f4028SBaptiste Daroussin 					nr = j;
3128c4f4028SBaptiste Daroussin 					mainloop = false;
3138c4f4028SBaptiste Daroussin 					break;
3148c4f4028SBaptiste Daroussin 				}
3158c4f4028SBaptiste Daroussin 			}
3168c4f4028SBaptiste Daroussin 		}
3178c4f4028SBaptiste Daroussin 	}
3188c4f4028SBaptiste Daroussin 
3198c4f4028SBaptiste Daroussin 	if (na != -1) {
3208c4f4028SBaptiste Daroussin 		*abs = na;
3218c4f4028SBaptiste Daroussin 		*group = ng;
3228c4f4028SBaptiste Daroussin 		*rel = nr;
3238c4f4028SBaptiste Daroussin 		return (true);
3248c4f4028SBaptiste Daroussin 	}
3258c4f4028SBaptiste Daroussin 
3268c4f4028SBaptiste Daroussin 	return (false);
3278c4f4028SBaptiste Daroussin }
3288c4f4028SBaptiste Daroussin 
329c76f0793SBaptiste Daroussin static enum menumode
330c76f0793SBaptiste Daroussin getmode(enum menumode mode, struct bsddialog_menugroup group)
331c76f0793SBaptiste Daroussin {
332c76f0793SBaptiste Daroussin 
333c76f0793SBaptiste Daroussin 	if (mode == MIXEDLISTMODE) {
334c76f0793SBaptiste Daroussin 		if (group.type == BSDDIALOG_SEPARATOR)
335c76f0793SBaptiste Daroussin 			mode = SEPARATORMODE;
336c76f0793SBaptiste Daroussin 		else if (group.type == BSDDIALOG_RADIOLIST)
337c76f0793SBaptiste Daroussin 			mode = RADIOLISTMODE;
338c76f0793SBaptiste Daroussin 		else if (group.type == BSDDIALOG_CHECKLIST)
339c76f0793SBaptiste Daroussin 			mode = CHECKLISTMODE;
340c76f0793SBaptiste Daroussin 	}
341c76f0793SBaptiste Daroussin 
342c76f0793SBaptiste Daroussin 	return mode;
343c76f0793SBaptiste Daroussin }
344c76f0793SBaptiste Daroussin 
345c76f0793SBaptiste Daroussin static void
346f499134dSBaptiste Daroussin drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
347c76f0793SBaptiste Daroussin     struct bsddialog_menuitem item, enum menumode mode, struct lineposition pos,
348c76f0793SBaptiste Daroussin     bool curr)
349c76f0793SBaptiste Daroussin {
3508c4f4028SBaptiste Daroussin 	int colordesc, colorname, colorshortcut, linech;
3518c4f4028SBaptiste Daroussin 	char *shortcut;
352c76f0793SBaptiste Daroussin 
353c76f0793SBaptiste Daroussin 	if (mode == SEPARATORMODE) {
354f499134dSBaptiste Daroussin 		if (conf->no_lines == false) {
355f499134dSBaptiste Daroussin 			wattron(pad, t.menu.desccolor);
356f499134dSBaptiste Daroussin 			linech = conf->ascii_lines ? '-' : ACS_HLINE;
357c76f0793SBaptiste Daroussin 			mvwhline(pad, y, 0, linech, pos.line);
358f499134dSBaptiste Daroussin 			wattroff(pad, t.menu.desccolor);
359c76f0793SBaptiste Daroussin 		}
360c76f0793SBaptiste Daroussin 		wmove(pad, y, pos.line/2 - (strlen(item.name)+strlen(item.desc))/2);
361f499134dSBaptiste Daroussin 		wattron(pad, t.menu.namesepcolor);
362c76f0793SBaptiste Daroussin 		waddstr(pad, item.name);
363f499134dSBaptiste Daroussin 		wattroff(pad, t.menu.namesepcolor);
364c76f0793SBaptiste Daroussin 		if (strlen(item.name) > 0 && strlen(item.desc) > 0)
365c76f0793SBaptiste Daroussin 			waddch(pad, ' ');
366f499134dSBaptiste Daroussin 		wattron(pad, t.menu.descsepcolor);
367c76f0793SBaptiste Daroussin 		waddstr(pad, item.desc);
368f499134dSBaptiste Daroussin 		wattroff(pad, t.menu.descsepcolor);
369c76f0793SBaptiste Daroussin 		return;
370c76f0793SBaptiste Daroussin 	}
371c76f0793SBaptiste Daroussin 
372c76f0793SBaptiste Daroussin 	/* prefix */
373c76f0793SBaptiste Daroussin 	if (item.prefix != NULL && item.prefix[0] != '\0')
374c76f0793SBaptiste Daroussin 		mvwaddstr(pad, y, 0, item.prefix);
375c76f0793SBaptiste Daroussin 
376c76f0793SBaptiste Daroussin 	/* selector */
377c76f0793SBaptiste Daroussin 	wmove(pad, y, pos.xselector);
3788c4f4028SBaptiste Daroussin 	wattron(pad, t.menu.selectorcolor);
379c76f0793SBaptiste Daroussin 	if (mode == CHECKLISTMODE)
380c76f0793SBaptiste Daroussin 		wprintw(pad, "[%c]", item.on ? 'X' : ' ');
381c76f0793SBaptiste Daroussin 	if (mode == RADIOLISTMODE)
382c76f0793SBaptiste Daroussin 		wprintw(pad, "(%c)", item.on ? '*' : ' ');
3838c4f4028SBaptiste Daroussin 	wattroff(pad, t.menu.selectorcolor);
384c76f0793SBaptiste Daroussin 
385c76f0793SBaptiste Daroussin 	/* name */
3868c4f4028SBaptiste Daroussin 	colorname = curr ? t.menu.f_namecolor : t.menu.namecolor;
387f499134dSBaptiste Daroussin 	if (mode != BUILDLISTMODE && conf->menu.no_name == false) {
388c76f0793SBaptiste Daroussin 		wattron(pad, colorname);
389c76f0793SBaptiste Daroussin 		mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.name);
390c76f0793SBaptiste Daroussin 		wattroff(pad, colorname);
391c76f0793SBaptiste Daroussin 	}
392c76f0793SBaptiste Daroussin 
393c76f0793SBaptiste Daroussin 	/* description */
3948c4f4028SBaptiste Daroussin 	if (mode == BUILDLISTMODE) {
3958c4f4028SBaptiste Daroussin 		if (curr == false)
3968c4f4028SBaptiste Daroussin 			colordesc = item.on ? t.menu.namecolor : t.menu.desccolor;
3978c4f4028SBaptiste Daroussin 		else
3988c4f4028SBaptiste Daroussin 			colordesc = t.menu.f_namecolor;
3998c4f4028SBaptiste Daroussin 	}
4008c4f4028SBaptiste Daroussin 	else {
4018c4f4028SBaptiste Daroussin 		if (conf->menu.no_name)
4028c4f4028SBaptiste Daroussin 			colordesc = curr ? t.menu.f_namecolor : t.menu.namecolor;
4038c4f4028SBaptiste Daroussin 		else
4048c4f4028SBaptiste Daroussin 			colordesc = curr ? t.menu.f_desccolor : t.menu.desccolor;
4058c4f4028SBaptiste Daroussin 	}
4068c4f4028SBaptiste Daroussin 	if (mode == BUILDLISTMODE || conf->menu.no_desc == false) {
4078c4f4028SBaptiste Daroussin 		wattron(pad, colordesc);
408f499134dSBaptiste Daroussin 		if (conf->menu.no_name)
409c76f0793SBaptiste Daroussin 			mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.desc);
410c76f0793SBaptiste Daroussin 		else
411c76f0793SBaptiste Daroussin 			mvwaddstr(pad, y, pos.xdesc, item.desc);
4128c4f4028SBaptiste Daroussin 		wattroff(pad, colordesc);
413c76f0793SBaptiste Daroussin 	}
414c76f0793SBaptiste Daroussin 
4158c4f4028SBaptiste Daroussin 	/* shortcut */
4168c4f4028SBaptiste Daroussin 	if (mode != BUILDLISTMODE && conf->menu.shortcut_buttons == false) {
4178c4f4028SBaptiste Daroussin 		colorshortcut = curr ? t.menu.f_shortcutcolor : t.menu.shortcutcolor;
4188c4f4028SBaptiste Daroussin 		wattron(pad, colorshortcut);
4198c4f4028SBaptiste Daroussin 
4208c4f4028SBaptiste Daroussin 		if (conf->menu.no_name)
4218c4f4028SBaptiste Daroussin 			shortcut = item.desc;
4228c4f4028SBaptiste Daroussin 		else
4238c4f4028SBaptiste Daroussin 			shortcut = item.name;
4248c4f4028SBaptiste Daroussin 		wmove(pad, y, pos.xname + item.depth * DEPTHSPACE);
4258c4f4028SBaptiste Daroussin 		if (shortcut != NULL && shortcut[0] != '\0')
4268c4f4028SBaptiste Daroussin 			waddch(pad, shortcut[0]);
4278c4f4028SBaptiste Daroussin 	wattroff(pad, colorshortcut);
4288c4f4028SBaptiste Daroussin }
4298c4f4028SBaptiste Daroussin 
4308c4f4028SBaptiste Daroussin 	/* bottom description */
431c76f0793SBaptiste Daroussin 	move(LINES-1, 2);
432c76f0793SBaptiste Daroussin 	clrtoeol();
4338c4f4028SBaptiste Daroussin 	if (item.bottomdesc != NULL) {
434c76f0793SBaptiste Daroussin 		addstr(item.bottomdesc);
435c76f0793SBaptiste Daroussin 		refresh();
436c76f0793SBaptiste Daroussin 	}
437c76f0793SBaptiste Daroussin }
438c76f0793SBaptiste Daroussin 
439c76f0793SBaptiste Daroussin static void
440f499134dSBaptiste Daroussin menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
441c76f0793SBaptiste Daroussin     char *text, int linelen, unsigned int *menurows, int nitems,
442c76f0793SBaptiste Daroussin     struct buttons bs)
443c76f0793SBaptiste Daroussin {
444c76f0793SBaptiste Daroussin 	int textrow, menusize;
445c76f0793SBaptiste Daroussin 
446c76f0793SBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
447c76f0793SBaptiste Daroussin 
448c76f0793SBaptiste Daroussin 	if (cols == BSDDIALOG_AUTOSIZE) {
449c76f0793SBaptiste Daroussin 		*w = VBORDERS;
450c76f0793SBaptiste Daroussin 		/* buttons size */
451c76f0793SBaptiste Daroussin 		*w += bs.nbuttons * bs.sizebutton;
452f499134dSBaptiste Daroussin 		*w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
453c76f0793SBaptiste Daroussin 		/* line size */
454c76f0793SBaptiste Daroussin 		*w = MAX(*w, linelen + 6);
4558c4f4028SBaptiste Daroussin 		/* conf.auto_minwidth */
4568c4f4028SBaptiste Daroussin 		*w = MAX(*w, (int)conf->auto_minwidth);
457c76f0793SBaptiste Daroussin 		/*
458c76f0793SBaptiste Daroussin 		* avoid terminal overflow,
459c76f0793SBaptiste Daroussin 		* -1 fix false negative with big menu over the terminal and
460c76f0793SBaptiste Daroussin 		* autosize, for example "portconfig /usr/ports/www/apache24/".
461c76f0793SBaptiste Daroussin 		*/
462c76f0793SBaptiste Daroussin 		*w = MIN(*w, widget_max_width(conf)-1);
463c76f0793SBaptiste Daroussin 	}
464c76f0793SBaptiste Daroussin 
465c76f0793SBaptiste Daroussin 	if (rows == BSDDIALOG_AUTOSIZE) {
466c76f0793SBaptiste Daroussin 		*h = HBORDERS + 2 /* buttons */ + textrow;
467c76f0793SBaptiste Daroussin 
468c76f0793SBaptiste Daroussin 		if (*menurows == 0) {
469c76f0793SBaptiste Daroussin 			*h += nitems + 2;
470c76f0793SBaptiste Daroussin 			*h = MIN(*h, widget_max_height(conf));
471c76f0793SBaptiste Daroussin 			menusize = MIN(nitems + 2, *h - (HBORDERS + 2 + textrow));
472c76f0793SBaptiste Daroussin 			menusize -=2;
473c76f0793SBaptiste Daroussin 			*menurows = menusize < 0 ? 0 : menusize;
474c76f0793SBaptiste Daroussin 		}
475c76f0793SBaptiste Daroussin 		else /* h autosize with a fixed menurows */
476c76f0793SBaptiste Daroussin 			*h = *h + *menurows + 2;
477c76f0793SBaptiste Daroussin 
4788c4f4028SBaptiste Daroussin 		/* conf.auto_minheight */
4798c4f4028SBaptiste Daroussin 		*h = MAX(*h, (int)conf->auto_minheight);
480c76f0793SBaptiste Daroussin 		/* avoid terminal overflow */
481c76f0793SBaptiste Daroussin 		*h = MIN(*h, widget_max_height(conf));
4828c4f4028SBaptiste Daroussin 		/* avoid menurows overflow */
4838c4f4028SBaptiste Daroussin 		/* manual: with rows=autosize menurows!=0 is maxmenurows */
4848c4f4028SBaptiste Daroussin 		*menurows = MIN(*h - 6 - textrow, (int)*menurows);
485c76f0793SBaptiste Daroussin 	}
486c76f0793SBaptiste Daroussin 	else {
487c76f0793SBaptiste Daroussin 		if (*menurows == 0)
488c76f0793SBaptiste Daroussin 			*menurows = MIN(rows-6-textrow, nitems);
489c76f0793SBaptiste Daroussin 	}
490c76f0793SBaptiste Daroussin }
491c76f0793SBaptiste Daroussin 
492c76f0793SBaptiste Daroussin static int
493c76f0793SBaptiste Daroussin menu_checksize(int rows, int cols, char *text, int menurows, int nitems,
494c76f0793SBaptiste Daroussin     struct buttons bs)
495c76f0793SBaptiste Daroussin {
496c76f0793SBaptiste Daroussin 	int mincols, textrow, menusize;
497c76f0793SBaptiste Daroussin 
498c76f0793SBaptiste Daroussin 	mincols = VBORDERS;
499c76f0793SBaptiste Daroussin 	/* buttons */
500c76f0793SBaptiste Daroussin 	mincols += bs.nbuttons * bs.sizebutton;
501f499134dSBaptiste Daroussin 	mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
502c76f0793SBaptiste Daroussin 	/* line, comment to permet some cols hidden */
503c76f0793SBaptiste Daroussin 	/* mincols = MAX(mincols, linelen); */
504c76f0793SBaptiste Daroussin 
505c76f0793SBaptiste Daroussin 	if (cols < mincols)
506c76f0793SBaptiste Daroussin 		RETURN_ERROR("Few cols, width < size buttons or "\
507c76f0793SBaptiste Daroussin 		    "name+descripion of the items");
508c76f0793SBaptiste Daroussin 
509c76f0793SBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
510c76f0793SBaptiste Daroussin 
511c76f0793SBaptiste Daroussin 	if (nitems > 0 && menurows == 0)
512c76f0793SBaptiste Daroussin 		RETURN_ERROR("items > 0 but menurows == 0, probably terminal "\
513c76f0793SBaptiste Daroussin 		    "too small");
514c76f0793SBaptiste Daroussin 
515c76f0793SBaptiste Daroussin 	menusize = nitems > 0 ? 3 : 0;
516c76f0793SBaptiste Daroussin 	if (rows < 2  + 2 + menusize + textrow)
517c76f0793SBaptiste Daroussin 		RETURN_ERROR("Few lines for this menus");
518c76f0793SBaptiste Daroussin 
519c76f0793SBaptiste Daroussin 	return 0;
520c76f0793SBaptiste Daroussin }
521c76f0793SBaptiste Daroussin 
522c76f0793SBaptiste Daroussin /* the caller has to call prefresh(menupad, ymenupad, 0, ys, xs, ye, xe); */
523c76f0793SBaptiste Daroussin static void
524f499134dSBaptiste Daroussin update_menuwin(struct bsddialog_conf *conf, WINDOW *menuwin, int h, int w,
525c76f0793SBaptiste Daroussin     int totnitems, unsigned int menurows, int ymenupad)
526c76f0793SBaptiste Daroussin {
527c76f0793SBaptiste Daroussin 
528c76f0793SBaptiste Daroussin 	draw_borders(conf, menuwin, h, w, LOWERED);
529c76f0793SBaptiste Daroussin 
5308c4f4028SBaptiste Daroussin 	if (totnitems > (int) menurows) {
531f499134dSBaptiste Daroussin 		wattron(menuwin, t.menu.arrowcolor);
532f499134dSBaptiste Daroussin 
533f499134dSBaptiste Daroussin 		if (ymenupad > 0)
534f499134dSBaptiste Daroussin 			mvwprintw(menuwin, 0, 2, "^^^");
535f499134dSBaptiste Daroussin 
536f499134dSBaptiste Daroussin 		if ((int) (ymenupad + menurows) < totnitems)
537f499134dSBaptiste Daroussin 			mvwprintw(menuwin, h-1, 2, "vvv");
538f499134dSBaptiste Daroussin 
539f499134dSBaptiste Daroussin 		wattroff(menuwin, t.menu.arrowcolor);
540c76f0793SBaptiste Daroussin 
541c76f0793SBaptiste Daroussin 		mvwprintw(menuwin, h-1, w-10, "%3d%%",
542c76f0793SBaptiste Daroussin 		    100 * (ymenupad + menurows) / totnitems);
543c76f0793SBaptiste Daroussin 	}
544c76f0793SBaptiste Daroussin }
545c76f0793SBaptiste Daroussin 
546c76f0793SBaptiste Daroussin static int
547f499134dSBaptiste Daroussin do_mixedlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
548c76f0793SBaptiste Daroussin     unsigned int menurows, enum menumode mode, int ngroups,
549c76f0793SBaptiste Daroussin     struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
550c76f0793SBaptiste Daroussin {
551c76f0793SBaptiste Daroussin 	WINDOW  *shadow, *widget, *textpad, *menuwin, *menupad;
552c76f0793SBaptiste Daroussin 	int i, j, y, x, h, w, htextpad, output, input;
553c76f0793SBaptiste Daroussin 	int ymenupad, ys, ye, xs, xe, abs, g, rel, totnitems;
5548c4f4028SBaptiste Daroussin 	bool loop, automenurows, shortcut_buttons;
555c76f0793SBaptiste Daroussin 	struct buttons bs;
556c76f0793SBaptiste Daroussin 	struct bsddialog_menuitem *item;
557c76f0793SBaptiste Daroussin 	enum menumode currmode;
558c76f0793SBaptiste Daroussin 	struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
559c76f0793SBaptiste Daroussin 
5608c4f4028SBaptiste Daroussin 	shortcut_buttons = conf->menu.shortcut_buttons;
5618c4f4028SBaptiste Daroussin 
562c76f0793SBaptiste Daroussin 	automenurows = menurows == BSDDIALOG_AUTOSIZE ? true : false;
563c76f0793SBaptiste Daroussin 
564c76f0793SBaptiste Daroussin 	totnitems = 0;
565c76f0793SBaptiste Daroussin 	for (i=0; i < ngroups; i++) {
566c76f0793SBaptiste Daroussin 		currmode = getmode(mode, groups[i]);
567c76f0793SBaptiste Daroussin 		if (currmode == RADIOLISTMODE)
568c76f0793SBaptiste Daroussin 			checkradiolist(groups[i].nitems, groups[i].items);
569c76f0793SBaptiste Daroussin 
570c76f0793SBaptiste Daroussin 		if (currmode == MENUMODE)
571c76f0793SBaptiste Daroussin 			checkmenu(groups[i].nitems, groups[i].items);
572c76f0793SBaptiste Daroussin 
573c76f0793SBaptiste Daroussin 		if (currmode == RADIOLISTMODE || currmode == CHECKLISTMODE)
574c76f0793SBaptiste Daroussin 			pos.selectorlen = 3;
575c76f0793SBaptiste Daroussin 
576c76f0793SBaptiste Daroussin 		for (j=0; j < (int) groups[i].nitems; j++) {
577c76f0793SBaptiste Daroussin 			totnitems++;
578c76f0793SBaptiste Daroussin 			item = &groups[i].items[j];
579c76f0793SBaptiste Daroussin 
580c76f0793SBaptiste Daroussin 			if (groups[i].type == BSDDIALOG_SEPARATOR) {
581c76f0793SBaptiste Daroussin 				pos.maxsepstr = MAX(pos.maxsepstr,
582c76f0793SBaptiste Daroussin 				    strlen(item->name) + strlen(item->desc));
583c76f0793SBaptiste Daroussin 				continue;
584c76f0793SBaptiste Daroussin 			}
585c76f0793SBaptiste Daroussin 
586c76f0793SBaptiste Daroussin 			pos.maxprefix = MAX(pos.maxprefix, strlen(item->prefix));
5878c4f4028SBaptiste Daroussin 			pos.maxdepth  = MAX(pos.maxdepth, item->depth);
588c76f0793SBaptiste Daroussin 			pos.maxname   = MAX(pos.maxname, strlen(item->name));
589c76f0793SBaptiste Daroussin 			pos.maxdesc   = MAX(pos.maxdesc, strlen(item->desc));
590c76f0793SBaptiste Daroussin 		}
591c76f0793SBaptiste Daroussin 	}
592f499134dSBaptiste Daroussin 	pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
593f499134dSBaptiste Daroussin 	pos.maxdesc = conf->menu.no_desc ? 0 : pos.maxdesc;
594c76f0793SBaptiste Daroussin 	pos.maxdepth *= DEPTHSPACE;
595c76f0793SBaptiste Daroussin 
596c76f0793SBaptiste Daroussin 	pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
597c76f0793SBaptiste Daroussin 	pos.xname = pos.xselector + pos.selectorlen + (pos.selectorlen > 0 ? 1 : 0);
598c76f0793SBaptiste Daroussin 	pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
599c76f0793SBaptiste Daroussin 	pos.xdesc += (pos.maxname != 0 ? 1 : 0);
600c76f0793SBaptiste Daroussin 	pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
601c76f0793SBaptiste Daroussin 
602c76f0793SBaptiste Daroussin 
603c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
604c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
605c76f0793SBaptiste Daroussin 
606c76f0793SBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
607c76f0793SBaptiste Daroussin 		return BSDDIALOG_ERROR;
608c76f0793SBaptiste Daroussin 	menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
609c76f0793SBaptiste Daroussin 	    totnitems, bs);
610c76f0793SBaptiste Daroussin 	if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
611c76f0793SBaptiste Daroussin 		return BSDDIALOG_ERROR;
612c76f0793SBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
613c76f0793SBaptiste Daroussin 		return BSDDIALOG_ERROR;
614c76f0793SBaptiste Daroussin 
615c76f0793SBaptiste Daroussin 	if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
616c76f0793SBaptiste Daroussin 	    &textpad, &htextpad, text, true) != 0)
617c76f0793SBaptiste Daroussin 		return BSDDIALOG_ERROR;
618c76f0793SBaptiste Daroussin 
619f499134dSBaptiste Daroussin 	prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
620f499134dSBaptiste Daroussin 	    y + h - menurows, x + 1 + w - t.text.hmargin);
621c76f0793SBaptiste Daroussin 
622c76f0793SBaptiste Daroussin 	menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
623c76f0793SBaptiste Daroussin 	    menurows+2, w-4, LOWERED);
624c76f0793SBaptiste Daroussin 
625c76f0793SBaptiste Daroussin 	menupad = newpad(totnitems, pos.line);
6268c4f4028SBaptiste Daroussin 	wbkgd(menupad, t.dialog.color);
627c76f0793SBaptiste Daroussin 
628c76f0793SBaptiste Daroussin 	ymenupad = 0;
629c76f0793SBaptiste Daroussin 	for (i=0; i<ngroups; i++) {
630c76f0793SBaptiste Daroussin 		currmode = getmode(mode, groups[i]);
631c76f0793SBaptiste Daroussin 		for (j=0; j < (int) groups[i].nitems; j++) {
632c76f0793SBaptiste Daroussin 			item = &groups[i].items[j];
6338c4f4028SBaptiste Daroussin 			drawitem(conf, menupad, ymenupad, *item, currmode, pos,
6348c4f4028SBaptiste Daroussin 			    false);
635c76f0793SBaptiste Daroussin 			ymenupad++;
636c76f0793SBaptiste Daroussin 		}
637c76f0793SBaptiste Daroussin 	}
6388c4f4028SBaptiste Daroussin 	getfirst_with_default(conf, ngroups, groups, &abs, &g, &rel);
6398c4f4028SBaptiste Daroussin 	currmode = getmode(mode, groups[g]);
6408c4f4028SBaptiste Daroussin 	item = &groups[g].items[rel];
6418c4f4028SBaptiste Daroussin 	drawitem(conf, menupad, abs, *item, currmode, pos, true);
642c76f0793SBaptiste Daroussin 
643c76f0793SBaptiste Daroussin 	ys = y + h - 5 - menurows + 1;
644c76f0793SBaptiste Daroussin 	ye = y + h - 5 ;
645f499134dSBaptiste Daroussin 	if (conf->menu.align_left || (int)pos.line > w - 6) {
646c76f0793SBaptiste Daroussin 		xs = x + 3;
647c76f0793SBaptiste Daroussin 		xe = xs + w - 7;
648c76f0793SBaptiste Daroussin 	}
649c76f0793SBaptiste Daroussin 	else { /* center */
650c76f0793SBaptiste Daroussin 		xs = x + 3 + (w-6)/2 - pos.line/2;
651c76f0793SBaptiste Daroussin 		xe = xs + w - 5;
652c76f0793SBaptiste Daroussin 	}
653c76f0793SBaptiste Daroussin 
654c76f0793SBaptiste Daroussin 	ymenupad = 0; /* now ymenupad is pminrow for prefresh() */
655c76f0793SBaptiste Daroussin 	if ((int)(ymenupad + menurows) - 1 < abs)
656c76f0793SBaptiste Daroussin 		ymenupad = abs - menurows + 1;
657c76f0793SBaptiste Daroussin 	update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows, ymenupad);
658c76f0793SBaptiste Daroussin 	wrefresh(menuwin);
659c76f0793SBaptiste Daroussin 	prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
660c76f0793SBaptiste Daroussin 
6618c4f4028SBaptiste Daroussin 	draw_buttons(widget, h-2, w, bs, shortcut_buttons);
662c76f0793SBaptiste Daroussin 	wrefresh(widget);
663c76f0793SBaptiste Daroussin 
664c76f0793SBaptiste Daroussin 	loop = true;
665c76f0793SBaptiste Daroussin 	while(loop) {
666c76f0793SBaptiste Daroussin 		input = getch();
667c76f0793SBaptiste Daroussin 		switch(input) {
668c76f0793SBaptiste Daroussin 		case KEY_ENTER:
669c76f0793SBaptiste Daroussin 		case 10: /* Enter */
670c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
671c76f0793SBaptiste Daroussin 			if (currmode == MENUMODE)
672c76f0793SBaptiste Daroussin 				item->on = true;
673c76f0793SBaptiste Daroussin 			loop = false;
674c76f0793SBaptiste Daroussin 			break;
675c76f0793SBaptiste Daroussin 		case 27: /* Esc */
676c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
677c76f0793SBaptiste Daroussin 			loop = false;
678c76f0793SBaptiste Daroussin 			break;
679c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
680c76f0793SBaptiste Daroussin 			bs.curr = (bs.curr + 1) % bs.nbuttons;
6818c4f4028SBaptiste Daroussin 			draw_buttons(widget, h-2, w, bs, shortcut_buttons);
682c76f0793SBaptiste Daroussin 			wrefresh(widget);
683c76f0793SBaptiste Daroussin 			break;
684c76f0793SBaptiste Daroussin 		case KEY_LEFT:
685c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
686c76f0793SBaptiste Daroussin 				bs.curr--;
6878c4f4028SBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, shortcut_buttons);
688c76f0793SBaptiste Daroussin 				wrefresh(widget);
689c76f0793SBaptiste Daroussin 			}
690c76f0793SBaptiste Daroussin 			break;
691c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
692c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
693c76f0793SBaptiste Daroussin 				bs.curr++;
6948c4f4028SBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, shortcut_buttons);
695c76f0793SBaptiste Daroussin 				wrefresh(widget);
696c76f0793SBaptiste Daroussin 			}
697c76f0793SBaptiste Daroussin 			break;
698f499134dSBaptiste Daroussin 		case KEY_CTRL('E'): /* add conf->menu.extrahelpkey ? */
699c76f0793SBaptiste Daroussin 		case KEY_F(1):
7008c4f4028SBaptiste Daroussin 			if (conf->f1_file == NULL && conf->f1_message == NULL)
701c76f0793SBaptiste Daroussin 				break;
702c76f0793SBaptiste Daroussin 			if (f1help(conf) != 0)
703c76f0793SBaptiste Daroussin 				return BSDDIALOG_ERROR;
704c76f0793SBaptiste Daroussin 			/* No break! the terminal size can change */
705c76f0793SBaptiste Daroussin 		case KEY_RESIZE:
706f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w,conf->shadow);
707c76f0793SBaptiste Daroussin 
708c76f0793SBaptiste Daroussin 			/*
709c76f0793SBaptiste Daroussin 			 * Unnecessary, but, when the columns decrease the
710c76f0793SBaptiste Daroussin 			 * following "refresh" seem not work
711c76f0793SBaptiste Daroussin 			 */
712c76f0793SBaptiste Daroussin 			refresh();
713c76f0793SBaptiste Daroussin 
714c76f0793SBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
715c76f0793SBaptiste Daroussin 				return BSDDIALOG_ERROR;
716c76f0793SBaptiste Daroussin 			menurows = automenurows ? 0 : menurows;
717c76f0793SBaptiste Daroussin 			menu_autosize(conf, rows, cols, &h, &w, text, pos.line,
718c76f0793SBaptiste Daroussin 			    &menurows, totnitems, bs);
719c76f0793SBaptiste Daroussin 			if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
720c76f0793SBaptiste Daroussin 				return BSDDIALOG_ERROR;
721c76f0793SBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
722c76f0793SBaptiste Daroussin 				return BSDDIALOG_ERROR;
723c76f0793SBaptiste Daroussin 
724c76f0793SBaptiste Daroussin 			wclear(shadow);
725f499134dSBaptiste Daroussin 			mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
726c76f0793SBaptiste Daroussin 			wresize(shadow, h, w);
727c76f0793SBaptiste Daroussin 
728c76f0793SBaptiste Daroussin 			wclear(widget);
729c76f0793SBaptiste Daroussin 			mvwin(widget, y, x);
730c76f0793SBaptiste Daroussin 			wresize(widget, h, w);
731c76f0793SBaptiste Daroussin 
732c76f0793SBaptiste Daroussin 			htextpad = 1;
733c76f0793SBaptiste Daroussin 			wclear(textpad);
734f499134dSBaptiste Daroussin 			wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
735c76f0793SBaptiste Daroussin 
736c76f0793SBaptiste Daroussin 			if(update_widget_withtextpad(conf, shadow, widget, h, w,
737c76f0793SBaptiste Daroussin 			    RAISED, textpad, &htextpad, text, true) != 0)
738c76f0793SBaptiste Daroussin 			return BSDDIALOG_ERROR;
739c76f0793SBaptiste Daroussin 
7408c4f4028SBaptiste Daroussin 			draw_buttons(widget, h-2, w, bs, shortcut_buttons);
741c76f0793SBaptiste Daroussin 			wrefresh(widget);
742c76f0793SBaptiste Daroussin 
743f499134dSBaptiste Daroussin 			prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
744f499134dSBaptiste Daroussin 			    y + h - menurows, x + 1 + w - t.text.hmargin);
745c76f0793SBaptiste Daroussin 
746c76f0793SBaptiste Daroussin 			wclear(menuwin);
747c76f0793SBaptiste Daroussin 			mvwin(menuwin, y + h - 5 - menurows, x + 2);
748c76f0793SBaptiste Daroussin 			wresize(menuwin,menurows+2, w-4);
749c76f0793SBaptiste Daroussin 			update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
750c76f0793SBaptiste Daroussin 			    menurows, ymenupad);
751c76f0793SBaptiste Daroussin 			wrefresh(menuwin);
752c76f0793SBaptiste Daroussin 
753c76f0793SBaptiste Daroussin 			ys = y + h - 5 - menurows + 1;
754c76f0793SBaptiste Daroussin 			ye = y + h - 5 ;
755f499134dSBaptiste Daroussin 			if (conf->menu.align_left || (int)pos.line > w - 6) {
756c76f0793SBaptiste Daroussin 				xs = x + 3;
757c76f0793SBaptiste Daroussin 				xe = xs + w - 7;
758c76f0793SBaptiste Daroussin 			}
759c76f0793SBaptiste Daroussin 			else { /* center */
760c76f0793SBaptiste Daroussin 				xs = x + 3 + (w-6)/2 - pos.line/2;
761c76f0793SBaptiste Daroussin 				xe = xs + w - 5;
762c76f0793SBaptiste Daroussin 			}
763c76f0793SBaptiste Daroussin 
764c76f0793SBaptiste Daroussin 			if ((int)(ymenupad + menurows) - 1 < abs)
765c76f0793SBaptiste Daroussin 				ymenupad = abs - menurows + 1;
766c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
767c76f0793SBaptiste Daroussin 
768c76f0793SBaptiste Daroussin 			refresh();
769c76f0793SBaptiste Daroussin 
770c76f0793SBaptiste Daroussin 			break;
771c76f0793SBaptiste Daroussin 		}
772c76f0793SBaptiste Daroussin 
773c76f0793SBaptiste Daroussin 		if (abs < 0)
774c76f0793SBaptiste Daroussin 			continue;
775c76f0793SBaptiste Daroussin 		switch(input) {
776c76f0793SBaptiste Daroussin 		case KEY_HOME:
777c76f0793SBaptiste Daroussin 		case KEY_UP:
778c76f0793SBaptiste Daroussin 		case KEY_PPAGE:
779c76f0793SBaptiste Daroussin 			if (abs == 0) /* useless, just to save cpu refresh */
780c76f0793SBaptiste Daroussin 				break;
781c76f0793SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, false);
782c76f0793SBaptiste Daroussin 			if (input == KEY_HOME)
783c76f0793SBaptiste Daroussin 				getfirst(ngroups, groups, &abs, &g, &rel);
784c76f0793SBaptiste Daroussin 			else if (input == KEY_UP)
785c76f0793SBaptiste Daroussin 				getprev(groups, &abs, &g, &rel);
786c76f0793SBaptiste Daroussin 			else /* input == KEY_PPAGE*/
787c76f0793SBaptiste Daroussin 				getfastprev(menurows, groups, &abs, &g, &rel);
788c76f0793SBaptiste Daroussin 			item = &groups[g].items[rel];
789c76f0793SBaptiste Daroussin 			currmode= getmode(mode, groups[g]);
790c76f0793SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, true);
791c76f0793SBaptiste Daroussin 			if (ymenupad > abs && ymenupad > 0)
792c76f0793SBaptiste Daroussin 				ymenupad = abs;
793c76f0793SBaptiste Daroussin 			update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
794c76f0793SBaptiste Daroussin 			    menurows, ymenupad);
795c76f0793SBaptiste Daroussin 			wrefresh(menuwin);
796c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
797c76f0793SBaptiste Daroussin 			break;
798c76f0793SBaptiste Daroussin 		case KEY_END:
799c76f0793SBaptiste Daroussin 		case KEY_DOWN:
800c76f0793SBaptiste Daroussin 		case KEY_NPAGE:
801c76f0793SBaptiste Daroussin 			if (abs == totnitems -1)
802c76f0793SBaptiste Daroussin 				break; /* useless, just to save cpu refresh */
803c76f0793SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, false);
804c76f0793SBaptiste Daroussin 			if (input == KEY_END)
805c76f0793SBaptiste Daroussin 				getlast(totnitems, ngroups, groups, &abs, &g, &rel);
806c76f0793SBaptiste Daroussin 			else if (input == KEY_DOWN)
807c76f0793SBaptiste Daroussin 				getnext(ngroups, groups, &abs, &g, &rel);
808c76f0793SBaptiste Daroussin 			else /* input == KEY_NPAGE*/
809c76f0793SBaptiste Daroussin 				getfastnext(menurows, ngroups, groups, &abs, &g, &rel);
810c76f0793SBaptiste Daroussin 			item = &groups[g].items[rel];
811c76f0793SBaptiste Daroussin 			currmode= getmode(mode, groups[g]);
812c76f0793SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, true);
813c76f0793SBaptiste Daroussin 			if ((int)(ymenupad + menurows) <= abs)
814c76f0793SBaptiste Daroussin 				ymenupad = abs - menurows + 1;
815c76f0793SBaptiste Daroussin 			update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
816c76f0793SBaptiste Daroussin 			    menurows, ymenupad);
817c76f0793SBaptiste Daroussin 			wrefresh(menuwin);
818c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
819c76f0793SBaptiste Daroussin 			break;
820c76f0793SBaptiste Daroussin 		case ' ': /* Space */
821c76f0793SBaptiste Daroussin 			if (currmode == MENUMODE)
822c76f0793SBaptiste Daroussin 				break;
823c76f0793SBaptiste Daroussin 			else if (currmode == CHECKLISTMODE)
824c76f0793SBaptiste Daroussin 				item->on = !item->on;
825c76f0793SBaptiste Daroussin 			else { /* RADIOLISTMODE */
826c76f0793SBaptiste Daroussin 				for (i=0; i < (int) groups[g].nitems; i++)
827f499134dSBaptiste Daroussin 					if (groups[g].items[i].on == true && i != rel) {
828c76f0793SBaptiste Daroussin 						groups[g].items[i].on = false;
829c76f0793SBaptiste Daroussin 						drawitem(conf, menupad,
830c76f0793SBaptiste Daroussin 						    abs - rel + i, groups[g].items[i],
831c76f0793SBaptiste Daroussin 						    currmode, pos, false);
832c76f0793SBaptiste Daroussin 					}
833f499134dSBaptiste Daroussin 				item->on = !item->on;
834c76f0793SBaptiste Daroussin 			}
835c76f0793SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, true);
836c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
8378c4f4028SBaptiste Daroussin 		default:
8388c4f4028SBaptiste Daroussin 			if (shortcut_buttons) {
8398c4f4028SBaptiste Daroussin 				for (i = 0; i < (int) bs.nbuttons; i++)
8408c4f4028SBaptiste Daroussin 					if (tolower(input) == tolower((bs.label[i])[0])) {
8418c4f4028SBaptiste Daroussin 						output = bs.value[i];
8428c4f4028SBaptiste Daroussin 						if (currmode == MENUMODE)
8438c4f4028SBaptiste Daroussin 							item->on = true;
8448c4f4028SBaptiste Daroussin 						loop = false;
8458c4f4028SBaptiste Daroussin 					}
8468c4f4028SBaptiste Daroussin 				break;
8478c4f4028SBaptiste Daroussin 			}
8488c4f4028SBaptiste Daroussin 
8498c4f4028SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, false);
8508c4f4028SBaptiste Daroussin 			getnextshortcut(conf, currmode, ngroups, groups, &abs,
8518c4f4028SBaptiste Daroussin 			    &g, &rel, input);
8528c4f4028SBaptiste Daroussin 			item = &groups[g].items[rel];
8538c4f4028SBaptiste Daroussin 			currmode = getmode(mode, groups[g]);
8548c4f4028SBaptiste Daroussin 			drawitem(conf, menupad, abs, *item, currmode, pos, true);
8558c4f4028SBaptiste Daroussin 			if (ymenupad > abs && ymenupad > 0)
8568c4f4028SBaptiste Daroussin 				ymenupad = abs;
8578c4f4028SBaptiste Daroussin 			if ((int)(ymenupad + menurows) <= abs)
8588c4f4028SBaptiste Daroussin 				ymenupad = abs - menurows + 1;
8598c4f4028SBaptiste Daroussin 			update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
8608c4f4028SBaptiste Daroussin 			    menurows, ymenupad);
8618c4f4028SBaptiste Daroussin 			wrefresh(menuwin);
8628c4f4028SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
863c76f0793SBaptiste Daroussin 		}
864c76f0793SBaptiste Daroussin 	}
865c76f0793SBaptiste Daroussin 
866c76f0793SBaptiste Daroussin 	if (focuslist != NULL)
867c76f0793SBaptiste Daroussin 		*focuslist = g;
868c76f0793SBaptiste Daroussin 	if (focusitem !=NULL)
869c76f0793SBaptiste Daroussin 		*focusitem = rel;
870c76f0793SBaptiste Daroussin 
871c76f0793SBaptiste Daroussin 	delwin(menupad);
872c76f0793SBaptiste Daroussin 	delwin(menuwin);
873c76f0793SBaptiste Daroussin 	end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
874c76f0793SBaptiste Daroussin 
875c76f0793SBaptiste Daroussin 	return output;
876c76f0793SBaptiste Daroussin }
877c76f0793SBaptiste Daroussin 
878c76f0793SBaptiste Daroussin /*
879c76f0793SBaptiste Daroussin  * API
880c76f0793SBaptiste Daroussin  */
881c76f0793SBaptiste Daroussin 
882f499134dSBaptiste Daroussin int bsddialog_mixedlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
883c76f0793SBaptiste Daroussin     unsigned int menurows, int ngroups, struct bsddialog_menugroup *groups,
884c76f0793SBaptiste Daroussin     int *focuslist, int *focusitem)
885c76f0793SBaptiste Daroussin {
886c76f0793SBaptiste Daroussin 	int output;
887c76f0793SBaptiste Daroussin 
888c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
889c76f0793SBaptiste Daroussin 	    ngroups, groups, focuslist, focusitem);
890c76f0793SBaptiste Daroussin 
891c76f0793SBaptiste Daroussin 	return output;
892c76f0793SBaptiste Daroussin }
893c76f0793SBaptiste Daroussin 
894c76f0793SBaptiste Daroussin int
895f499134dSBaptiste Daroussin bsddialog_checklist(struct bsddialog_conf *conf, char* text, int rows, int cols,
896c76f0793SBaptiste Daroussin     unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
897c76f0793SBaptiste Daroussin     int *focusitem)
898c76f0793SBaptiste Daroussin {
899c76f0793SBaptiste Daroussin 	int output;
900c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
901c76f0793SBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items};
902c76f0793SBaptiste Daroussin 
903c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
904c76f0793SBaptiste Daroussin 	    1, &group, NULL, focusitem);
905c76f0793SBaptiste Daroussin 
906c76f0793SBaptiste Daroussin 	return output;
907c76f0793SBaptiste Daroussin }
908c76f0793SBaptiste Daroussin 
909c76f0793SBaptiste Daroussin int
910f499134dSBaptiste Daroussin bsddialog_menu(struct bsddialog_conf *conf, char* text, int rows, int cols,
911c76f0793SBaptiste Daroussin     unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
912c76f0793SBaptiste Daroussin     int *focusitem)
913c76f0793SBaptiste Daroussin {
914c76f0793SBaptiste Daroussin 	int output;
915c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
916c76f0793SBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items};
917c76f0793SBaptiste Daroussin 
918c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
919c76f0793SBaptiste Daroussin 	    &group, NULL, focusitem);
920c76f0793SBaptiste Daroussin 
921c76f0793SBaptiste Daroussin 	return output;
922c76f0793SBaptiste Daroussin }
923c76f0793SBaptiste Daroussin 
924c76f0793SBaptiste Daroussin int
925f499134dSBaptiste Daroussin bsddialog_radiolist(struct bsddialog_conf *conf, char* text, int rows, int cols,
926c76f0793SBaptiste Daroussin     unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
927c76f0793SBaptiste Daroussin     int *focusitem)
928c76f0793SBaptiste Daroussin {
929c76f0793SBaptiste Daroussin 	int output;
930c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
931c76f0793SBaptiste Daroussin 	    BSDDIALOG_RADIOLIST /* unused */, nitems, items};
932c76f0793SBaptiste Daroussin 
933c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
934c76f0793SBaptiste Daroussin 	    1, &group, NULL, focusitem);
935c76f0793SBaptiste Daroussin 
936c76f0793SBaptiste Daroussin 	return output;
937c76f0793SBaptiste Daroussin }
938c76f0793SBaptiste Daroussin 
939f499134dSBaptiste Daroussin /* todo */
940f499134dSBaptiste Daroussin static int buildlist_autosize(int rows, int cols)
941c76f0793SBaptiste Daroussin {
942c76f0793SBaptiste Daroussin 
943f499134dSBaptiste Daroussin 	if (cols == BSDDIALOG_AUTOSIZE)
944f499134dSBaptiste Daroussin 		RETURN_ERROR("Unimplemented cols autosize for buildlist");
945c76f0793SBaptiste Daroussin 
946f499134dSBaptiste Daroussin 	if (rows == BSDDIALOG_AUTOSIZE)
947f499134dSBaptiste Daroussin 		RETURN_ERROR("Unimplemented rows autosize for buildlist");
948c76f0793SBaptiste Daroussin 
949f499134dSBaptiste Daroussin 	return 0;
950f499134dSBaptiste Daroussin }
951f499134dSBaptiste Daroussin 
952f499134dSBaptiste Daroussin /* to improve */
953f499134dSBaptiste Daroussin static int
954f499134dSBaptiste Daroussin buildlist_checksize(int rows, int cols, char *text, int menurows, int nitems,
955f499134dSBaptiste Daroussin     struct buttons bs)
956f499134dSBaptiste Daroussin {
957f499134dSBaptiste Daroussin 	int mincols, textrow, menusize;
958f499134dSBaptiste Daroussin 
959f499134dSBaptiste Daroussin 	mincols = VBORDERS;
960f499134dSBaptiste Daroussin 	/* buttons */
961f499134dSBaptiste Daroussin 	mincols += bs.nbuttons * bs.sizebutton;
962f499134dSBaptiste Daroussin 	mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
963f499134dSBaptiste Daroussin 	/* line, comment to permet some cols hidden */
964f499134dSBaptiste Daroussin 	/* mincols = MAX(mincols, linelen); */
965f499134dSBaptiste Daroussin 
966f499134dSBaptiste Daroussin 	if (cols < mincols)
967f499134dSBaptiste Daroussin 		RETURN_ERROR("Few cols, width < size buttons or "\
968f499134dSBaptiste Daroussin 		    "name+descripion of the items");
969f499134dSBaptiste Daroussin 
970f499134dSBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
971f499134dSBaptiste Daroussin 
972f499134dSBaptiste Daroussin 	if (nitems > 0 && menurows == 0)
973f499134dSBaptiste Daroussin 		RETURN_ERROR("items > 0 but menurows == 0, probably terminal "\
974f499134dSBaptiste Daroussin 		    "too small");
975f499134dSBaptiste Daroussin 
976f499134dSBaptiste Daroussin 	menusize = nitems > 0 ? 3 : 0;
977f499134dSBaptiste Daroussin 	if (rows < 2 + 2 + menusize + textrow)
978f499134dSBaptiste Daroussin 		RETURN_ERROR("Few lines for this menus");
979f499134dSBaptiste Daroussin 
980f499134dSBaptiste Daroussin 	return 0;
981c76f0793SBaptiste Daroussin }
982c76f0793SBaptiste Daroussin 
983c76f0793SBaptiste Daroussin int
984f499134dSBaptiste Daroussin bsddialog_buildlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
985c76f0793SBaptiste Daroussin     unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
986c76f0793SBaptiste Daroussin     int *focusitem)
987c76f0793SBaptiste Daroussin {
988f499134dSBaptiste Daroussin 	WINDOW *widget, *textpad, *leftwin, *leftpad, *rightwin, *rightpad, *shadow;
989f499134dSBaptiste Daroussin 	int output, i, x, y, h, w, htextpad, input;
990c76f0793SBaptiste Daroussin 	bool loop, buttupdate, padsupdate, startleft;
991c76f0793SBaptiste Daroussin 	int nlefts, nrights, leftwinx, rightwinx, winsy, padscols, curr;
992c76f0793SBaptiste Daroussin 	enum side {LEFT, RIGHT} currV;
993c76f0793SBaptiste Daroussin 	int currH;
994c76f0793SBaptiste Daroussin 	struct buttons bs;
995c76f0793SBaptiste Daroussin 	struct lineposition pos = {0,0,0,0,0,0,0,0,0,0};
996c76f0793SBaptiste Daroussin 
997c76f0793SBaptiste Daroussin 	startleft = false;
998c76f0793SBaptiste Daroussin 	for (i=0; i<nitems; i++) {
999c76f0793SBaptiste Daroussin 		pos.line = MAX(pos.line, strlen(items[i].desc));
1000c76f0793SBaptiste Daroussin 		if (items[i].on == false)
1001c76f0793SBaptiste Daroussin 			startleft = true;
1002c76f0793SBaptiste Daroussin 	}
1003c76f0793SBaptiste Daroussin 
1004f499134dSBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
1005f499134dSBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
1006c76f0793SBaptiste Daroussin 
1007f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
1008f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
1009f499134dSBaptiste Daroussin 	if (buildlist_autosize(rows, cols) != 0)
1010f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
1011f499134dSBaptiste Daroussin 	if (buildlist_checksize(h, w, text, menurows, nitems, bs) != 0)
1012f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
1013f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
1014f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
1015f499134dSBaptiste Daroussin 
1016f499134dSBaptiste Daroussin 	if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
1017f499134dSBaptiste Daroussin 	    &textpad, &htextpad, text, true) != 0)
1018f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
1019f499134dSBaptiste Daroussin 
1020f499134dSBaptiste Daroussin 	prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
1021f499134dSBaptiste Daroussin 	    y + h - menurows, x + 1 + w - t.text.hmargin);
1022f499134dSBaptiste Daroussin 
1023f499134dSBaptiste Daroussin 	winsy = y + h - 5 - menurows;
1024c76f0793SBaptiste Daroussin 	leftwinx = x+2;
1025f499134dSBaptiste Daroussin 	leftwin = new_boxed_window(conf, winsy, leftwinx, menurows+2, (w-5)/2,
1026c76f0793SBaptiste Daroussin 	    LOWERED);
1027f499134dSBaptiste Daroussin 	rightwinx = x + w - 2 -(w-5)/2;
1028c76f0793SBaptiste Daroussin 	rightwin = new_boxed_window(conf, winsy, rightwinx, menurows+2,
1029f499134dSBaptiste Daroussin 	    (w-5)/2, LOWERED);
1030c76f0793SBaptiste Daroussin 
1031c76f0793SBaptiste Daroussin 	wrefresh(leftwin);
1032c76f0793SBaptiste Daroussin 	wrefresh(rightwin);
1033c76f0793SBaptiste Daroussin 
1034f499134dSBaptiste Daroussin 	padscols = (w-5)/2 - 2;
1035c76f0793SBaptiste Daroussin 	leftpad  = newpad(nitems, pos.line);
1036c76f0793SBaptiste Daroussin 	rightpad = newpad(nitems, pos.line);
10378c4f4028SBaptiste Daroussin 	wbkgd(leftpad, t.dialog.color);
10388c4f4028SBaptiste Daroussin 	wbkgd(rightpad, t.dialog.color);
1039c76f0793SBaptiste Daroussin 
1040c76f0793SBaptiste Daroussin 	currH = 0;
1041c76f0793SBaptiste Daroussin 	currV = startleft ? LEFT : RIGHT;
1042c76f0793SBaptiste Daroussin 	loop = buttupdate = padsupdate = true;
1043c76f0793SBaptiste Daroussin 	while(loop) {
1044c76f0793SBaptiste Daroussin 		if (buttupdate) {
1045f499134dSBaptiste Daroussin 			draw_buttons(widget, h-2, w, bs, true);
1046c76f0793SBaptiste Daroussin 			wrefresh(widget);
1047c76f0793SBaptiste Daroussin 			buttupdate = false;
1048c76f0793SBaptiste Daroussin 		}
1049c76f0793SBaptiste Daroussin 
1050c76f0793SBaptiste Daroussin 		if (padsupdate) {
1051c76f0793SBaptiste Daroussin 			werase(leftpad);
1052c76f0793SBaptiste Daroussin 			werase(rightpad);
1053c76f0793SBaptiste Daroussin 			curr = -1;
1054c76f0793SBaptiste Daroussin 			nlefts = nrights = 0;
1055c76f0793SBaptiste Daroussin 			for (i=0; i<nitems; i++) {
1056c76f0793SBaptiste Daroussin 				if (items[i].on == false) {
1057c76f0793SBaptiste Daroussin 					if (currV == LEFT && currH == nlefts)
1058c76f0793SBaptiste Daroussin 						curr = i;
1059c76f0793SBaptiste Daroussin 					drawitem(conf, leftpad, nlefts, items[i],
1060c76f0793SBaptiste Daroussin 					    BUILDLISTMODE, pos, curr == i);
1061c76f0793SBaptiste Daroussin 					nlefts++;
1062c76f0793SBaptiste Daroussin 				} else {
1063c76f0793SBaptiste Daroussin 					if (currV == RIGHT && currH == nrights)
1064c76f0793SBaptiste Daroussin 						curr = i;
1065c76f0793SBaptiste Daroussin 					drawitem(conf, rightpad, nrights, items[i],
1066c76f0793SBaptiste Daroussin 					    BUILDLISTMODE, pos, curr == i);
1067c76f0793SBaptiste Daroussin 					nrights++;
1068c76f0793SBaptiste Daroussin 				}
1069c76f0793SBaptiste Daroussin 			}
1070c76f0793SBaptiste Daroussin 			prefresh(leftpad, 0, 0, winsy+1, leftwinx+1,
1071c76f0793SBaptiste Daroussin 			    winsy+1+menurows, leftwinx + 1 + padscols);
1072c76f0793SBaptiste Daroussin 			prefresh(rightpad, 0, 0, winsy+1, rightwinx+1,
1073c76f0793SBaptiste Daroussin 			    winsy+1+menurows, rightwinx + 1 + padscols);
1074c76f0793SBaptiste Daroussin 			padsupdate = false;
1075c76f0793SBaptiste Daroussin 		}
1076c76f0793SBaptiste Daroussin 
1077c76f0793SBaptiste Daroussin 		input = getch();
1078c76f0793SBaptiste Daroussin 		switch(input) {
1079f499134dSBaptiste Daroussin 		case KEY_ENTER:
1080f499134dSBaptiste Daroussin 		case 10: /* Enter */
1081f499134dSBaptiste Daroussin 			output = bs.value[bs.curr];
1082c76f0793SBaptiste Daroussin 			loop = false;
1083c76f0793SBaptiste Daroussin 			break;
1084f499134dSBaptiste Daroussin 		case 27: /* Esc */
1085c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ERROR;
1086c76f0793SBaptiste Daroussin 			loop = false;
1087c76f0793SBaptiste Daroussin 			break;
1088f499134dSBaptiste Daroussin 		case '\t': /* TAB */
1089c76f0793SBaptiste Daroussin 			bs.curr = (bs.curr + 1) % bs.nbuttons;
1090c76f0793SBaptiste Daroussin 			buttupdate = true;
1091c76f0793SBaptiste Daroussin 			break;
1092c76f0793SBaptiste Daroussin 		}
1093c76f0793SBaptiste Daroussin 
1094c76f0793SBaptiste Daroussin 		if (nitems <= 0)
1095c76f0793SBaptiste Daroussin 			continue;
1096c76f0793SBaptiste Daroussin 
1097c76f0793SBaptiste Daroussin 		switch(input) {
1098c76f0793SBaptiste Daroussin 		case KEY_LEFT:
1099c76f0793SBaptiste Daroussin 			if (currV == RIGHT && nrights > 0) {
1100c76f0793SBaptiste Daroussin 				currV = LEFT;
1101c76f0793SBaptiste Daroussin 				currH = 0;
1102c76f0793SBaptiste Daroussin 				padsupdate = true;
1103c76f0793SBaptiste Daroussin 			}
1104c76f0793SBaptiste Daroussin 			break;
1105c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
1106c76f0793SBaptiste Daroussin 			if (currV == LEFT && nrights > 0) {
1107c76f0793SBaptiste Daroussin 				currV = RIGHT;
1108c76f0793SBaptiste Daroussin 				currH = 0;
1109c76f0793SBaptiste Daroussin 				padsupdate = true;
1110c76f0793SBaptiste Daroussin 			}
1111c76f0793SBaptiste Daroussin 			break;
1112c76f0793SBaptiste Daroussin 		case KEY_UP:
1113c76f0793SBaptiste Daroussin 			currH = (currH > 0) ? currH - 1 : 0;
1114c76f0793SBaptiste Daroussin 			padsupdate = true;
1115c76f0793SBaptiste Daroussin 			break;
1116c76f0793SBaptiste Daroussin 		case KEY_DOWN:
1117c76f0793SBaptiste Daroussin 			if (currV == LEFT)
1118c76f0793SBaptiste Daroussin 				currH = (currH < nlefts-1) ? currH +1 : currH;
1119c76f0793SBaptiste Daroussin 			else
1120c76f0793SBaptiste Daroussin 				currH = (currH < nrights-1)? currH +1 : currH;
1121c76f0793SBaptiste Daroussin 			padsupdate = true;
1122c76f0793SBaptiste Daroussin 			break;
1123f499134dSBaptiste Daroussin 		case ' ': /* Space */
1124c76f0793SBaptiste Daroussin 			items[curr].on = ! items[curr].on;
1125c76f0793SBaptiste Daroussin 			if (currV == LEFT) {
1126c76f0793SBaptiste Daroussin 				if (nlefts > 1)
1127c76f0793SBaptiste Daroussin 					currH = currH > 0 ? currH-1 : 0;
1128c76f0793SBaptiste Daroussin 				else {
1129c76f0793SBaptiste Daroussin 					currH = 0;
1130c76f0793SBaptiste Daroussin 					currV = RIGHT;
1131c76f0793SBaptiste Daroussin 				}
1132c76f0793SBaptiste Daroussin 			} else {
1133c76f0793SBaptiste Daroussin 				if (nrights > 1)
1134c76f0793SBaptiste Daroussin 					currH = currH > 0 ? currH-1 : 0;
1135c76f0793SBaptiste Daroussin 				else {
1136c76f0793SBaptiste Daroussin 					currH = 0;
1137c76f0793SBaptiste Daroussin 					currV = LEFT;
1138c76f0793SBaptiste Daroussin 				}
1139c76f0793SBaptiste Daroussin 			}
1140c76f0793SBaptiste Daroussin 			padsupdate = true;
1141c76f0793SBaptiste Daroussin 			break;
1142c76f0793SBaptiste Daroussin 		default:
1143c76f0793SBaptiste Daroussin 
1144c76f0793SBaptiste Daroussin 			break;
1145c76f0793SBaptiste Daroussin 		}
1146c76f0793SBaptiste Daroussin 	}
1147c76f0793SBaptiste Daroussin 
1148c76f0793SBaptiste Daroussin 	if(focusitem != NULL)
1149c76f0793SBaptiste Daroussin 		*focusitem = curr;
1150c76f0793SBaptiste Daroussin 
1151c76f0793SBaptiste Daroussin 	delwin(leftpad);
1152c76f0793SBaptiste Daroussin 	delwin(leftwin);
1153c76f0793SBaptiste Daroussin 	delwin(rightpad);
1154c76f0793SBaptiste Daroussin 	delwin(rightwin);
1155f499134dSBaptiste Daroussin 	end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
1156c76f0793SBaptiste Daroussin 
1157c76f0793SBaptiste Daroussin 	return output;
1158c76f0793SBaptiste Daroussin }
1159