diff options
Diffstat (limited to 'contrib/bsddialog/lib/menubox.c')
-rw-r--r-- | contrib/bsddialog/lib/menubox.c | 880 |
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); } |