xref: /freebsd-src/contrib/bsddialog/lib/menubox.c (revision a6d8be451f62d425b71a4874f7d4e133b9fb393c)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4*a6d8be45SAlfonso S. Siciliano  * Copyright (c) 2021-2024 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 
28263660c0SAlfonso Siciliano #include <curses.h>
29263660c0SAlfonso Siciliano #include <stdlib.h>
30d93b4d32SBaptiste Daroussin 
31c76f0793SBaptiste Daroussin #include "bsddialog.h"
32c76f0793SBaptiste Daroussin #include "bsddialog_theme.h"
33263660c0SAlfonso Siciliano #include "lib_util.h"
34c76f0793SBaptiste Daroussin 
35c76f0793SBaptiste Daroussin enum menumode {
36c76f0793SBaptiste Daroussin 	CHECKLISTMODE,
37c76f0793SBaptiste Daroussin 	MENUMODE,
38c76f0793SBaptiste Daroussin 	MIXEDLISTMODE,
39c76f0793SBaptiste Daroussin 	RADIOLISTMODE,
40c76f0793SBaptiste Daroussin 	SEPARATORMODE
41c76f0793SBaptiste Daroussin };
42c76f0793SBaptiste Daroussin 
43263660c0SAlfonso Siciliano struct privateitem {
4461ba55bcSBaptiste Daroussin 	const char *prefix;
4561ba55bcSBaptiste Daroussin 	bool on;               /* menu changes, not API on */
4661ba55bcSBaptiste Daroussin 	unsigned int depth;
4761ba55bcSBaptiste Daroussin 	const char *name;
4861ba55bcSBaptiste Daroussin 	const char *desc;
4961ba55bcSBaptiste Daroussin 	const char *bottomdesc;
5061ba55bcSBaptiste Daroussin 	int group;             /* index menu in menugroup */
5161ba55bcSBaptiste Daroussin 	int index;             /* real item index inside its menu */
52263660c0SAlfonso Siciliano 	enum menumode type;
5361ba55bcSBaptiste Daroussin 	wchar_t shortcut;
54263660c0SAlfonso Siciliano };
55c76f0793SBaptiste Daroussin 
5661ba55bcSBaptiste Daroussin struct privatemenu {
5761ba55bcSBaptiste Daroussin 	WINDOW *box;              /* only for borders */
5861ba55bcSBaptiste Daroussin 	WINDOW *pad;              /* pad for the private items */
5961ba55bcSBaptiste Daroussin 	int ypad;                 /* start pad line */
6061ba55bcSBaptiste Daroussin 	int ys, ye, xs, xe;       /* pad pos */
6161ba55bcSBaptiste Daroussin 	unsigned int xselector;   /* [] */
6261ba55bcSBaptiste Daroussin 	unsigned int xname;       /* real x: xname + item.depth */
6361ba55bcSBaptiste Daroussin 	unsigned int xdesc;       /* real x: xdesc + item.depth */
6461ba55bcSBaptiste Daroussin 	unsigned int line;        /* wpad: prefix [] depth name desc */
6561ba55bcSBaptiste Daroussin 	unsigned int apimenurows;
6661ba55bcSBaptiste Daroussin 	unsigned int menurows;    /* real menurows after menu_size_position() */
6761ba55bcSBaptiste Daroussin 	int nitems;               /* total nitems (all groups * all items) */
6861ba55bcSBaptiste Daroussin 	struct privateitem *pritems;
6961ba55bcSBaptiste Daroussin 	int sel;                  /* current focus item, can be -1 */
7061ba55bcSBaptiste Daroussin 	bool hasbottomdesc;
7161ba55bcSBaptiste Daroussin };
7261ba55bcSBaptiste Daroussin 
7361ba55bcSBaptiste Daroussin static enum menumode
getmode(enum menumode mode,struct bsddialog_menugroup group)7461ba55bcSBaptiste Daroussin getmode(enum menumode mode, struct bsddialog_menugroup group)
75263660c0SAlfonso Siciliano {
7661ba55bcSBaptiste Daroussin 	if (mode == MIXEDLISTMODE) {
7761ba55bcSBaptiste Daroussin 		if (group.type == BSDDIALOG_SEPARATOR)
7861ba55bcSBaptiste Daroussin 			mode = SEPARATORMODE;
7961ba55bcSBaptiste Daroussin 		else if (group.type == BSDDIALOG_RADIOLIST)
8061ba55bcSBaptiste Daroussin 			mode = RADIOLISTMODE;
8161ba55bcSBaptiste Daroussin 		else if (group.type == BSDDIALOG_CHECKLIST)
8261ba55bcSBaptiste Daroussin 			mode = CHECKLISTMODE;
8361ba55bcSBaptiste Daroussin 	}
8461ba55bcSBaptiste Daroussin 
8561ba55bcSBaptiste Daroussin 	return (mode);
8661ba55bcSBaptiste Daroussin }
8761ba55bcSBaptiste Daroussin 
8861ba55bcSBaptiste Daroussin static int
build_privatemenu(struct bsddialog_conf * conf,struct privatemenu * m,enum menumode mode,unsigned int ngroups,struct bsddialog_menugroup * groups)8961ba55bcSBaptiste Daroussin build_privatemenu(struct bsddialog_conf *conf, struct privatemenu *m,
9061ba55bcSBaptiste Daroussin     enum menumode mode, unsigned int ngroups,
9161ba55bcSBaptiste Daroussin     struct bsddialog_menugroup *groups)
9261ba55bcSBaptiste Daroussin {
9361ba55bcSBaptiste Daroussin 	bool onetrue;
94263660c0SAlfonso Siciliano 	int i, j, abs;
9561ba55bcSBaptiste Daroussin 	unsigned int maxsepstr, maxprefix, selectorlen, maxdepth;
9661ba55bcSBaptiste Daroussin 	unsigned int maxname, maxdesc;
9761ba55bcSBaptiste Daroussin 	struct bsddialog_menuitem *item;
9861ba55bcSBaptiste Daroussin 	struct privateitem *pritem;
99263660c0SAlfonso Siciliano 
10061ba55bcSBaptiste Daroussin 	/* nitems and fault checks */
10161ba55bcSBaptiste Daroussin 	CHECK_ARRAY(ngroups, groups);
10261ba55bcSBaptiste Daroussin 	m->nitems = 0;
10361ba55bcSBaptiste Daroussin 	for (i = 0; i < (int)ngroups; i++) {
10461ba55bcSBaptiste Daroussin 		CHECK_ARRAY(groups[i].nitems, groups[i].items);
10561ba55bcSBaptiste Daroussin 		m->nitems += (int)groups[i].nitems;
10661ba55bcSBaptiste Daroussin 	}
107c76f0793SBaptiste Daroussin 
10861ba55bcSBaptiste Daroussin 	/* alloc and set private items */
10961ba55bcSBaptiste Daroussin 	m->pritems = calloc(m->nitems, sizeof (struct privateitem));
11061ba55bcSBaptiste Daroussin 	if (m->pritems == NULL)
11161ba55bcSBaptiste Daroussin 		RETURN_ERROR("Cannot allocate memory for internal menu items");
11261ba55bcSBaptiste Daroussin 	m->hasbottomdesc = false;
11361ba55bcSBaptiste Daroussin 	abs = 0;
11461ba55bcSBaptiste Daroussin 	for (i = 0; i < (int)ngroups; i++) {
11561ba55bcSBaptiste Daroussin 		onetrue = false;
11661ba55bcSBaptiste Daroussin 		for (j = 0; j < (int)groups[i].nitems; j++) {
11761ba55bcSBaptiste Daroussin 			item = &groups[i].items[j];
11861ba55bcSBaptiste Daroussin 			pritem = &m->pritems[abs];
11961ba55bcSBaptiste Daroussin 
12061ba55bcSBaptiste Daroussin 			if (getmode(mode, groups[i]) == MENUMODE) {
12161ba55bcSBaptiste Daroussin 				m->pritems[abs].on = false;
12261ba55bcSBaptiste Daroussin 			} else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
12361ba55bcSBaptiste Daroussin 				m->pritems[abs].on = onetrue ? false : item->on;
12461ba55bcSBaptiste Daroussin 				if (m->pritems[abs].on)
12561ba55bcSBaptiste Daroussin 					onetrue = true;
12661ba55bcSBaptiste Daroussin 			} else { /* CHECKLISTMODE */
12761ba55bcSBaptiste Daroussin 				m->pritems[abs].on = item->on;
12861ba55bcSBaptiste Daroussin 			}
12961ba55bcSBaptiste Daroussin 			pritem->group = i;
13061ba55bcSBaptiste Daroussin 			pritem->index = j;
13161ba55bcSBaptiste Daroussin 			pritem->type = getmode(mode, groups[i]);
13261ba55bcSBaptiste Daroussin 
13361ba55bcSBaptiste Daroussin 			pritem->prefix = CHECK_STR(item->prefix);
13461ba55bcSBaptiste Daroussin 			pritem->depth = item->depth;
13561ba55bcSBaptiste Daroussin 			pritem->name = CHECK_STR(item->name);
13661ba55bcSBaptiste Daroussin 			pritem->desc = CHECK_STR(item->desc);
13761ba55bcSBaptiste Daroussin 			pritem->bottomdesc = CHECK_STR(item->bottomdesc);
13861ba55bcSBaptiste Daroussin 			if (item->bottomdesc != NULL)
13961ba55bcSBaptiste Daroussin 				m->hasbottomdesc = true;
14061ba55bcSBaptiste Daroussin 
14161ba55bcSBaptiste Daroussin 			mbtowc(&pritem->shortcut, conf->menu.no_name ?
14261ba55bcSBaptiste Daroussin 			    pritem->desc : pritem->name, MB_CUR_MAX);
14361ba55bcSBaptiste Daroussin 
14461ba55bcSBaptiste Daroussin 			abs++;
14561ba55bcSBaptiste Daroussin 		}
14661ba55bcSBaptiste Daroussin 	}
14761ba55bcSBaptiste Daroussin 
14861ba55bcSBaptiste Daroussin 	/* positions */
14961ba55bcSBaptiste Daroussin 	m->xselector = m->xname = m->xdesc = m->line = 0;
15061ba55bcSBaptiste Daroussin 	maxsepstr = maxprefix = selectorlen = maxdepth = maxname = maxdesc = 0;
15161ba55bcSBaptiste Daroussin 	for (i = 0; i < m->nitems; i++) {
15261ba55bcSBaptiste Daroussin 		if (m->pritems[i].type == RADIOLISTMODE ||
15361ba55bcSBaptiste Daroussin 		    m->pritems[i].type == CHECKLISTMODE)
15461ba55bcSBaptiste Daroussin 			selectorlen = 4;
15561ba55bcSBaptiste Daroussin 
15661ba55bcSBaptiste Daroussin 		if (m->pritems[i].type == SEPARATORMODE) {
15761ba55bcSBaptiste Daroussin 			maxsepstr = MAX(maxsepstr,
15861ba55bcSBaptiste Daroussin 			    strcols(m->pritems[i].name) +
15961ba55bcSBaptiste Daroussin 			    strcols(m->pritems[i].desc));
160c76f0793SBaptiste Daroussin 			continue;
161c76f0793SBaptiste Daroussin 		}
162263660c0SAlfonso Siciliano 
16361ba55bcSBaptiste Daroussin 		maxprefix = MAX(maxprefix, strcols(m->pritems[i].prefix));
16461ba55bcSBaptiste Daroussin 		maxdepth  = MAX(maxdepth, m->pritems[i].depth);
16561ba55bcSBaptiste Daroussin 		maxname   = MAX(maxname, strcols(m->pritems[i].name));
16661ba55bcSBaptiste Daroussin 		maxdesc   = MAX(maxdesc, strcols(m->pritems[i].desc));
167c76f0793SBaptiste Daroussin 	}
16861ba55bcSBaptiste Daroussin 	maxname = conf->menu.no_name ? 0 : maxname;
16961ba55bcSBaptiste Daroussin 	maxdesc = conf->menu.no_desc ? 0 : maxdesc;
17061ba55bcSBaptiste Daroussin 
17161ba55bcSBaptiste Daroussin 	m->xselector = maxprefix + (maxprefix != 0 ? 1 : 0);
17261ba55bcSBaptiste Daroussin 	m->xname = m->xselector + selectorlen;
17361ba55bcSBaptiste Daroussin 	m->xdesc = maxdepth + m->xname + maxname;
17461ba55bcSBaptiste Daroussin 	m->xdesc += (maxname != 0 ? 1 : 0);
17561ba55bcSBaptiste Daroussin 	m->line = MAX(maxsepstr + 3, m->xdesc + maxdesc);
17661ba55bcSBaptiste Daroussin 
17761ba55bcSBaptiste Daroussin 	return (0);
17861ba55bcSBaptiste Daroussin }
17961ba55bcSBaptiste Daroussin 
18061ba55bcSBaptiste Daroussin static void
set_return_on(struct privatemenu * m,struct bsddialog_menugroup * groups)18161ba55bcSBaptiste Daroussin set_return_on(struct privatemenu *m, struct bsddialog_menugroup *groups)
18261ba55bcSBaptiste Daroussin {
18361ba55bcSBaptiste Daroussin 	int i;
18461ba55bcSBaptiste Daroussin 	struct privateitem *pritem;
18561ba55bcSBaptiste Daroussin 
18661ba55bcSBaptiste Daroussin 	for (i = 0; i < m->nitems; i++) {
18761ba55bcSBaptiste Daroussin 		if (m->pritems[i].type == SEPARATORMODE)
18861ba55bcSBaptiste Daroussin 			continue;
18961ba55bcSBaptiste Daroussin 		pritem = &m->pritems[i];
19061ba55bcSBaptiste Daroussin 		groups[pritem->group].items[pritem->index].on = pritem->on;
191c76f0793SBaptiste Daroussin 	}
192c76f0793SBaptiste Daroussin }
193c76f0793SBaptiste Daroussin 
getprev(struct privateitem * pritems,int abs)194263660c0SAlfonso Siciliano static int getprev(struct privateitem *pritems, int abs)
195c76f0793SBaptiste Daroussin {
196263660c0SAlfonso Siciliano 	int i;
197c76f0793SBaptiste Daroussin 
198263660c0SAlfonso Siciliano 	for (i = abs - 1; i >= 0; i--) {
199263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
200c76f0793SBaptiste Daroussin 			continue;
201263660c0SAlfonso Siciliano 		return (i);
202c76f0793SBaptiste Daroussin 	}
203c76f0793SBaptiste Daroussin 
204263660c0SAlfonso Siciliano 	return (abs);
205263660c0SAlfonso Siciliano }
206263660c0SAlfonso Siciliano 
getnext(int npritems,struct privateitem * pritems,int abs)207263660c0SAlfonso Siciliano static int getnext(int npritems, struct privateitem *pritems, int abs)
208c76f0793SBaptiste Daroussin {
209263660c0SAlfonso Siciliano 	int i;
210c76f0793SBaptiste Daroussin 
211263660c0SAlfonso Siciliano 	for (i = abs + 1; i < npritems; i++) {
212263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
213c76f0793SBaptiste Daroussin 			continue;
214263660c0SAlfonso Siciliano 		return (i);
215c76f0793SBaptiste Daroussin 	}
216c76f0793SBaptiste Daroussin 
217263660c0SAlfonso Siciliano 	return (abs);
218263660c0SAlfonso Siciliano }
219263660c0SAlfonso Siciliano 
220263660c0SAlfonso Siciliano static int
getfirst_with_default(int npritems,struct privateitem * pritems,int ngroups,struct bsddialog_menugroup * groups,int * focusgroup,int * focusitem)221263660c0SAlfonso Siciliano getfirst_with_default(int npritems, struct privateitem *pritems, int ngroups,
222263660c0SAlfonso Siciliano     struct bsddialog_menugroup *groups, int *focusgroup, int *focusitem)
223263660c0SAlfonso Siciliano {
224263660c0SAlfonso Siciliano 	int i, abs;
225263660c0SAlfonso Siciliano 
226263660c0SAlfonso Siciliano 	if ((abs =  getnext(npritems, pritems, -1)) < 0)
227263660c0SAlfonso Siciliano 		return (abs);
228263660c0SAlfonso Siciliano 
229263660c0SAlfonso Siciliano 	if (focusgroup == NULL || focusitem == NULL)
230263660c0SAlfonso Siciliano 		return (abs);
231263660c0SAlfonso Siciliano 	if (*focusgroup < 0 || *focusgroup >= ngroups)
232263660c0SAlfonso Siciliano 		return (abs);
233263660c0SAlfonso Siciliano 	if (groups[*focusgroup].type == BSDDIALOG_SEPARATOR)
234263660c0SAlfonso Siciliano 		return (abs);
235263660c0SAlfonso Siciliano 	if (*focusitem < 0 || *focusitem >= (int)groups[*focusgroup].nitems)
236263660c0SAlfonso Siciliano 		return (abs);
237263660c0SAlfonso Siciliano 
238263660c0SAlfonso Siciliano 	for (i = abs; i < npritems; i++) {
239263660c0SAlfonso Siciliano 		if (pritems[i].group == *focusgroup &&
240263660c0SAlfonso Siciliano 		    pritems[i].index == *focusitem)
241263660c0SAlfonso Siciliano 			return (i);
242263660c0SAlfonso Siciliano 	}
243263660c0SAlfonso Siciliano 
244263660c0SAlfonso Siciliano 	return (abs);
245263660c0SAlfonso Siciliano }
246263660c0SAlfonso Siciliano 
247263660c0SAlfonso Siciliano static int
getfastnext(int menurows,int npritems,struct privateitem * pritems,int abs)248263660c0SAlfonso Siciliano getfastnext(int menurows, int npritems, struct privateitem *pritems, int abs)
249c76f0793SBaptiste Daroussin {
250c76f0793SBaptiste Daroussin 	int a, start, i;
251c76f0793SBaptiste Daroussin 
252263660c0SAlfonso Siciliano 	start = abs;
253c76f0793SBaptiste Daroussin 	i = menurows;
254c76f0793SBaptiste Daroussin 	do {
255263660c0SAlfonso Siciliano 		a = abs;
256263660c0SAlfonso Siciliano 		abs = getnext(npritems, pritems, abs);
257c76f0793SBaptiste Daroussin 		i--;
258263660c0SAlfonso Siciliano 	} while (abs != a && abs < start + menurows && i > 0);
259263660c0SAlfonso Siciliano 
260263660c0SAlfonso Siciliano 	return (abs);
261c76f0793SBaptiste Daroussin }
262c76f0793SBaptiste Daroussin 
263263660c0SAlfonso Siciliano static int
getfastprev(int menurows,struct privateitem * pritems,int abs)264263660c0SAlfonso Siciliano getfastprev(int menurows, struct privateitem *pritems, int abs)
265c76f0793SBaptiste Daroussin {
266c76f0793SBaptiste Daroussin 	int a, start, i;
267c76f0793SBaptiste Daroussin 
268263660c0SAlfonso Siciliano 	start = abs;
269c76f0793SBaptiste Daroussin 	i = menurows;
270c76f0793SBaptiste Daroussin 	do {
271263660c0SAlfonso Siciliano 		a = abs;
272263660c0SAlfonso Siciliano 		abs = getprev(pritems, abs);
273c76f0793SBaptiste Daroussin 		i--;
274263660c0SAlfonso Siciliano 	} while (abs != a && abs > start - menurows && i > 0);
275263660c0SAlfonso Siciliano 
276263660c0SAlfonso Siciliano 	return (abs);
277c76f0793SBaptiste Daroussin }
278c76f0793SBaptiste Daroussin 
279263660c0SAlfonso Siciliano static int
getnextshortcut(int npritems,struct privateitem * pritems,int abs,wint_t key)28061ba55bcSBaptiste Daroussin getnextshortcut(int npritems, struct privateitem *pritems, int abs, wint_t key)
2818c4f4028SBaptiste Daroussin {
282b319d934SAlfonso S. Siciliano 	int i, next;
2838c4f4028SBaptiste Daroussin 
284263660c0SAlfonso Siciliano 	next = -1;
285263660c0SAlfonso Siciliano 	for (i = 0; i < npritems; i++) {
286263660c0SAlfonso Siciliano 		if (pritems[i].type == SEPARATORMODE)
2878c4f4028SBaptiste Daroussin 			continue;
28861ba55bcSBaptiste Daroussin 		if (pritems[i].shortcut == (wchar_t)key) {
289263660c0SAlfonso Siciliano 			if (i > abs)
290263660c0SAlfonso Siciliano 				return (i);
291263660c0SAlfonso Siciliano 			if (i < abs && next == -1)
292263660c0SAlfonso Siciliano 				next = i;
2938c4f4028SBaptiste Daroussin 		}
2948c4f4028SBaptiste Daroussin 	}
2958c4f4028SBaptiste Daroussin 
296263660c0SAlfonso Siciliano 	return (next != -1 ? next : abs);
2978c4f4028SBaptiste Daroussin }
2988c4f4028SBaptiste Daroussin 
drawseparators(struct bsddialog_conf * conf,struct privatemenu * m)29961ba55bcSBaptiste Daroussin static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m)
300c76f0793SBaptiste Daroussin {
301*a6d8be45SAlfonso S. Siciliano 	int i, realw, labellen;
302bce40c02SAlfonso S. Siciliano 	const char *desc, *name;
303263660c0SAlfonso Siciliano 
30461ba55bcSBaptiste Daroussin 	for (i = 0; i < m->nitems; i++) {
30561ba55bcSBaptiste Daroussin 		if (m->pritems[i].type != SEPARATORMODE)
306bce40c02SAlfonso S. Siciliano 			continue;
307f499134dSBaptiste Daroussin 		if (conf->no_lines == false) {
30861ba55bcSBaptiste Daroussin 			wattron(m->pad, t.menu.desccolor);
309*a6d8be45SAlfonso S. Siciliano 			if (conf->ascii_lines)
310*a6d8be45SAlfonso S. Siciliano 				mvwhline(m->pad, i, 0, '-', m->line);
311*a6d8be45SAlfonso S. Siciliano 			else
312*a6d8be45SAlfonso S. Siciliano 				mvwhline_set(m->pad, i, 0, WACS_HLINE, m->line);
31361ba55bcSBaptiste Daroussin 			wattroff(m->pad, t.menu.desccolor);
314c76f0793SBaptiste Daroussin 		}
31561ba55bcSBaptiste Daroussin 		name = m->pritems[i].name;
31661ba55bcSBaptiste Daroussin 		desc = m->pritems[i].desc;
31761ba55bcSBaptiste Daroussin 		realw = m->xe - m->xs;
318b319d934SAlfonso S. Siciliano 		labellen = strcols(name) + strcols(desc) + 1;
31961ba55bcSBaptiste Daroussin 		wmove(m->pad, i, (labellen < realw) ? realw/2 - labellen/2 : 0);
32061ba55bcSBaptiste Daroussin 		wattron(m->pad, t.menu.sepnamecolor);
32161ba55bcSBaptiste Daroussin 		waddstr(m->pad, name);
32261ba55bcSBaptiste Daroussin 		wattroff(m->pad, t.menu.sepnamecolor);
323b319d934SAlfonso S. Siciliano 		if (strcols(name) > 0 && strcols(desc) > 0)
32461ba55bcSBaptiste Daroussin 			waddch(m->pad, ' ');
32561ba55bcSBaptiste Daroussin 		wattron(m->pad, t.menu.sepdesccolor);
32661ba55bcSBaptiste Daroussin 		waddstr(m->pad, desc);
32761ba55bcSBaptiste Daroussin 		wattroff(m->pad, t.menu.sepdesccolor);
328bce40c02SAlfonso S. Siciliano 	}
329c76f0793SBaptiste Daroussin }
330c76f0793SBaptiste Daroussin 
331bce40c02SAlfonso S. Siciliano static void
drawitem(struct bsddialog_conf * conf,struct privatemenu * m,int y,bool focus)33261ba55bcSBaptiste Daroussin drawitem(struct bsddialog_conf *conf, struct privatemenu *m, int y, bool focus)
333bce40c02SAlfonso S. Siciliano {
334bce40c02SAlfonso S. Siciliano 	int colordesc, colorname, colorshortcut;
33561ba55bcSBaptiste Daroussin 	struct privateitem *pritem;
336bce40c02SAlfonso S. Siciliano 
33761ba55bcSBaptiste Daroussin 	pritem = &m->pritems[y];
338bce40c02SAlfonso S. Siciliano 
339c76f0793SBaptiste Daroussin 	/* prefix */
34061ba55bcSBaptiste Daroussin 	wattron(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
34161ba55bcSBaptiste Daroussin 	mvwaddstr(m->pad, y, 0, pritem->prefix);
34261ba55bcSBaptiste Daroussin 	wattroff(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
343c76f0793SBaptiste Daroussin 
344c76f0793SBaptiste Daroussin 	/* selector */
34561ba55bcSBaptiste Daroussin 	wmove(m->pad, y, m->xselector);
34661ba55bcSBaptiste Daroussin 	wattron(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
347bce40c02SAlfonso S. Siciliano 	if (pritem->type == CHECKLISTMODE)
34861ba55bcSBaptiste Daroussin 		wprintw(m->pad, "[%c]", pritem->on ? 'X' : ' ');
349bce40c02SAlfonso S. Siciliano 	if (pritem->type == RADIOLISTMODE)
35061ba55bcSBaptiste Daroussin 		wprintw(m->pad, "(%c)", pritem->on ? '*' : ' ');
35161ba55bcSBaptiste Daroussin 	wattroff(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
352c76f0793SBaptiste Daroussin 
353c76f0793SBaptiste Daroussin 	/* name */
354263660c0SAlfonso Siciliano 	colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
355263660c0SAlfonso Siciliano 	if (conf->menu.no_name == false) {
35661ba55bcSBaptiste Daroussin 		wattron(m->pad, colorname);
35761ba55bcSBaptiste Daroussin 		mvwaddstr(m->pad, y, m->xname + pritem->depth, pritem->name);
35861ba55bcSBaptiste Daroussin 		wattroff(m->pad, colorname);
359c76f0793SBaptiste Daroussin 	}
360c76f0793SBaptiste Daroussin 
361c76f0793SBaptiste Daroussin 	/* description */
3628c4f4028SBaptiste Daroussin 	if (conf->menu.no_name)
363263660c0SAlfonso Siciliano 		colordesc = focus ? t.menu.f_namecolor : t.menu.namecolor;
3648c4f4028SBaptiste Daroussin 	else
365263660c0SAlfonso Siciliano 		colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
366263660c0SAlfonso Siciliano 
367263660c0SAlfonso Siciliano 	if (conf->menu.no_desc == false) {
36861ba55bcSBaptiste Daroussin 		wattron(m->pad, colordesc);
369f499134dSBaptiste Daroussin 		if (conf->menu.no_name)
37061ba55bcSBaptiste Daroussin 			mvwaddstr(m->pad, y, m->xname + pritem->depth,
37161ba55bcSBaptiste Daroussin 			    pritem->desc);
372c76f0793SBaptiste Daroussin 		else
37361ba55bcSBaptiste Daroussin 			mvwaddstr(m->pad, y, m->xdesc, pritem->desc);
37461ba55bcSBaptiste Daroussin 		wattroff(m->pad, colordesc);
375c76f0793SBaptiste Daroussin 	}
376c76f0793SBaptiste Daroussin 
3778c4f4028SBaptiste Daroussin 	/* shortcut */
378263660c0SAlfonso Siciliano 	if (conf->menu.shortcut_buttons == false) {
379263660c0SAlfonso Siciliano 		colorshortcut = focus ?
380263660c0SAlfonso Siciliano 		    t.menu.f_shortcutcolor : t.menu.shortcutcolor;
38161ba55bcSBaptiste Daroussin 		wattron(m->pad, colorshortcut);
38261ba55bcSBaptiste Daroussin 		mvwaddwch(m->pad, y, m->xname + pritem->depth, pritem->shortcut);
38361ba55bcSBaptiste Daroussin 		wattroff(m->pad, colorshortcut);
3848c4f4028SBaptiste Daroussin 	}
3858c4f4028SBaptiste Daroussin 
3868c4f4028SBaptiste Daroussin 	/* bottom description */
38761ba55bcSBaptiste Daroussin 	if (m->hasbottomdesc) {
388263660c0SAlfonso Siciliano 		move(SCREENLINES - 1, 2);
389c76f0793SBaptiste Daroussin 		clrtoeol();
39061ba55bcSBaptiste Daroussin 		if (focus) {
391b319d934SAlfonso S. Siciliano 			attron(t.menu.bottomdesccolor);
39261ba55bcSBaptiste Daroussin 			addstr(pritem->bottomdesc);
393b319d934SAlfonso S. Siciliano 			attroff(t.menu.bottomdesccolor);
394c76f0793SBaptiste Daroussin 			refresh();
395c76f0793SBaptiste Daroussin 		}
396c76f0793SBaptiste Daroussin 	}
39761ba55bcSBaptiste Daroussin }
398c76f0793SBaptiste Daroussin 
update_menubox(struct bsddialog_conf * conf,struct privatemenu * m)39961ba55bcSBaptiste Daroussin static void update_menubox(struct bsddialog_conf *conf, struct privatemenu *m)
400b319d934SAlfonso S. Siciliano {
40161ba55bcSBaptiste Daroussin 	int h, w;
402b319d934SAlfonso S. Siciliano 
40361ba55bcSBaptiste Daroussin 	draw_borders(conf, m->box, LOWERED);
40461ba55bcSBaptiste Daroussin 	getmaxyx(m->box, h, w);
40561ba55bcSBaptiste Daroussin 
40661ba55bcSBaptiste Daroussin 	if (m->nitems > (int)m->menurows) {
40761ba55bcSBaptiste Daroussin 		wattron(m->box, t.dialog.arrowcolor);
40861ba55bcSBaptiste Daroussin 		if (m->ypad > 0)
409*a6d8be45SAlfonso S. Siciliano 			mvwhline(m->box, 0, 2, UARROW(conf), 3);
410b319d934SAlfonso S. Siciliano 
41161ba55bcSBaptiste Daroussin 		if ((m->ypad + (int)m->menurows) < m->nitems)
412*a6d8be45SAlfonso S. Siciliano 			mvwhline(m->box, h-1, 2, DARROW(conf), 3);
413b319d934SAlfonso S. Siciliano 
41461ba55bcSBaptiste Daroussin 		mvwprintw(m->box, h-1, w-6, "%3d%%",
41561ba55bcSBaptiste Daroussin 		    100 * (m->ypad + m->menurows) / m->nitems);
41661ba55bcSBaptiste Daroussin 		wattroff(m->box, t.dialog.arrowcolor);
417b319d934SAlfonso S. Siciliano 	}
418b319d934SAlfonso S. Siciliano }
419b319d934SAlfonso S. Siciliano 
menu_size_position(struct dialog * d,struct privatemenu * m)42061ba55bcSBaptiste Daroussin static int menu_size_position(struct dialog *d, struct privatemenu *m)
421c76f0793SBaptiste Daroussin {
42261ba55bcSBaptiste Daroussin 	int htext, hmenu;
423c76f0793SBaptiste Daroussin 
42461ba55bcSBaptiste Daroussin 	if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
425263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
426c76f0793SBaptiste Daroussin 
42761ba55bcSBaptiste Daroussin 	hmenu = (int)(m->menurows == BSDDIALOG_AUTOSIZE) ?
42861ba55bcSBaptiste Daroussin 	    (int)m->nitems : (int)m->menurows;
42961ba55bcSBaptiste Daroussin 	hmenu += 2; /* menu borders */
43061ba55bcSBaptiste Daroussin 	/*
43161ba55bcSBaptiste Daroussin 	 * algo 1: notext = 1 (grows vertically).
43261ba55bcSBaptiste Daroussin 	 * algo 2: notext = hmenu (grows horizontally, better for little term).
43361ba55bcSBaptiste Daroussin 	 */
43461ba55bcSBaptiste Daroussin 	if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
43561ba55bcSBaptiste Daroussin 	    d->text, &htext, &d->bs, hmenu, m->line + 4) != 0)
43661ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
43761ba55bcSBaptiste Daroussin 	/* avoid menurows overflow and menurows becomes "at most menurows" */
43861ba55bcSBaptiste Daroussin 	if (d->h - BORDERS - htext - HBUTTONS <= 2 /* menuborders */)
43961ba55bcSBaptiste Daroussin 		m->menurows = (m->nitems > 0) ? 1 : 0; /* widget_checksize() */
440b319d934SAlfonso S. Siciliano 	else
44161ba55bcSBaptiste Daroussin 		m->menurows = MIN(d->h - BORDERS - htext - HBUTTONS, hmenu) - 2;
442263660c0SAlfonso Siciliano 
44361ba55bcSBaptiste Daroussin 	/*
44461ba55bcSBaptiste Daroussin 	 * no minw=linelen to avoid big menu fault, then some col can be
44561ba55bcSBaptiste Daroussin 	 * hidden (example portconfig www/apache24).
44661ba55bcSBaptiste Daroussin 	 */
44761ba55bcSBaptiste Daroussin 	if (widget_checksize(d->h, d->w, &d->bs,
44861ba55bcSBaptiste Daroussin 	    2 /* border box */ + MIN(m->menurows, 1), 0) != 0)
44961ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
45061ba55bcSBaptiste Daroussin 
45161ba55bcSBaptiste Daroussin 	if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
45261ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
45384823cc7SAlfonso S. Siciliano 
454263660c0SAlfonso Siciliano 	return (0);
455c76f0793SBaptiste Daroussin }
456c76f0793SBaptiste Daroussin 
mixedlist_redraw(struct dialog * d,struct privatemenu * m)45761ba55bcSBaptiste Daroussin static int mixedlist_redraw(struct dialog *d, struct privatemenu *m)
458c76f0793SBaptiste Daroussin {
45961ba55bcSBaptiste Daroussin 	if (d->built) {
46061ba55bcSBaptiste Daroussin 		hide_dialog(d);
46161ba55bcSBaptiste Daroussin 		refresh(); /* Important for decreasing screen */
46261ba55bcSBaptiste Daroussin 	}
46361ba55bcSBaptiste Daroussin 	m->menurows = m->apimenurows;
46461ba55bcSBaptiste Daroussin 	if (menu_size_position(d, m) != 0)
46561ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
46661ba55bcSBaptiste Daroussin 	if (draw_dialog(d) != 0)
46761ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
46861ba55bcSBaptiste Daroussin 	if (d->built)
46961ba55bcSBaptiste Daroussin 		refresh(); /* Important to fix grey lines expanding screen */
47061ba55bcSBaptiste Daroussin 	TEXTPAD(d, 2/*bmenu*/ + m->menurows + HBUTTONS);
471c76f0793SBaptiste Daroussin 
47261ba55bcSBaptiste Daroussin 	/* selected item in view*/
47361ba55bcSBaptiste Daroussin 	if (m->ypad > m->sel && m->ypad > 0)
47461ba55bcSBaptiste Daroussin 		m->ypad = m->sel;
47561ba55bcSBaptiste Daroussin 	if ((int)(m->ypad + m->menurows) <= m->sel)
47661ba55bcSBaptiste Daroussin 		m->ypad = m->sel - m->menurows + 1;
47761ba55bcSBaptiste Daroussin 	/* lower pad after a terminal expansion */
47861ba55bcSBaptiste Daroussin 	if (m->ypad > 0 && (m->nitems - m->ypad) < (int)m->menurows)
47961ba55bcSBaptiste Daroussin 		m->ypad = m->nitems - m->menurows;
480c76f0793SBaptiste Daroussin 
48161ba55bcSBaptiste Daroussin 	update_box(d->conf, m->box, d->y + d->h - 5 - m->menurows, d->x + 2,
48261ba55bcSBaptiste Daroussin 	    m->menurows+2, d->w-4, LOWERED);
48361ba55bcSBaptiste Daroussin 	update_menubox(d->conf, m);
48461ba55bcSBaptiste Daroussin 	wnoutrefresh(m->box);
485c76f0793SBaptiste Daroussin 
48661ba55bcSBaptiste Daroussin 	m->ys = d->y + d->h - 5 - m->menurows + 1;
48761ba55bcSBaptiste Daroussin 	m->ye = d->y + d->h - 5 ;
48861ba55bcSBaptiste Daroussin 	if (d->conf->menu.align_left || (int)m->line > d->w - 6) {
48961ba55bcSBaptiste Daroussin 		m->xs = d->x + 3;
49061ba55bcSBaptiste Daroussin 		m->xe = m->xs + d->w - 7;
49161ba55bcSBaptiste Daroussin 	} else { /* center */
49261ba55bcSBaptiste Daroussin 		m->xs = d->x + 3 + (d->w-6)/2 - m->line/2;
49361ba55bcSBaptiste Daroussin 		m->xe = m->xs + d->w - 5;
49461ba55bcSBaptiste Daroussin 	}
49561ba55bcSBaptiste Daroussin 	drawseparators(d->conf, m); /* uses xe - xs */
49661ba55bcSBaptiste Daroussin 	pnoutrefresh(m->pad, m->ypad, 0, m->ys, m->xs, m->ye, m->xe);
497c76f0793SBaptiste Daroussin 
498263660c0SAlfonso Siciliano 	return (0);
499c76f0793SBaptiste Daroussin }
500c76f0793SBaptiste Daroussin 
501c76f0793SBaptiste Daroussin static int
do_mixedlist(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int menurows,enum menumode mode,unsigned int ngroups,struct bsddialog_menugroup * groups,int * focuslist,int * focusitem)502263660c0SAlfonso Siciliano do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
503263660c0SAlfonso Siciliano     unsigned int menurows, enum menumode mode, unsigned int ngroups,
504c76f0793SBaptiste Daroussin     struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
505c76f0793SBaptiste Daroussin {
50661ba55bcSBaptiste Daroussin 	bool loop, changeitem;
50761ba55bcSBaptiste Daroussin 	int i, next, retval;
508b319d934SAlfonso S. Siciliano 	wint_t input;
50961ba55bcSBaptiste Daroussin 	struct privatemenu m;
51061ba55bcSBaptiste Daroussin 	struct dialog d;
511c76f0793SBaptiste Daroussin 
51261ba55bcSBaptiste Daroussin 	if (prepare_dialog(conf, text, rows, cols, &d) != 0)
513263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
51461ba55bcSBaptiste Daroussin 	set_buttons(&d, conf->menu.shortcut_buttons, OK_LABEL, CANCEL_LABEL);
51561ba55bcSBaptiste Daroussin 	if (d.conf->menu.no_name && d.conf->menu.no_desc)
51661ba55bcSBaptiste Daroussin 		RETURN_ERROR("Both conf.menu.no_name and conf.menu.no_desc");
51761ba55bcSBaptiste Daroussin 
51861ba55bcSBaptiste Daroussin 	if (build_privatemenu(conf, &m, mode, ngroups, groups) != 0)
519263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
520c76f0793SBaptiste Daroussin 
52161ba55bcSBaptiste Daroussin 	if ((m.box = newwin(1, 1, 1, 1)) == NULL)
52261ba55bcSBaptiste Daroussin 		RETURN_ERROR("Cannot build WINDOW box menu");
52361ba55bcSBaptiste Daroussin 	wbkgd(m.box, t.dialog.color);
52461ba55bcSBaptiste Daroussin 	m.pad = newpad(m.nitems, m.line);
52561ba55bcSBaptiste Daroussin 	wbkgd(m.pad, t.dialog.color);
526c76f0793SBaptiste Daroussin 
52761ba55bcSBaptiste Daroussin 	for (i = 0; i < m.nitems; i++)
52861ba55bcSBaptiste Daroussin 		drawitem(conf, &m, i, false);
52961ba55bcSBaptiste Daroussin 	m.sel = getfirst_with_default(m.nitems, m.pritems, ngroups, groups,
530263660c0SAlfonso Siciliano 	    focuslist, focusitem);
53161ba55bcSBaptiste Daroussin 	if (m.sel >= 0)
53261ba55bcSBaptiste Daroussin 		drawitem(d.conf, &m, m.sel, true);
53361ba55bcSBaptiste Daroussin 	m.ypad = 0;
53461ba55bcSBaptiste Daroussin 	m.apimenurows = menurows;
53561ba55bcSBaptiste Daroussin 	if (mixedlist_redraw(&d, &m) != 0)
53661ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
537c76f0793SBaptiste Daroussin 
53861ba55bcSBaptiste Daroussin 	changeitem = false;
539c76f0793SBaptiste Daroussin 	loop = true;
540c76f0793SBaptiste Daroussin 	while (loop) {
54161ba55bcSBaptiste Daroussin 		doupdate();
542b319d934SAlfonso S. Siciliano 		if (get_wch(&input) == ERR)
543b319d934SAlfonso S. Siciliano 			continue;
544c76f0793SBaptiste Daroussin 		switch(input) {
545c76f0793SBaptiste Daroussin 		case KEY_ENTER:
546c76f0793SBaptiste Daroussin 		case 10: /* Enter */
54761ba55bcSBaptiste Daroussin 			retval = BUTTONVALUE(d.bs);
54861ba55bcSBaptiste Daroussin 			if (m.sel >= 0 && m.pritems[m.sel].type == MENUMODE)
54961ba55bcSBaptiste Daroussin 				m.pritems[m.sel].on = true;
550c76f0793SBaptiste Daroussin 			loop = false;
551c76f0793SBaptiste Daroussin 			break;
552c76f0793SBaptiste Daroussin 		case 27: /* Esc */
553263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
554b319d934SAlfonso S. Siciliano 				retval = BSDDIALOG_ESC;
55561ba55bcSBaptiste Daroussin 				if (m.sel >= 0 &&
55661ba55bcSBaptiste Daroussin 				   m.pritems[m.sel].type == MENUMODE)
55761ba55bcSBaptiste Daroussin 					m.pritems[m.sel].on = true;
558c76f0793SBaptiste Daroussin 				loop = false;
559263660c0SAlfonso Siciliano 			}
560c76f0793SBaptiste Daroussin 			break;
561c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
56261ba55bcSBaptiste Daroussin 		case KEY_RIGHT:
56361ba55bcSBaptiste Daroussin 			d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
56461ba55bcSBaptiste Daroussin 			DRAW_BUTTONS(d);
565c76f0793SBaptiste Daroussin 			break;
566c76f0793SBaptiste Daroussin 		case KEY_LEFT:
56761ba55bcSBaptiste Daroussin 			d.bs.curr--;
56861ba55bcSBaptiste Daroussin 			if (d.bs.curr < 0)
56961ba55bcSBaptiste Daroussin 				 d.bs.curr = d.bs.nbuttons - 1;
57061ba55bcSBaptiste Daroussin 			DRAW_BUTTONS(d);
571c76f0793SBaptiste Daroussin 			break;
572c76f0793SBaptiste Daroussin 		case KEY_F(1):
573bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
574bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
575c76f0793SBaptiste Daroussin 				break;
57661ba55bcSBaptiste Daroussin 			if (f1help_dialog(conf) != 0)
577263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
57861ba55bcSBaptiste Daroussin 			if (mixedlist_redraw(&d, &m) != 0)
57961ba55bcSBaptiste Daroussin 				return (BSDDIALOG_ERROR);
58061ba55bcSBaptiste Daroussin 			break;
581*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('l'):
582c76f0793SBaptiste Daroussin 		case KEY_RESIZE:
58361ba55bcSBaptiste Daroussin 			if (mixedlist_redraw(&d, &m) != 0)
584263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
585c76f0793SBaptiste Daroussin 			break;
586c76f0793SBaptiste Daroussin 		}
587c76f0793SBaptiste Daroussin 
58861ba55bcSBaptiste Daroussin 		if (m.sel < 0)
589c76f0793SBaptiste Daroussin 			continue;
590c76f0793SBaptiste Daroussin 		switch(input) {
591c76f0793SBaptiste Daroussin 		case KEY_HOME:
59261ba55bcSBaptiste Daroussin 			next = getnext(m.nitems, m.pritems, -1);
59361ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
594c76f0793SBaptiste Daroussin 			break;
595*a6d8be45SAlfonso S. Siciliano 		case '-':
596*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('p'):
597263660c0SAlfonso Siciliano 		case KEY_UP:
59861ba55bcSBaptiste Daroussin 			next = getprev(m.pritems, m.sel);
59961ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
600263660c0SAlfonso Siciliano 			break;
601263660c0SAlfonso Siciliano 		case KEY_PPAGE:
60261ba55bcSBaptiste Daroussin 			next = getfastprev(m.menurows, m.pritems, m.sel);
60361ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
604c76f0793SBaptiste Daroussin 			break;
605c76f0793SBaptiste Daroussin 		case KEY_END:
60661ba55bcSBaptiste Daroussin 			next = getprev(m.pritems, m.nitems);
60761ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
608263660c0SAlfonso Siciliano 			break;
609*a6d8be45SAlfonso S. Siciliano 		case '+':
610*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('n'):
611c76f0793SBaptiste Daroussin 		case KEY_DOWN:
61261ba55bcSBaptiste Daroussin 			next = getnext(m.nitems, m.pritems, m.sel);
61361ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
614263660c0SAlfonso Siciliano 			break;
615c76f0793SBaptiste Daroussin 		case KEY_NPAGE:
61661ba55bcSBaptiste Daroussin 			next = getfastnext(m.menurows, m.nitems, m.pritems, m.sel);
61761ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
618c76f0793SBaptiste Daroussin 			break;
619c76f0793SBaptiste Daroussin 		case ' ': /* Space */
62061ba55bcSBaptiste Daroussin 			if (m.pritems[m.sel].type == MENUMODE) {
62161ba55bcSBaptiste Daroussin 				retval = BUTTONVALUE(d.bs);
62261ba55bcSBaptiste Daroussin 				m.pritems[m.sel].on = true;
62384823cc7SAlfonso S. Siciliano 				loop = false;
62461ba55bcSBaptiste Daroussin 			} else if (m.pritems[m.sel].type == CHECKLISTMODE) {
62561ba55bcSBaptiste Daroussin 				m.pritems[m.sel].on = !m.pritems[m.sel].on;
62684823cc7SAlfonso S. Siciliano 			} else { /* RADIOLISTMODE */
62761ba55bcSBaptiste Daroussin 				for (i = m.sel - m.pritems[m.sel].index;
62861ba55bcSBaptiste Daroussin 				    i < m.nitems &&
62961ba55bcSBaptiste Daroussin 				    m.pritems[i].group == m.pritems[m.sel].group;
630263660c0SAlfonso Siciliano 				    i++) {
63161ba55bcSBaptiste Daroussin 					if (i != m.sel && m.pritems[i].on) {
63261ba55bcSBaptiste Daroussin 						m.pritems[i].on = false;
63361ba55bcSBaptiste Daroussin 						drawitem(conf, &m, i, false);
634c76f0793SBaptiste Daroussin 					}
635c76f0793SBaptiste Daroussin 				}
63661ba55bcSBaptiste Daroussin 				m.pritems[m.sel].on = !m.pritems[m.sel].on;
637263660c0SAlfonso Siciliano 			}
63861ba55bcSBaptiste Daroussin 			drawitem(conf, &m, m.sel, true);
63961ba55bcSBaptiste Daroussin 			pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
640263660c0SAlfonso Siciliano 			break;
6418c4f4028SBaptiste Daroussin 		default:
64261ba55bcSBaptiste Daroussin 			if (conf->menu.shortcut_buttons) {
64361ba55bcSBaptiste Daroussin 				if (shortcut_buttons(input, &d.bs)) {
64461ba55bcSBaptiste Daroussin 					DRAW_BUTTONS(d);
64561ba55bcSBaptiste Daroussin 					doupdate();
64661ba55bcSBaptiste Daroussin 					retval = BUTTONVALUE(d.bs);
64761ba55bcSBaptiste Daroussin 					if (m.pritems[m.sel].type == MENUMODE)
64861ba55bcSBaptiste Daroussin 						m.pritems[m.sel].on = true;
6498c4f4028SBaptiste Daroussin 					loop = false;
6508c4f4028SBaptiste Daroussin 				}
6518c4f4028SBaptiste Daroussin 				break;
6528c4f4028SBaptiste Daroussin 			}
6538c4f4028SBaptiste Daroussin 
654263660c0SAlfonso Siciliano 			/* shourtcut items */
65561ba55bcSBaptiste Daroussin 			next = getnextshortcut(m.nitems, m.pritems, m.sel,
656263660c0SAlfonso Siciliano 			    input);
65761ba55bcSBaptiste Daroussin 			changeitem = next != m.sel;
65861ba55bcSBaptiste Daroussin 		} /* end switch get_wch() */
659263660c0SAlfonso Siciliano 
66061ba55bcSBaptiste Daroussin 		if (changeitem) {
66161ba55bcSBaptiste Daroussin 			drawitem(conf, &m, m.sel, false);
66261ba55bcSBaptiste Daroussin 			m.sel = next;
66361ba55bcSBaptiste Daroussin 			drawitem(conf, &m, m.sel, true);
66461ba55bcSBaptiste Daroussin 			if (m.ypad > m.sel && m.ypad > 0)
66561ba55bcSBaptiste Daroussin 				m.ypad = m.sel;
66661ba55bcSBaptiste Daroussin 			if ((int)(m.ypad + m.menurows) <= m.sel)
66761ba55bcSBaptiste Daroussin 				m.ypad = m.sel - m.menurows + 1;
66861ba55bcSBaptiste Daroussin 			update_menubox(conf, &m);
66961ba55bcSBaptiste Daroussin 			wnoutrefresh(m.box);
67061ba55bcSBaptiste Daroussin 			pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
67161ba55bcSBaptiste Daroussin 			changeitem = false;
672c76f0793SBaptiste Daroussin 		}
67361ba55bcSBaptiste Daroussin 	} /* end while (loop) */
67461ba55bcSBaptiste Daroussin 
67561ba55bcSBaptiste Daroussin 	set_return_on(&m, groups);
676c76f0793SBaptiste Daroussin 
677c76f0793SBaptiste Daroussin 	if (focuslist != NULL)
67861ba55bcSBaptiste Daroussin 		*focuslist = m.sel < 0 ? -1 : m.pritems[m.sel].group;
679c76f0793SBaptiste Daroussin 	if (focusitem !=NULL)
68061ba55bcSBaptiste Daroussin 		*focusitem = m.sel < 0 ? -1 : m.pritems[m.sel].index;
681c76f0793SBaptiste Daroussin 
68261ba55bcSBaptiste Daroussin 	if (m.hasbottomdesc && conf->clear) {
68361ba55bcSBaptiste Daroussin 		move(SCREENLINES - 1, 2);
68461ba55bcSBaptiste Daroussin 		clrtoeol();
68561ba55bcSBaptiste Daroussin 	}
68661ba55bcSBaptiste Daroussin 	delwin(m.pad);
68761ba55bcSBaptiste Daroussin 	delwin(m.box);
68861ba55bcSBaptiste Daroussin 	end_dialog(&d);
68961ba55bcSBaptiste Daroussin 	free(m.pritems);
690c76f0793SBaptiste Daroussin 
691b319d934SAlfonso S. Siciliano 	return (retval);
692c76f0793SBaptiste Daroussin }
693c76f0793SBaptiste Daroussin 
694263660c0SAlfonso Siciliano /* API */
695263660c0SAlfonso Siciliano int
bsddialog_mixedlist(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int menurows,unsigned int ngroups,struct bsddialog_menugroup * groups,int * focuslist,int * focusitem)696263660c0SAlfonso Siciliano bsddialog_mixedlist(struct bsddialog_conf *conf, const char *text, int rows,
697263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int ngroups,
698263660c0SAlfonso Siciliano     struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
699c76f0793SBaptiste Daroussin {
700b319d934SAlfonso S. Siciliano 	int retval;
701c76f0793SBaptiste Daroussin 
702b319d934SAlfonso S. Siciliano 	retval = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
703c76f0793SBaptiste Daroussin 	    ngroups, groups, focuslist, focusitem);
704c76f0793SBaptiste Daroussin 
705b319d934SAlfonso S. Siciliano 	return (retval);
706c76f0793SBaptiste Daroussin }
707c76f0793SBaptiste Daroussin 
708c76f0793SBaptiste Daroussin int
bsddialog_checklist(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int menurows,unsigned int nitems,struct bsddialog_menuitem * items,int * focusitem)709263660c0SAlfonso Siciliano bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
710263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
711263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
712c76f0793SBaptiste Daroussin {
713b319d934SAlfonso S. Siciliano 	int retval, focuslist = 0;
714c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
71561ba55bcSBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
716c76f0793SBaptiste Daroussin 
71761ba55bcSBaptiste Daroussin 	CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
718b319d934SAlfonso S. Siciliano 	retval = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
719263660c0SAlfonso Siciliano 	    1, &group, &focuslist, focusitem);
720c76f0793SBaptiste Daroussin 
721b319d934SAlfonso S. Siciliano 	return (retval);
722c76f0793SBaptiste Daroussin }
723c76f0793SBaptiste Daroussin 
724c76f0793SBaptiste Daroussin int
bsddialog_menu(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int menurows,unsigned int nitems,struct bsddialog_menuitem * items,int * focusitem)725263660c0SAlfonso Siciliano bsddialog_menu(struct bsddialog_conf *conf, const char *text, int rows,
726263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
727263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
728c76f0793SBaptiste Daroussin {
729b319d934SAlfonso S. Siciliano 	int retval, focuslist = 0;
730c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
73161ba55bcSBaptiste Daroussin 	    BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
732c76f0793SBaptiste Daroussin 
73361ba55bcSBaptiste Daroussin 	CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
734b319d934SAlfonso S. Siciliano 	retval = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
735263660c0SAlfonso Siciliano 	    &group, &focuslist, focusitem);
736c76f0793SBaptiste Daroussin 
737b319d934SAlfonso S. Siciliano 	return (retval);
738c76f0793SBaptiste Daroussin }
739c76f0793SBaptiste Daroussin 
740c76f0793SBaptiste Daroussin int
bsddialog_radiolist(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int menurows,unsigned int nitems,struct bsddialog_menuitem * items,int * focusitem)741263660c0SAlfonso Siciliano bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
742263660c0SAlfonso Siciliano     int cols, unsigned int menurows, unsigned int nitems,
743263660c0SAlfonso Siciliano     struct bsddialog_menuitem *items, int *focusitem)
744c76f0793SBaptiste Daroussin {
745b319d934SAlfonso S. Siciliano 	int retval, focuslist = 0;
746c76f0793SBaptiste Daroussin 	struct bsddialog_menugroup group = {
74761ba55bcSBaptiste Daroussin 	    BSDDIALOG_RADIOLIST /* unused */, nitems, items, 0};
748c76f0793SBaptiste Daroussin 
74961ba55bcSBaptiste Daroussin 	CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
750b319d934SAlfonso S. Siciliano 	retval = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
751263660c0SAlfonso Siciliano 	    1, &group, &focuslist, focusitem);
752c76f0793SBaptiste Daroussin 
753b319d934SAlfonso S. Siciliano 	return (retval);
754c76f0793SBaptiste Daroussin }
755