aboutsummaryrefslogtreecommitdiff
path: root/contrib/bsddialog
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsddialog')
-rw-r--r--contrib/bsddialog/.gitignore28
-rw-r--r--contrib/bsddialog/CHANGELOG397
-rw-r--r--contrib/bsddialog/GNUMakefile28
-rw-r--r--contrib/bsddialog/LICENSE2
-rw-r--r--contrib/bsddialog/Makefile73
-rw-r--r--contrib/bsddialog/README.md66
-rw-r--r--contrib/bsddialog/bsddialog.1590
-rw-r--r--contrib/bsddialog/bsddialog.c1431
-rw-r--r--contrib/bsddialog/examples_library/calendar.c45
-rw-r--r--contrib/bsddialog/examples_library/checklist.c11
-rwxr-xr-xcontrib/bsddialog/examples_library/compile10
-rw-r--r--contrib/bsddialog/examples_library/datebox.c25
-rw-r--r--contrib/bsddialog/examples_library/form.c25
-rw-r--r--contrib/bsddialog/examples_library/formw.c61
-rw-r--r--contrib/bsddialog/examples_library/gauge.c57
-rw-r--r--contrib/bsddialog/examples_library/infobox.c6
-rw-r--r--contrib/bsddialog/examples_library/menu.c11
-rw-r--r--contrib/bsddialog/examples_library/mixedgauge.c79
-rw-r--r--contrib/bsddialog/examples_library/mixedlist.c21
-rw-r--r--contrib/bsddialog/examples_library/msgbox.c9
-rw-r--r--contrib/bsddialog/examples_library/pause.c21
-rw-r--r--contrib/bsddialog/examples_library/radiolist.c14
-rw-r--r--contrib/bsddialog/examples_library/rangebox.c7
-rw-r--r--contrib/bsddialog/examples_library/textbox.c38
-rw-r--r--contrib/bsddialog/examples_library/theme.c46
-rw-r--r--contrib/bsddialog/examples_library/timebox.c22
-rw-r--r--contrib/bsddialog/examples_library/yesno.c11
-rw-r--r--contrib/bsddialog/examples_utility/calendar.sh34
-rwxr-xr-xcontrib/bsddialog/examples_utility/checklist.sh16
-rwxr-xr-xcontrib/bsddialog/examples_utility/datebox.sh34
-rwxr-xr-xcontrib/bsddialog/examples_utility/form.sh14
-rwxr-xr-xcontrib/bsddialog/examples_utility/infobox.sh2
-rwxr-xr-xcontrib/bsddialog/examples_utility/inputbox.sh5
-rwxr-xr-xcontrib/bsddialog/examples_utility/menu.sh13
-rwxr-xr-xcontrib/bsddialog/examples_utility/mixedform.sh10
-rwxr-xr-xcontrib/bsddialog/examples_utility/mixedgauge.sh10
-rwxr-xr-xcontrib/bsddialog/examples_utility/passwordbox.sh4
-rwxr-xr-xcontrib/bsddialog/examples_utility/passwordform.sh14
-rwxr-xr-xcontrib/bsddialog/examples_utility/radiolist.sh18
-rw-r--r--contrib/bsddialog/examples_utility/rangebox.sh33
-rwxr-xr-xcontrib/bsddialog/examples_utility/timebox.sh3
-rw-r--r--contrib/bsddialog/lib/GNUMakefile31
-rw-r--r--contrib/bsddialog/lib/GNUmakefile51
-rw-r--r--contrib/bsddialog/lib/Makefile66
-rw-r--r--contrib/bsddialog/lib/barbox.c822
-rw-r--r--contrib/bsddialog/lib/bsddialog.3800
-rw-r--r--contrib/bsddialog/lib/bsddialog.h69
-rw-r--r--contrib/bsddialog/lib/bsddialog_progressview.h8
-rw-r--r--contrib/bsddialog/lib/bsddialog_theme.h45
-rw-r--r--contrib/bsddialog/lib/datebox.c746
-rw-r--r--contrib/bsddialog/lib/formbox.c1219
-rw-r--r--contrib/bsddialog/lib/infobox.c96
-rw-r--r--contrib/bsddialog/lib/lib_util.c1505
-rw-r--r--contrib/bsddialog/lib/lib_util.h169
-rw-r--r--contrib/bsddialog/lib/libbsddialog.c76
-rw-r--r--contrib/bsddialog/lib/menubox.c887
-rw-r--r--contrib/bsddialog/lib/messagebox.c260
-rw-r--r--contrib/bsddialog/lib/textbox.c279
-rw-r--r--contrib/bsddialog/lib/theme.c314
-rw-r--r--contrib/bsddialog/lib/timebox.c534
-rw-r--r--contrib/bsddialog/utility/GNUmakefile42
-rw-r--r--contrib/bsddialog/utility/Makefile42
-rw-r--r--contrib/bsddialog/utility/bsddialog.1952
-rw-r--r--contrib/bsddialog/utility/bsddialog.c338
-rw-r--r--contrib/bsddialog/utility/util.h125
-rw-r--r--contrib/bsddialog/utility/util_builders.c811
-rw-r--r--contrib/bsddialog/utility/util_cli.c841
-rw-r--r--contrib/bsddialog/utility/util_theme.c451
68 files changed, 9247 insertions, 5676 deletions
diff --git a/contrib/bsddialog/.gitignore b/contrib/bsddialog/.gitignore
index 62f7b594a708..c9613d477f7f 100644
--- a/contrib/bsddialog/.gitignore
+++ b/contrib/bsddialog/.gitignore
@@ -1,27 +1,27 @@
bsddialog
+.depend*
*.o
-*~
+*.so*
*.a
-examples_library/buildlist
+*.gz
+*.core
+*~
+BSDDIALOG.geany
+BSDDIALOG.tags
+examples_library/calendar
examples_library/checklist
examples_library/datebox
examples_library/form
-examples_library/formw
+examples_library/gauge
+examples_library/infobox
examples_library/menu
+examples_library/mixedgauge
examples_library/mixedlist
-examples_library/radiolist
-examples_library/theme
-examples_library/treeview
-examples_library/infobox
examples_library/msgbox
examples_library/pause
+examples_library/radiolist
examples_library/rangebox
-examples_library/sade
+examples_library/textbox
+examples_library/theme
examples_library/timebox
examples_library/yesno
-*.gz
-lib/libbsddialog.so*
-BSDDIALOG.geany
-BSDDIALOG.tags
-*.core
-freebsd-lab/
diff --git a/contrib/bsddialog/CHANGELOG b/contrib/bsddialog/CHANGELOG
index 22eb3342cfe2..7800098644d7 100644
--- a/contrib/bsddialog/CHANGELOG
+++ b/contrib/bsddialog/CHANGELOG
@@ -1,4 +1,392 @@
-2022-03-02 version 0.2
+2025-06-22 Version 1.0.5
+
+ Manual:
+ * fix: "User-friendly documentation for alternate screen"
+ https://bugs.freebsd.org/285459.
+ Improve bsddialog.1: --alternate-screen and --normal-screen.
+
+ NetBSD (tested on amd64) refactoring, no function changes:
+ * https://gitlab.com/alfix/bsddialog/-/merge_requests/4
+ lib: include <stdarg.h> in lib_util.c.
+ * https://gitlab.com/alfix/bsddialog/-/merge_requests/5
+ a call to curses' refresh() is performed, while a local
+ variable is also called refresh.
+ * Makefiles: add install and uninstall targets (both GND and BSD)
+ https://gitlab.com/alfix/bsddialog/-/merge_requests/3
+
+ MacOS (tested on amd64) refactoring, no function changes:
+ * https://gitlab.com/alfix/bsddialog/-/merge_requests/6
+ utility: replace u_int with unsigned int.
+
+ Library:
+ * fix: useless refreshes, https://gitlab.com/alfix/bsddialog/-/issues/8:
+ "It takes lot of time when running over a 115200 UART".
+ Not fixed for bsddialog_gauge() because it has to be rewritten.
+ * change: bsddialog_backtitle() does not update the screen so the
+ backtitle is not printed. To use if a dialog is built later.
+ Rationale: see "115200 UART" problem above.
+ * add: bsddialog_backtitle_rf() to print a top title refreshing the
+ screen like bsddialog_backtitle() was previously.
+ * change: forms, ENTER is also a navigation keys in forms fields.
+ Request: https://bugs.freebsd.org/287592
+ If conf.button.always_active is true the form is closes immediatly.
+
+ Library and implicitly utility:
+ * fix: textbox buttons returned values (was always OK).
+ Thanks to https://reviews.freebsd.org/D48668.
+ * change: TAB is a navigation keys in forms. Previously it directly
+ switched form-fields <-> buttons.
+ Request: https://bugs.freebsd.org/287592
+
+ Utility:
+ * change: forms, ENTER is a also navigation keys in forms fields.
+ Previously it directly closed the form except with --switch-buttons
+ Request: https://bugs.freebsd.org/287592
+
+
+2024-07-01 Version 1.0.4
+
+ Utility internal refactoring (no functional change):
+ * change: rename an internal constant to avoid a future conflict
+ because FreeBSD is changing headers files for _FORTIFY_SOURCE.
+ Reported and fixed by Kyle Evans.
+
+2024-05-27 Version 1.0.3
+
+ Utility:
+ change: --form and --mixedform do not print field value to output fd if
+ <fieldlen> is <= 0 (readonly). To note --mixedgauge continues
+ to print field value if <flag> = 2 (readonly) unless <fieldlen>
+ is <= 0 (as described previously).
+
+
+2024-04-11 Version 1.0.2
+
+ Utility:
+ improvements and changes for --form and --mixedform:
+ * add: <maxletters> 0 sets <maxletters> like <fieldlen>.
+ * add: <fieldlen> 0 sets <fieldlen> like <init> width and readonly.
+ * change: <maxletters> 0 was an error (remains error in lib).
+ * change: <fieldlen> 0 was an error (remains error in lib)
+ (<fieldlen> 0 and <init> "" 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:
+ * add: comments to --save-theme output file.
+ * add: blink, halfbright, highlight to --save-theme and --load-theme.
+ * add: theme.menu.[f_]prefixcolor to --save-theme and --load-theme.
+ * add: --datebox-format <d/m/y|m/d/y|y/m/d> to set --datebox UI.
+ * add: --help-print-items (--help-status becomes alias).
+ * add: --text-escape (--colors becomes alias).
+ * add: new escapes \Zd, \Zk, \Zs, \ZD, \ZK, \ZS, for --text-escape.
+ * add: env NO_COLOR, to set blackwhite theme.
+ * add: $HOME/.bsddialog.conf startup theme file.
+ * add: env BSDDIALOG_THEMEFILE startup theme file.
+ * add: --left1-button <label>.
+ * add: --left2-button <label>.
+ * add: --left3-button <label>.
+ * add: --right1-button <label>.
+ * add: --right2-button <label>.
+ * add: --right3-button <label>.
+ * add: dynamic exit codes.
+ - add: --error-exit-code.
+ - add: --ok-exit-code.
+ - add: --cancel-exit-code.
+ - add: --help-exit-code.
+ - add: --extra-exit-code.
+ - add: --timeout-exit-code.
+ - add: --esc-exit-code.
+ - add: --left1-exit-code.
+ - add: --left2-exit-code.
+ - add: --left3-exit-code.
+ - add: --right1-exit-code.
+ - add: --right2-exit-code.
+ - add: --right3-exit-code.
+ - add: env BSDDIALOG_ERROR.
+ - add: env BSDDIALOG_OK.
+ - add: env BSDDIALOG_CANCEL.
+ - add: env BSDDIALOG_HELP.
+ - add: env BSDDIALOG_EXTRA.
+ - add: env BSDDIALOG_TIMEOUT.
+ - add: env BSDDIALOG_ESC.
+ - add: env BSDDIALOG_LEFT1.
+ - add: env BSDDIALOG_LEFT2.
+ - add: env BSDDIALOG_LEFT3.
+ - add: env BSDDIALOG_RIGHT1.
+ - add: env BSDDIALOG_RIGHT2.
+ - add: env BSDDIALOG_RIGHT3.
+ * add: undocumented envs for bsdconfig(8) compatibility.
+ - env BSDDIALOG_COMPATRC for use_shadow setting.
+ - env BSDDIALOG_ITEM_HELP to add/set exit code.
+ * change: rename themes --theme <3d|blackwhite|flat>.
+ * change: --no-names and --no-descriptions mutually exclusive (via lia).
+ * change: quote only checklist output items if necessary. Previously
+ also radiolist item.
+ * change: dialogs with user input print always values except with ERROR,
+ ESC, Cancel. Previously the situation was quite heterogeneous.
+ * improve: DIAGNOSTIC messages adding fmt string errors.
+ * improve: disable theme setting (opt and env) with no-color terminals.
+ * improve: menus on|off status (strcasecmp, diagnostic, real off check).
+ * improve: --bikeshed with button delimiter and --date-format.
+ * improve: --textbox accepts button options.
+ * improve: Forms with Help button.
+ - print "HELP" (like menus).
+ - accept --help-list-items.
+ - accept --help-print-name.
+ * fix: --load-theme attributes.
+ * fix: --clear-screen with --and-dialog.
+ * delete: --theme <bsddialog> (partially implemented).
+ * delete: --esc-return-cancel (replaced by new env and option).
+ * delete: --generic-button1 (replaced by --right1-button).
+ * delete: --generic-button2 (replaced by --right2-button).
+ * refactor: modularize in more files (main, cli, builders, theme).
+
+ Library:
+ * add: bsddialog_inmode().
+ * add: bsddialog_clear(y) for utility --clear-screen.
+ * add: bsddialog_refresh() for utility terminal mode options.
+ * add: conf.date.format="d/m/y"|"m/d/y"|"y/m/d" to customize
+ bsddialog_datebox() UI (boxes) with a date format.
+ * add: 'const char *end' to bsddialog_gauge().
+ * add: draw focus on the shortcut-key-selected button at exit.
+ * add: escapes for conf.text.highlight \Zd, \Zk, \Zs, \ZD, \ZK, \ZS.
+ * add: other theme flags.
+ - BSDDIALOG_BLINK.
+ - BSDDIALOG_HALFBRIGHT.
+ - BSDDIALOG_HIGHLIGHT.
+ * add: generic buttons.
+ - conf.button.left1_label, BSDDIALOG_LEFT1 return value.
+ - conf.button.left2_label, BSDDIALOG_LEFT2 return value.
+ - conf.button.left3_label, BSDDIALOG_LEFT3 return value.
+ - conf.button.right1.label, BSDDIALOG_RIGHT1 return value.
+ - conf.button.right2.label, BSDDIALOG_RIGHT2 return value.
+ - conf.button.right3.label, BSDDIALOG_RIGHT3 return value.
+ * add: unused bsddialog_menugroup.min_on for future features.
+ * add: theme.menu.f_prefixcolor and theme.menu.prefixcolor.
+ * improve: check (when possible) API pointers.
+ * improve: circolar buttons with left and right keys for msgbox, yesno,
+ menus, rangebox and pause.
+ * improve: bsddialog_textbox() handles conf.buttons.
+ * improve: bsddialog_datebox() a box change affects the others as well.
+ * improve: bsddialog_geterror() with fmt strings.
+ * change: API NULL strings handled like "", except gauge *sep and *end.
+ * change: menus and form less restrictive with text, hide text with
+ little screens (same behavior as other dialogs).
+ * change: mixedgauge BSDDIALOG_MG_BLANK does not draw minibar but prints
+ minilabel. The change allows mixedgauge to add sections. To restore
+ the previous behavior setting minilabel to "".
+ * change: check/set bsddialog_gauge() perc max 100.
+ * change: check/set bsddialog_mixedgauge() mainperc max 100.
+ * change: conf.menu.no_name and conf.menu.no_desc mutually exclusive.
+ * change: bsddialog_pause() sec -> *sec to know remaining time at exit.
+ * change: add *focusitem to bsddialog_form() like menus.
+ * change: "pointer" values are always set except when BSDDIALOG_ERROR
+ occurs. Examples *yy/*mm/*ss, rangebox *value.
+ - delete conf.menu.on_without_ok.
+ - delete conf.form.value_without_ok.
+ * rename: conf.text.highlight -> conf.text.escape.
+ * rename: theme.menu.namesepcolor -> theme.menu.sepnamecolor.
+ * rename: theme.menu.descsepcolor -> theme.menu.sepdesccolor.
+ * fix: bsddialog_pause() elevation bar after resize.
+ * fix: bsddialog_textbox() key '0'.
+ * fix: timebox.c checksize (boxes width).
+ * fix: extend menurows after shrink and enlarge.
+ * fix: menu pad and form pad "re-expansion" after shrink and enlarge.
+ * fix: shadow top-left corner (trick wresize() before wmove()).
+ * fix: increment bsddialog_total_progview size for more general use.
+ * delete: BSDDIALOG_THEME_BSDDIALOG (partially implemented).
+ * delete: conf.button.generic1_label (for new conf.button.right1_label).
+ * delete: BSDDIALOG_GENERIC1 return value (new BSDDIALOG_RIGHT1).
+ * delete: conf.button.generic2_label (for new conf.button.right2_label).
+ * delete: BSDDIALOG_GENERIC2 return value (new BSDDIALOG_RIGHT2).
+ * delete: bsddialog_clearterminal(), replaced by bsddialog_clear(y).
+ * refactor: internal implementation.
+ - add: internal structures to represent components.
+ - merge: (when possible) dialogs autosize.
+ - merge: (when possible) dialogs checksize.
+ - merge: for each dialog "build" with "update" -> <dialog>_redraw().
+ - merge: new_dialog() with update_dialog() -> draw_dialog().
+ - merge: infobox.c with messagebox.c (delete infobox.c)
+ - merge: bsddialog_datebox() + bsddialog_calendar() -> datebox.c
+ - change: flat and blackwhite real themes, 3d adapted from flat.
+ - improve: replace wrefresh() -> wnoutrefresh()/doupdate().
+ - improve: replace prefresh() -> pnoutrefresh()/doupdate().
+ - improve: menu split code to build private items.
+ - improve: form split code to build private items.
+ - delete: -Wno-implicit-fallthrough.
+
+
+2023-06-12 Version 0.4.2
+
+ Library:
+ * fix: compile error with aarch64-gcc12 for "\Z[0-7]" check;
+ https://gitlab.com/alfix/bsddialog/-/issues/5.
+ * fix: BSDDIALOG_FIELDCURSOREND with multiple items
+ (warning aarch64-gcc12).
+
+
+2023-01-02 Version 0.4.1
+
+ Utility:
+ * fix: default space separator menus output, except if --separator " ".
+ * rename: GNUMakefile to GNUmakefile to simplify linux build.
+ Thanks to https://gitlab.com/alfix/bsddialog/-/merge_requests/2.
+
+ Library:
+ * fix: t.dialog.linelowercolor no bold-black, some terminal draws grey.
+ * fix: text wrapping (actual string length) with --colors.
+ * rename: GNUMakefile to GNUmakefile to simplify linux build.
+ Thanks to https://gitlab.com/alfix/bsddialog/-/merge_requests/2.
+
+
+2022-09-24 Version 0.4
+
+ Utility:
+ * add: --normal-screen to set normal mode.
+ * add: --alternate-screen to set alternate mode.
+ * add: --keep-tite as --alternate-screen alias.
+ * add: --and-dialog to build other dialogs.
+ * add: --and-widget as --and-dialog alias.
+ * add: --no-names (--no-tags becomes alias).
+ * add: --no-descriptions (--no-items becomes alias).
+ * add: --help-print-name (--help-tags becomes alias).
+ * add: --item-bottom-desc (--item-help becomes alias).
+ * add: --cr-wrap (was partially implemented) to keep '\n' with "\n".
+ * add: --text-unchanged to avoid default modification.
+ * add: --tab-escape to enable "\t" in text.
+ * add: --clear-screen to clear the screen.
+ * add: --clear-dialog to clear the dialog (was --clear).
+ * add: --calendar dialog to select a date.
+ * add: DIAGNOSTICS messages for bad arguments number.
+ * add: DIAGNOSTICS messages for missing and unexpected options.
+ * change: --clear becomes alias for --clear-screen.
+ * change: --print-maxsize format output.
+ * change: --menu, --radiolist, --checklist and --treeview output.
+ - no printed items with Cancel or ESC.
+ - --separator prints <sepstr> before each item except HELP.
+ - --separator and --separate-output print <sepstr> after each item.
+ - quoted item name/desc only when needed.
+ - --menu avoids to print selected item after focused HELP item.
+ * change: text default modification.
+ - without a "\n": '\t' -> space, '\n' -> '\n', trim spaces.
+ - with a "\n": '\t' -> space, '\n' -> space, "\n" -> '\n', no trim.
+ - delete '\n' after "\n" (also with --cr-wrap).
+ * change: --datebox input and output format yy/mm/dd -> dd/mm/yy.
+ * delete: --no-collapse (partially implemented).
+ * delete: --no-nl-expand (partially implemented).
+ * delete: --trim (partially implemented).
+
+ Library:
+ * add: bsddialog_msgbox() HOME, END, PPAGE and NPAGE keys.
+ * add: bsddialog_yesno() HOME, END, PPAGE and NPAGE keys.
+ * add: bsddialog_menu() SPACE key (equivalent to ENTER).
+ * add: bsddialog_calendar() to select a date.
+ * change: rename enum bsddialog_grouptype -> enum bsddialog_menutype.
+ * change: fixed-menurows becomes at most menurows (depending on text).
+ * change: fixed-rows becomes at most rows, min(rows, screenH - shadow).
+ * change: fixed-cols becomes at most cols, min(cols, screenW - shadow).
+ * delete: undocumented internal bsddialog_menuitem.depth factor (was 2).
+
+
+2022-08-29 Version 0.3
+
+ Utility:
+ * add: --textbox accepts options for the first button.
+ * add: --columns-per-row for text autosizing.
+ * add: --load-theme to read and set a custom theme at runtime.
+ * add: --save-theme to save current theme.
+ * add: --bikeshed for random settings.
+ * add: --switch-buttons to enable buttons/input widgets focus switching.
+ Available for: --form, --inputbox, --mixedform, --passwordform,
+ --passwordbox, --timebox and --datebox.
+ * change: rename --esc-cancelvalue to --esc-return-cancel.
+ * change: form field value is printed like multibyte charachter string,
+ previously widechar string.
+ * change: --timebox output with zero padding.
+ * change: --datebox output mm and dd with zero padding.
+ * fix: --hline with empty string.
+ * fix: avoid to overlay the backtitle by setting a top margin.
+ * fix: avoid to overlay down shadow with menus and forms bottomdesc
+ by setting a down margin.
+ * fix: --form read-only flag with multiple fields.
+
+ Library:
+ * add: conf.auto_topmargin and conf.auto_downmargin.
+ * add: bsddialog_textbox() accepts conf.button.* for the first button.
+ * add: bsddialog_textbox() arrows and percentage.
+ * add: conf.text.cols_per_row to set a ratio for text autosizing.
+ * add: timebox and datebox arrows and focus background for boxes.
+ * add: timebox and datebox UP key to switch focus.
+ * add: bsddialog_init_notheme() in bsddialog.h.
+ * add: bsddialog_hascolors() in bsddialog_theme.h.
+ * add: theme.form.bottomdesccolor and theme.menu.bottomdesccolor.
+ * add: conf.button.always_active to disable buttons/input-boxes switch.
+ * add: dynamic buttons margin.
+ - add: theme.button.minmargin and theme.button.maxmargin.
+ - delete: theme.button.hmargin.
+ * add: Unicode.
+ - UI handles multicolumn charachters: backtitle, title,
+ text (word wrapping, autosizing), menus (shortcuts, name, desc),
+ forms (label, field), textbox, mixedgauge (minilabel),
+ buttons (label, shortcuts), bottomtitle.
+ - API handles char* arguments like multibyte charachter string,
+ depending on the current locale.
+ - Internally wide charachters are used to get input from keyboard
+ and to adapt word wrapping and dynamic text autosizing to
+ muticolumn charachters.
+ * refactoring: (rewrite) form.c.
+ - delete: libformw dep implementing its features from scratch.
+ - delete: maxvaluelen >= valuelen constraint.
+ - delete: conf.form.enable_wchar, get always unicode (wchar) input.
+ - add: KEY_HOME, KEY_END, KEY_PPAGE, KEY_NPAGE keys in field.
+ - add: KEY_UP can move focus from buttons to fields.
+ - add: KEY_DOWN can move focus from item to buttons, if nitem is 1.
+ - add: conf.form.securembch secure multibyte charachter.
+ - add: BSDDIALOG_FIELDNOCOLOR for formitem.flags.
+ - add: BSDDIALOG_FIELDCURSOREND for formitem.flags.
+ - add: BSDDIALOG_FIELDEXTEND for formitem.flags.
+ - add: BSDDIALOG_FIELDSINGLEBYTE for formitem.flags.
+ - add: resizing and refresh after KEY_RESIZE (SIGWINCH).
+ - add: items scrolling.
+ - add: conf.form.value_wchar, value is wchar_t* instead of MB-char*.
+ - add: formheight autosizing.
+ - add: dynamic item position.
+ * fix: bsddialog_gauge() with fd < 0.
+ * fix: bsddialog_gauge() refresh new text.
+ * fix: internal segmentation fault with disabled shadow.
+ * fix: center position without shadow.
+ * fix: bsddialog_infobox() with zero text length.
+ * fix: text wrapping with more than 1024 words.
+ * fix: rename theme.shadow.h to theme.shadow.y.
+ * fix: rename theme.shadow.w to theme.shadow.x.
+ * fix: menurows autosize with fixed rows improving text_size().
+ * fix: messagebox.c scrolling and checksize without text.
+
+
+2022-03-02 Version 0.2
Utility:
* add: (this) CHANGELOG.
@@ -19,7 +407,7 @@
* change: theme.button.[left|right]ch -> theme.button.[left|right]delim.
* change: theme.button.space -> theme.button.hmargin.
* change: theme.menu.arrowcolor -> theme.dialog.arrowcolor.
- * change: default menu item depth 4 -> 2.
+ * change: internal bsddialog_menuitem.depth factor 4 -> 2.
* fix: disable HOME, PPAGE, END and NPAGE keys in bsddialog_form().
* fix: visible cursor for timebox.c and form.c in VM VirtualBox.
* fix: mixedlist, center position of separator with big pad.
@@ -31,9 +419,9 @@
* improve: "menus" colors for accessibility.
-2022-01-27 version 0.1
+2022-01-27 Version 0.1
- * Common-Options: --ascii-lines, --backtitle <backtitle>, --begin-x <x>,
+ * Options: --ascii-lines, --backtitle <backtitle>, --begin-x <x>,
--begin-y <y>, --cancel-label <label>, --clear, --colors, --cr-wrap,
--date-format <format>, --defaultno, --default-button <label>,
--default-no, --default-item <name>, --disable-esc,
@@ -58,4 +446,3 @@
--passwordbox, --passwordform, --pause, --radiolist, --rangebox,
--textbox, --timebox, --treeview, --yesno.
* Manuals: bsddialog.1, bsddialog.3.
-
diff --git a/contrib/bsddialog/GNUMakefile b/contrib/bsddialog/GNUMakefile
deleted file mode 100644
index ad3d4f55f4a7..000000000000
--- a/contrib/bsddialog/GNUMakefile
+++ /dev/null
@@ -1,28 +0,0 @@
-# PUBLIC DOMAIN - NO WARRANTY, see:
-# <http://creativecommons.org/publicdomain/zero/1.0/>
-#
-# Written in 2021 by Alfonso Sabato Siciliano
-
-OUTPUT= bsddialog
-SOURCES= bsddialog.c
-OBJECTS= $(SOURCES:.c=.o)
-LIBPATH= ./lib
-LIBBSDDIALOG= $(LIBPATH)/libbsddialog.so
-CFLAGS= -Wall -Wextra -Wno-unused-parameter -I$(LIBPATH)
-LDFLAGS= -Wl,-rpath=$(LIBPATH) -L$(LIBPATH) -lbsddialog
-RM = rm -f
-
-all : $(OUTPUT)
-
-$(OUTPUT): $(LIBBSDDIALOG) $(OBJECTS)
- $(CC) $^ -o $@ $(LDFLAGS)
-
-${LIBBSDDIALOG}:
- make -C ${LIBPATH} -f GNUMakefile
-
-%.o: %.c $(LIBBSDDIALOG)
- $(CC) $(CFLAGS) -c $<
-
-clean:
- make -C ${LIBPATH} -f GNUMakefile clean
- $(RM) $(OUTPUT) *.o *~
diff --git a/contrib/bsddialog/LICENSE b/contrib/bsddialog/LICENSE
index f24be045375b..9ea4a4a62f4b 100644
--- a/contrib/bsddialog/LICENSE
+++ b/contrib/bsddialog/LICENSE
@@ -1,6 +1,6 @@
BSD 2-Clause License
-Copyright (c) 2021-2022, Alfonso Sabato Siciliano
+Copyright (c) 2021-2025, 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/contrib/bsddialog/Makefile b/contrib/bsddialog/Makefile
index 5d5d0cc923a5..335b693470e6 100644
--- a/contrib/bsddialog/Makefile
+++ b/contrib/bsddialog/Makefile
@@ -1,50 +1,47 @@
# PUBLIC DOMAIN - NO WARRANTY, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>
#
-# Written in 2021 by Alfonso Sabato Siciliano
-
-OUTPUT= bsddialog
-SOURCES= bsddialog.c
-OBJECTS= ${SOURCES:.c=.o}
-LIBPATH= ${.CURDIR}/lib
-LIBBSDDIALOG= ${LIBPATH}/libbsddialog.so
-
-CFLAGS+= -I${LIBPATH} -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter
-# `make -DDEBUG`
-.if defined(DEBUG)
-CFLAGS= -g -Wall -I${LIBPATH}
-LIBDEBUG= -DDEBUG
-.endif
-LDFLAGS+= -Wl,-rpath=${LIBPATH} -L${LIBPATH} -lbsddialog
-
-BINDIR= /usr/local/bin
-MAN= ${OUTPUT}.1
-GZIP= gzip -cn
-MANDIR= /usr/local/share/man/man1
-
-INSTALL= install
+# Written in 2023 by Alfonso Sabato Siciliano
+
+OUTPUT = bsddialog
+export VERSION=1.0.5
+.CURDIR ?= ${CURDIR}
+LIBPATH = ${.CURDIR}/lib
+LIBBSDDIALOG = ${LIBPATH}/libbsddialog.so
+UTILITYPATH = ${.CURDIR}/utility
+
RM= rm -f
+LN = ln -s -f
-all : ${OUTPUT}
+### command-line options ###
+# FreeBSD port Makefile: 'MAKE_ARGS = -DNORPATH'
+NORPATH ?=
+export DISABLERPATH=${NORPATH}
+# Debug: `make -DDEBUG` or `gmake DEBUG=1`
+DEBUG ?=
+export ENABLEDEBUG=${DEBUG}
+###################
-${OUTPUT}: ${LIBBSDDIALOG} ${OBJECTS}
- ${CC} ${LDFLAGS} ${OBJECTS} -o ${.PREFIX}
+all: ${OUTPUT}
-${LIBBSDDIALOG}:
- make -C ${LIBPATH} ${LIBDEBUG}
+install: all
+ ${MAKE} -C ${LIBPATH} install
+ ${MAKE} -C ${UTILITYPATH} install
-.c.o:
- ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+uninstall:
+ ${MAKE} -C ${UTILITYPATH} uninstall
+ ${MAKE} -C ${LIBPATH} uninstall
-install:
- ${INSTALL} -s -m 555 ${OUTPUT} ${BINDIR}
- ${GZIP} ${MAN} > ${MAN}.gz
- ${INSTALL} -m 444 ${MAN}.gz ${MANDIR}
+${OUTPUT}: ${LIBBSDDIALOG}
+ ${MAKE} -C ${UTILITYPATH} LIBPATH=${LIBPATH}
+ ${LN} ${UTILITYPATH}/${OUTPUT} ${.CURDIR}/${OUTPUT}
-unistall:
- ${RM} ${BINDIR}/${OUTPUT}
- ${RM} ${MANDIR}/${MAN}.gz
+${LIBBSDDIALOG}:
+ ${MAKE} -C ${LIBPATH}
clean:
- make -C ${LIBPATH} clean
- ${RM} ${OUTPUT} *.o *~ *.core ${MAN}.gz
+ ${MAKE} -C ${LIBPATH} clean
+ ${MAKE} -C ${UTILITYPATH} clean
+ ${RM} ${OUTPUT} *.core
+
+.PHONY: all install uninstall clean
diff --git a/contrib/bsddialog/README.md b/contrib/bsddialog/README.md
index 3a814b38ddb4..5a25109775fe 100644
--- a/contrib/bsddialog/README.md
+++ b/contrib/bsddialog/README.md
@@ -1,28 +1,17 @@
-# BSDDialog 0.2
+# BSDDialog 1.0.5
+This project provides **bsddialog** and **libbsddialog**, an utility
+and a library to build scripts and tools with TUI dialogs and widgets.
-This project provides **bsddialog** and **libbsddialog**, an utility and a
-library to build scripts and tools with TUI dialogs and widgets.
+## Demo
-## Intro
-
-Briefly:
-<https://www.freebsd.org/status/report-2021-04-2021-06/#_bsddialog_tui_widgets>
-
-Utility:
-<https://alfonsosiciliano.gitlab.io/posts/2021-12-07-bsddialog.html>
-
-Library:
-<https://alfonsosiciliano.gitlab.io/posts/2022-01-16-libbsddialog.html>
-
-Screenshots:
-<https://www.flickr.com/photos/alfonsosiciliano/albums/72157720215006074>
+[Screenshots](https://www.flickr.com/photos/alfonsosiciliano/albums/72157720215006074).
## Getting Started
-FreeBSD:
+FreeBSD and Linux:
```
% git clone https://gitlab.com/alfix/bsddialog.git
@@ -40,9 +29,9 @@ Output:
**Dialogs:**
---checklist, --datebox, --form, --gauge, --inputbox, --menu, --mixedform,
---mixedgauge, --msgbox, --passwordbox, --passwordform, --pause, --radiolist,
---rangebox, --textbox, --timebox, --treeview, --yesno.
+--calendar, --checklist, --datebox, --form, --gauge, --infobox, --inputbox,
+--menu, --mixedform, --mixedgauge, --msgbox, --passwordbox, --passwordform,
+--pause, --radiolist, --rangebox, --textbox, --timebox, --treeview, --yesno.
**Manual**
@@ -64,7 +53,9 @@ Output:
and [Examples](https://gitlab.com/alfix/bsddialog/-/tree/main/examples_utility)
in the _Public Domain_ to build new projects:
```
+% sh ./examples_utility/calendar.sh
% sh ./examples_utility/checklist.sh
+% sh ./examples_utility/datebox.sh
% sh ./examples_utility/form.sh
% sh ./examples_utility/gauge.sh
% sh ./examples_utility/infobox.sh
@@ -77,6 +68,7 @@ in the _Public Domain_ to build new projects:
% sh ./examples_utility/passwordform.sh
% sh ./examples_utility/pause.sh
% sh ./examples_utility/radiolist.sh
+% sh ./examples_utility/rangebox.sh
% sh ./examples_utility/timebox.sh
% sh ./examples_utility/yesno.sh
```
@@ -101,10 +93,14 @@ in the _Public Domain_ to build new projects:
```
% cd examples_library
% sh compile
+% ./calendar
+% ./checklist
% ./datebox
% ./form
+% ./gauge
% ./infobox
% ./menu
+% ./mixedgauge
% ./mixedlist
% ./msgbox
% ./pause
@@ -114,4 +110,32 @@ in the _Public Domain_ to build new projects:
% ./timebox
% ./yesno
```
-
+
+
+## TODO and Ideas
+
+ - menubar feature.
+ - key callback.
+ - Right-To-Left text.
+ - some terminal does not hide the cursor, move it bottom-right before to getch.
+ - 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.
+ - doc: external tutorial, theming guide.
+ - implement menutype.min\_on.
+ - 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*
+ - check --passwordform *fieldlen* like --form and --mixedform.
+ - add manuals to Makefiles installe and uninstall targets.
diff --git a/contrib/bsddialog/bsddialog.1 b/contrib/bsddialog/bsddialog.1
deleted file mode 100644
index c87b760d2ea3..000000000000
--- a/contrib/bsddialog/bsddialog.1
+++ /dev/null
@@ -1,590 +0,0 @@
-.\"
-.\" Copyright (c) 2021-2022 Alfonso Sabato Siciliano
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd February 3, 2022
-.Dt BSDDIALOG 1
-.Os
-.Sh NAME
-.Nm bsddialog
-.Nd TUI dialogs
-.Sh SYNOPSIS
-.Nm
-.Fl Fl help
-.Nm
-.Fl Fl version
-.Nm
-.Op Fl Fl common-option
-.Fl Fl dialog
-.Ar text
-.Ar rows
-.Ar cols
-.Op Ar dialog-parameter
-.Sh DESCRIPTION
-The
-.Nm bsddialog
-utility builds Text User Interface dialogs and widgets: to display messages,
-to get input and to inform about a computation status.
-.Pp
-The options
-.Fl Fl help
-and
-.Fl Fl version
-print the list of options and the version, respectively, then exit.
-.Pp
-The following options are available for each dialog.
-.Ar text
-is a message printed inside the dialog, except for
-.Fl Fl textbox
-described later.
-.Ar rows
-and
-.Ar cols
-are the height and width, 0 for autosize and -1 for fullscreen.
-The possible input got from the user interface is printed to standard error.
-.Ss Common options
-The following options can change the default behavior of the utility and are
-common to some dialog.
-.Bl -tag -width Ds
-.It Fl Fl ascii-lines
-Ascii characters to draw lines.
-.It Fl Fl backtitle Ar backtitle
-Title on the top side of the screen.
-.It Fl Fl begin-x Ar x
-Dialog horizontal position, 0 is the left screen side, -1 center.
-.It Fl Fl begin-y Ar y
-Dialog vertical position, 0 is the top screen side, -1 center.
-.It Fl Fl cancel-label Ar label
-Label for the
-.Dq Cancel
-button.
-.It Fl Fl clear
-Hide the dialog at exit.
-.It Fl Fl colors
-Enable highlights for text, the following sequences are considered escapes:
-.Bl -column -compact
-.It Dq \eZ0
-black.
-.It Dq \eZ1
-red.
-.It Dq \eZ2
-green.
-.It Dq \eZ3
-yellow.
-.It Dq \eZ4
-blue.
-.It Dq \eZ5
-magenta.
-.It Dq \eZ6
-cyan.
-.It Dq \eZ7
-white.
-.It Dq \eZr
-reverse foreground and background colors.
-.It Dq \eZR
-disable reverse.
-.It Dq \eZb
-bold.
-.It Dq \eZB
-disable bold.
-.It Dq \eZu
-underline.
-.It Dq \eZU
-disable underline.
-.It Dq \eZn
-restore to normal text.
-.El
-.It Fl Fl cr-wrap
-Replace new line with a space in
-.Ar text .
-.It Fl Fl date-format Ar format
-String accepted by
-.Xr strftime 3
-to customize the output of
-.Fl Fl datebox .
-.It Fl Fl default-button Ar label
-Focus on the button with
-.Ar label
-on startup.
-.It Fl Fl default-item Ar name
-Focus on the item with
-.Ar name ,
-for Checklist, Menu, Radiolist and Treeview.
-.It Fl Fl default-no
-Focus on
-.Dq Cancel
-or
-.Dq \&No
-button on startup.
-.It Fl Fl defaultno
-Equivalent to
-.Fl Fl default-no .
-.It Fl Fl disable-esc
-Disable ESC key to quit.
-.It Fl Fl esc-cancelvalue
-Exits with the
-.Dq Cancel
-button value if the ESC key is pressed.
-.It Fl Fl exit-label Ar label
-Equivalent to
-.Fl Fl ok-label .
-.It Fl Fl extra-button
-Add a button with
-.Dq Extra
-label.
-.It Fl Fl extra-label Ar label
-Set
-.Ar label
-for the
-.Dq Extra
-button.
-.It Fl Fl generic-button1 Ar label
-Add a button with
-.Ar label .
-.It Fl Fl generic-button2 Ar label
-Add a button with
-.Ar label .
-.It Fl Fl help-button
-Add a button with
-.Dq Help
-label.
-.It Fl Fl help-label Ar label
-Set
-.Ar label
-for
-.Dq Help
-button.
-.It Fl Fl help-status
-Print also the selected items if the
-.Dq Help
-button is pressed.
-.It Fl Fl help-tags
-Print the name of the focused item if the Help button is pressed also
-with
-.Fl Fl item-help .
-.It Fl Fl hfile Ar filename
-Open
-.Ar filename
-in a Textbox if F1 key is pressed,
-.It Fl Fl hline Ar string
-Dialog subtitle.
-.It Fl Fl hmsg Ar string
-Open a Msgbox with
-.Ar string
-if the F1 key is pressed.
-.It Fl Fl ignore
-Do not exit with unknown options.
-.It Fl Fl insecure
-Print
-.Sq *
-to hide passwords while typing, default space
-.Sq " " .
-.It Fl Fl item-depth
-Specify a margin for items, available for Checklist, Menu and Radiolist.
-.It Fl Fl item-help
-Set a help string for each element of a Checklist, Form, Menu, Mixedform,
-Passwordform, Radiolist and Treeview to display at the bottom screen side.
-.It Fl Fl item-prefix
-Set a string to prefix each item of a Checklist, Menu, Radiolist or Treeview.
-.It Fl Fl max-input Ar size
-Maximum length of the input for
-.Fl Fl input-box
-ans
-.Fl Fl passwordbox ,
-default 2048.
-.It Fl Fl no-cancel
-Do not show
-.Dq Cancel
-button.
-.It Fl Fl no-collapse
-Do not replace a TAB character with a space in
-.Ar text .
-.It Fl Fl no-items
-Do not display items desciption, for Checklist, Menu, Radiolist or Treeview.
-.It Fl Fl no-label Ar label
-Equivalent to
-.Fl Fl cancel-label .
-.It Fl Fl no-lines
-Do not draw borders and lines.
-.It Fl Fl no-nl-expand
-do not consider the sequence
-.Dq \en
-like new line.
-.It Fl Fl no-ok
-Do not draw
-.Dq OK
-button.
-.It Fl Fl no-shadow
-No not draw the shadow of the dialog.
-.It Fl Fl no-tags
-Do not display items name, for Checklist, Menu and Radiolist.
-.It Fl Fl nocancel
-Equivalent to
-.Fl Fl no-cancel .
-.It Fl Fl nook
-Equivalent to
-.Fl Fl no-ok .
-.It Fl Fl ok-label Ar label
-Set
-.Ar label
-for
-.Dq OK
-button.
-.It Fl Fl output-fd Ar fd
-Print input from user interface to the specified file descriptor.
-.It Fl Fl output-separator Ar sep
-Set a sepator for the items in output, default whitespace.
-.It Fl Fl print-maxsize
-Screen size.
-.It Fl Fl print-size
-Print Dialog height and widget at exit.
-.It Fl Fl print-version
-Print version.
-.It Fl Fl quoted
-Quote items in output, default only when necessary.
-.It Fl Fl separate-output
-Separate selected items with a new line and avoid to quote.
-.It Fl Fl separator Ar sep
-Equivalent to
-.Fl Fl output-separator .
-.It Fl Fl shadow
-Show a pseudo shadow for the dialog, enabled by default.
-.It Fl Fl single-quoted
-Use single quote for items in output.
-.It Fl Fl sleep Ar secs
-Wait
-.Ar secs
-seconds to close the dialog.
-.It Fl Fl stderr
-Print input from user interface to standand error, default.
-.It Fl Fl stdout
-Print input from user interface to standard output.
-.It Fl Fl tab-len Ar spaces
-Number of spaces to print a TAB in
-.Ar text .
-.It Fl Fl theme Ar theme
-Set a graphical style: blackwhite, bsddialog, flat or dialog.
-.It Fl Fl time-format Ar format
-String accepted by
-.Xr strftime 3
-to customize the output of
-.Fl Fl timebox .
-.It Fl Fl title Ar title
-Dialog title.
-.It Fl Fl trim
-remove consecutive spaces in
-.Ar text .
-.It Fl Fl yes-label Ar label
-Equivalent to
-.Fl Fl ok-label .
-.El
-.Ss Dialogs
-The following dialogs are available:
-.Bl -tag -width Ds
-.It Fl Fl checklist Ar text Ar rows Ar cols Ar menurows Oo Ar name Ar desc \
-Ar status Oc ...
-Checklist to select some item from a list via the SPACE key.
-An item has a
-.Ar name ,
-.Ar desc
-and a default
-.Ar status
-specified by
-.Dq on
-or
-.Dq off .
-The names of the selected items are printed to standard error.
-.Ar menurows
-is the graphical height of the list, 0 for autosize.
-.It Fl Fl datebox Ar text Ar rows Ar cols Op Ar year Ar month Ar day
-Dialog to select a date.
-.It Fl Fl form Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
-Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxvaluelen Oc ...
-Dialog to get a list of strings via forms.
-A form has a
-.Ar label
-at the position
-.Ar ylabel
-and
-.Ar xlabel ,
-a field to get the input at the position
-.Ar yfield
-and
-.Ar xfield
-with graphical length
-.Ar fieldlen ,
-.Ar maxvaluelen
-is the maximum input length.
-The field can be customized, if
-.Ar fieldlen
-is 0 its length is the absolute value of
-.Ar maxvaluelen ,
-if
-.Ar maxvaluelen
-is negative the field is read only,
-.Ar init
-is a default value.
-.Ar formrows
-is the graphical height of the list, has to be at least the number of forms.
-.It Fl Fl gauge Ar text Ar rows Ar cols Op Ar percentage
-Dialog with a bar to shows
-.Ar percentage ,
-then it waits to read
-.Dq XXX
-from the standard input, then the first string replaces percentage and the
-following strings replace
-.Ar text
-until the next
-.Dq XXX ,
-the loop ends reading
-.Dv EOF .
-.It Fl Fl infobox Ar text Ar rows Ar cols
-Dialog without buttons to display a message and to exit immediately.
-.It Fl Fl inputbox Ar text Ar rows Ar cols Op Ar init
-Dialog to get a string in input,
-.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.
-An item has a
-.Ar name
-and a
-.Ar desc .
-The name of the selected item is printed to standard error.
-.Ar menurows
-is the graphical height of the list, 0 for autosize.
-.It Fl Fl mixedform Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
-Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxvaluelen Ar flag Oc ...
-Dialog to get a list of strings via forms.
-A form has a
-.Ar label
-at the position
-.Ar ylabel
-and
-.Ar xlabel ,
-a field to get the input with graphical length
-.Ar fieldlen
-at the position
-.Ar yfield
-and
-.Ar xfield ,
-.Ar maxvaluelen
-is the maximum input length,
-.Ar init
-is a default value,
-.Ar flag
-can be 0 for normal field, 1 to hide the typed characters and 2 to set the
-field read only.
-.Ar formrows
-is the graphical height of the list, has to be at least the number of forms.
-.It Fl Fl mixedgauge Ar text Ar rows Ar cols Ar mainperc Oo Ar minilabel \
-Ar miniperc Oc ...
-Dialog to show a main bar to represent
-.Ar mainperc
-from 0 to 100 and some mini bar with a
-.Ar minilabel
-string and a
-.Ar miniperc
-with value from 0 and 100 or negative to print a descriptive string: -1
-.Dq Succeeded ,
--2
-.Dq Failed ,
--3
-.Dq Passed ,
--4
-.Dq Completed ,
--5
-.Dq Checked ,
--6
-.Dq Done ,
--7
-.Dq Skipped ,
--8
-.Dq \&In Progress ,
--9
-a blank line,
--10
-.Dq N/A ,
--11
-.Dq Pending .
-.It Fl Fl msgbox Ar text Ar rows Ar cols
-Dialog to diplay a message without the
-.Dq Cancel
-button.
-.It Fl Fl passwordbox Ar text Ar rows Ar cols Op Ar init
-Dialog to get a password,
-.Ar init
-is the default value.
-.It Fl Fl passwordform Ar text Ar rows Ar cols Ar formrows Oo Ar label \
-Ar ylabel Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar valuelen Oc ...
-Dialog to get a list of passwords, equivalent to
-.Fl Fl form
-except typed characters are hidden.
-.It Fl Fl pause Ar text Ar rows Ar cols Ar seconds
-Dialog runs until the timeout in
-.Ar seconds
-expires or a button is pressed.
-.It Fl Fl radiolist Ar text Ar rows Ar cols Ar menurows Oo Ar name Ar desc \
-Ar status Oc ...
-Radiolist to select at most an item from a list via the SPACE key.
-An item has a
-.Ar name ,
-.Ar desc
-and a default
-.Ar status
-specified by
-.Dq on
-or
-.Dq off .
-The name of the selected item is printed to standard error.
-.Ar menurows
-is the graphical height of the list, 0 for autosize.
-.It Fl Fl rangebox Ar text Ar rows Ar cols Ar min Ar max Op Ar init
-Dialog to select a value between
-.Ar min
-and
-.Ar max ,
-.Ar init
-is the default value, the keys UP, DOWN, HOME, END, PAGEUP and PAGEDOWN can
-change it.
-.It Fl Fl textbox Ar file Ar rows Ar cols
-Opens and prints
-.Ar file
-the UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to navigate;
-.Dq OK
-button is renamed
-.Dq EXIT .
-.It Fl Fl timebox Ar text Ar rows Ar cols Op Ar hour Ar min Ar sec
-Dialog to select a time.
-.It Fl Fl treeview Ar text Ar rows Ar cols Ar menurows Oo Ar depth Ar name \
-Ar desc Ar status Oc ...
-Equivalent to Radiolist with
-.Fl Fl item-depth
-and
-.Fl Fl no-name .
-.It Fl Fl yesno Ar text Ar rows Ar cols
-.Dq Yes-No Question ,
-.Dq OK
-and
-.Dq Cancel
-buttons are renamed
-.Dq Yes
-and
-.Dq \&No .
-.El
-.Sh EXIT STATUS
-The
-.Nm
-utility exits 255 on unsuccessful, otherwise depending on the button or key
-pressed the following values can be returned:
-.Bl -column -compact
-.It 0
-.Dq OK ,
-.Dq Yes
-or
-.Dq Exit
-button.
-.It 1
-.Dq Cancel
-or
-.Dq \&No
-button.
-.It 2
-.Dq Help
-button.
-.It 3
-.Dq Extra
-button.
-.It 4
-Timeout.
-.It 5
-ESC key.
-.It 6
-Generic 1 button.
-.It 7
-Generic 2 button.
-.El
-.Sh EXAMPLES
-Backtitle, title and message:
-.Dl bsddialog --backtitle MESSAGE --title Msgbox --msgbox Message 0 0
-.Pp
-Yes-No Question and theme:
-.Dl bsddialog --theme blackwhite --yesno Question 10 30
-.Pp
-Checklist:
-.Dl bsddialog --checklist Checklist 0 0 3 N1 \&D1 off N2 D2 on N3 D3 off
-.Pp
-Mixedgauge:
-.Dl bsddialog --sleep 3 --mixedgauge Example 10 30 60 L1 "\(dq" -1" L2 30
-.Pp
-Form:
-.Dl bsddialog --form Form 0 0 2 L1: 1 1 X 1 5 20 25 L2: 2 1 X 2 5 20 25
-.Pp
-Gauge script:
-.Bd -literal -offset indent -compact
-i=1
-for c in A B C D E F G H
-do
- sleep 1
- echo XXX
- echo "$(expr $(expr $i "*" 100) "/" 8)"
- echo "[$i/8] Char: $c"
- echo XXX
- if [ $i -eq 8 ]
- then
- sleep 1
- echo EOF
- fi
- i=`expr $i + 1`
-done | bsddialog --title Gauge --gauge "Starting..." 10 70
-.Ed
-.Pp
-Mixedgauge script:
-.Bd -literal -offset indent -compact
-perc=0
-while [ $perc -le 100 ]
-do
- bsddialog --sleep 1 --title Mixedgauge \e
- --mixedgauge "\enExample...\en" 0 0 $perc \e
- "Hidden" " -9" \e
- "Label 1" " -4" \e
- "Label 2" " -4" \e
- "Label 3" $perc
-
- perc=`expr $perc + 20`
-done
-.Ed
-.Sh SEE ALSO
-.Xr bsddialog 3
-.Sh HISTORY
-The
-.Nm bsddialog
-utility first appeared in
-.Fx 14.0 .
-.Sh AUTHORS
-.Nm bsddialog
-was written by
-.An Alfonso Sabato Siciliano Aq Mt alf.siciliano@gmail.com .
-.Sh BUGS
-Forms do not resize the dialog after a terminal change and do not provide
-scrolling for items. \ No newline at end of file
diff --git a/contrib/bsddialog/bsddialog.c b/contrib/bsddialog/bsddialog.c
deleted file mode 100644
index d84df4b494d9..000000000000
--- a/contrib/bsddialog/bsddialog.c
+++ /dev/null
@@ -1,1431 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/ioctl.h>
-
-#include <getopt.h>
-#include <locale.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <bsddialog.h>
-#include <bsddialog_theme.h>
-
-#define BSDDIALOG_VERSION "0.2"
-
-enum OPTS {
- /* Common options */
- ASCII_LINES = '?' + 1,
- BACKTITLE,
- BEGIN_X,
- BEGIN_Y,
- CANCEL_LABEL,
- CLEAR,
- COLORS,
- CR_WRAP,
- DATE_FORMAT,
- DEFAULT_BUTTON,
- DEFAULT_ITEM,
- DEFAULT_NO,
- DISABLE_ESC,
- ESC_CANCELVALUE,
- EXIT_LABEL,
- EXTRA_BUTTON,
- EXTRA_LABEL,
- GENERIC_BUTTON1,
- GENERIC_BUTTON2,
- HELP,
- HELP_BUTTON,
- HELP_LABEL,
- HELP_STATUS,
- HELP_TAGS,
- HFILE,
- HLINE,
- HMSG,
- IGNORE,
- INSECURE,
- ITEM_DEPTH,
- ITEM_HELP,
- ITEM_PREFIX,
- MAX_INPUT,
- NO_CANCEL,
- NO_COLLAPSE,
- NO_ITEMS,
- NO_LINES,
- NO_NL_EXPAND,
- NO_OK,
- NO_SHADOW,
- NO_TAGS,
- OK_LABEL,
- OUTPUT_FD,
- OUTPUT_SEPARATOR,
- PRINT_MAXSIZE,
- PRINT_SIZE,
- PRINT_VERSION,
- QUOTED,
- SEPARATE_OUTPUT,
- SHADOW,
- SINGLE_QUOTED,
- SLEEP,
- STDERR,
- STDOUT,
- TAB_LEN,
- THEME,
- TIME_FORMAT,
- TITLE,
- TRIM,
- VERSION,
- /* Dialogs */
- CHECKLIST,
- DATEBOX,
- FORM,
- GAUGE,
- INFOBOX,
- INPUTBOX,
- MENU,
- MIXEDFORM,
- MIXEDGAUGE,
- MSGBOX,
- PASSWORDBOX,
- PASSWORDFORM,
- PAUSE,
- RADIOLIST,
- RANGEBOX,
- TEXTBOX,
- TIMEBOX,
- TREEVIEW,
- YESNO
-};
-
-/* Menus options */
-static bool item_prefix_opt, item_bottomdesc_opt, item_output_sepnl_opt;
-static bool item_singlequote_opt, list_items_on_opt, item_tag_help_opt;
-static bool item_always_quote_opt, item_depth_opt;
-static char *item_output_sep_opt, *item_default_opt;
-/* Date and Time options */
-static char *date_fmt_opt, *time_fmt_opt;
-/* Forms options */
-static int unsigned max_input_form_opt;
-/* General options */
-static int output_fd_opt;
-
-static void
-custom_text(bool cr_wrap, bool no_collapse, bool no_nl_expand, bool trim,
- char *text, char *buf);
-
-static void sigint_handler(int sig);
-
-/* Dialogs */
-#define BUILDER_ARGS struct bsddialog_conf conf, char* text, int rows, \
- int cols, int argc, char **argv, char *errbuf
-static int checklist_builder(BUILDER_ARGS);
-static int datebox_builder(BUILDER_ARGS);
-static int form_builder(BUILDER_ARGS);
-static int gauge_builder(BUILDER_ARGS);
-static int infobox_builder(BUILDER_ARGS);
-static int inputbox_builder(BUILDER_ARGS);
-static int menu_builder(BUILDER_ARGS);
-static int mixedform_builder(BUILDER_ARGS);
-static int mixedgauge_builder(BUILDER_ARGS);
-static int msgbox_builder(BUILDER_ARGS);
-static int passwordbox_builder(BUILDER_ARGS);
-static int passwordform_builder(BUILDER_ARGS);
-static int pause_builder(BUILDER_ARGS);
-static int radiolist_builder(BUILDER_ARGS);
-static int rangebox_builder(BUILDER_ARGS);
-static int textbox_builder(BUILDER_ARGS);
-static int timebox_builder(BUILDER_ARGS);
-static int treeview_builder(BUILDER_ARGS);
-static int yesno_builder(BUILDER_ARGS);
-
-static void usage(void)
-{
- printf("usage: bsddialog --help\n");
- printf(" bsddialog --version\n");
- printf(" bsddialog [--<common-opts>] --<dialog> <text> <rows> "
- "<cols> [--<dialog-opts>]\n");
- printf("\n");
-
- printf("Common Options:\n");
- printf("--ascii-lines, --backtitle <backtitle>, --begin-x <x>, "
- "--begin-y <y>, --cancel-label <label>, --clear, --colors, "
- "--cr-wrap, --date-format <format>, --defaultno, "
- "--default-button <label>, --default-no, --default-item <name>, "
- "--disable-esc, --esc-cancelvalue, --exit-label <label>, "
- "--extra-button, --extra-label <label>, "
- "--generic-button1 <label>, --generic-button2 <label>, --help, "
- "--help-button, --help-label <label>, --help-status, --help-tags, "
- "--hfile <filename>, --hline <string>, --hmsg <string>, --ignore, "
- "--insecure, --item-depth, --item-help, --items-prefix, "
- "--max-input <size>, --no-cancel, --nocancel, --no-collapse, "
- "--no-items, --no-label <label>, --no-lines, --no-nl-expand, "
- "--no-ok, --nook, --no-shadow, --no-tags, --ok-label <label>, "
- "--output-fd <fd>, --output-separator <sep>, --print-maxsize, "
- "--print-size, --print-version, --quoted, --separate-output, "
- "--separator <sep>, --shadow, --single-quoted, --sleep <secs>, "
- "--stderr, --stdout, --tab-len <spaces>, "
- "--theme <blackwhite|bsddialog|flat|dialog>, "
- "--time-format <format>, --title <title>, --trim, --version, "
- "--yes-label <label>.\n");
- printf("\n");
-
- printf("Dialogs:\n");
- printf("--checklist <text> <rows> <cols> <menurows> [<name> <desc> "
- "<on|off>] ...\n");
- printf("--datebox <text> <rows> <cols> [<yy> <mm> <dd>]\n");
- printf("--form <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxvaluelen>] "
- "...\n");
- printf("--gauge <text> <rows> <cols> [<perc>]\n");
- printf("--infobox <text> <rows> <cols>\n");
- printf("--inputbox <text> <rows> <cols> [init]\n");
- printf("--menu <text> <rows> <cols> <menurows> [<name> <desc>] ...\n");
- printf("--mixedform <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxvaluelen> "
- "<0|1|2>] ...\n");
- printf("--mixedgauge <text> <rows> <cols> <mainperc> [<minilabel> "
- "<miniperc>] ...\n");
- printf("--msgbox <text> <rows> <cols>\n");
- printf("--passwordbox <text> <rows> <cols> [init]\n");
- printf("--passwordform <text> <rows> <cols> <formrows> [<label> "
- "<ylabel> <xlabel> <init> <yfield> <xfield> <fieldlen> "
- "<maxvaluelen>] ...\n");
- printf("--pause <text> <rows> <cols> <secs>\n");
- printf("--radiolist <text> <rows> <cols> <menurows> [<name> <desc> "
- "<on|off>] ...\n");
- printf("--rangebox <text> <rows> <cols> <min> <max> [<init>]\n");
- printf("--textbox <file> <rows> <cols>\n");
- printf("--timebox <text> <rows> <cols> [<hh> <mm> <ss>]\n");
- printf("--treeview <text> <rows> <cols> <menurows> [<depth> <name> "
- "<desc> <on|off>] ...\n");
- printf("--yesno <text> <rows> <cols>\n");
- printf("\n");
-
- printf("See 'man 1 bsddialog' for more information.\n");
-}
-
-int main(int argc, char *argv[argc])
-{
- bool cr_wrap_opt, no_collapse_opt, no_nl_expand_opt, trim_opt;
- bool esc_cancelvalue_opt, ignore_opt, print_maxsize_opt;;
- int input, rows, cols, output, getH, getW;
- int (*dialogbuilder)(BUILDER_ARGS) = NULL;
- enum bsddialog_default_theme theme_opt;
- char *text, *backtitle_opt;
- char errorbuilder[1024];
- struct winsize ws;
- struct bsddialog_conf conf;
-
- setlocale(LC_ALL, "");
-
- bsddialog_initconf(&conf);
- conf.key.enable_esc = true;
- conf.menu.on_without_ok = true;
- conf.form.value_without_ok = true;
- conf.form.enable_wchar = true;
-
- backtitle_opt = NULL;
- theme_opt = BSDDIALOG_THEME_FLAT;
- output_fd_opt = STDERR_FILENO;
- print_maxsize_opt = false;
- ignore_opt = false;
- cr_wrap_opt = no_collapse_opt = no_nl_expand_opt = trim_opt = false;
- esc_cancelvalue_opt = false;
- errorbuilder[0] = '\0';
-
- item_output_sepnl_opt = item_singlequote_opt = false;
- item_prefix_opt = item_bottomdesc_opt = item_depth_opt = false;
- list_items_on_opt = item_tag_help_opt = false;
- item_always_quote_opt = false;
- item_output_sep_opt = NULL;
- item_default_opt = NULL;
-
- date_fmt_opt = time_fmt_opt = NULL;
-
- max_input_form_opt = 0;
-
- /* options descriptor */
- struct option longopts[] = {
- /* common options */
- {"ascii-lines", no_argument, NULL, ASCII_LINES},
- {"backtitle", required_argument, NULL, BACKTITLE},
- {"begin-x", required_argument, NULL, BEGIN_X},
- {"begin-y", required_argument, NULL, BEGIN_Y},
- {"cancel-label", required_argument, NULL, CANCEL_LABEL},
- {"clear", no_argument, NULL, CLEAR},
- {"colors", no_argument, NULL, COLORS},
- {"cr-wrap", no_argument, NULL, CR_WRAP},
- {"date-format", required_argument, NULL, DATE_FORMAT},
- {"defaultno", no_argument, NULL, DEFAULT_NO},
- {"default-button", required_argument, NULL, DEFAULT_BUTTON},
- {"default-item", required_argument, NULL, DEFAULT_ITEM},
- {"default-no", no_argument, NULL, DEFAULT_NO},
- {"disable-esc", no_argument, NULL, DISABLE_ESC},
- {"esc-cancelvalue", no_argument, NULL, ESC_CANCELVALUE},
- {"exit-label", required_argument, NULL, EXIT_LABEL},
- {"extra-button", no_argument, NULL, EXTRA_BUTTON},
- {"extra-label", required_argument, NULL, EXTRA_LABEL},
- {"generic-button1", required_argument, NULL, GENERIC_BUTTON1},
- {"generic-button2", required_argument, NULL, GENERIC_BUTTON2},
- {"help", no_argument, NULL, HELP},
- {"help-button", no_argument, NULL, HELP_BUTTON},
- {"help-label", required_argument, NULL, HELP_LABEL},
- {"help-status", no_argument, NULL, HELP_STATUS},
- {"help-tags", no_argument, NULL, HELP_TAGS},
- {"hfile", required_argument, NULL, HFILE},
- {"hline", required_argument, NULL, HLINE},
- {"hmsg", required_argument, NULL, HMSG},
- {"ignore", no_argument, NULL, IGNORE},
- {"insecure", no_argument, NULL, INSECURE},
- {"item-depth", no_argument, NULL, ITEM_DEPTH},
- {"item-help", no_argument, NULL, ITEM_HELP},
- {"item-prefix", no_argument, NULL, ITEM_PREFIX},
- {"max-input", required_argument, NULL, MAX_INPUT},
- {"no-cancel", no_argument, NULL, NO_CANCEL},
- {"nocancel", no_argument, NULL, NO_CANCEL},
- {"no-collapse", no_argument, NULL, NO_COLLAPSE},
- {"no-items", no_argument, NULL, NO_ITEMS},
- {"no-label", required_argument, NULL, CANCEL_LABEL},
- {"no-lines", no_argument, NULL, NO_LINES},
- {"no-nl-expand", no_argument, NULL, NO_NL_EXPAND},
- {"no-ok", no_argument, NULL, NO_OK},
- {"nook ", no_argument, NULL, NO_OK},
- {"no-shadow", no_argument, NULL, NO_SHADOW},
- {"no-tags", no_argument, NULL, NO_TAGS},
- {"ok-label", required_argument, NULL, OK_LABEL},
- {"output-fd", required_argument, NULL, OUTPUT_FD},
- {"output-separator", required_argument, NULL, OUTPUT_SEPARATOR},
- {"print-maxsize", no_argument, NULL, PRINT_MAXSIZE},
- {"print-size", no_argument, NULL, PRINT_SIZE},
- {"print-version", no_argument, NULL, PRINT_VERSION},
- {"quoted", no_argument, NULL, QUOTED},
- {"separate-output", no_argument, NULL, SEPARATE_OUTPUT},
- {"separator", required_argument, NULL, OUTPUT_SEPARATOR},
- {"shadow", no_argument, NULL, SHADOW},
- {"single-quoted", no_argument, NULL, SINGLE_QUOTED},
- {"sleep", required_argument, NULL, SLEEP},
- {"stderr", no_argument, NULL, STDERR},
- {"stdout", no_argument, NULL, STDOUT},
- {"tab-len", required_argument, NULL, TAB_LEN},
- {"theme", required_argument, NULL, THEME},
- {"time-format", required_argument, NULL, TIME_FORMAT},
- {"title", required_argument, NULL, TITLE},
- {"trim", no_argument, NULL, TRIM},
- {"version", no_argument, NULL, VERSION},
- {"yes-label", required_argument, NULL, OK_LABEL},
- /* Dialogs */
- {"checklist", no_argument, NULL, CHECKLIST},
- {"datebox", no_argument, NULL, DATEBOX},
- {"form", no_argument, NULL, FORM},
- {"gauge", no_argument, NULL, GAUGE},
- {"infobox", no_argument, NULL, INFOBOX},
- {"inputbox", no_argument, NULL, INPUTBOX},
- {"menu", no_argument, NULL, MENU},
- {"mixedform", no_argument, NULL, MIXEDFORM},
- {"mixedgauge", no_argument, NULL, MIXEDGAUGE},
- {"msgbox", no_argument, NULL, MSGBOX},
- {"passwordbox", no_argument, NULL, PASSWORDBOX},
- {"passwordform", no_argument, NULL, PASSWORDFORM},
- {"pause", no_argument, NULL, PAUSE},
- {"radiolist", no_argument, NULL, RADIOLIST},
- {"rangebox", no_argument, NULL, RANGEBOX},
- {"textbox", no_argument, NULL, TEXTBOX},
- {"timebox", no_argument, NULL, TIMEBOX},
- {"treeview", no_argument, NULL, TREEVIEW},
- {"yesno", no_argument, NULL, YESNO},
- /* END */
- { NULL, 0, NULL, 0}
- };
-
- while ((input = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
- switch (input) {
- /* Common options */
- case ASCII_LINES:
- conf.ascii_lines = true;
- break;
- case BACKTITLE:
- backtitle_opt = optarg;
- break;
- case BEGIN_X:
- conf.x = (int)strtol(optarg, NULL, 10);
- if (conf.x < BSDDIALOG_CENTER) {
- printf("Error: --begin-x %d < %d",
- conf.x, BSDDIALOG_CENTER);
- return (255);
- }
- break;
- case BEGIN_Y:
- conf.y = (int)strtol(optarg, NULL, 10);
- if (conf.y < BSDDIALOG_CENTER) {
- printf("Error: --begin-y %d < %d",
- conf.y, BSDDIALOG_CENTER);
- return (255);
- }
- break;
- case CANCEL_LABEL:
- conf.button.cancel_label = optarg;
- break;
- case CLEAR:
- conf.clear = true;
- break;
- case COLORS:
- conf.text.highlight = true;
- break;
- case CR_WRAP:
- cr_wrap_opt = true;
- break;
- case DATE_FORMAT:
- date_fmt_opt = optarg;
- break;
- case DEFAULT_BUTTON:
- conf.button.default_label = optarg;
- break;
- case DEFAULT_ITEM:
- item_default_opt = optarg;
- break;
- case DEFAULT_NO:
- conf.button.default_cancel = true;
- break;
- case DISABLE_ESC:
- conf.key.enable_esc = false;
- break;
- case ESC_CANCELVALUE:
- esc_cancelvalue_opt = true;
- break;
- case EXIT_LABEL:
- conf.button.ok_label = optarg;
- break;
- case EXTRA_BUTTON:
- conf.button.with_extra = true;
- break;
- case EXTRA_LABEL:
- conf.button.extra_label = optarg;
- break;
- case GENERIC_BUTTON1:
- conf.button.generic1_label = optarg;
- break;
- case GENERIC_BUTTON2:
- conf.button.generic2_label = optarg;
- break;
- case HELP:
- usage();
- return (BSDDIALOG_OK);
- case HELP_BUTTON:
- conf.button.with_help = true;
- break;
- case HELP_LABEL:
- conf.button.help_label = optarg;
- break;
- case HELP_STATUS:
- list_items_on_opt = true;
- break;
- case HELP_TAGS:
- item_tag_help_opt = true;
- break;
- case HFILE:
- conf.key.f1_file = optarg;
- break;
- case HLINE:
- if (strlen(optarg) > 0)
- conf.bottomtitle = optarg;
- break;
- case HMSG:
- conf.key.f1_message = optarg;
- break;
- case IGNORE:
- ignore_opt = true;
- break;
- case INSECURE:
- conf.form.securech = '*';
- break;
- case ITEM_DEPTH:
- item_depth_opt = true;
- break;
- case ITEM_HELP:
- item_bottomdesc_opt = true;
- break;
- case ITEM_PREFIX:
- item_prefix_opt = true;
- break;
- case MAX_INPUT:
- max_input_form_opt = (u_int)strtoul(optarg, NULL, 10);
- break;
- case NO_ITEMS:
- conf.menu.no_desc = true;
- break;
- case NO_CANCEL:
- conf.button.without_cancel = true;
- break;
- case NO_COLLAPSE:
- no_collapse_opt = true;
- break;
- case NO_LINES:
- conf.no_lines = true;
- break;
- case NO_NL_EXPAND:
- no_nl_expand_opt = true;
- break;
- case NO_OK:
- conf.button.without_ok = true;
- break;
- case NO_TAGS:
- conf.menu.no_name = true;
- break;
- case NO_SHADOW:
- conf.shadow = false;
- break;
- case OK_LABEL:
- conf.button.ok_label = optarg;
- break;
- case OUTPUT_FD:
- output_fd_opt = (int)strtol(optarg, NULL, 10);
- break;
- case OUTPUT_SEPARATOR:
- item_output_sep_opt = optarg;
- break;
- case QUOTED:
- item_always_quote_opt = true;
- break;
- case PRINT_MAXSIZE:
- print_maxsize_opt = true;
- break;
- case PRINT_SIZE:
- conf.get_height = &getH;
- conf.get_width = &getW;
- break;
- case PRINT_VERSION:
- printf("bsddialog version %s\n", BSDDIALOG_VERSION);
- break;
- case SEPARATE_OUTPUT:
- item_output_sepnl_opt = true;
- break;
- case SHADOW:
- conf.shadow = true;
- break;
- case SINGLE_QUOTED:
- item_singlequote_opt = true;
- break;
- case SLEEP:
- conf.sleep = (u_int)strtoul(optarg, NULL, 10);
- break;
- case STDERR:
- output_fd_opt = STDERR_FILENO;
- break;
- case STDOUT:
- output_fd_opt = STDOUT_FILENO;
- break;
- case TAB_LEN:
- conf.text.tablen = (u_int)strtoul(optarg, NULL, 10);
- break;
- case THEME:
- if (strcasecmp(optarg, "bsddialog") == 0)
- theme_opt = BSDDIALOG_THEME_BSDDIALOG;
- else if (strcasecmp(optarg, "blackwhite") == 0)
- theme_opt = BSDDIALOG_THEME_BLACKWHITE;
- else if (strcasecmp(optarg, "flat") == 0)
- theme_opt = BSDDIALOG_THEME_FLAT;
- else if (strcasecmp(optarg, "dialog") == 0)
- theme_opt = BSDDIALOG_THEME_DIALOG;
- else {
- printf("Error: unknown theme\n");
- return (255);
- }
- break;
- case TIME_FORMAT:
- time_fmt_opt = optarg;
- break;
- case TITLE:
- conf.title = optarg;
- break;
- case TRIM:
- trim_opt = true;
- break;
- case VERSION:
- printf("bsddialog %s (libbsddialog %s)\n",
- BSDDIALOG_VERSION, LIBBSDDIALOG_VERSION);
- return (BSDDIALOG_OK);
- /* Dialogs */
- case CHECKLIST:
- dialogbuilder = checklist_builder;
- break;
- case DATEBOX:
- dialogbuilder = datebox_builder;
- break;
- case FORM:
- dialogbuilder = form_builder;
- break;
- case GAUGE:
- dialogbuilder = gauge_builder;
- break;
- case INFOBOX:
- dialogbuilder = infobox_builder;
- break;
- case INPUTBOX:
- dialogbuilder = inputbox_builder;
- break;
- case MENU:
- dialogbuilder = menu_builder;
- break;
- case MIXEDFORM:
- dialogbuilder = mixedform_builder;
- break;
- case MIXEDGAUGE:
- dialogbuilder = mixedgauge_builder;
- break;
- case MSGBOX:
- dialogbuilder = msgbox_builder;
- break;
- case PAUSE:
- dialogbuilder = pause_builder;
- break;
- case PASSWORDBOX:
- dialogbuilder = passwordbox_builder;
- break;
- case PASSWORDFORM:
- dialogbuilder = passwordform_builder;
- break;
- case RADIOLIST:
- dialogbuilder = radiolist_builder;
- break;
- case RANGEBOX:
- dialogbuilder = rangebox_builder;
- break;
- case TEXTBOX:
- dialogbuilder = textbox_builder;
- break;
- case TIMEBOX:
- dialogbuilder = timebox_builder;
- break;
- case TREEVIEW:
- dialogbuilder = treeview_builder;
- break;
- case YESNO:
- dialogbuilder = yesno_builder;
- break;
- /* Error */
- default:
- if (ignore_opt == true)
- break;
- usage();
- return (255);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (print_maxsize_opt) {
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
- dprintf(output_fd_opt, "Screen size: (%d - %d)\n",
- ws.ws_row, ws.ws_col);
- if (argc == 0)
- return (BSDDIALOG_OK);
- }
-
- if (argc < 3) {
- usage();
- return (255);
- }
- if (dialogbuilder == textbox_builder)
- text = argv[0];
- else {
- if ((text = malloc(strlen(argv[0]) + 1)) == NULL) {
- printf("Error: cannot allocate memory for text\n");
- return (255);
- }
- custom_text(cr_wrap_opt, no_collapse_opt, no_nl_expand_opt,
- trim_opt, argv[0], text);
- }
- rows = (int)strtol(argv[1], NULL, 10);
- cols = (int)strtol(argv[2], NULL, 10);
- argc -= 3;
- argv += 3;
-
- /* bsddialog terminal mode */
- if (bsddialog_init() != 0) {
- printf("Error: %s\n", bsddialog_geterror());
- return (BSDDIALOG_ERROR);
- }
-
- signal(SIGINT, sigint_handler);
-
- if (theme_opt != BSDDIALOG_THEME_FLAT)
- bsddialog_set_default_theme(theme_opt);
-
- if (backtitle_opt != NULL)
- bsddialog_backtitle(&conf, backtitle_opt);
-
- errorbuilder[0] = '\0';
- output = BSDDIALOG_OK;
- if (dialogbuilder != NULL)
- output = dialogbuilder(conf, text, rows, cols, argc, argv,
- errorbuilder);
-
- if (dialogbuilder != textbox_builder)
- free(text);
-
- bsddialog_end();
- /* end bsddialog terminal mode */
-
- if (output == BSDDIALOG_ERROR) {
- if (errorbuilder[0] != '\0')
- printf("Error: %s\n", errorbuilder);
- else
- printf("Error: %s\n", bsddialog_geterror());
- return (255);
- }
-
- if (conf.get_height != NULL && conf.get_width != NULL)
- dprintf(output_fd_opt, "Dialog size: (%d - %d)\n",
- *conf.get_height, *conf.get_width);
-
- if (output == BSDDIALOG_ESC && esc_cancelvalue_opt)
- output = BSDDIALOG_CANCEL;
-
- return (output);
-}
-
-void sigint_handler(int sig)
-{
- bsddialog_end();
-
- exit(255);
-}
-
-void
-custom_text(bool cr_wrap, bool no_collapse, bool no_nl_expand, bool trim,
- char *text, char *buf)
-{
- int i, j;
-
- i = j = 0;
- while (text[i] != '\0') {
- switch (text[i]) {
- case '\\':
- buf[j] = '\\';
- switch (text[i+1]) {
- case '\\':
- i++;
- break;
- case 'n':
- if (no_nl_expand) {
- j++;
- buf[j] = 'n';
- } else
- buf[j] = '\n';
- i++;
- break;
- case 't':
- if (no_collapse) {
- j++;
- buf[j] = 't';
- } else
- buf[j] = '\t';
- i++;
- break;
- }
- break;
- case '\n':
- buf[j] = cr_wrap ? ' ' : '\n';
- break;
- case '\t':
- buf[j] = no_collapse ? '\t' : ' ';
- break;
- default:
- buf[j] = text[i];
- }
- i++;
- j += (buf[j] == ' ' && trim && j > 0 && buf[j-1] == ' ') ?
- 0 : 1;
- }
- buf[j] = '\0';
-}
-
-/* Dialogs */
-int gauge_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int perc;
-
- if (argc > 0) {
- perc = argc > 0 ? (u_int)strtoul(argv[0], NULL, 10) : 0;
- perc = perc > 100 ? 100 : perc;
- }
- else
- perc = 0;
-
- output = bsddialog_gauge(&conf, text, rows, cols, perc, STDIN_FILENO,
- "XXX");
-
- return (output);
-}
-
-int infobox_builder(BUILDER_ARGS)
-{
- int output;
-
- output = bsddialog_infobox(&conf, text, rows, cols);
-
- return (output);
-}
-
-int mixedgauge_builder(BUILDER_ARGS)
-{
- int output, *minipercs;
- unsigned int i, mainperc, nminibars;
- const char **minilabels;
-
- if (argc < 1 || (((argc-1) % 2) != 0) ) {
- strcpy(errbuf, "bad --mixedgauge arguments\n");
- return (BSDDIALOG_ERROR);
- }
-
- mainperc = (u_int)strtoul(argv[0], NULL, 10);
- mainperc = mainperc > 100 ? 100 : mainperc;
- argc--;
- argv++;
-
- nminibars = argc / 2;
- if ((minilabels = calloc(nminibars, sizeof(char*))) == NULL) {
- strcpy(errbuf, "Cannot allocate memory for minilabels\n");
- return BSDDIALOG_ERROR;
- }
- if ((minipercs = calloc(nminibars, sizeof(int))) == NULL) {
- strcpy(errbuf, "Cannot allocate memory for minipercs\n");
- return BSDDIALOG_ERROR;
- }
-
- for (i = 0; i < nminibars; i++) {
- minilabels[i] = argv[i * 2];
- minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
- }
-
- output = bsddialog_mixedgauge(&conf, text, rows, cols, mainperc,
- nminibars, minilabels, minipercs);
-
- return (output);
-}
-
-int msgbox_builder(BUILDER_ARGS)
-{
- int output;
-
- output = bsddialog_msgbox(&conf, text, rows, cols);
-
- return (output);
-}
-
-int pause_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int secs;
-
- if (argc < 1) {
- strcpy(errbuf, "missing <seconds> for --pause\n");
- return (BSDDIALOG_ERROR);
- }
-
- secs = (u_int)strtoul(argv[0], NULL, 10);
- output = bsddialog_pause(&conf, text, rows, cols, secs);
-
- return (output);
-}
-
-int rangebox_builder(BUILDER_ARGS)
-{
- int output, min, max, value;
-
- if (argc < 2) {
- strcpy(errbuf, "usage --rangebox <text> <rows> <cols> "
- "<min> <max> [<init>]\n");
- return (BSDDIALOG_ERROR);
- }
-
- min = (int)strtol(argv[0], NULL, 10);
- max = (int)strtol(argv[1], NULL, 10);
-
- if (argc > 2) {
- value = (int)strtol(argv[2], NULL, 10);
- value = value < min ? min : value;
- value = value > max ? max : value;
- }
- else
- value = min;
-
- output = bsddialog_rangebox(&conf, text, rows, cols, min, max, &value);
-
- dprintf(output_fd_opt, "%d", value);
-
- return (output);
-}
-
-int textbox_builder(BUILDER_ARGS)
-{
- int output;
-
- output = bsddialog_textbox(&conf, text, rows, cols);
-
- return (output);
-}
-
-int yesno_builder(BUILDER_ARGS)
-{
- int output;
-
- output = bsddialog_yesno(&conf, text, rows, cols);
-
- return (output);
-}
-
-/* DATE and TIME */
-int datebox_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int yy, mm, dd;
- time_t cal;
- struct tm *localtm;
- char stringdate[1024];
-
- time(&cal);
- localtm = localtime(&cal);
- yy = localtm->tm_year + 1900;
- mm = localtm->tm_mon + 1;
- dd = localtm->tm_mday;
-
- if (argc == 3) {
- yy = (u_int)strtoul(argv[0], NULL, 10);
- mm = (u_int)strtoul(argv[1], NULL, 10);
- dd = (u_int)strtoul(argv[2], NULL, 10);
- }
-
- output = bsddialog_datebox(&conf, text, rows, cols, &yy, &mm, &dd);
- if (output != BSDDIALOG_OK)
- return (output);
-
- if (date_fmt_opt == NULL) {
- dprintf(output_fd_opt, "%u/%u/%u", yy, mm, dd);
- } else {
- time(&cal);
- localtm = localtime(&cal);
- localtm->tm_year = yy - 1900;
- localtm->tm_mon = mm - 1;
- localtm->tm_mday = dd;
- strftime(stringdate, 1024, date_fmt_opt, localtm);
- dprintf(output_fd_opt, "%s", stringdate);
- }
-
- return (output);
-}
-
-int timebox_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int hh, mm, ss;
- time_t clock;
- struct tm *localtm;
- char stringtime[1024];
-
- time(&clock);
- localtm = localtime(&clock);
- hh = localtm->tm_hour;
- mm = localtm->tm_min;
- ss = localtm->tm_sec;
-
- if (argc == 3) {
- hh = (u_int)strtoul(argv[0], NULL, 10);
- mm = (u_int)strtoul(argv[1], NULL, 10);
- ss = (u_int)strtoul(argv[2], NULL, 10);
- }
-
- output = bsddialog_timebox(&conf, text, rows, cols, &hh, &mm, &ss);
- if (output != BSDDIALOG_OK)
- return (output);
-
- if (time_fmt_opt == NULL) {
- dprintf(output_fd_opt, "%u:%u:%u", hh, mm, ss);
- } else {
- time(&clock);
- localtm = localtime(&clock);
- localtm->tm_hour = hh;
- localtm->tm_min = mm;
- localtm->tm_sec = ss;
- strftime(stringtime, 1024, time_fmt_opt, localtm);
- dprintf(output_fd_opt, "%s", stringtime);
- }
-
- return (output);
-}
-
-/* MENU */
-static int
-get_menu_items(char *errbuf, int argc, char **argv, bool setprefix,
- bool setdepth, bool setname, bool setdesc, bool setstatus, bool sethelp,
- unsigned int *nitems, struct bsddialog_menuitem **items, int *focusitem)
-{
- unsigned int i, j, sizeitem;
-
- *focusitem = -1;
-
- sizeitem = 0;
- sizeitem += setprefix ? 1 : 0;
- sizeitem += setdepth ? 1 : 0;
- sizeitem += setname ? 1 : 0;
- sizeitem += setdesc ? 1 : 0;
- sizeitem += setstatus ? 1 : 0;
- sizeitem += sethelp ? 1 : 0;
- if ((argc % sizeitem) != 0) {
- strcpy(errbuf, "bad number of arguments for this menu\n");
- return (BSDDIALOG_ERROR);
- }
- *nitems = argc / sizeitem;
-
- *items = calloc(*nitems, sizeof(struct bsddialog_menuitem));
- if (items == NULL) {
- strcpy(errbuf, "cannot allocate memory menu items\n");
- return (BSDDIALOG_ERROR);
- }
-
- j = 0;
- for (i = 0; i < *nitems; i++) {
- (*items)[i].prefix = setprefix ? argv[j++] : "";
- (*items)[i].depth = setdepth ?
- (u_int)strtoul(argv[j++], NULL, 0) : 0;
- (*items)[i].name = setname ? argv[j++] : "";
- (*items)[i].desc = setdesc ? argv[j++] : "";
- if (setstatus)
- (*items)[i].on = strcmp(argv[j++], "on") == 0 ?
- true : false;
- else
- (*items)[i].on = false;
- (*items)[i].bottomdesc = sethelp ? argv[j++] : "";
-
- if (item_default_opt != NULL && *focusitem == -1)
- if (strcmp((*items)[i].name, item_default_opt) == 0)
- *focusitem = i;
- }
-
- return (BSDDIALOG_OK);
-}
-
-static void
-print_menu_items(int output, int nitems, struct bsddialog_menuitem *items,
- int focusitem)
-{
- bool sep, toquote;
- int i;
- char *sepstr, quotech;
- const char *focusname;
-
- sep = false;
- quotech = item_singlequote_opt ? '\'' : '"';
- sepstr = item_output_sep_opt != NULL ? item_output_sep_opt : " ";
-
- if (output != BSDDIALOG_OK && output != BSDDIALOG_ERROR &&
- focusitem >= 0) {
- focusname = items[focusitem].name;
-
- if (output == BSDDIALOG_HELP) {
- dprintf(output_fd_opt, "HELP ");
-
- if (item_bottomdesc_opt && item_tag_help_opt == false)
- focusname = items[focusitem].bottomdesc;
- }
-
- toquote = item_always_quote_opt ||
- (item_output_sepnl_opt == false &&
- strchr(focusname, ' ') != NULL);
-
- if (toquote)
- dprintf(output_fd_opt, "%c", quotech);
- dprintf(output_fd_opt, "%s", focusname);
- if (toquote)
- dprintf(output_fd_opt, "%c", quotech);
-
- sep = true;
- }
-
- if (output != BSDDIALOG_OK &&
- !(output == BSDDIALOG_HELP && list_items_on_opt))
- return;
-
- for (i = 0; i < nitems; i++) {
- if (items[i].on == false)
- continue;
-
- if (sep == true) {
- dprintf(output_fd_opt, "%s", sepstr);
- if (item_output_sepnl_opt)
- dprintf(output_fd_opt, "\n");
- }
- sep = true;
-
- toquote = item_always_quote_opt ||
- (item_output_sepnl_opt == false &&
- strchr(items[i].name, ' ') != NULL);
-
- if (toquote)
- dprintf(output_fd_opt, "%c", quotech);
- dprintf(output_fd_opt, "%s", items[i].name);
- if (toquote)
- dprintf(output_fd_opt, "%c", quotech);
- }
-}
-
-int checklist_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_opt,
- item_depth_opt, true, true, true, item_bottomdesc_opt, &nitems,
- &items, &focusitem);
- if (output != 0)
- return (output);
-
- output = bsddialog_checklist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem);
-
- free(items);
-
- return (output);
-}
-
-int menu_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_opt,
- item_depth_opt, true, true, false, item_bottomdesc_opt, &nitems,
- &items, &focusitem);
- if (output != 0)
- return (output);
-
- output = bsddialog_menu(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem);
-
- free(items);
-
- return (output);
-}
-
-int radiolist_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_opt,
- item_depth_opt, true, true, true, item_bottomdesc_opt, &nitems,
- &items, &focusitem);
- if (output != 0)
- return (output);
-
- output = bsddialog_radiolist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem);
-
- free(items);
-
- return (output);
-}
-
-int treeview_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_opt,
- true, true, true, true, item_bottomdesc_opt, &nitems, &items,
- &focusitem);
- if (output != 0)
- return (output);
-
- conf.menu.no_name = true;
- conf.menu.align_left = true;
-
- output = bsddialog_radiolist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem);
-
- free(items);
-
- return (output);
-}
-
-/* FORM */
-static int
-alloc_formitems(int nitems, struct bsddialog_formitem **items, char *errbuf)
-{
- *items = calloc(nitems, sizeof(struct bsddialog_formitem));
- if (items == NULL) {
- strcpy(errbuf, "cannot allocate memory for form items\n");
- return (BSDDIALOG_ERROR);
- }
-
- return (BSDDIALOG_OK);
-}
-
-static void
-print_form_items(int output, int nitems, struct bsddialog_formitem *items)
-{
- int i;
-
- if (output == BSDDIALOG_ERROR)
- return;
-
- for (i = 0; i < nitems; i++) {
- dprintf(output_fd_opt, "%ls\n", (wchar_t*)items[i].value);
- free(items[i].value);
- }
-}
-
-int form_builder(BUILDER_ARGS)
-{
- int output, fieldlen, valuelen;
- unsigned int i, j, flags, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- sizeitem = item_bottomdesc_opt ? 9 : 8;
- if (argc < 1 || (argc - 1) % sizeitem != 0) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = (u_int)strtoul(argv[0], NULL, 10);
- flags = 0;
-
- argc--;
- argv++;
-
- nitems = argc / sizeitem;
- if (alloc_formitems(nitems, &items, errbuf) != BSDDIALOG_OK)
- return (BSDDIALOG_ERROR);
- 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);
-
- fieldlen = (int)strtol(argv[j++], NULL, 10);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = (int)strtol(argv[j++], NULL, 10);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
-
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
-
-int inputbox_builder(BUILDER_ARGS)
-{
- int output;
- struct bsddialog_formitem item;
-
- item.label = "";
- item.ylabel = 0;
- item.xlabel = 0;
- item.init = argc > 0 ? argv[0] : "";
- item.yfield = 1;
- item.xfield = 1;
- item.fieldlen = cols > 4 ? cols-4 : 25;
- item.maxvaluelen = max_input_form_opt > 0 ? max_input_form_opt : 2048;
- item.flags = 0;
- item.bottomdesc = "";
-
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
- print_form_items(output, 1, &item);
-
- return (output);
-}
-
-int mixedform_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int i, j, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- sizeitem = item_bottomdesc_opt ? 10 : 9;
- if (argc < 1 || (argc-1) % sizeitem != 0) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = (u_int)strtoul(argv[0], NULL, 10);
-
- argc--;
- argv++;
-
- nitems = argc / sizeitem;
- if (alloc_formitems(nitems, &items, errbuf) != BSDDIALOG_OK)
- return (BSDDIALOG_ERROR);
- 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].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].flags = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
-
-int passwordbox_builder(BUILDER_ARGS)
-{
- int output;
- struct bsddialog_formitem item;
-
- item.label = "";
- item.ylabel = 0;
- item.xlabel = 0;
- item.init = argc > 0 ? argv[0] : "";
- item.yfield = 1;
- item.xfield = 1;
- item.fieldlen = cols > 4 ? cols-4 : 25;
- item.maxvaluelen = max_input_form_opt > 0 ? max_input_form_opt : 2048;
- item.flags = BSDDIALOG_FIELDHIDDEN;
- item.bottomdesc = "";
-
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
- print_form_items(output, 1, &item);
-
- return (output);
-}
-
-int passwordform_builder(BUILDER_ARGS)
-{
- int output, fieldlen, valuelen;
- unsigned int i, j, flags, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- sizeitem = item_bottomdesc_opt ? 9 : 8;
- if (argc < 1 || (argc - 1) % sizeitem != 0) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = (u_int)strtoul(argv[0], NULL, 10);
- flags = BSDDIALOG_FIELDHIDDEN;
-
- argc--;
- argv++;
-
- nitems = argc / sizeitem;
- if (alloc_formitems(nitems, &items, errbuf) != BSDDIALOG_OK)
- return (BSDDIALOG_ERROR);
- 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);
-
- fieldlen = (int)strtol(argv[j++], NULL, 10);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = (int)strtol(argv[j++], NULL, 10);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
-
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
diff --git a/contrib/bsddialog/examples_library/calendar.c b/contrib/bsddialog/examples_library/calendar.c
new file mode 100644
index 000000000000..5899fc4986fd
--- /dev/null
+++ b/contrib/bsddialog/examples_library/calendar.c
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2022 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bsddialog.h>
+#include <stdio.h>
+#include <time.h>
+
+int main()
+{
+ int output;
+ unsigned int yy, mm, dd;
+ struct bsddialog_conf conf;
+ time_t cal;
+ struct tm *localtm;
+
+ time(&cal);
+ localtm = localtime(&cal);
+ yy = localtm->tm_year + 1900;
+ mm = localtm->tm_mon + 1;
+ dd = localtm->tm_mday;
+
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
+ bsddialog_initconf(&conf);
+ conf.title = "calendar";
+ output = bsddialog_calendar(&conf, "Example", 18, 40, &yy, &mm, &dd);
+ bsddialog_end();
+ if (output == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
+
+ printf("Date: %u/%u/%u\n", yy, mm, dd);
+
+ return (0);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/checklist.c b/contrib/bsddialog/examples_library/checklist.c
index 6d860b91a076..a2b178d14270 100644
--- a/contrib/bsddialog/examples_library/checklist.c
+++ b/contrib/bsddialog/examples_library/checklist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,27 +27,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "checklist";
output = bsddialog_checklist(&conf, "Example", 15, 30, 5, 5, items,
NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Checklist:\n");
for (i = 0; i < 5; i++)
printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/compile b/contrib/bsddialog/examples_library/compile
index 3c3961d06baf..1a68313090f6 100755
--- a/contrib/bsddialog/examples_library/compile
+++ b/contrib/bsddialog/examples_library/compile
@@ -8,12 +8,16 @@
# worldwide. This software is distributed without any warranty, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>.
+set -x
+
libpath=../lib
examples="menu checklist radiolist mixedlist theme infobox yesno msgbox \
- datebox form formw timebox rangebox pause"
+datebox form timebox rangebox pause calendar gauge mixedgauge textbox"
+
+rm -f $examples
for e in $examples
do
- cc -g -Wall -Wextra -I$libpath ${e}.c -o $e -L$libpath -lbsddialog \
- -Wl,-rpath=$libpath
+ cc -g -Wall -Wextra -I$libpath ${e}.c -o $e \
+ -Wl,-rpath=$libpath -L$libpath -lbsddialog
done
diff --git a/contrib/bsddialog/examples_library/datebox.c b/contrib/bsddialog/examples_library/datebox.c
index a3c8946b7f79..e0741319d388 100644
--- a/contrib/bsddialog/examples_library/datebox.c
+++ b/contrib/bsddialog/examples_library/datebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
int main()
@@ -31,27 +30,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "datebox";
- output = bsddialog_datebox(&conf,
- "TAB / RIGHT / LEFT to move,\nUP / DOWN to select time", 10, 35,
- &yy, &mm, &dd);
-
+ output = bsddialog_datebox(&conf, "Example", 9, 35, &yy, &mm, &dd);
bsddialog_end();
-
- switch (output) {
- case BSDDIALOG_OK:
- printf("Date: %u/%u/%u", yy, mm, dd);
- break;
- case BSDDIALOG_CANCEL:
- printf("Cancel");
- break;
- case BSDDIALOG_ERROR:
- printf("Error: %s", bsddialog_geterror());
- break;
+ if (output == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
}
- printf("\n");
+ printf("Date: %u/%u/%u\n", yy, mm, dd);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/form.c b/contrib/bsddialog/examples_library/form.c
index 0256975f2023..4c6336610852 100644
--- a/contrib/bsddialog/examples_library/form.c
+++ b/contrib/bsddialog/examples_library/form.c
@@ -9,9 +9,9 @@
*/
#include <bsddialog.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#define H BSDDIALOG_FIELDHIDDEN
#define RO BSDDIALOG_FIELDREADONLY
@@ -21,37 +21,32 @@ int main()
int i, output;
struct bsddialog_conf conf;
struct bsddialog_formitem items[3] = {
- {"Input:", 1, 1, "value", 1, 11, 30, 50, NULL, 0, "desc 1"},
- {"Input:", 2, 1, "read only", 2, 11, 30, 50, NULL, RO, "desc 2"},
- {"Password:", 3, 1, "", 3, 11, 30, 50, NULL, H, "desc 3"}
+ {"Input:", 0, 0, "value", 0, 10, 30, 50, NULL, 0, "desc 1"},
+ {"Input:", 1, 0, "read only", 1, 10, 30, 50, NULL, RO, "desc 2"},
+ {"Password:", 2, 0, "", 2, 10, 30, 50, NULL, H, "desc 3"}
};
+ /* Optional, unless for unicode/multi-column characters */
+ setlocale(LC_ALL, "");
+
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "form";
conf.form.securech = '*';
- output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items);
-
+ output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items, NULL);
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
for (i = 0; i < 3; i++) {
printf("%s \"%s\"\n", items[i].label, items[i].value);
free(items[i].value);
}
- return (output);
-} \ No newline at end of file
+ return (0);
+}
diff --git a/contrib/bsddialog/examples_library/formw.c b/contrib/bsddialog/examples_library/formw.c
deleted file mode 100644
index edbeec98f2a3..000000000000
--- a/contrib/bsddialog/examples_library/formw.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-
- * SPDX-License-Identifier: CC0-1.0
- *
- * Written in 2022 by Alfonso Sabato Siciliano.
- * To the extent possible under law, the author has dedicated all copyright
- * and related and neighboring rights to this software to the public domain
- * worldwide. This software is distributed without any warranty, see:
- * <http://creativecommons.org/publicdomain/zero/1.0/>.
- */
-
-#include <bsddialog.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define H BSDDIALOG_FIELDHIDDEN
-#define RO BSDDIALOG_FIELDREADONLY
-
-int main()
-{
- int i, output;
- struct bsddialog_conf conf;
- struct bsddialog_formitem items[3] = {
- {"Input:", 1, 1, "value", 1, 11, 30, 50, NULL, 0, "desc 1"},
- {"Input:", 2, 1, "read only", 2, 11, 30, 50, NULL, RO, "desc 2"},
- {"Password:", 3, 1, "", 3, 11, 30, 50, NULL, H, "desc 3"}
- };
-
- setlocale(LC_ALL, "");
-
- if (bsddialog_init() == BSDDIALOG_ERROR) {
- printf("Error: %s\n", bsddialog_geterror());
- return (1);
- }
-
- bsddialog_initconf(&conf);
- conf.title = "form";
- conf.form.securech = '*';
- conf.form.enable_wchar = true;
- output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items);
-
- bsddialog_end();
-
- if (output == BSDDIALOG_ERROR) {
- printf("Error: %s", bsddialog_geterror());
- return (1);
- }
-
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
- for (i = 0; i < 3; i++) {
- printf("%s \"%ls\"\n", items[i].label, (wchar_t*)items[i].value);
- free(items[i].value);
- }
-
- return (output);
-} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/gauge.c b/contrib/bsddialog/examples_library/gauge.c
new file mode 100644
index 000000000000..8ed1a8f57664
--- /dev/null
+++ b/contrib/bsddialog/examples_library/gauge.c
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2023 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bsddialog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void sender(int fd)
+{
+ int i;
+
+ for (i = 1; i <= 10; i++) {
+ sleep(1);
+ dprintf(fd, "SEP\n");
+ dprintf(fd, "%d\n", i * 10);
+ dprintf(fd, "In Progress... [%d / 10]\n", i);
+ dprintf(fd, "SEP\n");
+ }
+ sleep(1);
+ dprintf(fd, "EOF\n");
+}
+
+int main()
+{
+ int rv, fd[2];
+ struct bsddialog_conf conf;
+
+ /* add checks and sync */
+ pipe(fd);
+ if (fork() == 0) {
+ close(fd[0]);
+ sender(fd[1]);
+ exit (0);
+ }
+ close(fd[1]);
+
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
+ bsddialog_initconf(&conf);
+ conf.title = "gauge";
+ rv = bsddialog_gauge(&conf, "Example", 7, 30, 0, fd[0], "SEP", "EOF");
+ bsddialog_end();
+ if (rv == BSDDIALOG_ERROR)
+ printf("Error: %s\n", bsddialog_geterror());
+
+ return (0);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/infobox.c b/contrib/bsddialog/examples_library/infobox.c
index 7334cd7536bf..bbd7f665d5a6 100644
--- a/contrib/bsddialog/examples_library/infobox.c
+++ b/contrib/bsddialog/examples_library/infobox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,18 +20,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "infobox";
conf.sleep = 3;
output = bsddialog_infobox(&conf, "Example\n(3 seconds)", 7, 20);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/menu.c b/contrib/bsddialog/examples_library/menu.c
index 044e0030a010..5c4941f6d5de 100644
--- a/contrib/bsddialog/examples_library/menu.c
+++ b/contrib/bsddialog/examples_library/menu.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,26 +27,18 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "menu";
output = bsddialog_menu(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Menu:\n");
for (i = 0; i < 5; i++)
printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/mixedgauge.c b/contrib/bsddialog/examples_library/mixedgauge.c
new file mode 100644
index 000000000000..e74bb3512a9a
--- /dev/null
+++ b/contrib/bsddialog/examples_library/mixedgauge.c
@@ -0,0 +1,79 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2023 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bsddialog.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define NMINIBAR 13
+
+static const char *minilabels[NMINIBAR] = {
+ "Label 1",
+ "Label 2",
+ "Label 3",
+ "Label 4",
+ "Label 5",
+ "Label 6",
+ "Label 7",
+ "Label 8",
+ "Label 9",
+ "Label 10",
+ "Label 11",
+ "Label X",
+ "Label Y",
+};
+
+static int minipercs[NMINIBAR] = {
+ BSDDIALOG_MG_SUCCEEDED,
+ BSDDIALOG_MG_FAILED,
+ BSDDIALOG_MG_PASSED,
+ BSDDIALOG_MG_COMPLETED,
+ BSDDIALOG_MG_CHECKED,
+ BSDDIALOG_MG_DONE,
+ BSDDIALOG_MG_SKIPPED,
+ BSDDIALOG_MG_INPROGRESS,
+ BSDDIALOG_MG_BLANK,
+ BSDDIALOG_MG_NA,
+ BSDDIALOG_MG_PENDING,
+ 67,
+ 0,
+};
+
+static void exit_error()
+{
+ if (bsddialog_inmode())
+ bsddialog_end();
+ printf("Error: %s\n", bsddialog_geterror());
+ exit (1);
+}
+
+int main()
+{
+ int retval, i;
+ struct bsddialog_conf conf;
+
+ if (bsddialog_init() == BSDDIALOG_ERROR)
+ exit_error();
+ bsddialog_initconf(&conf);
+ conf.title = "mixedgauge";
+ for (i = 0; i <= 10; i++) {
+ minipercs[11] += 3;
+ minipercs[12] = i * 10;
+ retval= bsddialog_mixedgauge(&conf, "Example", 20, 40,
+ 50 + i * 5, NMINIBAR, minilabels, minipercs);
+ if (retval == BSDDIALOG_ERROR)
+ exit_error();
+ sleep(1);
+ }
+ bsddialog_end();
+
+ return (0);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/mixedlist.c b/contrib/bsddialog/examples_library/mixedlist.c
index 30198d20a155..6d286996931b 100644
--- a/contrib/bsddialog/examples_library/mixedlist.c
+++ b/contrib/bsddialog/examples_library/mixedlist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -40,34 +39,26 @@ int main()
{ "", false, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
};
struct bsddialog_menugroup group[4] = {
- { BSDDIALOG_SEPARATOR, 1, sep1 },
- { BSDDIALOG_CHECKLIST, 5, check },
- { BSDDIALOG_SEPARATOR, 2, sep2 },
- { BSDDIALOG_RADIOLIST, 5, radio }
+ { BSDDIALOG_SEPARATOR, 1, sep1, 0 },
+ { BSDDIALOG_CHECKLIST, 5, check, 0 },
+ { BSDDIALOG_SEPARATOR, 2, sep2, 0 },
+ { BSDDIALOG_RADIOLIST, 5, radio, 0 }
};
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "mixedlist";
output = bsddialog_mixedlist(&conf, "Example", 20, 0, 13, 4, group,
NULL, NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Mixedlist:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < group[i].nitems; j++) {
@@ -83,5 +74,5 @@ int main()
}
}
- return (output);
-} \ No newline at end of file
+ return (0);
+}
diff --git a/contrib/bsddialog/examples_library/msgbox.c b/contrib/bsddialog/examples_library/msgbox.c
index 7d14073143ca..988e2976ee8e 100644
--- a/contrib/bsddialog/examples_library/msgbox.c
+++ b/contrib/bsddialog/examples_library/msgbox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,21 +20,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "msgbox";
output = bsddialog_msgbox(&conf, "Example", 7, 20);
-
bsddialog_end();
switch (output) {
case BSDDIALOG_ERROR:
printf("Error %s\n", bsddialog_geterror());
- break;
+ return (1);
case BSDDIALOG_OK:
- printf("OK\n");
+ printf("[OK]\n");
break;
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/pause.c b/contrib/bsddialog/examples_library/pause.c
index 1cd64f24a0cd..fd79d33aa4c0 100644
--- a/contrib/bsddialog/examples_library/pause.c
+++ b/contrib/bsddialog/examples_library/pause.c
@@ -10,38 +10,37 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
int output;
+ unsigned int sec;
struct bsddialog_conf conf;
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "pause";
- output = bsddialog_pause(&conf, "Example", 8, 50, 10);
-
+ sec = 10;
+ output = bsddialog_pause(&conf, "Example", 8, 50, &sec);
bsddialog_end();
switch (output) {
+ case BSDDIALOG_ERROR:
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
case BSDDIALOG_OK:
- printf("OK\n");
+ printf("[OK] remaining time: %u\n", sec);
break;
case BSDDIALOG_CANCEL:
- printf("Cancel\n");
- break;
- case BSDDIALOG_ERROR:
- printf("Error: %s\n", bsddialog_geterror());
+ printf("[Cancel] remaining time: %u\n", sec);
break;
case BSDDIALOG_TIMEOUT:
printf("Timeout\n");
break;
}
- return (output);
-} \ No newline at end of file
+ return (0);
+}
diff --git a/contrib/bsddialog/examples_library/radiolist.c b/contrib/bsddialog/examples_library/radiolist.c
index ac8ed5bb4064..09df32ac2e74 100644
--- a/contrib/bsddialog/examples_library/radiolist.c
+++ b/contrib/bsddialog/examples_library/radiolist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,26 +27,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "radiolist";
- output = bsddialog_radiolist(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
+ output = bsddialog_radiolist(&conf, "Example", 15, 30, 5, 5, items,
+ NULL);
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Radiolist:\n");
for (i = 0; i < 5; i++)
printf(" (%c) %s\n", items[i].on ? '*' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/rangebox.c b/contrib/bsddialog/examples_library/rangebox.c
index 8e6bf91c35a6..50498c459fc6 100644
--- a/contrib/bsddialog/examples_library/rangebox.c
+++ b/contrib/bsddialog/examples_library/rangebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,20 +20,16 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "rangebox";
value = 5;
output = bsddialog_rangebox(&conf, "Example", 8, 50, 0, 10, &value);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
printf("Value: %d\n", value);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/textbox.c b/contrib/bsddialog/examples_library/textbox.c
new file mode 100644
index 000000000000..2e76cbb97891
--- /dev/null
+++ b/contrib/bsddialog/examples_library/textbox.c
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2025 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <bsddialog.h>
+#include <stdio.h>
+
+int main()
+{
+ int output;
+ struct bsddialog_conf conf;
+
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
+ bsddialog_initconf(&conf);
+ conf.title = "textbox";
+ output = bsddialog_textbox(&conf, "./textbox.c", 20, 80);
+ bsddialog_end();
+
+ switch (output) {
+ case BSDDIALOG_ERROR:
+ printf("Error %s\n", bsddialog_geterror());
+ return (1);
+ case BSDDIALOG_OK:
+ printf("[Exit]\n");
+ break;
+ }
+
+ return (0);
+}
diff --git a/contrib/bsddialog/examples_library/theme.c b/contrib/bsddialog/examples_library/theme.c
index fcc5fd5cc31a..689633e624ed 100644
--- a/contrib/bsddialog/examples_library/theme.c
+++ b/contrib/bsddialog/examples_library/theme.c
@@ -11,64 +11,54 @@
#include <bsddialog.h>
#include <bsddialog_theme.h>
#include <stdio.h>
-#include <string.h>
int main()
{
int output, focusitem;
struct bsddialog_conf conf;
enum bsddialog_default_theme theme;
- struct bsddialog_menuitem items[5] = {
- {"", false, 0, "Flat", "dialog-like",
- "BSDDIALOG_THEME_FLAT" },
- {"", false, 0, "Dialog", "dialog clone",
- "BSDDIALOG_THEME_DIALOG" },
- {"", false, 0, "BSDDialog", "new theme",
- "BSDDIALOG_THEME_BSDDIALOG" },
- {"", false, 0, "BlackWhite","black and white",
- "BSDDIALOG_THEME_BLACKWHITE" },
- {"", false, 0, "Quit", "Exit", "Quit or Cancel to exit" }
+ struct bsddialog_menuitem items[4] = {
+ {"", false, 0, "Flat", "default flat theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_FLAT" },
+ {"", false, 0, "3D", "pseudo 3D theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_3D" },
+ {"", false, 0, "BlackWhite","black and white theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_BLACKWHITE" },
+ {"", false, 0, "Quit", "Exit", "Quit, Cancel or ESC to exit" }
};
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
-
+ conf.ascii_lines = true;
bsddialog_backtitle(&conf, "Theme Example");
-
+ bsddialog_initconf(&conf);
+ conf.key.enable_esc = true;
conf.title = " Theme ";
focusitem = -1;
while (true) {
- output = bsddialog_menu(&conf, "Choose theme", 15, 45, 5, 5,
+ output = bsddialog_menu(&conf, "Choose theme", 15, 45, 4, 4,
items, &focusitem);
- if (output != BSDDIALOG_OK || items[4].on)
+ if (output != BSDDIALOG_OK || items[3].on)
break;
if (items[0].on) {
theme = BSDDIALOG_THEME_FLAT;
focusitem = 0;
- }
- else if (items[1].on) {
- theme = BSDDIALOG_THEME_DIALOG;
+ } else if (items[1].on) {
+ theme = BSDDIALOG_THEME_3D;
focusitem = 1;
- }
- else if (items[2].on) {
- theme = BSDDIALOG_THEME_BSDDIALOG;
- focusitem = 2;
- }
- else if (items[3].on) {
+ } else if (items[2].on) {
theme = BSDDIALOG_THEME_BLACKWHITE;
- focusitem = 3;
+ focusitem = 2;
}
-
bsddialog_set_default_theme(theme);
}
bsddialog_end();
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/timebox.c b/contrib/bsddialog/examples_library/timebox.c
index 0e27f824af11..a9354c99c9be 100644
--- a/contrib/bsddialog/examples_library/timebox.c
+++ b/contrib/bsddialog/examples_library/timebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
int main()
@@ -31,26 +30,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "timebox";
- output = bsddialog_timebox(&conf,
- "TAB / RIGHT / LEFT to move,\nUP / DOWN to select time", 10, 35,
- &hh, &mm, &ss);
-
+ output = bsddialog_timebox(&conf, "Example", 9, 35, &hh, &mm, &ss);
bsddialog_end();
-
- switch (output) {
- case BSDDIALOG_OK:
- printf("Time: [%u:%u:%u]\n", hh, mm, ss);
- break;
- case BSDDIALOG_CANCEL:
- printf("Cancel\n");
- break;
- case BSDDIALOG_ERROR:
+ if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
- break;
+ return (1);
}
+ printf("Time: %u:%u:%u\n", hh, mm, ss);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_library/yesno.c b/contrib/bsddialog/examples_library/yesno.c
index 364a6c77fc26..36cb59fa013b 100644
--- a/contrib/bsddialog/examples_library/yesno.c
+++ b/contrib/bsddialog/examples_library/yesno.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,24 +20,22 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "yesno";
output = bsddialog_yesno(&conf, "Example", 7, 25);
-
bsddialog_end();
switch (output) {
case BSDDIALOG_ERROR:
printf("Error %s\n", bsddialog_geterror());
- break;
+ return (1);
case BSDDIALOG_YES:
- printf("YES\n");
+ printf("[YES]\n");
break;
case BSDDIALOG_NO:
- printf("NO\n");
+ printf("[NO]\n");
break;
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/contrib/bsddialog/examples_utility/calendar.sh b/contrib/bsddialog/examples_utility/calendar.sh
new file mode 100644
index 000000000000..a7ce4f1bb1d5
--- /dev/null
+++ b/contrib/bsddialog/examples_utility/calendar.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2022 by Alfonso Sabato Siciliano.
+#
+# To the extent possible under law, the author has dedicated all copyright
+# and related and neighboring rights to this software to the public domain
+# worldwide. This software is distributed without any warranty, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+DATE=$(./bsddialog --title " calendar " --date-format "%x" \
+ --calendar "Hello World!" 20 40 \
+3>&1 1>&2 2>&3 3>&-)
+
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $DATE"
+ ;;
+esac
diff --git a/contrib/bsddialog/examples_utility/checklist.sh b/contrib/bsddialog/examples_utility/checklist.sh
index fefabc282c80..7ff525cf765d 100755
--- a/contrib/bsddialog/examples_utility/checklist.sh
+++ b/contrib/bsddialog/examples_utility/checklist.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEMS=$(./bsddialog --title " checklist " --checklist "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" on \
- "Tag 2" "DESC 2 xyz" off \
- "Tag 3" "DESC 3 xyz" on \
- "Tag 4" "DESC 4 xyz" off \
- "Tag 5" "DESC 5 xyz" on \
+ "1 Name" "DESC 1 xyz" on \
+ "2 Name" "DESC 2 xyz" off \
+ "3 Name" "DESC 3 xyz" on \
+ "4 Name" "DESC 4 xyz" off \
+ "5 Name" "DESC 5 xyz" on \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -27,12 +27,12 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] focus: $ITEMS"
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] focus: $ITEMS"
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK] Selected: $ITEMS"
+ echo "[OK] $ITEMS"
;;
esac
diff --git a/contrib/bsddialog/examples_utility/datebox.sh b/contrib/bsddialog/examples_utility/datebox.sh
new file mode 100755
index 000000000000..bea4559dfbec
--- /dev/null
+++ b/contrib/bsddialog/examples_utility/datebox.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2023 by Alfonso Sabato Siciliano.
+#
+# To the extent possible under law, the author has dedicated all copyright
+# and related and neighboring rights to this software to the public domain
+# worldwide. This software is distributed without any warranty, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+DATE=$(./bsddialog --title " datebox " --date-format "%x" \
+ --datebox "Hello World!" 9 30 \
+3>&1 1>&2 2>&3 3>&-)
+
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $DATE"
+ ;;
+esac
diff --git a/contrib/bsddialog/examples_utility/form.sh b/contrib/bsddialog/examples_utility/form.sh
index bd1bac8a3939..ee25fa9cf352 100755
--- a/contrib/bsddialog/examples_utility/form.sh
+++ b/contrib/bsddialog/examples_utility/form.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
FORMS=$(./bsddialog --title " form " --form "Hello World!" 12 40 5 \
- Label1: 1 1 Value1 1 9 18 25 \
- Label2: 2 1 Value2 2 9 18 25 \
- Label3: 3 1 Value3 3 9 18 25 \
- Label4: 4 1 Value4 4 9 18 25 \
- Label5: 5 1 Value5 5 9 18 25 \
+ Label1: 0 0 Value1 0 8 18 25 \
+ Label2: 1 0 Value2 1 8 18 25 \
+ Label3: 2 0 Value3 2 8 18 25 \
+ Label4: 3 0 Value4 3 8 18 25 \
+ Label5: 4 0 Value5 4 8 18 25 \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -33,8 +33,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/contrib/bsddialog/examples_utility/infobox.sh b/contrib/bsddialog/examples_utility/infobox.sh
index ff39ad4d5f0e..b782e8cbf69e 100755
--- a/contrib/bsddialog/examples_utility/infobox.sh
+++ b/contrib/bsddialog/examples_utility/infobox.sh
@@ -9,4 +9,4 @@
# worldwide. This software is distributed without any warranty, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>.
-./bsddialog --sleep 3 --title " infobox " --infobox "Hello World!\n3 secs" 6 20
+./bsddialog --normal-screen --title " infobox " --infobox "Hello World!" 6 20
diff --git a/contrib/bsddialog/examples_utility/inputbox.sh b/contrib/bsddialog/examples_utility/inputbox.sh
index a359a3b8e833..756aec3c0241 100755
--- a/contrib/bsddialog/examples_utility/inputbox.sh
+++ b/contrib/bsddialog/examples_utility/inputbox.sh
@@ -28,9 +28,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORM"
;;
esac
-
-echo "$FORM"
-
diff --git a/contrib/bsddialog/examples_utility/menu.sh b/contrib/bsddialog/examples_utility/menu.sh
index 002a82f6a870..5b2f090037d8 100755
--- a/contrib/bsddialog/examples_utility/menu.sh
+++ b/contrib/bsddialog/examples_utility/menu.sh
@@ -15,10 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEM=$(./bsddialog --title " menu " --menu "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" \
- "Tag 2" "DESC 2 xyz" \
- "Tag 3" "DESC 3 xyz" \
- "Tag 4" "DESC 4 xyz" \
+ "1 Name" "DESC 1 xyz" \
+ "2 Name" "DESC 2 xyz" \
+ "3 Name" "DESC 3 xyz" \
+ "4 Name" "DESC 4 xyz" \
+ "5 Name" "DESC 5 xyz" \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -26,10 +27,10 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] $ITEM"
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] $ITEM"
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
echo "[OK] $ITEM"
diff --git a/contrib/bsddialog/examples_utility/mixedform.sh b/contrib/bsddialog/examples_utility/mixedform.sh
index 80b7abf93745..6b690e7e5b8c 100755
--- a/contrib/bsddialog/examples_utility/mixedform.sh
+++ b/contrib/bsddialog/examples_utility/mixedform.sh
@@ -16,9 +16,9 @@
FORMS=$(./bsddialog --insecure --title " mixedform " \
--mixedform "Hello World!" 12 40 3 \
- Label: 1 1 Entry 1 11 18 25 0 \
- Label: 2 1 Read-Only 2 11 18 25 2 \
- Password: 3 1 "" 3 11 18 25 1 \
+ Label: 0 0 Entry 0 10 18 25 0 \
+ Label: 1 0 Read-Only 1 10 18 25 2 \
+ Password: 2 0 "" 2 10 18 25 1 \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -32,8 +32,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/contrib/bsddialog/examples_utility/mixedgauge.sh b/contrib/bsddialog/examples_utility/mixedgauge.sh
index e98ff70614db..aa4ff2910cd9 100755
--- a/contrib/bsddialog/examples_utility/mixedgauge.sh
+++ b/contrib/bsddialog/examples_utility/mixedgauge.sh
@@ -10,11 +10,11 @@
# <http://creativecommons.org/publicdomain/zero/1.0/>.
perc=0
+mainperc=50
while [ $perc -le 100 ]
do
./bsddialog --sleep 1 --title " mixedgauge " \
- --mixedgauge "Example..." 20 45 $perc \
- "(Hidden)" " -9" \
+ --mixedgauge "Example..." 20 45 $mainperc \
"Label 1" " -1" \
"Label 2" " -2" \
"Label 3" " -3" \
@@ -23,9 +23,11 @@ do
"Label 6" " -6" \
"Label 7" " -7" \
"Label 8" " -8" \
- "Label 9" " -10" \
- "Label 10" " -11" \
+ "Label 9" " -9" \
+ "Label 10" " -10" \
+ "Label 11" " -11" \
"Label X" $perc
perc=`expr $perc + 20`
+ mainperc=`expr $mainperc + 10`
done
diff --git a/contrib/bsddialog/examples_utility/passwordbox.sh b/contrib/bsddialog/examples_utility/passwordbox.sh
index 0f93a13c877c..b43ef6f6b994 100755
--- a/contrib/bsddialog/examples_utility/passwordbox.sh
+++ b/contrib/bsddialog/examples_utility/passwordbox.sh
@@ -29,8 +29,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORM"
;;
esac
-
-echo "$FORM"
diff --git a/contrib/bsddialog/examples_utility/passwordform.sh b/contrib/bsddialog/examples_utility/passwordform.sh
index 19b3a355b6eb..874a185ee66f 100755
--- a/contrib/bsddialog/examples_utility/passwordform.sh
+++ b/contrib/bsddialog/examples_utility/passwordform.sh
@@ -16,11 +16,11 @@
FORMS=$(./bsddialog --insecure --title " passwordform " \
--passwordform "Example" 12 40 5 \
- Password1: 1 1 "" 1 12 18 25 \
- Password2: 2 1 "" 2 12 18 25 \
- Password3: 3 1 "" 3 12 18 25 \
- Password4: 4 1 "" 4 12 18 25 \
- Password5: 5 1 "" 5 12 18 25 \
+ Password1: 0 0 "" 0 11 18 25 \
+ Password2: 1 0 "" 1 11 18 25 \
+ Password3: 2 0 "" 2 11 18 25 \
+ Password4: 3 0 "" 3 11 18 25 \
+ Password5: 4 0 "" 4 11 18 25 \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -34,8 +34,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/contrib/bsddialog/examples_utility/radiolist.sh b/contrib/bsddialog/examples_utility/radiolist.sh
index 9de483369c75..359473abf35e 100755
--- a/contrib/bsddialog/examples_utility/radiolist.sh
+++ b/contrib/bsddialog/examples_utility/radiolist.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEM=$(./bsddialog --title " radiolist " --radiolist "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" off \
- "Tag 2" "DESC 2 xyz" off \
- "Tag 3" "DESC 3 xyz" on \
- "Tag 4" "DESC 4 xyz" off \
- "Tag 5" "DESC 5 xyz" off \
+ "1 Name" "DESC 1 xyz" off \
+ "2 Name" "DESC 2 xyz" off \
+ "3 Name" "DESC 3 xyz" on \
+ "4 Name" "DESC 4 xyz" off \
+ "5 Name" "DESC 5 xyz" off \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -27,14 +27,12 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] focus "
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] focus "
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $ITEM"
;;
esac
-
-echo "$ITEM"
diff --git a/contrib/bsddialog/examples_utility/rangebox.sh b/contrib/bsddialog/examples_utility/rangebox.sh
new file mode 100644
index 000000000000..9b3213d8acad
--- /dev/null
+++ b/contrib/bsddialog/examples_utility/rangebox.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2023 by Alfonso Sabato Siciliano.
+#
+# To the extent possible under law, the author has dedicated all copyright
+# and related and neighboring rights to this software to the public domain
+# worldwide. This software is distributed without any warranty, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+VALUE=$(./bsddialog --title " rangebox " --rangebox "Hello World!" 7 35 0 10 5 \
+3>&1 1>&2 2>&3 3>&-)
+
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] Value: $VALUE"
+ ;;
+esac
diff --git a/contrib/bsddialog/examples_utility/timebox.sh b/contrib/bsddialog/examples_utility/timebox.sh
index 81d24d558dc9..233434b29195 100755
--- a/contrib/bsddialog/examples_utility/timebox.sh
+++ b/contrib/bsddialog/examples_utility/timebox.sh
@@ -14,8 +14,7 @@
: ${BSDDIALOG_CANCEL=1}
: ${BSDDIALOG_ESC=5}
-TIME=$(./bsddialog --title " timebox " \
- --timebox "Tab / Left / Right to move\nUp / Down to select" 10 40 \
+TIME=$(./bsddialog --title " timebox " --timebox "Hello World!" 8 25 \
3>&1 1>&2 2>&3 3>&-)
case $? in
diff --git a/contrib/bsddialog/lib/GNUMakefile b/contrib/bsddialog/lib/GNUMakefile
deleted file mode 100644
index 0d724b803be3..000000000000
--- a/contrib/bsddialog/lib/GNUMakefile
+++ /dev/null
@@ -1,31 +0,0 @@
-# PUBLIC DOMAIN - NO WARRANTY, see:
-# <http://creativecommons.org/publicdomain/zero/1.0/>
-#
-# Written in 2021 by Alfonso Sabato Siciliano
-
-VERSION = 0.2
-LIBRARY = bsddialog
-LIBRARY_SO = lib${LIBRARY:=.so}
-HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
-SOURCES = barbox.c formbox.c infobox.c libbsddialog.c lib_util.c menubox.c \
- messagebox.c textbox.c theme.c timebox.c
-OBJECTS = $(SOURCES:.c=.o)
-CFLAGS = -D_XOPEN_SOURCE_EXTENDED -Wall -Wextra -Wno-implicit-fallthrough \
- -Werror -fpic
-LDFLAGS = -lformw -lncursesw -ltinfo
-LIBFLAG = -shared
-
-RM = rm -f
-LN = ln -s -f
-
-all : $(LIBRARY)
-
-$(LIBRARY): $(OBJECTS)
- $(CC) $(LIBFLAG) $^ -o $(LIBRARY_SO).$(VERSION) $(LDFLAGS)
- ${LN} ${LIBRARY_SO}.${VERSION} ${LIBRARY_SO}
-
-%.o: %.c $(HEADERS)
- $(CC) $(CFLAGS) -c $<
-
-clean:
- $(RM) $(LIBRARY_SO)* *.o *~
diff --git a/contrib/bsddialog/lib/GNUmakefile b/contrib/bsddialog/lib/GNUmakefile
new file mode 100644
index 000000000000..2cb060381a46
--- /dev/null
+++ b/contrib/bsddialog/lib/GNUmakefile
@@ -0,0 +1,51 @@
+# PUBLIC DOMAIN - NO WARRANTY, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written in 2021 by Alfonso Sabato Siciliano
+
+LIBRARY = bsddialog
+LIBRARY_SO = lib${LIBRARY:=.so}
+HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
+OBJECTS = $(SOURCES:.c=.o)
+PREFIX = /usr/local
+
+ifneq ($(ENABLEDEBUG),)
+CFLAGS += -g
+endif
+CFLAGS += -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE -D_GNU_SOURCE \
+ -Wall -Wextra -Werror -fpic
+LDFLAGS += -lncursesw -ltinfo
+LIBFLAG = -shared
+
+RM = rm -f
+LN = ln -s -f
+
+all: $(LIBRARY)
+
+install: all
+ ${INSTALL} -m 0644 bsddialog.h ${DESTDIR}${PREFIX}/include/bsddialog.h
+ ${INSTALL} -m 0644 bsddialog_progressview.h ${DESTDIR}${PREFIX}/include/bsddialog_progressview.h
+ ${INSTALL} -m 0644 bsddialog_theme.h ${DESTDIR}${PREFIX}/include/bsddialog_theme.h
+ ${INSTALL} -m 0755 ${LIBRARY_SO}.${VERSION} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}.${VERSION}
+ ${LN} ${LIBRARY_SO}.${VERSION} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}
+
+uninstall:
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog.h
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog_progressview.h
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog_theme.h
+ ${RM} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}.${VERSION}
+ ${RM} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}
+
+$(LIBRARY): $(OBJECTS)
+ $(CC) $(LIBFLAG) $^ -o $(LIBRARY_SO).$(VERSION) $(LDFLAGS)
+ ${LN} ${LIBRARY_SO}.${VERSION} ${LIBRARY_SO}
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ $(RM) $(LIBRARY_SO)* *.o *~
+
+.PHONY: all install uninstall ${LIBRARY} clean
diff --git a/contrib/bsddialog/lib/Makefile b/contrib/bsddialog/lib/Makefile
index 962b059b3e03..c728541a9f7a 100644
--- a/contrib/bsddialog/lib/Makefile
+++ b/contrib/bsddialog/lib/Makefile
@@ -3,39 +3,44 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.2
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
LIBRARY_A = lib${LIBRARY:=.a}
HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
-SOURCES = barbox.c formbox.c infobox.c libbsddialog.c lib_util.c menubox.c \
- messagebox.c textbox.c theme.c timebox.c
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
OBJECTS = ${SOURCES:.c=.o}
-CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
- -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
- -L/usr/lib -lformw -lncursesw -ltinfow
+PREFIX = /usr/local
.if defined(DEBUG)
-# `make -DDEBUG`
-CFLAGS = -g -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-.else
-CFLAGS += -std=gnu99 -fstack-protector-strong
+CFLAGS += -g
.endif
+CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra -std=gnu99 \
+ -fstack-protector-strong
+LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
+ -L/usr/lib -lncursesw -ltinfow
-LOCALBASE = /usr/local
LN = ln -s -f
RM = rm -f
-CP = cp
-GZIP = gzip -cn
-LDCONFIG = /sbin/ldconfig -m
-MAN = ${OUTPUT}.3
-GZIP = gzip -cn
-MANDIR = ${LOCALBASE}/share/man/man3
-INSTALL = install
-RM = rm -f
-all : man ${LIBRARY}
+all: ${LIBRARY}
+
+install: all
+ ${INSTALL} -m 0644 bsddialog.h ${DESTDIR}${PREFIX}/include/bsddialog.h
+ ${INSTALL} -m 0644 bsddialog_progressview.h ${DESTDIR}${PREFIX}/include/bsddialog_progressview.h
+ ${INSTALL} -m 0644 bsddialog_theme.h ${DESTDIR}${PREFIX}/include/bsddialog_theme.h
+ ${INSTALL} -m 0644 ${LIBRARY_A} ${DESTDIR}${PREFIX}/lib/${LIBRARY_A}
+ ${INSTALL} -m 0755 ${LIBRARY_SO}.${VERSION} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}.${VERSION}
+ ${LN} ${LIBRARY_SO}.${VERSION} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}
+
+uninstall:
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog.h
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog_progressview.h
+ ${RM} ${DESTDIR}${PREFIX}/include/bsddialog_theme.h
+ ${RM} ${DESTDIR}${PREFIX}/lib/${LIBRARY_A}
+ ${RM} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}.${VERSION}
+ ${RM} ${DESTDIR}${PREFIX}/lib/${LIBRARY_SO}
${LIBRARY}: ${LIBRARY_SO} ${LIBRARY_A}
@@ -52,24 +57,7 @@ ${LIBRARY_A}: ${OBJECTS}
.c.o:
${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
-man:
- ${GZIP} ${LIBRARY}.3 > ${LIBRARY}.3.gz
-
clean:
${RM} ${LIBRARY_SO}* *.o *~ *.gz ${LIBRARY_A}
-
-install:
- ${INSTALL} -m 644 ${HEADERS} ${LOCALBASE}/include
- ${INSTALL} -m 644 -s ${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/
- ${INSTALL} -l rs ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${INSTALL} -m 644 ${LIBRARY_A} ${LOCALBASE}/lib
- ${LDCONFIG} ${LOCALBASE}/lib
- ${INSTALL} -m 644 ${LIBRARY}.3.gz ${MANDIR}
-
-unistall:
- ${RM} ${LOCALBASE}/include/${LIBRARY}*.h
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION}
- ${LDCONFIG} ${LOCALBASE}/lib
- ${RM} ${MANDIR}/${LIBRARY}.3.gz
+.PHONY: all install uninstall ${LIBRARY} clean
diff --git a/contrib/bsddialog/lib/barbox.c b/contrib/bsddialog/lib/barbox.c
index 49aa105c1de3..51f81ecbca68 100644
--- a/contrib/bsddialog/lib/barbox.c
+++ b/contrib/bsddialog/lib/barbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,9 +25,6 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
@@ -39,139 +36,138 @@
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define BARPADDING 2
-#define MINBARLEN 15
-#define MINBARWIDTH (2 + 2 * BARPADDING + MINBARLEN)
-#define MINMGBARLEN 18
-#define MINMGBARWIDTH (2 + 2 * BARPADDING + MINMGBARLEN)
+#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 /* Mixedgauge main bar */
+#define MIN_WMGBOX (BARPADDING + BOXBORDERS + MIN_WMGBAR + BARPADDING)
+#define HBOX 3
+#define WBOX(d) ((d)->w - BORDERS - BARPADDING - BARPADDING)
+#define WBAR(d) (WBOX(d) - BOXBORDERS)
bool bsddialog_interruptprogview;
bool bsddialog_abortprogview;
-int bsddialog_total_progview;
-
-static void
-draw_bar(WINDOW *win, int y, int x, int barlen, int perc, bool withlabel,
- int label)
+long long int bsddialog_total_progview;
+
+static const char states[12][14] = {
+ " Succeeded ", /* -1 */
+ " Failed ", /* -2 */
+ " Passed ", /* -3 */
+ " Completed ", /* -4 */
+ " Checked ", /* -5 */
+ " Done ", /* -6 */
+ " Skipped ", /* -7 */
+ " In Progress ", /* -8 */
+ "(blank) ", /* -9 */
+ " N/A ", /* -10 */
+ " Pending ", /* -11 */
+ " UNKNOWN ", /* < -11, no API */
+};
+
+struct bar {
+ bool toupdate;
+ WINDOW *win;
+ int y; /* bar y in win */
+ int x; /* bar x in win */
+ int w; /* width in win */
+ int perc; /* barlen = (w * perc) / 100 */
+ const char* fmt; /* format for label */
+ int label; /* rangebox and pause perc!=label */
+};
+
+static void draw_bar(struct bar *b)
{
- int i, blue_x, color, stringlen;
- char labelstr[128];
-
- blue_x = perc > 0 ? (perc * barlen) / 100 : -1;
-
- wmove(win, y, x);
- for (i = 0; i < barlen; i++) {
- color = (i <= blue_x) ? t.bar.f_color : t.bar.color;
- wattron(win, color);
- waddch(win, ' ');
- wattroff(win, color);
- }
-
- if (withlabel)
- sprintf(labelstr, "%d", label);
- else
- sprintf(labelstr, "%3d%%", perc);
- stringlen = (int)strlen(labelstr);
- wmove(win, y, x + barlen/2 - stringlen/2);
- for (i = 0; i < stringlen; i++) {
- color = (blue_x + 1 <= barlen/2 - stringlen/2 + i ) ?
- t.bar.color : t.bar.f_color;
- wattron(win, color);
- waddch(win, labelstr[i]);
- wattroff(win, color);
- }
+ int barlen, xlabel;
+ chtype ch;
+ char label[128];
+
+ barlen = b->perc > 0 ? (b->perc * b->w) / 100 : 0;
+
+ ch = ' ' | t.bar.f_color;
+ mvwhline(b->win, b->y, b->x, ch, barlen);
+ ch = ' ' | t.bar.color;
+ mvwhline(b->win, b->y, b->x + barlen, ch, b->w - barlen);
+
+ sprintf(label, b->fmt, b->label);
+ xlabel = b->x + b->w/2 - (int)strlen(label)/2; /* 1-byte-char string */
+ wattron(b->win, t.bar.color); /* x+barlen < xlabel */
+ mvwaddstr(b->win, b->y, xlabel, label);
+ wattroff(b->win, t.bar.color);
+ wattron(b->win, t.bar.f_color); /* x+barlen >= xlabel */
+ mvwaddnstr(b->win, b->y, xlabel, label, MAX((b->x+barlen) - xlabel, 0));
+ wattroff(b->win, t.bar.f_color);
+
+ if (b->toupdate)
+ wnoutrefresh(b->win);
+ b->toupdate = false;
}
-static int
-bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, struct buttons *bs)
+static void update_barbox(struct dialog *d, struct bar *b, bool buttons)
{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, bs, 3, MINBARWIDTH,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, MINBARWIDTH, bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* bar */, bs != NULL);
-
- return (0);
-}
-
-static int
-bar_checksize(int rows, int cols, struct buttons *bs)
-{
- int minheight, minwidth;
-
- minwidth = 0;
- if (bs != NULL) /* gauge has not buttons */
- minwidth = buttons_width(*bs);
+ int y;
- minwidth = MAX(minwidth, MINBARWIDTH);
- minwidth += VBORDERS;
-
- if (cols < minwidth)
- RETURN_ERROR("Few cols to draw bar and/or buttons");
-
- minheight = HBORDERS + 3;
- if (bs != NULL)
- minheight += 2;
- if (rows < minheight)
- RETURN_ERROR("Few rows to draw bar");
-
- return (0);
+ y = d->y + d->h - BORDER - HBOX;
+ if (buttons)
+ y -= HBUTTONS;
+ update_box(d->conf, b->win, y, d->x + BORDER + BARPADDING, HBOX,
+ WBOX(d), RAISED);
}
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep)
+ int cols, unsigned int perc, int fd, const char *sep, const char *end)
{
bool mainloop;
- int y, x, h, w, fd2;
+ int fd2;
FILE *input;
- WINDOW *widget, *textpad, *bar, *shadow;
char inputbuf[2048], ntext[2048], *pntext;
+ struct bar b;
+ struct dialog d;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, NULL) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, NULL) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, NULL,
- false) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%3d%%";
- bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
+ input = NULL;
+ if (fd >= 0) {
+ CHECK_PTR(sep);
+ CHECK_PTR(end);
- mainloop = (fd < 0) ? false : true;
-
- if (mainloop) {
fd2 = dup(fd);
- input = fdopen(fd2, "r");
- if (input == NULL)
- RETURN_ERROR("Cannot build FILE* from fd");
- } else
- input = NULL;
+ if ((input = fdopen(fd2, "r")) == NULL)
+ RETURN_FMTERROR("Cannot build FILE* from fd %d", fd);
+ }
+ perc = MIN(perc, 100);
+ mainloop = true;
while (mainloop) {
- wrefresh(widget);
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-4,
- x+w-1-TEXTHMARGIN);
- draw_borders(conf, bar, 3, w-6, RAISED);
- draw_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/);
- wrefresh(bar);
+ if (d.built) {
+ hide_dialog(&d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(&d, HBOX, MIN_WBOX, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d))
+ return (BSDDIALOG_ERROR);
+ if (d.built)
+ refresh(); /* fix grey lines expanding screen */
+ TEXTPAD(&d, HBOX);
+ update_barbox(&d, &b, false);
+ b.w = WBAR(&d);
+ b.perc = b.label = perc;
+ b.toupdate = true;
+ draw_bar(&b);
+ doupdate();
+ if (input == NULL) /* that is fd < 0 */
+ break;
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
@@ -181,154 +177,173 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
if (mainloop == false)
break;
fscanf(input, "%d", &perc);
- perc = perc > 100 ? 100 : perc;
+ perc = MIN(perc, 100);
pntext = &ntext[0];
ntext[0] = '\0';
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
if (strcmp(inputbuf, sep) == 0)
break;
strcpy(pntext, inputbuf);
- pntext += strlen(inputbuf);
+ pntext += strlen(inputbuf); /* end string, no strlen */
pntext[0] = ' ';
pntext++;
}
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- ntext, NULL, false) != 0)
- return (BSDDIALOG_ERROR);
+ pntext[0] = '\0';
+ d.text = ntext;
}
if (input != NULL)
fclose(input);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
/* 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; /* ' '<max_minibarlen>' ['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, output, miniperc, y, x, h, w, ypad, max_minbarlen;
- int htextpad, htext, wtext;
- int colorperc, red, green;
- WINDOW *widget, *textpad, *bar, *shadow;
- char states[12][14] = {
- " Succeeded ", /* -1 */
- " Failed ", /* -2 */
- " Passed ", /* -3 */
- " Completed ", /* -4 */
- " Checked ", /* -5 */
- " Done ", /* -6 */
- " Skipped ", /* -7 */
- " In Progress ", /* -8 */
- "(blank) ", /* -9 */
- " N/A ", /* -10 */
- " Pending ", /* -11 */
- " UNKNOWN ", /* < -11, no API */
- };
+ int i, miniperc;
+ int ystext, htext;
+ int minicolor, red, green;
+ struct bar b;
+ struct dialog d;
+
+ CHECK_ARRAY(nminibars, minilabels);
+ CHECK_ARRAY(nminibars, minipercs);
red = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_RED, BSDDIALOG_BOLD);
green = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_GREEN,BSDDIALOG_BOLD);
- max_minbarlen = 0;
- for (i = 0; i < (int)nminibars; i++)
- max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i]));
- max_minbarlen += 3 + 16; /* seps + [...] */
- max_minbarlen = MAX(max_minbarlen, MINMGBARWIDTH); /* mainbar */
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
-
- /* mixedgauge autosize */
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, nminibars + 3,
- max_minbarlen, &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
- if (cols == BSDDIALOG_AUTOSIZE)
- w = widget_min_width(conf, wtext, max_minbarlen, NULL);
- if (rows == BSDDIALOG_AUTOSIZE)
- h = widget_min_height(conf, htext, nminibars + 3, false);
-
- /* mixedgauge checksize */
- if (w < max_minbarlen + 2)
- RETURN_ERROR("Few cols for this mixedgauge");
- if (h < 5 + (int)nminibars)
- RETURN_ERROR("Few rows for this mixedgauge");
-
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (mixedgauge_size_position(&d, nminibars, minilabels, &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
return (BSDDIALOG_ERROR);
-
- output = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false);
- if (output == BSDDIALOG_ERROR)
- return (output);
/* mini bars */
+ b.win = d.widget;
+ b.x = 1 + d.w - 2 - 15;
+ b.w = 13;
+ b.fmt = "%3d%%";
+ b.toupdate = false;
for (i = 0; i < (int)nminibars; i++) {
miniperc = minipercs[i];
- if (miniperc == BSDDIALOG_MG_BLANK)
- continue;
/* label */
- if (color && (miniperc >= 0))
- wattron(widget, A_BOLD);
- mvwaddstr(widget, i+1, 2, minilabels[i]);
- wattroff(widget, A_BOLD);
+ if (color && miniperc >= 0)
+ wattron(d.widget, A_BOLD);
+ mvwaddcstr(d.widget, i+1, 2, CHECK_STR(minilabels[i]), d.w-20);
+ if (color && miniperc >= 0)
+ wattroff(d.widget, A_BOLD);
/* perc */
- if (miniperc < -11)
- mvwaddstr(widget, i+1, w-2-15, states[11]);
- else if (miniperc < 0) {
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- colorperc = -1;
+ if (miniperc == BSDDIALOG_MG_BLANK)
+ continue;
+ mvwaddstr(d.widget, i+1, d.w-2-15, "[ ]");
+ if (miniperc >= 0) {
+ b.y = i + 1;
+ b.perc = b.label = MIN(miniperc, 100);
+ draw_bar(&b);
+ } else { /* miniperc < 0 */
+ if (miniperc < BSDDIALOG_MG_PENDING)
+ miniperc = -12; /* UNKNOWN */
+ minicolor = t.dialog.color;
if (color && miniperc == BSDDIALOG_MG_FAILED)
- colorperc = red;
- if (color && miniperc == BSDDIALOG_MG_DONE)
- colorperc = green;
- if (colorperc != -1)
- wattron(widget, colorperc);
+ minicolor = red;
+ else if (color && miniperc == BSDDIALOG_MG_DONE)
+ minicolor = green;
+ wattron(d.widget, minicolor);
miniperc = abs(miniperc + 1);
- mvwaddstr(widget, i+1, 1+w-2-15, states[miniperc]);
- if (colorperc != -1)
- wattroff(widget, colorperc);
- }
- else { /* miniperc >= 0 */
- if (miniperc > 100)
- miniperc = 100;
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- draw_bar(widget, i+1, 1+w-2-15, 13, miniperc, false,
- -1 /*unused*/);
+ mvwaddstr(d.widget, i+1, 1+d.w-2-15, states[miniperc]);
+ wattroff(d.widget, minicolor);
}
}
+ wnoutrefresh(d.widget);
- wrefresh(widget);
- getmaxyx(textpad, htextpad, i /* unused */);
- ypad = y + h - 4 - htextpad;
- ypad = ypad < y+(int)nminibars ? y+(int)nminibars : ypad;
- prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2);
+ /* text */
+ ystext = MAX(d.h - BORDERS - htext - HBOX, (int)nminibars);
+ rtextpad(&d, 0, 0, ystext, HBOX);
/* main bar */
- bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED);
-
- draw_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/);
-
- wattron(bar, t.bar.color);
- mvwaddstr(bar, 0, 2, "Overall Progress");
- wattroff(bar, t.bar.color);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ update_barbox(&d, &b, false);
+ wattron(b.win, t.bar.color);
+ mvwaddstr(b.win, 0, 2, "Overall Progress");
+ wattroff(b.win, t.bar.color);
+
+ b.y = b.x = 1;
+ b.w = WBAR(&d);
+ b.fmt = "%3d%%";
+ b.perc = b.label = MIN(mainperc, 100);
+ b.toupdate = true;
+ draw_bar(&b);
- wrefresh(bar);
-
- /* getch(); port ncurses shows nothing */
+ doupdate();
+ /* getch(); to test with "alternate mode" */
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
@@ -338,12 +353,12 @@ bsddialog_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int mainperc, unsigned int nminibars,
const char **minilabels, int *minipercs)
{
- int output;
+ int retval;
- output = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars,
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars,
minilabels, minipercs, false);
- return (output);
+ return (retval);
}
int
@@ -352,11 +367,11 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
struct bsddialog_fileminibar *minibar)
{
bool update;
- int perc, output, *minipercs;
+ int perc, retval, *minipercs;
unsigned int i, mainperc, totaltodo;
float readforsec;
const char **minilabels;
- time_t tstart, told, tnew, refresh;
+ time_t tstart, told, tnew, trefresh;
if ((minilabels = calloc(nminibar, sizeof(char*))) == NULL)
RETURN_ERROR("Cannot allocate memory for minilabels");
@@ -370,8 +385,8 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
minipercs[i] = minibar[i].status;
}
- refresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1;
- output = BSDDIALOG_OK;
+ trefresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1;
+ retval = BSDDIALOG_OK;
i = 0;
update = true;
time(&told);
@@ -383,10 +398,10 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
mainperc = (bsddialog_total_progview * 100) / totaltodo;
time(&tnew);
- if (update || tnew > told + refresh) {
- output = do_mixedgauge(conf, text, rows, cols, mainperc,
+ if (update || tnew > told + trefresh) {
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc,
nminibar, minilabels, minipercs, true);
- if (output == BSDDIALOG_ERROR)
+ if (retval == BSDDIALOG_ERROR)
return (BSDDIALOG_ERROR);
move(SCREENLINES - 1, 2);
@@ -412,7 +427,8 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
minipercs[i] = BSDDIALOG_MG_DONE;
update = true;
i++;
- } else if (minibar[i].status == BSDDIALOG_MG_FAILED || perc < 0) {
+ } else if (minibar[i].status == BSDDIALOG_MG_FAILED ||
+ perc < 0) {
minipercs[i] = BSDDIALOG_MG_FAILED;
update = true;
} else /* perc >= 0 */
@@ -421,326 +437,280 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
free(minilabels);
free(minipercs);
- return (output);
+ return (retval);
+}
+
+static int
+rangebox_redraw(struct dialog *d, bool redraw, struct bar *b, int *bigchange)
+{
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MIN_WBOX, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* doupdate() in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
+
+ b->w = WBAR(d);
+ *bigchange = MAX(1, b->w / 10);
+ update_barbox(d, b, true);
+ b->toupdate = true;
+
+ return (0);
}
int
bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
int cols, int min, int max, int *value)
{
- bool loop, buttupdate, barupdate;
- int y, x, h, w;
- int input, currvalue, output, sizebar, bigchange, positions;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- if (value == NULL)
- RETURN_ERROR("*value cannot be NULL");
+ bool loop;
+ int currvalue, retval, bigchange, positions;
+ wint_t input;
+ struct bar b;
+ struct dialog d;
+ CHECK_PTR(value);
if (min >= max)
- RETURN_ERROR("min >= max");
+ RETURN_FMTERROR("min (%d) >= max (%d)", min, max);
+ if (*value < min)
+ RETURN_FMTERROR("value (%d) < min (%d)", *value, min);
+ if (*value > max)
+ RETURN_FMTERROR("value (%d) > max (%d)", *value, max);
currvalue = *value;
positions = max - min + 1;
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%d";
+ if (rangebox_redraw(&d, false, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
-
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
-
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
+ if (b.toupdate) {
+ b.perc = ((float)(currvalue - min)*100) / (positions-1);
+ b.label = currvalue;
+ draw_bar(&b);
}
- if (barupdate) {
- perc = ((float)(currvalue - min)*100) / (positions-1);
- draw_bar(bar, 1, 1, sizebar, perc, true, currvalue);
- barupdate = false;
- wrefresh(bar);
- }
-
- input = getch();
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
- *value = currvalue;
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
+ 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:
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_HOME:
currvalue = max;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_END:
currvalue = min;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_NPAGE:
currvalue -= bigchange;
if (currvalue < min)
currvalue = min;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_PPAGE:
currvalue += bigchange;
if (currvalue > max)
currvalue = max;
- barupdate = true;
+ b.toupdate = true;
break;
+ case '-':
case KEY_UP:
- if (currvalue < max) {
- currvalue++;
- barupdate = true;
+ if (currvalue > min) {
+ currvalue--;
+ b.toupdate = true;
}
break;
+ case '+':
case KEY_DOWN:
- if (currvalue > min) {
- currvalue--;
- barupdate = true;
+ if (currvalue < max) {
+ currvalue++;
+ b.toupdate = true;
}
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);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
+ if (rangebox_redraw(&d, true, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &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, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (rangebox_redraw(&d, true, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, RAISED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *value = currvalue;
+
+ delwin(b.win);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
-int
-bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int sec)
+static int pause_redraw(struct dialog *d, bool redraw, struct bar *b)
{
- bool loop, buttupdate, barupdate;
- int output, y, x, h, w, input, tout, sizebar;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MIN_WBOX, NULL) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (draw_dialog(d) != 0) /* doupdate() in main loop */
return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
+ b->w = WBAR(d);
+ update_barbox(d, b, true);
+ b->toupdate = true;
- doupdate();
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
+ return (0);
+}
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
+int
+bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *seconds)
+{
+ bool loop;
+ int retval, tout;
+ wint_t input;
+ struct bar b;
+ struct dialog d;
+
+ CHECK_PTR(seconds);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%d";
+ if (pause_redraw(&d, false, &b) != 0)
+ return (BSDDIALOG_ERROR);
- tout = sec;
+ tout = *seconds;
nodelay(stdscr, TRUE);
timeout(1000);
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (barupdate) {
- perc = (float)tout * 100 / sec;
- draw_bar(bar, 1, 1, sizebar, perc, true, tout);
- barupdate = false;
- wrefresh(bar);
- }
-
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
+ if (b.toupdate) {
+ b.perc = (float)tout * 100 / *seconds;
+ b.label = tout;
+ draw_bar(&b);
}
-
- input = getch();
- if (input < 0) { /* timeout */
+ doupdate();
+ if (get_wch(&input) == ERR) { /* timeout */
tout--;
if (tout < 0) {
- output = BSDDIALOG_TIMEOUT;
+ retval = BSDDIALOG_TIMEOUT;
break;
}
else {
- barupdate = true;
+ b.toupdate = true;
continue;
}
}
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
+ 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--;
- buttupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ 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)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (pause_redraw(&d, true, &b) != 0)
return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget,y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (pause_redraw(&d, true, &b) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, LOWERED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
-
nodelay(stdscr, FALSE);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *seconds = MAX(tout, 0);
- return (output);
-} \ No newline at end of file
+ delwin(b.win);
+ end_dialog(&d);
+
+ return (retval);
+}
diff --git a/contrib/bsddialog/lib/bsddialog.3 b/contrib/bsddialog/lib/bsddialog.3
index 38500b4da6ca..bbd756661a78 100644
--- a/contrib/bsddialog/lib/bsddialog.3
+++ b/contrib/bsddialog/lib/bsddialog.3
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+.\" Copyright (c) 2021-2025 Alfonso Sabato Siciliano
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -22,13 +22,16 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 9, 2022
+.Dd June 22, 2025
.Dt BSDDIALOG 3
.Os
.Sh NAME
.Nm bsddialog_backtitle ,
-.Nm bsddialog_clearterminal ,
+.Nm bsddialog_backtitle_rf ,
+.Nm bsddialog_calendar ,
+.Nm bsddialog_clear ,
.Nm bsddialog_color ,
+.Nm bsddialog_color_attrs ,
.Nm bsddialog_checklist ,
.Nm bsddialog_datebox ,
.Nm bsddialog_end ,
@@ -36,9 +39,12 @@
.Nm bsddialog_gauge ,
.Nm bsddialog_geterror ,
.Nm bsddialog_get_theme ,
+.Nm bsddialog_hascolors ,
.Nm bsddialog_infobox ,
.Nm bsddialog_init ,
+.Nm bsddialog_init_notheme ,
.Nm bsddialog_initconf ,
+.Nm bsddialog_inmode ,
.Nm bsddialog_menu ,
.Nm bsddialog_mixedgauge ,
.Nm bsddialog_mixedlist ,
@@ -46,6 +52,7 @@
.Nm bsddialog_pause ,
.Nm bsddialog_radiolist ,
.Nm bsddialog_rangebox ,
+.Nm bsddialog_refresh ,
.Nm bsddialog_set_theme ,
.Nm bsddialog_set_default_theme ,
.Nm bsddialog_textbox ,
@@ -59,6 +66,18 @@
.Ft int
.Fn bsddialog_backtitle "struct bsddialog_conf *conf" "const char *backtitle"
.Ft int
+.Fn bsddialog_backtitle_rf "struct bsddialog_conf *conf" "const char *backtitle"
+.Ft int
+.Fo bsddialog_calendar
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
+.Fc
+.Ft int
.Fo bsddialog_checklist
.Fa "struct bsddialog_conf *conf"
.Fa "const char *text"
@@ -69,17 +88,17 @@
.Fa "struct bsddialog_menuitem *items"
.Fa "int *focusitem"
.Fc
+.Ft void
+.Fn bsddialog_clear "unsigned int y"
.Ft int
-.Fn bsddialog_clearterminal "void"
-.Ft int
-.Fo bsddialog_datebox"
+.Fo bsddialog_datebox
.Fa "struct bsddialog_conf *conf"
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int *yy"
-.Fa "unsigned int *mm"
-.Fa "unsigned int *dd"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
.Fc
.Ft int
.Fn bsddialog_end "void"
@@ -92,6 +111,7 @@
.Fa "unsigned int formrows"
.Fa "unsigned int nitems"
.Fa "struct bsddialog_formitem *items"
+.Fa "int *focusitem"
.Fc
.Ft int
.Fo bsddialog_gauge
@@ -102,6 +122,7 @@
.Fa "unsigned int perc"
.Fa "int fd"
.Fa "const char *sep"
+.Fa "const char *end"
.Fc
.Ft const char *
.Fn bsddialog_geterror "void"
@@ -115,6 +136,10 @@
.Ft int
.Fn bsddialog_init "void"
.Ft int
+.Fn bsddialog_init_notheme "void"
+.Ft bool
+.Fn bsddialog_inmode "void"
+.Ft int
.Fn bsddialog_initconf "struct bsddialog_conf *conf"
.Ft int
.Fo bsddialog_menu
@@ -163,7 +188,7 @@
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int seconds"
+.Fa "unsigned int *seconds"
.Fc
.Ft int
.Fo bsddialog_radiolist
@@ -186,6 +211,8 @@
.Fa "int max"
.Fa "int *value"
.Fc
+.Ft void
+.Fn bsddialog_refresh "void"
.Ft int
.Fo bsddialog_textbox
.Fa "struct bsddialog_conf *conf"
@@ -218,7 +245,16 @@
.Fa "unsigned int flags"
.Fc
.Ft int
+.Fo bsddialog_color_attrs
+.Fa "int color"
+.Fa "enum bsddialog_color *foreground"
+.Fa "enum bsddialog_color *background"
+.Fa "unsigned int *flags"
+.Fc
+.Ft int
.Fn bsddialog_get_theme "struct bsddialog_theme *theme"
+.Ft bool
+.Fn bsddialog_hascolors "void"
.Ft int
.Fn bsddialog_set_default_theme "enum bsddialog_default_theme theme"
.Ft int
@@ -226,8 +262,7 @@
.Sh DESCRIPTION
The
.Nm bsddialog
-library provides an API to build Text User Interface dialogs and widgets: to
-display messages, to get input and to inform about a computation status.
+library provides an API to build Text User Interface dialogs and widgets.
.Pp
.Fn bsddialog_init
initializes the library, the only functions that can be called before is
@@ -235,53 +270,85 @@ initializes the library, the only functions that can be called before is
described later.
After the initialization the input and output should be handled via the library
API.
+.Pp
+.Fn bsddialog_init_notheme
+is equivalent to
+.Fn bsddialog_init
+except it does not set the default graphical theme; see
+.Sx Theme
+subsection to set a theme explicitly.
+.Pp
.Fn bsddialog_end
restores the screen like before
-.Fn bsddialog_init ,
-then it is not possible to use the library functions.
+.Fn bsddialog_init .
+After the call is not possible to use the library functions.
.Pp
-.Fn bsddialog_error
-returns a string to describe the last error, it should be called after a
-.Dv BSDDIALOG_ERROR
-returned value.
-.Fn bsddialog_clearterminal
-clears the screen.
-.Fn bsddialog_backtitle
+.Fn bsddialog_inmode
+returns
+.Dv true
+after
+.Fn bsddialog_init
+or
+.Fn bsddialog_init_notheme
+and before
+.Fn bsddialog_end ,
+.Dv false
+otherwise.
+.Pp
+.Fn bsddialog_backtitle_rf
prints
.Fa backtitle
-on the top of the screen, it is possible to set
+on the top of the screen.
+The function handles
.Fa conf.ascii_lines
and
-.Fa conf.no_lines ;
-.Fa conf
-is described later.
+.Fa conf.no_lines
+described later.
.Pp
-Each
-.Fa char*
-argument has to be a well terminated string, can be empty
-.Pq Dq
-but not
-.Dv NULL .
+.Fn bsddialog_backtitle
+is like
+.Fn bsddialog_backtitle_rf
+but it does not update the screen, using if a dialog is built later.
+.Pp
+.Fn bsddialog_error
+returns a string to describe the last error.
+The function should be called after a
+.Dv BSDDIALOG_ERROR
+returned value.
+.Pp
+.Fn bsddialog_clear
+clears the screen from
+.Fa y .
+.Pp
+.Fn bsddialog_refresh
+useful to refresh the screen after a terminal mode change, see
+.Xr terminfo 5 .
.Ss Dialogs
The dialogs have common arguments.
.Fa text
is a string printed inside the dialog.
+Each
+.Fa char*
+parameter can be a multibyte character string depending on current locale, see
+.Xr setlocale 3 .
.Fa rows
and
.Fa cols
-are height and width, their value can be between 2 and the screen size,
+are height and width, their value can be a fixed size,
.Dv BSDDIALOG_AUTOSIZE
or
.Dv BSDDIALOG_FULLSCREEN .
.Fa conf
-is a struct to customize the dialog, it does not set global properties to the
-library.
+is a struct to customize the current dialog, it does not set global properties
+to the library.
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_conf {
bool ascii_lines;
unsigned int auto_minheight;
unsigned int auto_minwidth;
+ unsigned int auto_topmargin;
+ unsigned int auto_downmargin;
const char *bottomtitle;
bool clear;
int *get_height;
@@ -298,22 +365,29 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
- bool highlight;
+ unsigned int cols_per_row;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
- bool value_without_ok;
+ char securech;
+ char *securembch;
+ bool value_wchar;
} form;
struct {
+ const char *format;
+ } date;
+ struct {
+ bool always_active;
+ const char *left1_label;
+ const char *left2_label;
+ const char *left3_label;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -323,8 +397,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -343,8 +418,25 @@ minimum width if
.Fa cols
is
.Dv BSDDIALOG_AUTOSIZE .
+.It Fa conf.auto_topmargin
+top margin if
+.Fa rows
+is
+.Dv BSDDIALOG_AUTOSIZE
+or
+.Dv BSDDIALOG_FULLSCREEN ,
+.Fa conf.y
+has to be
+.Dv BSDDIALOG_CENTER .
+.It Fa conf.auto_downmargin
+down margin if
+.Fa rows
+is
+.Dv BSDDIALOG_AUTOSIZE
+or
+.Dv BSDDIALOG_FULLSCREEN .
.It Fa conf.bottomtitle
-subtitle at the dialog bottom side.
+dialog subtitle.
.It Fa conf.clear
hide the dialog at exit.
.It Fa conf.get_height
@@ -362,31 +454,35 @@ draw shadow.
.It Fa conf.sleep
wait before to return, the value is in seconds.
.It Fa conf.title
-title at the top dialog side.
+dialog title.
.It Fa conf.y
-vertical position, 0 is top screen size, can be
+dialog vertical position, 0 is top screen, can be
.Dv BSDDIALOG_CENTER .
.It Fa conf.x
-horizontal position, 0 is left screen side, can be
+dialog horizontal position, 0 is left screen, can be
.Dv BSDDIALOG_CENTER .
.El
.Pp
.Bl -column -compact
.It Fa conf.key.enable_esc
-enables
+enable
.Dv ESC
key to close the dialog.
.It Fa conf.key.f1_file
-file to open if F1 is pressed.
+open a file in a textbox if F1 is pressed.
.It Fa conf.key.f1_message
-message to display if F1 is pressed.
+build a msgbox with message if F1 is pressed.
.El
.Pp
-.Fa conf.text.highlight
-enables highlights for
-.Fa text ,
-properly the following sequences are considered escapes:
.Bl -column -compact
+.It Fa conf.text.cols_per_row
+Try to set the number of columns for a row of
+.Fa text
+with autosizing, default
+.Dv 10 .
+.It Fa conf.text.escape
+enable escapes in
+.Fa text :
.It Dq \eZ0
black.
.It Dq \eZ1
@@ -403,25 +499,55 @@ magenta.
cyan.
.It Dq \eZ7
white.
-.It Dq \eZr
-reverse colors between foreground and background.
-.It Dq \eZR
-disable reverse.
.It Dq \eZb
bold.
.It Dq \eZB
disable bold.
+.It Dq \eZd
+Half bright.
+.It Dq \eZD
+disable half bright.
+.It Dq \eZk
+Blink.
+.It Dq \eZK
+disable blinking.
+.It Dq \eZr
+reverse foreground and background.
+.It Dq \eZR
+disable reverse.
+.It Dq \eZs
+Highlight.
+.It Dq \eZS
+disable highlighting.
.It Dq \eZu
underline.
.It Dq \eZU
disable underline.
.It Dq \eZn
disable each customization.
+.It Fa conf.text.tablen
+tab length for
+.Fa text
+argument and
+.Fn bsddialog_textbox
+function.
.El
-.Fa conf.text.tablen
-tab length.
.Pp
.Bl -column -compact
+.It Fa conf.button.always_active
+buttons always active, avoiding focus switch between buttons and input fields or
+input boxes in
+.Fn bsddialog_form ,
+.Fn bsddialog_datebox ,
+.Fn bsddialog_calendar
+and
+.Fn bsddialog_timebox .
+.It Fa conf.button.left1_label
+add a button with the specified label.
+.It Fa conf.button.left2_label
+add a button with the specified label.
+.It Fa conf.button.left3_label
+add a button with the specified label.
.It Fa conf.button.without_ok
disable OK button.
.It Fa conf.button.ok_label
@@ -440,9 +566,11 @@ on startup focus on the Cancel button.
add Help button.
.It Fa conf.button.help_label
set a label for Help button.
-.It Fa conf.button.generic1_label
+.It Fa conf.button.right1_label
+add a button with the specified label.
+.It Fa conf.button.right2_label
add a button with the specified label.
-.It Fa conf.button.generic2_label
+.It Fa conf.button.right3_label
add a button with the specified label.
.It Fa conf.button.default_label
focus on the button with the specified label.
@@ -458,148 +586,58 @@ to true,
and
.Fa conf.x
to
-.Dv BSDDIALOG_CENTER .
-.Pp
-.Fn bsddialog_infobox
-builds a dialog without buttons and returns instantly.
-.Fn bsddialog_msgbox
-builds a dialog with OK button.
-.Fn bsddialog_yesno
-provides a dialog for a
-.Dq Yes-No Question ,
-the labels on buttons are Yes and No.
-.Pp
-.Fn bsddialog_pause
-builds a dialog waiting until the timeout in
-.Fa seconds
-expires or a button is pressed.
+.Dv BSDDIALOG_CENTER ,
+.Fa conf.text.cols_per_row
+to
+.Dv 10 .
.Pp
-.Fn bsddialog_datebox
-builds a dialog to select a date,
-.Fa yy ,
-.Fa mm ,
+.Fn bsddialog_calendar
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fa dd
+.Fa day
are default values on startup, selected date at exit.
-.Fn bsddialog_timebox
-builds a dialog to choose a time,
-.Fa hh ,
-.Fa mm ,
-and
-.Fa ss
-are default values on startup, selected time at exit.
-.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu
-and
-.Fn bsddialog_radiolist
-build dialogs to select some item from a list via the SPACE key, an item is
-defined like:
.Pp
-.Bd -literal -offset indent -compact
-struct bsddialog_menuitem {
- const char *prefix;
- bool on;
- unsigned int depth;
- const char *name;
- const char *desc;
- const char *bottomdesc;
-};
-.Ed
+.Fn bsddialog_checklist
+builds dialogs to select some item from a list via the SPACE key, can be
+customized by
+.Fa conf.menu.* .
+See
+.Fn bsddialog_menu .
.Pp
-.Fa prefix ,
-.Fa name
-and
-.Fa desc
-are strings to describe the item and are printed on its row,
-.Fa bottomdesc
-is printed on the bottom side of the screen,
-.Fa depth
-is a margin between the
-.Fa prefix
-and
-.Fa name
-useful to implement a
-.Dq treeview,
-.Fa on
-is set to
-.Dv true
-if the item is selected,
-.Dv false
-otherwise.
-.Fa items
-is an array of items of
-.Fa nitem
-elements,
-.Fa menurows
-specifies the graphical fixed height of the list, if
-.Fa cols
-is set to
-.Dv BSDDIALOG_AUTOSIZE
-.Fa menurows
-specifies a maximum value.
-Finally, if not
-.Dv NULL ,
-.Fa focusitem
-specifies the default item on startup and the last focused item at exit, could
-be a negative value if no item is focused.
-.Pp
-.Fn bsddialog_mixedlist
-builds a dialog with collections of checklists, radiolists and separators.
-A collection is a set defined like:
-.Pp
-.Bd -literal -offset indent -compact
-enum bsddialog_grouptype {
- BSDDIALOG_CHECKLIST,
- BSDDIALOG_RADIOLIST,
- BSDDIALOG_SEPARATOR,
-};
-
-struct bsddialog_menugroup {
- enum bsddialog_grouptype type;
- unsigned int nitems;
- struct bsddialog_menuitem *items;
-};
-.Ed
-.Pp
-.Fa groups
-is an array of sets of
-.Fa ngroups
-elements.
-.Fa menurows
-is the graphical height size for the list.
-If not
-.Dv NULL ,
-.Fa focuslist
-and
-.Fa focusitem
-specify the default item on startup and the last focused item at exit, could be
-a negative value if no item is focused.
-.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu ,
-.Fn bsddialog_mixedlist
+.Fn bsddialog_datebox
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fn bsddialog_radiolist
-can be costomizated by:
+.Fa day
+are default values on startup, selected date at exit.
+The function can be customized by:
.Bl -column -compact
-.It Fa conf.menu.align_left
-aligns items to left, default center.
-.It Fa conf.menu.no_desc
-hide description.
-.It Fa conf.menu.no_name
-hide names.
-.It Fa conf.menu.on_without_ok
-set items
-.Fa on
-also if the OK button is not pressed.
-.It Fa conf.menu.shortcut_buttons
-enable shortcut keys on buttons, default on items.
+.It Fa conf.date.format
+date format user interface, possible values:
+.Dq d/m/y ,
+.Dq m/d/y ,
+.Dq y/m/d .
.El
.Pp
.Fn bsddialog_form
-builds a dialog to display a list of items to get strings in input, an item is
-defined like:
+builds a dialog to display an array of
+.Fa items
+of
+.Fa nitems
+elements to get input strings.
+.Fa formrows
+is the graphical height for the items inside the dialog,
+.Dv 0
+for autosizing.
+If not
+.Dv NULL
+.Fa focusitem
+is the default item index on startup and the last focused item at exit, a
+negative value if no item is focused.
+An item is defined like:
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_formitem {
@@ -621,7 +659,7 @@ struct bsddialog_formitem {
.Ed
.Pp
.Fa label
-describes the request, it is printed at the position
+is a string to describe the request at the position
.Fa ylabel
and
.Fa xlabel .
@@ -632,77 +670,142 @@ and
.Fa fieldlen
is its graphical width, while
.Fa maxvalelen
-is the maximum length of the input string,
+is the maximum number of characters of the input string.
.Fa init
-is the default value.
-If the OK button is pressed
+is the default field value.
+If no error occurs
.Fa value
-is the allocated memory with the current field string.
+is the allocated memory with the current field string at exit, its size depends
+on the current locale.
.Fa flags
-is an OR value to set the
-.Dv BSDDIALOG_FIELDHIDDEN
-and
-.Dv BSDDIALOG_FIELDREADONLY
-flags for the field.
+is an OR value to set the field:
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Dv BSDDIALOG_FIELDREADONLY ,
+.Dv BSDDIALOG_FIELDNOCOLOR ,
+.Dv BSDDIALOG_FIELDCURSOREND ,
+.Dv BSDDIALOG_FIELDEXTEND ,
+.Dv BSDDIALOG_FIELDSINGLEBYTE .
.Fa bottomdesc
-is printed on the bottom side of the screen if the item is focused.
-.Fa items
-is an array of items of
-.Fa nitems
-elements,
-.Fa formrows
-specifies the graphical fixed height for the items list;
-.Fa ylabel
-and
-.Fa yfield
-have to be between 1 and
-.Fa formrows .
+is printed at bottom screen if the item is focused.
.Pp
.Fn bsddialog_form
can be customized by:
.Bl -column -compact
-.It Fa conf.form.enable_wchar
-enables characters greater than 127 in the field,
-.Fa value
-is a pointer to allocated memory for a
-.Em wchar_t
-string.
.It Fa conf.form.securech
-charachter to hide the input
-with
+charachter to hide the input with
.Dv BSDDIALOG_FIELDHIDDEN .
-.It Fa conf.form.value_without_ok
-allocate memory and set
+.It Fa conf.form.securembch
+multibyte charachter to hide the input with
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Fa conf.form.securech
+is ignored.
+.It Fa conf.form.value_wchar
+the allocated
.Fa value
-also if the OK button is not pressed.
+is a
+.Em wchar_t*
+string.
.El
.Pp
.Fn bsddialog_gauge
-builds a dialog with a bar to shows
-.Fa perc ,
-if the file descriptor
+builds a dialog with a bar to show
+.Fa perc .
+If the file descriptor
.Fa fd
is greater or equal to 0 the dialog waits to read
-.Fa separator
+.Fa sep
from it, then the first string replaces
.Fa perc
and the following strings replace
.Fa text
until the next
-.Fa separator ,
+.Fa sep ,
the loop ends reading
-.Dv EOF .
+.Fa end .
+.Pp
+.Fn bsddialog_infobox
+builds a dialog without buttons and returns instantly.
+.Pp
+.Fn bsddialog_menu
+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 {
+ const char *prefix;
+ bool on;
+ unsigned int depth;
+ const char *name;
+ const char *desc;
+ const char *bottomdesc;
+};
+.Ed
+.Pp
+.Fa prefix ,
+.Fa name
+and
+.Fa desc
+are printed at the item row.
+.Fa bottomdesc
+is printed at bottom screen if the item is focused.
+.Fa depth
+is a margin between
+.Fa prefix
+and
+.Fa name .
+At exit
+.Fa on
+is set to
+.Dv true
+if the item is selected,
+.Dv false
+otherwise.
+.Fa items
+is an array of items of
+.Fa nitem
+elements.
+.Fa menurows
+is the graphical height of the list inside the dialog, if
+.Fa cols
+is
+.Dv BSDDIALOG_AUTOSIZE
+.Fa menurows
+specifies a maximum value.
+if not
+.Dv NULL
+.Fa focusitem
+is the default item index on startup and the last focused item at exit, a
+negative value if no item is focused.
+.Pp
+.Fn bsddialog_checklist ,
+.Fn bsddialog_menu ,
+.Fn bsddialog_mixedlist
+and
+.Fn bsddialog_radiolist
+can be customized by:
+.Bl -column -compact
+.It Fa conf.menu.align_left
+align items to left, default center.
+.It Fa conf.menu.no_desc
+hide items description.
+.It Fa conf.menu.no_name
+hide items name, mutually exclusive with
+.Fa conf.menu.no_desc .
+.It Fa conf.menu.shortcut_buttons
+enable shortcut keys on buttons, default on items.
+.El
.Pp
.Fn bsddialog_mixedgauge
-draws a main bar with the
+builds a dialog with a main bar with the
.Fa mainperc
percentage and
.Fa nminibars
each one with a
.Fa minilabel
and a
+.Fa miniperc .
.Fa miniperc
-with a value between 0 and 100 or
+can be: a positive value to print a bar with a percentace, a negative constant
.Dv BSDDIALOG_MG_SUCCEEDED ,
.Dv BSDDIALOG_MG_FAILED ,
.Dv BSDDIALOG_MG_PASSED ,
@@ -711,11 +814,69 @@ with a value between 0 and 100 or
.Dv BSDDIALOG_MG_DONE ,
.Dv BSDDIALOG_MG_SKIPPED ,
.Dv BSDDIALOG_MG_INPROGRESS ,
-.Dv BSDDIALOG_MG_BLANK ,
-.Dv BSDDIALOG_MG_NA
-or
+.Dv BSDDIALOG_MG_BLANK
+to hide
+.Fa miniperc ,
+.Dv BSDDIALOG_MG_NA ,
.Dv BSDDIALOG_MG_PENDING
-to print a descriptive string.
+to print a descriptive string, otherwise
+.Dq "UNKNOWN"
+is printed.
+.Pp
+.Fn bsddialog_mixedlist
+builds a dialog with collections of checklists, radiolists and separators.
+A collection is a set defined like:
+.Pp
+.Bd -literal -offset indent -compact
+enum bsddialog_menutype {
+ BSDDIALOG_CHECKLIST,
+ BSDDIALOG_RADIOLIST,
+ BSDDIALOG_SEPARATOR,
+};
+
+struct bsddialog_menugroup {
+ enum bsddialog_menutype type;
+ unsigned int nitems;
+ struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
+};
+.Ed
+.Pp
+.Fa groups
+is an array of sets of
+.Fa ngroups
+elements.
+.Fa menurows
+is the graphical height size for the list.
+If not
+.Dv NULL ,
+.Fa focuslist
+and
+.Fa focusitem
+specify the default item on startup and the last focused item at exit, could be
+a negative value if no item is focused.
+The dialog can be customized by
+.Fa conf.menu.* ,
+see
+.Fn bsddialog_menu .
+.Pp
+.Fn bsddialog_msgbox
+builds a dialog with OK button.
+.Pp
+.Fn bsddialog_pause
+builds a dialog waiting until the timeout in
+.Fa seconds
+expires or a button is pressed.
+At exit
+.Fa seconds
+is set like remaining time.
+.Pp
+.Fn bsddialog_radiolist
+builds dialogs to select at most an item from a list via the SPACE key, can be
+customized by
+.Fa conf.menu.* .
+See
+.Fn bsddialog_menu .
.Pp
.Fn bsddialog_rangebox
to select a value between
@@ -724,17 +885,49 @@ and
.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
-in a dialog, the UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to
-navigate the file.
-OK button is renamed EXIT.
+.Fa file .
+TAB key changes button.
+Extra keys 0, h, l, k, j are available to navigate the text.
+.Dq OK
+button is renamed
+.Dq EXIT .
+.Pp
+.Fn bsddialog_timebox
+builds a dialog to choose a time.
+.Fa hh ,
+.Fa mm ,
+and
+.Fa ss
+are default values on startup, selected time at exit.
+.Pp
+.Fn bsddialog_yesno
+provides a dialog for a
+.Dq Yes-No Question ,
+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
+The graphical properties are global to the library.
+They are represented by
.Fa struct bsddialog_theme
and can be customized at runtime via the
.In bsddialog_theme.h
@@ -747,8 +940,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -760,56 +953,56 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
- int delimcolor;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
.Ed
.Pp
A member with the
.Dq f_
-prefix refers to an element with focus.
+refers to focus when an element can be in selected or not selected state.
.Pp
-.Fn bsddialog_get_theme
-sets
-.Fa theme
-like the current theme.
-.Pp
-A color can be set by the value returned by
-.Fn bsddialog_color ,
-Possible values for
-.Fa background
-and
-.Fa foreground
-are:
+.Fn bsddialog_color
+generates and returns a color to set a
+.Fa struct bsddialog_theme
+color member.
+An
+.Fa enum bsddialog_color
+can be:
.Dv BSDDIALOG_BLACK ,
.Dv BSDDIALOG_RED ,
.Dv BSDDIALOG_GREEN ,
@@ -817,29 +1010,51 @@ are:
.Dv BSDDIALOG_BLUE ,
.Dv BSDDIALOG_MAGENTA ,
.Dv BSDDIALOG_CYAN ,
-and
-.Dv BSDDIALOG_WHITE ,
+.Dv BSDDIALOG_WHITE .
.Fa flags
-specifies OR-flags, possible values:
+is an OR value:
+.Dv BSDDIALOG_BLINK ,
.Dv BSDDIALOG_BOLD ,
-.Dv BSDDIALOG_REVERSE
-and
+.Dv BSDDIALOG_HALFBRIGHT ,
+.Dv BSDDIALOG_HIGHLIGHT ,
+.Dv BSDDIALOG_REVERSE ,
.Dv BSDDIALOG_UNDERLINE .
.Pp
+.Fn bsddialog_color_attrs
+sets, if not NULL,
+.Fa foreground ,
+.Fa background ,
+.Fa flags ,
+like the properties of
+.Fa color ,
+see
+.Fn bsddialog_color .
+.Pp
+.Fn bsddialog_get_theme
+sets
+.Fa theme
+like the current runtime theme.
+.Pp
+.Fn bsddialog_hascolors
+returns
+.Dv true
+if the terminal provides colors,
+.Dv false
+otherwise.
+.Pp
.Fn bsddialog_set_theme
sets
.Fa theme
-like current theme, the changes takes effect only for dialogs built after the
-call.
+like current runtime theme.
+Changes take effect only for dialogs built after
+the call.
.Pp
-The library provides predefined themes:
+.Fn bsddialog_set_default_theme
+sets a library default theme like current theme, possible values:
.Dv BSDDIALOG_THEME_BLACKWHITE ,
-.Dv BSDDIALOG_THEME_BSDDIALOG ,
-.Dv BSDDIALOG_THEME_FLAT
-and
-.Dv BSDDIALOG_THEME_DIALOG ,
-they can be set via
-.Fn bsddialog_set_default_theme .
+.Dv BSDDIALOG_THEME_FLAT ,
+.Dv BSDDIALOG_THEME_3D .
+Changes take effect only for dialogs built after the call.
.Sh RETURN VALUES
The functions return the value
.Dv BSDDIALOG_ERROR
@@ -850,9 +1065,12 @@ returned:
.Dv BSDDIALOG_CANCEL ,
.Dv BSDDIALOG_HELP ,
.Dv BSDDIALOG_EXTRA ,
-.Dv BSDDIALOG_GENERIC1
-or
-.Dv BSDDIALOG_GENERIC2 .
+.Dv BSDDIALOG_LEFT1 ,
+.Dv BSDDIALOG_LEFT2 ,
+.Dv BSDDIALOG_LEFT3 ,
+.Dv BSDDIALOG_RIGHT1 ,
+.Dv BSDDIALOG_RIGHT2 ,
+.Dv BSDDIALOG_RIGHT3 .
.Dv BSDDIALOG_YES
and
.Dv BSDDIALOG_NO
@@ -894,10 +1112,11 @@ case BSDDIALOG_YES:
printf("Yes\\n");
break;
case BSDDIALOG_NO
- printf("NO\\n");
+ printf("No\\n");
break;
case BSDDIALOG_ERROR:
printf("Error: %s\\n", bsddialog_geterror());
+ break;
}
.Ed
.Pp
@@ -938,7 +1157,7 @@ struct bsddialog_menuitem check[2] = {
struct bsddialog_menuitem sep[1] = {
{ "3", true, 0, "Radiolist", "(desc)", "" }
};
-struct bsddialog_menuitem radio[5] = {
+struct bsddialog_menuitem radio[2] = {
{ "4", true, 0, "Name 1", "Desc 1", "Radio Bottom Desc 1" },
{ "5", false, 0, "Name 2", "Desc 2", "Radio Bottom Desc 2" }
};
@@ -975,8 +1194,7 @@ for (i = 0; i < 3; i++) {
.Ed
.Sh SEE ALSO
.Xr bsddialog 1 ,
-.Xr curses 3 ,
-.Xr ncurses 3
+.Xr curses 3
.Sh HISTORY
The
.Nm bsddialog
@@ -985,8 +1203,4 @@ library first appeared in
.Sh AUTHORS
.Nm bsddialog
was written by
-.An Alfonso Sabato Siciliano Aq Mt alf.siciliano@gmail.com .
-.Sh BUGS
-.Fn bsddialog_form
-does not resize the dialog after a terminal resize and does not provide
-scrolling for items. \ No newline at end of file
+.An Alfonso Sabato Siciliano Aq Mt asiciliano@FreeBSD.org .
diff --git a/contrib/bsddialog/lib/bsddialog.h b/contrib/bsddialog/lib/bsddialog.h
index 37f9899141c0..fc59071c6fa0 100644
--- a/contrib/bsddialog/lib/bsddialog.h
+++ b/contrib/bsddialog/lib/bsddialog.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,9 +30,9 @@
#include <stdbool.h>
-#define LIBBSDDIALOG_VERSION "0.2"
+#define LIBBSDDIALOG_VERSION "1.0.5"
-/* Exit status */
+/* Return values */
#define BSDDIALOG_ERROR -1
#define BSDDIALOG_OK 0
#define BSDDIALOG_YES BSDDIALOG_OK
@@ -42,8 +42,12 @@
#define BSDDIALOG_EXTRA 3
#define BSDDIALOG_TIMEOUT 4
#define BSDDIALOG_ESC 5
-#define BSDDIALOG_GENERIC1 6
-#define BSDDIALOG_GENERIC2 7
+#define BSDDIALOG_LEFT1 6
+#define BSDDIALOG_LEFT2 7
+#define BSDDIALOG_LEFT3 8
+#define BSDDIALOG_RIGHT1 9
+#define BSDDIALOG_RIGHT2 10
+#define BSDDIALOG_RIGHT3 11
/* Size and position */
#define BSDDIALOG_FULLSCREEN -1
@@ -64,13 +68,19 @@
#define BSDDIALOG_MG_PENDING -11
/* Form */
-#define BSDDIALOG_FIELDHIDDEN 1U
-#define BSDDIALOG_FIELDREADONLY 2U
+#define BSDDIALOG_FIELDHIDDEN 1U
+#define BSDDIALOG_FIELDREADONLY 2U
+#define BSDDIALOG_FIELDNOCOLOR 4U
+#define BSDDIALOG_FIELDCURSOREND 8U
+#define BSDDIALOG_FIELDEXTEND 16U
+#define BSDDIALOG_FIELDSINGLEBYTE 32U
struct bsddialog_conf {
bool ascii_lines;
unsigned int auto_minheight;
unsigned int auto_minwidth;
+ unsigned int auto_topmargin;
+ unsigned int auto_downmargin;
const char *bottomtitle;
bool clear;
int *get_height;
@@ -87,22 +97,29 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
- bool highlight;
+ unsigned int cols_per_row;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
- bool value_without_ok;
+ char securech;
+ char *securembch;
+ bool value_wchar;
} form;
struct {
+ const char *format;
+ } date;
+ struct {
+ bool always_active;
+ const char *left1_label;
+ const char *left2_label;
+ const char *left3_label;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -112,8 +129,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -127,16 +145,17 @@ struct bsddialog_menuitem {
const char *bottomdesc;
};
-enum bsddialog_grouptype {
+enum bsddialog_menutype {
BSDDIALOG_CHECKLIST,
BSDDIALOG_RADIOLIST,
BSDDIALOG_SEPARATOR,
};
struct bsddialog_menugroup {
- enum bsddialog_grouptype type;
+ enum bsddialog_menutype type;
unsigned int nitems;
struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
};
struct bsddialog_formitem {
@@ -156,30 +175,38 @@ struct bsddialog_formitem {
};
int bsddialog_init(void);
+int bsddialog_init_notheme(void);
+bool bsddialog_inmode(void);
int bsddialog_end(void);
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle);
+int bsddialog_backtitle_rf(struct bsddialog_conf *conf, const char *backtitle);
int bsddialog_initconf(struct bsddialog_conf *conf);
-int bsddialog_clearterminal(void);
+void bsddialog_clear(unsigned int y);
+void bsddialog_refresh(void);
const char *bsddialog_geterror(void);
/* Dialogs */
int
+bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
+
+int
bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int nitems,
struct bsddialog_menuitem *items, int *focusitem);
int
bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd);
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
int
bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items);
+ struct bsddialog_formitem *items, int *focusitem);
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep);
+ int cols, unsigned int perc, int fd, const char *sep, const char *end);
int
bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
@@ -206,7 +233,7 @@ bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int
bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int seconds);
+ int cols, unsigned int *seconds);
int
bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
diff --git a/contrib/bsddialog/lib/bsddialog_progressview.h b/contrib/bsddialog/lib/bsddialog_progressview.h
index 0cd9368a1040..5203b798bb07 100644
--- a/contrib/bsddialog/lib/bsddialog_progressview.h
+++ b/contrib/bsddialog/lib/bsddialog_progressview.h
@@ -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
@@ -36,14 +36,14 @@
extern bool bsddialog_interruptprogview;
extern bool bsddialog_abortprogview;
-extern int bsddialog_total_progview;
+extern long long int bsddialog_total_progview;
struct bsddialog_fileminibar {
const char *path;
const char *label;
int status; /* next if BSDDIALOG_MG_DONE or BSDDIALOG_MG_FAILED */
- long long size;
- long long read;
+ long long int size;
+ long long int read;
};
struct bsddialog_progviewconf {
diff --git a/contrib/bsddialog/lib/bsddialog_theme.h b/contrib/bsddialog/lib/bsddialog_theme.h
index 89381cfe28d5..77938c65b6ce 100644
--- a/contrib/bsddialog/lib/bsddialog_theme.h
+++ b/contrib/bsddialog/lib/bsddialog_theme.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,9 +29,12 @@
#define _LIBBSDDIALOG_THEME_H_
/* color flags */
-#define BSDDIALOG_BOLD 1U
-#define BSDDIALOG_REVERSE 2U
-#define BSDDIALOG_UNDERLINE 4U
+#define BSDDIALOG_BLINK 1U
+#define BSDDIALOG_BOLD 2U
+#define BSDDIALOG_HALFBRIGHT 4U
+#define BSDDIALOG_HIGHLIGHT 8U
+#define BSDDIALOG_REVERSE 16U
+#define BSDDIALOG_UNDERLINE 32U
struct bsddialog_theme {
struct {
@@ -39,8 +42,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -52,44 +55,48 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
- int delimcolor;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
enum bsddialog_default_theme {
+ BSDDIALOG_THEME_3D,
BSDDIALOG_THEME_BLACKWHITE,
- BSDDIALOG_THEME_BSDDIALOG,
- BSDDIALOG_THEME_FLAT,
- BSDDIALOG_THEME_DIALOG
+ BSDDIALOG_THEME_FLAT
};
enum bsddialog_color {
@@ -106,7 +113,11 @@ enum bsddialog_color {
int
bsddialog_color(enum bsddialog_color foreground,
enum bsddialog_color background, unsigned int flags);
+int
+bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
+ enum bsddialog_color *background, unsigned int *flags);
int bsddialog_get_theme(struct bsddialog_theme *theme);
+bool bsddialog_hascolors(void);
int bsddialog_set_default_theme(enum bsddialog_default_theme theme);
int bsddialog_set_theme(struct bsddialog_theme *theme);
diff --git a/contrib/bsddialog/lib/datebox.c b/contrib/bsddialog/lib/datebox.c
new file mode 100644
index 000000000000..66f36f5f4a99
--- /dev/null
+++ b/contrib/bsddialog/lib/datebox.c
@@ -0,0 +1,746 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <curses.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bsddialog.h"
+#include "bsddialog_theme.h"
+#include "lib_util.h"
+
+/* Calendar */
+#define MIN_YEAR_CAL 0
+#define MAX_YEAR_CAL 999999999
+#define MINHCAL 13
+#define MINWCAL 36 /* 34 calendar, 1 + 1 margins */
+/* Datebox */
+#define MIN_YEAR_DATE 0
+#define MAX_YEAR_DATE 9999
+#define MINWDATE 23 /* 3 windows and their borders */
+
+#define ISLEAP(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+
+static int minyear;
+static int maxyear;
+
+static const char *m[12] = {
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December"
+};
+
+enum operation {
+ UP_DAY,
+ DOWN_DAY,
+ LEFT_DAY,
+ RIGHT_DAY,
+ UP_MONTH,
+ DOWN_MONTH,
+ UP_YEAR,
+ DOWN_YEAR
+};
+
+/* private datebox item */
+struct dateitem {
+ enum operation up;
+ enum operation down;
+ WINDOW *win;
+ int width;
+ const char *fmt;
+ int *value;
+};
+
+static int month_days(int yy, int mm)
+{
+ int days;
+
+ if (mm == 2)
+ days = ISLEAP(yy) ? 29 : 28;
+ else if (mm == 4 || mm == 6 || mm == 9 || mm == 11)
+ days = 30;
+ else
+ days = 31;
+
+ return (days);
+}
+
+static int week_day(int yy, int mm, int dd)
+{
+ int wd;
+
+ dd += mm < 3 ? yy-- : yy - 2;
+ wd = 23*mm/9 + dd + 4 + yy/4 - yy/100 + yy/400;
+ wd %= 7;
+
+ return (wd);
+}
+
+static void
+init_date(unsigned int *year, unsigned int *month, unsigned int *day, int *yy,
+ int *mm, int *dd)
+{
+ *yy = MIN(*year, (unsigned int)maxyear);
+ if (*yy < minyear)
+ *yy = minyear;
+ *mm = MIN(*month, 12);
+ if (*mm == 0)
+ *mm = 1;
+ *dd = (*day == 0) ? 1 : *day;
+ if (*dd > month_days(*yy, *mm))
+ *dd = month_days(*yy, *mm);
+}
+
+static void datectl(enum operation op, int *yy, int *mm, int *dd)
+{
+ int ndays;
+
+ ndays = month_days(*yy, *mm);
+
+ switch (op) {
+ case UP_DAY:
+ if (*dd > 7)
+ *dd -= 7;
+ else {
+ if (*mm == 1) {
+ *yy -= 1;
+ *mm = 12;
+ } else
+ *mm -= 1;
+ ndays = month_days(*yy, *mm);
+ *dd = ndays - abs(7 - *dd);
+ }
+ break;
+ case DOWN_DAY:
+ if (*dd + 7 < ndays)
+ *dd += 7;
+ else {
+ if (*mm == 12) {
+ *yy += 1;
+ *mm = 1;
+ } else
+ *mm += 1;
+ *dd = *dd + 7 - ndays;
+ }
+ break;
+ case LEFT_DAY:
+ if (*dd > 1)
+ *dd -= 1;
+ else {
+ if (*mm == 1) {
+ *yy -= 1;
+ *mm = 12;
+ } else
+ *mm -= 1;
+ *dd = month_days(*yy, *mm);
+ }
+ break;
+ case RIGHT_DAY:
+ if (*dd < ndays)
+ *dd += 1;
+ else {
+ if (*mm == 12) {
+ *yy += 1;
+ *mm = 1;
+ } else
+ *mm += 1;
+ *dd = 1;
+ }
+ break;
+ case UP_MONTH:
+ if (*mm == 1) {
+ *mm = 12;
+ *yy -= 1;
+ } else
+ *mm -= 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case DOWN_MONTH:
+ if (*mm == 12) {
+ *mm = 1;
+ *yy += 1;
+ } else
+ *mm += 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case UP_YEAR:
+ *yy -= 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case DOWN_YEAR:
+ *yy += 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ }
+
+ if (*yy < minyear) {
+ *yy = minyear;
+ *mm = 1;
+ *dd = 1;
+ }
+ if (*yy > maxyear) {
+ *yy = maxyear;
+ *mm = 12;
+ *dd = 31;
+ }
+}
+
+static void
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev,
+ const char *fmt, int value, bool focus)
+{
+ int h, l, w;
+
+ getmaxyx(win, h, w);
+ draw_borders(conf, win, elev);
+ if (focus) {
+ l = 2 + w%2;
+ wattron(win, t.dialog.arrowcolor);
+ 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);
+ }
+
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ if (strchr(fmt, 's') != NULL)
+ mvwprintw(win, 1, 1, fmt, m[value - 1]);
+ else
+ mvwprintw(win, 1, 1, fmt, value);
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
+
+ wnoutrefresh(win);
+}
+
+static void
+print_calendar(struct bsddialog_conf *conf, WINDOW *win, int yy, int mm, int dd,
+ bool active)
+{
+ int ndays, i, y, x, wd, h, w;
+
+ getmaxyx(win, h, w);
+ wclear(win);
+ draw_borders(conf, win, RAISED);
+ if (active) {
+ wattron(win, t.dialog.arrowcolor);
+ 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);
+ }
+
+ mvwaddstr(win, 1, 5, "Sun Mon Tue Wed Thu Fri Sat");
+ ndays = month_days(yy, mm);
+ y = 2;
+ wd = week_day(yy, mm, 1);
+ for (i = 1; i <= ndays; i++) {
+ x = 5 + (4 * wd); /* x has to be 6 with week number */
+ wmove(win, y, x);
+ mvwprintw(win, y, x, "%2d", i);
+ if (i == dd) {
+ wattron(win, t.menu.f_namecolor);
+ mvwprintw(win, y, x, "%2d", i);
+ wattroff(win, t.menu.f_namecolor);
+ }
+ wd++;
+ if (wd > 6) {
+ wd = 0;
+ y++;
+ }
+ }
+
+ wnoutrefresh(win);
+}
+
+static int
+calendar_draw(struct dialog *d, bool redraw, WINDOW *yy_win, WINDOW *mm_win,
+ WINDOW *dd_win)
+{
+ int ycal, xcal;
+
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, MINHCAL, MINWCAL, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* doupdate in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, MINHCAL + HBUTTONS);
+
+ ycal = d->y + d->h - 15;
+ xcal = d->x + d->w/2 - 17;
+ mvwaddstr(d->widget, d->h - 16, d->w/2 - 17, "Month");
+ update_box(d->conf, mm_win, ycal, xcal, 3, 17, RAISED);
+ mvwaddstr(d->widget, d->h - 16, d->w/2, "Year");
+ update_box(d->conf, yy_win, ycal, xcal + 17, 3, 17, RAISED);
+ update_box(d->conf, dd_win, ycal + 3, xcal, 9, 34, RAISED);
+ wnoutrefresh(d->widget);
+
+ return (0);
+}
+
+int
+bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day)
+{
+ bool loop, focusbuttons;
+ int retval, sel, yy, mm, dd;
+ wint_t input;
+ WINDOW *yy_win, *mm_win, *dd_win;
+ struct dialog d;
+
+ CHECK_PTR(year);
+ CHECK_PTR(month);
+ CHECK_PTR(day);
+ minyear = MIN_YEAR_CAL;
+ maxyear = MAX_YEAR_CAL;
+ init_date(year, month, day, &yy, &mm, &dd);
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((yy_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for yy");
+ wbkgd(yy_win, t.dialog.color);
+ if ((mm_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for mm");
+ wbkgd(mm_win, t.dialog.color);
+ if ((dd_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for dd");
+ wbkgd(dd_win, t.dialog.color);
+ if (calendar_draw(&d, false, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+
+ sel = -1;
+ loop = focusbuttons = true;
+ while (loop) {
+ drawsquare(conf, mm_win, RAISED, "%15s", mm, sel == 0);
+ drawsquare(conf, yy_win, RAISED, "%15d", yy, sel == 1);
+ print_calendar(conf, dd_win, yy, mm, dd, sel == 2);
+ doupdate();
+
+ if (get_wch(&input) == ERR)
+ continue;
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ break;
+ case 27: /* Esc */
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
+ break;
+ case '\t': /* TAB */
+ if (focusbuttons) {
+ d.bs.curr++;
+ if (d.bs.curr >= (int)d.bs.nbuttons) {
+ focusbuttons = false;
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel++;
+ if (sel > 2) {
+ focusbuttons = true;
+ sel = -1;
+ d.bs.curr = 0;
+ }
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
+ if (focusbuttons) {
+ d.bs.curr++;
+ if (d.bs.curr >= (int)d.bs.nbuttons) {
+ focusbuttons = false;
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else if (sel == 2) {
+ datectl(RIGHT_DAY, &yy, &mm, &dd);
+ } else { /* Month or Year*/
+ sel++;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('p'):
+ case KEY_LEFT:
+ if (focusbuttons) {
+ d.bs.curr--;
+ if (d.bs.curr < 0) {
+ focusbuttons = false;
+ sel = 2;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else if (sel == 2) {
+ datectl(LEFT_DAY, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ sel = 0;
+ } else { /* sel = 0, Month */
+ focusbuttons = true;
+ sel = -1;
+ d.bs.curr = 0;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_UP:
+ if (focusbuttons) {
+ sel = 2;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
+ } else if (sel == 0) {
+ datectl(UP_MONTH, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ datectl(UP_YEAR, &yy, &mm, &dd);
+ } else { /* sel = 2 */
+ datectl(UP_DAY, &yy, &mm, &dd);
+ }
+ break;
+ case KEY_DOWN:
+ 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(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;
+ case KEY_END:
+ datectl(DOWN_MONTH, &yy, &mm, &dd);
+ break;
+ case KEY_PPAGE:
+ datectl(UP_YEAR, &yy, &mm, &dd);
+ break;
+ case KEY_NPAGE:
+ datectl(DOWN_YEAR, &yy, &mm, &dd);
+ break;
+ case KEY_F(1):
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
+ break;
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (calendar_draw(&d, true, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (calendar_draw(&d, true, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ default:
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ }
+ }
+
+ *year = yy;
+ *month = mm;
+ *day = dd;
+
+ delwin(yy_win);
+ delwin(mm_win);
+ delwin(dd_win);
+ end_dialog(&d);
+
+ return (retval);
+}
+
+static int datebox_draw(struct dialog *d, bool redraw, struct dateitem *di)
+{
+ int y, x;
+
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, 3 /*windows*/, MINWDATE, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 3 /*windows*/ + HBUTTONS);
+
+ y = d->y + d->h - 6;
+ x = (d->x + d->w / 2) - 11;
+ update_box(d->conf, di[0].win, y, x, 3, di[0].width, LOWERED);
+ mvwaddch(d->widget, d->h - 5, x - d->x + di[0].width, '/');
+ x += di[0].width + 1;
+ update_box(d->conf, di[1].win, y, x , 3, di[1].width, LOWERED);
+ mvwaddch(d->widget, d->h - 5, x - d->x + di[1].width, '/');
+ x += di[1].width + 1;
+ update_box(d->conf, di[2].win, y, x, 3, di[2].width, LOWERED);
+ wnoutrefresh(d->widget);
+
+ return (0);
+}
+
+static int
+build_dateitem(const char *format, int *yy, int *mm, int *dd,
+ struct dateitem *dt)
+{
+ int i;
+ wchar_t *wformat;
+ struct dateitem init[3] = {
+ {UP_YEAR, DOWN_YEAR, NULL, 6, "%4d", yy},
+ {UP_MONTH, DOWN_MONTH, NULL, 11, "%9s", mm},
+ {LEFT_DAY, RIGHT_DAY, NULL, 4, "%02d", dd},
+ };
+
+ for (i = 0; i < 3; i++) {
+ if ((init[i].win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_FMTERROR("Cannot build WINDOW dateitem[%d]", i);
+ wbkgd(init[i].win, t.dialog.color);
+ }
+
+ if ((wformat = alloc_mbstows(CHECK_STR(format))) == NULL)
+ RETURN_ERROR("Cannot allocate conf.date.format in wchar_t*");
+ if (format == NULL || wcscmp(wformat, L"d/m/y") == 0) {
+ dt[0] = init[2];
+ dt[1] = init[1];
+ dt[2] = init[0];
+ } else if (wcscmp(wformat, L"m/d/y") == 0) {
+ dt[0] = init[1];
+ dt[1] = init[2];
+ dt[2] = init[0];
+ } else if (wcscmp(wformat, L"y/m/d") == 0) {
+ dt[0] = init[0];
+ dt[1] = init[1];
+ dt[2] = init[2];
+ } else
+ RETURN_FMTERROR("Invalid conf.date.format=\"%s\"", format);
+ free(wformat);
+
+ return (0);
+}
+
+int
+bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day)
+{
+ bool loop, focusbuttons;
+ int retval, i, sel, yy, mm, dd;
+ wint_t input;
+ struct dateitem di[3];
+ struct dialog d;
+
+ CHECK_PTR(year);
+ CHECK_PTR(month);
+ CHECK_PTR(day);
+ minyear = MIN_YEAR_DATE;
+ maxyear = MAX_YEAR_DATE;
+ init_date(year, month, day, &yy, &mm, &dd);
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if (build_dateitem(conf->date.format, &yy, &mm, &dd, di) != 0)
+ return (BSDDIALOG_ERROR);
+ if (datebox_draw(&d, false, di) != 0)
+ return (BSDDIALOG_ERROR);
+
+ sel = -1;
+ loop = focusbuttons = true;
+ while (loop) {
+ for (i = 0; i < 3; i++)
+ drawsquare(conf, di[i].win, LOWERED, di[i].fmt,
+ *di[i].value, sel == i);
+ doupdate();
+
+ if (get_wch(&input) == ERR)
+ continue;
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ break;
+ case 27: /* Esc */
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
+ break;
+ case '\t': /* TAB */
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
+ if (focusbuttons) {
+ d.bs.curr++;
+ focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
+ true : false;
+ if (focusbuttons == false) {
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel++;
+ focusbuttons = sel > 2 ? true : false;
+ if (focusbuttons) {
+ d.bs.curr = 0;
+ }
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('p'):
+ case KEY_LEFT:
+ if (focusbuttons) {
+ d.bs.curr--;
+ focusbuttons = d.bs.curr < 0 ? false : true;
+ if (focusbuttons == false) {
+ sel = 2;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel--;
+ focusbuttons = sel < 0 ? true : false;
+ if (focusbuttons)
+ d.bs.curr = (int)d.bs.nbuttons - 1;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case '-':
+ if (focusbuttons == false)
+ datectl(di[sel].up, &yy, &mm, &dd);
+ break;
+ case KEY_UP:
+ if (focusbuttons) {
+ sel = 0;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
+ } else {
+ datectl(di[sel].up, &yy, &mm, &dd);
+ }
+ break;
+ case '+':
+ case KEY_DOWN:
+ if (focusbuttons)
+ break;
+ datectl(di[sel].down, &yy, &mm, &dd);
+ break;
+ case KEY_F(1):
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
+ break;
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (datebox_draw(&d, true, di) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (datebox_draw(&d, true, di) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ default:
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ }
+ }
+
+ *year = yy;
+ *month = mm;
+ *day = dd;
+
+ for (i = 0; i < 3 ; i++)
+ delwin(di[i].win);
+ end_dialog(&d);
+
+ return (retval);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/formbox.c b/contrib/bsddialog/lib/formbox.c
index 564fa99d69a8..a072461c43e1 100644
--- a/contrib/bsddialog/lib/formbox.c
+++ b/contrib/bsddialog/lib/formbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,10 +25,8 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <form.h>
+#include <curses.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -36,502 +34,911 @@
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define ISFIELDHIDDEN(item) (item.flags & BSDDIALOG_FIELDHIDDEN)
-#define ISFIELDREADONLY(item) (item.flags & BSDDIALOG_FIELDREADONLY)
-#define REDRAWFORM 19860214 /* magic number */
-
-/* field_userptr for private buffer and view options */
-struct myfield {
- int buflen;
- wchar_t *buf;
- int pos;
- int maxpos;
- bool secure;
- int securech;
- const char *bottomdesc;
+enum field_action {
+ MOVE_CURSOR_BEGIN,
+ MOVE_CURSOR_END,
+ MOVE_CURSOR_RIGHT,
+ MOVE_CURSOR_LEFT,
+ DEL_LETTER
+};
+
+struct privateitem {
+ const char *label; /* formitem.label */
+ unsigned int ylabel; /* formitem.ylabel */
+ unsigned int xlabel; /* formitem.xlabel */
+ unsigned int yfield; /* formitem.yfield */
+ unsigned int xfield; /* formitem.xfield */
+ bool secure; /* formitem.flags & BSDDIALOG_FIELDHIDDEN */
+ bool readonly; /* formitem.flags & BSDDIALOG_FIELDREADONLY */
+ bool fieldnocolor; /* formitem.flags & BSDDIALOG_FIELDNOCOLOR */
+ bool extendfield; /* formitem.flags & BSDDIALOG_FIELDEXTEND */
+ bool fieldonebyte; /* formitem.flags & BSDDIALOG_FIELDSINGLEBYTE */
+ bool cursorend; /* formitem.flags & BSDDIALOG_FIELDCURSOREND */
+ bool cursor; /* field cursor visibility */
+ const char *bottomdesc; /* formitem.bottomdesc */
+
+ wchar_t *privwbuf; /* formitem.value */
+ wchar_t *pubwbuf; /* string for drawitem() */
+ unsigned int maxletters; /* formitem.maxvaluelen, [priv|pub]wbuf size */
+ unsigned int nletters; /* letters in privwbuf and pubwbuf */
+ unsigned int pos; /* pos in privwbuf and pubwbuf */
+ unsigned int fieldcols; /* formitem.fieldlen */
+ unsigned int xcursor; /* position in fieldcols [0 - fieldcols-1] */
+ unsigned int xposdraw; /* first pubwbuf index to draw */
+};
+
+struct privateform {
+ WINDOW *box; /* window to draw borders */
+ WINDOW *pad;
+ unsigned int h; /* only to create pad */
+ unsigned int w; /* only to create pad */
+ unsigned int wmin; /* to refresh, w can change for FIELDEXTEND */
+ unsigned int ys; /* to refresh */
+ unsigned int ye; /* to refresh */
+ unsigned int xs; /* to refresh */
+ unsigned int xe; /* to refresh */
+ unsigned int y; /* changes moving focus around items */
+ unsigned int formheight; /* API formheight */
+ 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 nitems */
+ struct privateitem *pritems;
+ int sel; /* selected item in pritem, can be -1 */
+ bool hasbottomdesc; /* some item has bottomdesc */
};
-#define GETMYFIELD(field) ((struct myfield*)field_userptr(field))
-#define GETMYFIELD2(form) ((struct myfield*)field_userptr(current_field(form)))
-static void insertch(struct myfield *mf, int ch)
+static int
+build_privateform(struct bsddialog_conf*conf, unsigned int nitems,
+ struct bsddialog_formitem *items, struct privateform *f)
{
- int i;
+ bool insecurecursor;
+ int mbchsize;
+ unsigned int i, j, itemybeg, itemxbeg, tmp;
+ wchar_t *winit;
+ struct privateitem *item;
+
+ /* checks */
+ CHECK_ARRAY(nitems, items);
+ for (i = 0; i < nitems; i++) {
+ 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;
+
+ /* insecure ch */
+ insecurecursor = false;
+ if (conf->form.securembch != NULL) {
+ mbchsize = mblen(conf->form.securembch, MB_LEN_MAX);
+ 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') {
+ f->securewch = btowc(conf->form.securech);
+ insecurecursor = true;
+ } else {
+ f->securewch = L' ';
+ }
- if (mf->buflen > mf->maxpos)
- return;
+ /* alloc and set private items */
+ f->pritems = malloc(f->nitems * sizeof(struct privateitem));
+ if (f->pritems == NULL)
+ RETURN_ERROR("Cannot allocate internal form.pritems");
+ f->hasbottomdesc = false;
+ f->h = f->w = f->minviewrows = 0;
+ for (i = 0; i < f->nitems; i++) {
+ item = &f->pritems[i];
+ item->label = CHECK_STR(items[i].label);
+ item->ylabel = items[i].ylabel;
+ item->xlabel = items[i].xlabel;
+ item->yfield = items[i].yfield;
+ item->xfield = items[i].xfield;
+ item->secure = items[i].flags & BSDDIALOG_FIELDHIDDEN;
+ item->readonly = items[i].flags & BSDDIALOG_FIELDREADONLY;
+ item->fieldnocolor = items[i].flags & BSDDIALOG_FIELDNOCOLOR;
+ item->extendfield = items[i].flags & BSDDIALOG_FIELDEXTEND;
+ item->fieldonebyte = items[i].flags &
+ BSDDIALOG_FIELDSINGLEBYTE;
+ item->cursorend = items[i].flags & BSDDIALOG_FIELDCURSOREND;
+ item->bottomdesc = CHECK_STR(items[i].bottomdesc);
+ if (items[i].bottomdesc != NULL)
+ f->hasbottomdesc = true;
+ if (item->readonly || (item->secure && !insecurecursor))
+ item->cursor = false;
+ else
+ item->cursor = true;
+
+ item->maxletters = items[i].maxvaluelen;
+ item->privwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->privwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->privwbuf, 0, item->maxletters + 1);
+ item->pubwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->pubwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->pubwbuf, 0, item->maxletters + 1);
+
+ if ((winit = alloc_mbstows(CHECK_STR(items[i].init))) == NULL)
+ RETURN_ERROR("Cannot allocate item.init in wchar_t*");
+ wcsncpy(item->privwbuf, winit, item->maxletters);
+ wcsncpy(item->pubwbuf, winit, item->maxletters);
+ free(winit);
+ item->nletters = wcslen(item->pubwbuf);
+ if (item->secure) {
+ for (j = 0; j < item->nletters; j++)
+ item->pubwbuf[j] = f->securewch;
+ }
- for (i = mf->buflen; i >= mf->pos; i--) {
- mf->buf[i+1] = mf->buf[i];
+ item->fieldcols = items[i].fieldlen;
+ item->xposdraw = 0;
+ item->xcursor = 0;
+ item->pos = 0;
+
+ /* size and position */
+ f->h = MAX(f->h, item->ylabel);
+ f->h = MAX(f->h, item->yfield);
+ f->w = MAX(f->w, item->xlabel + strcols(item->label));
+ f->w = MAX(f->w, item->xfield + item->fieldcols);
+ if (i == 0) {
+ itemybeg = MIN(item->ylabel, item->yfield);
+ itemxbeg = MIN(item->xlabel, item->xfield);
+ } else {
+ tmp = MIN(item->ylabel, item->yfield);
+ itemybeg = MIN(itemybeg, tmp);
+ tmp = MIN(item->xlabel, item->xfield);
+ itemxbeg = MIN(itemxbeg, tmp);
+ }
+ tmp = abs((int)item->ylabel - (int)item->yfield);
+ f->minviewrows = MAX(f->minviewrows, tmp);
+ }
+ if (f->nitems > 0) {
+ f->h = f->h + 1 - itemybeg;
+ f->w -= itemxbeg;
+ f->minviewrows += 1;
+ }
+ f->wmin = f->w;
+ for (i = 0; i < f->nitems; i++) {
+ f->pritems[i].ylabel -= itemybeg;
+ f->pritems[i].yfield -= itemybeg;
+ f->pritems[i].xlabel -= itemxbeg;
+ f->pritems[i].xfield -= itemxbeg;
}
- mf->buf[mf->pos] = ch;
- mf->pos += 1;
- if (mf->pos > mf->maxpos)
- mf->pos = mf->maxpos;
- mf->buflen += 1;
- mf->buf[mf->buflen] = '\0';
+ return (0);
}
-static void shiftleft(struct myfield *mf)
+static bool fieldctl(struct privateitem *item, enum field_action act)
{
- int i, last;
+ bool change;
+ int width, oldwidth, nextwidth, cols;
+ unsigned int i;
+
+ change = false;
+ switch (act){
+ case MOVE_CURSOR_BEGIN:
+ if (item->pos == 0 && item->xcursor == 0)
+ break;
+ /* here the cursor is changed */
+ change = true;
+ item->pos = 0;
+ item->xcursor = 0;
+ item->xposdraw = 0;
+ break;
+ case MOVE_CURSOR_END:
+ while (fieldctl(item, MOVE_CURSOR_RIGHT))
+ change = true;
+ break;
+ case MOVE_CURSOR_LEFT:
+ if (item->pos == 0)
+ break;
+ /* check redundant by item->pos == 0 because of 'while' below */
+ if (item->xcursor == 0 && item->xposdraw == 0)
+ break;
+ /* here some letter to left */
+ change = true;
+ item->pos -= 1;
+ width = wcwidth(item->pubwbuf[item->pos]);
+ if (((int)item->xcursor) - width < 0) {
+ item->xcursor = 0;
+ item->xposdraw -= 1;
+ } else
+ item->xcursor -= width;
+
+ while (true) {
+ if (item->xposdraw == 0)
+ break;
+ if (item->xcursor >= item->fieldcols / 2)
+ break;
+ if (wcwidth(item->pubwbuf[item->xposdraw - 1]) +
+ item->xcursor + width > item->fieldcols)
+ break;
- for (i = mf->pos; i < mf->buflen -1; i++) {
- mf->buf[i] = mf->buf[i+1];
+ item->xposdraw -= 1;
+ item->xcursor +=
+ wcwidth(item->pubwbuf[item->xposdraw]);
+ }
+ break;
+ case DEL_LETTER:
+ if (item->nletters == 0)
+ break;
+ if (item->pos == item->nletters)
+ break;
+ /* here a letter under the cursor */
+ change = true;
+ for (i = item->pos; i < item->nletters; i++) {
+ item->privwbuf[i] = item->privwbuf[i+1];
+ item->pubwbuf[i] = item->pubwbuf[i+1];
+ }
+ item->nletters -= 1;
+ item->privwbuf[i] = L'\0';
+ item->pubwbuf[i] = L'\0';
+ break;
+ case MOVE_CURSOR_RIGHT: /* used also by "insert", see handler loop */
+ if (item->pos + 1 == item->maxletters)
+ break;
+ if (item->pos == item->nletters)
+ break;
+ /* here a change to right */
+ change = true;
+ oldwidth = wcwidth(item->pubwbuf[item->pos]);
+ item->pos += 1;
+ if (item->pos == item->nletters) { /* empty column */
+ nextwidth = 1;
+ } else { /* a letter to right */
+ nextwidth = wcwidth(item->pubwbuf[item->pos]);
+ }
+ if (item->xcursor + oldwidth + nextwidth - 1 >= item->fieldcols) {
+ cols = nextwidth;
+ item->xposdraw = item->pos;
+ while (item->xposdraw != 0) {
+ cols += wcwidth(item->pubwbuf[item->xposdraw - 1]);
+ if (cols > (int)item->fieldcols)
+ break;
+ item->xposdraw -= 1;
+ }
+ item->xcursor = 0;
+ for (i = item->xposdraw; i < item->pos ; i++)
+ item->xcursor += wcwidth(item->pubwbuf[i]);
+ }
+ else {
+ item->xcursor += oldwidth;
+ }
+
+ break;
}
- last = mf->buflen > 0 ? mf->buflen -1 : 0;
- mf->buf[last] = '\0';
- mf->buflen = last;
+ return (change);
}
-static void print_bottomdesc(struct myfield *mf)
+static bool insertch(struct privateitem *item, wchar_t wch, wchar_t securewch)
{
- move(SCREENLINES - 1, 2);
- clrtoeol();
- if (mf->bottomdesc != NULL) {
- addstr(mf->bottomdesc);
- refresh();
+ int i;
+
+ if (item->nletters >= item->maxletters)
+ return (false);
+
+ for (i = (int)item->nletters - 1; i >= (int)item->pos; i--) {
+ item->privwbuf[i+1] = item->privwbuf[i];
+ item->pubwbuf[i+1] = item->pubwbuf[i];
}
+
+ item->privwbuf[item->pos] = wch;
+ item->pubwbuf[item->pos] = item->secure ? securewch : wch;
+ item->nletters += 1;
+ item->privwbuf[item->nletters] = L'\0';
+ item->pubwbuf[item->nletters] = L'\0';
+
+ return (true);
}
-static char *w2c(wchar_t *string)
+static char* alloc_wstomb(wchar_t *wstr)
{
- int i, len;
- char *value;
-
- len = wcslen(string);
- if ((value = calloc(len + 1, sizeof(char))) == NULL)
- return NULL;
+ int len, nbytes, i;
+ char mbch[MB_LEN_MAX], *mbstr;
+
+ nbytes = MB_LEN_MAX; /* to ensure a null terminated string */
+ len = wcslen(wstr);
+ for (i = 0; i < len; i++) {
+ wctomb(mbch, wstr[i]);
+ nbytes += mblen(mbch, MB_LEN_MAX);
+ }
+ if ((mbstr = malloc(nbytes)) == NULL)
+ return (NULL);
- for (i = 0; i < len; i++)
- value[i] = string[i];
- value[i] = '\0';
+ wcstombs(mbstr, wstr, nbytes);
- return value;
+ return (mbstr);
}
static int
-return_values(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_formitem *items, FORM *form, FIELD **cfield)
+return_values(struct bsddialog_conf *conf, struct privateform *f,
+ struct bsddialog_formitem *items)
+{
+ unsigned int i;
+
+ for (i = 0; i < f->nitems; i++) {
+ if (conf->form.value_wchar)
+ items[i].value = (char*)wcsdup(f->pritems[i].privwbuf);
+ else
+ items[i].value = alloc_wstomb(f->pritems[i].privwbuf);
+
+ if (items[i].value == NULL)
+ RETURN_FMTERROR(
+ "Cannot allocate memory for item[%d].value", i);
+ }
+
+ return (0);
+}
+
+static void set_first_with_default(struct privateform *f, int *focusitem)
+{
+ unsigned int i;
+
+ f->sel = -1;
+ if (focusitem != NULL && *focusitem >=0 && *focusitem < (int)f->nitems)
+ if (f->pritems[*focusitem].readonly == false) {
+ f->sel = *focusitem;
+ return;
+ }
+ for (i = 0 ; i < f->nitems; i++)
+ if (f->pritems[i].readonly == false) {
+ f->sel = i;
+ break;
+ }
+}
+
+static unsigned int firstitem(unsigned int nitems, struct privateitem *items)
{
int i;
- struct myfield *mf;
- if (output != BSDDIALOG_OK && conf->form.value_without_ok == false)
- return (output);
+ for (i = 0; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ break;
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_FIELD);
- for (i = 0; i < nitems; i++) {
- mf = GETMYFIELD(cfield[i]);
- if (conf->form.enable_wchar) {
- items[i].value = (char*)wcsdup(mf->buf);
- } else {
- items[i].value = w2c(mf->buf);
+ return (i);
+}
+
+static unsigned int lastitem(unsigned int nitems, struct privateitem *items)
+{
+ int i;
+
+ for (i = nitems - 1; i >= 0 ; i--)
+ if (items[i].readonly == false)
+ break;
+
+ return (i);
+}
+
+static unsigned int
+previtem(unsigned int nitems, struct privateitem *items, int curritem)
+{
+ int i;
+
+ for (i = curritem - 1; i >= 0; i--)
+ if (items[i].readonly == false)
+ return(i);
+
+ for (i = nitems - 1; i > curritem - 1; i--)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static unsigned int
+nextitem(unsigned int nitems, struct privateitem *items, int curritem)
+{
+ int i;
+
+ for (i = curritem + 1; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ for (i = 0; i < curritem; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static void redrawbuttons(struct dialog *d, bool focus, bool shortcut)
+{
+ int selected;
+
+ selected = d->bs.curr;
+ if (focus == false)
+ d->bs.curr = -1;
+ d->bs.shortcut = shortcut;
+ draw_buttons(d);
+ d->bs.curr = selected;
+}
+
+static void
+drawitem(struct privateform *f, int idx, bool focus)
+{
+ int color;
+ unsigned int n, cols;
+ struct privateitem *item;
+
+ item = &f->pritems[idx];
+
+ /* Label */
+ wattron(f->pad, t.dialog.color);
+ mvwaddstr(f->pad, item->ylabel, item->xlabel, item->label);
+ wattroff(f->pad, t.dialog.color);
+
+ /* Field */
+ if (item->readonly)
+ color = t.form.readonlycolor;
+ else if (item->fieldnocolor)
+ color = t.dialog.color;
+ else
+ color = focus ? t.form.f_fieldcolor : t.form.fieldcolor;
+ wattron(f->pad, color);
+ mvwhline(f->pad, item->yfield, item->xfield, ' ', item->fieldcols);
+ n = 0;
+ cols = wcwidth(item->pubwbuf[item->xposdraw]);
+ while (cols <= item->fieldcols &&
+ item->xposdraw + n < wcslen(item->pubwbuf)) {
+ n++;
+ cols += wcwidth(item->pubwbuf[item->xposdraw + n]);
+
+ }
+ mvwaddnwstr(f->pad, item->yfield, item->xfield,
+ &item->pubwbuf[item->xposdraw], n);
+ wattroff(f->pad, color);
+
+ /* Bottom Desc */
+ if (f->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (item->bottomdesc != NULL && focus) {
+ attron(t.form.bottomdesccolor);
+ addstr(item->bottomdesc);
+ attroff(t.form.bottomdesccolor);
+ refresh();
}
- if (items[i].value == NULL)
- RETURN_ERROR("Cannot allocate memory for form value");
}
- return (output);
+ /* Cursor */
+ curs_set((focus && item->cursor) ? 1 : 0);
+ wmove(f->pad, item->yfield, item->xfield + item->xcursor);
+}
+
+/*
+ * Trick: draw 2 times an item switching focus.
+ * Problem: curses tries to optimize the rendering but sometimes it misses some
+ * updates or draws old stuff. libformw has a similar problem fixed by the
+ * same trick.
+ * Case 1: KEY_DC and KEY_BACKSPACE, deleted multicolumn letters are drawn
+ * again. It seems fixed by new items pad and prefresh(), previously WINDOW.
+ * Case2: some terminal, tmux and ssh does not show the cursor.
+ */
+#define DRAWITEM_TRICK(f, idx, focus) do { \
+ drawitem(f, idx, !focus); \
+ prefresh((f)->pad, (f)->y, 0, (f)->ys, (f)->xs, (f)->ye, (f)->xe); \
+ drawitem(f, idx, focus); \
+ prefresh((f)->pad, (f)->y, 0, (f)->ys, (f)->xs, (f)->ye, (f)->xe); \
+} while (0)
+
+static void update_formbox(struct bsddialog_conf *conf, struct privateform *f)
+{
+ int h, w;
+
+ getmaxyx(f->box, h, w);
+ draw_borders(conf, f->box, LOWERED);
+
+ if (f->viewrows < f->h) {
+ wattron(f->box, t.dialog.arrowcolor);
+ if (f->y > 0)
+ 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, DARROW(conf), 5);
+ wattroff(f->box, t.dialog.arrowcolor);
+ }
+}
+
+static void curriteminview(struct privateform *f, struct privateitem *item)
+{
+ unsigned int yup, ydown;
+
+ yup = MIN(item->ylabel, item->yfield);
+ ydown = MAX(item->ylabel, item->yfield);
+
+ /* selected item in view */
+ if (f->y > yup && f->y > 0)
+ f->y = yup;
+ if ((int)(f->y + f->viewrows) - 1 < (int)ydown)
+ f->y = ydown - f->viewrows + 1;
+ /* lower pad after a terminal expansion */
+ if (f->y > 0 && (f->h - f->y) < f->viewrows)
+ f->y = f->h - f->viewrows;
+}
+
+static int form_size_position(struct dialog *d, struct privateform *f)
+{
+ int htext, hform;
+
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ /* autosize */
+ hform = (int) f->viewrows;
+ if (f->viewrows == BSDDIALOG_AUTOSIZE)
+ hform = MAX(f->h, f->minviewrows);
+ hform += 2; /* formborders */
+
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, &htext, &d->bs, hform, f->w + 4) != 0)
+ return (BSDDIALOG_ERROR);
+ /* formheight: avoid overflow, "at most" and at least minviewrows */
+ if (d->h - BORDERS - htext - HBUTTONS < 2 + (int)f->minviewrows) {
+ f->viewrows = f->minviewrows; /* for widget_checksize() */
+ } else if (f->viewrows == BSDDIALOG_AUTOSIZE) {
+ f->viewrows = MIN(d->h - BORDERS - htext - HBUTTONS, hform) - 2;
+ f->viewrows = MAX(f->viewrows, f->minviewrows);
+ } else {
+ f->viewrows = MIN(d->h - BORDERS - htext - HBUTTONS, hform) - 2;
+ }
+
+ /* checksize */
+ if (f->viewrows < f->minviewrows)
+ RETURN_FMTERROR("formheight, current: %u needed at least %u",
+ f->viewrows, f->minviewrows);
+ if (widget_checksize(d->h, d->w, &d->bs,
+ 2 /* borders */ + f->minviewrows, f->w + 4) != 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
-form_handler(struct bsddialog_conf *conf, WINDOW *widget, struct buttons bs,
- WINDOW *formwin, FORM *form, FIELD **cfield, int nitems,
- struct bsddialog_formitem *items)
+form_draw(struct dialog *d, bool redraw, struct privateform *f, bool focusinform)
{
- bool loop, buttupdate, informwin;
- int i, chtype, output;
+ unsigned int i;
+
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ f->viewrows = f->formheight;
+ f->w = f->wmin;
+ if (form_size_position(d, f) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* doupdate() in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2 /* box borders */ + f->viewrows + HBUTTONS);
+
+ update_box(d->conf, f->box, d->y + d->h - 5 - f->viewrows, d->x + 2,
+ f->viewrows + 2, d->w - 4, LOWERED);
+
+ for (i = 0; i < f->nitems; i++) {
+ fieldctl(&f->pritems[i], MOVE_CURSOR_BEGIN);
+ if (f->pritems[i].extendfield) {
+ f->w = d->w - 6;
+ f->pritems[i].fieldcols = f->w - f->pritems[i].xfield;
+ }
+ if (f->pritems[i].cursorend)
+ fieldctl(&f->pritems[i], MOVE_CURSOR_END);
+ }
+
+ wresize(f->pad, f->h, f->w);
+ for (i = 0; i < f->nitems; i++)
+ drawitem(f, i, false);
+
+ f->ys = d->y + d->h - 5 - f->viewrows + 1;
+ f->ye = d->y + d->h - 5 ;
+ if ((int)f->w >= d->w - 6) { /* left */
+ f->xs = d->x + 3;
+ f->xe = f->xs + d->w - 7;
+ } else { /* center */
+ f->xs = d->x + 3 + (d->w - 6)/2 - f->w/2;
+ f->xe = f->xs + d->w - 5;
+ }
+
+ if (f->sel != -1) { /* at least 1 writable item */
+ redrawbuttons(d,
+ d->conf->button.always_active || !focusinform,
+ !focusinform);
+ wnoutrefresh(d->widget);
+ curriteminview(f, &f->pritems[f->sel]);
+ update_formbox(d->conf, f);
+ wnoutrefresh(f->box);
+ DRAWITEM_TRICK(f, f->sel, focusinform);
+ } else if (f->sel == -1 && f->nitems > 0) { /* all read only */
+ redrawbuttons(d, true, true);
+ wnoutrefresh(d->widget);
+ update_formbox(d->conf, f);
+ wnoutrefresh(f->box);
+ DRAWITEM_TRICK(f, 0, false); /* to refresh pad*/
+ } else { /* no item */
+ wnoutrefresh(f->box);
+ }
+
+ return (0);
+}
+
+/* API */
+int
+bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int formheight, unsigned int nitems,
+ struct bsddialog_formitem *items, int *focusitem)
+{
+ bool switchfocus, changeitem, focusinform, loop;
+ int next, retval, wchtype;
+ unsigned int i;
wint_t input;
- struct myfield *mf;
+ struct privateitem *item;
+ struct privateform form;
+ struct dialog d;
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+
+ if (build_privateform(conf, nitems, items, &form) != 0)
+ return (BSDDIALOG_ERROR);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- pos_form_cursor(form);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- curs_set(1);
- informwin = true;
+ if ((form.box = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW form box");
+ wbkgd(form.box, t.dialog.color);
+ if ((form.pad = newpad(1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW form pad");
+ wbkgd(form.pad, t.dialog.color);
+
+ set_first_with_default(&form, focusitem);
+ if (form.sel != -1) {
+ focusinform = true;
+ form.y = 0;
+ item = &form.pritems[form.sel];
+ } else {
+ item = NULL;
+ focusinform = false;
+ }
- bs.curr = -1;
- buttupdate = true;
+ form.formheight = formheight;
+ if (form_draw(&d, false, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
+ changeitem = switchfocus = false;
loop = true;
while (loop) {
- if (buttupdate) {
- draw_buttons(widget, bs, !informwin);
- wrefresh(widget);
- buttupdate = false;
- }
- wrefresh(formwin);
- chtype = get_wch(&input);
- if (chtype != KEY_CODE_YES && input > 127 &&
- conf->form.enable_wchar == false)
+ doupdate();
+ if ((wchtype = get_wch(&input)) == ERR)
continue;
switch(input) {
- case KEY_HOME:
- case KEY_PPAGE:
- case KEY_END:
- case KEY_NPAGE:
- /* disabled keys */
- break;
case KEY_ENTER:
case 10: /* Enter */
- if (informwin)
- break;
- output = return_values(conf, bs.value[bs.curr], nitems,
- items, form, cfield);
- loop = false;
+ if (focusinform && conf->button.always_active == false) {
+ next = nextitem(form.nitems, form.pritems, form.sel);
+ if (next > form.sel)
+ changeitem = true; /* needs next */
+ else
+ switchfocus = true;
+ } else {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = return_values(conf, BSDDIALOG_ESC,
- nitems, items, form, cfield);
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- if (informwin) {
- bs.curr = 0;
- informwin = false;
- curs_set(0);
+ if (focusinform) {
+ next = nextitem(form.nitems, form.pritems,
+ form.sel);
+ if (next > form.sel)
+ changeitem = true; /* needs next */
+ else
+ switchfocus = true;
} else {
- bs.curr++;
- informwin = bs.curr >= (int)bs.nbuttons ?
- true : false;
- if (informwin) {
- curs_set(1);
- pos_form_cursor(form);
+ if (d.bs.curr + 1 < (int)d.bs.nbuttons) {
+ d.bs.curr++;
+ } else {
+ d.bs.curr = 0;
+ if (form.sel != -1) {
+ switchfocus = true;
+ }
}
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
}
- buttupdate = true;
break;
case KEY_LEFT:
- if (informwin) {
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->pos > 0)
- mf->pos -= 1;
- } else {
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
+ if (focusinform) {
+ if (fieldctl(item, MOVE_CURSOR_LEFT))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ } else if (d.bs.curr > 0) {
+ d.bs.curr--;
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
+ } else if (form.sel != -1) {
+ switchfocus = true;
}
break;
case KEY_RIGHT:
- if (informwin) {
- mf = GETMYFIELD2(form);
- if (mf->pos >= mf->buflen)
- break;
- mf->pos += 1;
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_CHAR);
- } else {
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ if (focusinform) {
+ 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++;
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
+ } else if (form.sel != -1) {
+ switchfocus = true;
}
break;
+ case KEY_CTRL('p'):
case KEY_UP:
- if (nitems < 2)
- break;
- set_field_fore(current_field(form), t.form.fieldcolor);
- set_field_back(current_field(form), t.form.fieldcolor);
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- set_field_fore(current_field(form), t.form.f_fieldcolor);
- set_field_back(current_field(form), t.form.f_fieldcolor);
+ if (focusinform) {
+ next = previtem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
+ } else if (form.sel != -1) {
+ switchfocus = true;
+ }
break;
+ case KEY_CTRL('n'):
case KEY_DOWN:
- if (nitems < 2)
+ if (focusinform == false)
break;
- set_field_fore(current_field(form), t.form.fieldcolor);
- set_field_back(current_field(form), t.form.fieldcolor);
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- set_field_fore(current_field(form), t.form.f_fieldcolor);
- set_field_back(current_field(form), t.form.f_fieldcolor);
+ if (form.nitems == 1) {
+ switchfocus = true;
+ } else {
+ next = nextitem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
+ }
+ break;
+ case KEY_PPAGE:
+ if (focusinform) {
+ next = firstitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
+ }
+ break;
+ case KEY_NPAGE:
+ if (focusinform) {
+ next = lastitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
+ }
break;
case KEY_BACKSPACE:
case 127: /* Backspace */
- mf = GETMYFIELD2(form);
- if (mf->pos <= 0)
+ if (focusinform == false)
break;
- form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
- form_driver_w(form, KEY_CODE_YES, REQ_BEG_LINE);
- mf->pos = mf->pos - 1;
- for (i = 0; i < mf->pos; i++)
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_CHAR);
- shiftleft(mf);
+ if (fieldctl(item, MOVE_CURSOR_LEFT))
+ if (fieldctl(item, DEL_LETTER))
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_DC:
- form_driver_w(form, KEY_CODE_YES, REQ_DEL_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->pos < mf->buflen)
- shiftleft(mf);
+ if (focusinform == false)
+ break;
+ 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))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ break;
+ case KEY_END:
+ if (focusinform == false)
+ break;
+ if (fieldctl(item, MOVE_CURSOR_END))
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
+ curs_set(0);
+ if (f1help_dialog(conf) != 0) {
+ retval = BSDDIALOG_ERROR;
+ loop = false;
+ }
+ if (form_draw(&d, true, &form, focusinform) != 0)
return (BSDDIALOG_ERROR);
- /* No Break */
+ break;
+ case KEY_CTRL('l'):
case KEY_RESIZE:
- output = REDRAWFORM;
- loop = false;
+ if (form_draw(&d, true, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- if (informwin) {
- if (chtype == KEY_CODE_YES)
+ if (wchtype == KEY_CODE_YES)
+ break;
+ if (focusinform) {
+ if (item->fieldonebyte && wctob(input) == EOF)
break;
- mf = GETMYFIELD2(form);
- if (mf->secure)
- form_driver_w(form, chtype, mf->securech);
- else
- form_driver_w(form, chtype, input);
- insertch(mf, input);
- }
- else {
- if (shortcut_buttons(input, &bs)) {
- output = return_values(conf,
- bs.value[bs.curr], nitems, items,
- form, cfield);
+ /*
+ * MOVE_CURSOR_RIGHT manages new positions
+ * because the cursor remains on the new letter,
+ * "if" and "while" update the positions.
+ */
+ if (insertch(item, input, form.securewch)) {
+ fieldctl(item, MOVE_CURSOR_RIGHT);
+ /*
+ * no if (fieldctl), update always
+ * because it fails with maxletters.
+ */
+ DRAWITEM_TRICK(&form, form.sel, true);
+ }
+ } else {
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
break;
+ } /* end switch get_wch() */
+
+ if (switchfocus) {
+ focusinform = !focusinform;
+ d.bs.curr = 0;
+ redrawbuttons(&d,
+ conf->button.always_active || !focusinform,
+ !focusinform);
+ wnoutrefresh(d.widget);
+ if (focusinform == false)
+ DRAWITEM_TRICK(&form, form.sel, false);
+ else {
+ next = firstitem(form.nitems, form.pritems);
+ if (next == form.sel)
+ DRAWITEM_TRICK(&form, form.sel, true);
+ else
+ changeitem = true;
+ }
+ switchfocus = false;
}
- }
-
- curs_set(0);
-
- return (output);
-}
-
-static int
-form_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *formheight, int nitems,
- struct buttons bs)
-{
- int htext, wtext, menusize;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, *formheight + 2,
- linelen + 2, &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 2, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*formheight == 0) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *formheight = menusize - 2 < 0 ? 0 : menusize - 2;
- }
- else /* h autosize with fixed formheight */
- menusize = *formheight + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- } else {
- if (*formheight == 0)
- *formheight = MIN(rows-6-htext, nitems);
- }
-
- return (0);
-}
-
-static int
-form_checksize(int rows, int cols, const char *text, int formheight, int nitems,
- unsigned int linelen, struct buttons bs)
-{
- int mincols, textrow, formrows;
-
- mincols = VBORDERS;
- /* buttons */
- mincols += buttons_width(bs);
- mincols = MAX(mincols, (int)linelen + 4);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "forms (label + field)");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
-
- if (nitems > 0 && formheight == 0)
- RETURN_ERROR("fields > 0 but formheight == 0, probably "
- "terminal too small");
-
- formrows = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + formrows + textrow)
- RETURN_ERROR("Few lines for this menus");
-
- return (0);
-}
-
-int
-bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items)
-{
- int i, output, color, y, x, h, w;
- unsigned long j, maxline, mybufsize;
- struct buttons bs;
- struct myfield *myfields;
- FIELD **cfield;
- FORM *form;
- WINDOW *widget, *formwin, *textpad, *shadow;
-
- /* disable form scrolling */
- if (formheight < nitems)
- formheight = nitems;
-
- for (i = 0; i < (int)nitems; i++) {
- if (items[i].maxvaluelen == 0)
- RETURN_ERROR("maxvaluelen cannot be zero");
- if (items[i].fieldlen == 0)
- RETURN_ERROR("fieldlen cannot be zero");
- if (items[i].fieldlen > items[i].maxvaluelen)
- RETURN_ERROR("fieldlen cannot be > maxvaluelen");
- }
-
- maxline = 0;
- myfields = malloc(nitems * sizeof(struct myfield));
- cfield = calloc(nitems + 1, sizeof(FIELD*));
- for (i = 0; i < (int)nitems; i++) {
- cfield[i] = new_field(1, items[i].fieldlen, items[i].yfield-1,
- items[i].xfield-1, 0, 0);
- field_opts_off(cfield[i], O_STATIC);
- set_max_field(cfield[i], items[i].maxvaluelen);
- /* setlocale() should handle set_field_buffer() */
- set_field_buffer(cfield[i], 0, items[i].init);
-
- mybufsize = (items[i].maxvaluelen + 1) * sizeof(wchar_t);
- myfields[i].buf = malloc(mybufsize);
- memset(myfields[i].buf, 0, mybufsize);
- for (j = 0; j < items[i].maxvaluelen && j < strlen(items[i].init);
- j++)
- myfields[i].buf[j] = items[i].init[j];
-
- myfields[i].buflen = wcslen(myfields[i].buf);
-
- myfields[i].maxpos = items[i].maxvaluelen -1;
- myfields[i].pos = MIN(myfields[i].buflen, myfields[i].maxpos);
-
- myfields[i].bottomdesc = items[i].bottomdesc;
- set_field_userptr(cfield[i], &myfields[i]);
-
- field_opts_off(cfield[i], O_AUTOSKIP);
- field_opts_off(cfield[i], O_BLANK);
-
- if (ISFIELDHIDDEN(items[i])) {
- myfields[i].secure = true;
- myfields[i].securech = ' ';
- if (conf->form.securech != '\0')
- myfields[i].securech = conf->form.securech;
- }
- else
- myfields[i].secure = false;
- if (ISFIELDREADONLY(items[i])) {
- field_opts_off(cfield[i], O_EDIT);
- field_opts_off(cfield[i], O_ACTIVE);
- color = t.form.readonlycolor;
- } else {
- color = i == 0 ? t.form.f_fieldcolor : t.form.fieldcolor;
+ if (changeitem) {
+ /* useless after if(switchfocus) */
+ DRAWITEM_TRICK(&form, form.sel, false);
+ form.sel = next;
+ item = &form.pritems[form.sel];
+ curriteminview(&form, item);
+ update_formbox(conf, &form);
+ wnoutrefresh(form.box);
+ DRAWITEM_TRICK(&form, form.sel, true);
+ changeitem = false;
}
- set_field_fore(cfield[i], color);
- set_field_back(cfield[i], color);
+ } /* end while (loop) */
- maxline = MAX(maxline, items[i].xlabel + strlen(items[i].label));
- maxline = MAX(maxline, items[i].xfield + items[i].fieldlen - 1);
- }
- cfield[i] = NULL;
-
- /* disable focus with 1 item (inputbox or passwordbox) */
- if (formheight == 1 && nitems == 1 && strlen(items[0].label) == 0 &&
- items[0].xfield == 1 ) {
- set_field_fore(cfield[0], t.dialog.color);
- set_field_back(cfield[0], t.dialog.color);
- }
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (form_autosize(conf, rows, cols, &h, &w, text, maxline, &formheight,
- nitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (form_checksize(h, w, text, formheight, nitems, maxline, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
+ curs_set(0);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ if (return_values(conf, &form, items) == BSDDIALOG_ERROR)
return (BSDDIALOG_ERROR);
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
-
- formwin = new_boxed_window(conf, y + h - 3 - formheight -2, x +1,
- formheight+2, w-2, LOWERED);
-
- form = new_form(cfield);
- set_form_win(form, formwin);
- /* should be formheight */
- set_form_sub(form, derwin(formwin, nitems, w-4, 1, 1));
- post_form(form);
-
- for (i = 0; i < (int)nitems; i++)
- mvwaddstr(formwin, items[i].ylabel, items[i].xlabel,
- items[i].label);
-
- wrefresh(formwin);
-
- do {
- output = form_handler(conf, widget, bs, formwin, form, cfield,
- nitems, items);
+ if (focusitem != NULL)
+ *focusitem = form.sel;
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
-
- draw_borders(conf, formwin, formheight+2, w-2, LOWERED);
- wrefresh(formwin);
-
- refresh();
- } while (output == REDRAWFORM);
-
- unpost_form(form);
- free_form(form);
- for (i = 0; i < (int)nitems; i++) {
- free_field(cfield[i]);
- free(myfields[i].buf);
+ if (form.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
}
- free(cfield);
- free(myfields);
-
- delwin(formwin);
- end_dialog(conf, shadow, widget, textpad);
+ for (i = 0; i < form.nitems; i++) {
+ free(form.pritems[i].privwbuf);
+ free(form.pritems[i].pubwbuf);
+ }
+ delwin(form.pad);
+ delwin(form.box);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
diff --git a/contrib/bsddialog/lib/infobox.c b/contrib/bsddialog/lib/infobox.c
deleted file mode 100644
index 5a6b7c2fd692..000000000000
--- a/contrib/bsddialog/lib/infobox.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-
-#include <curses.h>
-
-#include "bsddialog.h"
-#include "lib_util.h"
-
-static int
-infobox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text)
-{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, NULL);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, false);
-
- return (0);
-}
-
-static int infobox_checksize(int rows, int cols)
-{
- if (cols < HBORDERS)
- RETURN_ERROR("Few cols, infobox needs at least width 2");
-
- if (rows < VBORDERS)
- RETURN_ERROR("Infobox needs at least height 2");
-
- return (0);
-}
-
-/* API */
-int
-bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols)
-{
- int y, x, h, w;
- WINDOW *shadow, *widget, *textpad;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_autosize(conf, rows, cols, &h, &w, text) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_checksize(h, w) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-2,
- x+w-TEXTHMARGIN);
-
- doupdate();
-
- end_dialog(conf, shadow, widget, textpad);
-
- return (BSDDIALOG_OK);
-} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/lib_util.c b/contrib/bsddialog/lib/lib_util.c
index 506003b52c8d..f042a2832eb9 100644
--- a/contrib/bsddialog/lib/lib_util.c
+++ b/contrib/bsddialog/lib/lib_util.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,22 +25,83 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
+#include <stdarg.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <wctype.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define TABLEN 4 /* Default tab len */
-#define ERRBUFLEN 1024 /* Error buffer */
+/*
+ * -1- Error and diagnostic
+ *
+ * get_error_string();
+ * set_error_string();
+ * set_fmt_error_string();
+ *
+ * ----------------------------------------------------
+ * -2- (Unicode) Multicolumn character strings
+ *
+ * alloc_mbstows();
+ * mvwaddwch();
+ * str_props();
+ * strcols();
+ *
+ * ----------------------------------------------------
+ * -3- Buttons
+ *
+ * [static] buttons_min_width();
+ * [static] draw_button();
+ * draw_buttons();
+ * set_buttons(); (to call 1 time after prepare_dialog()).
+ * shortcut_buttons();
+ *
+ * ----------------------------------------------------
+ * -4- (Auto) Sizing and (Auto) Position
+ *
+ * [static] widget_max_height(conf);
+ * [static] widget_max_width(struct bsddialog_conf *conf)
+ * [static] is_wtext_attr();
+ * [static] text_properties();
+ * [static] text_autosize();
+ * [static] text_size();
+ * [static] widget_min_height(conf, htext, hnotext, bool buttons);
+ * [static] widget_min_width(conf, wtext, minw, buttons);
+ * set_widget_size();
+ * set_widget_autosize(); (not for all dialogs).
+ * widget_checksize(); (not for all dialogs).
+ * set_widget_position();
+ * dialog_size_position(struct dialog); (not for all dialogs).
+ *
+ * ----------------------------------------------------
+ * -5- (Dialog) Widget components and utils
+ *
+ * hide_dialog(struct dialog);
+ * f1help_dialog(conf);
+ * draw_borders(conf, win, elev);
+ * update_box(conf, win, y, x, h, w, elev);
+ * rtextpad(); (helper for pnoutrefresh(textpad)).
+ *
+ * ----------------------------------------------------
+ * -6- Dialog init/build, update/draw, destroy
+ *
+ * end_dialog(struct dialog);
+ * [static] check_set_wtext_attr();
+ * [static] print_string(); (word wrapping).
+ * [static] print_textpad();
+ * draw_dialog(struct dialog);
+ * prepare_dialog(struct dialog);
+ */
+
+/*
+ * -1- Error and diagnostic
+ */
+#define ERRBUFLEN 1024
-/* Error */
static char errorbuffer[ERRBUFLEN];
const char *get_error_string(void)
@@ -53,55 +114,122 @@ void set_error_string(const char *str)
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
-/* Clear */
-int hide_widget(int y, int x, int h, int w, bool withshadow)
+void set_fmt_error_string(const char *fmt, ...)
{
- WINDOW *clear;
+ va_list arg_ptr;
- if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL)
- RETURN_ERROR("Cannot hide the widget");
- wbkgd(clear, t.screen.color);
+ va_start(arg_ptr, fmt);
+ vsnprintf(errorbuffer, ERRBUFLEN-1, fmt, arg_ptr);
+ va_end(arg_ptr);
+}
- if (withshadow)
- wrefresh(clear);
+/*
+ * -2- (Unicode) Multicolumn character strings
+ */
+wchar_t* alloc_mbstows(const char *mbstring)
+{
+ size_t charlen, nchar;
+ mbstate_t mbs;
+ const char *pmbstring;
+ wchar_t *wstring;
+
+ nchar = 1;
+ pmbstring = mbstring;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ pmbstring += charlen;
+ nchar++;
+ }
- mvwin(clear, y, x);
- wrefresh(clear);
+ if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL)
+ return (NULL);
+ mbstowcs(wstring, mbstring, nchar);
- delwin(clear);
+ return (wstring);
+}
+
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
+{
+ wchar_t ws[2];
+
+ ws[0] = wch;
+ ws[1] = L'\0';
+ mvwaddwstr(w, y, x, ws);
+}
+
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
+{
+ bool multicol;
+ int w;
+ unsigned int ncol;
+ size_t charlen, mb_cur_max;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ multicol = false;
+ mb_cur_max = MB_CUR_MAX;
+ ncol = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
+ return (-1);
+ w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ ncol += (w < 0) ? 0 : w;
+ if (w > 1 && wch != L'\t')
+ multicol = true;
+ mbstring += charlen;
+ }
+
+ if (cols != NULL)
+ *cols = ncol;
+ if (has_multi_col != NULL)
+ *has_multi_col = multicol;
return (0);
}
-/* F1 help */
-int f1help(struct bsddialog_conf *conf)
+unsigned int strcols(const char *mbstring)
{
- int output;
- struct bsddialog_conf hconf;
+ 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(mbstring, mb_cur_max, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
+ return (0);
+ w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ ncol += (w < 0) ? 0 : w;
+ mbstring += charlen;
+ }
- bsddialog_initconf(&hconf);
- hconf.title = "HELP";
- hconf.button.ok_label = "EXIT";
- hconf.clear = true;
- hconf.ascii_lines = conf->ascii_lines;
- hconf.no_lines = conf->no_lines;
- hconf.shadow = conf->shadow;
- hconf.text.highlight = conf->text.highlight;
+ return (ncol);
+}
- output = BSDDIALOG_OK;
- if (conf->key.f1_message != NULL)
- output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+/*
+ * -3- Buttons
+ */
+static int buttons_min_width(struct buttons *bs)
+{
+ unsigned int width;
- if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
- output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+ width = bs->nbuttons * bs->sizebutton;
+ if (bs->nbuttons > 0)
+ width += (bs->nbuttons - 1) * t.button.minmargin;
- return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+ return (width);
}
-/* Buttons */
static void
draw_button(WINDOW *window, int y, int x, int size, const char *text,
- bool selected, bool shortcut)
+ wchar_t first, bool selected, bool shortcut)
{
int i, color_arrows, color_shortkey, color_button;
@@ -126,129 +254,160 @@ draw_button(WINDOW *window, int y, int x, int size, const char *text,
mvwaddch(window, y, x + i, t.button.rightdelim);
wattroff(window, color_arrows);
- x = x + 1 + ((size - 2 - strlen(text))/2);
+ x = x + 1 + ((size - 2 - strcols(text))/2);
wattron(window, color_button);
mvwaddstr(window, y, x, text);
wattroff(window, color_button);
if (shortcut) {
wattron(window, color_shortkey);
- mvwaddch(window, y, x, text[0]);
+ mvwaddwch(window, y, x, first);
wattroff(window, color_shortkey);
}
}
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut)
+void draw_buttons(struct dialog *d)
{
- int i, x, startx, y, rows, cols;
+ int i, x, startx, y;
+ unsigned int newmargin, margin, wbuttons;
- getmaxyx(window, rows, cols);
- y = rows - 2;
+ y = d->h - 2;
- startx = cols/2 - buttons_width(bs)/2;
+ newmargin = d->w - BORDERS - (d->bs.nbuttons * d->bs.sizebutton);
+ newmargin /= (d->bs.nbuttons + 1);
+ newmargin = MIN(newmargin, t.button.maxmargin);
+ if (newmargin == 0) {
+ margin = t.button.minmargin;
+ wbuttons = buttons_min_width(&d->bs);
+ } else {
+ margin = newmargin;
+ wbuttons = d->bs.nbuttons * d->bs.sizebutton;
+ wbuttons += (d->bs.nbuttons + 1) * margin;
+ }
- for (i = 0; i < (int)bs.nbuttons; i++) {
- x = i * (bs.sizebutton + t.button.hmargin);
- draw_button(window, y, startx + x, bs.sizebutton, bs.label[i],
- i == bs.curr, shortcut);
+ startx = d->w/2 - wbuttons/2 + newmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ x = i * (d->bs.sizebutton + margin);
+ draw_button(d->widget, y, startx + x, d->bs.sizebutton,
+ d->bs.label[i], d->bs.first[i], i == d->bs.curr,
+ d->bs.shortcut);
}
}
void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel)
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *cancellabel)
{
int i;
#define SIZEBUTTON 8
-#define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL
+#define DEFAULT_BUTTON_LABEL OK_LABEL
#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
+ wchar_t first;
- bs->nbuttons = 0;
- bs->curr = 0;
- bs->sizebutton = 0;
+ d->bs.nbuttons = 0;
+ d->bs.curr = 0;
+ d->bs.sizebutton = 0;
+ d->bs.shortcut = shortcut;
- if (yesoklabel != NULL && conf->button.without_ok == false) {
- bs->label[0] = conf->button.ok_label != NULL ?
- conf->button.ok_label : yesoklabel;
- bs->value[0] = BSDDIALOG_OK;
- bs->nbuttons += 1;
+ if (d->conf->button.left1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT1;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_extra) {
- bs->label[bs->nbuttons] = conf->button.extra_label != NULL ?
- conf->button.extra_label : "Extra";
- bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
- bs->nbuttons += 1;
+ if (d->conf->button.left2_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left2_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT2;
+ d->bs.nbuttons += 1;
}
- if (nocancellabel != NULL && conf->button.without_cancel == false) {
- bs->label[bs->nbuttons] = conf->button.cancel_label ?
- conf->button.cancel_label : nocancellabel;
- bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
- if (conf->button.default_cancel)
- bs->curr = bs->nbuttons;
- bs->nbuttons += 1;
+ if (d->conf->button.left3_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left3_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT3;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_help) {
- bs->label[bs->nbuttons] = conf->button.help_label != NULL ?
- conf->button.help_label : "Help";
- bs->value[bs->nbuttons] = BSDDIALOG_HELP;
- bs->nbuttons += 1;
+ if (oklabel != NULL && d->conf->button.without_ok == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.ok_label != NULL ?
+ d->conf->button.ok_label : oklabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_OK;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic1_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic1_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1;
- bs->nbuttons += 1;
+ if (d->conf->button.with_extra) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.extra_label != NULL ?
+ d->conf->button.extra_label : "Extra";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_EXTRA;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic2_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic2_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
- bs->nbuttons += 1;
+ if (cancellabel != NULL && d->conf->button.without_cancel == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.cancel_label ?
+ d->conf->button.cancel_label : cancellabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_CANCEL;
+ if (d->conf->button.default_cancel)
+ d->bs.curr = d->bs.nbuttons;
+ d->bs.nbuttons += 1;
}
- if (bs->nbuttons == 0) {
- bs->label[0] = DEFAULT_BUTTON_LABEL;
- bs->value[0] = DEFAULT_BUTTON_VALUE;
- bs->nbuttons = 1;
+ if (d->conf->button.with_help) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.help_label != NULL ?
+ d->conf->button.help_label : "Help";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_HELP;
+ d->bs.nbuttons += 1;
}
- if (conf->button.default_label != NULL) {
- for (i = 0; i < (int)bs->nbuttons; i++) {
- if (strcmp(conf->button.default_label,
- bs->label[i]) == 0)
- bs->curr = i;
- }
+ if (d->conf->button.right1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT1;
+ d->bs.nbuttons += 1;
}
- bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
- for (i = 1; i < (int)bs->nbuttons; i++)
- bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
- bs->sizebutton += 2;
-}
+ if (d->conf->button.right2_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right2_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT2;
+ d->bs.nbuttons += 1;
+ }
-int buttons_width(struct buttons bs)
-{
- unsigned int width;
+ if (d->conf->button.right3_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right3_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT3;
+ d->bs.nbuttons += 1;
+ }
+
+ if (d->bs.nbuttons == 0) {
+ d->bs.label[0] = DEFAULT_BUTTON_LABEL;
+ d->bs.value[0] = DEFAULT_BUTTON_VALUE;
+ d->bs.nbuttons = 1;
+ }
- width = bs.nbuttons * bs.sizebutton;
- if (bs.nbuttons > 0)
- width += (bs.nbuttons - 1) * t.button.hmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
+ d->bs.first[i] = first;
+ }
- return (width);
+ if (d->conf->button.default_label != NULL) {
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ if (strcmp(d->conf->button.default_label,
+ d->bs.label[i]) == 0)
+ d->bs.curr = i;
+ }
+ }
+
+ d->bs.sizebutton = MAX(SIZEBUTTON - 2, strcols(d->bs.label[0]));
+ for (i = 1; i < (int)d->bs.nbuttons; i++)
+ d->bs.sizebutton = MAX(d->bs.sizebutton, strcols(d->bs.label[i]));
+ d->bs.sizebutton += 2;
}
-bool shortcut_buttons(int key, struct buttons *bs)
+bool shortcut_buttons(wint_t key, struct buttons *bs)
{
bool match;
unsigned int i;
match = false;
for (i = 0; i < bs->nbuttons; i++) {
- if (tolower(key) == tolower(bs->label[i][0])) {
+ if (towlower(key) == towlower(bs->first[i])) {
bs->curr = i;
match = true;
break;
@@ -258,233 +417,192 @@ bool shortcut_buttons(int key, struct buttons *bs)
return (match);
}
-/* Text */
-static bool is_text_attr(const char *text)
+/*
+ * -4- (Auto) Sizing and (Auto) Position
+ */
+static int widget_max_height(struct bsddialog_conf *conf)
{
- if (strnlen(text, 3) < 3)
- return (false);
-
- if (text[0] != '\\' || text[1] != 'Z')
- return (false);
-
- return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true);
-}
+ int maxheight;
-static bool check_set_text_attr(WINDOW *win, char *text)
-{
- if (is_text_attr(text) == false)
- return (false);
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
- if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) {
- wattron(win, bsddialog_color(text[2] - '0', COLOR_WHITE, 0));
- return (true);
+ if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
+ RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
+ else if (conf->y == BSDDIALOG_CENTER) {
+ maxheight -= conf->auto_topmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - top "
+ "margins <= 0");
+ } else if (conf->y > 0) {
+ maxheight -= conf->y;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - "
+ "shadow - y <= 0");
}
- switch (text[2]) {
- case 'n':
- wattron(win, t.dialog.color);
- wattrset(win, A_NORMAL);
- break;
- case 'b':
- wattron(win, A_BOLD);
- break;
- case 'B':
- wattroff(win, A_BOLD);
- break;
- case 'r':
- wattron(win, A_REVERSE);
- break;
- case 'R':
- wattroff(win, A_REVERSE);
- break;
- case 'u':
- wattron(win, A_UNDERLINE);
- break;
- case 'U':
- wattroff(win, A_UNDERLINE);
- break;
- }
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
- return (true);
+ return (maxheight);
}
-static void
-print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str,
- bool color)
+static int widget_max_width(struct bsddialog_conf *conf)
{
- int i, j, len, reallen;
+ int maxwidth;
- len = reallen = strlen(str);
- if (color) {
- i=0;
- while (i < len) {
- if (is_text_attr(str+i))
- reallen -= 3;
- i++;
- }
- }
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
- i = 0;
- while (i < len) {
- if (*x + reallen > cols) {
- *y = (*x != 0 ? *y+1 : *y);
- if (*y >= *rows) {
- *rows = *y + 1;
- wresize(win, *rows, cols);
- }
- *x = 0;
- }
- j = *x;
- while (j < cols && i < len) {
- if (color && check_set_text_attr(win, str+i)) {
- i += 3;
- } else {
- mvwaddch(win, *y, j, str[i]);
- i++;
- reallen--;
- j++;
- *x = j;
- }
- }
+ if (conf->x > 0) {
+ maxwidth -= conf->x;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow "
+ "- x <= 0");
}
+
+ return (maxwidth);
}
-static int
-print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- bool loop;
- int i, j, z, rows, cols, x, y, tablen;
- char *string;
-
- if ((string = malloc(strlen(text) + 1)) == NULL)
- RETURN_ERROR("Cannot build (analyze) text");
-
- getmaxyx(pad, rows, cols);
- tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen;
+ bool att;
- i = j = x = y = 0;
- loop = true;
- while (loop) {
- string[j] = text[i];
-
- if (strchr("\n\t ", string[j]) != NULL || string[j] == '\0') {
- string[j] = '\0';
- print_string(pad, &rows, cols, &y, &x, string,
- conf->text.highlight);
- }
-
- switch (text[i]) {
- case '\0':
- loop = false;
- break;
- case '\n':
- x = 0;
- y++;
- j = -1;
- break;
- case '\t':
- for (z = 0; z < tablen; z++) {
- if (x >= cols) {
- x = 0;
- y++;
- }
- x++;
- }
- j = -1;
- break;
- case ' ':
- x++;
- if (x >= cols) {
- x = 0;
- y++;
- }
- j = -1;
- }
+ if (wcsnlen(wtext, 3) < 3)
+ return (false);
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
+ return (false);
- if (y >= rows) {
- rows = y + 1;
- wresize(pad, rows, cols);
- }
+ att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
- j++;
- i++;
- }
+ return (att);
+}
- free(string);
+#define NL -1
+#define WS -2
+#define TB -3
- return (0);
-}
+struct textproperties {
+ int nword;
+ int *words;
+ uint8_t *wletters;
+ int maxwordcols;
+ int maxline;
+ bool hasnewline;
+};
-/* Autosize */
static int
-text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
- int mincols, bool increasecols, int *h, int *w)
+text_properties(struct bsddialog_conf *conf, const char *text,
+ struct textproperties *tp)
{
- int i, j, z, x, y;
- int tablen, wordlen, maxwordlen, nword, maxwords, line, maxwidth;
- int *words;
-#define NL -1
-#define WS -2
+ int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
+ wchar_t *wtext;
+
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
maxwords = 1024;
- if ((words = calloc(maxwords, sizeof(int))) == NULL)
+ if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
RETURN_ERROR("Cannot alloc memory for text autosize");
- tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen;
- maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS;
-
- nword = 0;
- wordlen = 0;
- maxwordlen = 0;
- i=0;
- while (true) {
- if (conf->text.highlight && is_text_attr(text + i)) {
- i += 3;
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/autosize text in wchar_t*");
+ wtextlen = wcslen(wtext);
+ if ((tp->wletters = calloc(wtextlen, sizeof(uint8_t))) == NULL)
+ RETURN_ERROR("Cannot allocate wletters for text autosizing");
+
+ tp->nword = 0;
+ tp->maxline = 0;
+ tp->maxwordcols = 0;
+ tp->hasnewline = false;
+ currlinecols = 0;
+ wordcols = 0;
+ l = 0;
+ for (i = 0; i < wtextlen; i++) {
+ if (conf->text.escape && is_wtext_attr(wtext + i)) {
+ i += 2; /* +1 for update statement */
continue;
}
- if (nword + tablen + 1 >= maxwords) {
+ if (tp->nword + 1 >= maxwords) {
maxwords += 1024;
- words = realloc(words, maxwords * sizeof(int));
- if (words == NULL)
+ tp->words = realloc(tp->words, maxwords * sizeof(int));
+ if (tp->words == NULL)
RETURN_ERROR("Cannot realloc memory for text "
"autosize");
}
- if (text[i] == '\0') {
- words[nword] = wordlen;
- maxwordlen = MAX(wordlen, maxwordlen);
- break;
- }
-
- if (strchr("\t\n ", text[i]) != NULL) {
- maxwordlen = MAX(wordlen, maxwordlen);
+ if (wcschr(L"\t\n ", wtext[i]) != NULL) {
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
- if (wordlen != 0) {
- words[nword] = wordlen;
- nword++;
- wordlen = 0;
+ if (wordcols != 0) {
+ /* line */
+ currlinecols += wordcols;
+ /* word */
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ wordcols = 0;
}
- if (text[i] == '\t') {
- for (j = 0; j < tablen; j++)
- words[nword + j] = 1;
- nword += tablen;
- } else {
- words[nword] = text[i] == '\n' ? NL : WS;
- nword++;
+ switch (wtext[i]) {
+ case L'\t':
+ /* line */
+ currlinecols += tablen;
+ /* word */
+ tp->words[tp->nword] = TB;
+ break;
+ case L'\n':
+ /* line */
+ tp->hasnewline = true;
+ tp->maxline = MAX(tp->maxline, currlinecols);
+ currlinecols = 0;
+ /* word */
+ tp->words[tp->nword] = NL;
+ break;
+ case L' ':
+ /* line */
+ currlinecols += 1;
+ /* word */
+ tp->words[tp->nword] = WS;
+ break;
}
+ tp->nword += 1;
+ } else {
+ tp->wletters[l] = wcwidth(wtext[i]);
+ wordcols += tp->wletters[l];
+ l++;
}
- else
- wordlen++;
-
- i++;
}
+ /* word */
+ if (wordcols != 0) {
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
+ }
+ /* line */
+ tp->maxline = MAX(tp->maxline, currlinecols);
+
+ free(wtext);
+
+ return (0);
+}
+
+static int
+text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
+ int maxrows, int mincols, bool increasecols, int *h, int *w)
+{
+ int i, j, x, y, z, l, line, maxwidth, tablen;
+
+ maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
if (increasecols) {
- mincols = MAX(mincols, maxwordlen);
+ mincols = MAX(mincols, tp->maxwordcols);
mincols = MAX(mincols,
- (int)conf->auto_minwidth - HBORDERS - TEXTHMARGINS);
+ (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
mincols = MIN(mincols, maxwidth);
}
@@ -492,26 +610,50 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
x = 0;
y = 1;
line=0;
- for (i = 0; i <= nword; i++) {
- if (words[i] == NL) {
+ l = 0;
+ for (i = 0; i < tp->nword; i++) {
+ switch (tp->words[i]) {
+ case TB:
+ for (j = 0; j < tablen; j++) {
+ if (x >= mincols) {
+ x = 0;
+ y++;
+ }
+ x++;
+ }
+ break;
+ case NL:
y++;
x = 0;
- }
- else if (words[i] == WS) {
+ break;
+ case WS:
x++;
if (x >= mincols) {
x = 0;
y++;
}
- }
- else {
- if (words[i] + x <= mincols)
- x += words[i];
- else {
- for (z = words[i]; z > 0; ) {
- y++;
- x = MIN(mincols, z);
- z -= x;
+ break;
+ default:
+ if (tp->words[i] + x <= mincols) {
+ x += tp->words[i];
+ for (z = 0 ; z != tp->words[i]; l++ )
+ z += tp->wletters[l];
+ } else if (tp->words[i] <= mincols) {
+ y++;
+ x = tp->words[i];
+ for (z = 0 ; z != tp->words[i]; l++ )
+ z += tp->wletters[l];
+ } else {
+ for (j = tp->words[i]; j > 0; ) {
+ y = (x == 0) ? y : y + 1;
+ z = 0;
+ while (z != j && z < mincols) {
+ z += tp->wletters[l];
+ l++;
+ }
+ x = z;
+ line = MAX(line, x);
+ j -= z;
}
}
}
@@ -520,141 +662,111 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
if (increasecols == false)
break;
- if (y <= maxrows || mincols >= maxwidth)
+ if (mincols >= maxwidth)
+ break;
+ if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
break;
mincols++;
}
- *h = (nword == 0 && words[0] == 0) ? 0 : y;
+ *h = (tp->nword == 0) ? 0 : y;
*w = MIN(mincols, line); /* wtext can be less than mincols */
- free(words);
-
return (0);
}
-int
+static int
text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
{
- int wbuttons, maxhtext;
bool changewtext;
+ int wbuttons, maxhtext;
+ struct textproperties tp;
wbuttons = 0;
- if (bs != NULL)
- wbuttons = buttons_width(*bs);
+ if (bs->nbuttons > 0)
+ wbuttons = buttons_min_width(bs);
+ /* Rows */
+ if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
+ maxhtext = widget_max_height(conf) - BORDERS - rowsnotext;
+ } else { /* fixed */
+ maxhtext = rows - BORDERS - rowsnotext;
+ }
+ if (bs->nbuttons > 0)
+ maxhtext -= 2;
+ if (maxhtext <= 0)
+ maxhtext = 1; /* text_autosize() computes always htext */
+
+ /* Cols */
if (cols == BSDDIALOG_AUTOSIZE) {
startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
changewtext = true;
} else if (cols == BSDDIALOG_FULLSCREEN) {
- startwtext = widget_max_width(conf) - VBORDERS - TEXTHMARGINS;
+ startwtext = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
changewtext = false;
} else { /* fixed */
- startwtext = cols - VBORDERS - TEXTHMARGINS;
+ startwtext = cols - BORDERS - TEXTHMARGINS;
changewtext = false;
}
- if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
- maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext;
- if (bs != NULL)
- maxhtext -= 2;
- } else { /* fixed */
- maxhtext = rows - VBORDERS - rowsnotext;
- if (bs != NULL)
- maxhtext -= 2;
- }
-
if (startwtext <= 0 && changewtext)
startwtext = 1;
- if (maxhtext <= 0 || startwtext <= 0) {
- *htext = *wtext = 0;
- return (0);
- }
- if (text_autosize(conf, text, maxhtext, startwtext, changewtext,
- htext, wtext) != 0)
+ /* Sizing calculation */
+ if (text_properties(conf, text, &tp) != 0)
+ return (BSDDIALOG_ERROR);
+ if (tp.nword > 0 && startwtext <= 0)
+ RETURN_FMTERROR("(fixed cols or fullscreen) "
+ "needed at least %d cols to draw text",
+ BORDERS + TEXTHMARGINS + 1);
+ if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
+ wtext) != 0)
return (BSDDIALOG_ERROR);
- return (0);
-}
-
-int widget_max_height(struct bsddialog_conf *conf)
-{
- int maxheight;
-
- maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.h : SCREENLINES;
- if (maxheight <= 0)
- RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
-
- if (conf->y > 0) {
- maxheight -= conf->y;
- if (maxheight <= 0)
- RETURN_ERROR("Terminal too small, screen lines - "
- "shadow - y <= 0");
- }
-
- return (maxheight);
-}
-
-int widget_max_width(struct bsddialog_conf *conf)
-{
- int maxwidth;
-
- maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.w : SCREENCOLS;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
+ free(tp.words);
+ free(tp.wletters);
- if (conf->x > 0) {
- maxwidth -= conf->x;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow "
- "- x <= 0");
- }
-
- return (maxwidth);
+ return (0);
}
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
+static int
+widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
bool withbuttons)
{
int min;
- min = 0;
-
- /* buttons */
- if (withbuttons)
- min += 2; /* buttons and border */
+ /* dialog borders */
+ min = BORDERS;
/* text */
min += htext;
- /* specific widget min height */
- min += minwidget;
+ /* specific widget lines without text */
+ min += hnotext;
+
+ /* buttons */
+ if (withbuttons)
+ min += HBUTTONS; /* buttons and their up-border */
- /* dialog borders */
- min += HBORDERS;
/* conf.auto_minheight */
min = MAX(min, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_height(conf));
return (min);
}
-int
+static int
widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
struct buttons *bs)
{
- int min, delimtitle;
+ int min, delimtitle, wbottomtitle, wtitle;
min = 0;
/* buttons */
- if (bs != NULL)
- min += buttons_width(*bs);
+ if (bs->nbuttons > 0)
+ min += buttons_min_width(bs);
/* text */
if (wtext > 0)
@@ -666,19 +778,20 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
/* title */
if (conf->title != NULL) {
delimtitle = t.dialog.delimtitle ? 2 : 0;
- min = MAX(min, (int)strlen(conf->title) + 2 + delimtitle);
+ wtitle = strcols(conf->title);
+ min = MAX(min, wtitle + 2 + delimtitle);
}
/* bottom title */
- if (conf->bottomtitle != NULL)
- min = MAX(min, (int)strlen(conf->bottomtitle) + 4);
+ if (conf->bottomtitle != NULL) {
+ wbottomtitle = strcols(conf->bottomtitle);
+ min = MAX(min, wbottomtitle + 4);
+ }
/* dialog borders */
- min += VBORDERS;
+ min += BORDERS;
/* conf.auto_minwidth */
min = MAX(min, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_width(conf));
return (min);
}
@@ -695,11 +808,8 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
*h = maxheight;
else if (rows < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) height");
- else if (rows > BSDDIALOG_AUTOSIZE) {
- if ((*h = rows) > maxheight)
- RETURN_ERROR("Height too big (> terminal height - "
- "shadow)");
- }
+ else if (rows > BSDDIALOG_AUTOSIZE) /* fixed rows */
+ *h = MIN(rows, maxheight); /* rows is at most maxheight */
/* rows == AUTOSIZE: each widget has to set its size */
if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
@@ -709,21 +819,78 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
*w = maxwidth;
else if (cols < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) width");
- else if (cols > BSDDIALOG_AUTOSIZE) {
- if ((*w = cols) > maxwidth)
- RETURN_ERROR("Width too big (> terminal width - "
- "shadow)");
- }
+ else if (cols > BSDDIALOG_AUTOSIZE) /* fixed cols */
+ *w = MIN(cols, maxwidth); /* cols is at most maxwidth */
/* cols == AUTOSIZE: each widget has to set its size */
return (0);
}
int
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw)
+{
+ int htext, wtext;
+
+ if (rows == BSDDIALOG_AUTOSIZE || cols == BSDDIALOG_AUTOSIZE ||
+ rowstext != NULL) {
+ if (text_size(conf, rows, cols, text, bs, hnotext, minw,
+ &htext, &wtext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (rowstext != NULL)
+ *rowstext = htext;
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = widget_min_height(conf, htext, hnotext, bs->nbuttons > 0);
+ *h = MIN(*h, widget_max_height(conf));
+ }
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = widget_min_width(conf, wtext, minw, bs);
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ return (0);
+}
+
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw)
+{
+ int minheight, minwidth;
+
+ minheight = BORDERS + hnotext;
+ if (bs->nbuttons > 0)
+ minheight += HBUTTONS;
+ if (h < minheight)
+ RETURN_FMTERROR("Current rows: %d, needed at least: %d",
+ h, minheight);
+
+ minwidth = 0;
+ if (bs->nbuttons > 0)
+ minwidth = buttons_min_width(bs);
+ minwidth = MAX(minwidth, minw);
+ minwidth += BORDERS;
+ if (w < minwidth)
+ RETURN_FMTERROR("Current cols: %d, nedeed at least %d",
+ w, minwidth);
+
+ return (0);
+}
+
+int
set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
{
- if (conf->y == BSDDIALOG_CENTER)
- *y = SCREENLINES/2 - (h + t.shadow.h)/2;
+ int hshadow = conf->shadow ? (int)t.shadow.y : 0;
+ int wshadow = conf->shadow ? (int)t.shadow.x : 0;
+
+ if (conf->y == BSDDIALOG_CENTER) {
+ *y = SCREENLINES/2 - (h + hshadow)/2;
+ if (*y < (int)conf->auto_topmargin)
+ *y = conf->auto_topmargin;
+ if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin)
+ *y = SCREENLINES - h - hshadow - conf->auto_downmargin;
+ }
else if (conf->y < BSDDIALOG_CENTER)
RETURN_ERROR("Negative begin y (less than -1)");
else if (conf->y >= SCREENLINES)
@@ -731,13 +898,13 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
else
*y = conf->y;
- if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > SCREENLINES)
+ if (*y + h + hshadow > SCREENLINES)
RETURN_ERROR("The lower of the box under the terminal "
"(begin Y + height (+ shadow) > terminal lines)");
if (conf->x == BSDDIALOG_CENTER)
- *x = SCREENCOLS/2 - (w + t.shadow.w)/2;
+ *x = SCREENCOLS/2 - (w + wshadow)/2;
else if (conf->x < BSDDIALOG_CENTER)
RETURN_ERROR("Negative begin x (less than -1)");
else if (conf->x >= SCREENCOLS)
@@ -745,228 +912,456 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
else
*x = conf->x;
- if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > SCREENCOLS)
+ if ((*x + w + wshadow) > SCREENCOLS)
RETURN_ERROR("The right of the box over the terminal "
"(begin X + width (+ shadow) > terminal cols)");
return (0);
}
-/* Widgets builders */
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev)
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext)
+{
+ 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, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (widget_checksize(d->h, d->w, &d->bs, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
+}
+
+/*
+ * -5- Widget components and utilities
+ */
+int hide_dialog(struct dialog *d)
{
+ WINDOW *clear;
+
+ if ((clear = newwin(d->h, d->w, d->y, d->x)) == NULL)
+ RETURN_ERROR("Cannot hide the widget");
+ wbkgd(clear, t.screen.color);
+ wrefresh(clear);
+
+ if (d->conf->shadow) {
+ mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
+ wrefresh(clear);
+ }
+
+ delwin(clear);
+
+ return (0);
+}
+
+int f1help_dialog(struct bsddialog_conf *conf)
+{
+ int output;
+ struct bsddialog_conf hconf;
+
+ bsddialog_initconf(&hconf);
+ hconf.title = "HELP";
+ hconf.button.ok_label = "EXIT";
+ hconf.clear = true;
+ hconf.ascii_lines = conf->ascii_lines;
+ hconf.no_lines = conf->no_lines;
+ hconf.shadow = conf->shadow;
+ hconf.text.escape = conf->text.escape;
+
+ output = BSDDIALOG_OK;
+ if (conf->key.f1_message != NULL)
+ output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+
+ if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
+ output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+
+ return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+}
+
+void draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev)
+{
+ 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;
}
- leftcolor = elev == RAISED ?
+ getmaxyx(win, h, w);
+ 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, cols-1, tr);
- mvwvline(win, 1, cols-1, rs, rows-2);
- mvwaddch(win, rows-1, cols-1, br);
- mvwhline(win, rows-1, 1, bs, cols-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);
}
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
enum elevation elev)
{
- WINDOW *win;
+ wclear(win);
+ wresize(win, h, w);
+ mvwin(win, y, x);
+ draw_borders(conf, win, elev);
+}
- if ((win = newwin(rows, cols, y, x)) == NULL) {
- set_error_string("Cannot build boxed window");
- return (NULL);
- }
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext)
+{
+ pnoutrefresh(d->textpad, ytext, xtext,
+ d->y + BORDER + upnotext,
+ d->x + BORDER + TEXTHMARGIN,
+ d->y + d->h - 1 - downnotext - BORDER,
+ d->x + d->w - TEXTHMARGIN - BORDER);
+}
- wbkgd(win, t.dialog.color);
+/*
+ * -6- Dialog init/build, update/draw, destroy
+ */
+void end_dialog(struct dialog *d)
+{
+ if (d->conf->sleep > 0)
+ sleep(d->conf->sleep);
- draw_borders(conf, win, rows, cols, elev);
+ delwin(d->textpad);
+ delwin(d->widget);
+ if (d->conf->shadow)
+ delwin(d->shadow);
- return (win);
+ if (d->conf->clear)
+ hide_dialog(d);
+
+ if (d->conf->get_height != NULL)
+ *d->conf->get_height = d->h;
+ if (d->conf->get_width != NULL)
+ *d->conf->get_width = d->w;
}
-static int
-draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons)
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
{
- int h, w, ts, ltee, rtee;
+ enum bsddialog_color bg;
+
+ if (is_wtext_attr(wtext) == false)
+ return (false);
+
+ if ((wtext[2] >= L'0') && (wtext[2] <= L'7')) {
+ bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
+ wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
+ return (true);
+ }
- ts = conf->ascii_lines ? '-' : ACS_HLINE;
- ltee = conf->ascii_lines ? '+' : ACS_LTEE;
- rtee = conf->ascii_lines ? '+' : ACS_RTEE;
+ switch (wtext[2]) {
+ case L'n':
+ wattron(win, t.dialog.color);
+ wattrset(win, A_NORMAL);
+ break;
+ case L'b':
+ wattron(win, A_BOLD);
+ break;
+ case L'B':
+ wattroff(win, A_BOLD);
+ break;
+ case L'd':
+ wattron(win, A_DIM);
+ break;
+ case L'D':
+ wattroff(win, A_DIM);
+ break;
+ case L'k':
+ wattron(win, A_BLINK);
+ break;
+ case L'K':
+ wattroff(win, A_BLINK);
+ break;
+ case L'r':
+ wattron(win, A_REVERSE);
+ break;
+ case L'R':
+ wattroff(win, A_REVERSE);
+ break;
+ case L's':
+ wattron(win, A_STANDOUT);
+ break;
+ case L'S':
+ wattroff(win, A_STANDOUT);
+ break;
+ case L'u':
+ wattron(win, A_UNDERLINE);
+ break;
+ case L'U':
+ wattroff(win, A_UNDERLINE);
+ break;
+ }
- getmaxyx(widget, h, w);
+ return (true);
+}
- if (conf->shadow)
- wnoutrefresh(shadow);
+static void
+print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
+ bool color)
+{
+ int charwidth, i, j, strlen, strwidth;
+ wchar_t ws[2];
- draw_borders(conf, widget, h, w, RAISED);
+ ws[1] = L'\0';
- if (conf->title != NULL) {
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, 0, w/2-strlen(conf->title)/2-1, rtee);
- wattroff(widget, t.dialog.lineraisecolor);
- }
- wattron(widget, t.dialog.titlecolor);
- mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title);
- wattroff(widget, t.dialog.titlecolor);
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- waddch(widget, ltee);
- wattroff(widget, t.dialog.lineraisecolor);
+ strlen = wcslen(str);
+ if (color) {
+ strwidth = 0;
+ i=0;
+ while (i < strlen) {
+ if (is_wtext_attr(str+i) == false) {
+ strwidth += wcwidth(str[i]);
+ i++;
+ } else {
+ i += 3;
+ }
}
- }
+ } else
+ strwidth = wcswidth(str, strlen);
- if (bs != NULL) {
- if (conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, h-3, 0, ltee);
- mvwhline(widget, h-3, 1, ts, w-2);
- wattroff(widget, t.dialog.lineraisecolor);
+ i = 0;
+ while (i < strlen) {
+ if (*x + strwidth > cols) {
+ if (*x != 0)
+ *y = *y + 1;
+ if (*y >= *rows) {
+ *rows = *y + 1;
+ wresize(win, *rows, cols);
+ }
+ *x = 0;
+ }
+ j = *x;
+ while (i < strlen) {
+ if (color && check_set_wtext_attr(win, str+i)) {
+ i += 3;
+ continue;
+ }
- wattron(widget, t.dialog.linelowercolor);
- mvwaddch(widget, h-3, w-1, rtee);
- wattroff(widget, t.dialog.linelowercolor);
+ 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++;
}
- draw_buttons(widget, *bs, shortcutbuttons);
}
+}
- if (conf->bottomtitle != NULL) {
- wattron(widget, t.dialog.bottomtitlecolor);
- wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1);
- waddch(widget, ' ');
- waddstr(widget, conf->bottomtitle);
- waddch(widget, ' ');
- wattroff(widget, t.dialog.bottomtitlecolor);
- }
+static int
+print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
+{
+ bool loop;
+ int i, j, z, rows, cols, x, y, tablen;
+ wchar_t *wtext, *string;
- wnoutrefresh(widget);
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- if (textpad != NULL && text != NULL) /* textbox */
- if (print_textpad(conf, textpad, text) !=0)
- return (BSDDIALOG_ERROR);
+ if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
+ RETURN_ERROR("Cannot build (analyze) text");
- return (0);
-}
+ getmaxyx(pad, rows, cols);
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
-int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons)
-{
- int error;
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = wtext[i];
- if (conf->shadow) {
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
- }
+ if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
+ string[j] = L'\0';
+ print_string(pad, &rows, cols, &y, &x, string,
+ conf->text.escape);
+ }
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
+ switch (wtext[i]) {
+ case L'\0':
+ loop = false;
+ break;
+ case L'\n':
+ x = 0;
+ y++;
+ j = -1;
+ break;
+ case L'\t':
+ for (z = 0; z < tablen; z++) {
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ x++;
+ }
+ j = -1;
+ break;
+ case L' ':
+ x++;
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ j = -1;
+ }
- if (textpad != NULL) {
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - TEXTHMARGINS);
+ if (y >= rows) {
+ rows = y + 1;
+ wresize(pad, rows, cols);
+ }
+
+ j++;
+ i++;
}
- error = draw_dialog(conf, shadow, widget, textpad, text, bs,
- shortcutbuttons);
+ free(wtext);
+ free(string);
- return (error);
+ return (0);
}
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons)
+int draw_dialog(struct dialog *d)
{
- int error;
+ int wtitle, wbottomtitle;
+ cchar_t ts, ltee, rtee;
- if (conf->shadow) {
- *shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w);
- if (*shadow == NULL)
- RETURN_ERROR("Cannot build shadow");
- wbkgd(*shadow, t.shadow.color);
+ if (d->conf->ascii_lines) {
+ setcchar(&ts, L"-", 0, 0, NULL);
+ setcchar(&ltee, L"+", 0, 0,NULL);
+ setcchar(&rtee, L"+", 0, 0, NULL);
+ } else {
+ ts = *WACS_HLINE;
+ ltee = *WACS_LTEE;
+ rtee = *WACS_RTEE;
}
- if ((*widget = new_boxed_window(conf, y, x, h, w, RAISED)) == NULL) {
- if (conf->shadow)
- delwin(*shadow);
- return (BSDDIALOG_ERROR);
+ if (d->conf->shadow) {
+ wclear(d->shadow);
+ wresize(d->shadow, d->h, d->w);
+ mvwin(d->shadow, d->y + t.shadow.y, d->x + t.shadow.x);
+ wnoutrefresh(d->shadow);
}
- if (textpad != NULL && text != NULL) { /* textbox */
- *textpad = newpad(1, w - HBORDERS - TEXTHMARGINS);
- if (*textpad == NULL) {
- delwin(*widget);
- if (conf->shadow)
- delwin(*shadow);
- RETURN_ERROR("Cannot build the pad window for text");
+ wclear(d->widget);
+ wresize(d->widget, d->h, d->w);
+ mvwin(d->widget, d->y, d->x);
+ draw_borders(d->conf, d->widget, RAISED);
+
+ if (d->conf->title != NULL) {
+ if ((wtitle = strcols(d->conf->title)) < 0)
+ return (BSDDIALOG_ERROR);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwadd_wch(d->widget, 0, d->w/2 - wtitle/2 -1, &rtee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+ wattron(d->widget, t.dialog.titlecolor);
+ mvwaddstr(d->widget, 0, d->w/2 - wtitle/2, d->conf->title);
+ wattroff(d->widget, t.dialog.titlecolor);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ wadd_wch(d->widget, &ltee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
}
- wbkgd(*textpad, t.dialog.color);
}
- error = draw_dialog(conf, *shadow, *widget,
- textpad == NULL ? NULL : *textpad, text, bs, shortcutbuttons);
+ if (d->bs.nbuttons > 0) {
+ if (d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwadd_wch(d->widget, d->h-3, 0, &ltee);
+ mvwhline_set(d->widget, d->h-3, 1, &ts, d->w-2);
+ wattroff(d->widget, t.dialog.lineraisecolor);
- return (error);
-}
+ wattron(d->widget, t.dialog.linelowercolor);
+ mvwadd_wch(d->widget, d->h-3, d->w-1, &rtee);
+ wattroff(d->widget, t.dialog.linelowercolor);
+ }
+ draw_buttons(d);
+ }
-void
-end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad)
-{
- int y, x, h, w;
+ if (d->conf->bottomtitle != NULL) {
+ if ((wbottomtitle = strcols(d->conf->bottomtitle)) < 0)
+ return (BSDDIALOG_ERROR);
+ wattron(d->widget, t.dialog.bottomtitlecolor);
+ wmove(d->widget, d->h - 1, d->w/2 - wbottomtitle/2 - 1);
+ waddch(d->widget, ' ');
+ waddstr(d->widget, d->conf->bottomtitle);
+ waddch(d->widget, ' ');
+ wattroff(d->widget, t.dialog.bottomtitlecolor);
+ }
- getbegyx(widget, y, x);
- getmaxyx(widget, h, w);
+ wnoutrefresh(d->widget);
- if (conf->sleep > 0)
- sleep(conf->sleep);
+ wclear(d->textpad);
+ /* `infobox "" 0 2` fails but text is empty and textpad remains 1 1 */
+ wresize(d->textpad, 1, d->w - BORDERS - TEXTHMARGINS);
- if (textpad != NULL)
- delwin(textpad);
+ if (print_textpad(d->conf, d->textpad, d->text) != 0)
+ return (BSDDIALOG_ERROR);
- delwin(widget);
+ d->built = true;
- if (conf->shadow)
- delwin(shadow);
+ return (0);
+}
- if (conf->clear)
- hide_widget(y, x, h, w, conf->shadow);
+int
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d)
+{
+ CHECK_PTR(conf);
+
+ d->built = false;
+ d->conf = conf;
+ d->rows = rows;
+ d->cols = cols;
+ d->text = CHECK_STR(text);
+ d->bs.nbuttons = 0;
+
+ if (d->conf->shadow) {
+ if ((d->shadow = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW shadow");
+ wbkgd(d->shadow, t.shadow.color);
+ }
- if (conf->get_height != NULL)
- *conf->get_height = h;
- if (conf->get_width != NULL)
- *conf->get_width = w;
-}
+ if ((d->widget = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW widget");
+ wbkgd(d->widget, t.dialog.color);
+
+ /* fake for textpad */
+ if ((d->textpad = newpad(1, 1)) == NULL)
+ RETURN_ERROR("Cannot build the pad WINDOW for text");
+ wbkgd(d->textpad, t.dialog.color);
+
+ return (0);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/lib_util.h b/contrib/bsddialog/lib/lib_util.h
index 6ebc73cf1055..1adc34f3b80a 100644
--- a/contrib/bsddialog/lib/lib_util.h
+++ b/contrib/bsddialog/lib/lib_util.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,106 +28,141 @@
#ifndef _LIBBSDDIALOG_UTIL_H_
#define _LIBBSDDIALOG_UTIL_H_
-#define HBORDERS 2
-#define VBORDERS 2
+#define BORDER 1
+#define BORDERS (BORDER + BORDER)
#define TEXTHMARGIN 1
#define TEXTHMARGINS (TEXTHMARGIN + TEXTHMARGIN)
+#define HBUTTONS 2
+#define OK_LABEL "OK"
+#define CANCEL_LABEL "Cancel"
-/* current theme */
+/* theme util */
extern struct bsddialog_theme t;
+extern bool hastermcolors;
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
/* debug */
-#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
- mvprintw(y, x, fmt, __VA_ARGS__); \
- refresh(); \
+#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
+ mvprintw(y, x, fmt, __VA_ARGS__); \
+ refresh(); \
} while (0)
-
-/* error buffer */
-const char *get_error_string(void);
-void set_error_string(const char *string);
-
-#define RETURN_ERROR(str) do { \
- set_error_string(str); \
- return (BSDDIALOG_ERROR); \
+/* error and diagnostic */
+#define RETURN_ERROR(str) do { \
+ set_error_string(str); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+#define RETURN_FMTERROR(fmt, ...) do { \
+ set_fmt_error_string(fmt, __VA_ARGS__); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+/* check ptr */
+#define CHECK_PTR(p) do { \
+ if (p == NULL) \
+ RETURN_ERROR("*" #p " is NULL"); \
+} while (0)
+#define CHECK_ARRAY(nitem, a) do { \
+ 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); \
} while (0)
-/* buttons */
+/* internal types */
+enum elevation { RAISED, LOWERED };
+
struct buttons {
unsigned int nbuttons;
-#define MAXBUTTONS 6 /* ok + extra + cancel + help + 2 generics */
+#define MAXBUTTONS 10 /* 3left + ok + extra + cancel + help + 3 right */
const char *label[MAXBUTTONS];
+ bool shortcut;
+ wchar_t first[MAXBUTTONS];
int value[MAXBUTTONS];
int curr;
+#define BUTTONVALUE(bs) bs.value[bs.curr]
unsigned int sizebutton; /* including left and right delimiters */
};
-#define BUTTON_OK_LABEL "OK"
-#define BUTTON_CANCEL_LABEL "Cancel"
-void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel);
-
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut);
-
-int buttons_width(struct buttons bs);
-bool shortcut_buttons(int key, struct buttons *bs);
+struct dialog {
+ bool built; /* true after the first draw_dialog() */
+ struct bsddialog_conf *conf; /* Checked API conf */
+ WINDOW *widget; /* Size and position refer to widget */
+ int y, x; /* Current position, API conf.[y|x]: -1, >=0 */
+ int rows, cols; /* API rows and cols: -1, 0, >0 */
+ int h, w; /* Current height and width */
+ const char *text; /* Checked API text, at least "" */
+ WINDOW *textpad; /* Fake for textbox */
+ struct buttons bs; /* bs.nbuttons = 0 for no buttons */
+ WINDOW *shadow;
+};
-/* help window with F1 key */
-int f1help(struct bsddialog_conf *conf);
+/* error and diagnostic */
+const char *get_error_string(void);
+void set_error_string(const char *string);
+void set_fmt_error_string(const char *fmt, ...);
-/* cleaner */
-int hide_widget(int y, int x, int h, int w, bool withshadow);
+/* multicolumn character string */
+unsigned int strcols(const char *mbstring);
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col);
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch);
+wchar_t* alloc_mbstows(const char *mbstring);
-/* (auto) size and (auto) position */
-#define SCREENLINES (getmaxy(stdscr))
-#define SCREENCOLS (getmaxx(stdscr))
+/* buttons */
+void
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *canclabel);
+void draw_buttons(struct dialog *d);
+bool shortcut_buttons(wint_t key, struct buttons *bs);
-int
-text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
- struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext);
+/* widget utils */
+int hide_dialog(struct dialog *d);
+int f1help_dialog(struct bsddialog_conf *conf);
-int widget_max_height(struct bsddialog_conf *conf);
-int widget_max_width(struct bsddialog_conf *conf);
+void
+draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev);
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
- bool withbuttons);
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev);
-int
-widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
- struct buttons *bs);
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext);
+/* (auto) sizing and (auto) position */
int
set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h,
int *w);
int
-set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw);
-/* widget builders */
-enum elevation { RAISED, LOWERED };
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw);
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev);
+int
+set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
- enum elevation elev);
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext);
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons);
+/* dialog */
+void end_dialog(struct dialog *d);
+int draw_dialog(struct dialog *d);
int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons);
-
-void
-end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad);
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d);
-#endif \ No newline at end of file
+#endif
diff --git a/contrib/bsddialog/lib/libbsddialog.c b/contrib/bsddialog/lib/libbsddialog.c
index 761bdc3efa77..cdb5e1e251dc 100644
--- a/contrib/bsddialog/lib/libbsddialog.c
+++ b/contrib/bsddialog/lib/libbsddialog.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,18 +26,19 @@
*/
#include <curses.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-int bsddialog_init(void)
+#define DEFAULT_COLS_PER_ROW 10 /* Default conf.text.columns_per_row */
+
+static bool in_bsddialog_mode = false;
+
+int bsddialog_init_notheme(void)
{
int i, j, c, error;
- enum bsddialog_default_theme theme;
set_error_string("");
@@ -54,6 +55,7 @@ int bsddialog_init(void)
bsddialog_end();
RETURN_ERROR("Cannot init curses (keypad and cursor)");
}
+ in_bsddialog_mode = true;
c = 1;
error += start_color();
@@ -64,13 +66,25 @@ int bsddialog_init(void)
}
}
- if (error == OK && has_colors())
+ hastermcolors = (error == OK && has_colors()) ? true : false;
+
+ return (BSDDIALOG_OK);
+}
+
+int bsddialog_init(void)
+{
+ enum bsddialog_default_theme theme;
+
+ bsddialog_init_notheme();
+
+ if (bsddialog_hascolors())
theme = BSDDIALOG_THEME_FLAT;
else
theme = BSDDIALOG_THEME_BLACKWHITE;
if (bsddialog_set_default_theme(theme) != 0) {
bsddialog_end();
+ in_bsddialog_mode = false;
return (BSDDIALOG_ERROR);
}
@@ -81,22 +95,45 @@ int bsddialog_end(void)
{
if (endwin() != OK)
RETURN_ERROR("Cannot end curses (endwin)");
+ in_bsddialog_mode = false;
return (BSDDIALOG_OK);
}
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle)
{
- mvaddstr(0, 1, backtitle);
- if (conf->no_lines != true)
- mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE,
- SCREENCOLS - 2);
+ CHECK_PTR(conf);
+
+ move(0, 1);
+ clrtoeol();
+ addstr(CHECK_STR(backtitle));
+ if (conf->no_lines != true) {
+ if (conf->ascii_lines)
+ mvhline(1, 1, '-', SCREENCOLS - 2);
+ else
+ mvhline_set(1, 1, WACS_HLINE, SCREENCOLS - 2);
+ }
- refresh();
+ wnoutrefresh(stdscr);
return (BSDDIALOG_OK);
}
+int bsddialog_backtitle_rf(struct bsddialog_conf *conf, const char *backtitle)
+{
+ int rv;
+
+ rv = bsddialog_backtitle(conf, backtitle);
+ doupdate();
+
+ return (rv);
+}
+
+bool bsddialog_inmode(void)
+{
+ return (in_bsddialog_mode);
+}
+
const char *bsddialog_geterror(void)
{
return (get_error_string());
@@ -104,24 +141,25 @@ const char *bsddialog_geterror(void)
int bsddialog_initconf(struct bsddialog_conf *conf)
{
- if (conf == NULL)
- RETURN_ERROR("conf is NULL");
- if (sizeof(*conf) != sizeof(struct bsddialog_conf))
- RETURN_ERROR("Bad conf size");
+ CHECK_PTR(conf);
memset(conf, 0, sizeof(struct bsddialog_conf));
conf->y = BSDDIALOG_CENTER;
conf->x = BSDDIALOG_CENTER;
conf->shadow = true;
+ conf->text.cols_per_row = DEFAULT_COLS_PER_ROW;
return (BSDDIALOG_OK);
}
-int bsddialog_clearterminal(void)
+void bsddialog_refresh(void)
{
- if (clear() != OK)
- RETURN_ERROR("Cannot clear the terminal");
refresh();
+}
- return (BSDDIALOG_OK);
+void bsddialog_clear(unsigned int y)
+{
+ move(y, 0);
+ clrtobot();
+ refresh();
} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/menubox.c b/contrib/bsddialog/lib/menubox.c
index 22ed15e6e7a0..e6e2e7e3e63e 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-2025 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,66 @@ getnextshortcut(struct bsddialog_conf *conf, int npritems,
return (next != -1 ? next : abs);
}
-static enum menumode
-getmode(enum menumode mode, struct bsddialog_menugroup group)
+static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m)
{
- 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)
-{
- int i, linech, labellen;
+ int i, 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);
- linech = conf->ascii_lines ? '-' : ACS_HLINE;
- mvwhline(pad, i, 0, linech, linelen);
- wattroff(pad, t.menu.desccolor);
+ wattron(m->pad, t.menu.desccolor);
+ 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 = 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 +365,137 @@ 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);
+ wnoutrefresh(stdscr);
+ }
}
}
-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, UARROW(conf), 3);
- return (0);
+ if ((m->ypad + (int)m->menurows) < m->nitems)
+ mvwhline(m->box, h-1, 2, DARROW(conf), 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_draw(struct dialog *d, bool redraw, 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 (redraw) {
+ 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) /* doupdate() in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ 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,192 @@ 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;
+ bool loop, changeitem;
+ int i, next, retval;
+ wint_t input;
+ struct privatemenu m;
+ struct dialog d;
- 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;
- }
-
- 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 ((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);
- 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;
-
- 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_draw(&d, false, &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_draw(&d, true, &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_CTRL('l'):
+ case KEY_RESIZE:
+ if (mixedlist_draw(&d, true, &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 '-':
+ case KEY_CTRL('p'):
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 '+':
+ case KEY_CTRL('n'):
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 +697,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 +710,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 +726,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 +742,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);
}
diff --git a/contrib/bsddialog/lib/messagebox.c b/contrib/bsddialog/lib/messagebox.c
index 24b34ccbce97..c3d4a20f5404 100644
--- a/contrib/bsddialog/lib/messagebox.c
+++ b/contrib/bsddialog/lib/messagebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,184 +25,172 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
-static int
-message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text, struct buttons bs)
-{
- int htext, wtext;
+struct scroll {
+ int ypad; /* y scrollable pad */
+ int htext; /* real h text to draw, to use with htextpad */
+ int htextpad; /* h textpad, draw_dialog() set at least 1 */
+ int printrows; /* h - BORDER - HBUTTONS - BORDER */
+};
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
+static void textupdate(struct dialog *d, struct scroll *s)
+{
+ if (s->htext > 0 && s->htextpad > s->printrows) {
+ wattron(d->widget, t.dialog.arrowcolor);
+ mvwprintw(d->widget, d->h - HBUTTONS - BORDER,
+ d->w - 4 - TEXTHMARGIN - BORDER,
+ "%3d%%", 100 * (s->ypad + s->printrows) / s->htextpad);
+ wattroff(d->widget, t.dialog.arrowcolor);
+ wnoutrefresh(d->widget);
}
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, true);
-
- return (0);
+ rtextpad(d, s->ypad, 0, 0, HBUTTONS);
}
-static int message_checksize(int rows, int cols, struct buttons bs)
+static int message_size_position(struct dialog *d, int *htext)
{
- int mincols;
+ int minw;
- mincols = VBORDERS;
- mincols += buttons_width(bs);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "
- "for borders, buttons and spaces between buttons");
-
- if (rows < HBORDERS + 2 /*buttons*/)
- RETURN_ERROR("Msgbox and Yesno need at least height 4");
+ 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 < 0) ? htext : NULL, &d->bs, 0, 0) != 0)
+ return (BSDDIALOG_ERROR);
+ minw = (*htext > 0) ? 1 + TEXTHMARGINS : 0 ;
+ if (widget_checksize(d->h, d->w, &d->bs, MIN(*htext, 1), minw) != 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 void
-textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad)
+static int message_draw(struct dialog *d, bool redraw, struct scroll *s)
{
- int y, x, h, w;
+ int unused;
- getbegyx(widget, y, x);
- getmaxyx(widget, h, w);
-
- if (htextpad > h - 4) {
- mvwprintw(widget, h-3, w-6, "%3d%%",
- 100 * (ytextpad+h-4)/ htextpad);
- wnoutrefresh(widget);
+ if (redraw) { /* redraw: RESIZE or F1 */
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
+ if (message_size_position(d, &s->htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* doupdate() in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+
+ s->printrows = d->h - BORDER - HBUTTONS - BORDER;
+ s->ypad = 0;
+ getmaxyx(d->textpad, s->htextpad, unused);
+ (void)unused; /* fix unused error */
- pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2);
+ return (0);
}
static int
do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
- struct buttons bs)
+ const char *oklabel, const char *cancellabel)
{
bool loop;
- int y, x, h, w, input, output, ytextpad, htextpad, unused;
- WINDOW *widget, *textpad, *shadow;
+ int retval;
+ wint_t input;
+ struct scroll s;
+ struct dialog d;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, oklabel, cancellabel);
+ s.htext = -1;
+ if (message_draw(&d, false, &s) != 0)
return (BSDDIALOG_ERROR);
- ytextpad = 0;
- getmaxyx(textpad, htextpad, unused);
- unused++; /* fix unused error */
- textupdate(widget, textpad, htextpad, ytextpad);
loop = true;
while (loop) {
+ textupdate(&d, &s);
doupdate();
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch (input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
- if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ if (d.conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, true);
- wnoutrefresh(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, true);
- wnoutrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
- case KEY_RIGHT:
- if (bs.curr < (int)bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
- }
+ 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++;
+ break;
+ case KEY_HOME:
+ s.ypad = 0;
+ break;
+ case KEY_END:
+ s.ypad = MAX(s.htextpad - s.printrows, 0);
+ break;
+ case KEY_PPAGE:
+ s.ypad = MAX(s.ypad - s.printrows, 0);
+ break;
+ case KEY_NPAGE:
+ s.ypad += s.printrows;
+ if (s.ypad + s.printrows > s.htextpad)
+ s.ypad = s.htextpad - s.printrows;
break;
case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
+ if (d.conf->key.f1_file == NULL &&
+ d.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)
- return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
+ if (f1help_dialog(d.conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (message_draw(&d, true, &s) != 0)
return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- getmaxyx(textpad, htextpad, unused);
- textupdate(widget, textpad, htextpad, ytextpad);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
- case KEY_UP:
- if (ytextpad == 0)
- break;
- ytextpad--;
- textupdate(widget, textpad, htextpad, ytextpad);
- break;
- case KEY_DOWN:
- if (ytextpad + h - 4 >= htextpad)
- break;
- ytextpad++;
- textupdate(widget, textpad, htextpad, ytextpad);
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (message_draw(&d, true, &s) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
/* API */
@@ -210,20 +198,34 @@ int
bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL);
-
- return (do_message(conf, text, rows, cols, bs));
+ return (do_message(conf, text, rows, cols, OK_LABEL, NULL));
}
int
bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
+ return (do_message(conf, text, rows, cols, "Yes", "No"));
+}
- get_buttons(conf, &bs, "Yes", "No");
+int
+bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
+{
+ int htext;
+ struct dialog d;
- return (do_message(conf, text, rows, cols, bs));
-} \ No newline at end of file
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ htext = -1;
+ if (message_size_position(&d, &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
+ return (BSDDIALOG_ERROR);
+ TEXTPAD(&d, 0);
+ doupdate();
+
+ end_dialog(&d);
+
+ return (BSDDIALOG_OK);
+}
diff --git a/contrib/bsddialog/lib/textbox.c b/contrib/bsddialog/lib/textbox.c
index 69eff7c0bc2e..1f730e0d925b 100644
--- a/contrib/bsddialog/lib/textbox.c
+++ b/contrib/bsddialog/lib/textbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,199 +25,248 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-static void
-textbox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int hpad, int wpad, struct buttons bs)
+struct scrolltext {
+ WINDOW *pad;
+ int ypad;
+ int xpad;
+ int ys;
+ int ye;
+ int xs;
+ int xe;
+ int hpad;
+ int wpad;
+ int margin; /* 2 with multicolumn char, 0 otherwise */
+ int printrows; /* d.h - BORDERS - HBUTTONS */
+};
+
+static void updateborders(struct dialog *d, struct scrolltext *st)
{
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, 0, wpad, &bs);
+ chtype arrowch;
+ cchar_t borderch;
+
+ if (d->conf->no_lines)
+ setcchar(&borderch, L" ", 0, 0, NULL);
+ else if (d->conf->ascii_lines)
+ setcchar(&borderch, L"|", 0, 0, NULL);
+ else
+ borderch = *WACS_VLINE;
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, 0, hpad, true);
+ if (st->xpad > 0) {
+ arrowch = LARROW(d->conf) | t.dialog.arrowcolor;
+ mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4);
+ } else {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwvline_set(d->widget, (d->h / 2) - 2, 0, &borderch, 4);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+
+ if (st->xpad + d->w - 2 - st->margin < st->wpad) {
+ arrowch = RARROW(d->conf) | t.dialog.arrowcolor;
+ mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4);
+ } else {
+ 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);
+ }
+
+ if (st->hpad > d->h - 4) {
+ wattron(d->widget, t.dialog.arrowcolor);
+ mvwprintw(d->widget, d->h - 3, d->w - 6,
+ "%3d%%", 100 * (st->ypad + d->h - 4) / st->hpad);
+ wattroff(d->widget, t.dialog.arrowcolor);
+ }
}
-static int
-textbox_checksize(int rows, int cols, int hpad, struct buttons bs)
+static int textbox_size_position(struct dialog *d, struct scrolltext *st)
{
- int mincols;
+ int minw;
- mincols = VBORDERS + bs.sizebutton;
+ 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, NULL, &d->bs, st->hpad, st->wpad + st->margin) != 0)
+ return (BSDDIALOG_ERROR);
+ minw = (st->wpad > 0) ? 2 /*multicolumn char*/ + st->margin : 0 ;
+ if (widget_checksize(d->h, d->w, &d->bs, MIN(st->hpad, 1), minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
- if (cols < mincols)
- RETURN_ERROR("Few cols for the textbox");
+ return (0);
+}
+
+static int textbox_draw(struct dialog *d, bool redraw, struct scrolltext *st)
+{
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (textbox_size_position(d, st) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* wrefresh() and prefresh() in main loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
- if (rows < 4 /* HBORDERS + button*/ + (hpad > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for the textbox");
+ st->ys = d->y + 1;
+ st->xs = (st->margin == 0) ? d->x + 1 : d->x + 2;
+ st->ye = st->ys + d->h - 5;
+ st->xe = st->xs + d->w - 3 - st->margin;
+ st->ypad = st->xpad = 0;
+ st->printrows = d->h-4;
return (0);
}
/* API */
int
-bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
+bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
int cols)
{
- bool loop;
- int i, output, input;
- int y, x, h, w, hpad, wpad, ypad, xpad, ys, ye, xs, xe, printrows;
+ bool loop, has_multicol_ch;
+ int i, retval;
+ unsigned int defaulttablen, linecols;
+ wint_t input;
char buf[BUFSIZ];
FILE *fp;
- struct buttons bs;
- WINDOW *shadow, *widget, *pad;
+ struct scrolltext st;
+ struct dialog d;
+ if (file == NULL)
+ RETURN_ERROR("*file is NULL");
if ((fp = fopen(file, "r")) == NULL)
- RETURN_ERROR("Cannot open file");
+ RETURN_FMTERROR("Cannot open file \"%s\"", file);
+
+ if (prepare_dialog(conf, "" /* fake */, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, "EXIT", NULL);
- hpad = 1;
- wpad = 1;
- pad = newpad(hpad, wpad);
- wbkgd(pad, t.dialog.color);
+ defaulttablen = TABSIZE;
+ if (conf->text.tablen > 0)
+ set_tabsize(conf->text.tablen);
+ st.hpad = 1;
+ st.wpad = 1;
+ st.pad = newpad(st.hpad, st.wpad);
+ wbkgd(st.pad, t.dialog.color);
+ st.margin = 0;
i = 0;
while (fgets(buf, BUFSIZ, fp) != NULL) {
- if ((int) strlen(buf) > wpad) {
- wpad = strlen(buf);
- wresize(pad, hpad, wpad);
+ if (str_props(buf, &linecols, &has_multicol_ch) != 0)
+ continue;
+ if ((int)linecols > st.wpad) {
+ st.wpad = linecols;
+ wresize(st.pad, st.hpad, st.wpad);
}
- if (i > hpad-1) {
- hpad++;
- wresize(pad, hpad, wpad);
+ if (i > st.hpad-1) {
+ st.hpad++;
+ wresize(st.pad, st.hpad, st.wpad);
}
- mvwaddstr(pad, i, 0, buf);
+ mvwaddstr(st.pad, i, 0, buf);
i++;
+ if (has_multicol_ch)
+ st.margin = 2;
}
fclose(fp);
+ set_tabsize(defaulttablen); /* reset because it is curses global */
- bs.nbuttons = 1;
- bs.label[0] = "EXIT";
- if (conf->button.ok_label != NULL)
- bs.label[0] = conf->button.ok_label;
- bs.value[0] = BSDDIALOG_OK;
- bs.curr = 0;
- bs.sizebutton = strlen(bs.label[0]) + 2;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad, bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, NULL, NULL, &bs,
- true) != 0)
+ if (textbox_draw(&d, false, &st) != 0)
return (BSDDIALOG_ERROR);
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h-4;
loop = true;
while (loop) {
- wnoutrefresh(widget);
- pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
- doupdate();
- input = getch();
+ updateborders(&d, &st);
+ /*
+ * Trick, overflow multicolumn charchter right border:
+ * wnoutrefresh(widget);
+ * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ * doupdate();
+ */
+ wrefresh(d.widget);
+ prefresh(st.pad, st.ypad, st.xpad, st.ys, st.xs, st.ye, st.xe);
+ if (get_wch(&input) == ERR)
+ continue;
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ break; /* loop */
+ }
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = BSDDIALOG_OK;
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
+ case '\t': /* TAB */
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
+ break;
case KEY_HOME:
- ypad = 0;
+ st.ypad = 0;
break;
case KEY_END:
- ypad = hpad - printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.hpad - st.printrows, 0);
break;
case KEY_PPAGE:
- ypad -= printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.ypad - st.printrows, 0);
break;
case KEY_NPAGE:
- ypad += printrows;
- if (ypad + printrows > hpad)
- ypad = hpad - printrows;
+ st.ypad += st.printrows;
+ if (st.ypad + st.printrows > st.hpad)
+ st.ypad = st.hpad - st.printrows;
break;
case '0':
- xpad = 0;
+ st.xpad = 0;
+ break;
case KEY_LEFT:
case 'h':
- xpad = xpad > 0 ? xpad - 1 : 0;
+ st.xpad = MAX(st.xpad - 1, 0);
break;
case KEY_RIGHT:
case 'l':
- xpad = (xpad + w-2) < wpad-1 ? xpad + 1 : xpad;
+ if (st.xpad + d.w - 2 - st.margin < st.wpad)
+ st.xpad++;
break;
case KEY_UP:
case 'k':
- ypad = ypad > 0 ? ypad - 1 : 0;
+ st.ypad = MAX(st.ypad - 1, 0);
break;
case KEY_DOWN:
case'j':
- ypad = ypad + printrows <= hpad -1 ? ypad + 1 : ypad;
+ if (st.ypad + st.printrows <= st.hpad -1)
+ st.ypad++;
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)
- return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad,
- bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (textbox_draw(&d, true, &st) != 0)
return (BSDDIALOG_ERROR);
-
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h - 4;
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- NULL, NULL, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (textbox_draw(&d, true, &st) != 0)
return (BSDDIALOG_ERROR);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
- default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
- loop = false;
- }
}
}
- end_dialog(conf, shadow, widget, pad);
+ delwin(st.pad);
+ end_dialog(&d);
- return (output);
-} \ No newline at end of file
+ return (retval);
+}
diff --git a/contrib/bsddialog/lib/theme.c b/contrib/bsddialog/lib/theme.c
index 20b1e35428dd..6c17d908324b 100644
--- a/contrib/bsddialog/lib/theme.c
+++ b/contrib/bsddialog/lib/theme.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,137 +32,117 @@
#include "lib_util.h"
#define GET_COLOR(bg, fg) (COLOR_PAIR(bg * 8 + fg +1))
+#define WHITE GET_COLOR(COLOR_WHITE, COLOR_BLACK)
+#define BLACK GET_COLOR(COLOR_WHITE, COLOR_BLACK) | A_REVERSE
+#define NFLAGS 6
struct bsddialog_theme t;
+bool hastermcolors;
-static struct bsddialog_theme bsddialogtheme = {
-#define bgwidget COLOR_WHITE
-#define bgcurr COLOR_YELLOW
- .screen.color = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
-
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+struct flag_converter {
+ unsigned int public;
+ unsigned int private;
+};
- .dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.color = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.arrowcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
-
- .menu.f_selectorcolor = GET_COLOR(COLOR_BLACK, bgcurr),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, bgcurr),
- .menu.desccolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_namecolor = GET_COLOR(COLOR_BLACK, bgcurr),
- .menu.namecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.namesepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .menu.descsepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, bgcurr),
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, bgwidget),
-
- .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
- .form.readonlycolor = GET_COLOR(COLOR_CYAN,COLOR_WHITE),
-
- .bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
-
- .button.hmargin = 3,
- .button.leftdelim = '[',
- .button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .button.delimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .button.f_color = GET_COLOR(COLOR_BLACK, bgcurr) | A_UNDERLINE,
- .button.color = GET_COLOR(COLOR_BLACK, bgwidget) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(COLOR_RED, bgcurr) | A_UNDERLINE,
- .button.shortcutcolor = GET_COLOR(COLOR_RED, bgwidget) | A_UNDERLINE
+static struct flag_converter flagconv[NFLAGS] = {
+ {BSDDIALOG_BLINK, A_BLINK},
+ {BSDDIALOG_BOLD, A_BOLD},
+ {BSDDIALOG_HALFBRIGHT, A_DIM},
+ {BSDDIALOG_HIGHLIGHT, A_STANDOUT},
+ {BSDDIALOG_REVERSE, A_REVERSE},
+ {BSDDIALOG_UNDERLINE, A_UNDERLINE}
};
static struct bsddialog_theme blackwhite = {
-#define fg COLOR_WHITE
-#define bk COLOR_BLACK
- .screen.color = GET_COLOR(fg, bk),
+ .screen.color = WHITE,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(fg, bk),
- .dialog.lineraisecolor = GET_COLOR(fg, bk),
- .dialog.linelowercolor = GET_COLOR(fg, bk),
- .dialog.color = GET_COLOR(fg, bk),
- .dialog.bottomtitlecolor = GET_COLOR(fg, bk),
- .dialog.arrowcolor = GET_COLOR(fg, bk),
-
- .menu.f_selectorcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.selectorcolor = GET_COLOR(fg, bk),
- .menu.f_desccolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.desccolor = GET_COLOR(fg, bk),
- .menu.f_namecolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.namecolor = GET_COLOR(fg, bk),
- .menu.namesepcolor = GET_COLOR(fg, bk),
- .menu.descsepcolor = GET_COLOR(fg, bk),
- .menu.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .menu.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE,
-
- .form.f_fieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .form.fieldcolor = GET_COLOR(fg, bk),
- .form.readonlycolor = GET_COLOR(fg, bk),
-
- .bar.f_color = GET_COLOR(fg, bk) | A_REVERSE,
- .bar.color = GET_COLOR(fg, bk),
-
- .button.hmargin = 3,
+ .dialog.titlecolor = WHITE,
+ .dialog.lineraisecolor = WHITE,
+ .dialog.linelowercolor = WHITE,
+ .dialog.color = WHITE,
+ .dialog.bottomtitlecolor = WHITE,
+ .dialog.arrowcolor = WHITE,
+
+ .menu.f_prefixcolor = WHITE,
+ .menu.prefixcolor = WHITE,
+ .menu.f_selectorcolor = BLACK,
+ .menu.selectorcolor = WHITE,
+ .menu.f_desccolor = BLACK,
+ .menu.desccolor = WHITE,
+ .menu.f_namecolor = BLACK,
+ .menu.namecolor = WHITE,
+ .menu.f_shortcutcolor = BLACK | A_UNDERLINE,
+ .menu.shortcutcolor = WHITE | A_UNDERLINE,
+ .menu.bottomdesccolor = WHITE,
+ .menu.sepnamecolor = WHITE,
+ .menu.sepdesccolor = WHITE,
+
+ .form.f_fieldcolor = BLACK,
+ .form.fieldcolor = WHITE,
+ .form.readonlycolor = WHITE,
+ .form.bottomdesccolor = WHITE,
+
+ .bar.f_color = BLACK,
+ .bar.color = WHITE,
+
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
.button.leftdelim = '[',
.button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(fg, bk),
- .button.delimcolor = GET_COLOR(fg, bk),
- .button.f_color = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.color = GET_COLOR(fg, bk) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE
+ .button.f_delimcolor = WHITE,
+ .button.delimcolor = WHITE,
+ .button.f_color = BLACK,
+ .button.color = WHITE,
+ .button.f_shortcutcolor = BLACK | A_UNDERLINE | A_BOLD,
+ .button.shortcutcolor = WHITE | A_UNDERLINE | A_BOLD
};
-static struct bsddialog_theme dialogtheme = {
- .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
+static struct bsddialog_theme flat = {
+ .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
- .dialog.delimtitle = false,
+ .dialog.delimtitle = true,
.dialog.titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .dialog.lineraisecolor = GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD,
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
+ .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
- .dialog.arrowcolor = GET_COLOR(COLOR_GREEN, COLOR_WHITE),
-
- .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
- .menu.namesepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.descsepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
-
- .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
- .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
- .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
+ .dialog.arrowcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+
+ .menu.f_prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+ .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
+ .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.sepnamecolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.sepdesccolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+
+ .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
+ .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
.bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
.bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .button.hmargin = 3,
- .button.leftdelim = '<',
- .button.rightdelim = '>',
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
+ .button.leftdelim = '[',
+ .button.rightdelim = ']',
.button.f_delimcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
.button.delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.button.f_color = GET_COLOR(COLOR_YELLOW, COLOR_BLUE) | A_BOLD,
@@ -177,8 +157,8 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->screen.color = src->screen.color;
dst->shadow.color = src->shadow.color;
- dst->shadow.h = src->shadow.h;
- dst->shadow.w = src->shadow.w;
+ dst->shadow.y = src->shadow.y;
+ dst->shadow.x = src->shadow.x;
dst->dialog.delimtitle = src->dialog.delimtitle;
dst->dialog.titlecolor = src->dialog.titlecolor;
@@ -188,25 +168,30 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->dialog.bottomtitlecolor = src->dialog.bottomtitlecolor;
dst->dialog.arrowcolor = src->dialog.arrowcolor;
+ dst->menu.f_prefixcolor = src->menu.f_prefixcolor;
+ dst->menu.prefixcolor = src->menu.prefixcolor;
dst->menu.f_selectorcolor = src->menu.f_selectorcolor;
dst->menu.selectorcolor = src->menu.selectorcolor;
dst->menu.f_desccolor = src->menu.f_desccolor;
dst->menu.desccolor = src->menu.desccolor;
dst->menu.f_namecolor = src->menu.f_namecolor;
dst->menu.namecolor = src->menu.namecolor;
- dst->menu.namesepcolor = src->menu.namesepcolor;
- dst->menu.descsepcolor = src->menu.descsepcolor;
dst->menu.f_shortcutcolor = src->menu.f_shortcutcolor;
dst->menu.shortcutcolor = src->menu.shortcutcolor;
+ dst->menu.bottomdesccolor = src->menu.bottomdesccolor;
+ dst->menu.sepnamecolor = src->menu.sepnamecolor;
+ dst->menu.sepdesccolor = src->menu.sepdesccolor;
- dst->form.f_fieldcolor = src->form.f_fieldcolor;
- dst->form.fieldcolor = src->form.fieldcolor;
- dst->form.readonlycolor = src->form.readonlycolor;
+ dst->form.f_fieldcolor = src->form.f_fieldcolor;
+ dst->form.fieldcolor = src->form.fieldcolor;
+ dst->form.readonlycolor = src->form.readonlycolor;
+ dst->form.bottomdesccolor = src->form.bottomdesccolor;
dst->bar.f_color = src->bar.f_color;
dst->bar.color = src->bar.color;
- dst->button.hmargin = src->button.hmargin;
+ dst->button.minmargin = src->button.minmargin;
+ dst->button.maxmargin = src->button.maxmargin;
dst->button.leftdelim = src->button.leftdelim;
dst->button.rightdelim = src->button.rightdelim;
dst->button.f_delimcolor = src->button.f_delimcolor;
@@ -217,68 +202,87 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->button.shortcutcolor = src->button.shortcutcolor;
bkgd(dst->screen.color);
- refresh();
}
/* API */
int bsddialog_get_theme(struct bsddialog_theme *theme)
{
- if (theme == NULL)
- RETURN_ERROR("theme is NULL");
- if (sizeof(*theme) != sizeof(struct bsddialog_theme))
- RETURN_ERROR("Bad suze struct bsddialog_theme");
-
+ CHECK_PTR(theme);
set_theme(theme, &t);
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_theme(struct bsddialog_theme *theme)
{
- if (theme == NULL)
- RETURN_ERROR("theme is NULL");
- if (sizeof(*theme) != sizeof(struct bsddialog_theme))
- RETURN_ERROR("Bad size struct bsddialog_theme");
-
+ CHECK_PTR(theme);
set_theme(&t, theme);
+ wnoutrefresh(stdscr);
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
{
-
- if (newtheme == BSDDIALOG_THEME_FLAT) {
- bsddialog_set_theme(&dialogtheme);
- t.dialog.lineraisecolor = t.dialog.linelowercolor;
- t.dialog.delimtitle = true;
- t.button.leftdelim = '[';
- t.button.rightdelim = ']';
+ if (newtheme == BSDDIALOG_THEME_3D) {
+ set_theme(&t, &flat);
+ t.dialog.lineraisecolor =
+ GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD;
+ t.dialog.delimtitle = false;
+ t.dialog.bottomtitlecolor = t.dialog.bottomtitlecolor | A_BOLD;
+ } else if (newtheme == BSDDIALOG_THEME_BLACKWHITE) {
+ set_theme(&t, &blackwhite);
+ } else if (newtheme == BSDDIALOG_THEME_FLAT) {
+ set_theme(&t, &flat);
+ } else {
+ RETURN_FMTERROR("Unknown default theme (%d), "
+ "to use enum bsddialog_default_theme",
+ newtheme);
}
- else if (newtheme == BSDDIALOG_THEME_BSDDIALOG)
- bsddialog_set_theme(&bsddialogtheme);
- else if (newtheme == BSDDIALOG_THEME_BLACKWHITE)
- bsddialog_set_theme(&blackwhite);
- else if (newtheme == BSDDIALOG_THEME_DIALOG)
- bsddialog_set_theme(&dialogtheme);
- else
- RETURN_ERROR("Unknow default theme");
-
- return (0);
+ wnoutrefresh(stdscr);
+
+ return (BSDDIALOG_OK);
}
int
bsddialog_color(enum bsddialog_color foreground,
enum bsddialog_color background, unsigned int flags)
{
- unsigned int cursesflags = 0;
+ unsigned int i, f;
+
+ f = 0;
+ for (i=0; i < NFLAGS; i++)
+ if (flags & flagconv[i].public)
+ f |= flagconv[i].private;
- if (flags & BSDDIALOG_BOLD)
- cursesflags |= A_BOLD;
- if (flags & BSDDIALOG_REVERSE)
- cursesflags |= A_REVERSE;
- if (flags & BSDDIALOG_UNDERLINE)
- cursesflags |= A_UNDERLINE;
+ return (GET_COLOR(foreground, background) | f);
+}
- return (GET_COLOR(foreground, background) | cursesflags);
+int
+bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
+ enum bsddialog_color *background, unsigned int *flags)
+{
+ short fg, bg;
+ unsigned int i, f;
+
+ if (flags != NULL) {
+ f = 0;
+ for (i=0; i < NFLAGS; i++)
+ if (color & flagconv[i].private)
+ f |= flagconv[i].public;
+ *flags = f;
+ }
+ if (pair_content(PAIR_NUMBER(color), &fg, &bg) != OK)
+ RETURN_ERROR("Cannot get color attributes");
+ if (foreground != NULL)
+ *foreground = fg;
+ if (background != NULL)
+ *background = bg;
+
+ return (BSDDIALOG_OK);
+}
+
+bool bsddialog_hascolors(void)
+{
+ return (hastermcolors);
}
diff --git a/contrib/bsddialog/lib/timebox.c b/contrib/bsddialog/lib/timebox.c
index 7d69666c32b8..603d5fa5d7a3 100644
--- a/contrib/bsddialog/lib/timebox.c
+++ b/contrib/bsddialog/lib/timebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,512 +25,216 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
-#define MINWDATE 23 /* 3 windows and their borders */
#define MINWTIME 14 /* 3 windows and their borders */
-
-static int
-datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int minw, const char *text, struct buttons bs)
+#define HBOX 3
+#define WBOX 4
+
+struct clock {
+ unsigned int max;
+ unsigned int value;
+ WINDOW *win;
+};
+
+static void
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value,
+ bool focus)
{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 3, minw, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
+ draw_borders(conf, win, LOWERED);
+ if (focus) {
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, 1, UARROW(conf), 2);
+ mvwhline(win, 2, 1, DARROW(conf), 2);
+ wattroff(win, t.dialog.arrowcolor);
}
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, htext,minw, &bs);
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ mvwprintw(win, 1, 1, "%02u", value);
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* windows */, true);
-
- return (0);
+ wnoutrefresh(win);
}
-static int
-datetime_checksize(int rows, int cols, int minw, struct buttons bs)
+static int timebox_draw(struct dialog *d, bool redraw, struct clock *c)
{
- int mincols;
-
- mincols = VBORDERS;
- mincols += buttons_width(bs);
- mincols = MAX(minw, mincols);
+ int y, x;
- if (cols < mincols)
- RETURN_ERROR("Few cols for this timebox/datebox");
-
- if (rows < 7) /* 2 button + 2 borders + 3 windows */
- RETURN_ERROR("Few rows for this timebox/datebox, at least 7");
+ if (redraw) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MINWTIME, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0) /* doupdate() in mail loop */
+ return (BSDDIALOG_ERROR);
+ if (redraw)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
+
+ y = d->y + d->h - BORDER - HBUTTONS - HBOX;
+ x = d->x + d->w/2 - 7;
+ update_box(d->conf, c[0].win, y, x, HBOX, WBOX, LOWERED);
+ mvwaddch(d->widget, d->h - 5, d->w/2 - 3, ':');
+ update_box(d->conf, c[1].win, y, x += 5, HBOX, WBOX, LOWERED);
+ mvwaddch(d->widget, d->h - 5, d->w/2 + 2, ':');
+ update_box(d->conf, c[2].win, y, x + 5, HBOX, WBOX, LOWERED);
+ wnoutrefresh(d->widget); /* for mvwaddch(':') */
return (0);
}
+/* API */
int
bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
{
bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct myclockstruct {
- unsigned int max;
- unsigned int value;
- WINDOW *win;
- };
-
- if (hh == NULL || mm == NULL || ss == NULL)
- RETURN_ERROR("hh / mm / ss cannot be NULL");
-
- struct myclockstruct c[3] = {
+ int i, retval, sel;
+ wint_t input;
+ struct dialog d;
+ struct clock c[3] = {
{23, *hh, NULL},
{59, *mm, NULL},
{59, *ss, NULL}
};
- for (i = 0 ; i < 3; i++) {
- if (c[i].value > c[i].max)
- c[i].value = c[i].max;
- }
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ CHECK_PTR(hh);
+ CHECK_PTR(mm);
+ CHECK_PTR(ss);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ for (i=0; i<3; i++) {
+ if ((c[i].win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_FMTERROR("Cannot build WINDOW for time[%d]", i);
+ wbkgd(c[i].win, t.dialog.color);
+ c[i].value = MIN(c[i].value, c[i].max);
+ }
+ if (timebox_draw(&d, false, c) != 0)
return (BSDDIALOG_ERROR);
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 7, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 2, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 3, 3, 4, LOWERED);
-
- wrefresh(widget);
-
+ sel = -1;
loop = focusbuttons = true;
while (loop) {
- for (i = 0; i < 3; i++) {
- mvwprintw(c[i].win, 1, 1, "%2d", c[i].value);
- wrefresh(c[i].win);
- }
-
- if (focusbuttons == false) {
- wmove(c[sel].win, 1, 2);
- wrefresh(c[sel].win);
- }
-
- input = getch();
+ for (i = 0; i < 3; i++)
+ drawsquare(conf, c[i].win, c[i].value, sel == i);
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
- case KEY_RIGHT:
case '\t': /* TAB */
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
if (focusbuttons) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
+ d.bs.curr++;
+ focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
true : false;
if (focusbuttons == false) {
- curs_set(1);
sel = 0;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel++;
focusbuttons = sel > 2 ? true : false;
if (focusbuttons) {
- curs_set(0);
- bs.curr = 0;
+ d.bs.curr = 0;
}
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ DRAW_BUTTONS(d);
break;
+ case KEY_CTRL('p'):
case KEY_LEFT:
if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
+ d.bs.curr--;
+ focusbuttons = d.bs.curr < 0 ? false : true;
if (focusbuttons == false) {
- curs_set(1);
sel = 2;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel--;
focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = (int)bs.nbuttons - 1;
- }
+ if (focusbuttons)
+ d.bs.curr = (int)d.bs.nbuttons - 1;
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_UP:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value > 0 ?
- c[sel].value - 1 : c[sel].max;
- break;
- case KEY_DOWN:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value < c[sel].max ?
- c[sel].value + 1 : 0;
+ DRAW_BUTTONS(d);
break;
- case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
- break;
- curs_set(0);
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- curs_set(1);
- /* 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)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWTIME, text, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, 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, true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 7);
- draw_borders(conf, c[0].win, 3, 4, LOWERED);
- wrefresh(c[0].win);
-
- wclear(c[1].win);
- mvwin(c[1].win, y + h - 6, x + w/2 - 2);
- draw_borders(conf, c[1].win, 3, 4, LOWERED);
- wrefresh(c[1].win);
-
- wclear(c[2].win);
- mvwin(c[2].win, y + h - 6, x + w/2 + 3);
- draw_borders(conf, c[2].win, 3, 4, LOWERED);
- wrefresh(c[2].win);
-
- /* Important to avoid grey lines expanding screen */
- refresh();
- break;
- default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
- loop = false;
- }
- }
- }
-
- if (output == BSDDIALOG_OK) {
- *hh = c[0].value;
- *mm = c[1].value;
- *ss = c[2].value;
- }
-
- curs_set(0);
-
- for (i = 0; i < 3; i++)
- delwin(c[i].win);
- end_dialog(conf, shadow, widget, textpad);
-
- return (output);
-}
-
-int
-bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
-{
- bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct calendar {
- int max;
- int value;
- WINDOW *win;
- unsigned int x;
- };
- struct month {
- const char *name;
- unsigned int days;
- };
-
- if (yy == NULL || mm == NULL || dd == NULL)
- RETURN_ERROR("yy / mm / dd cannot be NULL");
-
- struct calendar c[3] = {
- {9999, *yy, NULL, 4 },
- {12, *mm, NULL, 9 },
- {31, *dd, NULL, 2 }
- };
-
- struct month m[12] = {
- { "January", 31 }, { "February", 28 }, { "March", 31 },
- { "April", 30 }, { "May", 31 }, { "June", 30 },
- { "July", 31 }, { "August", 31 }, { "September", 30 },
- { "October", 31 }, { "November", 30 }, { "December", 31 }
- };
-
-#define ISLEAF(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
-
- for (i = 0 ; i < 3; i++) {
- if (c[i].value > c[i].max)
- c[i].value = c[i].max;
- if (c[i].value < 1)
- c[i].value = 1;
- }
- c[2].max = m[c[1].value -1].days;
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 11, 3, 6, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 4, 3, 11, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 8, 3, 4, LOWERED);
-
- wrefresh(widget);
-
- loop = focusbuttons = true;
- while (loop) {
- mvwprintw(c[0].win, 1, 1, "%4d", c[0].value);
- mvwprintw(c[1].win, 1, 1, "%9s", m[c[1].value-1].name);
- mvwprintw(c[2].win, 1, 1, "%2d", c[2].value);
- for (i = 0; i < 3; i++) {
- wrefresh(c[i].win);
- }
- if (focusbuttons == false) {
- wmove(c[sel].win, 1, c[sel].x);
- wrefresh(c[sel].win);
- }
-
- input = getch();
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
+ case '-':
if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
- break;
- case 27: /* Esc */
- if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
- loop = false;
- }
- break;
- case KEY_RIGHT:
- case '\t': /* TAB */
- if (focusbuttons) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
- true : false;
- if (focusbuttons == false) {
- curs_set(1);
- sel = 0;
- }
- } else {
- sel++;
- focusbuttons = sel > 2 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = 0;
- }
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ c[sel].value = c[sel].value > 0 ?
+ c[sel].value - 1 : c[sel].max;
break;
- case KEY_LEFT:
+ case KEY_UP:
if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
- if (focusbuttons == false) {
- curs_set(1);
- sel = 2;
- }
+ sel = 0;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
} else {
- sel--;
- focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = (int)bs.nbuttons - 1;
- }
+ c[sel].value = c[sel].value > 0 ?
+ c[sel].value - 1 : c[sel].max;
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_UP:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value > 1 ?
- c[sel].value - 1 : c[sel].max ;
- /* if mount change */
- c[2].max = m[c[1].value -1].days;
- /* if year change */
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
break;
+ case '+':
case KEY_DOWN:
if (focusbuttons)
break;
c[sel].value = c[sel].value < c[sel].max ?
- c[sel].value + 1 : 1;
- /* if mount change */
- c[2].max = m[c[1].value -1].days;
- /* if year change */
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
+ c[sel].value + 1 : 0;
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- curs_set(0);
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- curs_set(1);
- /* 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)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWDATE, text, bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
+ if (timebox_draw(&d, true, c) != 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, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (timebox_draw(&d, true, c) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 11);
- draw_borders(conf, c[0].win, 3, 6, LOWERED);
- wrefresh(c[0].win);
-
- wclear(c[1].win);
- mvwin(c[1].win, y + h - 6, x + w/2 - 4);
- draw_borders(conf, c[1].win, 3, 11, LOWERED);
- wrefresh(c[1].win);
-
- wclear(c[2].win);
- mvwin(c[2].win, y + h - 6, x + w/2 + 8);
- draw_borders(conf, c[2].win, 3, 4, LOWERED);
- wrefresh(c[2].win);
-
- /* Important to avoid grey lines expanding screen */
- refresh();
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- if (output == BSDDIALOG_OK) {
- *yy = c[0].value;
- *mm = c[1].value;
- *dd = c[2].value;
- }
-
- curs_set(0);
+ *hh = c[0].value;
+ *mm = c[1].value;
+ *ss = c[2].value;
for (i = 0; i < 3; i++)
delwin(c[i].win);
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
diff --git a/contrib/bsddialog/utility/GNUmakefile b/contrib/bsddialog/utility/GNUmakefile
new file mode 100644
index 000000000000..600efc7aacf6
--- /dev/null
+++ b/contrib/bsddialog/utility/GNUmakefile
@@ -0,0 +1,42 @@
+# PUBLIC DOMAIN - NO WARRANTY, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written in 2021 by Alfonso Sabato Siciliano
+
+OUTPUT = bsddialog
+SOURCES = bsddialog.c util_builders.c util_cli.c util_theme.c
+OBJECTS = $(SOURCES:.c=.o)
+PREFIX = /usr/local
+
+ifneq ($(ENABLEDEBUG),)
+CFLAGS += -g
+endif
+CFLAGS += -D_GNU_SOURCE -Wall -Wextra -I$(LIBPATH)
+
+ifneq ($(DISABLERPATH),)
+LDFLAGS += -ltinfo -L$(LIBPATH) -lbsddialog
+else
+LDFLAGS += -ltinfo -Wl,-rpath=$(LIBPATH) -L$(LIBPATH) -lbsddialog
+endif
+
+RM = rm -f
+
+all: $(OUTPUT)
+
+install: all
+ ${INSTALL} -m 0755 ${OUTPUT} ${DESTDIR}${PREFIX}/bin/${OUTPUT}
+
+uninstall:
+ ${RM} ${DESTDIR}${PREFIX}/bin/${OUTPUT}
+
+$(OUTPUT): $(OBJECTS)
+ $(CC) $^ -o $@ $(LDFLAGS)
+
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ $(RM) $(OUTPUT) *.o *~
+
+.PHONY: all install uninstall clean
diff --git a/contrib/bsddialog/utility/Makefile b/contrib/bsddialog/utility/Makefile
new file mode 100644
index 000000000000..e6cd541fded4
--- /dev/null
+++ b/contrib/bsddialog/utility/Makefile
@@ -0,0 +1,42 @@
+# PUBLIC DOMAIN - NO WARRANTY, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written in 2021 by Alfonso Sabato Siciliano
+
+OUTPUT = bsddialog
+SOURCES = bsddialog.c util_builders.c util_cli.c util_theme.c
+OBJECTS = ${SOURCES:.c=.o}
+PREFIX = /usr/local
+
+.if defined(DEBUG)
+CFLAGS += -g
+.endif
+CFLAGS += -I${LIBPATH} -std=gnu99 -Wall -Wextra -Werror
+
+.if defined(NORPATH)
+LDFLAGS += -ltinfow -L${LIBPATH} -lbsddialog
+.else
+LDFLAGS += -ltinfow -Wl,-rpath=${LIBPATH} -L${LIBPATH} -lbsddialog
+.endif
+
+INSTALL = install
+RM = rm -f
+
+all: ${OUTPUT}
+
+install: all
+ ${INSTALL} -m 0755 ${OUTPUT} ${DESTDIR}${PREFIX}/bin/${OUTPUT}
+
+uninstall:
+ ${RM} ${DESTDIR}${PREFIX}/bin/${OUTPUT}
+
+${OUTPUT}: ${OBJECTS}
+ ${CC} ${LDFLAGS} ${OBJECTS} -o ${.PREFIX}
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+clean:
+ ${RM} ${OUTPUT} *.o *~ *.core *.gz
+
+.PHONY: all install uninstall clean
diff --git a/contrib/bsddialog/utility/bsddialog.1 b/contrib/bsddialog/utility/bsddialog.1
new file mode 100644
index 000000000000..0ec2a96952bd
--- /dev/null
+++ b/contrib/bsddialog/utility/bsddialog.1
@@ -0,0 +1,952 @@
+.\"
+.\" Copyright (c) 2021-2025 Alfonso Sabato Siciliano
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd June 22, 2025
+.Dt BSDDIALOG 1
+.Os
+.Sh NAME
+.Nm bsddialog
+.Nd TUI dialogs
+.Sh SYNOPSIS
+.Nm
+.Fl Fl help | Fl Fl version
+.Nm
+.Op Fl Fl option
+.Fl Fl dialog
+.Ar text
+.Ar rows
+.Ar cols
+.Op Ar dialog-argument
+.Op Fl Fl option
+.Nm
+\&...
+.Fl Fl dialog1
+.Ar ...
+.Oo Fl Fl and-dialog
+.Fl Fl dialog2
+.Ar ...
+.Oc ...
+.Sh DESCRIPTION
+The
+.Nm bsddialog
+utility builds Text User Interface dialogs and widgets.
+.Pp
+The option
+.Fl Fl help
+prints a brief list of features and exits.
+The option
+.Fl Fl version
+prints the version and exits.
+The option
+.Fl Fl and-dialog
+builds another dialog unless the previous one returns Error, ESC or Cancel.
+.Pp
+Each dialog accepts
+.Ar text
+to print a message inside,
+.Ar rows
+and
+.Ar cols
+to set height and width,
+.Dv 0
+for autosize and
+.Dv -1
+for fullscreen.
+.Pp
+The possible input from the user interface is printed to standard error at exit.
+.Ss Options
+The following options can change the default behavior of the utility and are
+common to some dialog.
+.Bl -tag -width Ds
+.It Fl Fl alternate-screen
+Set alternate screen mode if the terminal and
+.Xr curses 3
+provide it.
+If enabled bsddialog draws to the alternate screen and restores the main screen
+after exit.
+See
+.Dq smcup
+in
+.Xr terminfo 5 .
+.It Fl Fl ascii-lines
+Ascii characters to draw lines.
+.It Fl Fl backtitle Ar backtitle
+Screen title.
+.It Fl Fl begin-x Ar x
+Set dialog horizontal position,
+.Dv -1
+center,
+.Dv 0
+left screen.
+.It Fl Fl begin-y Ar y
+Set dialog vertical position,
+.Dv -1
+center,
+.Dv 0
+top screen.
+.It Fl Fl bikeshed
+Random settings.
+Colors, title delimiter, button delimiter; see theme features.
+Title margin.
+Buttons always active or TAB to switch focus with other components, see
+.Fl Fl switch-buttons .
+Zero padding with time output; see
+.Fl Fl time-format .
+Zero padding with date output; see
+.Fl Fl date-format .
+User Interface date format for
+.Fl Fl datebox ;
+see
+.Fl Fl datebox-format .
+.It Fl Fl cancel-exit-code Ar retval
+Set an exit code value for the
+.Dq Cancel
+button.
+.It Fl Fl cancel-label Ar label
+Label for the
+.Dq Cancel
+button.
+.It Fl Fl clear-dialog
+Hide the dialog at exit.
+.It Fl Fl clear-screen
+Clear the screen, wait a dialog if built.
+.It Fl Fl columns-per-row Ar columns
+Try to set the number of columns for a row of text with autosizing; default
+.Dv 10 .
+.It Fl Fl cr-wrap
+Keep new line in
+.Ar text
+also if it constains a
+.Dq \en ,
+see
+.Fl Fl text-unchanged .
+.It Fl Fl datebox-format Ar format
+String to customize
+.Fl Fl datebox
+interface, possible values:
+.Dq d/m/y ,
+.Dq m/y/d ,
+.Dq y/m/d .
+.It Fl Fl date-format Ar format
+String accepted by
+.Xr strftime 3
+to customize the output of
+.Fl Fl datebox
+and
+.Fl Fl calendar .
+.It Fl Fl default-button Ar label
+Focus on the button with
+.Ar label
+on startup.
+.It Fl Fl default-item Ar name
+Focus on the item with
+.Ar name ,
+for Checklist, Menu, Radiolist and Treeview.
+.It Fl Fl default-no
+Focus on
+.Dq Cancel
+or
+.Dq \&No
+button on startup.
+.It Fl Fl disable-esc
+Disable ESC key to quit.
+.It Fl Fl error-exit-code Ar retval
+Set an exit code value for the
+.Nm
+errors.
+.It Fl Fl esc-exit-code Ar retval
+Set an exit code value for the
+.Dv ESC
+key.
+.It Fl Fl extra-button
+Add a button with
+.Dq Extra
+label.
+.It Fl Fl extra-exit-code Ar retval
+Set an exit code value for the
+.Dq Extra
+button.
+.It Fl Fl extra-label Ar label
+Set
+.Ar label
+for the
+.Dq Extra
+button.
+.It Fl Fl left1-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl left1-exit-code Ar retval
+Set an exit code for
+.Fl Fl left1-button .
+.It Fl Fl left2-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl left2-exit-code Ar retval
+Set an exit code for
+.Fl Fl left2-button .
+.It Fl Fl left3-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl left3-exit-code Ar retval
+Set an exit code for
+.Fl Fl left3-button .
+.It Fl Fl help-button
+Add a button with
+.Dq Help
+label.
+.It Fl Fl help-exit-code Ar retval
+Set an exit code value for the
+.Dq Help
+button.
+.It Fl Fl help-label Ar label
+Set
+.Ar label
+for
+.Dq Help
+button.
+.It Fl Fl help-print-items
+Print also the selected items or form values if the
+.Dq Help
+button is pressed.
+.It Fl Fl help-print-name
+Print the name of the focused item if the
+.Dq Help
+button is pressed also
+with
+.Fl Fl item-bottom-desc .
+.It Fl Fl hfile Ar filename
+Open
+.Ar filename
+in a Textbox if F1 key is pressed.
+.It Fl Fl hline Ar string
+Dialog subtitle.
+.It Fl Fl hmsg Ar string
+Open a Msgbox with
+.Ar string
+if the F1 key is pressed.
+.It Fl Fl ignore
+Do not exit with unknown options.
+.It Fl Fl insecure
+Print
+.Sq *
+to hide passwords while typing, white space otherwise.
+.It Fl Fl item-bottom-desc
+Set a help string for each item of a Checklist, Form, Menu, Mixedform,
+Passwordform, Radiolist and Treeview to display at the bottom screen side.
+.It Fl Fl item-depth
+Specify a margin for items, available for Checklist, Menu and Radiolist.
+.It Fl Fl item-prefix
+Set a string to prefix each item of a Checklist, Menu, Radiolist or Treeview.
+.It Fl Fl load-theme Ar file
+Load theme from
+.Ar file .
+.It Fl Fl max-input Ar size
+Maximum length of the input for
+.Fl Fl inputbox
+and
+.Fl Fl passwordbox ,
+default 2048.
+.It Fl Fl no-cancel
+Do not show
+.Dq Cancel
+button.
+.It Fl Fl no-descriptions
+Do not display items desciption, for Checklist, Menu, Radiolist or Treeview;
+mutually exclusive with
+.Fl Fl no-names .
+.It Fl Fl no-lines
+Do not draw borders and lines.
+.It Fl Fl no-names
+Do not display items name, for Checklist, Menu and Radiolist; mutually exclusive
+with
+.Fl Fl no-descriptions .
+.It Fl Fl no-ok
+Do not draw
+.Dq OK
+button.
+.It Fl Fl no-shadow
+No not draw the shadow of the dialog.
+.It Fl Fl ok-label Ar label
+Set
+.Ar label
+for
+.Dq OK
+button.
+.It Fl Fl ok-exit-code Ar retval
+Set an exit code value for the
+.Dq Ok
+button.
+.It Fl Fl normal-screen
+Set normal screen mode.
+bsddialog does not restore the previous screen after exit.
+See
+.Dq rmcup
+in
+.Xr terminfo 5 .
+.It Fl Fl output-fd Ar fd
+Print input from user interface to the specified file descriptor.
+.It Fl Fl output-separator Ar sep
+Set a sepator for the items in output, default white space.
+.It Fl Fl print-maxsize
+Screen size.
+This option can be used without a dialog.
+.It Fl Fl print-size
+Print dialog height and width at exit.
+.It Fl Fl print-version
+Print version.
+This option can be used without a dialog.
+.It Fl Fl quoted
+Quote items in output, default only when necessary.
+.It Fl Fl right1-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl right1-exit-code Ar retval
+Set an exit code for
+.Fl Fl right1-button .
+.It Fl Fl right2-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl right2-exit-code Ar retval
+Set an exit code for
+.Fl Fl right2-button .
+.It Fl Fl right3-button Ar label
+Add a button with
+.Ar label .
+.It Fl Fl right3-exit-code Ar retval
+Set an exit code for
+.Fl Fl right3-button .
+.It Fl Fl save-theme Ar file
+Save the current theme.
+This option can be used without a dialog.
+.It Fl Fl separate-output
+Print selected items separated by a new line and avoid to quote.
+.It Fl Fl shadow
+Show a shadow for the dialog, enabled by default.
+.It Fl Fl single-quoted
+Use single quote for items in output.
+.It Fl Fl sleep Ar secs
+Wait
+.Ar secs
+seconds to close the dialog.
+.It Fl Fl stderr
+Print input from user interface to standand error, default.
+.It Fl Fl stdout
+Print input from user interface to standard output.
+.It Fl Fl switch-buttons
+Enable focus switching between buttons and input components pressing TAB,
+otherwise buttons are always active and ENTER key closes the dialog.
+Suitable for:
+.Fl Fl form ,
+.Fl Fl inputbox ,
+.Fl Fl mixedform ,
+.Fl Fl passwordbox ,
+.Fl Fl passwordform ,
+.Fl Fl timebox ,
+.Fl Fl calendar
+and
+.Fl Fl datebox .
+.It Fl Fl tab-escape
+Replace
+.Dq \et
+with a tab in
+.Ar text .
+.It Fl Fl tab-len Ar spaces
+Number of spaces to print a TAB in
+.Ar text .
+.It Fl Fl text-escape
+Enable escapes in
+.Ar text :
+.Bl -column -compact
+.It Dq \eZ0
+black.
+.It Dq \eZ1
+red.
+.It Dq \eZ2
+green.
+.It Dq \eZ3
+yellow.
+.It Dq \eZ4
+blue.
+.It Dq \eZ5
+magenta.
+.It Dq \eZ6
+cyan.
+.It Dq \eZ7
+white.
+.It Dq \eZb
+bold.
+.It Dq \eZB
+disable bold.
+.It Dq \eZd
+Half bright.
+.It Dq \eZD
+disable half bright.
+.It Dq \eZk
+Blink.
+.It Dq \eZK
+disable blinking.
+.It Dq \eZr
+reverse foreground and background.
+.It Dq \eZR
+disable reverse.
+.It Dq \eZs
+Highlight.
+.It Dq \eZS
+disable highlighting.
+.It Dq \eZu
+underline.
+.It Dq \eZU
+disable underline.
+.It Dq \eZn
+disable each customization.
+.El
+.It Fl Fl text-unchanged
+Disable
+.Ar text
+modification.
+By default
+.Ar text
+is changed before to be printed in the dialog.
+If it contains at least a
+.Dq \en
+each new line and TAB is converted to a space, subsequent spaces are merged.
+Otherwise new line characters are preserved and a TAB becomes a space.
+.It Fl Fl theme Ar theme
+Set theme, possible values:
+.Dq 3d ,
+.Dq blackwhite ,
+.Dq flat .
+.It Fl Fl time-format Ar format
+String accepted by
+.Xr strftime 3
+to customize the output of
+.Fl Fl timebox .
+.It Fl Fl timeout-exit-code Ar retval
+Set an exit code value for the
+.Fl Fl pause
+timeout.
+.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
+.It Fl Fl calendar Ar text Ar rows Ar cols Op Ar day Ar month Ar year
+Dialog to select a date.
+.It Fl Fl checklist Ar text Ar rows Ar cols Ar menurows Oo Ar name Ar desc \
+Ar status Oc ...
+Checklist to select some item from a list via the SPACE key.
+An item has a
+.Ar name ,
+.Ar desc
+and a default
+.Ar status
+specified by
+.Dq on
+or
+.Dq off .
+The names of the selected items are printed to standard error.
+.Ar menurows
+is the graphical height of the list, 0 for autosize.
+.It Fl Fl datebox Ar text Ar rows Ar cols Op Ar day Ar month Ar year
+Dialog to select a date.
+.It Fl Fl form Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
+Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters Oc ...
+Dialog to get a list of strings via forms.
+A form has a
+.Ar label
+at the position
+.Ar ylabel
+and
+.Ar xlabel ,
+a field to get the input at the position
+.Ar yfield
+and
+.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.
+The field input is not printed to output if it is readonly.
+.Ar maxletters
+is the maximum input length, if is
+.Dv 0
+its value is
+.Ar fieldlen .
+.Ar init
+is the default value in the field.
+.Ar formrows
+is the graphical height of the list,
+.Dv 0
+for autosize.
+.It Fl Fl gauge Ar text Ar rows Ar cols Op Ar percentage
+Dialog with a bar to shows
+.Ar percentage ,
+then it waits to read
+.Dq XXX
+from the standard input, then the first string replaces percentage and the
+following strings replace
+.Ar text
+until the next
+.Dq XXX ,
+the loop ends reading
+.Dq EOF .
+.It Fl Fl infobox Ar text Ar rows Ar cols
+Dialog without buttons to display a message and to exit immediately.
+.It Fl Fl inputbox Ar text Ar rows Ar cols Op Ar init
+Dialog to get a string in input,
+.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.
+An item has a
+.Ar name
+and a
+.Ar desc .
+The name of the selected item is printed to standard error.
+.Ar menurows
+is the graphical height of the list, 0 for autosize.
+.It Fl Fl mixedform Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
+Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters Ar flag Oc ...
+Dialog to get a list of strings via forms.
+A form has a
+.Ar label
+at the position
+.Ar ylabel
+and
+.Ar xlabel ,
+a field to get the input at the position
+.Ar yfield
+and
+.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.
+The field input is not printed to output if
+.Ar fieldlen
+is less than or equal to
+.Dv 0 .
+.Ar maxletters
+is the maximum input length, if is
+.Dv 0
+its value is
+.Ar fieldlen .
+.Ar init
+is the default value in the field.
+.Ar flag
+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
+for autosize.
+.It Fl Fl mixedgauge Ar text Ar rows Ar cols Ar mainperc Oo Ar minilabel \
+Ar miniperc Oc ...
+Dialog to show a main bar to represent
+.Ar mainperc
+from 0 to 100.
+Some mini bar with a
+.Ar minilabel
+string and a
+.Ar miniperc
+with a value from 0 and 100 or negative to print a descriptive string: -1
+.Dq Succeeded ,
+-2
+.Dq Failed ,
+-3
+.Dq Passed ,
+-4
+.Dq Completed ,
+-5
+.Dq Checked ,
+-6
+.Dq Done ,
+-7
+.Dq Skipped ,
+-8
+.Dq \&In Progress ,
+-9
+to hide
+.Fa miniperc ,
+-10
+.Dq N/A ,
+-11
+.Dq Pending ,
+otherwise
+.Dq UNKNOWN .
+.It Fl Fl msgbox Ar text Ar rows Ar cols
+Dialog to diplay a message without the
+.Dq Cancel
+button.
+.It Fl Fl passwordbox Ar text Ar rows Ar cols Op Ar init
+Dialog to get a password,
+.Ar init
+is the default value.
+.It Fl Fl passwordform Ar text Ar rows Ar cols Ar formrows Oo Ar label \
+Ar ylabel Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters \
+Oc ...
+Dialog to get a list of passwords, equivalent to
+.Fl Fl form
+except typed characters are hidden.
+.It Fl Fl pause Ar text Ar rows Ar cols Ar seconds
+Dialog runs until
+.Ar seconds
+timeout expires or a button is pressed.
+.It Fl Fl radiolist Ar text Ar rows Ar cols Ar menurows Oo Ar name Ar desc \
+Ar status Oc ...
+Radiolist to select at most an item from a list via the SPACE key.
+An item has a
+.Ar name ,
+.Ar desc
+and a default
+.Ar status
+specified by
+.Dq on
+or
+.Dq off .
+The name of the selected item is printed to standard error.
+.Ar menurows
+is the graphical height of the list, 0 for autosize.
+.It Fl Fl rangebox Ar text Ar rows Ar cols Ar min Ar max Op Ar init
+Dialog to select a value between
+.Ar min
+and
+.Ar max ,
+.Ar init
+is the default value.
+.It Fl Fl textbox Ar file Ar rows Ar cols
+Opens and prints
+.Ar file .
+TAB changes button.
+Extra keys 0, h, l, k, j are available to navigate the text.
+.Dq OK
+button is renamed
+.Dq EXIT .
+.It Fl Fl timebox Ar text Ar rows Ar cols Op Ar hour Ar min Ar sec
+Dialog to select a time.
+.It Fl Fl treeview Ar text Ar rows Ar cols Ar menurows Oo Ar depth Ar name \
+Ar desc Ar status Oc ...
+Equivalent to Radiolist with
+.Fl Fl item-depth
+and
+.Fl Fl no-name .
+.It Fl Fl yesno Ar text Ar rows Ar cols
+.Dq Yes-No Question ,
+.Dq OK
+and
+.Dq Cancel
+buttons are renamed
+.Dq Yes
+and
+.Dq \&No .
+.El
+.Sh ENVIRONMENT
+The following environment variables take effect only on startup, other options
+can override their setting.
+.Bl -tag -width indent
+.It Ev NO_COLOR
+If present and not an empty string (regardless of its value) equivalent to
+.Fl Fl theme Ar blackwhite .
+.It Ev BSDDIALOG_ERROR , Ev BSDDIALOG_OK , Ev BSDDIALOG_CANCEL , \
+Ev BSDDIALOG_HELP , Ev BSDDIALOG_EXTRA , Ev BSDDIALOG_TIMEOUT , \
+Ev BSDDIALOG_ESC , Ev BSDDIALOG_LEFT1 , Ev BSDDIALOG_LEFT2 , \
+Ev BSDDIALOG_LEFT3 , Ev BSDDIALOG_RIGHT1 , Ev BSDDIALOG_RIGHT2 , \
+Ev BSDDIALOG_RIGHT3
+Set exit codes.
+.It Ev BSDDIALOG_THEMEFILE Ar file
+Equivalent to
+.Fl Fl load-theme Ar file .
+.El
+.Sh FILES
+The theme file
+.Pa $HOME/.bsddialog.conf
+is read on startup if exists.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 255 on unsuccessful, otherwise depending on the button or key
+pressed the following values can be returned:
+.Bl -column -compact
+.It 0
+.Dq OK ,
+.Dq Yes
+or
+.Dq Exit
+button.
+.It 1
+.Dq Cancel
+or
+.Dq \&No
+button.
+.It 2
+.Dq Help
+button.
+.It 3
+.Dq Extra
+button.
+.It 4
+Timeout.
+.It 5
+ESC key.
+.It 6
+Left1 generic button.
+.It 7
+Left2 generic button.
+.It 8
+Left3 generic button.
+.It 9
+Right1 generic button.
+.It 10
+Right2 generic button.
+.It 11
+Right3 generic button.
+.El
+.Sh EXAMPLES
+Backtitle, title and message:
+.Dl bsddialog --backtitle MESSAGE --title Msgbox --msgbox Message 0 0
+.Pp
+Yes-No Question and theme:
+.Dl bsddialog --theme blackwhite --yesno Question 10 30
+.Pp
+Save a custom theme:
+.Dl bsddialog --save-theme mytheme.txt --infobox \*qSaving theme...\*q 0 0
+.Pp
+Load a custom theme:
+.Dl bsddialog --load-theme mytheme.txt --infobox \*qCustom theme\*q 0 0
+.Pp
+Checklist:
+.Dl bsddialog --checklist Checklist 0 0 3 N1 \&D1 off N2 D2 on N3 D3 off
+.Pp
+Form:
+.Dl bsddialog --form Form 0 0 0 L1: 0 0 X 0 4 20 25 L2: 1 0 Y 1 4 20 25
+.Pp
+Multi-dialog:
+.Dl bsddialog --normal-screen --begin-y 1 --yesno Continue? 0 0 \e \
+--and-dialog --begin-y 10 --infobox Yes 0 0
+.Pp
+Bikeshed:
+.Dl bsddialog --bikeshed --inputbox Example 0 0
+.Dl bsddialog --bikeshed --datebox Example 0 0
+.Pp
+Mixedgauge:
+.Dl bsddialog --sleep 3 --mixedgauge Example 10 30 60 L1 \*q -1\*q L2 30
+.Pp
+Mixedgauge script:
+.Bd -literal -offset indent -compact
+perc=0
+while [ $perc -le 100 ]
+do
+ bsddialog --sleep 1 --title Mixedgauge \e
+ --mixedgauge "\enExample...\en" 0 0 $perc \e
+ "Hidden" " -9" \e
+ "Label 1" " -4" \e
+ "Label 2" " -4" \e
+ "Label 3" $perc
+
+ perc=`expr $perc + 20`
+done
+.Ed
+.Pp
+Gauge script:
+.Bd -literal -offset indent -compact
+i=1
+for c in A B C D E F G H
+do
+ sleep 1
+ echo XXX
+ echo "$(expr $(expr $i "*" 100) "/" 8)"
+ echo "[$i/8] Char: $c"
+ echo XXX
+ if [ $i -eq 8 ]
+ then
+ sleep 1
+ echo EOF
+ fi
+ i=`expr $i + 1`
+done | bsddialog --title Gauge --gauge "Starting..." 10 70
+.Ed
+.Sh COMPATIBILITY
+Outdated options are retained for compatibility, properly equivalent options are
+used:
+.Bd -literal -offset indent -compact
+Obsolete Equivalent
+--and-widget --and-dialog
+--calendar <text> 2 <cols> --calendar <text> 0 <cols>
+--clear --clear-screen
+--colors --text-escape
+--defaultno --default-no
+--exit-label --ok-label
+--help-status --help-print-items
+--help-tags --help-print-name
+--item-help --item-bottom-desc
+--keep-tite --alternate-screen
+--no-items --no-descriptions
+--no-label --cancel-label
+--no-tags --no-names
+--nocancel --no-cancel
+--nook --no-ok
+--separator --output-separator
+--yes-label --ok-label
+.Ed
+.Sh SEE ALSO
+.Xr bsddialog 3 ,
+.Xr strftime 3 ,
+.Xr terminfo 5
+.Sh HISTORY
+The
+.Nm bsddialog
+utility first appeared in
+.Fx 14.0 .
+.Sh AUTHORS
+.Nm bsddialog
+was written by
+.An Alfonso Sabato Siciliano
+.Aq Mt asiciliano@FreeBSD.org .
+.Pp
+.Nm bsddialog
+provides also a subset of the functionality described in the
+.Nm dialog
+manual.
+The following features were reimplemented:
+.Pp
+Options:
+.Fl Fl and-widget ,
+.Fl Fl ascii-lines ,
+.Fl Fl backtitle ,
+.Fl Fl cancel-label ,
+.Fl Fl clear ,
+.Fl Fl colors ,
+.Fl Fl cr-wrap ,
+.Fl Fl date-format ,
+.Fl Fl defaultno ,
+.Fl Fl default-button ,
+.Fl Fl default-no ,
+.Fl Fl default-item ,
+.Fl Fl exit-label ,
+.Fl Fl extra-button ,
+.Fl Fl extra-label ,
+.Fl Fl help ,
+.Fl Fl help-button ,
+.Fl Fl help-label ,
+.Fl Fl help-status ,
+.Fl Fl help-tags ,
+.Fl Fl hfile ,
+.Fl Fl hline ,
+.Fl Fl ignore ,
+.Fl Fl insecure ,
+.Fl Fl item-help ,
+.Fl Fl keep-tite ,
+.Fl Fl max-input ,
+.Fl Fl no-cancel ,
+.Fl Fl nocancel ,
+.Fl Fl no-items ,
+.Fl Fl no-label ,
+.Fl Fl no-lines ,
+.Fl Fl no-ok ,
+.Fl Fl nook ,
+.Fl Fl no-shadow ,
+.Fl Fl no-tags ,
+.Fl Fl ok-label ,
+.Fl Fl output-fd ,
+.Fl Fl output-separator ,
+.Fl Fl print-maxsize ,
+.Fl Fl print-size ,
+.Fl Fl print-version ,
+.Fl Fl quoted ,
+.Fl Fl separate-output ,
+.Fl Fl separator ,
+.Fl Fl shadow ,
+.Fl Fl single-quoted ,
+.Fl Fl sleep ,
+.Fl Fl stderr ,
+.Fl Fl stdout ,
+.Fl Fl tab-len ,
+.Fl Fl time-format ,
+.Fl Fl title ,
+.Fl Fl version ,
+.Fl Fl yes-label .
+.Pp
+Keys: Ctrl-l, F1.
+.Pp
+Dialogs:
+.Fl Fl calendar ,
+.Fl Fl checklist ,
+.Fl Fl form ,
+.Fl Fl gauge ,
+.Fl Fl infobox ,
+.Fl Fl inputbox ,
+.Fl Fl menu ,
+.Fl Fl mixedform ,
+.Fl Fl mixedgauge ,
+.Fl Fl msgbox ,
+.Fl Fl passwordbox ,
+.Fl Fl passwordform ,
+.Fl Fl pause ,
+.Fl Fl radiolist ,
+.Fl Fl rangebox ,
+.Fl Fl textbox ,
+.Fl Fl timebox ,
+.Fl Fl treeview ,
+.Fl Fl yesno .
+.Pp
+Some feature differs in input, output, or behavior.
+Compatibility is not a priority for future development.
+.Sh THANKS TO
+.An Baptiste Daroussin
+.Aq Mt bapt@FreeBSD.org ,
+.An \&Ed Maste
+.Aq Mt emaste@FreeBSD.org ,
+.An Juraj Lutter
+.Aq Mt otis@FreeBSD.org
+and
+.An Trenton Schulz
+for suggestions, help, and testing.
diff --git a/contrib/bsddialog/utility/bsddialog.c b/contrib/bsddialog/utility/bsddialog.c
new file mode 100644
index 000000000000..bce1d0ab8452
--- /dev/null
+++ b/contrib/bsddialog/utility/bsddialog.c
@@ -0,0 +1,338 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <getopt.h>
+#include <limits.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <term.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#include "util.h"
+
+#define EXITCODE(retval) (exitcodes[retval + 1].value)
+#define UNUSED_PAR(x) UNUSED_ ## x __attribute__((__unused__))
+
+static void custom_text(struct options *opt, char *text, char *buf);
+
+/* Exit codes */
+struct exitcode {
+ const char *name;
+ int value;
+};
+
+static struct exitcode exitcodes[14] = {
+ { "BSDDIALOG_ERROR", 255 },
+ { "BSDDIALOG_OK", 0 },
+ { "BSDDIALOG_CANCEL", 1 },
+ { "BSDDIALOG_HELP", 2 },
+ { "BSDDIALOG_EXTRA", 3 },
+ { "BSDDIALOG_TIMEOUT", 4 },
+ { "BSDDIALOG_ESC", 5 },
+ { "BSDDIALOG_LEFT1", 6 },
+ { "BSDDIALOG_LEFT2", 7 },
+ { "BSDDIALOG_LEFT3", 8 },
+ { "BSDDIALOG_RIGHT1", 9 },
+ { "BSDDIALOG_RIGHT2", 10 },
+ { "BSDDIALOG_RIGHT3", 11 },
+ { "BSDDIALOG_ITEM_HELP", 2 } /* like HELP by default */
+};
+
+void set_exit_code(int lib_retval, int exitcode)
+{
+ exitcodes[lib_retval + 1].value = exitcode;
+}
+
+/* Error */
+void exit_error(bool usage, const char *fmt, ...)
+{
+ va_list arg_ptr;
+
+ if (bsddialog_inmode())
+ bsddialog_end();
+ printf("Error: ");
+ va_start(arg_ptr, fmt);
+ vprintf(fmt, arg_ptr);
+ va_end(arg_ptr);
+ printf(".\n\n");
+ if (usage) {
+ printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
+ printf("for more information.\n");
+ }
+
+ exit (EXITCODE(BSDDIALOG_ERROR));
+}
+
+void error_args(const char *dialog, int argc, char **argv)
+{
+ int i;
+
+ if (bsddialog_inmode())
+ bsddialog_end();
+ printf("Error: %s unexpected argument%s:", dialog, argc > 1 ? "s" : "");
+ for (i = 0; i < argc; i++)
+ printf(" \"%s\"", argv[i]);
+ printf(".\n\n");
+ printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
+ printf("for more information.\n");
+
+ exit (EXITCODE(BSDDIALOG_ERROR));
+}
+
+/* init */
+static void sigint_handler(int UNUSED_PAR(sig))
+{
+ bsddialog_end();
+
+ exit(EXITCODE(BSDDIALOG_ERROR));
+}
+
+static void start_bsddialog_mode(void)
+{
+ if (bsddialog_inmode())
+ return;
+ if (bsddialog_init() != BSDDIALOG_OK)
+ exit_error(false, bsddialog_geterror());
+
+ signal(SIGINT, sigint_handler);
+}
+
+static void getenv_exitcodes(void)
+{
+ int i;
+ int value;
+ char *envvalue;
+
+ for (i = 0; i < 10; i++) {
+ envvalue = getenv(exitcodes[i].name);
+ if (envvalue == NULL || envvalue[0] == '\0')
+ continue;
+ value = (int)strtol(envvalue, NULL, 10);
+ exitcodes[i].value = value;
+ /* ITEM_HELP follows HELP without explicit setting */
+ if (i == BSDDIALOG_HELP + 1)
+ exitcodes[BSDDIALOG_ITEM_HELP + 1].value = value;
+ }
+}
+
+/*
+ * bsddialog utility: TUI widgets and dialogs.
+ */
+int main(int argc, char *argv[argc])
+{
+ bool startup;
+ int i, rows, cols, retval, parsed, nargc, firstoptind;
+ char *text, **nargv, *pn;
+ struct bsddialog_conf conf;
+ struct options opt;
+
+ setlocale(LC_ALL, "");
+ getenv_exitcodes();
+ firstoptind = optind;
+ pn = argv[0];
+ retval = BSDDIALOG_OK;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "--version") == 0) {
+ printf("Version: %s\n", LIBBSDDIALOG_VERSION);
+ return (BSDDIALOG_OK);
+ }
+ if (strcmp(argv[i], "--help") == 0) {
+ usage();
+ return (BSDDIALOG_OK);
+ }
+ }
+
+ startup = true;
+ while (true) {
+ parsed = parseargs(argc, argv, &conf, &opt);
+ nargc = argc - parsed;
+ nargv = argv + parsed;
+ argc = parsed - optind;
+ argv += optind;
+
+ if (opt.mandatory_dialog && opt.dialogbuilder == NULL)
+ exit_error(true, "expected a --<dialog>");
+
+ if (opt.dialogbuilder == NULL && argc > 0)
+ error_args("(no --<dialog>)", argc, argv);
+
+ /* --print-maxsize or --print-version */
+ if (opt.mandatory_dialog == false && opt.clearscreen == false &&
+ opt.savethemefile == NULL && opt.dialogbuilder == NULL) {
+ retval = BSDDIALOG_OK;
+ break;
+ }
+
+ /* --<dialog>, --save-theme or clear-screen */
+ text = NULL; /* useless inits, fix compiler warnings */
+ rows = BSDDIALOG_AUTOSIZE;
+ cols = BSDDIALOG_AUTOSIZE;
+ if (opt.dialogbuilder != NULL) {
+ if (argc < 3)
+ exit_error(true,
+ "expected <text> <rows> <cols>");
+ if ((text = strdup(argv[0])) == NULL)
+ exit_error(false, "cannot allocate <text>");
+ if (opt.dialogbuilder != textbox_builder)
+ custom_text(&opt, argv[0], text);
+ rows = (int)strtol(argv[1], NULL, 10);
+ cols = (int)strtol(argv[2], NULL, 10);
+ argc -= 3;
+ argv += 3;
+ }
+
+ /* bsddialog terminal mode (first iteration) */
+ start_bsddialog_mode();
+
+ if (opt.screen_mode != NULL) {
+ opt.screen_mode = tigetstr(opt.screen_mode);
+ if (opt.screen_mode != NULL &&
+ opt.screen_mode != (char*)-1) {
+ tputs(opt.screen_mode, 1, putchar);
+ fflush(stdout);
+ bsddialog_refresh();
+ }
+ }
+
+ /* theme */
+ if (startup)
+ startuptheme();
+ startup = false;
+ if ((int)opt.theme >= 0)
+ setdeftheme(opt.theme);
+ if (opt.loadthemefile != NULL)
+ loadtheme(opt.loadthemefile, false);
+ if (opt.bikeshed)
+ bikeshed(&conf);
+ if (opt.savethemefile != NULL)
+ savetheme(opt.savethemefile);
+
+ /* backtitle and dialog */
+ if (opt.dialogbuilder == NULL)
+ break;
+ if (opt.backtitle != NULL)
+ if (bsddialog_backtitle(&conf, opt.backtitle))
+ exit_error(false, bsddialog_geterror());
+ retval = opt.dialogbuilder(&conf, text, rows, cols, argc, argv,
+ &opt);
+ free(text);
+ if (retval == BSDDIALOG_ERROR)
+ exit_error(false, bsddialog_geterror());
+ if (conf.get_height != NULL && conf.get_width != NULL)
+ dprintf(opt.output_fd, "DialogSize: %d, %d\n",
+ *conf.get_height, *conf.get_width);
+ if (opt.clearscreen)
+ bsddialog_clear(0);
+ opt.clearscreen = false;
+ /* --and-dialog ends loop with Cancel or ESC */
+ if (retval == BSDDIALOG_CANCEL || retval == BSDDIALOG_ESC)
+ break;
+ argc = nargc;
+ argv = nargv;
+ if (argc <= 0)
+ break;
+ /* prepare next parseargs() call */
+ argc++;
+ argv--;
+ argv[0] = pn;
+ optind = firstoptind;
+ }
+
+ if (bsddialog_inmode()) {
+ /* --clear-screen can be a single option */
+ if (opt.clearscreen)
+ bsddialog_clear(0);
+ bsddialog_end();
+ }
+ /* end bsddialog terminal mode */
+
+ return (EXITCODE(retval));
+}
+
+void custom_text(struct options *opt, char *text, char *buf)
+{
+ bool trim, crwrap;
+ int i, j;
+
+ if (strstr(text, "\\n") == NULL) {
+ /* "hasnl" mode */
+ trim = true;
+ crwrap = true;
+ } else {
+ trim = false;
+ crwrap = opt->cr_wrap;
+ }
+ if (opt->text_unchanged) {
+ trim = false;
+ crwrap = true;
+ }
+
+ i = j = 0;
+ while (text[i] != '\0') {
+ switch (text[i]) {
+ case '\\':
+ buf[j] = '\\';
+ switch (text[i+1]) {
+ case 'n': /* implicitly in "hasnl" mode */
+ buf[j] = '\n';
+ i++;
+ if (text[i+1] == '\n')
+ i++;
+ break;
+ case 't':
+ if (opt->tab_escape) {
+ buf[j] = '\t';
+ } else {
+ j++;
+ buf[j] = 't';
+ }
+ i++;
+ break;
+ }
+ break;
+ case '\n':
+ buf[j] = crwrap ? '\n' : ' ';
+ break;
+ case '\t':
+ buf[j] = opt->text_unchanged ? '\t' : ' ';
+ break;
+ default:
+ buf[j] = text[i];
+ }
+ i++;
+ if (!trim || buf[j] != ' ' || j == 0 || buf[j-1] != ' ')
+ j++;
+ }
+ buf[j] = '\0';
+}
diff --git a/contrib/bsddialog/utility/util.h b/contrib/bsddialog/utility/util.h
new file mode 100644
index 000000000000..d1f7793c9755
--- /dev/null
+++ b/contrib/bsddialog/utility/util.h
@@ -0,0 +1,125 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSDDIALOG_UTIL_H_
+#define _BSDDIALOG_UTIL_H_
+
+/*
+ * Exit codes and errors, bsddialog.c
+ */
+#define BSDDIALOG_ITEM_HELP 12
+
+void set_exit_code(int lib_retval, int exitcode);
+void exit_error(bool usage, const char *fmt, ...);
+void error_args(const char *dialog, int argc, char **argv);
+
+/*
+ * Command Line, util_cli.c
+ */
+struct options {
+ /* Menus options */
+ bool item_always_quote;
+ char *item_default;
+ bool item_depth;
+ char *item_output_sep;
+ bool item_output_sepnl;
+ bool item_prefix;
+ bool item_singlequote;
+ /* Menus and Forms options */
+ bool help_print_item_name;
+ bool help_print_items;
+ bool item_bottomdesc;
+ /* Forms options */
+ int unsigned max_input_form;
+ /* Date and Time options */
+ char *date_fmt;
+ char *time_fmt;
+ /* General options */
+ int getH;
+ int getW;
+ bool ignore;
+ int output_fd;
+ /* Text option */
+ bool cr_wrap;
+ bool tab_escape;
+ bool text_unchanged;
+ /* Theme and Screen options*/
+ char *backtitle;
+ bool bikeshed;
+ enum bsddialog_default_theme theme;
+ bool clearscreen;
+ char *loadthemefile;
+ char *savethemefile;
+ const char *screen_mode;
+ /* Dialog */
+ bool mandatory_dialog;
+ const char *name;
+ int (*dialogbuilder)(struct bsddialog_conf *conf, char* text, int rows,
+ int cols, int argc, char **argv, struct options *opt);
+};
+
+void usage(void);
+int
+parseargs(int argc, char **argv, struct bsddialog_conf *conf,
+ struct options *opt);
+
+/*
+ * Dialogs builders, util_builders.c
+ */
+#define BUILDER_ARGS struct bsddialog_conf *conf, char* text, int rows, \
+ int cols, int argc, char **argv, struct options *opt
+int calendar_builder(BUILDER_ARGS);
+int checklist_builder(BUILDER_ARGS);
+int datebox_builder(BUILDER_ARGS);
+int form_builder(BUILDER_ARGS);
+int gauge_builder(BUILDER_ARGS);
+int infobox_builder(BUILDER_ARGS);
+int inputbox_builder(BUILDER_ARGS);
+int menu_builder(BUILDER_ARGS);
+int mixedform_builder(BUILDER_ARGS);
+int mixedgauge_builder(BUILDER_ARGS);
+int msgbox_builder(BUILDER_ARGS);
+int passwordbox_builder(BUILDER_ARGS);
+int passwordform_builder(BUILDER_ARGS);
+int pause_builder(BUILDER_ARGS);
+int radiolist_builder(BUILDER_ARGS);
+int rangebox_builder(BUILDER_ARGS);
+int textbox_builder(BUILDER_ARGS);
+int timebox_builder(BUILDER_ARGS);
+int treeview_builder(BUILDER_ARGS);
+int yesno_builder(BUILDER_ARGS);
+
+/*
+ * Theme, util_theme.c
+ */
+void savetheme(const char *file);
+void loadtheme(const char *file, bool compatibility);
+void setdeftheme(enum bsddialog_default_theme theme);
+void bikeshed(struct bsddialog_conf *conf);
+void startuptheme(void);
+
+#endif
diff --git a/contrib/bsddialog/utility/util_builders.c b/contrib/bsddialog/utility/util_builders.c
new file mode 100644
index 000000000000..0a968d4319f9
--- /dev/null
+++ b/contrib/bsddialog/utility/util_builders.c
@@ -0,0 +1,811 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#include "util.h"
+
+#define NO_PRINT_VALUES(rv) \
+(rv == BSDDIALOG_ERROR || rv == BSDDIALOG_CANCEL || rv == BSDDIALOG_ESC)
+
+/* message */
+int infobox_builder(BUILDER_ARGS)
+{
+ if (argc > 0)
+ error_args(opt->name, argc, argv);
+
+ return (bsddialog_infobox(conf, text, rows, cols));
+}
+
+int msgbox_builder(BUILDER_ARGS)
+{
+ if (argc > 0)
+ error_args(opt->name, argc, argv);
+
+ return (bsddialog_msgbox(conf, text, rows, cols));
+}
+
+int yesno_builder(BUILDER_ARGS)
+{
+ if (argc > 0)
+ error_args(opt->name, argc, argv);
+
+ return (bsddialog_yesno(conf, text, rows, cols));
+}
+
+/* textbox */
+int textbox_builder(BUILDER_ARGS)
+{
+ if (argc > 0)
+ error_args(opt->name, argc, argv);
+
+ return (bsddialog_textbox(conf, text, rows, cols));
+}
+
+/* bar */
+int gauge_builder(BUILDER_ARGS)
+{
+ int output;
+ unsigned int perc;
+
+ perc = 0;
+ if (argc == 1) {
+ perc = (unsigned int)strtoul(argv[0], NULL, 10);
+ perc = perc > 100 ? 100 : perc;
+ } else if (argc > 1) {
+ error_args(opt->name, argc - 1, argv + 1);
+ }
+
+ output = bsddialog_gauge(conf, text, rows, cols, perc, STDIN_FILENO,
+ "XXX", "EOF");
+
+ return (output);
+}
+
+int mixedgauge_builder(BUILDER_ARGS)
+{
+ int output, *minipercs;
+ unsigned int i, mainperc, nminibars;
+ const char **minilabels;
+
+ if (argc < 1)
+ exit_error(true, "%s missing <mainperc>", opt->name);
+ if (((argc-1) % 2) != 0)
+ exit_error(true,
+ "bad %s pair number [<minilabel> <miniperc>]", opt->name);
+
+ mainperc = (unsigned int)strtoul(argv[0], NULL, 10);
+ mainperc = mainperc > 100 ? 100 : mainperc;
+ argc--;
+ argv++;
+
+ nminibars = argc / 2;
+ if ((minilabels = calloc(nminibars, sizeof(char*))) == NULL)
+ exit_error(false, "Cannot allocate memory for minilabels");
+ if ((minipercs = calloc(nminibars, sizeof(int))) == NULL)
+ exit_error(false, "Cannot allocate memory for minipercs");
+
+ for (i = 0; i < nminibars; i++) {
+ minilabels[i] = argv[i * 2];
+ minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
+ }
+
+ output = bsddialog_mixedgauge(conf, text, rows, cols, mainperc,
+ nminibars, minilabels, minipercs);
+
+ return (output);
+}
+
+int pause_builder(BUILDER_ARGS)
+{
+ int output;
+ unsigned int secs;
+
+ if (argc == 0)
+ exit_error(true, "--pause missing <seconds>");
+ if (argc > 1)
+ error_args(opt->name, argc - 1, argv + 1);
+
+ secs = (unsigned int)strtoul(argv[0], NULL, 10);
+ output = bsddialog_pause(conf, text, rows, cols, &secs);
+
+ return (output);
+}
+
+int rangebox_builder(BUILDER_ARGS)
+{
+ int output, min, max, value;
+
+ if (argc < 2)
+ exit_error(true, "--rangebox missing <min> <max> [<init>]");
+ if (argc > 3)
+ error_args("--rangebox", argc - 3, argv + 3);
+
+ min = (int)strtol(argv[0], NULL, 10);
+ max = (int)strtol(argv[1], NULL, 10);
+
+ if (argc == 3) {
+ value = (int)strtol(argv[2], NULL, 10);
+ value = value < min ? min : value;
+ value = value > max ? max : value;
+ } else
+ value = min;
+
+ output = bsddialog_rangebox(conf, text, rows, cols, min, max, &value);
+ if (NO_PRINT_VALUES(output) == false)
+ dprintf(opt->output_fd, "%d", value);
+
+ return (output);
+}
+
+/* date and time */
+static int date(BUILDER_ARGS)
+{
+ int rv;
+ unsigned int yy, mm, dd;
+ time_t cal;
+ struct tm *localtm;
+ char stringdate[1024];
+
+ time(&cal);
+ localtm = localtime(&cal);
+ yy = localtm->tm_year + 1900;
+ mm = localtm->tm_mon + 1;
+ dd = localtm->tm_mday;
+
+ if (argc > 3) {
+ error_args(opt->name, argc - 3, argv + 3);
+ } else if (argc == 3) {
+ /* lib checks/sets max and min */
+ dd = (unsigned int)strtoul(argv[0], NULL, 10);
+ mm = (unsigned int)strtoul(argv[1], NULL, 10);
+ yy = (unsigned int)strtoul(argv[2], NULL, 10);
+ }
+
+ if (strcmp(opt->name, "--datebox") == 0)
+ rv = bsddialog_datebox(conf, text, rows, cols, &yy, &mm, &dd);
+ else
+ rv = bsddialog_calendar(conf, text, rows, cols, &yy, &mm, &dd);
+ if (NO_PRINT_VALUES(rv))
+ return (rv);
+
+ if (opt->date_fmt != NULL) {
+ time(&cal);
+ localtm = localtime(&cal);
+ localtm->tm_year = yy - 1900;
+ localtm->tm_mon = mm - 1;
+ localtm->tm_mday = dd;
+ strftime(stringdate, 1024, opt->date_fmt, localtm);
+ dprintf(opt->output_fd, "%s", stringdate);
+ } else if (opt->bikeshed && ~dd & 1) {
+ dprintf(opt->output_fd, "%u/%u/%u", dd, mm, yy);
+ } else {
+ dprintf(opt->output_fd, "%02u/%02u/%u", dd, mm, yy);
+ }
+
+ return (rv);
+}
+
+int calendar_builder(BUILDER_ARGS)
+{
+ /* Use height autosizing with rows = 2. Documented in bsddialog(1).
+ *
+ * f_dialog_calendar_size() in bsdconfig/share/dialog.subr:1352
+ * computes height 2 for `dialog --calendar', called by:
+ * 1) f_dialog_input_expire_password() in
+ * bsdconfig/usermgmt/share/user_input.subr:517 and
+ * 2) f_dialog_input_expire_account() in
+ * bsdconfig/usermgmt/share/user_input.subr:660.
+ *
+ * Then use height autosizing with 2 that is min height like dialog.
+ */
+ if (rows == 2)
+ rows = 0;
+
+ return (date(conf, text, rows, cols, argc, argv, opt));
+}
+
+int datebox_builder(BUILDER_ARGS)
+{
+ return (date(conf, text, rows, cols, argc, argv, opt));
+}
+
+int timebox_builder(BUILDER_ARGS)
+{
+ int output;
+ unsigned int hh, mm, ss;
+ time_t clock;
+ struct tm *localtm;
+ char stringtime[1024];
+
+ time(&clock);
+ localtm = localtime(&clock);
+ hh = localtm->tm_hour;
+ mm = localtm->tm_min;
+ ss = localtm->tm_sec;
+
+ if (argc > 3) {
+ error_args("--timebox", argc - 3, argv + 3);
+ } else if (argc == 3) {
+ hh = (unsigned int)strtoul(argv[0], NULL, 10);
+ mm = (unsigned int)strtoul(argv[1], NULL, 10);
+ ss = (unsigned int)strtoul(argv[2], NULL, 10);
+ }
+
+ output = bsddialog_timebox(conf, text, rows, cols, &hh, &mm, &ss);
+ if (NO_PRINT_VALUES(output))
+ return (output);
+
+ if (opt->time_fmt != NULL) {
+ time(&clock);
+ localtm = localtime(&clock);
+ localtm->tm_hour = hh;
+ localtm->tm_min = mm;
+ localtm->tm_sec = ss;
+ strftime(stringtime, 1024, opt->time_fmt, localtm);
+ dprintf(opt->output_fd, "%s", stringtime);
+ } else if (opt->bikeshed && ~ss & 1) {
+ dprintf(opt->output_fd, "%u:%u:%u", hh, mm, ss);
+ } else {
+ dprintf(opt->output_fd, "%02u:%02u:%02u", hh, mm, ss);
+ }
+
+ return (output);
+}
+
+/* menu */
+static void
+get_menu_items(int argc, char **argv, bool setprefix, bool setdepth,
+ bool setname, bool setdesc, bool setstatus, bool sethelp,
+ unsigned int *nitems, struct bsddialog_menuitem **items, int *focusitem,
+ struct options *opt)
+{
+ unsigned int i, j, sizeitem;
+
+ *focusitem = -1;
+
+ sizeitem = 0;
+ sizeitem += setprefix ? 1 : 0;
+ sizeitem += setdepth ? 1 : 0;
+ sizeitem += setname ? 1 : 0;
+ sizeitem += setdesc ? 1 : 0;
+ sizeitem += setstatus ? 1 : 0;
+ sizeitem += sethelp ? 1 : 0;
+ if ((argc % sizeitem) != 0)
+ exit_error(true, "%s bad arguments items number", opt->name);
+
+ *nitems = argc / sizeitem;
+ *items = calloc(*nitems, sizeof(struct bsddialog_menuitem));
+ if (items == NULL)
+ exit_error(false, "%s cannot allocate items", opt->name);
+
+ j = 0;
+ for (i = 0; i < *nitems; i++) {
+ (*items)[i].prefix = setprefix ? argv[j++] : "";
+ (*items)[i].depth = setdepth ?
+ (unsigned int)strtoul(argv[j++], NULL, 0) : 0;
+ (*items)[i].name = setname ? argv[j++] : "";
+ (*items)[i].desc = setdesc ? argv[j++] : "";
+ if (setstatus) {
+ if (strcasecmp(argv[j], "on") == 0)
+ (*items)[i].on = true;
+ else if (strcasecmp(argv[j], "off") == 0)
+ (*items)[i].on = false;
+ else
+ exit_error(true,
+ "\"%s\" (item %i) invalid status \"%s\"",
+ (*items)[i].name, i+1, argv[j]);
+ j++;
+ } else
+ (*items)[i].on = false;
+ (*items)[i].bottomdesc = sethelp ? argv[j++] : "";
+
+ if (opt->item_default != NULL && *focusitem == -1)
+ if (strcmp((*items)[i].name, opt->item_default) == 0)
+ *focusitem = i;
+ }
+}
+
+static void
+print_menu_items(int output, int nitems, struct bsddialog_menuitem *items,
+ int focusitem, struct options *opt)
+{
+ bool sep, sepbefore, sepafter, sepsecond, toquote, ismenu, ischecklist;
+ int i;
+ char quotech;
+ const char *focusname, *sepstr;
+
+ ismenu = (strcmp(opt->name, "--menu") == 0) ? true : false;
+ ischecklist = (strcmp(opt->name, "--checklist") == 0) ? true : false;
+ sep = false;
+ quotech = opt->item_singlequote ? '\'' : '"';
+
+ if (NO_PRINT_VALUES(output))
+ return;
+
+ if (output == BSDDIALOG_HELP) {
+ dprintf(opt->output_fd, "HELP ");
+
+ if (focusitem >= 0) {
+ focusname = items[focusitem].name;
+ if (opt->item_bottomdesc &&
+ opt->help_print_item_name == false)
+ focusname = items[focusitem].bottomdesc;
+
+ toquote = false;
+ if (strchr(focusname, ' ') != NULL) {
+ toquote = opt->item_always_quote;
+ if (ismenu == false &&
+ opt->item_output_sepnl == false)
+ toquote = true;
+ }
+ if (toquote) {
+ dprintf(opt->output_fd, "%c%s%c",
+ quotech, focusname, quotech);
+ } else
+ dprintf(opt->output_fd, "%s", focusname);
+ }
+
+ if (ismenu || opt->help_print_items == false)
+ return;
+ sep = true;
+ }
+
+ sepbefore = false;
+ sepsecond = false;
+ if ((sepstr = opt->item_output_sep) == NULL) {
+ if (opt->item_output_sepnl)
+ sepstr = "\n";
+ else {
+ sepstr = " ";
+ sepsecond = true;
+ }
+ } else
+ sepbefore = true;
+
+ sepafter = false;
+ if (opt->item_output_sepnl) {
+ sepbefore = false;
+ sepafter = true;
+ }
+
+ for (i = 0; i < nitems; i++) {
+ if (items[i].on == false)
+ continue;
+
+ if (sep || sepbefore)
+ dprintf(opt->output_fd, "%s", sepstr);
+ sep = false;
+ if (sepsecond)
+ sep = true;
+
+ toquote = false;
+ if (strchr(items[i].name, ' ') != NULL) {
+ toquote = opt->item_always_quote;
+ if (ischecklist && opt->item_output_sepnl == false)
+ toquote = true;
+ }
+ if (toquote)
+ dprintf(opt->output_fd, "%c%s%c",
+ quotech, items[i].name, quotech);
+ else
+ dprintf(opt->output_fd, "%s", items[i].name);
+
+ if (sepafter)
+ dprintf(opt->output_fd, "%s", sepstr);
+ }
+}
+
+int checklist_builder(BUILDER_ARGS)
+{
+ int output, focusitem;
+ unsigned int menurows, nitems;
+ struct bsddialog_menuitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--checklist missing <menurows>");
+ menurows = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
+ true, true, opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
+
+ output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_menu_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+int menu_builder(BUILDER_ARGS)
+{
+ int output, focusitem;
+ unsigned int menurows, nitems;
+ struct bsddialog_menuitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--menu missing <menurows>");
+ menurows = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
+ true, false, opt->item_bottomdesc, &nitems, &items, &focusitem,
+ opt);
+
+ output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_menu_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+int radiolist_builder(BUILDER_ARGS)
+{
+ int output, focusitem;
+ unsigned int menurows, nitems;
+ struct bsddialog_menuitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--radiolist missing <menurows>");
+ menurows = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ get_menu_items(argc-1, argv+1, opt->item_prefix, opt->item_depth, true,
+ true, true, opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
+
+ output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_menu_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+int treeview_builder(BUILDER_ARGS)
+{
+ int output, focusitem;
+ unsigned int menurows, nitems;
+ struct bsddialog_menuitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--treeview missing <menurows>");
+ menurows = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ get_menu_items(argc-1, argv+1, opt->item_prefix, true, true, true, true,
+ opt->item_bottomdesc, &nitems, &items, &focusitem, opt);
+
+ conf->menu.no_name = true;
+ conf->menu.align_left = true;
+
+ output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_menu_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+/* 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)
+{
+ int i;
+ const char *helpname;
+
+ if (NO_PRINT_VALUES(output))
+ return;
+
+ if (output == BSDDIALOG_HELP) {
+ dprintf(opt->output_fd, "HELP");
+ if (focusitem >= 0) {
+ helpname = items[focusitem].label;
+ if (opt->item_bottomdesc &&
+ opt->help_print_item_name == false)
+ helpname = items[focusitem].bottomdesc;
+ dprintf(opt->output_fd, " %s", helpname);
+ }
+ if (opt->help_print_items == false)
+ return;
+ dprintf(opt->output_fd, "\n");
+ }
+
+ for (i = 0; i < nitems; i++) {
+ if (!(items[i].flags & BSDDIALOG_FIELDREADONLY))
+ dprintf(opt->output_fd, "%s\n", items[i].value);
+ free(items[i].value);
+ }
+}
+
+int form_builder(BUILDER_ARGS)
+{
+ int output, fieldlen, focusitem;
+ unsigned int i, j, flags, formheight, nitems, sizeitem;
+ struct bsddialog_formitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--form missing <formheight>");
+ formheight = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ argc--;
+ argv++;
+ sizeitem = opt->item_bottomdesc ? 9 : 8;
+ if (argc % sizeitem != 0)
+ exit_error(true, "--form bad number of arguments items");
+
+ nitems = argc / sizeitem;
+ if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
+ 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 = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xlabel = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].init = argv[j++];
+ items[i].yfield = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xfield = (unsigned 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 = (unsigned int)strtoul(argv[j++], NULL, 10);
+ if (items[i].maxvaluelen == 0)
+ items[i].maxvaluelen = items[i].fieldlen;
+
+ flags = (fieldlen <= 0) ? BSDDIALOG_FIELDREADONLY : 0;
+ items[i].flags = flags;
+
+ items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : "";
+ }
+
+ focusitem = -1;
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
+ items, &focusitem);
+ print_form_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+int inputbox_builder(BUILDER_ARGS)
+{
+ int output;
+ struct bsddialog_formitem item;
+
+ if (argc > 1)
+ error_args("--inputbox", argc - 1, argv + 1);
+
+ item.label = "";
+ item.ylabel = 0;
+ item.xlabel = 0;
+ item.init = argc > 0 ? argv[0] : "";
+ item.yfield = 0;
+ item.xfield = 0;
+ item.fieldlen = 1;
+ item.maxvaluelen = opt->max_input_form;
+ item.flags = BSDDIALOG_FIELDNOCOLOR;
+ item.flags |= BSDDIALOG_FIELDCURSOREND;
+ item.flags |= BSDDIALOG_FIELDEXTEND;
+ item.bottomdesc = "";
+
+ output = bsddialog_form(conf, text, rows, cols, 1, 1, &item, NULL);
+ print_form_items(output, 1, &item, -1, opt);
+
+ return (output);
+}
+
+int mixedform_builder(BUILDER_ARGS)
+{
+ int output, fieldlen, focusitem;
+ unsigned int i, j, formheight, nitems, sizeitem;
+ struct bsddialog_formitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--mixedform missing <formheight>");
+ formheight = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ argc--;
+ argv++;
+ sizeitem = opt->item_bottomdesc ? 10 : 9;
+ if (argc % sizeitem != 0)
+ exit_error(true, "--mixedform bad number of arguments items");
+
+ nitems = argc / sizeitem;
+ if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
+ 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 = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xlabel = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].init = argv[j++];
+ items[i].yfield = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xfield = (unsigned 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 = (unsigned int)strtoul(argv[j++], NULL, 10);
+ if (items[i].maxvaluelen == 0)
+ items[i].maxvaluelen = items[i].fieldlen;
+
+ items[i].flags = (unsigned int)strtoul(argv[j++], NULL, 10);
+ if (fieldlen <= 0)
+ items[i].flags |= BSDDIALOG_FIELDREADONLY;
+
+ items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : "";
+ }
+
+ focusitem = -1;
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
+ items, &focusitem);
+ for (i = 0; i < nitems; i++) {
+ if ((int)strtol(argv[i * sizeitem + 6], NULL, 10) > 0)
+ items[i].flags &= ~ BSDDIALOG_FIELDREADONLY;
+ }
+ print_form_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
+
+int passwordbox_builder(BUILDER_ARGS)
+{
+ int output;
+ struct bsddialog_formitem item;
+
+ if (argc > 1)
+ error_args("--passwordbox", argc - 1, argv + 1);
+
+ item.label = "";
+ item.ylabel = 0;
+ item.xlabel = 0;
+ item.init = argc > 0 ? argv[0] : "";
+ item.yfield = 0;
+ item.xfield = 0;
+ item.fieldlen = 1;
+ item.maxvaluelen = opt->max_input_form;
+ item.flags = BSDDIALOG_FIELDHIDDEN;
+ item.flags |= BSDDIALOG_FIELDNOCOLOR;
+ item.flags |= BSDDIALOG_FIELDCURSOREND;
+ item.flags |= BSDDIALOG_FIELDEXTEND;
+ item.bottomdesc = "";
+
+ output = bsddialog_form(conf, text, rows, cols, 1, 1, &item, NULL);
+ print_form_items(output, 1, &item, -1, opt);
+
+ return (output);
+}
+
+int passwordform_builder(BUILDER_ARGS)
+{
+ int output, fieldlen, valuelen, focusitem;
+ unsigned int i, j, flags, formheight, nitems, sizeitem;
+ struct bsddialog_formitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--passwordform missing <formheight>");
+ formheight = (unsigned int)strtoul(argv[0], NULL, 10);
+
+ argc--;
+ argv++;
+ sizeitem = opt->item_bottomdesc ? 9 : 8;
+ if (argc % sizeitem != 0)
+ exit_error(true, "--passwordform bad arguments items number");
+
+ flags = BSDDIALOG_FIELDHIDDEN;
+ nitems = argc / sizeitem;
+ if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
+ 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 = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xlabel = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].init = argv[j++];
+ items[i].yfield = (unsigned int)strtoul(argv[j++], NULL, 10);
+ items[i].xfield = (unsigned int)strtoul(argv[j++], NULL, 10);
+
+ fieldlen = (int)strtol(argv[j++], NULL, 10);
+ items[i].fieldlen = abs(fieldlen);
+
+ valuelen = (int)strtol(argv[j++], NULL, 10);
+ items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
+
+ flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
+ items[i].flags = flags;
+
+ items[i].bottomdesc = opt->item_bottomdesc ? argv[j++] : "";
+ }
+
+ focusitem = -1;
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
+ items, &focusitem);
+ print_form_items(output, nitems, items, focusitem, opt);
+ free(items);
+
+ if (output == BSDDIALOG_HELP && opt->item_bottomdesc)
+ output = BSDDIALOG_ITEM_HELP;
+
+ return (output);
+}
diff --git a/contrib/bsddialog/utility/util_cli.c b/contrib/bsddialog/utility/util_cli.c
new file mode 100644
index 000000000000..01b6fc31f065
--- /dev/null
+++ b/contrib/bsddialog/utility/util_cli.c
@@ -0,0 +1,841 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#include "util.h"
+
+enum OPTS {
+ /* Options */
+ ALTERNATE_SCREEN = '?' + 1,
+ AND_DIALOG,
+ ASCII_LINES,
+ BACKTITLE,
+ BEGIN_X,
+ BEGIN_Y,
+ BIKESHED,
+ CANCEL_EXIT_CODE,
+ CANCEL_LABEL,
+ CLEAR_DIALOG,
+ CLEAR_SCREEN,
+ COLUMNS_PER_ROW,
+ CR_WRAP,
+ DATEBOX_FORMAT,
+ DATE_FORMAT,
+ DEFAULT_BUTTON,
+ DEFAULT_ITEM,
+ DEFAULT_NO,
+ DISABLE_ESC,
+ ERROR_EXIT_CODE,
+ ESC_EXIT_CODE,
+ EXIT_LABEL,
+ EXTRA_BUTTON,
+ EXTRA_EXIT_CODE,
+ EXTRA_LABEL,
+ HELP_BUTTON,
+ HELP_EXIT_CODE,
+ HELP_LABEL,
+ HELP_PRINT_ITEMS,
+ HELP_PRINT_NAME,
+ HFILE,
+ HLINE,
+ HMSG,
+ IGNORE,
+ INSECURE,
+ ITEM_BOTTOM_DESC,
+ ITEM_DEPTH,
+ ITEM_PREFIX,
+ LEFT1_BUTTON,
+ LEFT1_EXIT_CODE,
+ LEFT2_BUTTON,
+ LEFT2_EXIT_CODE,
+ LEFT3_BUTTON,
+ LEFT3_EXIT_CODE,
+ LOAD_THEME,
+ MAX_INPUT_FORM,
+ NO_CANCEL,
+ NO_DESCRIPTIONS,
+ NO_LINES,
+ NO_NAMES,
+ NO_OK,
+ NO_SHADOW,
+ NORMAL_SCREEN,
+ OK_EXIT_CODE,
+ OK_LABEL,
+ OUTPUT_FD,
+ OUTPUT_SEPARATOR,
+ PRINT_MAXSIZE,
+ PRINT_SIZE,
+ PRINT_VERSION,
+ QUOTED,
+ RIGHT1_BUTTON,
+ RIGHT1_EXIT_CODE,
+ RIGHT2_BUTTON,
+ RIGHT2_EXIT_CODE,
+ RIGHT3_BUTTON,
+ RIGHT3_EXIT_CODE,
+ SAVE_THEME,
+ SEPARATE_OUTPUT,
+ SHADOW,
+ SINGLE_QUOTED,
+ SLEEP,
+ STDERR,
+ STDOUT,
+ SWITCH_BUTTONS,
+ TAB_ESCAPE,
+ TAB_LEN,
+ TEXT_ESCAPE,
+ TEXT_UNCHANGED,
+ THEME,
+ TIMEOUT_EXIT_CODE,
+ TIME_FORMAT,
+ TITLE,
+ /* Dialogs */
+ CALENDAR,
+ CHECKLIST,
+ DATEBOX,
+ FORM,
+ GAUGE,
+ INFOBOX,
+ INPUTBOX,
+ MENU,
+ MIXEDFORM,
+ MIXEDGAUGE,
+ MSGBOX,
+ PASSWORDBOX,
+ PASSWORDFORM,
+ PAUSE,
+ RADIOLIST,
+ RANGEBOX,
+ TEXTBOX,
+ TIMEBOX,
+ TREEVIEW,
+ YESNO
+};
+
+/* options descriptor */
+static struct option longopts[] = {
+ /* Options */
+ {"alternate-screen", no_argument, NULL, ALTERNATE_SCREEN},
+ {"and-dialog", no_argument, NULL, AND_DIALOG},
+ {"and-widget", no_argument, NULL, AND_DIALOG},
+ {"ascii-lines", no_argument, NULL, ASCII_LINES},
+ {"backtitle", required_argument, NULL, BACKTITLE},
+ {"begin-x", required_argument, NULL, BEGIN_X},
+ {"begin-y", required_argument, NULL, BEGIN_Y},
+ {"bikeshed", no_argument, NULL, BIKESHED},
+ {"cancel-exit-code", required_argument, NULL, CANCEL_EXIT_CODE},
+ {"cancel-label", required_argument, NULL, CANCEL_LABEL},
+ {"clear", no_argument, NULL, CLEAR_SCREEN},
+ {"clear-dialog", no_argument, NULL, CLEAR_DIALOG},
+ {"clear-screen", no_argument, NULL, CLEAR_SCREEN},
+ {"colors", no_argument, NULL, TEXT_ESCAPE},
+ {"columns-per-row", required_argument, NULL, COLUMNS_PER_ROW},
+ {"cr-wrap", no_argument, NULL, CR_WRAP},
+ {"datebox-format", required_argument, NULL, DATEBOX_FORMAT},
+ {"date-format", required_argument, NULL, DATE_FORMAT},
+ {"defaultno", no_argument, NULL, DEFAULT_NO},
+ {"default-button", required_argument, NULL, DEFAULT_BUTTON},
+ {"default-item", required_argument, NULL, DEFAULT_ITEM},
+ {"default-no", no_argument, NULL, DEFAULT_NO},
+ {"disable-esc", no_argument, NULL, DISABLE_ESC},
+ {"error-exit-code", required_argument, NULL, ERROR_EXIT_CODE},
+ {"esc-exit-code", required_argument, NULL, ESC_EXIT_CODE},
+ {"exit-label", required_argument, NULL, EXIT_LABEL},
+ {"extra-button", no_argument, NULL, EXTRA_BUTTON},
+ {"extra-exit-code", required_argument, NULL, EXTRA_EXIT_CODE},
+ {"extra-label", required_argument, NULL, EXTRA_LABEL},
+ {"help-button", no_argument, NULL, HELP_BUTTON},
+ {"help-exit-code", required_argument, NULL, HELP_EXIT_CODE},
+ {"help-label", required_argument, NULL, HELP_LABEL},
+ {"help-print-items", no_argument, NULL, HELP_PRINT_ITEMS},
+ {"help-print-name", no_argument, NULL, HELP_PRINT_NAME},
+ {"help-status", no_argument, NULL, HELP_PRINT_ITEMS},
+ {"help-tags", no_argument, NULL, HELP_PRINT_NAME},
+ {"hfile", required_argument, NULL, HFILE},
+ {"hline", required_argument, NULL, HLINE},
+ {"hmsg", required_argument, NULL, HMSG},
+ {"ignore", no_argument, NULL, IGNORE},
+ {"insecure", no_argument, NULL, INSECURE},
+ {"item-bottom-desc", no_argument, NULL, ITEM_BOTTOM_DESC},
+ {"item-depth", no_argument, NULL, ITEM_DEPTH},
+ {"item-help", no_argument, NULL, ITEM_BOTTOM_DESC},
+ {"item-prefix", no_argument, NULL, ITEM_PREFIX},
+ {"keep-tite", no_argument, NULL, ALTERNATE_SCREEN},
+ {"left1-button", required_argument, NULL, LEFT1_BUTTON},
+ {"left1-exit-code", required_argument, NULL, LEFT1_EXIT_CODE},
+ {"left2-button", required_argument, NULL, LEFT2_BUTTON},
+ {"left2-exit-code", required_argument, NULL, LEFT2_EXIT_CODE},
+ {"left3-button", required_argument, NULL, LEFT3_BUTTON},
+ {"left3-exit-code", required_argument, NULL, LEFT3_EXIT_CODE},
+ {"load-theme", required_argument, NULL, LOAD_THEME},
+ {"max-input", required_argument, NULL, MAX_INPUT_FORM},
+ {"no-cancel", no_argument, NULL, NO_CANCEL},
+ {"nocancel", no_argument, NULL, NO_CANCEL},
+ {"no-descriptions", no_argument, NULL, NO_DESCRIPTIONS},
+ {"no-items", no_argument, NULL, NO_DESCRIPTIONS},
+ {"no-label", required_argument, NULL, CANCEL_LABEL},
+ {"no-lines", no_argument, NULL, NO_LINES},
+ {"no-names", no_argument, NULL, NO_NAMES},
+ {"no-ok", no_argument, NULL, NO_OK},
+ {"nook", no_argument, NULL, NO_OK},
+ {"no-shadow", no_argument, NULL, NO_SHADOW},
+ {"no-tags", no_argument, NULL, NO_NAMES},
+ {"normal-screen", no_argument, NULL, NORMAL_SCREEN},
+ {"ok-exit-code", required_argument, NULL, OK_EXIT_CODE},
+ {"ok-label", required_argument, NULL, OK_LABEL},
+ {"output-fd", required_argument, NULL, OUTPUT_FD},
+ {"output-separator", required_argument, NULL, OUTPUT_SEPARATOR},
+ {"print-maxsize", no_argument, NULL, PRINT_MAXSIZE},
+ {"print-size", no_argument, NULL, PRINT_SIZE},
+ {"print-version", no_argument, NULL, PRINT_VERSION},
+ {"quoted", no_argument, NULL, QUOTED},
+ {"right1-button", required_argument, NULL, RIGHT1_BUTTON},
+ {"right1-exit-code", required_argument, NULL, RIGHT1_EXIT_CODE},
+ {"right2-button", required_argument, NULL, RIGHT2_BUTTON},
+ {"right2-exit-code", required_argument, NULL, RIGHT2_EXIT_CODE},
+ {"right3-button", required_argument, NULL, RIGHT3_BUTTON},
+ {"right3-exit-code", required_argument, NULL, RIGHT3_EXIT_CODE},
+ {"save-theme", required_argument, NULL, SAVE_THEME},
+ {"separate-output", no_argument, NULL, SEPARATE_OUTPUT},
+ {"separator", required_argument, NULL, OUTPUT_SEPARATOR},
+ {"shadow", no_argument, NULL, SHADOW},
+ {"single-quoted", no_argument, NULL, SINGLE_QUOTED},
+ {"sleep", required_argument, NULL, SLEEP},
+ {"stderr", no_argument, NULL, STDERR},
+ {"stdout", no_argument, NULL, STDOUT},
+ {"switch-buttons", no_argument, NULL, SWITCH_BUTTONS},
+ {"tab-escape", no_argument, NULL, TAB_ESCAPE},
+ {"tab-len", required_argument, NULL, TAB_LEN},
+ {"text-escape", no_argument, NULL, TEXT_ESCAPE},
+ {"text-unchanged", no_argument, NULL, TEXT_UNCHANGED},
+ {"theme", required_argument, NULL, THEME},
+ {"timeout-exit-code", required_argument, NULL, TIMEOUT_EXIT_CODE},
+ {"time-format", required_argument, NULL, TIME_FORMAT},
+ {"title", required_argument, NULL, TITLE},
+ {"yes-label", required_argument, NULL, OK_LABEL},
+ /* Dialogs */
+ {"calendar", no_argument, NULL, CALENDAR},
+ {"checklist", no_argument, NULL, CHECKLIST},
+ {"datebox", no_argument, NULL, DATEBOX},
+ {"form", no_argument, NULL, FORM},
+ {"gauge", no_argument, NULL, GAUGE},
+ {"infobox", no_argument, NULL, INFOBOX},
+ {"inputbox", no_argument, NULL, INPUTBOX},
+ {"menu", no_argument, NULL, MENU},
+ {"mixedform", no_argument, NULL, MIXEDFORM},
+ {"mixedgauge", no_argument, NULL, MIXEDGAUGE},
+ {"msgbox", no_argument, NULL, MSGBOX},
+ {"passwordbox", no_argument, NULL, PASSWORDBOX},
+ {"passwordform", no_argument, NULL, PASSWORDFORM},
+ {"pause", no_argument, NULL, PAUSE},
+ {"radiolist", no_argument, NULL, RADIOLIST},
+ {"rangebox", no_argument, NULL, RANGEBOX},
+ {"textbox", no_argument, NULL, TEXTBOX},
+ {"timebox", no_argument, NULL, TIMEBOX},
+ {"treeview", no_argument, NULL, TREEVIEW},
+ {"yesno", no_argument, NULL, YESNO},
+ /* END */
+ { NULL, 0, NULL, 0}
+};
+
+void usage(void)
+{
+ printf("usage: bsddialog --help | --version\n");
+ printf(" bsddialog [--<opt>] --<dialog> <text> <rows> <cols> "
+ "[<arg>] [--<opt>]\n");
+ printf(" bsddialog ... --<dialog1> ... [--and-dialog --<dialog2> "
+ "...] ...\n");
+ printf("\n");
+
+ printf("Options:\n");
+ printf(" --alternate-screen, --ascii-lines, --backtitle <backtitle>,"
+ " --begin-x <x>,\n --begin-y <y>, --bikeshed,"
+ " --cancel-exit-code <retval>, --cancel-label <label>,\n"
+ " --clear-dialog, --clear-screen, --columns-per-row <columns>,"
+ " --cr-wrap,\n --datebox-format d/m/y|m/d/y|y/m/d,"
+ " --date-format <format>,\n --default-button <label>,"
+ " --default-item <name>, --default-no, --disable-esc,\n"
+ " --error-exit-code <retval>, --esc-exit-code <retval>,"
+ " --exit-label <label>,\n --extra-button,"
+ " --extra-exit-code <retval>, --extra-label <label>,\n"
+ " --left1-button <label>, --left1-exit-code <retval>,"
+ " --left2-button <label>,\n --left2-exit-code <retval>,"
+ " --left3-button <label>, --left3-exit-code <retval>,\n"
+ " --help-button, --help-exit-code <retval>, --help-label <label>,\n"
+ " --help-print-items, --help-print-name, --hfile <file>,"
+ " --hline <string>,\n --hmsg <string>, --ignore, --insecure,"
+ " --item-bottom-desc, --item-depth,\n --item-prefix,"
+ " --load-theme <file>, --max-input <size>, --no-cancel,\n"
+ " --no-descriptions, --no-label <label>, --no-lines, --no-names,"
+ " --no-ok,\n --no-shadow, --normal-screen, --ok-exit-code <retval>,"
+ " --ok-label <label>,\n --output-fd <fd>, --output-separator <sep>,"
+ " --print-maxsize, --print-size,\n --print-version, --quoted,"
+ " --right1-button <label>,\n --right1-exit-code <retval>,"
+ " --right2-button <label>,\n --right2-exit-code <retval>,"
+ " --right3-button <label>,\n --right3-exit-code <retval>,"
+ " --save-theme <file>, --separate-output,\n --separator <sep>,"
+ " --shadow, --single-quoted, --sleep <secs>, --stderr,\n --stdout,"
+ " --switch-buttons, --tab-escape, --tab-len <spaces>,"
+ " --text-escape,\n --text-unchanged, --theme 3d|blackwhite|flat,"
+ " --timeout-exit-code <retval>,\n --time-format <format>,"
+ " --title <title>, --yes-label <label>.");
+ printf("\n\n");
+
+ printf("Dialogs:\n");
+ printf(" --calendar <text> <rows> <cols> [<dd> <mm> <yy>]\n");
+ printf(" --checklist <text> <rows> <cols> <menurows> [<name> <desc> "
+ "on|off] ...\n");
+ printf(" --datebox <text> <rows> <cols> [<dd> <mm> <yy>]\n");
+ printf(" --form <text> <rows> <cols> <formrows> [<label> <ylabel> "
+ "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters>] "
+ "...\n");
+ printf(" --gauge <text> <rows> <cols> [<perc>]\n");
+ printf(" --infobox <text> <rows> <cols>\n");
+ printf(" --inputbox <text> <rows> <cols> [<init>]\n");
+ printf(" --menu <text> <rows> <cols> <menurows> [<name> <desc>] ...\n");
+ printf(" --mixedform <text> <rows> <cols> <formrows> [<label> <ylabel> "
+ "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters> "
+ "0|1|2] ...\n");
+ printf(" --mixedgauge <text> <rows> <cols> <mainperc> [<minilabel> "
+ "<miniperc>] ...\n");
+ printf(" --msgbox <text> <rows> <cols>\n");
+ printf(" --passwordbox <text> <rows> <cols> [<init>]\n");
+ printf(" --passwordform <text> <rows> <cols> <formrows> [<label> "
+ "<ylabel> <xlabel> <init> <yfield> <xfield> <fieldlen> "
+ "<maxletters>] ...\n");
+ printf(" --pause <text> <rows> <cols> <secs>\n");
+ printf(" --radiolist <text> <rows> <cols> <menurows> [<name> <desc> "
+ "on|off] ...\n");
+ printf(" --rangebox <text> <rows> <cols> <min> <max> [<init>]\n");
+ printf(" --textbox <file> <rows> <cols>\n");
+ printf(" --timebox <text> <rows> <cols> [<hh> <mm> <ss>]\n");
+ printf(" --treeview <text> <rows> <cols> <menurows> [<depth> <name> "
+ "<desc> on|off] ...\n");
+ printf(" --yesno <text> <rows> <cols>\n");
+ printf("\n");
+
+ printf("See 'man 1 bsddialog' for more information.\n");
+}
+
+int
+parseargs(int argc, char **argv, struct bsddialog_conf *conf,
+ struct options *opt)
+{
+ int arg, parsed, i;
+ struct winsize ws;
+
+ bsddialog_initconf(conf);
+ conf->key.enable_esc = true;
+ conf->button.always_active = true;
+
+ memset(opt, 0, sizeof(struct options));
+ opt->theme = -1;
+ opt->output_fd = STDERR_FILENO;
+ opt->max_input_form = 2048;
+ opt->mandatory_dialog = true;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "--and-dialog") == 0 ||
+ strcmp(argv[i], "--and-widget") == 0) {
+ argc = i + 1;
+ break;
+ }
+ }
+ parsed = argc;
+ while ((arg = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+ switch (arg) {
+ /* Options */
+ case ALTERNATE_SCREEN:
+ opt->screen_mode = "smcup";
+ break;
+ case AND_DIALOG:
+ if (opt->dialogbuilder == NULL)
+ exit_error(true,"--and-dialog without "
+ "previous --<dialog>");
+ break;
+ case ASCII_LINES:
+ conf->ascii_lines = true;
+ break;
+ case BACKTITLE:
+ opt->backtitle = optarg;
+ if (conf->y == BSDDIALOG_CENTER)
+ conf->auto_topmargin = 2;
+ break;
+ case BEGIN_X:
+ conf->x = (int)strtol(optarg, NULL, 10);
+ if (conf->x < BSDDIALOG_CENTER)
+ exit_error(false, "--begin-x %d is < %d",
+ conf->x, BSDDIALOG_CENTER);
+ break;
+ case BEGIN_Y:
+ conf->y = (int)strtol(optarg, NULL, 10);
+ if (conf->y < BSDDIALOG_CENTER)
+ exit_error(false, "--begin-y %d is < %d",
+ conf->y, BSDDIALOG_CENTER);
+ conf->auto_topmargin = 0;
+ break;
+ case BIKESHED:
+ opt->bikeshed = true;
+ break;
+ case CANCEL_EXIT_CODE:
+ set_exit_code(BSDDIALOG_CANCEL,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case CANCEL_LABEL:
+ conf->button.cancel_label = optarg;
+ break;
+ case CLEAR_DIALOG:
+ conf->clear = true;
+ break;
+ case CLEAR_SCREEN:
+ opt->mandatory_dialog = false;
+ opt->clearscreen = true;
+ break;
+ case COLUMNS_PER_ROW:
+ conf->text.cols_per_row =
+ (u_int)strtoul(optarg, NULL, 10);
+ break;
+ case CR_WRAP:
+ opt->cr_wrap = true;
+ break;
+ case DATEBOX_FORMAT:
+ if (strcasecmp(optarg, "d/m/y") == 0)
+ conf->date.format = "d/m/y";
+ else if (strcasecmp(optarg, "m/d/y") == 0)
+ conf->date.format = "m/d/y";
+ else if (strcasecmp(optarg, "y/m/d") == 0)
+ conf->date.format = "y/m/d";
+ else
+ exit_error(true,
+ "date format \"%s\" is invalid", optarg);
+ break;
+ case DATE_FORMAT:
+ opt->date_fmt = optarg;
+ break;
+ case DEFAULT_BUTTON:
+ conf->button.default_label = optarg;
+ break;
+ case DEFAULT_ITEM:
+ opt->item_default = optarg;
+ break;
+ case DEFAULT_NO:
+ conf->button.default_cancel = true;
+ break;
+ case DISABLE_ESC:
+ conf->key.enable_esc = false;
+ break;
+ case ERROR_EXIT_CODE:
+ set_exit_code(BSDDIALOG_ERROR,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case ESC_EXIT_CODE:
+ set_exit_code(BSDDIALOG_ESC,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case EXIT_LABEL:
+ conf->button.ok_label = optarg;
+ break;
+ case EXTRA_BUTTON:
+ conf->button.with_extra = true;
+ break;
+ case EXTRA_EXIT_CODE:
+ set_exit_code(BSDDIALOG_EXTRA,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case EXTRA_LABEL:
+ conf->button.extra_label = optarg;
+ break;
+ case HELP_BUTTON:
+ conf->button.with_help = true;
+ break;
+ case HELP_EXIT_CODE:
+ i = (int)strtol(optarg, NULL, 10);
+ set_exit_code(BSDDIALOG_HELP, i);
+ /* _TEM_HELP follows _HELP */
+ set_exit_code(BSDDIALOG_ITEM_HELP, i);
+ break;
+ case HELP_LABEL:
+ conf->button.help_label = optarg;
+ break;
+ case HELP_PRINT_ITEMS:
+ opt->help_print_items = true;
+ break;
+ case HELP_PRINT_NAME:
+ opt->help_print_item_name = true;
+ break;
+ case HFILE:
+ conf->key.f1_file = optarg;
+ break;
+ case HLINE:
+ if (optarg[0] != '\0')
+ conf->bottomtitle = optarg;
+ break;
+ case HMSG:
+ conf->key.f1_message = optarg;
+ break;
+ case IGNORE:
+ opt->ignore = true;
+ break;
+ case INSECURE:
+ conf->form.securech = '*';
+ break;
+ case ITEM_BOTTOM_DESC:
+ opt->item_bottomdesc = true;
+ break;
+ case ITEM_DEPTH:
+ opt->item_depth = true;
+ break;
+ case ITEM_PREFIX:
+ opt->item_prefix = true;
+ break;
+ case LEFT1_BUTTON:
+ conf->button.left1_label = optarg;
+ break;
+ case LEFT1_EXIT_CODE:
+ set_exit_code(BSDDIALOG_LEFT1,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case LEFT2_BUTTON:
+ conf->button.left2_label = optarg;
+ break;
+ case LEFT2_EXIT_CODE:
+ set_exit_code(BSDDIALOG_LEFT2,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case LEFT3_BUTTON:
+ conf->button.left3_label = optarg;
+ break;
+ case LEFT3_EXIT_CODE:
+ set_exit_code(BSDDIALOG_LEFT3,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case LOAD_THEME:
+ opt->loadthemefile = optarg;
+ break;
+ case MAX_INPUT_FORM:
+ opt->max_input_form = (u_int)strtoul(optarg, NULL, 10);
+ break;
+ case NO_CANCEL:
+ conf->button.without_cancel = true;
+ break;
+ case NO_DESCRIPTIONS:
+ conf->menu.no_desc = true;
+ break;
+ case NO_LINES:
+ conf->no_lines = true;
+ break;
+ case NO_NAMES:
+ conf->menu.no_name = true;
+ break;
+ case NO_OK:
+ conf->button.without_ok = true;
+ break;
+ case NO_SHADOW:
+ conf->shadow = false;
+ break;
+ case NORMAL_SCREEN:
+ opt->screen_mode = "rmcup";
+ break;
+ case OK_EXIT_CODE:
+ set_exit_code(BSDDIALOG_OK,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case OK_LABEL:
+ conf->button.ok_label = optarg;
+ break;
+ case OUTPUT_FD:
+ opt->output_fd = (int)strtol(optarg, NULL, 10);
+ break;
+ case OUTPUT_SEPARATOR:
+ opt->item_output_sep = optarg;
+ break;
+ case QUOTED:
+ opt->item_always_quote = true;
+ break;
+ case PRINT_MAXSIZE:
+ opt->mandatory_dialog = false;
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+ dprintf(opt->output_fd, "MaxSize: %d, %d\n",
+ ws.ws_row, ws.ws_col);
+ break;
+ case PRINT_SIZE:
+ conf->get_height = &opt->getH;
+ conf->get_width = &opt->getW;
+ break;
+ case PRINT_VERSION:
+ opt->mandatory_dialog = false;
+ dprintf(opt->output_fd, "Version: %s\n",
+ LIBBSDDIALOG_VERSION);
+ break;
+ case RIGHT1_BUTTON:
+ conf->button.right1_label = optarg;
+ break;
+ case RIGHT1_EXIT_CODE:
+ set_exit_code(BSDDIALOG_RIGHT1,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case RIGHT2_BUTTON:
+ conf->button.right2_label = optarg;
+ break;
+ case RIGHT2_EXIT_CODE:
+ set_exit_code(BSDDIALOG_RIGHT2,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case RIGHT3_BUTTON:
+ conf->button.right3_label = optarg;
+ break;
+ case RIGHT3_EXIT_CODE:
+ set_exit_code(BSDDIALOG_RIGHT3,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case SAVE_THEME:
+ opt->mandatory_dialog = false;
+ opt->savethemefile = optarg;
+ break;
+ case SEPARATE_OUTPUT:
+ opt->item_output_sepnl = true;
+ break;
+ case SHADOW:
+ conf->shadow = true;
+ break;
+ case SINGLE_QUOTED:
+ opt->item_singlequote = true;
+ break;
+ case SLEEP:
+ conf->sleep = (u_int)strtoul(optarg, NULL, 10);
+ break;
+ case STDERR:
+ opt->output_fd = STDERR_FILENO;
+ break;
+ case STDOUT:
+ opt->output_fd = STDOUT_FILENO;
+ break;
+ case SWITCH_BUTTONS:
+ conf->button.always_active = false;
+ break;
+ case TAB_ESCAPE:
+ opt->tab_escape = true;
+ break;
+ case TAB_LEN:
+ conf->text.tablen = (u_int)strtoul(optarg, NULL, 10);
+ break;
+ case TEXT_ESCAPE:
+ conf->text.escape = true;
+ break;
+ case TEXT_UNCHANGED:
+ opt->text_unchanged = true;
+ break;
+ case THEME:
+ if (strcasecmp(optarg, "blackwhite") == 0)
+ opt->theme = BSDDIALOG_THEME_BLACKWHITE;
+ else if (strcasecmp(optarg, "flat") == 0)
+ opt->theme = BSDDIALOG_THEME_FLAT;
+ else if (strcasecmp(optarg, "3d") == 0)
+ opt->theme = BSDDIALOG_THEME_3D;
+ else
+ exit_error(true,
+ "--theme: \"%s\" is unknown", optarg);
+ break;
+ case TIMEOUT_EXIT_CODE:
+ set_exit_code(BSDDIALOG_TIMEOUT,
+ (int)strtol(optarg, NULL, 10));
+ break;
+ case TIME_FORMAT:
+ opt->time_fmt = optarg;
+ break;
+ case TITLE:
+ conf->title = optarg;
+ break;
+ /* Dialogs */
+ case CALENDAR:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --calendar without "
+ "--and-dialog", opt->name);
+ opt->name = "--calendar";
+ opt->dialogbuilder = calendar_builder;
+ break;
+ case CHECKLIST:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --checklist without "
+ "--and-dialog", opt->name);
+ opt->name = "--checklist";
+ opt->dialogbuilder = checklist_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case DATEBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --datebox without "
+ "--and-dialog", opt->name);
+ opt->name = "--datebox";
+ opt->dialogbuilder = datebox_builder;
+ break;
+ case FORM:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --form without "
+ "--and-dialog", opt->name);
+ opt->name = "--form";
+ opt->dialogbuilder = form_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case GAUGE:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --gauge without "
+ "--and-dialog", opt->name);
+ opt->name = "--gauge";
+ opt->dialogbuilder = gauge_builder;
+ break;
+ case INFOBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --infobox without "
+ "--and-dialog", opt->name);
+ opt->name = "--infobox";
+ opt->dialogbuilder = infobox_builder;
+ break;
+ case INPUTBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --inputbox without "
+ "--and-dialog", opt->name);
+ opt->name = "--inputbox";
+ opt->dialogbuilder = inputbox_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case MENU:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --menu without "
+ "--and-dialog", opt->name);
+ opt->name = "--menu";
+ opt->dialogbuilder = menu_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case MIXEDFORM:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --mixedform without "
+ "--and-dialog", opt->name);
+ opt->name = "--mixedform";
+ opt->dialogbuilder = mixedform_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case MIXEDGAUGE:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --mixedgauge without "
+ "--and-dialog", opt->name);
+ opt->name = "--mixedgauge";
+ opt->dialogbuilder = mixedgauge_builder;
+ break;
+ case MSGBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --msgbox without "
+ "--and-dialog", opt->name);
+ opt->name = "--";
+ opt->dialogbuilder = msgbox_builder;
+ break;
+ case PAUSE:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --pause without "
+ "--and-dialog", opt->name);
+ opt->name = "--pause";
+ opt->dialogbuilder = pause_builder;
+ break;
+ case PASSWORDBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --passwordbox without "
+ "--and-dialog", opt->name);
+ opt->name = "--passwordbox";
+ opt->dialogbuilder = passwordbox_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case PASSWORDFORM:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --passwordform "
+ "without --and-dialog", opt->name);
+ opt->name = "--passwordform";
+ opt->dialogbuilder = passwordform_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case RADIOLIST:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --radiolist without "
+ "--and-dialog", opt->name);
+ opt->name = "--radiolist";
+ opt->dialogbuilder = radiolist_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case RANGEBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --rangebox without "
+ "--and-dialog", opt->name);
+ opt->name = "--rangebox";
+ opt->dialogbuilder = rangebox_builder;
+ break;
+ case TEXTBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --textbox without "
+ "--and-dialog", opt->name);
+ opt->name = "--textbox";
+ opt->dialogbuilder = textbox_builder;
+ break;
+ case TIMEBOX:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --timebox without "
+ "--and-dialog", opt->name);
+ opt->name = "--timebox";
+ opt->dialogbuilder = timebox_builder;
+ break;
+ case TREEVIEW:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --treeview without "
+ "--and-dialog", opt->name);
+ opt->name = "--treeview";
+ opt->dialogbuilder = treeview_builder;
+ conf->auto_downmargin = 1;
+ break;
+ case YESNO:
+ if (opt->dialogbuilder != NULL)
+ exit_error(true, "%s and --yesno without "
+ "--and-dialog", opt->name);
+ opt->name = "--yesno";
+ opt->dialogbuilder = yesno_builder;
+ break;
+ default: /* Error */
+ if (opt->ignore == true)
+ break;
+ exit_error(true, "--ignore to continue");
+ }
+ }
+
+ return (parsed);
+}
diff --git a/contrib/bsddialog/utility/util_theme.c b/contrib/bsddialog/utility/util_theme.c
new file mode 100644
index 000000000000..cca79e83b97d
--- /dev/null
+++ b/contrib/bsddialog/utility/util_theme.c
@@ -0,0 +1,451 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2025 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#include "util.h"
+
+static struct bsddialog_theme t;
+static char title[1024];
+
+#define NPROPERTY 41
+#define NCOLOR 8
+#define NATTR 6
+
+#define PROP_ERROR(name, error) do { \
+ fclose(fp); \
+ exit_error(false, "%s for \"%s\"", error, name); \
+} while (0)
+
+enum typeproperty {
+ BOOL,
+ CHAR,
+ INT,
+ UINT,
+ COLOR,
+ COMPAT
+};
+
+struct property {
+ const char *comment;
+ const char *name;
+ enum typeproperty type;
+ void *value;
+};
+
+struct namevalue {
+ const char *name;
+ unsigned int value;
+};
+
+static struct namevalue color[NCOLOR] = {
+ {"black", BSDDIALOG_BLACK},
+ {"red", BSDDIALOG_RED},
+ {"green", BSDDIALOG_GREEN},
+ {"yellow", BSDDIALOG_YELLOW},
+ {"blue", BSDDIALOG_BLUE},
+ {"magenta", BSDDIALOG_MAGENTA},
+ {"cyan", BSDDIALOG_CYAN},
+ {"white", BSDDIALOG_WHITE}
+};
+
+static struct namevalue attr[NATTR] = {
+ {"bold", BSDDIALOG_BOLD},
+ {"reverse", BSDDIALOG_REVERSE},
+ {"underline", BSDDIALOG_UNDERLINE},
+ {"blink", BSDDIALOG_BLINK},
+ {"halfbright", BSDDIALOG_HALFBRIGHT},
+ {"highlight", BSDDIALOG_HIGHLIGHT}
+};
+
+static struct property p[NPROPERTY] = {
+ {"\n#Terminal\n", "theme.screen.color", COLOR, &t.screen.color},
+
+ {"\n# Shadow\n",
+ "theme.shadow.color", COLOR, &t.shadow.color},
+ {"# shift down right from main widget\n",
+ "theme.shadow.y", UINT, &t.shadow.y},
+ {"", "theme.shadow.x", UINT, &t.shadow.x},
+
+ {"\n# Main widget\n",
+ "theme.dialog.color", COLOR, &t.dialog.color},
+ {"", "theme.dialog.delimtitle", BOOL, &t.dialog.delimtitle},
+ {"", "theme.dialog.titlecolor", COLOR, &t.dialog.titlecolor},
+ {"", "theme.dialog.lineraisecolor", COLOR, &t.dialog.lineraisecolor},
+ {"", "theme.dialog.linelowercolor", COLOR, &t.dialog.linelowercolor},
+ {"", "theme.dialog.bottomtitlecolor", COLOR,
+ &t.dialog.bottomtitlecolor},
+ {"", "theme.dialog.arrowcolor", COLOR, &t.dialog.arrowcolor},
+
+ {"\n# Menus: --checklist, --menu, --radiolist\n"
+ "# prefix [selector] shortcut name desc bottomdesc\n",
+ "theme.menu.f_prefixcolor", COLOR, &t.menu.f_prefixcolor},
+ {"", "theme.menu.prefixcolor", COLOR, &t.menu.prefixcolor},
+ {"", "theme.menu.f_selectorcolor", COLOR, &t.menu.f_selectorcolor},
+ {"", "theme.menu.selectorcolor", COLOR, &t.menu.selectorcolor},
+ {"", "theme.menu.f_namecolor", COLOR, &t.menu.f_namecolor},
+ {"", "theme.menu.namecolor", COLOR, &t.menu.namecolor},
+ {"", "theme.menu.f_desccolor", COLOR, &t.menu.f_desccolor},
+ {"", "theme.menu.desccolor", COLOR, &t.menu.desccolor},
+ {"", "theme.menu.f_shortcutcolor", COLOR, &t.menu.f_shortcutcolor},
+ {"", "theme.menu.shortcutcolor", COLOR, &t.menu.shortcutcolor},
+ {"", "theme.menu.bottomdesccolor", COLOR, &t.menu.bottomdesccolor},
+ {"# bsddialog_menutype BSDDIALOG_SEPARATOR\n",
+ "theme.menu.sepnamecolor", COLOR, &t.menu.sepnamecolor},
+ {"", "theme.menu.sepdesccolor", COLOR, &t.menu.sepdesccolor},
+
+ {"\n# Forms\n",
+ "theme.form.f_fieldcolor", COLOR, &t.form.f_fieldcolor},
+ {"", "theme.form.fieldcolor", COLOR, &t.form.fieldcolor},
+ {"", "theme.form.readonlycolor", COLOR, &t.form.readonlycolor},
+ {"", "theme.form.bottomdesccolor", COLOR, &t.form.bottomdesccolor},
+
+ {"\n# Bar of --gauge, --mixedgauge, --pause, --rangebox\n",
+ "theme.bar.f_color", COLOR, &t.bar.f_color},
+ {"", "theme.bar.color", COLOR, &t.bar.color},
+
+ {"\n# Buttons\n",
+ "theme.button.minmargin", UINT, &t.button.minmargin},
+ {"", "theme.button.maxmargin", UINT, &t.button.maxmargin},
+ {"", "theme.button.leftdelim", CHAR, &t.button.leftdelim},
+ {"", "theme.button.rightdelim", CHAR, &t.button.rightdelim},
+ {"", "theme.button.f_delimcolor", COLOR, &t.button.f_delimcolor},
+ {"", "theme.button.delimcolor", COLOR, &t.button.delimcolor},
+ {"", "theme.button.f_color", COLOR, &t.button.f_color},
+ {"", "theme.button.color", COLOR, &t.button.color},
+ {"", "theme.button.f_shortcutcolor", COLOR, &t.button.f_shortcutcolor},
+ {"", "theme.button.shortcutcolor", COLOR, &t.button.shortcutcolor},
+
+ {"\n#Compatibility. Do not use, can be deleted\n",
+ "use_shadow", COMPAT, NULL}
+};
+
+void savetheme(const char *file)
+{
+ int i, j;
+ unsigned int flags;
+ enum bsddialog_color bg, fg;
+ time_t clock;
+ FILE *fp;
+
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
+ exit_error(false,
+ "cannot save theme: %s", bsddialog_geterror());
+
+ 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);
+
+ fprintf(fp, "### bsddialog theme - %s\n", ctime(&clock));
+
+ fputs("# Colors: ", fp);
+ fputs("black red green yellow blue magenta cyan white.\n", fp);
+ fputs("# Attributes: ", fp);
+ fputs("bold reverse underline blink halfbright highlight.\n", fp);
+ fputs("# f_* refers to focus for an element with selected or ", fp);
+ fputs("unselected state.\n\n", fp);
+
+ fprintf(fp, "version %s\n", LIBBSDDIALOG_VERSION);
+
+ for (i = 0; i < NPROPERTY; i++) {
+ if (p[i].type == COMPAT)
+ continue;
+ fprintf(fp, "%s%s", p[i].comment, p[i].name);
+ switch (p[i].type) {
+ case CHAR:
+ fprintf(fp, " %c\n", *((char*)p[i].value));
+ break;
+ case INT:
+ fprintf(fp, " %d\n", *((int*)p[i].value));
+ break;
+ case UINT:
+ fprintf(fp, " %u\n", *((unsigned int*)p[i].value));
+ break;
+ case BOOL:
+ fprintf(fp, " %s\n",
+ *((bool*)p[i].value) ? "true" : "false");
+ break;
+ case COLOR:
+ bsddialog_color_attrs(*(int*)p[i].value, &fg, &bg,
+ &flags);
+ fprintf(fp, " %s %s", color[fg].name, color[bg].name);
+ for (j = 0; j < NATTR; j++)
+ if (flags & attr[j].value)
+ fprintf(fp, " %s", attr[j].name);
+ fputs("\n", fp);
+ break;
+ case COMPAT:
+ /* Do not save compat property for now */
+ break;
+ }
+ }
+
+ fclose(fp);
+}
+
+void loadtheme(const char *file, bool compatibility)
+{
+ bool boolvalue;
+ char charvalue, *value;
+ char line[BUFSIZ], name[BUFSIZ], c1[BUFSIZ], c2[BUFSIZ];
+ int i, j, intvalue;
+ unsigned int uintvalue, flags;
+ enum bsddialog_color bg, fg;
+ FILE *fp;
+
+ if (bsddialog_hascolors() == false)
+ return;
+
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
+ exit_error(false, "Cannot get current theme: %s",
+ bsddialog_geterror());
+
+ 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')
+ continue; /* superfluous, only for efficiency */
+ sscanf(line, "%s", name);
+ value = NULL; /* useless init, fix compiler warning */
+ for (i = 0; i < NPROPERTY; i++) {
+ if (strcmp(name, p[i].name) == 0) {
+ value = &line[strlen(name)];
+ break;
+ }
+ }
+ if (i >= NPROPERTY) {
+ /* unknown name in property p[] */
+ if (strcmp(name, "version") == 0)
+ continue; /* nothing for now */
+ else if (compatibility)
+ continue; /* just ignore */
+ else
+ PROP_ERROR(name, "Unknown theme property name");
+ }
+ switch (p[i].type) {
+ case CHAR:
+ while (value[0] == ' ' || value[0] == '\n' ||
+ value[0] == '\0')
+ value++;
+ if (sscanf(value, "%c", &charvalue) != 1)
+ PROP_ERROR(p[i].name, "Cannot get a char");
+ *((int*)p[i].value) = charvalue;
+ break;
+ case INT:
+ if (sscanf(value, "%d", &intvalue) != 1)
+ PROP_ERROR(p[i].name, "Cannot get a int");
+ *((int*)p[i].value) = intvalue;
+ break;
+ case UINT:
+ if (sscanf(value, "%u", &uintvalue) != 1)
+ PROP_ERROR(p[i].name, "Cannot get a uint");
+ *((unsigned int*)p[i].value) = uintvalue;
+ break;
+ case BOOL:
+ boolvalue = (strstr(value, "true") != NULL) ?
+ true : false;
+ *((bool*)p[i].value) = boolvalue;
+ break;
+ case COLOR:
+ if (sscanf(value, "%s %s", c1, c2) != 2)
+ PROP_ERROR(p[i].name, "Cannot get 2 colors");
+ /* Foreground */
+ for (j = 0; j < NCOLOR ; j++)
+ if ((strstr(c1, color[j].name)) != NULL)
+ break;
+ if (j >= NCOLOR)
+ PROP_ERROR(p[i].name, "Bad foreground");
+ fg = color[j].value;
+ /* Background */
+ for (j = 0; j < NCOLOR ; j++)
+ if ((strstr(c2, color[j].name)) != NULL)
+ break;
+ if (j >= NCOLOR)
+ PROP_ERROR(p[i].name, "Bad background");
+ bg = color[j].value;
+ /* Flags */
+ flags = 0;
+ for (j = 0; j < NATTR; j++)
+ if (strstr(value, attr[j].name) != NULL)
+ flags |= attr[j].value;
+ *((int*)p[i].value) = bsddialog_color(fg, bg, flags);
+ break;
+ case COMPAT:
+ /*
+ * usr.sbin/bsdconfig/share/dialog.subr:2255
+ * uses this parameter to set NO_SHADOW.
+ * Set t.shadow.[y|x] for compatibilty.
+ */
+ if (strcmp(name, "use_shadow") == 0) {
+ if (strcasestr(value, "off") != NULL)
+ t.shadow.y = t.shadow.x = 0;
+ }
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ if (bsddialog_set_theme(&t) != BSDDIALOG_OK)
+ exit_error(false, bsddialog_geterror());
+}
+
+void setdeftheme(enum bsddialog_default_theme theme)
+{
+ if (bsddialog_hascolors() == false)
+ return;
+ if (bsddialog_set_default_theme(theme) != BSDDIALOG_OK)
+ exit_error(false, bsddialog_geterror());
+}
+
+void startuptheme(void)
+{
+ bool sep;
+ char *env, *file, *home, path[PATH_MAX];
+
+ env = getenv("NO_COLOR");
+ if (env != NULL && env[0] != '\0')
+ setdeftheme(BSDDIALOG_THEME_BLACKWHITE);
+
+ if ((home = getenv("HOME")) != NULL) {
+ sep = (strcmp(home, "/") == 0) ? false : true;
+
+ snprintf(path, PATH_MAX, "%s%s.bsddialog.conf",
+ home, sep ? "/" : "");
+ if (access(path, F_OK) == 0)
+ loadtheme(path, false);
+
+ if ((file = getenv("BSDDIALOG_COMPATRC")) != NULL) {
+ snprintf(path, PATH_MAX, "%s%s%s",
+ home, sep ? "/" : "", file);
+ if (access(path, F_OK) == 0)
+ loadtheme(path, true);
+ }
+ }
+ if ((file = getenv("BSDDIALOG_THEMEFILE")) != NULL) {
+ if (access(file, F_OK) == 0)
+ loadtheme(file, false);
+ }
+}
+
+void bikeshed(struct bsddialog_conf *conf)
+{
+ int margin, i;
+ int colors[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ char delim[8] = {'[', '<', '(', '|', ']', '>', ')', '|'};
+ enum bsddialog_color col[6];
+ struct timeval tv;
+
+ /* theme */
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
+ exit_error(false, bsddialog_geterror());
+
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_usec);
+ for (i = 0; i < 6; i++) {
+ do {
+ col[i] = rand() % 8;
+ } while (colors[col[i]] == 1);
+ colors[col[i]] = 1;
+ }
+
+ t.screen.color = bsddialog_color(col[4], col[3], 0);
+
+ t.shadow.color = bsddialog_color(col[0], col[0], 0);
+ t.shadow.y = 1,
+ t.shadow.x = 2,
+
+ t.dialog.delimtitle = (~rand() & 1) ? true : false;
+ t.dialog.titlecolor = bsddialog_color(col[3], col[5], 0);
+ t.dialog.lineraisecolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.linelowercolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.color = bsddialog_color(col[0], col[5], 0);
+ t.dialog.bottomtitlecolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.arrowcolor = bsddialog_color(col[3], col[5], 0);
+
+ t.menu.f_prefixcolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.prefixcolor = bsddialog_color(col[0], col[5], 0);
+ t.menu.f_selectorcolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.selectorcolor = bsddialog_color(col[0], col[5], 0);
+ t.menu.f_desccolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.desccolor = bsddialog_color(col[0], col[5], 0);
+ t.menu.f_namecolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.namecolor = bsddialog_color(col[3], col[5], 0);
+ t.menu.f_shortcutcolor = bsddialog_color(col[1], col[3], 0);
+ t.menu.shortcutcolor = bsddialog_color(col[1], col[5], 0);
+ t.menu.bottomdesccolor = bsddialog_color(col[4], col[3], 0);
+ t.menu.sepnamecolor = bsddialog_color(col[1], col[5], 0);
+ t.menu.sepdesccolor = bsddialog_color(col[1], col[5], 0);
+
+ t.form.f_fieldcolor = bsddialog_color(col[5], col[3], 0);
+ t.form.fieldcolor = bsddialog_color(col[5], col[4], 0);
+ t.form.readonlycolor = bsddialog_color(col[4], col[5], 0);
+ t.form.bottomdesccolor = bsddialog_color(col[4], col[3], 0);
+
+ t.bar.f_color = bsddialog_color(col[5], col[3], 0);
+ t.bar.color = bsddialog_color(col[3], col[5], 0);
+
+ t.button.minmargin = 1,
+ t.button.maxmargin = 5,
+ i = rand() % 4;
+ t.button.leftdelim = delim[i];
+ t.button.rightdelim = delim[i + 4];
+ t.button.f_delimcolor = bsddialog_color(col[5], col[3], 0);
+ t.button.delimcolor = bsddialog_color(col[0], col[5], 0);
+ t.button.f_color = bsddialog_color(col[2], col[3], 0);
+ t.button.color = bsddialog_color(col[0], col[5], 0);
+ t.button.f_shortcutcolor = bsddialog_color(col[5], col[3], 0);
+ t.button.shortcutcolor = bsddialog_color(col[1], col[5], 0);
+
+ if (bsddialog_set_theme(&t))
+ exit_error(false, bsddialog_geterror());
+
+ /* conf */
+ conf->button.always_active = (~rand() & 1) ? true : false;
+ if ((i = rand() % 3) != 0) /* default "d/m/y" */
+ conf->date.format = (i & 1) ? "m/d/y" : "y/m/d" ;
+ if (conf->title != NULL) {
+ memset(title, 0, 1024);
+ margin = rand() % 5;
+ memset(title, ' ', margin);
+ strcpy(title + margin, conf->title);
+ memset(title + strlen(title), ' ', margin);
+ conf->title = title;
+ }
+}