diff --git a/CHANGELOG b/CHANGELOG --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,35 @@ +2024-04-11 Version 1.0.2 + + Utility: + improvements and changes for --form and --mixedform: + * add: 0 sets like . + * add: 0 sets like width and readonly. + * change: 0 was an error (remains error in lib). + * change: 0 was an error (remains error in lib) + ( 0 and "" is still an error.). + + Library and implicitly utility: + * add: Ctrl-l to redraw dialog. + Request stable@freebsd.org January 2024. + * add: -, +, Ctrl-p, Ctrl-n for several dialogs. + +, - request for menus, private feature request. + Ctrl-p, Ctrl-n for menu, request hackers@freebsd.org February 2024. + * fix: escaped text ending with an escape symbol. + * change: truncate mixedgauge long (over the screen/minibars) + minilabels adding "...". As a result, avoid check-size error. + https://gitlab.com/alfix/bsddialog/-/issues/6. + * change: invert UP/DOWN keys to set a rangebox value. + + +2023-11-16 Version 1.0.1 + + Library Internal Refactoring: + * add: arrow macro handlers. + * change: Box-drawing characters, from utf8 to wide chars to avoid to + handle "env NCURSES_NO_UTF8_ACS=1". + Request https://bugs.freebsd.org/274472, + Rationale https://reviews.freebsd.org/D42380. + 2023-08-01 Version 1.0 Utility: diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2021-2023, Alfonso Sabato Siciliano +Copyright (c) 2021-2024, Alfonso Sabato Siciliano Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ # # Written in 2023 by Alfonso Sabato Siciliano -OUTPUT = bsddialog -export VERSION=1.0 +OUTPUT = bsddialog +export VERSION=1.0.2 .CURDIR ?= ${CURDIR} LIBPATH = ${.CURDIR}/lib LIBBSDDIALOG = ${LIBPATH}/libbsddialog.so @@ -13,14 +13,14 @@ RM= rm -f LN = ln -s -f -### cli options ### -# port/pkg Makefile: 'MAKE_ARGS = -DNORPATH' +### command-line options ### +# FreeBSD port Makefile: 'MAKE_ARGS = -DNORPATH' NORPATH ?= export DISABLERPATH=${NORPATH} -# `make -DDEBUG` -# `gmake DEBUG=1` +# Debug: `make -DDEBUG` or `gmake DEBUG=1` DEBUG ?= export ENABLEDEBUG=${DEBUG} +################### all : ${OUTPUT} diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# BSDDialog 1.0 +# BSDDialog 1.0.2 This project provides **bsddialog** and **libbsddialog**, an utility and a library to build scripts and tools with TUI dialogs and widgets. @@ -114,18 +114,27 @@ ## TODO and Ideas - - menubar feature - - key callback - - Right-To-Left text + - menubar feature. + - key callback. + - Right-To-Left text. - some terminal does not hide the cursor, move it bottom-right before to getch. - - refactor backtitle: multiline, conf.backtitle, WINDOW \*dialog.backtitle. - - refactor bottomdesc: WINDOW \*dialog.bottomdesc -> fix expandig screen. - - accessibility https://wiki.freebsd.org/Accessibility/Wishlist/Base + - refactor backtitle: add WINDOW \*dialog.backtitle for multiline and fix expanding screen. + - refactor bottomdesc: add WINDOW \*dialog.bottomdesc to fix expandig screen. + - accessibility https://wiki.freebsd.org/Accessibility/Wishlist/Base. - add bool conf.menu.depthlines. - implement custom getopt\_long(). - refactor/redesign gauge(). - improve grey lines expanding terminal (maybe redrawwin() in hide\_dialog()). - more restrictive strtol() and strtoul(). - implement global buttons handler. - - add/move external tutorial. - - implement menutype.min_on. + - doc: external tutorial, theming guide. + - implement menutype.min\_on. + - improve refresh at startup, avoid dialog refresh before drawing text. + - add debug API: bsddialog\_debug(y,x,refresh,"fmt",...). + - add mouse support. + - use alarm(2) for bsddialog\_pause. + - delete form fieldlen constraint, hide or truncate long field in little screens. + - improve --inputbox autosizing, consider also input length. + - fix --form "" 0 0 0 Label 1 0 Init 1 12 0 0 (with 0 editable field). + - fix --mixedform "" 0 0 0 Label 1 0 Init 1 12 0 0 2 (with 0 editable field). + - add *text* customization to --hmsg *help-message* diff --git a/examples_library/gauge.c b/examples_library/gauge.c --- a/examples_library/gauge.c +++ b/examples_library/gauge.c @@ -50,8 +50,8 @@ conf.title = "gauge"; rv = bsddialog_gauge(&conf, "Example", 7, 30, 0, fd[0], "SEP", "EOF"); bsddialog_end(); - if(rv == BSDDIALOG_ERROR) + if (rv == BSDDIALOG_ERROR) printf("Error: %s\n", bsddialog_geterror()); return (0); } \ No newline at end of file diff --git a/examples_library/mixedgauge.c b/examples_library/mixedgauge.c --- a/examples_library/mixedgauge.c +++ b/examples_library/mixedgauge.c @@ -69,7 +69,7 @@ minipercs[12] = i * 10; retval= bsddialog_mixedgauge(&conf, "Example", 20, 40, 50 + i * 5, NMINIBAR, minilabels, minipercs); - if(retval == BSDDIALOG_ERROR) + if (retval == BSDDIALOG_ERROR) exit_error(); sleep(1); } diff --git a/lib/barbox.c b/lib/barbox.c --- a/lib/barbox.c +++ b/lib/barbox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,11 +36,11 @@ #include "bsddialog_theme.h" #include "lib_util.h" -#define BARPADDING 2 /* widget border | BARPADDING | box bar */ +#define BARPADDING 2 /* Dialog border | BARPADDING | box bar */ #define BOXBORDERS 2 #define MIN_WBAR 15 #define MIN_WBOX (BARPADDING + BOXBORDERS + MIN_WBAR + BARPADDING) -#define MIN_WMGBAR 18 +#define MIN_WMGBAR 18 /* Mixedgauge main bar */ #define MIN_WMGBOX (BARPADDING + BOXBORDERS + MIN_WMGBAR + BARPADDING) #define HBOX 3 #define WBOX(d) ((d)->w - BORDERS - BARPADDING - BARPADDING) @@ -206,12 +206,64 @@ } /* Mixedgauge */ +static void +mvwaddcstr(WINDOW *win, int y, int x, const char *mbstring, unsigned int cols) +{ + size_t charlen, n, w; + mbstate_t mbs; + const char *pmbstring; + wchar_t wch; + + w = n = 0; + pmbstring = mbstring; + memset(&mbs, 0, sizeof(mbs)); + while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 && + charlen != (size_t)-1 && charlen != (size_t)-2) { + mbtowc(&wch, pmbstring, charlen); + w += (wch == L'\t') ? TABSIZE : wcwidth(wch); + if (w > cols) + break; + pmbstring += charlen; + n += charlen; + } + mvwaddnstr(win, y, x, mbstring, n); + if(w > cols) + mvwaddstr(win, y, (x + cols) - 3, "..."); +} + +static int +mixedgauge_size_position(struct dialog *d, int nminibars, + const char **minilabels, int *htext) +{ + int i, max_minibarlen; + + max_minibarlen = 0; + for (i = 0; i < (int)nminibars; i++) + max_minibarlen = MAX(max_minibarlen, + (int)strcols(CHECK_STR(minilabels[i]))); + max_minibarlen += 18; /* ' '' ['13'] ' */ + max_minibarlen = MAX(max_minibarlen, MIN_WMGBOX); /* mainbar */ + + if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0) + return (BSDDIALOG_ERROR); + if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w, + d->text, htext, &d->bs, nminibars + HBOX, max_minibarlen) != 0) + return (BSDDIALOG_ERROR); + if (widget_checksize(d->h, d->w, &d->bs, nminibars + HBOX, + MIN_WMGBOX) != 0) + return (BSDDIALOG_ERROR); + if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0) + return (BSDDIALOG_ERROR); + + return (0); +} + static int do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols, unsigned int mainperc, unsigned int nminibars, const char **minilabels, int *minipercs, bool color) { - int i, miniperc, max_minibarlen; + int i, miniperc; int ystext, htext; int minicolor, red, green; struct bar b; @@ -223,17 +275,9 @@ red = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_RED, BSDDIALOG_BOLD); green = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_GREEN,BSDDIALOG_BOLD); - max_minibarlen = 0; - for (i = 0; i < (int)nminibars; i++) - max_minibarlen = MAX(max_minibarlen, - (int)strcols(CHECK_STR(minilabels[i]))); - max_minibarlen += 3 + 16; /* seps + [...] */ - max_minibarlen = MAX(max_minibarlen, MIN_WMGBOX); /* mainbar */ - if (prepare_dialog(conf, text, rows, cols, &d) != 0) return (BSDDIALOG_ERROR); - if (dialog_size_position(&d, nminibars + HBOX, max_minibarlen, - &htext) != 0) + if (mixedgauge_size_position(&d, nminibars, minilabels, &htext) != 0) return (BSDDIALOG_ERROR); if (draw_dialog(&d) != 0) return (BSDDIALOG_ERROR); @@ -249,7 +293,7 @@ /* label */ if (color && miniperc >= 0) wattron(d.widget, A_BOLD); - mvwaddstr(d.widget, i+1, 2, CHECK_STR(minilabels[i])); + mvwaddcstr(d.widget, i+1, 2, CHECK_STR(minilabels[i]), d.w-20); if (color && miniperc >= 0) wattroff(d.widget, A_BOLD); /* perc */ @@ -472,10 +516,12 @@ } break; case '\t': /* TAB */ + case KEY_CTRL('n'): case KEY_RIGHT: d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons; DRAW_BUTTONS(d); break; + case KEY_CTRL('p'): case KEY_LEFT: d.bs.curr--; if (d.bs.curr < 0) @@ -502,15 +548,17 @@ currvalue = max; b.toupdate = true; break; + case '-': case KEY_UP: - if (currvalue < max) { - currvalue++; + if (currvalue > min) { + currvalue--; b.toupdate = true; } break; + case '+': case KEY_DOWN: - if (currvalue > min) { - currvalue--; + if (currvalue < max) { + currvalue++; b.toupdate = true; } break; @@ -523,6 +571,7 @@ if (rangebox_redraw(&d, &b, &bigchange) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (rangebox_redraw(&d, &b, &bigchange) != 0) return (BSDDIALOG_ERROR); @@ -641,6 +690,7 @@ if (pause_redraw(&d, &b) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (pause_redraw(&d, &b) != 0) return (BSDDIALOG_ERROR); diff --git a/lib/bsddialog.h b/lib/bsddialog.h --- a/lib/bsddialog.h +++ b/lib/bsddialog.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,7 @@ #include -#define LIBBSDDIALOG_VERSION "1.0" +#define LIBBSDDIALOG_VERSION "1.0.2" /* Return values */ #define BSDDIALOG_ERROR -1 diff --git a/lib/bsddialog.3 b/lib/bsddialog.3 --- a/lib/bsddialog.3 +++ b/lib/bsddialog.3 @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 2021-2023 Alfonso Sabato Siciliano +.\" Copyright (c) 2021-2024 Alfonso Sabato Siciliano .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 28, 2023 +.Dd March 16, 2024 .Dt BSDDIALOG 3 .Os .Sh NAME @@ -719,9 +719,8 @@ builds a dialog without buttons and returns instantly. .Pp .Fn bsddialog_menu -builds a dialog to select an item from a list via SPACE or ENTER. -An item is -defined like: +builds a dialog to select an item from a list via SPACE and ENTER. +An item is defined like: .Pp .Bd -literal -offset indent -compact struct bsddialog_menuitem { @@ -878,14 +877,13 @@ .Fa max . .Fa value is the default value on startup and the selected value at exit. -The current value is printed inside a bar, the keys UP, DOWN, HOME, END, PAGEUP -and PAGEDOWN can change it. +The current value is printed inside a bar. .Pp .Fn bsddialog_textbox opens and prints .Fa file . -UP, DOWN, LEFT, RIGHT, HOME, END, PAGEUP and PAGEDOWN keys are available to -navigate the file, TAB changes button. +TAB key changes button. +Extra keys 0, h, l, k, j are available to navigate the text. .Dq OK button is renamed .Dq EXIT . @@ -901,7 +899,24 @@ .Fn bsddialog_yesno provides a dialog for a .Dq Yes-No Question , -the labels on buttons are Yes and No. +the labels on buttons are +.Dq Yes +and +.Dq No . +.Ss Keys +.Bl -tag -width Ds +.It Ctrl-l +Redraw the dialog. +.It F1 +Refer to +.Fa conf.key.f1_file +and +.Fa conf.key.f1_message . +.It SPACE +Select menu item. +.It UP DOWN LEFT RIGHT - + HOME END PAGEUP PAGEDOWN Ctrl-p Ctrl-n TAB +Navigate elements and set value, depending on the dialog. +.El .Ss Theme The graphical properties are global to the library. They are represented by @@ -1089,7 +1104,7 @@ printf("Yes\\n"); break; case BSDDIALOG_NO - printf("NO\\n"); + printf("No\\n"); break; case BSDDIALOG_ERROR: printf("Error: %s\\n", bsddialog_geterror()); diff --git a/lib/datebox.c b/lib/datebox.c --- a/lib/datebox.c +++ b/lib/datebox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2022-2023 Alfonso Sabato Siciliano + * Copyright (c) 2022-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -120,7 +120,7 @@ if (*mm == 0) *mm = 1; *dd = (*day == 0) ? 1 : *day; - if(*dd > month_days(*yy, *mm)) + if (*dd > month_days(*yy, *mm)) *dd = month_days(*yy, *mm); } @@ -237,10 +237,8 @@ if (focus) { l = 2 + w%2; wattron(win, t.dialog.arrowcolor); - mvwhline(win, 0, w/2 - l/2, - conf->ascii_lines ? '^' : ACS_UARROW, l); - mvwhline(win, h-1, w/2 - l/2, - conf->ascii_lines ? 'v' : ACS_DARROW, l); + mvwhline(win, 0, w/2 - l/2, UARROW(conf), l); + mvwhline(win, h-1, w/2 - l/2, DARROW(conf), l); wattroff(win, t.dialog.arrowcolor); } @@ -267,10 +265,10 @@ draw_borders(conf, win, RAISED); if (active) { wattron(win, t.dialog.arrowcolor); - mvwhline(win, 0, 15, conf->ascii_lines ? '^' : ACS_UARROW, 4); - mvwhline(win, h-1, 15, conf->ascii_lines ? 'v' : ACS_DARROW, 4); - mvwvline(win, 3, 0, conf->ascii_lines ? '<' : ACS_LARROW, 3); - mvwvline(win, 3, w-1, conf->ascii_lines ? '>' : ACS_RARROW, 3); + mvwhline(win, 0, 15, UARROW(conf), 4); + mvwhline(win, h-1, 15, DARROW(conf), 4); + mvwvline(win, 3, 0, LARROW(conf), 3); + mvwvline(win, 3, w-1, RARROW(conf), 3); wattroff(win, t.dialog.arrowcolor); } @@ -402,6 +400,7 @@ } DRAW_BUTTONS(d); break; + case KEY_CTRL('n'): case KEY_RIGHT: if (focusbuttons) { d.bs.curr++; @@ -418,6 +417,7 @@ } DRAW_BUTTONS(d); break; + case KEY_CTRL('p'): case KEY_LEFT: if (focusbuttons) { d.bs.curr--; @@ -463,6 +463,28 @@ datectl(DOWN_DAY, &yy, &mm, &dd); } break; + case '-': + if (focusbuttons) { + break; + } else if (sel == 0) { + datectl(UP_MONTH, &yy, &mm, &dd); + } else if (sel == 1) { + datectl(UP_YEAR, &yy, &mm, &dd); + } else { /* sel = 2 */ + datectl(LEFT_DAY, &yy, &mm, &dd); + } + break; + case '+': + if (focusbuttons) { + break; + } else if (sel == 0) { + datectl(DOWN_MONTH, &yy, &mm, &dd); + } else if (sel == 1) { + datectl(DOWN_YEAR, &yy, &mm, &dd); + } else { /* sel = 2 */ + datectl(RIGHT_DAY, &yy, &mm, &dd); + } + break; case KEY_HOME: datectl(UP_MONTH, &yy, &mm, &dd); break; @@ -484,6 +506,7 @@ if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0) return (BSDDIALOG_ERROR); @@ -628,8 +651,9 @@ loop = false; } break; - case KEY_RIGHT: case '\t': /* TAB */ + case KEY_CTRL('n'): + case KEY_RIGHT: if (focusbuttons) { d.bs.curr++; focusbuttons = d.bs.curr < (int)d.bs.nbuttons ? @@ -648,6 +672,7 @@ } DRAW_BUTTONS(d); break; + case KEY_CTRL('p'): case KEY_LEFT: if (focusbuttons) { d.bs.curr--; @@ -665,6 +690,10 @@ } DRAW_BUTTONS(d); break; + case '-': + if (focusbuttons == false) + datectl(di[sel].up, &yy, &mm, &dd); + break; case KEY_UP: if (focusbuttons) { sel = 0; @@ -675,6 +704,7 @@ datectl(di[sel].up, &yy, &mm, &dd); } break; + case '+': case KEY_DOWN: if (focusbuttons) break; @@ -689,6 +719,7 @@ if (datebox_redraw(&d, di) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (datebox_redraw(&d, di) != 0) return (BSDDIALOG_ERROR); diff --git a/lib/formbox.c b/lib/formbox.c --- a/lib/formbox.c +++ b/lib/formbox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -82,7 +82,7 @@ unsigned int viewrows; /* visible rows, real formheight */ unsigned int minviewrows; /* min viewrows, ylabel != yfield */ wchar_t securewch; /* wide char of conf.form.secure[mb]ch */ - unsigned int nitems; /* like API nkitems */ + unsigned int nitems; /* like API nitems */ struct privateitem *pritems; int sel; /* selected item in pritem, can be -1 */ bool hasbottomdesc; /* some item has bottomdesc */ @@ -101,12 +101,12 @@ /* checks */ CHECK_ARRAY(nitems, items); for (i = 0; i < nitems; i++) { - if (items[i].maxvaluelen == 0) - RETURN_FMTERROR("item %u [0-%u] maxvaluelen = 0", - i, nitems); if (items[i].fieldlen == 0) RETURN_FMTERROR("item %u [0-%u] fieldlen = 0", i, nitems); + if (items[i].maxvaluelen == 0) + RETURN_FMTERROR("item %u [0-%u] maxvaluelen = 0", + i, nitems); } f->nitems = nitems; @@ -114,7 +114,7 @@ insecurecursor = false; if (conf->form.securembch != NULL) { mbchsize = mblen(conf->form.securembch, MB_LEN_MAX); - if(mbtowc(&f->securewch, conf->form.securembch, mbchsize) < 0) + if (mbtowc(&f->securewch, conf->form.securembch, mbchsize) < 0) RETURN_ERROR("Cannot convert securembch to wchar_t"); insecurecursor = true; } else if (conf->form.securech != '\0') { @@ -346,7 +346,7 @@ wctomb(mbch, wstr[i]); nbytes += mblen(mbch, MB_LEN_MAX); } - if((mbstr = malloc(nbytes)) == NULL) + if ((mbstr = malloc(nbytes)) == NULL) return (NULL); wcstombs(mbstr, wstr, nbytes); @@ -379,7 +379,7 @@ unsigned int i; f->sel = -1; - if(focusitem != NULL && *focusitem >=0 && *focusitem < (int)f->nitems) + if (focusitem != NULL && *focusitem >=0 && *focusitem < (int)f->nitems) if (f->pritems[*focusitem].readonly == false) { f->sel = *focusitem; return; @@ -535,12 +535,10 @@ if (f->viewrows < f->h) { wattron(f->box, t.dialog.arrowcolor); if (f->y > 0) - mvwhline(f->box, 0, (w / 2) - 2, - conf->ascii_lines ? '^' : ACS_UARROW, 5); + mvwhline(f->box, 0, (w / 2) - 2, UARROW(conf), 5); if (f->y + f->viewrows < f->h) - mvwhline(f->box, h-1, (w / 2) - 2, - conf->ascii_lines ? 'v' : ACS_DARROW, 5); + mvwhline(f->box, h-1, (w / 2) - 2, DARROW(conf), 5); wattroff(f->box, t.dialog.arrowcolor); } } @@ -750,7 +748,7 @@ break; case KEY_LEFT: if (focusinform) { - if(fieldctl(item, MOVE_CURSOR_LEFT)) + if (fieldctl(item, MOVE_CURSOR_LEFT)) DRAWITEM_TRICK(&form, form.sel, true); } else if (d.bs.curr > 0) { d.bs.curr--; @@ -762,7 +760,7 @@ break; case KEY_RIGHT: if (focusinform) { - if(fieldctl(item, MOVE_CURSOR_RIGHT)) + if (fieldctl(item, MOVE_CURSOR_RIGHT)) DRAWITEM_TRICK(&form, form.sel, true); } else if (d.bs.curr < (int) d.bs.nbuttons - 1) { d.bs.curr++; @@ -772,6 +770,7 @@ switchfocus = true; } break; + case KEY_CTRL('p'): case KEY_UP: if (focusinform) { next = previtem(form.nitems, form.pritems, @@ -781,6 +780,7 @@ switchfocus = true; } break; + case KEY_CTRL('n'): case KEY_DOWN: if (focusinform == false) break; @@ -808,20 +808,20 @@ case 127: /* Backspace */ if (focusinform == false) break; - if(fieldctl(item, MOVE_CURSOR_LEFT)) - if(fieldctl(item, DEL_LETTER)) + if (fieldctl(item, MOVE_CURSOR_LEFT)) + if (fieldctl(item, DEL_LETTER)) DRAWITEM_TRICK(&form, form.sel, true); break; case KEY_DC: if (focusinform == false) break; - if(fieldctl(item, DEL_LETTER)) + if (fieldctl(item, DEL_LETTER)) DRAWITEM_TRICK(&form, form.sel, true); break; case KEY_HOME: if (focusinform == false) break; - if(fieldctl(item, MOVE_CURSOR_BEGIN)) + if (fieldctl(item, MOVE_CURSOR_BEGIN)) DRAWITEM_TRICK(&form, form.sel, true); break; case KEY_END: @@ -842,6 +842,7 @@ if (form_redraw(&d, &form, focusinform) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (form_redraw(&d, &form, focusinform) != 0) return (BSDDIALOG_ERROR); @@ -857,10 +858,10 @@ * because the cursor remains on the new letter, * "if" and "while" update the positions. */ - if(insertch(item, input, form.securewch)) { + if (insertch(item, input, form.securewch)) { fieldctl(item, MOVE_CURSOR_RIGHT); /* - * no if(fieldctl), update always + * no if (fieldctl), update always * because it fails with maxletters. */ DRAWITEM_TRICK(&form, form.sel, true); @@ -897,7 +898,7 @@ DRAWITEM_TRICK(&form, form.sel, true); changeitem = false; } - } /* end while(loop) */ + } /* end while (loop) */ curs_set(0); diff --git a/lib/lib_util.h b/lib/lib_util.h --- a/lib/lib_util.h +++ b/lib/lib_util.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,14 +62,19 @@ RETURN_ERROR("*" #p " is NULL"); \ } while (0) #define CHECK_ARRAY(nitem, a) do { \ - if(nitem > 0 && a == NULL) \ + if (nitem > 0 && a == NULL) \ RETURN_FMTERROR(#nitem " is %d but *" #a " is NULL", nitem); \ } while (0) /* widget utils */ +#define KEY_CTRL(c) (c & 037) #define TEXTPAD(d, downnotext) rtextpad(d, 0, 0, 0, downnotext) #define SCREENLINES (getmaxy(stdscr)) #define SCREENCOLS (getmaxx(stdscr)) #define CHECK_STR(s) (s == NULL ? "" : s) +#define UARROW(c) (c->ascii_lines ? '^' : ACS_UARROW) +#define DARROW(c) (c->ascii_lines ? 'v' : ACS_DARROW) +#define LARROW(c) (c->ascii_lines ? '<' : ACS_LARROW) +#define RARROW(c) (c->ascii_lines ? '>' : ACS_RARROW) #define DRAW_BUTTONS(d) do { \ draw_buttons(&d); \ wnoutrefresh(d.widget); \ diff --git a/lib/lib_util.c b/lib/lib_util.c --- a/lib/lib_util.c +++ b/lib/lib_util.c @@ -983,41 +983,43 @@ { int h, w; int leftcolor, rightcolor; - int ls, rs, ts, bs, tl, tr, bl, br, ltee, rtee; + cchar_t *ls, *rs, *ts, *bs, *tl, *tr, *bl, *br; + cchar_t hline, vline, corner; if (conf->no_lines) return; if (conf->ascii_lines) { - ls = rs = '|'; - ts = bs = '-'; - tl = tr = bl = br = ltee = rtee = '+'; + setcchar(&hline, L"|", 0, 0, NULL); + ls = rs = &hline; + setcchar(&vline, L"-", 0, 0, NULL); + ts = bs = &vline; + setcchar(&corner, L"+", 0, 0, NULL); + tl = tr = bl = br = &corner; } else { - ls = rs = ACS_VLINE; - ts = bs = ACS_HLINE; - tl = ACS_ULCORNER; - tr = ACS_URCORNER; - bl = ACS_LLCORNER; - br = ACS_LRCORNER; - ltee = ACS_LTEE; - rtee = ACS_RTEE; + ls = rs = WACS_VLINE; + ts = bs = WACS_HLINE; + tl = WACS_ULCORNER; + tr = WACS_URCORNER; + bl = WACS_LLCORNER; + br = WACS_LRCORNER; } getmaxyx(win, h, w); - leftcolor = elev == RAISED ? + leftcolor = (elev == RAISED) ? t.dialog.lineraisecolor : t.dialog.linelowercolor; - rightcolor = elev == RAISED ? + rightcolor = (elev == RAISED) ? t.dialog.linelowercolor : t.dialog.lineraisecolor; wattron(win, leftcolor); - wborder(win, ls, rs, ts, bs, tl, tr, bl, br); + wborder_set(win, ls, rs, ts, bs, tl, tr, bl, br); wattroff(win, leftcolor); wattron(win, rightcolor); - mvwaddch(win, 0, w-1, tr); - mvwvline(win, 1, w-1, rs, h-2); - mvwaddch(win, h-1, w-1, br); - mvwhline(win, h-1, 1, bs, w-2); + mvwadd_wch(win, 0, w-1, tr); + mvwvline_set(win, 1, w-1, rs, h-2); + mvwadd_wch(win, h-1, w-1, br); + mvwhline_set(win, h-1, 1, bs, w-2); wattroff(win, rightcolor); } @@ -1126,30 +1128,31 @@ print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str, bool color) { - int i, j, len, reallen, wc; + int charwidth, i, j, strlen, strwidth; wchar_t ws[2]; ws[1] = L'\0'; - len = wcslen(str); + strlen = wcslen(str); if (color) { - reallen = 0; + strwidth = 0; i=0; - while (i < len) { + while (i < strlen) { if (is_wtext_attr(str+i) == false) { - reallen += wcwidth(str[i]); + strwidth += wcwidth(str[i]); i++; } else { - i +=3 ; + i += 3; } } } else - reallen = wcswidth(str, len); + strwidth = wcswidth(str, strlen); i = 0; - while (i < len) { - if (*x + reallen > cols) { - *y = (*x != 0 ? *y+1 : *y); + while (i < strlen) { + if (*x + strwidth > cols) { + if (*x != 0) + *y = *y + 1; if (*y >= *rows) { *rows = *y + 1; wresize(win, *rows, cols); @@ -1157,21 +1160,22 @@ *x = 0; } j = *x; - while (j < cols && i < len) { + while (i < strlen) { if (color && check_set_wtext_attr(win, str+i)) { i += 3; - } else if (j + wcwidth(str[i]) > cols) { - break; - } else { - /* inline mvwaddwch() for efficiency */ - ws[0] = str[i]; - mvwaddwstr(win, *y, j, ws); - wc = wcwidth(str[i]);; - reallen -= wc; - j += wc; - i++; - *x = j; + continue; } + + charwidth = wcwidth(str[i]); + if (j + wcwidth(str[i]) > cols) + break; + /* inline mvwaddwch() for efficiency */ + ws[0] = str[i]; + mvwaddwstr(win, *y, j, ws); + strwidth -= charwidth; + j += charwidth; + *x = j; + i++; } } } @@ -1248,11 +1252,18 @@ int draw_dialog(struct dialog *d) { - int wtitle, wbottomtitle, ts, ltee, rtee; + int wtitle, wbottomtitle; + cchar_t ts, ltee, rtee; - ts = d->conf->ascii_lines ? '-' : ACS_HLINE; - ltee = d->conf->ascii_lines ? '+' : ACS_LTEE; - rtee = d->conf->ascii_lines ? '+' : ACS_RTEE; + if (d->conf->ascii_lines) { + setcchar(&ts, L"-", 0, 0, NULL); + setcchar(<ee, L"+", 0, 0,NULL); + setcchar(&rtee, L"+", 0, 0, NULL); + } else { + ts = *WACS_HLINE; + ltee = *WACS_LTEE; + rtee = *WACS_RTEE; + } if (d->conf->shadow) { wclear(d->shadow); @@ -1271,7 +1282,7 @@ return (BSDDIALOG_ERROR); if (t.dialog.delimtitle && d->conf->no_lines == false) { wattron(d->widget, t.dialog.lineraisecolor); - mvwaddch(d->widget, 0, d->w/2 - wtitle/2 -1, rtee); + mvwadd_wch(d->widget, 0, d->w/2 - wtitle/2 -1, &rtee); wattroff(d->widget, t.dialog.lineraisecolor); } wattron(d->widget, t.dialog.titlecolor); @@ -1279,7 +1290,7 @@ wattroff(d->widget, t.dialog.titlecolor); if (t.dialog.delimtitle && d->conf->no_lines == false) { wattron(d->widget, t.dialog.lineraisecolor); - waddch(d->widget, ltee); + wadd_wch(d->widget, <ee); wattroff(d->widget, t.dialog.lineraisecolor); } } @@ -1287,12 +1298,12 @@ if (d->bs.nbuttons > 0) { if (d->conf->no_lines == false) { wattron(d->widget, t.dialog.lineraisecolor); - mvwaddch(d->widget, d->h-3, 0, ltee); - mvwhline(d->widget, d->h-3, 1, ts, d->w-2); + mvwadd_wch(d->widget, d->h-3, 0, <ee); + mvwhline_set(d->widget, d->h-3, 1, &ts, d->w-2); wattroff(d->widget, t.dialog.lineraisecolor); wattron(d->widget, t.dialog.linelowercolor); - mvwaddch(d->widget, d->h-3, d->w-1, rtee); + mvwadd_wch(d->widget, d->h-3, d->w-1, &rtee); wattroff(d->widget, t.dialog.linelowercolor); } draw_buttons(d); diff --git a/lib/libbsddialog.c b/lib/libbsddialog.c --- a/lib/libbsddialog.c +++ b/lib/libbsddialog.c @@ -107,9 +107,12 @@ move(0, 1); clrtoeol(); addstr(CHECK_STR(backtitle)); - if (conf->no_lines != true) - mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE, - SCREENCOLS - 2); + if (conf->no_lines != true) { + if (conf->ascii_lines) + mvhline(1, 1, '-', SCREENCOLS - 2); + else + mvhline_set(1, 1, WACS_HLINE, SCREENCOLS - 2); + } refresh(); diff --git a/lib/menubox.c b/lib/menubox.c --- a/lib/menubox.c +++ b/lib/menubox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -183,7 +183,7 @@ int i; struct privateitem *pritem; - for(i = 0; i < m->nitems; i++) { + for (i = 0; i < m->nitems; i++) { if (m->pritems[i].type == SEPARATORMODE) continue; pritem = &m->pritems[i]; @@ -298,7 +298,7 @@ static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m) { - int i, linech, realw, labellen; + int i, realw, labellen; const char *desc, *name; for (i = 0; i < m->nitems; i++) { @@ -306,8 +306,10 @@ continue; if (conf->no_lines == false) { wattron(m->pad, t.menu.desccolor); - linech = conf->ascii_lines ? '-' : ACS_HLINE; - mvwhline(m->pad, i, 0, linech, m->line); + if (conf->ascii_lines) + mvwhline(m->pad, i, 0, '-', m->line); + else + mvwhline_set(m->pad, i, 0, WACS_HLINE, m->line); wattroff(m->pad, t.menu.desccolor); } name = m->pritems[i].name; @@ -404,12 +406,10 @@ 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); + mvwhline(m->box, 0, 2, UARROW(conf), 3); if ((m->ypad + (int)m->menurows) < m->nitems) - mvwhline(m->box, h-1, 2, - conf->ascii_lines ? 'v' : ACS_DARROW, 3); + mvwhline(m->box, h-1, 2, DARROW(conf), 3); mvwprintw(m->box, h-1, w-6, "%3d%%", 100 * (m->ypad + m->menurows) / m->nitems); @@ -578,6 +578,7 @@ if (mixedlist_redraw(&d, &m) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (mixedlist_redraw(&d, &m) != 0) return (BSDDIALOG_ERROR); @@ -591,6 +592,8 @@ next = getnext(m.nitems, m.pritems, -1); changeitem = next != m.sel; break; + case '-': + case KEY_CTRL('p'): case KEY_UP: next = getprev(m.pritems, m.sel); changeitem = next != m.sel; @@ -603,6 +606,8 @@ next = getprev(m.pritems, m.nitems); changeitem = next != m.sel; break; + case '+': + case KEY_CTRL('n'): case KEY_DOWN: next = getnext(m.nitems, m.pritems, m.sel); changeitem = next != m.sel; @@ -665,7 +670,7 @@ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe); changeitem = false; } - } /* end while(loop) */ + } /* end while (loop) */ set_return_on(&m, groups); diff --git a/lib/messagebox.c b/lib/messagebox.c --- a/lib/messagebox.c +++ b/lib/messagebox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -87,7 +87,7 @@ s->printrows = d->h - BORDER - HBUTTONS - BORDER; s->ypad = 0; getmaxyx(d->textpad, s->htextpad, unused); - unused++; /* fix unused error */ + (void)unused; /* fix unused error */ return (0); } @@ -106,7 +106,7 @@ return (BSDDIALOG_ERROR); set_buttons(&d, true, oklabel, cancellabel); s.htext = -1; - if(message_draw(&d, &s) != 0) + if (message_draw(&d, &s) != 0) return (BSDDIALOG_ERROR); loop = true; @@ -138,10 +138,14 @@ d.bs.curr = d.bs.nbuttons - 1; DRAW_BUTTONS(d); break; + case '-': + case KEY_CTRL('p'): case KEY_UP: if (s.ypad > 0) s.ypad--; break; + case '+': + case KEY_CTRL('n'): case KEY_DOWN: if (s.ypad + s.printrows < s.htextpad) s.ypad++; @@ -166,11 +170,12 @@ break; if (f1help_dialog(d.conf) != 0) return (BSDDIALOG_ERROR); - if(message_draw(&d, &s) != 0) + if (message_draw(&d, &s) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: - if(message_draw(&d, &s) != 0) + if (message_draw(&d, &s) != 0) return (BSDDIALOG_ERROR); break; default: diff --git a/lib/textbox.c b/lib/textbox.c --- a/lib/textbox.c +++ b/lib/textbox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,32 +47,33 @@ static void updateborders(struct dialog *d, struct scrolltext *st) { - chtype arrowch, borderch; + chtype arrowch; + cchar_t borderch; if (d->conf->no_lines) - borderch = ' '; + setcchar(&borderch, L" ", 0, 0, NULL); else if (d->conf->ascii_lines) - borderch = '|'; + setcchar(&borderch, L"|", 0, 0, NULL); else - borderch = ACS_VLINE; + borderch = *WACS_VLINE; if (st->xpad > 0) { - arrowch = d->conf->ascii_lines ? '<' : ACS_LARROW; - arrowch |= t.dialog.arrowcolor; + arrowch = LARROW(d->conf) | t.dialog.arrowcolor; + mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4); } else { - arrowch = borderch; - arrowch |= t.dialog.lineraisecolor; + wattron(d->widget, t.dialog.lineraisecolor); + mvwvline_set(d->widget, (d->h / 2) - 2, 0, &borderch, 4); + wattroff(d->widget, t.dialog.lineraisecolor); } - mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4); if (st->xpad + d->w - 2 - st->margin < st->wpad) { - arrowch = d->conf->ascii_lines ? '>' : ACS_RARROW; - arrowch |= t.dialog.arrowcolor; + arrowch = RARROW(d->conf) | t.dialog.arrowcolor; + mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4); } else { - arrowch = borderch; - arrowch |= t.dialog.linelowercolor; + wattron(d->widget, t.dialog.linelowercolor); + mvwvline_set(d->widget, (d->h / 2) - 2, d->w - 1, &borderch, 4); + wattroff(d->widget, t.dialog.linelowercolor); } - mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4); if (st->hpad > d->h - 4) { wattron(d->widget, t.dialog.arrowcolor); @@ -181,7 +182,7 @@ while (loop) { updateborders(&d, &st); /* - * Overflow multicolumn charchter right border: + * Trick, overflow multicolumn charchter right border: * wnoutrefresh(widget); * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe); * doupdate(); @@ -256,6 +257,7 @@ if (textbox_draw(&d, &st) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (textbox_draw(&d, &st) != 0) return (BSDDIALOG_ERROR); diff --git a/lib/timebox.c b/lib/timebox.c --- a/lib/timebox.c +++ b/lib/timebox.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,8 +48,8 @@ draw_borders(conf, win, LOWERED); if (focus) { wattron(win, t.dialog.arrowcolor); - mvwhline(win, 0, 1, conf->ascii_lines ? '^' : ACS_UARROW, 2); - mvwhline(win, 2, 1, conf->ascii_lines ? 'v' : ACS_DARROW, 2); + mvwhline(win, 0, 1, UARROW(conf), 2); + mvwhline(win, 2, 1, DARROW(conf), 2); wattroff(win, t.dialog.arrowcolor); } @@ -142,8 +142,9 @@ loop = false; } break; - case KEY_RIGHT: case '\t': /* TAB */ + case KEY_CTRL('n'): + case KEY_RIGHT: if (focusbuttons) { d.bs.curr++; focusbuttons = d.bs.curr < (int)d.bs.nbuttons ? @@ -162,6 +163,7 @@ } DRAW_BUTTONS(d); break; + case KEY_CTRL('p'): case KEY_LEFT: if (focusbuttons) { d.bs.curr--; @@ -179,6 +181,11 @@ } DRAW_BUTTONS(d); break; + case '-': + if (focusbuttons == false) + c[sel].value = c[sel].value > 0 ? + c[sel].value - 1 : c[sel].max; + break; case KEY_UP: if (focusbuttons) { sel = 0; @@ -190,6 +197,7 @@ c[sel].value - 1 : c[sel].max; } break; + case '+': case KEY_DOWN: if (focusbuttons) break; @@ -205,6 +213,7 @@ if (timebox_redraw(&d, c) != 0) return (BSDDIALOG_ERROR); break; + case KEY_CTRL('l'): case KEY_RESIZE: if (timebox_redraw(&d, c) != 0) return (BSDDIALOG_ERROR); diff --git a/utility/bsddialog.1 b/utility/bsddialog.1 --- a/utility/bsddialog.1 +++ b/utility/bsddialog.1 @@ -1,5 +1,5 @@ .\" -.\" Copyright (c) 2021-2023 Alfonso Sabato Siciliano +.\" Copyright (c) 2021-2024 Alfonso Sabato Siciliano .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 25, 2023 +.Dd April 7, 2024 .Dt BSDDIALOG 1 .Os .Sh NAME @@ -438,6 +438,21 @@ .It Fl Fl title Ar title Dialog title. .El +.Ss Keys +The following keys are available at runtime: +.Bl -tag -width Ds +.It Ctrl-l +Redraw the dialog. +.It F1 +See +.Fl Fl hfile +and +.Fl Fl hmsg . +.It SPACE +Select menu item. +.It UP DOWN LEFT RIGHT - + HOME END PAGEUP PAGEDOWN Ctrl-p Ctrl-n TAB +Navigate elements and set value, depending on the dialog. +.El .Ss Dialogs The following dialogs are available: .Bl -tag -width Ds @@ -472,20 +487,21 @@ a field to get the input at the position .Ar yfield and -.Ar xfield -with graphical length -.Ar fieldlen , -.Ar maxletters -is the maximum input length. -The field can be customized, if +.Ar xfield . .Ar fieldlen -is negative the field is read only and its absolute value is the field length. -If +is the field width, if negative is readonly and the width is the absolute value, +if +.Dv 0 +the field becomes readonly and its value is the +.Ar init +width. .Ar maxletters -is 0 it is the absolute value of +is the maximum input length, if is +.Dv 0 +its value is .Ar fieldlen . .Ar init -is a default value. +is the default value in the field. .Ar formrows is the graphical height of the list, .Dv 0 @@ -509,7 +525,7 @@ .Ar init is the default value. .It Fl Fl menu Ar text Ar rows Ar cols Ar menurows Oo Ar name desc Oc ... -Builds a menu to select an item from a list, Space key is equivalent to Enter. +Builds a menu to select an item from a list, SPACE key is equivalent to ENTER. An item has a .Ar name and a @@ -526,19 +542,33 @@ .Ar ylabel and .Ar xlabel , -a field to get the input with graphical length -.Ar fieldlen -at the position +a field to get the input at the position .Ar yfield and -.Ar xfield , +.Ar xfield . +.Ar fieldlen +is the field width, if negative is readonly and the width is the absolute value, +if +.Dv 0 +the field becomes readonly and its value is the +.Ar init +width. .Ar maxletters -is the maximum input length, +is the maximum input length, if is +.Dv 0 +its value is +.Ar fieldlen . .Ar init -is a default value, +is the default value in the field. .Ar flag -can be 0 for normal field, 1 to hide the typed characters and 2 to set the -field read only. +can customize +.Ar field : +.Dv 0 +normal, +.Dv 1 +hide typed characters, +.Dv 2 +readonly. .Ar formrows is the graphical height of the list, .Dv 0 @@ -581,7 +611,6 @@ Dialog to diplay a message without the .Dq Cancel button. -UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to scroll the text. .It Fl Fl passwordbox Ar text Ar rows Ar cols Op Ar init Dialog to get a password, .Ar init @@ -617,13 +646,12 @@ and .Ar max , .Ar init -is the default value, the keys UP, DOWN, HOME, END, PAGEUP and PAGEDOWN can -change it. +is the default value. .It Fl Fl textbox Ar file Ar rows Ar cols Opens and prints .Ar file . -UP, DOWN, LEFT, RIGHT, HOME, END, PAGEUP and PAGEDOWN keys are available to -navigate the file, TAB changes button. +TAB changes button. +Extra keys 0, h, l, k, j are available to navigate the text. .Dq OK button is renamed .Dq EXIT . @@ -644,7 +672,6 @@ .Dq Yes and .Dq \&No . -UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to scroll the text. .El .Sh ENVIRONMENT The following environment variables take effect only on startup, other options @@ -872,6 +899,8 @@ .Fl Fl version , .Fl Fl yes-label . .Pp +Keys: Ctrl-l, F1. +.Pp Dialogs: .Fl Fl calendar , .Fl Fl checklist , diff --git a/utility/bsddialog.c b/utility/bsddialog.c --- a/utility/bsddialog.c +++ b/utility/bsddialog.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -140,7 +140,7 @@ value = (int)strtol(envvalue, NULL, 10); exitcodes[i].value = value; /* ITEM_HELP follows HELP without explicit setting */ - if(i == BSDDIALOG_HELP + 1) + if (i == BSDDIALOG_HELP + 1) exitcodes[BSDDIALOG_ITEM_HELP + 1].value = value; } } @@ -242,7 +242,7 @@ if (opt.dialogbuilder == NULL) break; if (opt.backtitle != NULL) - if(bsddialog_backtitle(&conf, opt.backtitle)) + if (bsddialog_backtitle(&conf, opt.backtitle)) exit_error(false, bsddialog_geterror()); retval = opt.dialogbuilder(&conf, text, rows, cols, argc, argv, &opt); diff --git a/utility/util_builders.c b/utility/util_builders.c --- a/utility/util_builders.c +++ b/utility/util_builders.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021-2023 Alfonso Sabato Siciliano + * Copyright (c) 2021-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -532,6 +533,29 @@ } /* form */ +static unsigned int strcols(const char *string) +{ + int w; + unsigned int ncol; + size_t charlen, mb_cur_max; + wchar_t wch; + mbstate_t mbs; + + mb_cur_max = MB_CUR_MAX; + ncol = 0; + memset(&mbs, 0, sizeof(mbs)); + while ((charlen = mbrlen(string, mb_cur_max, &mbs)) != 0 && + charlen != (size_t)-1 && charlen != (size_t)-2) { + if (mbtowc(&wch, string, mb_cur_max) < 0) + return (0); + if ((w = wcwidth(wch)) > 0) + ncol += w; + string += charlen; + } + + return (ncol); +} + static void print_form_items(int output, int nitems, struct bsddialog_formitem *items, int focusitem, struct options *opt) @@ -551,7 +575,7 @@ helpname = items[focusitem].bottomdesc; dprintf(opt->output_fd, " %s", helpname); } - if(opt->help_print_items == false) + if (opt->help_print_items == false) return; dprintf(opt->output_fd, "\n"); } @@ -564,7 +588,7 @@ int form_builder(BUILDER_ARGS) { - int output, fieldlen, valuelen, focusitem; + int output, fieldlen, focusitem; unsigned int i, j, flags, formheight, nitems, sizeitem; struct bsddialog_formitem *items; @@ -591,12 +615,16 @@ items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10); fieldlen = (int)strtol(argv[j++], NULL, 10); - items[i].fieldlen = abs(fieldlen); + if (fieldlen == 0) + items[i].fieldlen = strcols(items[i].init); + else + items[i].fieldlen = abs(fieldlen); - valuelen = (int)strtol(argv[j++], NULL, 10); - items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen; + items[i].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10); + if (items[i].maxvaluelen == 0) + items[i].maxvaluelen = items[i].fieldlen; - flags = (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0); + flags = (fieldlen <= 0) ? BSDDIALOG_FIELDREADONLY : 0; items[i].flags = flags; items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : ""; @@ -643,7 +671,7 @@ int mixedform_builder(BUILDER_ARGS) { - int output, focusitem; + int output, fieldlen, focusitem; unsigned int i, j, formheight, nitems, sizeitem; struct bsddialog_formitem *items; @@ -662,16 +690,26 @@ exit_error(false, "cannot allocate memory for form items"); j = 0; for (i = 0; i < nitems; i++) { - items[i].label = argv[j++]; - items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10); - items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10); - items[i].init = argv[j++]; - items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10); - items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10); - items[i].fieldlen = (u_int)strtoul(argv[j++], NULL, 10); + items[i].label = argv[j++]; + items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10); + items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10); + items[i].init = argv[j++]; + items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10); + items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10); + fieldlen = (int)strtol(argv[j++], NULL, 10); + if (fieldlen == 0) + items[i].fieldlen = strcols(items[i].init); + else + items[i].fieldlen = abs(fieldlen); items[i].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10); - items[i].flags = (u_int)strtoul(argv[j++], NULL, 10); - items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : ""; + if (items[i].maxvaluelen == 0) + items[i].maxvaluelen = items[i].fieldlen; + + items[i].flags = (u_int)strtoul(argv[j++], NULL, 10); + if (fieldlen <= 0) + items[i].flags |= BSDDIALOG_FIELDREADONLY; + + items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : ""; } focusitem = -1; diff --git a/utility/util_theme.c b/utility/util_theme.c --- a/utility/util_theme.c +++ b/utility/util_theme.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2022-2023 Alfonso Sabato Siciliano + * Copyright (c) 2022-2024 Alfonso Sabato Siciliano * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -166,7 +166,7 @@ exit_error(false, "cannot save theme: %s", bsddialog_geterror()); - if(time(&clock) < 0) + if (time(&clock) < 0) exit_error(false, "cannot save profile getting current time"); if ((fp = fopen(file, "w")) == NULL) exit_error(false, "cannot open %s to save profile", file); @@ -235,11 +235,11 @@ exit_error(false, "Cannot get current theme: %s", bsddialog_geterror()); - if((fp = fopen(file, "r")) == NULL) + if ((fp = fopen(file, "r")) == NULL) exit_error(false, "Cannot open theme \"%s\" file", file); - while(fgets(line, BUFSIZ, fp) != NULL) { - if(line[0] == '#' || line[0] == '\n') + while (fgets(line, BUFSIZ, fp) != NULL) { + if (line[0] == '#' || line[0] == '\n') continue; /* superfluous, only for efficiency */ sscanf(line, "%s", name); value = NULL; /* useless init, fix compiler warning */ @@ -322,7 +322,7 @@ fclose(fp); - if(bsddialog_set_theme(&t) != BSDDIALOG_OK) + if (bsddialog_set_theme(&t) != BSDDIALOG_OK) exit_error(false, bsddialog_geterror()); }