xref: /freebsd/contrib/bsddialog/lib/menubox.c (revision bce40c02)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4263660c0SAlfonso Siciliano  * Copyright (c) 2021-2022 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>
31263660c0SAlfonso Siciliano #include <curses.h>
32263660c0SAlfonso Siciliano #include <stdlib.h>
33d93b4d32SBaptiste Daroussin #include <string.h>
34d93b4d32SBaptiste Daroussin 
35c76f0793SBaptiste Daroussin #include "bsddialog.h"
36c76f0793SBaptiste Daroussin #include "bsddialog_theme.h"
37263660c0SAlfonso Siciliano #include "lib_util.h"
38c76f0793SBaptiste Daroussin 
39*bce40c02SAlfonso S. Siciliano #define DEPTH       2
40c76f0793SBaptiste Daroussin #define MIN_HEIGHT  VBORDERS + 6 /* 2 buttons 1 text 3 menu */
41c76f0793SBaptiste Daroussin 
42c76f0793SBaptiste Daroussin enum menumode {
43c76f0793SBaptiste Daroussin 	CHECKLISTMODE,
44c76f0793SBaptiste Daroussin 	MENUMODE,
45c76f0793SBaptiste Daroussin 	MIXEDLISTMODE,
46c76f0793SBaptiste Daroussin 	RADIOLISTMODE,
47c76f0793SBaptiste Daroussin 	SEPARATORMODE
48c76f0793SBaptiste Daroussin };
49c76f0793SBaptiste Daroussin 
50c76f0793SBaptiste Daroussin struct lineposition {
51c76f0793SBaptiste Daroussin 	unsigned int maxsepstr;
52c76f0793SBaptiste Daroussin 	unsigned int maxprefix;
53c76f0793SBaptiste Daroussin 	unsigned int xselector;
54c76f0793SBaptiste Daroussin 	unsigned int selectorlen;
55c76f0793SBaptiste Daroussin 	unsigned int maxdepth;
56c76f0793SBaptiste Daroussin 	unsigned int xname;
57c76f0793SBaptiste Daroussin 	unsigned int maxname;
58c76f0793SBaptiste Daroussin 	unsigned int xdesc;
59c76f0793SBaptiste Daroussin 	unsigned int maxdesc;
60c76f0793SBaptiste Daroussin 	unsigned int line;
61c76f0793SBaptiste Daroussin };
62c76f0793SBaptiste Daroussin 
63263660c0SAlfonso Siciliano struct privateitem {
64263660c0SAlfonso Siciliano 	bool on;
65263660c0SAlfonso Siciliano 	int group;
66263660c0SAlfonso Siciliano 	int index;
67263660c0SAlfonso Siciliano 	enum menumode type;
68c76f0793SBaptiste Daroussin 	struct bsddialog_menuitem *item;
69263660c0SAlfonso Siciliano };
70c76f0793SBaptiste Daroussin 
71263660c0SAlfonso Siciliano static void
72263660c0SAlfonso Siciliano set_on_output(struct bsddialog_conf *conf, int output, int ngroups,
73263660c0SAlfonso Siciliano     struct bsddialog_menugroup *groups, struct privateitem *pritems)
74263660c0SAlfonso Siciliano {
75263660c0SAlfonso Siciliano 	int i, j, abs;
76263660c0SAlfonso Siciliano 
77263660c0SAlfonso Siciliano 	if (output != BSDDIALOG_OK && !conf->menu.on_without_ok)
78c76f0793SBaptiste Daroussin 		return;
79c76f0793SBaptiste Daroussin 
80263660c0SAlfonso Siciliano 	for(i = abs = 0; i < ngroups; i++) {
81c76f0793SBaptiste Daroussin 		if (groups[i].type == BSDDIALOG_SEPARATOR) {
82263660c0SAlfonso Siciliano 			abs += groups[i].nitems;
83c76f0793SBaptiste Daroussin 			continue;
84c76f0793SBaptiste Daroussin 		}
85263660c0SAlfonso Siciliano 
86c76f0793SBaptiste Daroussin 		for(j = 0; j < (int)groups[i].nitems; j++) {
87263660c0SAlfonso Siciliano 			groups[i].items[j].on = pritems[abs].on;
88263660c0SAlfonso Siciliano 			abs++;
89c76f0793SBaptiste Daroussin 		}
90c76f0793SBaptiste Daroussin 	}
91c76f0793SBaptiste Daroussin }
92c76f0793SBaptiste Daroussin 
93263660c0SAlfonso Siciliano static int getprev(struct privateitem *pritems, int abs)
94c76f0793SBaptiste Daroussin {
95263660c0SAlfonso Siciliano 	int i;
96c76f0793SBaptiste Daroussin 
97263660c0SAlfonso Siciliano 	for (i = abs - 1; i >= 0; i--) {
98263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
99c76f0793SBaptiste Daroussin 			continue;
100263660c0SAlfonso Siciliano 		return (i);
101c76f0793SBaptiste Daroussin 	}
102c76f0793SBaptiste Daroussin 
103263660c0SAlfonso Siciliano 	return (abs);
104263660c0SAlfonso Siciliano }
105263660c0SAlfonso Siciliano 
106263660c0SAlfonso Siciliano static int getnext(int npritems, struct privateitem *pritems, int abs)
107c76f0793SBaptiste Daroussin {
108263660c0SAlfonso Siciliano 	int i;
109c76f0793SBaptiste Daroussin 
110263660c0SAlfonso Siciliano 	for (i = abs + 1; i < npritems; i++) {
111263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
112c76f0793SBaptiste Daroussin 			continue;
113263660c0SAlfonso Siciliano 		return (i);
114c76f0793SBaptiste Daroussin 	}
115c76f0793SBaptiste Daroussin 
116263660c0SAlfonso Siciliano 	return (abs);
117263660c0SAlfonso Siciliano }
118263660c0SAlfonso Siciliano 
119263660c0SAlfonso Siciliano static int
120263660c0SAlfonso Siciliano getfirst_with_default(int npritems, struct privateitem *pritems, int ngroups,
121263660c0SAlfonso Siciliano     struct bsddialog_menugroup *groups, int *focusgroup, int *focusitem)
122263660c0SAlfonso Siciliano {
123263660c0SAlfonso Siciliano 	int i, abs;
124263660c0SAlfonso Siciliano 
125263660c0SAlfonso Siciliano 	if ((abs =  getnext(npritems, pritems, -1)) < 0)
126263660c0SAlfonso Siciliano 		return (abs);
127263660c0SAlfonso Siciliano 
128263660c0SAlfonso Siciliano 	if (focusgroup == NULL || focusitem == NULL)
129263660c0SAlfonso Siciliano 		return (abs);
130263660c0SAlfonso Siciliano 	if (*focusgroup < 0 || *focusgroup >= ngroups)
131263660c0SAlfonso Siciliano 		return (abs);
132263660c0SAlfonso Siciliano 	if (groups[*focusgroup].type == BSDDIALOG_SEPARATOR)
133263660c0SAlfonso Siciliano 		return (abs);
134263660c0SAlfonso Siciliano 	if (*focusitem < 0 || *focusitem >= (int)groups[*focusgroup].nitems)
135263660c0SAlfonso Siciliano 		return (abs);
136263660c0SAlfonso Siciliano 
137263660c0SAlfonso Siciliano 	for (i = abs; i < npritems; i++) {
138263660c0SAlfonso Siciliano 		if (pritems[i].group == *focusgroup &&
139263660c0SAlfonso Siciliano 		    pritems[i].index == *focusitem)
140263660c0SAlfonso Siciliano 			return (i);
141263660c0SAlfonso Siciliano 	}
142263660c0SAlfonso Siciliano 
143263660c0SAlfonso Siciliano 	return (abs);
144263660c0SAlfonso Siciliano }
145263660c0SAlfonso Siciliano 
146263660c0SAlfonso Siciliano static int
147263660c0SAlfonso Siciliano getfastnext(int menurows, int npritems, struct privateitem *pritems, int abs)
148c76f0793SBaptiste Daroussin {
149c76f0793SBaptiste Daroussin 	int a, start, i;
150c76f0793SBaptiste Daroussin 
151263660c0SAlfonso Siciliano 	start = abs;
152c76f0793SBaptiste Daroussin 	i = menurows;
153c76f0793SBaptiste Daroussin 	do {
154263660c0SAlfonso Siciliano 		a = abs;
155263660c0SAlfonso Siciliano 		abs = getnext(npritems, pritems, abs);
156c76f0793SBaptiste Daroussin 		i--;
157263660c0SAlfonso Siciliano 	} while (abs != a && abs < start + menurows && i > 0);
158263660c0SAlfonso Siciliano 
159263660c0SAlfonso Siciliano 	return (abs);
160c76f0793SBaptiste Daroussin }
161c76f0793SBaptiste Daroussin 
162263660c0SAlfonso Siciliano static int
163263660c0SAlfonso Siciliano getfastprev(int menurows, struct privateitem *pritems, int abs)
164c76f0793SBaptiste Daroussin {
165c76f0793SBaptiste Daroussin 	int a, start, i;
166c76f0793SBaptiste Daroussin 
167263660c0SAlfonso Siciliano 	start = abs;
168c76f0793SBaptiste Daroussin 	i = menurows;
169c76f0793SBaptiste Daroussin 	do {
170263660c0SAlfonso Siciliano 		a = abs;
171263660c0SAlfonso Siciliano 		abs = getprev(pritems, abs);
172c76f0793SBaptiste Daroussin 		i--;
173263660c0SAlfonso Siciliano 	} while (abs != a && abs > start - menurows && i > 0);
174263660c0SAlfonso Siciliano 
175263660c0SAlfonso Siciliano 	return (abs);
176c76f0793SBaptiste Daroussin }
177c76f0793SBaptiste Daroussin 
178263660c0SAlfonso Siciliano static int
179263660c0SAlfonso Siciliano getnextshortcut(struct bsddialog_conf *conf, int npritems,
180263660c0SAlfonso Siciliano     struct privateitem *pritems, int abs, int key)
1818c4f4028SBaptiste Daroussin {
182263660c0SAlfonso Siciliano 	int i, ch, next;
1838c4f4028SBaptiste Daroussin 
184263660c0SAlfonso Siciliano 	next = -1;
185263660c0SAlfonso Siciliano 	for (i = 0; i < npritems; i++) {
186263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
1878c4f4028SBaptiste Daroussin 			continue;
1888c4f4028SBaptiste Daroussin 
1898c4f4028SBaptiste Daroussin 		if (conf->menu.no_name)
190263660c0SAlfonso Siciliano 			ch = pritems[i].item->desc[0];
1918c4f4028SBaptiste Daroussin 		else
192263660c0SAlfonso Siciliano 			ch = pritems[i].item->name[0];
1938c4f4028SBaptiste Daroussin 
1948c4f4028SBaptiste Daroussin 		if (ch == key) {
195263660c0SAlfonso Siciliano 			if (i > abs)
196263660c0SAlfonso Siciliano 				return (i);
197263660c0SAlfonso Siciliano 
198263660c0SAlfonso Siciliano 			if (i < abs && next == -1)
199263660c0SAlfonso Siciliano 				next = i;
2008c4f4028SBaptiste Daroussin 		}
2018c4f4028SBaptiste Daroussin 	}
2028c4f4028SBaptiste Daroussin 
203263660c0SAlfonso Siciliano 	return (next != -1 ? next : abs);
2048c4f4028SBaptiste Daroussin }
2058c4f4028SBaptiste Daroussin 
206c76f0793SBaptiste Daroussin static enum menumode
207c76f0793SBaptiste Daroussin getmode(enum menumode mode, struct bsddialog_menugroup group)
208c76f0793SBaptiste Daroussin {
209c76f0793SBaptiste Daroussin 	if (mode == MIXEDLISTMODE) {
210c76f0793SBaptiste Daroussin 		if (group.type == BSDDIALOG_SEPARATOR)
211c76f0793SBaptiste Daroussin 			mode = SEPARATORMODE;
212c76f0793SBaptiste Daroussin 		else if (group.type == BSDDIALOG_RADIOLIST)
213c76f0793SBaptiste Daroussin 			mode = RADIOLISTMODE;
214c76f0793SBaptiste Daroussin 		else if (group.type == BSDDIALOG_CHECKLIST)
215c76f0793SBaptiste Daroussin 			mode = CHECKLISTMODE;
216c76f0793SBaptiste Daroussin 	}
217c76f0793SBaptiste Daroussin 
218263660c0SAlfonso Siciliano 	return (mode);
219c76f0793SBaptiste Daroussin }
220c76f0793SBaptiste Daroussin 
221c76f0793SBaptiste Daroussin static void
222*bce40c02SAlfonso S. Siciliano drawseparators(struct bsddialog_conf *conf, WINDOW *pad, int linelen,
223*bce40c02SAlfonso S. Siciliano     int nitems, struct privateitem *pritems)
224c76f0793SBaptiste Daroussin {
225*bce40c02SAlfonso S. Siciliano 	int i, linech, labellen;
226*bce40c02SAlfonso S. Siciliano 	const char *desc, *name;
227263660c0SAlfonso Siciliano 
228*bce40c02SAlfonso S. Siciliano 	for (i = 0; i < nitems; i++) {
229*bce40c02SAlfonso S. Siciliano 		if (pritems[i].type != SEPARATORMODE)
230*bce40c02SAlfonso S. Siciliano 			continue;
231f499134dSBaptiste Daroussin 		if (conf->no_lines == false) {
232f499134dSBaptiste Daroussin 			wattron(pad, t.menu.desccolor);
233f499134dSBaptiste Daroussin 			linech = conf->ascii_lines ? '-' : ACS_HLINE;
234*bce40c02SAlfonso S. Siciliano 			mvwhline(pad, i, 0, linech, linelen);
235f499134dSBaptiste Daroussin 			wattroff(pad, t.menu.desccolor);
236c76f0793SBaptiste Daroussin 		}
237*bce40c02SAlfonso S. Siciliano 		name = pritems[i].item->name;
238*bce40c02SAlfonso S. Siciliano 		desc = pritems[i].item->desc;
239*bce40c02SAlfonso S. Siciliano 		labellen = strlen(name) + strlen(desc) + 1;
240*bce40c02SAlfonso S. Siciliano 		wmove(pad, i, labellen < linelen ? linelen/2 - labellen/2 : 0);
241f499134dSBaptiste Daroussin 		wattron(pad, t.menu.namesepcolor);
242263660c0SAlfonso Siciliano 		waddstr(pad, name);
243f499134dSBaptiste Daroussin 		wattroff(pad, t.menu.namesepcolor);
244263660c0SAlfonso Siciliano 		if (strlen(name) > 0 && strlen(desc) > 0)
245c76f0793SBaptiste Daroussin 			waddch(pad, ' ');
246f499134dSBaptiste Daroussin 		wattron(pad, t.menu.descsepcolor);
247263660c0SAlfonso Siciliano 		waddstr(pad, desc);
248f499134dSBaptiste Daroussin 		wattroff(pad, t.menu.descsepcolor);
249*bce40c02SAlfonso S. Siciliano 	}
250c76f0793SBaptiste Daroussin }
251c76f0793SBaptiste Daroussin 
252*bce40c02SAlfonso S. Siciliano static void
253*bce40c02SAlfonso S. Siciliano drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
254*bce40c02SAlfonso S. Siciliano     struct lineposition pos, struct privateitem *pritem, bool focus)
255*bce40c02SAlfonso S. Siciliano {
256*bce40c02SAlfonso S. Siciliano 	int colordesc, colorname, colorshortcut;
257*bce40c02SAlfonso S. Siciliano 	const char *shortcut;
258*bce40c02SAlfonso S. Siciliano 	struct bsddialog_menuitem *item;
259*bce40c02SAlfonso S. Siciliano 
260*bce40c02SAlfonso S. Siciliano 	item = pritem->item;
261*bce40c02SAlfonso S. Siciliano 
262c76f0793SBaptiste Daroussin 	/* prefix */
263*bce40c02SAlfonso S. Siciliano 	if (item->prefix != NULL && item->prefix[0] != '\0')
264*bce40c02SAlfonso S. Siciliano 		mvwaddstr(pad, y, 0, item->prefix);
265c76f0793SBaptiste Daroussin 
266c76f0793SBaptiste Daroussin 	/* selector */
267c76f0793SBaptiste Daroussin 	wmove(pad, y, pos.xselector);
268*bce40c02SAlfonso S. Siciliano 	wattron(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
269*bce40c02SAlfonso S. Siciliano 	if (pritem->type == CHECKLISTMODE)
270263660c0SAlfonso Siciliano 		wprintw(pad, "[%c]", pritem->on ? 'X' : ' ');
271*bce40c02SAlfonso S. Siciliano 	if (pritem->type == RADIOLISTMODE)
272263660c0SAlfonso Siciliano 		wprintw(pad, "(%c)", pritem->on ? '*' : ' ');
273*bce40c02SAlfonso S. Siciliano 	wattroff(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
274c76f0793SBaptiste Daroussin 
275c76f0793SBaptiste Daroussin 	/* name */
276263660c0SAlfonso Siciliano 	colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
277263660c0SAlfonso Siciliano 	if (conf->menu.no_name == false) {
278c76f0793SBaptiste Daroussin 		wattron(pad, colorname);
279*bce40c02SAlfonso S. Siciliano 		mvwaddstr(pad, y, pos.xname + item->depth * DEPTH, item->name);
280c76f0793SBaptiste Daroussin 		wattroff(pad, colorname);
281c76f0793SBaptiste Daroussin 	}
282c76f0793SBaptiste Daroussin 
283c76f0793SBaptiste Daroussin 	/* description */
2848c4f4028SBaptiste Daroussin 	if (conf->menu.no_name)
285263660c0SAlfonso Siciliano 		colordesc = focus ? t.menu.f_namecolor : t.menu.namecolor;
2868c4f4028SBaptiste Daroussin 	else
287263660c0SAlfonso Siciliano 		colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
288263660c0SAlfonso Siciliano 
289263660c0SAlfonso Siciliano 	if (conf->menu.no_desc == false) {
2908c4f4028SBaptiste Daroussin 		wattron(pad, colordesc);
291f499134dSBaptiste Daroussin 		if (conf->menu.no_name)
292*bce40c02SAlfonso S. Siciliano 			mvwaddstr(pad, y, pos.xname + item->depth * DEPTH,
293*bce40c02SAlfonso S. Siciliano 			    item->desc);
294c76f0793SBaptiste Daroussin 		else
295*bce40c02SAlfonso S. Siciliano 			mvwaddstr(pad, y, pos.xdesc, item->desc);
2968c4f4028SBaptiste Daroussin 		wattroff(pad, colordesc);
297c76f0793SBaptiste Daroussin 	}
298c76f0793SBaptiste Daroussin 
2998c4f4028SBaptiste Daroussin 	/* shortcut */
300263660c0SAlfonso Siciliano 	if (conf->menu.shortcut_buttons == false) {
301263660c0SAlfonso Siciliano 		colorshortcut = focus ?
302263660c0SAlfonso Siciliano 		    t.menu.f_shortcutcolor : t.menu.shortcutcolor;
3038c4f4028SBaptiste Daroussin 		wattron(pad, colorshortcut);
3048c4f4028SBaptiste Daroussin 
3058c4f4028SBaptiste Daroussin 		if (conf->menu.no_name)
306*bce40c02SAlfonso S. Siciliano 			shortcut = item->desc;
3078c4f4028SBaptiste Daroussin 		else
308*bce40c02SAlfonso S. Siciliano 			shortcut = item->name;
309*bce40c02SAlfonso S. Siciliano 		wmove(pad, y, pos.xname + item->depth * DEPTH);
3108c4f4028SBaptiste Daroussin 		if (shortcut != NULL && shortcut[0] != '\0')
3118c4f4028SBaptiste Daroussin 			waddch(pad, shortcut[0]);
3128c4f4028SBaptiste Daroussin 	wattroff(pad, colorshortcut);
3138c4f4028SBaptiste Daroussin 	}
3148c4f4028SBaptiste Daroussin 
3158c4f4028SBaptiste Daroussin 	/* bottom description */
316263660c0SAlfonso Siciliano 	move(SCREENLINES - 1, 2);
317c76f0793SBaptiste Daroussin 	clrtoeol();
318*bce40c02SAlfonso S. Siciliano 	if (item->bottomdesc != NULL && focus) {
319*bce40c02SAlfonso S. Siciliano 		addstr(item->bottomdesc);
320c76f0793SBaptiste Daroussin 		refresh();
321c76f0793SBaptiste Daroussin 	}
322c76f0793SBaptiste Daroussin }
323c76f0793SBaptiste Daroussin 
324263660c0SAlfonso Siciliano static int
325f499134dSBaptiste Daroussin menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
326263660c0SAlfonso Siciliano     const char *text, int linelen, unsigned int *menurows, int nitems,
327c76f0793SBaptiste Daroussin     struct buttons bs)
328c76f0793SBaptiste Daroussin {
329263660c0SAlfonso Siciliano 	int htext, wtext, menusize, notext;
330c76f0793SBaptiste Daroussin 
331263660c0SAlfonso Siciliano 	notext = 2;
332263660c0SAlfonso Siciliano 	if (*menurows == BSDDIALOG_AUTOSIZE) {
333263660c0SAlfonso Siciliano 		/* algo 1): grows vertically */
334263660c0SAlfonso Siciliano 		/* notext = 1; */
335*bce40c02SAlfonso S. Siciliano 		/* algo 2): grows horizontally, better with little screens */
336263660c0SAlfonso Siciliano 		notext += nitems;
337263660c0SAlfonso Siciliano 		notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
338263660c0SAlfonso Siciliano 	} else
339263660c0SAlfonso Siciliano 		notext += *menurows;
340c76f0793SBaptiste Daroussin 
341*bce40c02SAlfonso S. Siciliano 	/* cols autosize, rows autosize, rows fullscreen, menu particularity */
342*bce40c02SAlfonso S. Siciliano 	if (cols == BSDDIALOG_AUTOSIZE || rows <= BSDDIALOG_AUTOSIZE) {
343*bce40c02SAlfonso S. Siciliano 		if (text_size(conf, rows, cols, text, &bs, notext, linelen + 4,
344263660c0SAlfonso Siciliano 		    &htext, &wtext) != 0)
345263660c0SAlfonso Siciliano 			return (BSDDIALOG_ERROR);
346c76f0793SBaptiste Daroussin 	}
347c76f0793SBaptiste Daroussin 
348263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE)
349*bce40c02SAlfonso S. Siciliano 		*w = widget_min_width(conf, wtext, linelen + 4, &bs);
350263660c0SAlfonso Siciliano 
351c76f0793SBaptiste Daroussin 	if (rows == BSDDIALOG_AUTOSIZE) {
352c76f0793SBaptiste Daroussin 		if (*menurows == 0) {
353263660c0SAlfonso Siciliano 			menusize = widget_max_height(conf) - HBORDERS -
354263660c0SAlfonso Siciliano 			     2 /*buttons*/ - htext;
355263660c0SAlfonso Siciliano 			menusize = MIN(menusize, nitems + 2);
356263660c0SAlfonso Siciliano 			*menurows = menusize - 2 < 0 ? 0 : menusize - 2;
357c76f0793SBaptiste Daroussin 		}
358263660c0SAlfonso Siciliano 		else /* h autosize with fixed menurows */
359263660c0SAlfonso Siciliano 			menusize = *menurows + 2;
360c76f0793SBaptiste Daroussin 
361263660c0SAlfonso Siciliano 		*h = widget_min_height(conf, htext, menusize, true);
362263660c0SAlfonso Siciliano 		/*
363263660c0SAlfonso Siciliano 		 * avoid menurows overflow and
364263660c0SAlfonso Siciliano 		 * with rows=AUTOSIZE menurows!=0 becomes max-menurows
365263660c0SAlfonso Siciliano 		 */
366263660c0SAlfonso Siciliano 		*menurows = MIN(*h - 6 - htext, (int)*menurows);
367263660c0SAlfonso Siciliano 	} else {
368c76f0793SBaptiste Daroussin 		if (*menurows == 0)
369*bce40c02SAlfonso S. Siciliano 			*menurows = MIN(*h-6-htext, nitems);
370c76f0793SBaptiste Daroussin 	}
371263660c0SAlfonso Siciliano 
372263660c0SAlfonso Siciliano 	return (0);
373c76f0793SBaptiste Daroussin }
374c76f0793SBaptiste Daroussin 
375c76f0793SBaptiste Daroussin static int
376263660c0SAlfonso Siciliano menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
377c76f0793SBaptiste Daroussin     struct buttons bs)
378c76f0793SBaptiste Daroussin {
379c76f0793SBaptiste Daroussin 	int mincols, textrow, menusize;
380c76f0793SBaptiste Daroussin 
381c76f0793SBaptiste Daroussin 	mincols = VBORDERS;
382c76f0793SBaptiste Daroussin 	/* buttons */
383*bce40c02SAlfonso S. Siciliano 	mincols += buttons_width(bs);
384*bce40c02SAlfonso S. Siciliano 
385263660c0SAlfonso Siciliano 	/*
386263660c0SAlfonso Siciliano 	 * linelen check, comment to allow some hidden col otherwise portconfig
387263660c0SAlfonso Siciliano 	 * could not show big menus like www/apache24
388263660c0SAlfonso Siciliano 	 */
389c76f0793SBaptiste Daroussin 	/* mincols = MAX(mincols, linelen); */
390c76f0793SBaptiste Daroussin 
391c76f0793SBaptiste Daroussin 	if (cols < mincols)
392263660c0SAlfonso Siciliano 		RETURN_ERROR("Few cols, width < size buttons or "
393c76f0793SBaptiste Daroussin 		    "name + descripion of the items");
394c76f0793SBaptiste Daroussin 
395c76f0793SBaptiste Daroussin 	textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
396c76f0793SBaptiste Daroussin 
397c76f0793SBaptiste Daroussin 	if (nitems > 0 && menurows == 0)
398263660c0SAlfonso Siciliano 		RETURN_ERROR("items > 0 but menurows == 0, probably terminal "
399c76f0793SBaptiste Daroussin 		    "too small");
400c76f0793SBaptiste Daroussin 
401c76f0793SBaptiste Daroussin 	menusize = nitems > 0 ? 3 : 0;
402c76f0793SBaptiste Daroussin 	if (rows < 2  + 2 + menusize + textrow)
403c76f0793SBaptiste Daroussin 		RETURN_ERROR("Few lines for this menus");
404c76f0793SBaptiste Daroussin 
405263660c0SAlfonso Siciliano 	return (0);
406c76f0793SBaptiste Daroussin }
407c76f0793SBaptiste Daroussin 
408c76f0793SBaptiste Daroussin /* the caller has to call prefresh(menupad, ymenupad, 0, ys, xs, ye, xe); */
409c76f0793SBaptiste Daroussin static void
410f499134dSBaptiste Daroussin update_menuwin(struct bsddialog_conf *conf, WINDOW *menuwin, int h, int w,
411c76f0793SBaptiste Daroussin     int totnitems, unsigned int menurows, int ymenupad)
412c76f0793SBaptiste Daroussin {
413c76f0793SBaptiste Daroussin 	draw_borders(conf, menuwin, h, w, LOWERED);
414c76f0793SBaptiste Daroussin 
4158c4f4028SBaptiste Daroussin 	if (totnitems > (int)menurows) {
416*bce40c02SAlfonso S. Siciliano 		wattron(menuwin, t.dialog.arrowcolor);
417f499134dSBaptiste Daroussin 
418f499134dSBaptiste Daroussin 		if (ymenupad > 0)
419f499134dSBaptiste Daroussin 			mvwprintw(menuwin, 0, 2, "^^^");
420f499134dSBaptiste Daroussin 
421*bce40c02SAlfonso S. Siciliano 		if ((ymenupad + (int)menurows) < totnitems)
422f499134dSBaptiste Daroussin 			mvwprintw(menuwin, h-1, 2, "vvv");
423f499134dSBaptiste Daroussin 
424*bce40c02SAlfonso S. Siciliano 		wattroff(menuwin, t.dialog.arrowcolor);
425c76f0793SBaptiste Daroussin 
426c76f0793SBaptiste Daroussin 		mvwprintw(menuwin, h-1, w-10, "%3d%%",
427c76f0793SBaptiste Daroussin 		    100 * (ymenupad + menurows) / totnitems);
428c76f0793SBaptiste Daroussin 	}
429c76f0793SBaptiste Daroussin }
430c76f0793SBaptiste Daroussin 
431c76f0793SBaptiste Daroussin static int
432263660c0SAlfonso Siciliano do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
433263660c0SAlfonso Siciliano     unsigned int menurows, enum menumode mode, unsigned int ngroups,
434c76f0793SBaptiste Daroussin     struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
435c76f0793SBaptiste Daroussin {
436263660c0SAlfonso Siciliano 	bool loop, onetrue, movefocus, automenurows, shortcut_butts;
437263660c0SAlfonso Siciliano 	int i, j, y, x, h, w, output, input;
438263660c0SAlfonso Siciliano 	int ymenupad, ys, ye, xs, xe, abs, next, totnitems;
439c76f0793SBaptiste Daroussin 	WINDOW  *shadow, *widget, *textpad, *menuwin, *menupad;
440c76f0793SBaptiste Daroussin 	struct buttons bs;
441c76f0793SBaptiste Daroussin 	struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
442263660c0SAlfonso Siciliano 	struct bsddialog_menuitem *item;
443263660c0SAlfonso Siciliano 	struct privateitem *pritems;
444c76f0793SBaptiste Daroussin 
445263660c0SAlfonso Siciliano 	shortcut_butts = conf->menu.shortcut_buttons;
4468c4f4028SBaptiste Daroussin 
447*bce40c02SAlfonso S. Siciliano 	automenurows = (menurows == BSDDIALOG_AUTOSIZE) ? true : false;
448c76f0793SBaptiste Daroussin 
449c76f0793SBaptiste Daroussin 	totnitems = 0;
450263660c0SAlfonso Siciliano 	for (i = 0; i < (int)ngroups; i++) {
451263660c0SAlfonso Siciliano 		if (getmode(mode, groups[i]) == RADIOLISTMODE ||
452263660c0SAlfonso Siciliano 		    getmode(mode, groups[i]) == CHECKLISTMODE)
453c76f0793SBaptiste Daroussin 			pos.selectorlen = 3;
454c76f0793SBaptiste Daroussin 
455c76f0793SBaptiste Daroussin 		for (j = 0; j < (int)groups[i].nitems; j++) {
456c76f0793SBaptiste Daroussin 			totnitems++;
457c76f0793SBaptiste Daroussin 			item = &groups[i].items[j];
458c76f0793SBaptiste Daroussin 
459c76f0793SBaptiste Daroussin 			if (groups[i].type == BSDDIALOG_SEPARATOR) {
460c76f0793SBaptiste Daroussin 				pos.maxsepstr = MAX(pos.maxsepstr,
461c76f0793SBaptiste Daroussin 				    strlen(item->name) + strlen(item->desc));
462c76f0793SBaptiste Daroussin 				continue;
463c76f0793SBaptiste Daroussin 			}
464c76f0793SBaptiste Daroussin 
465c76f0793SBaptiste Daroussin 			pos.maxprefix = MAX(pos.maxprefix,strlen(item->prefix));
4668c4f4028SBaptiste Daroussin 			pos.maxdepth  = MAX(pos.maxdepth, item->depth);
467c76f0793SBaptiste Daroussin 			pos.maxname   = MAX(pos.maxname, strlen(item->name));
468c76f0793SBaptiste Daroussin 			pos.maxdesc   = MAX(pos.maxdesc, strlen(item->desc));
469c76f0793SBaptiste Daroussin 		}
470c76f0793SBaptiste Daroussin 	}
471f499134dSBaptiste Daroussin 	pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
472f499134dSBaptiste Daroussin 	pos.maxdesc = conf->menu.no_desc ? 0 : pos.maxdesc;
473*bce40c02SAlfonso S. Siciliano 	pos.maxdepth = DEPTH * pos.maxdepth;
474c76f0793SBaptiste Daroussin 
475c76f0793SBaptiste Daroussin 	pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
476263660c0SAlfonso Siciliano 	pos.xname = pos.xselector + pos.selectorlen +
477263660c0SAlfonso Siciliano 	    (pos.selectorlen > 0 ? 1 : 0);
478c76f0793SBaptiste Daroussin 	pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
479c76f0793SBaptiste Daroussin 	pos.xdesc += (pos.maxname != 0 ? 1 : 0);
480c76f0793SBaptiste Daroussin 	pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
481c76f0793SBaptiste Daroussin 
482c76f0793SBaptiste Daroussin 
483263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
484c76f0793SBaptiste Daroussin 
485c76f0793SBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
486263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
487263660c0SAlfonso Siciliano 	if (menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
488263660c0SAlfonso Siciliano 	    totnitems, bs) != 0)
489263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
490c76f0793SBaptiste Daroussin 	if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
491263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
492c76f0793SBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
493263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
494c76f0793SBaptiste Daroussin 
495263660c0SAlfonso Siciliano 	if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
496263660c0SAlfonso Siciliano 	     shortcut_butts) != 0)
497263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
498c76f0793SBaptiste Daroussin 
499263660c0SAlfonso Siciliano 	doupdate();
500263660c0SAlfonso Siciliano 
501263660c0SAlfonso Siciliano 	prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
502263660c0SAlfonso Siciliano 	    y + h - menurows, x + 1 + w - TEXTHMARGIN);
503c76f0793SBaptiste Daroussin 
504c76f0793SBaptiste Daroussin 	menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
505c76f0793SBaptiste Daroussin 	    menurows+2, w-4, LOWERED);
506c76f0793SBaptiste Daroussin 
507c76f0793SBaptiste Daroussin 	menupad = newpad(totnitems, pos.line);
5088c4f4028SBaptiste Daroussin 	wbkgd(menupad, t.dialog.color);
509c76f0793SBaptiste Daroussin 
510263660c0SAlfonso Siciliano 	if ((pritems = calloc(totnitems, sizeof (struct privateitem))) == NULL)
511263660c0SAlfonso Siciliano 		RETURN_ERROR("Cannot allocate memory for internal menu items");
512263660c0SAlfonso Siciliano 
513263660c0SAlfonso Siciliano 	abs = 0;
514263660c0SAlfonso Siciliano 	for (i = 0; i < (int)ngroups; i++) {
515263660c0SAlfonso Siciliano 		onetrue = false;
516c76f0793SBaptiste Daroussin 		for (j = 0; j < (int)groups[i].nitems; j++) {
517c76f0793SBaptiste Daroussin 			item = &groups[i].items[j];
518263660c0SAlfonso Siciliano 
519263660c0SAlfonso Siciliano 			if (getmode(mode, groups[i]) == MENUMODE) {
520263660c0SAlfonso Siciliano 				pritems[abs].on = false;
521263660c0SAlfonso Siciliano 			} else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
522263660c0SAlfonso Siciliano 				pritems[abs].on = onetrue ? false : item->on;
523263660c0SAlfonso Siciliano 				if (pritems[abs].on)
524263660c0SAlfonso Siciliano 					onetrue = true;
525263660c0SAlfonso Siciliano 			} else {
526263660c0SAlfonso Siciliano 				pritems[abs].on = item->on;
527263660c0SAlfonso Siciliano 			}
528263660c0SAlfonso Siciliano 			pritems[abs].group = i;
529263660c0SAlfonso Siciliano 			pritems[abs].index = j;
530263660c0SAlfonso Siciliano 			pritems[abs].type = getmode(mode, groups[i]);
531263660c0SAlfonso Siciliano 			pritems[abs].item = item;
532263660c0SAlfonso Siciliano 
533263660c0SAlfonso Siciliano 			drawitem(conf, menupad, abs, pos, &pritems[abs], false);
534263660c0SAlfonso Siciliano 			abs++;
535c76f0793SBaptiste Daroussin 		}
536c76f0793SBaptiste Daroussin 	}
537*bce40c02SAlfonso S. Siciliano 	drawseparators(conf, menupad, MIN((int)pos.line, w-6), totnitems,
538*bce40c02SAlfonso S. Siciliano 	    pritems);
539263660c0SAlfonso Siciliano 	abs = getfirst_with_default(totnitems, pritems, ngroups, groups,
540263660c0SAlfonso Siciliano 	    focuslist, focusitem);
541263660c0SAlfonso Siciliano 	if (abs >= 0)
542263660c0SAlfonso Siciliano 		drawitem(conf, menupad, abs, pos, &pritems[abs], true);
543c76f0793SBaptiste Daroussin 
544c76f0793SBaptiste Daroussin 	ys = y + h - 5 - menurows + 1;
545c76f0793SBaptiste Daroussin 	ye = y + h - 5 ;
546f499134dSBaptiste Daroussin 	if (conf->menu.align_left || (int)pos.line > w - 6) {
547c76f0793SBaptiste Daroussin 		xs = x + 3;
548c76f0793SBaptiste Daroussin 		xe = xs + w - 7;
549263660c0SAlfonso Siciliano 	} else { /* center */
550c76f0793SBaptiste Daroussin 		xs = x + 3 + (w-6)/2 - pos.line/2;
551c76f0793SBaptiste Daroussin 		xe = xs + w - 5;
552c76f0793SBaptiste Daroussin 	}
553c76f0793SBaptiste Daroussin 
554263660c0SAlfonso Siciliano 	ymenupad = 0;
555c76f0793SBaptiste Daroussin 	if ((int)(ymenupad + menurows) - 1 < abs)
556c76f0793SBaptiste Daroussin 		ymenupad = abs - menurows + 1;
557263660c0SAlfonso Siciliano 	update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows,
558263660c0SAlfonso Siciliano 	    ymenupad);
559c76f0793SBaptiste Daroussin 	wrefresh(menuwin);
560c76f0793SBaptiste Daroussin 	prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
561c76f0793SBaptiste Daroussin 
562263660c0SAlfonso Siciliano 	movefocus = false;
563c76f0793SBaptiste Daroussin 	loop = true;
564c76f0793SBaptiste Daroussin 	while (loop) {
565c76f0793SBaptiste Daroussin 		input = getch();
566c76f0793SBaptiste Daroussin 		switch(input) {
567c76f0793SBaptiste Daroussin 		case KEY_ENTER:
568c76f0793SBaptiste Daroussin 		case 10: /* Enter */
569c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
570263660c0SAlfonso Siciliano 			if (abs >= 0 && pritems[abs].type == MENUMODE)
571263660c0SAlfonso Siciliano 				pritems[abs].on = true;
572263660c0SAlfonso Siciliano 			set_on_output(conf, output, ngroups, groups, pritems);
573c76f0793SBaptiste Daroussin 			loop = false;
574c76f0793SBaptiste Daroussin 			break;
575c76f0793SBaptiste Daroussin 		case 27: /* Esc */
576263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
577c76f0793SBaptiste Daroussin 				output = BSDDIALOG_ESC;
578263660c0SAlfonso Siciliano 				if (abs >= 0 && pritems[abs].type == MENUMODE)
579263660c0SAlfonso Siciliano 					pritems[abs].on = true;
580263660c0SAlfonso Siciliano 				set_on_output(conf, output, ngroups, groups,
581263660c0SAlfonso Siciliano 				    pritems);
582c76f0793SBaptiste Daroussin 				loop = false;
583263660c0SAlfonso Siciliano 			}
584c76f0793SBaptiste Daroussin 			break;
585c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
586c76f0793SBaptiste Daroussin 			bs.curr = (bs.curr + 1) % bs.nbuttons;
587263660c0SAlfonso Siciliano 			draw_buttons(widget, bs, shortcut_butts);
588c76f0793SBaptiste Daroussin 			wrefresh(widget);
589c76f0793SBaptiste Daroussin 			break;
590c76f0793SBaptiste Daroussin 		case KEY_LEFT:
591c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
592c76f0793SBaptiste Daroussin 				bs.curr--;
593263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, shortcut_butts);
594c76f0793SBaptiste Daroussin 				wrefresh(widget);
595c76f0793SBaptiste Daroussin 			}
596c76f0793SBaptiste Daroussin 			break;
597c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
598c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
599c76f0793SBaptiste Daroussin 				bs.curr++;
600263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, shortcut_butts);
601c76f0793SBaptiste Daroussin 				wrefresh(widget);
602c76f0793SBaptiste Daroussin 			}
603c76f0793SBaptiste Daroussin 			break;
604c76f0793SBaptiste Daroussin 		case KEY_F(1):
605*bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
606*bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
607c76f0793SBaptiste Daroussin 				break;
608c76f0793SBaptiste Daroussin 			if (f1help(conf) != 0)
609263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
610263660c0SAlfonso Siciliano 			/* No break, screen size can change */
611c76f0793SBaptiste Daroussin 		case KEY_RESIZE:
612263660c0SAlfonso Siciliano 			/* Important for decreasing screen */
613f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w, conf->shadow);
614c76f0793SBaptiste Daroussin 			refresh();
615c76f0793SBaptiste Daroussin 
616c76f0793SBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
617263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
618c76f0793SBaptiste Daroussin 			menurows = automenurows ? 0 : menurows;
619263660c0SAlfonso Siciliano 			if (menu_autosize(conf, rows, cols, &h, &w, text,
620263660c0SAlfonso Siciliano 			    pos.line, &menurows, totnitems, bs) != 0)
621263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
622263660c0SAlfonso Siciliano 			if (menu_checksize(h, w, text, menurows, totnitems,
623263660c0SAlfonso Siciliano 			    bs) != 0)
624263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
625c76f0793SBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
626263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
627c76f0793SBaptiste Daroussin 
628263660c0SAlfonso Siciliano 			if (update_dialog(conf, shadow, widget, y, x, h, w,
629263660c0SAlfonso Siciliano 			    textpad, text, &bs, shortcut_butts) != 0)
630263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
631c76f0793SBaptiste Daroussin 
632263660c0SAlfonso Siciliano 			doupdate();
633c76f0793SBaptiste Daroussin 
634263660c0SAlfonso Siciliano 			prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
635263660c0SAlfonso Siciliano 			    y + h - menurows, x + 1 + w - TEXTHMARGIN);
636c76f0793SBaptiste Daroussin 
637c76f0793SBaptiste Daroussin 			wclear(menuwin);
638c76f0793SBaptiste Daroussin 			mvwin(menuwin, y + h - 5 - menurows, x + 2);
639c76f0793SBaptiste Daroussin 			wresize(menuwin,menurows+2, w-4);
640263660c0SAlfonso Siciliano 			update_menuwin(conf, menuwin, menurows+2, w-4,
641263660c0SAlfonso Siciliano 			    totnitems, menurows, ymenupad);
642c76f0793SBaptiste Daroussin 			wrefresh(menuwin);
643c76f0793SBaptiste Daroussin 
644c76f0793SBaptiste Daroussin 			ys = y + h - 5 - menurows + 1;
645c76f0793SBaptiste Daroussin 			ye = y + h - 5 ;
646f499134dSBaptiste Daroussin 			if (conf->menu.align_left || (int)pos.line > w - 6) {
647c76f0793SBaptiste Daroussin 				xs = x + 3;
648c76f0793SBaptiste Daroussin 				xe = xs + w - 7;
649263660c0SAlfonso Siciliano 			} else { /* center */
650c76f0793SBaptiste Daroussin 				xs = x + 3 + (w-6)/2 - pos.line/2;
651c76f0793SBaptiste Daroussin 				xe = xs + w - 5;
652c76f0793SBaptiste Daroussin 			}
653c76f0793SBaptiste Daroussin 
654*bce40c02SAlfonso S. Siciliano 			drawseparators(conf, menupad, MIN((int)pos.line, w-6),
655*bce40c02SAlfonso S. Siciliano 			    totnitems, pritems);
656*bce40c02SAlfonso S. Siciliano 
657c76f0793SBaptiste Daroussin 			if ((int)(ymenupad + menurows) - 1 < abs)
658c76f0793SBaptiste Daroussin 				ymenupad = abs - menurows + 1;
659c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
660c76f0793SBaptiste Daroussin 
661c76f0793SBaptiste Daroussin 			refresh();
662c76f0793SBaptiste Daroussin 
663c76f0793SBaptiste Daroussin 			break;
664c76f0793SBaptiste Daroussin 		}
665c76f0793SBaptiste Daroussin 
666c76f0793SBaptiste Daroussin 		if (abs < 0)
667c76f0793SBaptiste Daroussin 			continue;
668c76f0793SBaptiste Daroussin 		switch(input) {
669c76f0793SBaptiste Daroussin 		case KEY_HOME:
670263660c0SAlfonso Siciliano 			next = getnext(totnitems, pritems, -1);
671263660c0SAlfonso Siciliano 			movefocus = next != abs;
672c76f0793SBaptiste Daroussin 			break;
673263660c0SAlfonso Siciliano 		case KEY_UP:
674263660c0SAlfonso Siciliano 			next = getprev(pritems, abs);
675263660c0SAlfonso Siciliano 			movefocus = next != abs;
676263660c0SAlfonso Siciliano 			break;
677263660c0SAlfonso Siciliano 		case KEY_PPAGE:
678263660c0SAlfonso Siciliano 			next = getfastprev(menurows, pritems, abs);
679263660c0SAlfonso Siciliano 			movefocus = next != abs;
680c76f0793SBaptiste Daroussin 			break;
681c76f0793SBaptiste Daroussin 		case KEY_END:
682263660c0SAlfonso Siciliano 			next = getprev(pritems, totnitems);
683263660c0SAlfonso Siciliano 			movefocus = next != abs;
684263660c0SAlfonso Siciliano 			break;
685c76f0793SBaptiste Daroussin 		case KEY_DOWN:
686263660c0SAlfonso Siciliano 			next = getnext(totnitems, pritems, abs);
687263660c0SAlfonso Siciliano 			movefocus = next != abs;
688263660c0SAlfonso Siciliano 			break;
689c76f0793SBaptiste Daroussin 		case KEY_NPAGE:
690263660c0SAlfonso Siciliano 			next = getfastnext(menurows, totnitems, pritems, abs);
691263660c0SAlfonso Siciliano 			movefocus = next != abs;
692c76f0793SBaptiste Daroussin 			break;
693c76f0793SBaptiste Daroussin 		case ' ': /* Space */
694263660c0SAlfonso Siciliano 			if (pritems[abs].type == MENUMODE)
695c76f0793SBaptiste Daroussin 				break;
696263660c0SAlfonso Siciliano 			else if (pritems[abs].type == CHECKLISTMODE)
697263660c0SAlfonso Siciliano 				pritems[abs].on = !pritems[abs].on;
698c76f0793SBaptiste Daroussin 			else { /* RADIOLISTMODE */
699263660c0SAlfonso Siciliano 				for (i = abs - pritems[abs].index;
700263660c0SAlfonso Siciliano 				    i < totnitems &&
701263660c0SAlfonso Siciliano 				    pritems[i].group == pritems[abs].group;
702263660c0SAlfonso Siciliano 				    i++) {
703263660c0SAlfonso Siciliano 					if (i != abs && pritems[i].on) {
704263660c0SAlfonso Siciliano 						pritems[i].on = false;
705263660c0SAlfonso Siciliano 						drawitem(conf, menupad, i, pos,
706263660c0SAlfonso Siciliano 						    &pritems[i], false);
707c76f0793SBaptiste Daroussin 					}
708c76f0793SBaptiste Daroussin 				}
709263660c0SAlfonso Siciliano 				pritems[abs].on = !pritems[abs].on;
710263660c0SAlfonso Siciliano 			}
711263660c0SAlfonso Siciliano 			drawitem(conf, menupad, abs, pos, &pritems[abs], true);
712c76f0793SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
713263660c0SAlfonso Siciliano 			break;
7148c4f4028SBaptiste Daroussin 		default:
715263660c0SAlfonso Siciliano 			if (shortcut_butts) {
716263660c0SAlfonso Siciliano 				if (shortcut_buttons(input, &bs)) {
717263660c0SAlfonso Siciliano 					output = bs.value[bs.curr];
718263660c0SAlfonso Siciliano 					if (pritems[abs].type == MENUMODE)
719263660c0SAlfonso Siciliano 						pritems[abs].on = true;
720263660c0SAlfonso Siciliano 					set_on_output(conf, output, ngroups,
721263660c0SAlfonso Siciliano 					    groups, pritems);
7228c4f4028SBaptiste Daroussin 					loop = false;
7238c4f4028SBaptiste Daroussin 				}
7248c4f4028SBaptiste Daroussin 				break;
7258c4f4028SBaptiste Daroussin 			}
7268c4f4028SBaptiste Daroussin 
727263660c0SAlfonso Siciliano 			/* shourtcut items */
728263660c0SAlfonso Siciliano 			next = getnextshortcut(conf, totnitems, pritems, abs,
729263660c0SAlfonso Siciliano 			    input);
730263660c0SAlfonso Siciliano 			movefocus = next != abs;
731263660c0SAlfonso Siciliano 		}
732263660c0SAlfonso Siciliano 
733263660c0SAlfonso Siciliano 		if (movefocus) {
734263660c0SAlfonso Siciliano 			drawitem(conf, menupad, abs, pos, &pritems[abs], false);
735263660c0SAlfonso Siciliano 			abs = next;
736263660c0SAlfonso Siciliano 			drawitem(conf, menupad, abs, pos, &pritems[abs], true);
7378c4f4028SBaptiste Daroussin 			if (ymenupad > abs && ymenupad > 0)
7388c4f4028SBaptiste Daroussin 				ymenupad = abs;
7398c4f4028SBaptiste Daroussin 			if ((int)(ymenupad + menurows) <= abs)
7408c4f4028SBaptiste Daroussin 				ymenupad = abs - menurows + 1;
741263660c0SAlfonso Siciliano 			update_menuwin(conf, menuwin, menurows+2, w-4,
742263660c0SAlfonso Siciliano 			    totnitems, menurows, ymenupad);
7438c4f4028SBaptiste Daroussin 			wrefresh(menuwin);
7448c4f4028SBaptiste Daroussin 			prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
745263660c0SAlfonso Siciliano 			movefocus = false;
746c76f0793SBaptiste Daroussin 		}
747c76f0793SBaptiste Daroussin 	}
748c76f0793SBaptiste Daroussin 
749c76f0793SBaptiste Daroussin 	if (focuslist != NULL)
750263660c0SAlfonso Siciliano 		*focuslist = abs < 0 ? -1 : pritems[abs].group;
751c76f0793SBaptiste Daroussin 	if (focusitem !=NULL)
752263660c0SAlfonso Siciliano 		*focusitem = abs < 0 ? -1 : pritems[abs].index;
753c76f0793SBaptiste Daroussin 
754c76f0793SBaptiste Daroussin 	delwin(menupad);
755c76f0793SBaptiste Daroussin 	delwin(menuwin);
756263660c0SAlfonso Siciliano 	end_dialog(conf, shadow, widget, textpad);
757263660c0SAlfonso Siciliano 	free(pritems);
758c76f0793SBaptiste Daroussin 
759263660c0SAlfonso Siciliano 	return (output);
760c76f0793SBaptiste Daroussin }
761c76f0793SBaptiste Daroussin 
762263660c0SAlfonso Siciliano /* API */
763263660c0SAlfonso Siciliano int
764263660c0SAlfonso Siciliano bsddialog_mixedlist(struct bsddialog_conf *conf, const char *text, int rows,
765263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int ngroups,
766263660c0SAlfonso Siciliano     struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
767c76f0793SBaptiste Daroussin {
768c76f0793SBaptiste Daroussin 	int output;
769c76f0793SBaptiste Daroussin 
770c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
771c76f0793SBaptiste Daroussin 	    ngroups, groups, focuslist, focusitem);
772c76f0793SBaptiste Daroussin 
773263660c0SAlfonso Siciliano 	return (output);
774c76f0793SBaptiste Daroussin }
775c76f0793SBaptiste Daroussin 
776c76f0793SBaptiste Daroussin int
777263660c0SAlfonso Siciliano bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
778263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
779263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
780c76f0793SBaptiste Daroussin {
781263660c0SAlfonso Siciliano 	int output, focuslist = 0;
782c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
783c76f0793SBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items};
784c76f0793SBaptiste Daroussin 
785c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
786263660c0SAlfonso Siciliano 	    1, &group, &focuslist, focusitem);
787c76f0793SBaptiste Daroussin 
788263660c0SAlfonso Siciliano 	return (output);
789c76f0793SBaptiste Daroussin }
790c76f0793SBaptiste Daroussin 
791c76f0793SBaptiste Daroussin int
792263660c0SAlfonso Siciliano bsddialog_menu(struct bsddialog_conf *conf, const char *text, int rows,
793263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
794263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
795c76f0793SBaptiste Daroussin {
796263660c0SAlfonso Siciliano 	int output, focuslist = 0;
797c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
798c76f0793SBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items};
799c76f0793SBaptiste Daroussin 
800c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
801263660c0SAlfonso Siciliano 	    &group, &focuslist, focusitem);
802c76f0793SBaptiste Daroussin 
803263660c0SAlfonso Siciliano 	return (output);
804c76f0793SBaptiste Daroussin }
805c76f0793SBaptiste Daroussin 
806c76f0793SBaptiste Daroussin int
807263660c0SAlfonso Siciliano bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
808263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
809263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
810c76f0793SBaptiste Daroussin {
811263660c0SAlfonso Siciliano 	int output, focuslist = 0;
812c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
813c76f0793SBaptiste Daroussin 	    BSDDIALOG_RADIOLIST /* unused */, nitems, items};
814c76f0793SBaptiste Daroussin 
815c76f0793SBaptiste Daroussin 	output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
816263660c0SAlfonso Siciliano 	    1, &group, &focuslist, focusitem);
817c76f0793SBaptiste Daroussin 
818263660c0SAlfonso Siciliano 	return (output);
819c76f0793SBaptiste Daroussin }
820