aboutsummaryrefslogtreecommitdiff
path: root/contrib/bsddialog/lib/menubox.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsddialog/lib/menubox.c')
-rw-r--r--contrib/bsddialog/lib/menubox.c880
1 files changed, 405 insertions, 475 deletions
diff --git a/contrib/bsddialog/lib/menubox.c b/contrib/bsddialog/lib/menubox.c
index 22ed15e6e7a0..b6213aa8f997 100644
--- a/contrib/bsddialog/lib/menubox.c
+++ b/contrib/bsddialog/lib/menubox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,20 +25,13 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define DEPTH 2
-#define MIN_HEIGHT VBORDERS + 6 /* 2 buttons 1 text 3 menu */
-
enum menumode {
CHECKLISTMODE,
MENUMODE,
@@ -47,47 +40,155 @@ enum menumode {
SEPARATORMODE
};
-struct lineposition {
- unsigned int maxsepstr;
- unsigned int maxprefix;
- unsigned int xselector;
- unsigned int selectorlen;
- unsigned int maxdepth;
- unsigned int xname;
- unsigned int maxname;
- unsigned int xdesc;
- unsigned int maxdesc;
- unsigned int line;
-};
-
struct privateitem {
- bool on;
- int group;
- int index;
+ const char *prefix;
+ bool on; /* menu changes, not API on */
+ unsigned int depth;
+ const char *name;
+ const char *desc;
+ const char *bottomdesc;
+ int group; /* index menu in menugroup */
+ int index; /* real item index inside its menu */
enum menumode type;
- struct bsddialog_menuitem *item;
+ wchar_t shortcut;
};
-static void
-set_on_output(struct bsddialog_conf *conf, int output, int ngroups,
- struct bsddialog_menugroup *groups, struct privateitem *pritems)
+struct privatemenu {
+ WINDOW *box; /* only for borders */
+ WINDOW *pad; /* pad for the private items */
+ int ypad; /* start pad line */
+ int ys, ye, xs, xe; /* pad pos */
+ unsigned int xselector; /* [] */
+ unsigned int xname; /* real x: xname + item.depth */
+ unsigned int xdesc; /* real x: xdesc + item.depth */
+ unsigned int line; /* wpad: prefix [] depth name desc */
+ unsigned int apimenurows;
+ unsigned int menurows; /* real menurows after menu_size_position() */
+ int nitems; /* total nitems (all groups * all items) */
+ struct privateitem *pritems;
+ int sel; /* current focus item, can be -1 */
+ bool hasbottomdesc;
+};
+
+static enum menumode
+getmode(enum menumode mode, struct bsddialog_menugroup group)
{
+ if (mode == MIXEDLISTMODE) {
+ if (group.type == BSDDIALOG_SEPARATOR)
+ mode = SEPARATORMODE;
+ else if (group.type == BSDDIALOG_RADIOLIST)
+ mode = RADIOLISTMODE;
+ else if (group.type == BSDDIALOG_CHECKLIST)
+ mode = CHECKLISTMODE;
+ }
+
+ return (mode);
+}
+
+static int
+build_privatemenu(struct bsddialog_conf *conf, struct privatemenu *m,
+ enum menumode mode, unsigned int ngroups,
+ struct bsddialog_menugroup *groups)
+{
+ bool onetrue;
int i, j, abs;
+ unsigned int maxsepstr, maxprefix, selectorlen, maxdepth;
+ unsigned int maxname, maxdesc;
+ struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- if (output != BSDDIALOG_OK && !conf->menu.on_without_ok)
- return;
+ /* nitems and fault checks */
+ CHECK_ARRAY(ngroups, groups);
+ m->nitems = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ CHECK_ARRAY(groups[i].nitems, groups[i].items);
+ m->nitems += (int)groups[i].nitems;
+ }
- for(i = abs = 0; i < ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- abs += groups[i].nitems;
- continue;
- }
+ /* alloc and set private items */
+ m->pritems = calloc(m->nitems, sizeof (struct privateitem));
+ if (m->pritems == NULL)
+ RETURN_ERROR("Cannot allocate memory for internal menu items");
+ m->hasbottomdesc = false;
+ abs = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ onetrue = false;
+ for (j = 0; j < (int)groups[i].nitems; j++) {
+ item = &groups[i].items[j];
+ pritem = &m->pritems[abs];
+
+ if (getmode(mode, groups[i]) == MENUMODE) {
+ m->pritems[abs].on = false;
+ } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
+ m->pritems[abs].on = onetrue ? false : item->on;
+ if (m->pritems[abs].on)
+ onetrue = true;
+ } else { /* CHECKLISTMODE */
+ m->pritems[abs].on = item->on;
+ }
+ pritem->group = i;
+ pritem->index = j;
+ pritem->type = getmode(mode, groups[i]);
+
+ pritem->prefix = CHECK_STR(item->prefix);
+ pritem->depth = item->depth;
+ pritem->name = CHECK_STR(item->name);
+ pritem->desc = CHECK_STR(item->desc);
+ pritem->bottomdesc = CHECK_STR(item->bottomdesc);
+ if (item->bottomdesc != NULL)
+ m->hasbottomdesc = true;
+
+ mbtowc(&pritem->shortcut, conf->menu.no_name ?
+ pritem->desc : pritem->name, MB_CUR_MAX);
- for(j = 0; j < (int)groups[i].nitems; j++) {
- groups[i].items[j].on = pritems[abs].on;
abs++;
}
}
+
+ /* positions */
+ m->xselector = m->xname = m->xdesc = m->line = 0;
+ maxsepstr = maxprefix = selectorlen = maxdepth = maxname = maxdesc = 0;
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == RADIOLISTMODE ||
+ m->pritems[i].type == CHECKLISTMODE)
+ selectorlen = 4;
+
+ if (m->pritems[i].type == SEPARATORMODE) {
+ maxsepstr = MAX(maxsepstr,
+ strcols(m->pritems[i].name) +
+ strcols(m->pritems[i].desc));
+ continue;
+ }
+
+ maxprefix = MAX(maxprefix, strcols(m->pritems[i].prefix));
+ maxdepth = MAX(maxdepth, m->pritems[i].depth);
+ maxname = MAX(maxname, strcols(m->pritems[i].name));
+ maxdesc = MAX(maxdesc, strcols(m->pritems[i].desc));
+ }
+ maxname = conf->menu.no_name ? 0 : maxname;
+ maxdesc = conf->menu.no_desc ? 0 : maxdesc;
+
+ m->xselector = maxprefix + (maxprefix != 0 ? 1 : 0);
+ m->xname = m->xselector + selectorlen;
+ m->xdesc = maxdepth + m->xname + maxname;
+ m->xdesc += (maxname != 0 ? 1 : 0);
+ m->line = MAX(maxsepstr + 3, m->xdesc + maxdesc);
+
+ return (0);
+}
+
+static void
+set_return_on(struct privatemenu *m, struct bsddialog_menugroup *groups)
+{
+ int i;
+ struct privateitem *pritem;
+
+ for(i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == SEPARATORMODE)
+ continue;
+ pritem = &m->pritems[i];
+ groups[pritem->group].items[pritem->index].on = pritem->on;
+ }
}
static int getprev(struct privateitem *pritems, int abs)
@@ -176,25 +277,17 @@ getfastprev(int menurows, struct privateitem *pritems, int abs)
}
static int
-getnextshortcut(struct bsddialog_conf *conf, int npritems,
- struct privateitem *pritems, int abs, int key)
+getnextshortcut(int npritems, struct privateitem *pritems, int abs, wint_t key)
{
- int i, ch, next;
+ int i, next;
next = -1;
for (i = 0; i < npritems; i++) {
if (pritems[i].type == SEPARATORMODE)
continue;
-
- if (conf->menu.no_name)
- ch = pritems[i].item->desc[0];
- else
- ch = pritems[i].item->name[0];
-
- if (ch == key) {
+ if (pritems[i].shortcut == (wchar_t)key) {
if (i > abs)
return (i);
-
if (i < abs && next == -1)
next = i;
}
@@ -203,81 +296,64 @@ getnextshortcut(struct bsddialog_conf *conf, int npritems,
return (next != -1 ? next : abs);
}
-static enum menumode
-getmode(enum menumode mode, struct bsddialog_menugroup group)
-{
- if (mode == MIXEDLISTMODE) {
- if (group.type == BSDDIALOG_SEPARATOR)
- mode = SEPARATORMODE;
- else if (group.type == BSDDIALOG_RADIOLIST)
- mode = RADIOLISTMODE;
- else if (group.type == BSDDIALOG_CHECKLIST)
- mode = CHECKLISTMODE;
- }
-
- return (mode);
-}
-
-static void
-drawseparators(struct bsddialog_conf *conf, WINDOW *pad, int linelen,
- int nitems, struct privateitem *pritems)
+static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m)
{
- int i, linech, labellen;
+ int i, linech, realw, labellen;
const char *desc, *name;
- for (i = 0; i < nitems; i++) {
- if (pritems[i].type != SEPARATORMODE)
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type != SEPARATORMODE)
continue;
if (conf->no_lines == false) {
- wattron(pad, t.menu.desccolor);
+ wattron(m->pad, t.menu.desccolor);
linech = conf->ascii_lines ? '-' : ACS_HLINE;
- mvwhline(pad, i, 0, linech, linelen);
- wattroff(pad, t.menu.desccolor);
+ mvwhline(m->pad, i, 0, linech, m->line);
+ wattroff(m->pad, t.menu.desccolor);
}
- name = pritems[i].item->name;
- desc = pritems[i].item->desc;
- labellen = strlen(name) + strlen(desc) + 1;
- wmove(pad, i, labellen < linelen ? linelen/2 - labellen/2 : 0);
- wattron(pad, t.menu.namesepcolor);
- waddstr(pad, name);
- wattroff(pad, t.menu.namesepcolor);
- if (strlen(name) > 0 && strlen(desc) > 0)
- waddch(pad, ' ');
- wattron(pad, t.menu.descsepcolor);
- waddstr(pad, desc);
- wattroff(pad, t.menu.descsepcolor);
+ name = m->pritems[i].name;
+ desc = m->pritems[i].desc;
+ realw = m->xe - m->xs;
+ labellen = strcols(name) + strcols(desc) + 1;
+ wmove(m->pad, i, (labellen < realw) ? realw/2 - labellen/2 : 0);
+ wattron(m->pad, t.menu.sepnamecolor);
+ waddstr(m->pad, name);
+ wattroff(m->pad, t.menu.sepnamecolor);
+ if (strcols(name) > 0 && strcols(desc) > 0)
+ waddch(m->pad, ' ');
+ wattron(m->pad, t.menu.sepdesccolor);
+ waddstr(m->pad, desc);
+ wattroff(m->pad, t.menu.sepdesccolor);
}
}
static void
-drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
- struct lineposition pos, struct privateitem *pritem, bool focus)
+drawitem(struct bsddialog_conf *conf, struct privatemenu *m, int y, bool focus)
{
int colordesc, colorname, colorshortcut;
- const char *shortcut;
- struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- item = pritem->item;
+ pritem = &m->pritems[y];
/* prefix */
- if (item->prefix != NULL && item->prefix[0] != '\0')
- mvwaddstr(pad, y, 0, item->prefix);
+ wattron(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
+ mvwaddstr(m->pad, y, 0, pritem->prefix);
+ wattroff(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
/* selector */
- wmove(pad, y, pos.xselector);
- wattron(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wmove(m->pad, y, m->xselector);
+ wattron(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
if (pritem->type == CHECKLISTMODE)
- wprintw(pad, "[%c]", pritem->on ? 'X' : ' ');
+ wprintw(m->pad, "[%c]", pritem->on ? 'X' : ' ');
if (pritem->type == RADIOLISTMODE)
- wprintw(pad, "(%c)", pritem->on ? '*' : ' ');
- wattroff(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wprintw(m->pad, "(%c)", pritem->on ? '*' : ' ');
+ wattroff(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
/* name */
colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
if (conf->menu.no_name == false) {
- wattron(pad, colorname);
- mvwaddstr(pad, y, pos.xname + item->depth * DEPTH, item->name);
- wattroff(pad, colorname);
+ wattron(m->pad, colorname);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth, pritem->name);
+ wattroff(m->pad, colorname);
}
/* description */
@@ -287,145 +363,139 @@ drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
if (conf->menu.no_desc == false) {
- wattron(pad, colordesc);
+ wattron(m->pad, colordesc);
if (conf->menu.no_name)
- mvwaddstr(pad, y, pos.xname + item->depth * DEPTH,
- item->desc);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth,
+ pritem->desc);
else
- mvwaddstr(pad, y, pos.xdesc, item->desc);
- wattroff(pad, colordesc);
+ mvwaddstr(m->pad, y, m->xdesc, pritem->desc);
+ wattroff(m->pad, colordesc);
}
/* shortcut */
if (conf->menu.shortcut_buttons == false) {
colorshortcut = focus ?
t.menu.f_shortcutcolor : t.menu.shortcutcolor;
- wattron(pad, colorshortcut);
-
- if (conf->menu.no_name)
- shortcut = item->desc;
- else
- shortcut = item->name;
- wmove(pad, y, pos.xname + item->depth * DEPTH);
- if (shortcut != NULL && shortcut[0] != '\0')
- waddch(pad, shortcut[0]);
- wattroff(pad, colorshortcut);
+ wattron(m->pad, colorshortcut);
+ mvwaddwch(m->pad, y, m->xname + pritem->depth, pritem->shortcut);
+ wattroff(m->pad, colorshortcut);
}
/* bottom description */
- move(SCREENLINES - 1, 2);
- clrtoeol();
- if (item->bottomdesc != NULL && focus) {
- addstr(item->bottomdesc);
- refresh();
+ if (m->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (focus) {
+ attron(t.menu.bottomdesccolor);
+ addstr(pritem->bottomdesc);
+ attroff(t.menu.bottomdesccolor);
+ refresh();
+ }
}
}
-static int
-menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *menurows, int nitems,
- struct buttons bs)
+static void update_menubox(struct bsddialog_conf *conf, struct privatemenu *m)
{
- int htext, wtext, menusize, notext;
-
- notext = 2;
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- /* algo 1): grows vertically */
- /* notext = 1; */
- /* algo 2): grows horizontally, better with little screens */
- notext += nitems;
- notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
- } else
- notext += *menurows;
-
- /* cols autosize, rows autosize, rows fullscreen, menu particularity */
- if (cols == BSDDIALOG_AUTOSIZE || rows <= BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, notext, linelen + 4,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
+ int h, w;
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 4, &bs);
+ draw_borders(conf, m->box, LOWERED);
+ getmaxyx(m->box, h, w);
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*menurows == 0) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *menurows = menusize - 2 < 0 ? 0 : menusize - 2;
- }
- else /* h autosize with fixed menurows */
- menusize = *menurows + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- /*
- * avoid menurows overflow and
- * with rows=AUTOSIZE menurows!=0 becomes max-menurows
- */
- *menurows = MIN(*h - 6 - htext, (int)*menurows);
- } else {
- if (*menurows == 0)
- *menurows = MIN(*h-6-htext, nitems);
- }
+ if (m->nitems > (int)m->menurows) {
+ wattron(m->box, t.dialog.arrowcolor);
+ if (m->ypad > 0)
+ mvwhline(m->box, 0, 2,
+ conf->ascii_lines ? '^' : ACS_UARROW, 3);
- return (0);
+ if ((m->ypad + (int)m->menurows) < m->nitems)
+ mvwhline(m->box, h-1, 2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 3);
+
+ mvwprintw(m->box, h-1, w-6, "%3d%%",
+ 100 * (m->ypad + m->menurows) / m->nitems);
+ wattroff(m->box, t.dialog.arrowcolor);
+ }
}
-static int
-menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
- struct buttons bs)
+static int menu_size_position(struct dialog *d, struct privatemenu *m)
{
- int mincols, textrow, menusize;
+ int htext, hmenu;
- mincols = VBORDERS;
- /* buttons */
- mincols += buttons_width(bs);
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ hmenu = (int)(m->menurows == BSDDIALOG_AUTOSIZE) ?
+ (int)m->nitems : (int)m->menurows;
+ hmenu += 2; /* menu borders */
/*
- * linelen check, comment to allow some hidden col otherwise portconfig
- * could not show big menus like www/apache24
+ * algo 1: notext = 1 (grows vertically).
+ * algo 2: notext = hmenu (grows horizontally, better for little term).
*/
- /* mincols = MAX(mincols, linelen); */
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "name + descripion of the items");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, &htext, &d->bs, hmenu, m->line + 4) != 0)
+ return (BSDDIALOG_ERROR);
+ /* avoid menurows overflow and menurows becomes "at most menurows" */
+ if (d->h - BORDERS - htext - HBUTTONS <= 2 /* menuborders */)
+ m->menurows = (m->nitems > 0) ? 1 : 0; /* widget_checksize() */
+ else
+ m->menurows = MIN(d->h - BORDERS - htext - HBUTTONS, hmenu) - 2;
- if (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, probably terminal "
- "too small");
+ /*
+ * no minw=linelen to avoid big menu fault, then some col can be
+ * hidden (example portconfig www/apache24).
+ */
+ if (widget_checksize(d->h, d->w, &d->bs,
+ 2 /* border box */ + MIN(m->menurows, 1), 0) != 0)
+ return (BSDDIALOG_ERROR);
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this menus");
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
return (0);
}
-/* the caller has to call prefresh(menupad, ymenupad, 0, ys, xs, ye, xe); */
-static void
-update_menuwin(struct bsddialog_conf *conf, WINDOW *menuwin, int h, int w,
- int totnitems, unsigned int menurows, int ymenupad)
+static int mixedlist_redraw(struct dialog *d, struct privatemenu *m)
{
- draw_borders(conf, menuwin, h, w, LOWERED);
-
- if (totnitems > (int)menurows) {
- wattron(menuwin, t.dialog.arrowcolor);
-
- if (ymenupad > 0)
- mvwprintw(menuwin, 0, 2, "^^^");
-
- if ((ymenupad + (int)menurows) < totnitems)
- mvwprintw(menuwin, h-1, 2, "vvv");
-
- wattroff(menuwin, t.dialog.arrowcolor);
-
- mvwprintw(menuwin, h-1, w-10, "%3d%%",
- 100 * (ymenupad + menurows) / totnitems);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
+ m->menurows = m->apimenurows;
+ if (menu_size_position(d, m) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2/*bmenu*/ + m->menurows + HBUTTONS);
+
+ /* selected item in view*/
+ if (m->ypad > m->sel && m->ypad > 0)
+ m->ypad = m->sel;
+ if ((int)(m->ypad + m->menurows) <= m->sel)
+ m->ypad = m->sel - m->menurows + 1;
+ /* lower pad after a terminal expansion */
+ if (m->ypad > 0 && (m->nitems - m->ypad) < (int)m->menurows)
+ m->ypad = m->nitems - m->menurows;
+
+ update_box(d->conf, m->box, d->y + d->h - 5 - m->menurows, d->x + 2,
+ m->menurows+2, d->w-4, LOWERED);
+ update_menubox(d->conf, m);
+ wnoutrefresh(m->box);
+
+ m->ys = d->y + d->h - 5 - m->menurows + 1;
+ m->ye = d->y + d->h - 5 ;
+ if (d->conf->menu.align_left || (int)m->line > d->w - 6) {
+ m->xs = d->x + 3;
+ m->xe = m->xs + d->w - 7;
+ } else { /* center */
+ m->xs = d->x + 3 + (d->w-6)/2 - m->line/2;
+ m->xe = m->xs + d->w - 5;
+ }
+ drawseparators(d->conf, m); /* uses xe - xs */
+ pnoutrefresh(m->pad, m->ypad, 0, m->ys, m->xs, m->ye, m->xe);
+
+ return (0);
}
static int
@@ -433,330 +503,187 @@ 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)
{
- bool loop, onetrue, movefocus, automenurows, shortcut_butts;
- int i, j, y, x, h, w, output, input;
- int ymenupad, ys, ye, xs, xe, abs, next, totnitems;
- WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
- struct buttons bs;
- struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- struct bsddialog_menuitem *item;
- struct privateitem *pritems;
-
- shortcut_butts = conf->menu.shortcut_buttons;
-
- automenurows = (menurows == BSDDIALOG_AUTOSIZE) ? true : false;
-
- totnitems = 0;
- for (i = 0; i < (int)ngroups; i++) {
- if (getmode(mode, groups[i]) == RADIOLISTMODE ||
- getmode(mode, groups[i]) == CHECKLISTMODE)
- pos.selectorlen = 3;
-
- for (j = 0; j < (int)groups[i].nitems; j++) {
- totnitems++;
- item = &groups[i].items[j];
-
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- pos.maxsepstr = MAX(pos.maxsepstr,
- strlen(item->name) + strlen(item->desc));
- continue;
- }
+ bool loop, changeitem;
+ int i, next, retval;
+ wint_t input;
+ struct privatemenu m;
+ struct dialog d;
- pos.maxprefix = MAX(pos.maxprefix,strlen(item->prefix));
- pos.maxdepth = MAX(pos.maxdepth, item->depth);
- pos.maxname = MAX(pos.maxname, strlen(item->name));
- pos.maxdesc = MAX(pos.maxdesc, strlen(item->desc));
- }
- }
- pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
- pos.maxdesc = conf->menu.no_desc ? 0 : pos.maxdesc;
- pos.maxdepth = DEPTH * pos.maxdepth;
-
- pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
- pos.xname = pos.xselector + pos.selectorlen +
- (pos.selectorlen > 0 ? 1 : 0);
- pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
- pos.xdesc += (pos.maxname != 0 ? 1 : 0);
- pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
-
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
- totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
+ set_buttons(&d, conf->menu.shortcut_buttons, OK_LABEL, CANCEL_LABEL);
+ if (d.conf->menu.no_name && d.conf->menu.no_desc)
+ RETURN_ERROR("Both conf.menu.no_name and conf.menu.no_desc");
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- shortcut_butts) != 0)
+ if (build_privatemenu(conf, &m, mode, ngroups, groups) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
-
- menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
- menurows+2, w-4, LOWERED);
-
- menupad = newpad(totnitems, pos.line);
- wbkgd(menupad, t.dialog.color);
-
- if ((pritems = calloc(totnitems, sizeof (struct privateitem))) == NULL)
- RETURN_ERROR("Cannot allocate memory for internal menu items");
-
- abs = 0;
- for (i = 0; i < (int)ngroups; i++) {
- onetrue = false;
- for (j = 0; j < (int)groups[i].nitems; j++) {
- item = &groups[i].items[j];
-
- if (getmode(mode, groups[i]) == MENUMODE) {
- pritems[abs].on = false;
- } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
- pritems[abs].on = onetrue ? false : item->on;
- if (pritems[abs].on)
- onetrue = true;
- } else {
- pritems[abs].on = item->on;
- }
- pritems[abs].group = i;
- pritems[abs].index = j;
- pritems[abs].type = getmode(mode, groups[i]);
- pritems[abs].item = item;
+ if ((m.box = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW box menu");
+ wbkgd(m.box, t.dialog.color);
+ m.pad = newpad(m.nitems, m.line);
+ wbkgd(m.pad, t.dialog.color);
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs++;
- }
- }
- drawseparators(conf, menupad, MIN((int)pos.line, w-6), totnitems,
- pritems);
- abs = getfirst_with_default(totnitems, pritems, ngroups, groups,
+ for (i = 0; i < m.nitems; i++)
+ drawitem(conf, &m, i, false);
+ m.sel = getfirst_with_default(m.nitems, m.pritems, ngroups, groups,
focuslist, focusitem);
- if (abs >= 0)
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- ymenupad = 0;
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows,
- ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ if (m.sel >= 0)
+ drawitem(d.conf, &m, m.sel, true);
+ m.ypad = 0;
+ m.apimenurows = menurows;
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
- movefocus = false;
+ changeitem = false;
loop = true;
while (loop) {
- input = getch();
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups, pritems);
+ retval = BUTTONVALUE(d.bs);
+ if (m.sel >= 0 && m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups,
- pritems);
+ retval = BSDDIALOG_ESC;
+ if (m.sel >= 0 &&
+ m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- menurows = automenurows ? 0 : menurows;
- if (menu_autosize(conf, rows, cols, &h, &w, text,
- pos.line, &menurows, totnitems, bs) != 0)
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, shortcut_butts) != 0)
+ break;
+ case KEY_RESIZE:
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
-
- wclear(menuwin);
- mvwin(menuwin, y + h - 5 - menurows, x + 2);
- wresize(menuwin,menurows+2, w-4);
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- drawseparators(conf, menupad, MIN((int)pos.line, w-6),
- totnitems, pritems);
-
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
-
- refresh();
-
break;
}
- if (abs < 0)
+ if (m.sel < 0)
continue;
switch(input) {
case KEY_HOME:
- next = getnext(totnitems, pritems, -1);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, -1);
+ changeitem = next != m.sel;
break;
case KEY_UP:
- next = getprev(pritems, abs);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_PPAGE:
- next = getfastprev(menurows, pritems, abs);
- movefocus = next != abs;
+ next = getfastprev(m.menurows, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_END:
- next = getprev(pritems, totnitems);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.nitems);
+ changeitem = next != m.sel;
break;
case KEY_DOWN:
- next = getnext(totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_NPAGE:
- next = getfastnext(menurows, totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getfastnext(m.menurows, m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case ' ': /* Space */
- if (pritems[abs].type == MENUMODE)
- break;
- else if (pritems[abs].type == CHECKLISTMODE)
- pritems[abs].on = !pritems[abs].on;
- else { /* RADIOLISTMODE */
- for (i = abs - pritems[abs].index;
- i < totnitems &&
- pritems[i].group == pritems[abs].group;
+ if (m.pritems[m.sel].type == MENUMODE) {
+ retval = BUTTONVALUE(d.bs);
+ m.pritems[m.sel].on = true;
+ loop = false;
+ } else if (m.pritems[m.sel].type == CHECKLISTMODE) {
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
+ } else { /* RADIOLISTMODE */
+ for (i = m.sel - m.pritems[m.sel].index;
+ i < m.nitems &&
+ m.pritems[i].group == m.pritems[m.sel].group;
i++) {
- if (i != abs && pritems[i].on) {
- pritems[i].on = false;
- drawitem(conf, menupad, i, pos,
- &pritems[i], false);
+ if (i != m.sel && m.pritems[i].on) {
+ m.pritems[i].on = false;
+ drawitem(conf, &m, i, false);
}
}
- pritems[abs].on = !pritems[abs].on;
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
}
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ drawitem(conf, &m, m.sel, true);
+ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
break;
default:
- if (shortcut_butts) {
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
- if (pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups,
- groups, pritems);
+ if (conf->menu.shortcut_buttons) {
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ if (m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
}
/* shourtcut items */
- next = getnextshortcut(conf, totnitems, pritems, abs,
+ next = getnextshortcut(m.nitems, m.pritems, m.sel,
input);
- movefocus = next != abs;
+ changeitem = next != m.sel;
+ } /* end switch get_wch() */
+
+ if (changeitem) {
+ drawitem(conf, &m, m.sel, false);
+ m.sel = next;
+ drawitem(conf, &m, m.sel, true);
+ if (m.ypad > m.sel && m.ypad > 0)
+ m.ypad = m.sel;
+ if ((int)(m.ypad + m.menurows) <= m.sel)
+ m.ypad = m.sel - m.menurows + 1;
+ update_menubox(conf, &m);
+ wnoutrefresh(m.box);
+ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
+ changeitem = false;
}
+ } /* end while(loop) */
- if (movefocus) {
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs = next;
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- if (ymenupad > abs && ymenupad > 0)
- ymenupad = abs;
- if ((int)(ymenupad + menurows) <= abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
- movefocus = false;
- }
- }
+ set_return_on(&m, groups);
if (focuslist != NULL)
- *focuslist = abs < 0 ? -1 : pritems[abs].group;
+ *focuslist = m.sel < 0 ? -1 : m.pritems[m.sel].group;
if (focusitem !=NULL)
- *focusitem = abs < 0 ? -1 : pritems[abs].index;
+ *focusitem = m.sel < 0 ? -1 : m.pritems[m.sel].index;
- delwin(menupad);
- delwin(menuwin);
- end_dialog(conf, shadow, widget, textpad);
- free(pritems);
+ if (m.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ }
+ delwin(m.pad);
+ delwin(m.box);
+ end_dialog(&d);
+ free(m.pritems);
- return (output);
+ return (retval);
}
/* API */
@@ -765,12 +692,12 @@ 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)
{
- int output;
+ int retval;
- output = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
+ retval = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
ngroups, groups, focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -778,14 +705,15 @@ 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)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -793,14 +721,15 @@ 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)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
&group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -808,12 +737,13 @@ 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)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_RADIOLIST /* unused */, nitems, items};
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}