aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore25
-rw-r--r--CHANGELOG354
-rw-r--r--GNUMakefile28
-rw-r--r--LICENSE2
-rw-r--r--Makefile63
-rw-r--r--README.md184
-rw-r--r--bsddialog.152
-rw-r--r--bsddialog.c1349
-rw-r--r--examples_library/buildlist.c44
-rw-r--r--examples_library/calendar.c45
-rw-r--r--examples_library/checklist.c39
-rwxr-xr-xexamples_library/compile17
-rw-r--r--examples_library/datebox.c39
-rw-r--r--examples_library/form.c37
-rw-r--r--examples_library/gauge.c57
-rw-r--r--examples_library/infobox.c24
-rw-r--r--examples_library/menu.c36
-rw-r--r--examples_library/mixedgauge.c79
-rw-r--r--examples_library/mixedlist.c60
-rw-r--r--examples_library/msgbox.c34
-rw-r--r--examples_library/pause.c32
-rw-r--r--examples_library/radiolist.c39
-rw-r--r--examples_library/rangebox.c26
-rw-r--r--examples_library/sade.c64
-rw-r--r--examples_library/theme.c58
-rw-r--r--examples_library/timebox.c36
-rw-r--r--examples_library/treeview.c46
-rw-r--r--examples_library/yesno.c29
-rwxr-xr-xexamples_utility/buildlist.sh17
-rw-r--r--examples_utility/calendar.sh34
-rwxr-xr-xexamples_utility/checklist.sh37
-rwxr-xr-xexamples_utility/datebox.sh34
-rwxr-xr-xexamples_utility/form.sh35
-rwxr-xr-xexamples_utility/gauge.sh34
-rwxr-xr-xexamples_utility/infobox.sh6
-rwxr-xr-xexamples_utility/inputbox.sh27
-rwxr-xr-xexamples_utility/menu.sh37
-rwxr-xr-xexamples_utility/mixedform.sh34
-rwxr-xr-xexamples_utility/mixedgauge.sh45
-rwxr-xr-xexamples_utility/msgbox.sh21
-rwxr-xr-xexamples_utility/passwordbox.sh28
-rwxr-xr-xexamples_utility/passwordform.sh38
-rwxr-xr-xexamples_utility/pause.sh36
-rwxr-xr-xexamples_utility/radiolist.sh37
-rw-r--r--examples_utility/rangebox.sh33
-rwxr-xr-xexamples_utility/timebox.sh33
-rwxr-xr-xexamples_utility/treeview.sh17
-rwxr-xr-xexamples_utility/yesno.sh25
-rw-r--r--lib/GNUmakefile (renamed from lib/GNUMakefile)18
-rw-r--r--lib/Makefile77
-rw-r--r--lib/barbox.c983
-rw-r--r--lib/bsddialog.31215
-rw-r--r--lib/bsddialog.h228
-rw-r--r--lib/bsddialog_progressview.h60
-rw-r--r--lib/bsddialog_theme.h65
-rw-r--r--lib/datebox.c715
-rw-r--r--lib/formbox.c1216
-rw-r--r--lib/infobox.c118
-rw-r--r--lib/lib_util.c1571
-rw-r--r--lib/lib_util.h175
-rw-r--r--lib/libbsddialog.c121
-rw-r--r--lib/menubox.c1481
-rw-r--r--lib/messagebox.c349
-rw-r--r--lib/textbox.c339
-rw-r--r--lib/theme.c344
-rw-r--r--lib/timebox.c606
-rw-r--r--utility/GNUmakefile33
-rw-r--r--utility/Makefile33
-rw-r--r--utility/bsddialog.1907
-rw-r--r--utility/bsddialog.c338
-rw-r--r--utility/util.h125
-rw-r--r--utility/util_builders.c768
-rw-r--r--utility/util_cli.c841
-rw-r--r--utility/util_theme.c451
74 files changed, 10755 insertions, 5928 deletions
diff --git a/.gitignore b/.gitignore
index ee80e5f5a073..c8fc68ed8a0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,25 +1,26 @@
bsddialog
+.depend*
*.o
+*.so*
+*.a
+*.gz
+*.core
*~
-examples_library/buildlist
+BSDDIALOG.geany
+BSDDIALOG.tags
+examples_library/calendar
examples_library/checklist
examples_library/datebox
examples_library/form
+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/theme
examples_library/timebox
examples_library/yesno
-*.gz
-lib/libbsddialog.so*
-BSDDIALOG.geany
-BSDDIALOG.tags
-*.core
-bsdinstall/*
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 000000000000..e6295768d906
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,354 @@
+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.
+ * add: "menus" print item with focus (except with OK and ERROR).
+ * add: pause.sh example.
+ * add: timebox.sh example.
+ * change: --theme name "default" -> "flat".
+ * delete: treeview.sh example.
+ * fix: --separate-output does not quote (except with --quoted).
+ * fix: --datebox and --date-format month in output.
+ * improve: examples handle exit status.
+
+ Library:
+ * add: conf.form.enable_wchar for wide characters in bsddialog_form().
+ * add: theme.menu.f_selectorcolor.
+ * add: formw.c example.
+ * change: move conf.f1_file and conf.f1_message in conf.key.
+ * 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: 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.
+ * fix: timebox and datebox set values only with BSDDIALOG_OK.
+ * fix: menurows autosize with fullscreen.
+ * fix: bar color with 0%.
+ * fix: bar label position.
+ * improve: timebox and datebox navigation (keys, buttons and shortcuts).
+ * improve: "menus" colors for accessibility.
+
+
+2022-01-27 Version 0.1
+
+ * 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,
+ --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|default|dialog>,
+ --time-format <format>, --title <title>, --trim, --version,
+ --yes-label <label>.
+ * Dialogs: --checklist, --datebox, --form, --gauge, --infobox,
+ --inputbox, --menu, --mixedform, --mixedgauge, --msgbox,
+ --passwordbox, --passwordform, --pause, --radiolist, --rangebox,
+ --textbox, --timebox, --treeview, --yesno.
+ * Manuals: bsddialog.1, bsddialog.3.
diff --git a/GNUMakefile b/GNUMakefile
deleted file mode 100644
index 7480ae33ec21..000000000000
--- a/GNUMakefile
+++ /dev/null
@@ -1,28 +0,0 @@
-# PUBLIC DOMAIN - NO WARRANTY, see:
-# <http://creativecommons.org/publicdomain/zero/1.0/>
-#
-# Written by Alfonso Sabato Siciliano
-
-OUTPUT= bsddialog
-SOURCES= bsddialog.c
-OBJECTS= $(SOURCES:.c=.o)
-LIBPATH= ./lib
-LIBBSDDIALOG= $(LIBPATH)/libbsddialog.so
-CFLAGS= -g -Wall -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/LICENSE b/LICENSE
index 434f1782e537..d19ad87fca1f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 2-Clause License
-Copyright (c) 2021, 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 are met:
diff --git a/Makefile b/Makefile
index 295aa927e4c5..884cfa1b3e60 100644
--- a/Makefile
+++ b/Makefile
@@ -1,49 +1,38 @@
-# Any copyright is dedicated to the Public Domain, see:
+# PUBLIC DOMAIN - NO WARRANTY, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>
#
-# Written by Alfonso Sabato Siciliano
+# Written in 2023 by Alfonso Sabato Siciliano
-OUTPUT= bsddialog
-SOURCES= bsddialog.c
-OBJECTS= ${SOURCES:.c=.o}
-LIBPATH= ${.CURDIR}/lib
-LIBBSDDIALOG= ${LIBPATH}/libbsddialog.so
+OUTPUT = bsddialog
+export VERSION=1.0
+.CURDIR ?= ${CURDIR}
+LIBPATH = ${.CURDIR}/lib
+LIBBSDDIALOG = ${LIBPATH}/libbsddialog.so
+UTILITYPATH = ${.CURDIR}/utility
-CFLAGS= -Wall -I${LIBPATH}
-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
RM= rm -f
+LN = ln -s -f
+
+### cli options ###
+# port/pkg Makefile: 'MAKE_ARGS = -DNORPATH'
+NORPATH ?=
+export DISABLERPATH=${NORPATH}
+# `make -DDEBUG`
+# `gmake DEBUG=1`
+DEBUG ?=
+export ENABLEDEBUG=${DEBUG}
all : ${OUTPUT}
-${OUTPUT}: ${LIBBSDDIALOG} ${OBJECTS}
- ${CC} ${LDFLAGS} ${OBJECTS} -o ${.PREFIX}
+${OUTPUT}: ${LIBBSDDIALOG}
+ ${MAKE} -C ${UTILITYPATH} LIBPATH=${LIBPATH}
+ ${LN} ${UTILITYPATH}/${OUTPUT} ${.CURDIR}/${OUTPUT}
${LIBBSDDIALOG}:
-.if defined(PORTNCURSES)
- make -C ${LIBPATH} -DPORTNCURSES
-.else
- make -C ${LIBPATH}
-.endif
-
-.c.o:
- ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
-
-install:
- ${INSTALL} -s -m 555 ${OUTPUT} ${BINDIR}
- ${GZIP} ${MAN} > ${MAN}.gz
- ${INSTALL} -m 444 ${MAN}.gz ${MANDIR}
-
-unistall:
- ${RM} ${BINDIR}/${OUTPUT}
- ${RM} ${MANDIR}/${MAN}.gz
+ ${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
+
diff --git a/README.md b/README.md
index 31579f519ab6..f4846ec07745 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,17 @@
-# BSDDialog
+# BSDDialog 1.0
-**Work In Progress!**
+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 Widgets*.
-Description:
-<https://www.freebsd.org/status/report-2021-04-2021-06/#_bsddialog_tui_widgets>
+## Demo
-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
@@ -23,36 +20,42 @@ FreeBSD:
% ./bsddialog --msgbox "Hello World!" 8 20
```
-If you are using XFCE install
-[devel/ncurses](https://www.freshports.org/devel/ncurses/)
-
-```
-% sudo pkg install ncurses
-% git clone https://gitlab.com/alfix/bsddialog.git
-% cd bsddialog
-% make -DPORTNCURSES
-% ./bsddialog --msgbox "Hello World!" 8 20
-```
-
Output:
![screenshot](screenshot.png)
-Examples utility:
+## Utility
+
+**Dialogs:**
+
+--calendar, --checklist, --datebox, --form, --gauge, --infobox, --inputbox,
+--menu, --mixedform, --mixedgauge, --msgbox, --passwordbox, --passwordform,
+--pause, --radiolist, --rangebox, --textbox, --timebox, --treeview, --yesno.
+
+**Manual**
+
+ - [bsddialog(1)](https://alfonsosiciliano.gitlab.io/posts/2022-01-26-manual-bsddialog.html)
+
+
+**Examples**:
+
```
-% ./bsddialog --title msgbox --msgbox "Hello World!" 5 30
-% ./bsddialog --theme default --title msgbox --msgbox "Hello World!" 5 30
-% ./bsddialog --begin-y 2 --title yesno --yesno "Hello World!" 5 30
-% ./bsddialog --ascii-lines --pause "Hello World!" 8 50 5
-% ./bsddialog --checklist "Space to select" 0 0 0 Name1 Desc1 off Name2 Desc2 on Name3 Desc3 off
-% ./bsddialog --backtitle "TITLE" --title yesno --hline "bsddialog" --yesno "Hello World!" 5 25
-% ./bsddialog --extra-button --help-button --defaultno --yesno "Hello World!" 0 0
+% ./bsddialog --backtitle "TITLE" --title msgbox --msgbox "Hello World!" 5 30
+% ./bsddialog --theme blackwhite --title msgbox --msgbox "Hello World!" 5 30
+% ./bsddialog --begin-y 2 --default-no --title yesno --yesno "Hello World!" 5 30
+% ./bsddialog --ascii-lines --pause "Hello World!" 8 50 10
+% ./bsddialog --checklist "Space to select" 0 0 0 Name1 Desc1 off Name2 Desc2 on
+% ./bsddialog --title yesno --hline "bsddialog" --yesno "Hello World!" 5 25
+% ./bsddialog --extra-button --help-button --yesno "Hello World!" 0 0
```
-and
+
+and [Examples](https://gitlab.com/alfix/bsddialog/-/tree/main/examples_utility)
+in the _Public Domain_ to build new projects:
```
-% sh ./examples_utility/buildlist.sh
+% 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
@@ -63,105 +66,66 @@ and
% sh ./examples_utility/msgbox.sh
% sh ./examples_utility/passwordbox.sh
% sh ./examples_utility/passwordform.sh
+% sh ./examples_utility/pause.sh
% sh ./examples_utility/radiolist.sh
-% sh ./examples_utility/treeview.sh
+% sh ./examples_utility/rangebox.sh
+% sh ./examples_utility/timebox.sh
% sh ./examples_utility/yesno.sh
```
-Examples library:
+## Library
+
+**API**
+
+ - [bsddialog.h](https://gitlab.com/alfix/bsddialog/-/blob/main/lib/bsddialog.h)
+ - [bsddialog\_theme.h](https://gitlab.com/alfix/bsddialog/-/blob/main/lib/bsddialog_theme.h)
+
+
+**Manual**
+
+ - [bsddialog(3)](https://alfonsosiciliano.gitlab.io/posts/2022-01-15-manual-libbsddialog.html)
+
+
+**Examples**:
+
+[Examples](https://gitlab.com/alfix/bsddialog/-/tree/main/examples_library)
+in the _Public Domain_ to build new projects:
```
% cd examples_library
% sh compile
-% ./buildlist
-% ./compile
+% ./calendar
+% ./checklist
% ./datebox
% ./form
+% ./gauge
% ./infobox
% ./menu
+% ./mixedgauge
% ./mixedlist
% ./msgbox
% ./pause
% ./radiolist
% ./rangebox
-% ./sade
% ./theme
% ./timebox
-% ./treeview
% ./yesno
```
-Use Cases:
-
- - [portconfig](https://gitlab.com/alfix/portconfig)
-
-
-## Features
-
-**Common Options:**
-
---ascii-lines, --aspect *ratio* (for infobox, msgbox and yesno),
---backtitle *backtitle*, --begin-x *x* (--begin *y y*),
-(--begin *y x*), --cancel-label *string*, -clear (test with multiple widgets),
---colors, --date-format *format*, --default-button *string*, --defaultno,
---default-item *string*,
---exit-label *string*, --extra-button, --extra-label *string*,
---hfile *filename* (for completed widgets), --help, --help-button,
---help-label *string*, --help-status, --help-tags, --hline *string*, --ignore,
---insecure, --item-help, --max-input *size*, --no-cancel, --nocancel,
---no-label *string*, --no-items, --no-lines, --no-ok,
---nook, --no-shadow, --no-tags, --ok-label *string*, --output-fd *fd*,
---output-separator *string*, --print-version,
---print-size (todo move lib -> utility), --quoted (quotes all != dialog),
---print-maxsize, --shadow, --single-quoted (add --quote-with *ch*?),
---separator *string* (alias --output-separator *string*),
---separate-output (rename --separate-output-withnl?), --sleep *secs*, --stderr,
---stdout, --theme *string* ("bsddialog", "dialog", "blackwhite"),
---time-format *format*, --title *title*, --version, --yes-label *string*.
-
-**Widgets:**
-
- infobox (do not clear the screen), msgbox,
- yesno (dialog renames "yes/no" -> "ok/cancel" with --extra-button --help-button).
- checklist, radiolist, menu, mixedlist, treeview, textbox, mixedgauge, datebox,
- timebox, gauge, rangebox, pause.
-
-
- Without resize:
-
- form, inputbox, mixedform, passwordbox, passwordform.
-
-
- Without autosize, resize, F1:
-
- buildlist
-
-
-
-## TODO
-
-
-**Common Options:**
-
-| Option | Status | Note |
-| ---------------------------- | ----------- | ------------------------------- |
-| --cr-wrap | In progress | text |
-| --no-collapse | In progress | text |
-| --no-nl-expand | In progress | text |
-| --trim | In progress | text |
-
-
-To evaluate / Not planned in the short term / not in bsdinstall:
-
---create-rc *file*, --iso-week, --no-mouse, --print-text-only *str h w*,
---print-text-size *str h w*, --reorder, -scrollbar, --separate-widget *string*,
---size-err, --timeout *secs*,--trace *filename*, --visit-items,
---week-start *day*, --keep-tite, --keep-window, --last-key, --no-kill,
---column-separator *string*, --input-fd *fd*, --tab-correct, --tab-len *n*
-
-
-**Widgets:**
-
-To evaluate / Not planned in the short term:
-tailbox (textbox/fseek), tailboxbg, dselect, fselect, inputmenu, editbox,
-calendar (use datebox), prgbox, programbox, progressbox.
+## 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: multiline, conf.backtitle, WINDOW \*dialog.backtitle.
+ - refactor bottomdesc: WINDOW \*dialog.bottomdesc -> fix expandig screen.
+ - accessibility https://wiki.freebsd.org/Accessibility/Wishlist/Base
+ - add bool conf.menu.depthlines.
+ - implement custom getopt\_long().
+ - refactor/redesign gauge().
+ - improve grey lines expanding terminal (maybe redrawwin() in hide\_dialog()).
+ - more restrictive strtol() and strtoul().
+ - implement global buttons handler.
+ - add/move external tutorial.
+ - implement menutype.min_on.
diff --git a/bsddialog.1 b/bsddialog.1
deleted file mode 100644
index 2846b77547a9..000000000000
--- a/bsddialog.1
+++ /dev/null
@@ -1,52 +0,0 @@
-.\"
-.\" Copyright (c) 2021 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 December 11, 2021
-.Dt BSDDIALOG 1
-.Os
-.Sh NAME
-.Nm bsddialog
-.Nd build dialogs and widgets with a TUI
-.Sh SYNOPSIS
-.Nm bsddialog
-.Op Fl options
-.Ar
-.Sh DESCRIPTION
-The
-.Nm
-utility processes files ...
-.\" .Sh ENVIRONMENT
-.\" For sections 1, 6, 7, and 8 only.
-.\" .Sh FILES
-.\" .Sh EXIT STATUS
-.\" For sections 1, 6, and 8 only.
-.\" .Sh EXAMPLES
-.\" .Sh DIAGNOSTICS
-.\" For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
-.\" .Sh SEE ALSO
-.\" .Xr foobar 1
-.\" .Sh HISTORY
-.\" .Sh AUTHORS
-.\" .Sh CAVEATS
-.\" .Sh BUGS
diff --git a/bsddialog.c b/bsddialog.c
deleted file mode 100644
index 6fc0d834a1ad..000000000000
--- a/bsddialog.c
+++ /dev/null
@@ -1,1349 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021 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 <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.0.1"
-
-enum OPTS {
- /* Common options */
- ASCII_LINES = '?' + 1,
- ASPECT_RATIO,
- BACKTITLE,
- BEGIN_X,
- BEGIN_Y,
- CANCEL_LABEL,
- CLEAR,
- COLORS,
- CR_WRAP,
- DATE_FORMAT,
- DEFAULTNO,
- DEFAULT_BUTTON,
- DEFAULT_ITEM,
- EXIT_LABEL,
- EXTRA_BUTTON,
- EXTRA_LABEL,
- HELP,
- HELP_BUTTON,
- HELP_LABEL,
- HELP_STATUS,
- HELP_TAGS,
- HFILE,
- HLINE,
- IGNORE,
- INSECURE,
- ITEM_HELP,
- ITEM_PREFIX,
- MAX_INPUT,
- NO_CANCEL,
- NOCANCEL,
- NO_COLLAPSE,
- NO_ITEMS,
- NO_LABEL,
- NO_LINES,
- NO_NL_EXPAND,
- NO_OK,
- NOOK,
- NO_TAGS,
- NO_SHADOW,
- OK_LABEL,
- OUTPUT_FD,
- OUTPUT_SEPARATOR,
- PRINT_MAXSIZE,
- PRINT_SIZE,
- PRINT_VERSION,
- QUOTED,
- SEPARATE_OUTPUT,
- SEPARATOR,
- SHADOW,
- SINGLE_QUOTED,
- SLEEP,
- STDERR,
- STDOUT,
- THEME,
- TIME_FORMAT,
- TITLE,
- TRIM,
- VERSION,
- YES_LABEL,
- /* Widgets */
- BUILDLIST,
- CHECKLIST,
- DATEBOX,
- FORM,
- GAUGE,
- INFOBOX,
- INPUTBOX,
- MENU,
- MIXEDFORM,
- MIXEDGAUGE,
- MSGBOX,
- PASSWORDBOX,
- PASSWORDFORM,
- PAUSE,
- RADIOLIST,
- RANGEBOX,
- TEXTBOX,
- TIMEBOX,
- TREEVIEW,
- YESNO,
-};
-
-/* libbsddialog does not support NULL string for now */
-static char *nostring = "";
-/* Menus flags and options */
-static bool item_prefix_flag, item_bottomdesc_flag, item_output_sepnl_flag;
-static bool item_singlequote_flag, list_items_on_flag, item_tag_help_flag;
-static bool item_always_quote_flag;
-static char *item_output_sep_flag;
-/* Time and calendar options */
-static char *date_fmt_flag, *time_fmt_flag;
-/* Forms */
-static int max_input_form_flag;
-/* General flags and options */
-static int output_fd_flag;
-
-void usage(void);
-/* widgets */
-#define BUILDER_ARGS struct bsddialog_conf conf, char* text, int rows, \
- int cols, int argc, char **argv, char *errbuf
-int buildlist_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);
-
-static 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';
-}
-
-void usage(void)
-{
-
- printf("usage: bsddialog --help\n"
- " bsddialog --version\n"
- " bsddialog [--<common-opts>] --<widget> <text> "
- "<height> <width> [--<widget-opts>]\n");
- printf("\n");
- printf("Common Options:\n");
- printf("--ascii-lines, --aspect <ratio>, --backtitle <backtitle>, "
- "--begin-x <x>, --begin-y <y>, --cancel-label <string>, "
- "--clear, --colors, --date-format <format>, "
- "--default-button <label>, --defaultno, --default-item <name>,"
- "--exit-label <label>, --extra-button, --extra-label <label>,"
- "--hfile <filename>, --help-button, --help-label <label>, "
- "--help-status, --help-tags, --hline string, --ignore, "
- "--insecure, --item-help, --items-prefix, --max-input <size>, "
- "--no-cancel, --nocancel, --no-label <label>, --no-items, "
- "--no-lines, --no-ok, --nook, --no-shadow, --no-tags, "
- "--ok-label <label>, --output-fd <fd>, "
- "--output-separator <sep>, --print-version, --print-size, "
- "--quoted, --print-maxsize, --shadow, --single-quoted, "
- "--separator <sep>, --separate-output, --sleep <secs>, "
- "--stderr, --stdout, --theme <blackwhite|bsddialog|dialog>, "
- "--time-format <format>, --title <title>, "
- "--yes-label <string>.\n");
- printf("\n");
- printf("Widgets:\n");
- printf("--buildlist <text> <rows> <cols> <menurows> [<name> <desc> "
- "<on|off> ...]\n"
- "--checklist <text> <rows> <cols> <menurows> [<name> <desc> "
- "<on|off> ...]\n"
- "--datebox <text> <rows> <cols> [<yy> <mm> <dd>]\n"
- "--form <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxvalue> "
- "...]\n"
- "--gauge <text> <rows> <cols> [<perc\\n> [<text> ...] XXX "
- "...] EOF\n"
- "--infobox <text> <rows> <cols>\n"
- "--inputbox <text> <rows> <cols> [init]\n"
- "--menu <text> <rows> <cols> <menurows> [<name> <desc> ...]\n"
- "--mixedform <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabe> <init> <yfield> <xfield> <fieldlen> <maxvalue> "
- "<0|1|2> ...]\n"
- "--mixedgauge <text> <rows> <cols> <mainperc> [<label> "
- "<01234567|-perc> ...]\n"
- "--msgbox <text> <rows> <cols>\n"
- "--passwordbox <text> <rows> <cols> [init]\n"
- "--passwordform <text> <rows> <cols> <formrows> [<label> "
- "<ylabel> <xlabe> <init> <yfield> <xfield> <fieldlen> "
- "<maxvalue> ...]\n"
- "--pause <text> <rows> <cols> <secs>\n"
- "--radiolist <text> <rows> <cols> <menurows> [<name> <desc> "
- "<on|off> ...]\n"
- "--rangebox <text> <rows> <cols> <min> <max> <default>\n"
- "--textbox <file> <rows> <cols>\n"
- "--timebox <text> <rows> <cols> [<hh> <mm> <ss>]\n"
- "--treeview <text> <rows> <cols> <menurows> [<depth> <name> "
- "<desc> <on|off> ...]\n"
- "--yesno <text> <rows> <cols>\n");
-
-
-}
-
-int main(int argc, char *argv[argc])
-{
- char *text, *backtitle_flag, errorbuilder[1024];
- int input, rows, cols, output, getH, getW;
- int (*widgetbuilder)(BUILDER_ARGS) = NULL;
- bool ignore_flag, print_maxsize_flag;
- struct winsize ws;
- struct bsddialog_conf conf;
- enum bsddialog_default_theme theme_flag;
- bool cr_wrap_flag, no_collapse_flag, no_nl_expand_flag, trim_flag;
-
- bsddialog_initconf(&conf);
-
- backtitle_flag = NULL;
- theme_flag = -1;
- output_fd_flag = STDERR_FILENO;
- print_maxsize_flag = false;
- ignore_flag = false;
- errorbuilder[0] = '\0';
- cr_wrap_flag = no_collapse_flag = no_nl_expand_flag = trim_flag = false;
-
- item_output_sepnl_flag = item_singlequote_flag = false;
- item_prefix_flag = item_bottomdesc_flag = false;
- list_items_on_flag = item_tag_help_flag = false;
- item_always_quote_flag = false;
- item_output_sep_flag = NULL;
-
- date_fmt_flag = time_fmt_flag = NULL;
-
- max_input_form_flag = 0;
-
- /* options descriptor */
- struct option longopts[] = {
- /* common options */
- {"ascii-lines", no_argument, NULL, ASCII_LINES },
- {"aspect", required_argument, NULL, ASPECT_RATIO },
- {"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, DEFAULTNO },
- {"default-button", required_argument, NULL, DEFAULT_BUTTON },
- {"default-item", required_argument, NULL, DEFAULT_ITEM },
- {"exit-label", required_argument, NULL, EXIT_LABEL },
- {"extra-button", no_argument, NULL, EXTRA_BUTTON },
- {"extra-label", required_argument, NULL, EXTRA_LABEL },
- {"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 },
- {"ignore", no_argument, NULL, IGNORE },
- {"insecure", no_argument, NULL, INSECURE },
- {"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, NOCANCEL },
- {"no-collapse", no_argument, NULL, NO_COLLAPSE },
- {"no-items", no_argument, NULL, NO_ITEMS },
- {"no-label", required_argument, NULL, NO_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, NOOK },
- {"no-tags", no_argument, NULL, NO_TAGS },
- {"no-shadow", no_argument, NULL, NO_SHADOW },
- {"ok-label", required_argument, NULL, OK_LABEL },
- {"output-fd", required_argument, NULL, OUTPUT_FD },
- {"separator", required_argument, NULL, SEPARATOR },
- {"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 },
- {"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 },
- {"theme_flag", 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, YES_LABEL },
- /* Widgets */
- {"buildlist", no_argument, NULL, BUILDLIST },
- {"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 ASPECT_RATIO:
- conf.aspect_ratio = atoi(optarg);
- if (conf.aspect_ratio < 1) {
- printf("Error: aspect cannot be < 1");
- return (BSDDIALOG_ERROR);
- }
- break;
- case BACKTITLE:
- backtitle_flag = optarg;
- break;
- case BEGIN_X:
- conf.x = atoi(optarg);
- if (conf.x < BSDDIALOG_CENTER) {
- printf("Error: --begin-x %d, cannot be < %d",
- conf.x, BSDDIALOG_CENTER);
- return (BSDDIALOG_ERROR);
- }
- break;
- case BEGIN_Y:
- conf.y = atoi(optarg);
- if (conf.y < BSDDIALOG_CENTER) {
- printf("Error: --begin-y %d, cannot be < %d",
- conf.y, BSDDIALOG_CENTER);
- return (BSDDIALOG_ERROR);
- }
- break;
- case CANCEL_LABEL:
- conf.button.cancel_label = optarg;
- break;
- case CLEAR:
- conf.clear = true;
- break;
- case COLORS:
- conf.text.colors = true;
- break;
- case CR_WRAP:
- cr_wrap_flag = true;
- break;
- case DATE_FORMAT:
- date_fmt_flag = optarg;
- break;
- case DEFAULT_BUTTON:
- conf.button.default_label = optarg;
- break;
- case DEFAULT_ITEM:
- conf.menu.default_item = optarg;
- break;
- case DEFAULTNO:
- conf.button.default_cancel = true;
- break;
- case EXIT_LABEL:
- conf.button.exit_label = optarg;
- break;
- case EXTRA_BUTTON:
- conf.button.with_extra = true;
- break;
- case EXTRA_LABEL:
- conf.button.extra_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_flag = true;
- break;
- case HELP_TAGS:
- item_tag_help_flag = true;
- break;
- case HFILE:
- conf.f1_file = optarg;
- break;
- case HLINE:
- conf.bottomtitle = optarg;
- break;
- case IGNORE:
- ignore_flag = true;
- break;
- case INSECURE:
- conf.form.securech = '*';
- break;
- case ITEM_HELP:
- item_bottomdesc_flag = true;
- break;
- case ITEM_PREFIX:
- item_prefix_flag = true;
- break;
- case MAX_INPUT:
- max_input_form_flag = atoi(optarg);
- break;
- case NO_ITEMS:
- conf.menu.no_desc = true;
- break;
- case NOCANCEL:
- case NO_CANCEL:
- conf.button.without_cancel = true;
- break;
- case NO_COLLAPSE:
- no_collapse_flag = true;
- break;
- case NO_LABEL:
- conf.button.cancel_label = optarg;
- break;
- case NO_LINES:
- conf.no_lines = true;
- break;
- case NO_NL_EXPAND:
- no_nl_expand_flag = true;
- break;
- case NOOK:
- 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_flag = atoi(optarg);
- break;
- case SEPARATOR:
- case OUTPUT_SEPARATOR:
- item_output_sep_flag = optarg;
- break;
- case QUOTED:
- item_always_quote_flag = true;
- break;
- case PRINT_MAXSIZE:
- print_maxsize_flag = 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_flag = true;
- break;
- case SHADOW:
- conf.shadow = true;
- break;
- case SINGLE_QUOTED:
- item_singlequote_flag = true;
- break;
- case SLEEP:
- conf.sleep = atoi(optarg);
- break;
- case STDERR:
- output_fd_flag = STDERR_FILENO;
- break;
- case STDOUT:
- output_fd_flag = STDOUT_FILENO;
- break;
- case THEME:
- if (strcmp(optarg, "bsddialog") == 0)
- theme_flag = BSDDIALOG_THEME_BSDDIALOG;
- else if (strcmp(optarg, "blackwhite") == 0)
- theme_flag = BSDDIALOG_THEME_BLACKWHITE;
- else if (strcmp(optarg, "dialog") == 0)
- theme_flag = BSDDIALOG_THEME_DIALOG;
- else {
- printf("Unknown theme, possible values: ");
- printf("blackwhite, bsddialog, dialog");
- return (BSDDIALOG_ERROR);
- }
- break;
- case TIME_FORMAT:
- time_fmt_flag = optarg;
- break;
- case TITLE:
- conf.title = optarg;
- break;
- case TRIM:
- trim_flag = true;
- break;
- case VERSION:
- printf("bsddialog %s (libbsddialog %s).\n",
- BSDDIALOG_VERSION, LIBBSDDIALOG_VERSION);
- return (BSDDIALOG_OK);
- case YES_LABEL:
- conf.button.ok_label = optarg;
- break;
- /* Widgets */
- case BUILDLIST:
- widgetbuilder = buildlist_builder;
- break;
- case CHECKLIST:
- widgetbuilder = checklist_builder;
- break;
- case DATEBOX:
- widgetbuilder = datebox_builder;
- break;
- case FORM:
- widgetbuilder = form_builder;
- break;
- case GAUGE:
- widgetbuilder = gauge_builder;
- break;
- case INFOBOX:
- widgetbuilder = infobox_builder;
- break;
- case INPUTBOX:
- widgetbuilder = inputbox_builder;
- break;
- case MENU:
- widgetbuilder = menu_builder;
- break;
- case MIXEDFORM:
- widgetbuilder = mixedform_builder;
- break;
- case MIXEDGAUGE:
- widgetbuilder = mixedgauge_builder;
- break;
- case MSGBOX:
- widgetbuilder = msgbox_builder;
- break;
- case PAUSE:
- widgetbuilder = pause_builder;
- break;
- case PASSWORDBOX:
- widgetbuilder = passwordbox_builder;
- break;
- case PASSWORDFORM:
- widgetbuilder = passwordform_builder;
- break;
- case RADIOLIST:
- widgetbuilder = radiolist_builder;
- break;
- case RANGEBOX:
- widgetbuilder = rangebox_builder;
- break;
- case TEXTBOX:
- widgetbuilder = textbox_builder;
- break;
- case TIMEBOX:
- widgetbuilder = timebox_builder;
- break;
- case TREEVIEW:
- widgetbuilder = treeview_builder;
- break;
- case YESNO:
- widgetbuilder = yesno_builder;
- break;
- /* Error */
- default:
- if (ignore_flag == true)
- break;
- usage();
- return (BSDDIALOG_ERROR);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (print_maxsize_flag) {
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
- dprintf(output_fd_flag, "MaxSize: %d, %d\n",
- ws.ws_row, ws.ws_col);
- if (argc == 0)
- return (BSDDIALOG_OK);
- }
-
- if (argc < 3) {
- usage();
- return (BSDDIALOG_ERROR);
- }
- if (widgetbuilder == textbox_builder)
- text = argv[0];
- else {
- text = malloc(strlen(argv[0] + 1));
- custom_text(cr_wrap_flag, no_collapse_flag, no_nl_expand_flag,
- trim_flag, argv[0], text);
- }
- rows = atoi(argv[1]);
- cols = atoi(argv[2]);
- argc -= 3;
- argv += 3;
-
- /* bsddialog terminal mode */
- if(bsddialog_init() != 0) {
- printf("Error: %s\n", bsddialog_geterror());
- return (BSDDIALOG_ERROR);
- }
-
- if (theme_flag >= 0)
- bsddialog_set_default_theme(theme_flag);
-
- if (backtitle_flag != NULL)
- bsddialog_backtitle(&conf, backtitle_flag);
-
- output = BSDDIALOG_OK;
- if (widgetbuilder != NULL)
- output = widgetbuilder(conf, text, rows, cols, argc, argv,
- errorbuilder);
-
- if (widgetbuilder != 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());
- }
-
- if (conf.get_height != NULL && conf.get_width != NULL)
- dprintf(output_fd_flag, "Widget size: (%d - %d)\n",
- *conf.get_height, *conf.get_width);
-
- return (output);
-}
-
-/* Widgets */
-
-int gauge_builder(BUILDER_ARGS)
-{
- int output, perc;
-
- if (argc > 0) {
- perc = argc > 0 ? atoi (argv[0]) : 0;
- perc = perc < 0 ? 0 : perc;
- perc = perc > 100 ? 100 : perc;
- }
- else
- perc = 0;
-
- output = bsddialog_gauge(&conf, text, rows, cols, perc);
-
- return (output);
-}
-
-int infobox_builder(BUILDER_ARGS)
-{
- int output;
-
- output = bsddialog_infobox(&conf, text, rows, cols);
-
- return (output);
-}
-
-int mixedgauge_builder(BUILDER_ARGS)
-{
- int i, output, mainperc, nminibars, *minipercs;
- char **minilabels;
-
- if (argc < 1 || (((argc-1) % 2) != 0) ) {
- strcpy(errbuf, "bad --mixedgauge arguments\n");
- return (BSDDIALOG_ERROR);
- }
-
- mainperc = atoi(argv[0]);
- mainperc = mainperc < 0 ? 0 : mainperc;
- 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] = atoi(argv[i * 2 + 1]);
- }
-
- 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, sec;
-
- if (argc < 1) {
- strcpy(errbuf, "not <seconds> argument for --pause\n");
- return (BSDDIALOG_ERROR);
- }
-
- sec = atoi(argv[0]);
- output = bsddialog_pause(&conf, text, rows, cols, sec);
-
- 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 = atoi(argv[0]);
- max = atoi(argv[1]);
-
- if (argc > 2) {
- value = atoi(argv[2]);
- 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_flag, "%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;
-
- /* --calendar text h w [year month day] */
- if (argc == 3) {
- yy = atoi(argv[0]);
- mm = atoi(argv[1]);
- dd = atoi(argv[2]);
- }
-
- output = bsddialog_datebox(&conf, text, rows, cols, &yy, &mm, &dd);
- if (output != BSDDIALOG_OK)
- return (output);
-
- if (date_fmt_flag == NULL) {
- dprintf(output_fd_flag, "%u/%u/%u", yy, mm, dd);
- }
- else {
- time(&cal);
- localtm = localtime(&cal);
- localtm->tm_year = yy - 1900;
- localtm->tm_mon = mm;
- localtm->tm_mday = dd;
- strftime(stringdate, 1024, date_fmt_flag, localtm);
- dprintf(output_fd_flag, "%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;
-
- /* --timebox text h w [hour minute second] */
- if (argc == 3) {
- hh = atoi(argv[0]);
- mm = atoi(argv[1]);
- ss = atoi(argv[2]);
- }
-
- output = bsddialog_timebox(&conf, text, rows, cols, &hh, &mm, &ss);
- if (output != BSDDIALOG_OK)
- return (output);
-
- if (time_fmt_flag == NULL) {
- dprintf(output_fd_flag, "%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_flag, localtm);
- dprintf(output_fd_flag, "%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,
- int *nitems, struct bsddialog_menuitem *items)
-{
- int i, j, sizeitem;
-
- sizeitem = 0;
- if (setprefix) sizeitem++;
- if (setdepth) sizeitem++;
- if (setname) sizeitem++;
- if (setdesc) sizeitem++;
- if (setstatus) sizeitem++;
- if (sethelp) sizeitem++;
- if ((argc % sizeitem) != 0) {
- strcpy(errbuf, "bad number of arguments for this menu\n");
- return (BSDDIALOG_ERROR);
- }
-
- *nitems = argc / sizeitem;
- j = 0;
- for (i=0; i<*nitems; i++) {
- items[i].prefix = setprefix ? argv[j++] : nostring;
- items[i].depth = setdepth ? atoi(argv[j++]) : 0;
- items[i].name = setname ? argv[j++] : nostring;
- items[i].desc = setdesc ? argv[j++] : nostring;
- if (setstatus)
- items[i].on = strcmp(argv[j++], "on") == 0 ?
- true : false;
- else
- items[i].on = false;
- items[i].bottomdesc = sethelp ? argv[j++] : nostring;
- }
-
- return (BSDDIALOG_OK);
-}
-
-static void
-print_menu_items(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_menuitem *items, int focusitem)
-{
- int i;
- bool sep, toquote;
- char *sepstr, quotech, *helpvalue;
-
- sep = false;
- quotech = item_singlequote_flag ? '\'' : '"';
- sepstr = item_output_sep_flag != NULL ? item_output_sep_flag : " ";
-
- if (output == BSDDIALOG_HELP && focusitem >= 0) {
- dprintf(output_fd_flag, "HELP ");
-
- helpvalue = items[focusitem].name;
- if (item_bottomdesc_flag && item_tag_help_flag == false)
- helpvalue = items[focusitem].bottomdesc;
-
- toquote = item_always_quote_flag ||
- strchr(helpvalue, ' ') != NULL;
-
- if (toquote)
- dprintf(output_fd_flag, "%c", quotech);
- dprintf(output_fd_flag, "%s", helpvalue);
- if (toquote)
- dprintf(output_fd_flag, "%c", quotech);
-
- if (list_items_on_flag == false)
- return;
-
- sep = true;
- }
-
- if (output != BSDDIALOG_OK && list_items_on_flag == false)
- return;
-
- for (i = 0; i < nitems; i++) {
- if (items[i].on == false)
- continue;
-
- if (sep == true) {
- dprintf(output_fd_flag, "%s", sepstr);
- if (item_output_sepnl_flag)
- dprintf(output_fd_flag, "\n");
- }
- sep = true;
-
- toquote = item_always_quote_flag ||
- strchr(items[i].name, ' ') != NULL;
-
- if (toquote)
- dprintf(output_fd_flag, "%c", quotech);
- dprintf(output_fd_flag, "%s", items[i].name);
- if (toquote)
- dprintf(output_fd_flag, "%c", quotech);
- }
-}
-
-int buildlist_builder(BUILDER_ARGS)
-{
- int output, menurows, nitems, focusitem;
- struct bsddialog_menuitem items[1024];
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = atoi(argv[0]);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_flag, false,
- true, true, true, item_bottomdesc_flag, &nitems, items);
- if (output != 0)
- return (output);
-
- output = bsddialog_buildlist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
- if (output == BSDDIALOG_ERROR)
- return (BSDDIALOG_ERROR);
-
- print_menu_items(&conf, output, nitems, items, focusitem);
-
- return (output);
-}
-
-int checklist_builder(BUILDER_ARGS)
-{
- int output, menurows, nitems, focusitem;
- struct bsddialog_menuitem items[1024];
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = atoi(argv[0]);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_flag, false,
- true, true, true, item_bottomdesc_flag, &nitems, items);
- if (output != 0)
- return (output);
-
- output = bsddialog_checklist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(&conf, output, nitems, items, focusitem);
-
- return (output);
-}
-
-int menu_builder(BUILDER_ARGS)
-{
- int output, menurows, nitems, focusitem;
- struct bsddialog_menuitem items[1024];
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = atoi(argv[0]);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_flag, false,
- true, true, false, item_bottomdesc_flag, &nitems, items);
- if (output != 0)
- return (output);
-
- output = bsddialog_menu(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(&conf, output, nitems, items, focusitem);
-
- return (output);
-}
-
-int radiolist_builder(BUILDER_ARGS)
-{
- int output, menurows, nitems, focusitem;
- struct bsddialog_menuitem items[1024];
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = atoi(argv[0]);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_flag, false,
- true, true, true, item_bottomdesc_flag, &nitems, items);
- if (output != 0)
- return (output);
-
- output = bsddialog_radiolist(&conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(&conf, output, nitems, items, focusitem);
-
- return (output);
-}
-
-int treeview_builder(BUILDER_ARGS)
-{
- int output, menurows, nitems, focusitem;
- struct bsddialog_menuitem items[1024];
-
- if (argc < 1) {
- strcpy(errbuf, "<menurows> not provided");
- return (BSDDIALOG_ERROR);
- }
-
- menurows = atoi(argv[0]);
-
- output = get_menu_items(errbuf, argc-1, argv+1, item_prefix_flag, true,
- true, true, true, item_bottomdesc_flag, &nitems, items);
- 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(&conf, output, nitems, items, focusitem);
-
- return (output);
-}
-
-/* FORM */
-static void
-print_form_items(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_formitem *items)
-{
- int i;
-
- if (output == BSDDIALOG_ERROR)
- return;
-
- for (i=0; i < nitems; i++) {
- dprintf(output_fd_flag, "%s\n", items[i].value);
- free(items[i].value);
- }
-}
-
-int form_builder(BUILDER_ARGS)
-{
- int i, output, formheight, nitems, fieldlen, valuelen;
- struct bsddialog_formitem items[1024];
- unsigned int flags = 0;
-
- if (argc < 1 || (((argc-1) % 8) != 0) ) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = atoi(argv[0]);
-
- argc--;
- argv++;
-
- nitems = argc / 8;
- for (i=0; i<nitems; i++) {
- items[i].label = argv[8*i];
- items[i].ylabel = atoi(argv[8*i+1]);
- items[i].xlabel = atoi(argv[8*i+2]);
- items[i].init = argv[8*i+3];
- items[i].yfield = atoi(argv[8*i+4]);
- items[i].xfield = atoi(argv[8*i+5]);
-
- fieldlen = atoi(argv[8*i+6]);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = atoi(argv[8*i+7]);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(&conf, output, nitems, 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_flag > 0 ? max_input_form_flag : 2048;
- item.flags = 0;
-
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
- print_form_items(&conf, output, 1, &item);
-
- return (output);
-}
-
-int mixedform_builder(BUILDER_ARGS)
-{
- int i, output, formheight, nitems;
- struct bsddialog_formitem items[1024];
-
- if (argc < 1 || (((argc-1) % 9) != 0) ) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = atoi(argv[0]);
-
- argc--;
- argv++;
-
- nitems = argc / 9;
- for (i=0; i<nitems; i++) {
- items[i].label = argv[9*i];
- items[i].ylabel = atoi(argv[9*i+1]);
- items[i].xlabel = atoi(argv[9*i+2]);
- items[i].init = argv[9*i+3];
- items[i].yfield = atoi(argv[9*i+4]);
- items[i].xfield = atoi(argv[9*i+5]);
- items[i].fieldlen = atoi(argv[9*i+6]);
- items[i].maxvaluelen = atoi(argv[9*i+7]);
- items[i].flags = atoi(argv[9*i+8]);
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(&conf, output, nitems, 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_flag > 0 ? max_input_form_flag : 2048;
- item.flags = BSDDIALOG_FIELDHIDDEN;
-
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
- print_form_items(&conf, output, 1, &item);
-
- return (output);
-}
-
-int passwordform_builder(BUILDER_ARGS)
-{
- int i, output, formheight, nitems, fieldlen, valuelen;
- struct bsddialog_formitem items[1024];
- unsigned int flags = BSDDIALOG_FIELDHIDDEN;
-
- if (argc < 1 || (((argc-1) % 8) != 0) ) {
- strcpy(errbuf, "bad number of arguments for this form\n");
- return (BSDDIALOG_ERROR);
- }
-
- formheight = atoi(argv[0]);
-
- argc--;
- argv++;
-
- nitems = argc / 8;
- for (i=0; i<nitems; i++) {
- items[i].label = argv[8*i];
- items[i].ylabel = atoi(argv[8*i+1]);
- items[i].xlabel = atoi(argv[8*i+2]);
- items[i].init = argv[8*i+3];
- items[i].yfield = atoi(argv[8*i+4]);
- items[i].xfield = atoi(argv[8*i+5]);
-
- fieldlen = atoi(argv[8*i+6]);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = atoi(argv[8*i+7]);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
- }
-
- output = bsddialog_form(&conf, text, rows, cols, formheight,
- nitems, items);
- print_form_items(&conf, output, nitems, items);
-
- return (output);
-}
diff --git a/examples_library/buildlist.c b/examples_library/buildlist.c
deleted file mode 100644
index 37c1e342ace5..000000000000
--- a/examples_library/buildlist.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: CC0-1.0
- *
- * Written in 2021 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 <stdio.h>
-#include <string.h>
-
-#include <bsddialog.h>
-
-int main()
-{
- int i, output;
- struct bsddialog_conf conf;
- struct bsddialog_menuitem items[5] = {
- {"", false, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
- {"", true, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
- {"", false, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
- {"", true, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
- {"", false, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
- };
-
- bsddialog_initconf(&conf);
- conf.title = "radiolist";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_buildlist(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
- bsddialog_end();
-
- printf("Buildlist:\n");
- for (i=0; i<5; i++)
- printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
-
-
- return output;
-}
diff --git a/examples_library/calendar.c b/examples_library/calendar.c
new file mode 100644
index 000000000000..5899fc4986fd
--- /dev/null
+++ b/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/examples_library/checklist.c b/examples_library/checklist.c
index d1c4a4db3597..a2b178d14270 100644
--- a/examples_library/checklist.c
+++ b/examples_library/checklist.c
@@ -8,37 +8,38 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
int i, output;
struct bsddialog_conf conf;
struct bsddialog_menuitem items[5] = {
- {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
- {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
- {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
- {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
- {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ {"i", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"ii", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"iii", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"iv", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"v", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
};
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
bsddialog_initconf(&conf);
conf.title = "checklist";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_checklist(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
+ 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);
+ }
printf("Checklist:\n");
- for (i=0; i<5; i++)
+ 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/examples_library/compile b/examples_library/compile
index 4427568a7f0f..9025f35426d9 100755
--- a/examples_library/compile
+++ b/examples_library/compile
@@ -1,10 +1,21 @@
#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2021 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/>.
libpath=../lib
-examples="buildlist menu treeview checklist radiolist mixedlist theme \
- infobox yesno msgbox datebox form timebox sade rangebox pause"
+examples="menu checklist radiolist mixedlist theme infobox yesno msgbox \
+ datebox form timebox rangebox pause calendar gauge mixedgauge"
+
+rm -f $examples
for e in $examples
do
- cc -g -Wall -I$libpath ${e}.c -o $e -L$libpath -lbsddialog -Wl,-rpath=$libpath
+ cc -g -Wall -Wextra -I$libpath ${e}.c -o $e -L$libpath -lbsddialog \
+ -Wl,-rpath=$libpath
done
diff --git a/examples_library/datebox.c b/examples_library/datebox.c
index 4839c3dbd895..e0741319d388 100644
--- a/examples_library/datebox.c
+++ b/examples_library/datebox.c
@@ -8,12 +8,10 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
+#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
-#include <bsddialog.h>
-
int main()
{
int output;
@@ -28,32 +26,19 @@ int main()
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 = "datebox";
- conf.bottomtitle = "Press TAB and arrows";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_datebox(&conf, "Example", 10, 50, &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_ESC:
- printf("ESC\n");
- 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/examples_library/form.c b/examples_library/form.c
index efb997f31d36..4c6336610852 100644
--- a/examples_library/form.c
+++ b/examples_library/form.c
@@ -8,12 +8,10 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-
+#include <bsddialog.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-
-#include <bsddialog.h>
#define H BSDDIALOG_FIELDHIDDEN
#define RO BSDDIALOG_FIELDREADONLY
@@ -23,29 +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 = '*';
-
- if (bsddialog_init() < 0)
- return -1;
-
- 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)
+ if (output == BSDDIALOG_ERROR) {
printf("Error: %s", bsddialog_geterror());
+ return (1);
+ }
- for (i=0; i<3; i++) {
+ for (i = 0; i < 3; i++) {
printf("%s \"%s\"\n", items[i].label, items[i].value);
free(items[i].value);
}
-
- return output;
+
+ return (0);
}
diff --git a/examples_library/gauge.c b/examples_library/gauge.c
new file mode 100644
index 000000000000..3b38a80f3f2c
--- /dev/null
+++ b/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/examples_library/infobox.c b/examples_library/infobox.c
index 74f34bba91e1..bbd7f665d5a6 100644
--- a/examples_library/infobox.c
+++ b/examples_library/infobox.c
@@ -8,25 +8,27 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#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 = "infobox";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_infobox(&conf, "Example", 7, 20);
-
+ 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/examples_library/menu.c b/examples_library/menu.c
index 59999dabd1e5..5c4941f6d5de 100644
--- a/examples_library/menu.c
+++ b/examples_library/menu.c
@@ -8,37 +8,37 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
int i, output;
struct bsddialog_conf conf;
struct bsddialog_menuitem items[5] = {
- {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
- {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
- {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
- {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
- {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ {"I", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"II", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"III", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"IV", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"V", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
};
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
bsddialog_initconf(&conf);
conf.title = "menu";
-
- if (bsddialog_init() < 0)
- return -1;
-
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);
+ }
printf("Menu:\n");
- for (i=0; i<5; i++)
+ 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/examples_library/mixedgauge.c b/examples_library/mixedgauge.c
new file mode 100644
index 000000000000..7666867902fb
--- /dev/null
+++ b/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/examples_library/mixedlist.c b/examples_library/mixedlist.c
index 2a4e9102164c..6d286996931b 100644
--- a/examples_library/mixedlist.c
+++ b/examples_library/mixedlist.c
@@ -8,16 +8,18 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
- int i, j, output;
+ int output;
+ unsigned int i, j;
struct bsddialog_conf conf;
struct bsddialog_menuitem item;
+ struct bsddialog_menuitem sep1[1] = {
+ { "", true, 0, "Checklist", "(desc)", "" }
+ };
struct bsddialog_menuitem check[5] = {
{ "+", true, 0, "Name 1", "Desc 1", "Bottom Desc 1" },
{ "" , false, 0, "Name 2", "Desc 2", "Bottom Desc 2" },
@@ -25,8 +27,9 @@ int main()
{ "" , false, 0, "Name 4", "Desc 4", "Bottom Desc 4" },
{ "+", true, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
};
- struct bsddialog_menuitem sep[1] = {
- { "", true, 0, "Radiolist", "(desc)", "" }
+ struct bsddialog_menuitem sep2[2] = {
+ { "", true, 0, "Radiolist", "(desc)", "" },
+ { "", true, 0, "Subtitle", "(desc)", "" }
};
struct bsddialog_menuitem radio[5] = {
{ "", true, 0, "Name 1", "Desc 1", "Bottom Desc 1" },
@@ -35,36 +38,41 @@ int main()
{ "+", false, 0, "Name 4", "Desc 4", "Bottom Desc 4" },
{ "", false, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
};
- struct bsddialog_menugroup group[3] = {
- { BSDDIALOG_CHECKLIST, 5, check },
- { BSDDIALOG_SEPARATOR, 1, sep },
- { BSDDIALOG_RADIOLIST, 5, radio }
+ struct bsddialog_menugroup group[4] = {
+ { 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 = "mixedmenu";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_mixedlist(&conf, "dialog4ports", 20, 30, 11, 3, group,
- NULL,NULL);
-
+ 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);
+ }
printf("Mixedlist:\n");
- for (i=0; i<3; i++) {
- for (j=0; j<group[i].nitems; j++) {
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < group[i].nitems; j++) {
item = group[i].items[j];
if (group[i].type == BSDDIALOG_SEPARATOR)
printf("----- %s -----\n", item.name);
else if (group[i].type == BSDDIALOG_RADIOLIST)
- printf(" (%c) %s\n", item.on ? '*' : ' ', item.name);
- else /* BSDDIALOG_PORTCHECKLIST */
- printf(" [%c] %s\n", item.on ? 'X' : ' ', item.name);
+ printf(" (%c) %s\n",
+ item.on ? '*' : ' ', item.name);
+ else /* BSDDIALOG_CHECKLIST */
+ printf(" [%c] %s\n",
+ item.on ? 'X' : ' ', item.name);
}
}
-
-
- return output;
+
+ return (0);
}
diff --git a/examples_library/msgbox.c b/examples_library/msgbox.c
index 487266745c65..988e2976ee8e 100644
--- a/examples_library/msgbox.c
+++ b/examples_library/msgbox.c
@@ -8,35 +8,31 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
- int input;
+ int output;
struct bsddialog_conf conf;
- /* Configuration */
- bsddialog_initconf(&conf);
- conf.title = "msgbox";
-
- /* Run BSDDialog */
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
- return -1;
+ return (1);
}
- input = bsddialog_msgbox(&conf, "Example", 7, 20);
+ bsddialog_initconf(&conf);
+ conf.title = "msgbox";
+ output = bsddialog_msgbox(&conf, "Example", 7, 20);
bsddialog_end();
- /* User Input */
- printf("User input: ");
- switch (input) {
- case BSDDIALOG_ERROR: printf("Error %s\n", bsddialog_geterror()); break;
- case BSDDIALOG_OK: printf("OK\n"); break;
- case BSDDIALOG_ESC: printf("ESC\n"); break;
+ switch (output) {
+ case BSDDIALOG_ERROR:
+ printf("Error %s\n", bsddialog_geterror());
+ return (1);
+ case BSDDIALOG_OK:
+ printf("[OK]\n");
+ break;
}
- return input;
-}
+ return (0);
+} \ No newline at end of file
diff --git a/examples_library/pause.c b/examples_library/pause.c
index eb693325a18d..fd79d33aa4c0 100644
--- a/examples_library/pause.c
+++ b/examples_library/pause.c
@@ -8,43 +8,39 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.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";
-
- if (bsddialog_init() < 0)
- return -1;
-
- 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");
- break;
- case BSDDIALOG_ESC:
- printf("ESC\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;
+ return (0);
}
diff --git a/examples_library/radiolist.c b/examples_library/radiolist.c
index d4c93c3d406f..09df32ac2e74 100644
--- a/examples_library/radiolist.c
+++ b/examples_library/radiolist.c
@@ -8,37 +8,38 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
int i, output;
struct bsddialog_conf conf;
struct bsddialog_menuitem items[5] = {
- {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
- {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
- {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
- {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
- {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ {"I", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"II", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"III", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"IV", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"V", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
};
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
bsddialog_initconf(&conf);
conf.title = "radiolist";
-
- if (bsddialog_init() < 0)
- return -1;
-
- 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);
+ }
printf("Radiolist:\n");
- for (i=0; i<5; i++)
+ 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/examples_library/rangebox.c b/examples_library/rangebox.c
index 624bd4e438e8..50498c459fc6 100644
--- a/examples_library/rangebox.c
+++ b/examples_library/rangebox.c
@@ -8,28 +8,28 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
+#include <stdio.h>
int main()
{
int value, output;
struct bsddialog_conf conf;
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
bsddialog_initconf(&conf);
conf.title = "rangebox";
-
- if (bsddialog_init() < 0)
- return -1;
-
value = 5;
output = bsddialog_rangebox(&conf, "Example", 8, 50, 0, 10, &value);
-
bsddialog_end();
-
- printf("Value: %d", value);
-
- return output;
-}
+ if (output == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
+ printf("Value: %d\n", value);
+
+ return (0);
+} \ No newline at end of file
diff --git a/examples_library/sade.c b/examples_library/sade.c
deleted file mode 100644
index a159ab2afc0b..000000000000
--- a/examples_library/sade.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-
- * SPDX-License-Identifier: CC0-1.0
- *
- * Written in 2021 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 <stdio.h>
-#include <string.h>
-
-#include <bsddialog.h>
-
-/* Figure 15 - https://docs.freebsd.org/en/books/handbook/bsdinstall/ */
-int main()
-{
- int i, output;
- struct bsddialog_conf conf;
- struct bsddialog_menuitem items[5] = {
- {"", false, 0, "ada0", "16 GB GPT", ""},
- {"", false, 1, "ada0p1", "512 KB freebsd-boot", ""},
- {"", false, 1, "ada0p2", "15 GB freebsd-ufs", ""},
- {"", false, 1, "ada0p3", "819 MB freebsd-swap none", ""},
- {"", false, 0, "ada1", "16 GB", ""}
- };
-
- bsddialog_initconf(&conf);
- conf.title = "Partition Editor";
- char *text = "Please review the disk setup. When complete, press the "\
- "Finish button";
-
- conf.menu.align_left = true;
-
- conf.button.ok_label = "Create";
-
- conf.button.with_extra = true;
- conf.button.extra_label = "Delete";
-
- conf.button.cancel_label = "Cancel";
-
- conf.button.with_help = true;
- conf.button.help_label = "Revert";
-
- conf.button.generic1_label = "Auto";
- conf.button.generic2_label = "Finish";
-
- conf.button.default_label= "Finish";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_menu(&conf, text, 20, 0, 10, 5, items, NULL);
-
- bsddialog_end();
-
- printf("Menu:\n");
- for (i=0; i<5; i++)
- printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
-
-
- return output;
-}
diff --git a/examples_library/theme.c b/examples_library/theme.c
index 305692d39cff..689633e624ed 100644
--- a/examples_library/theme.c
+++ b/examples_library/theme.c
@@ -8,55 +8,57 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#include <bsddialog.h>
#include <bsddialog_theme.h>
+#include <stdio.h>
int main()
{
- int output;
+ int output, focusitem;
struct bsddialog_conf conf;
enum bsddialog_default_theme theme;
struct bsddialog_menuitem items[4] = {
- {"", false, 0, "Dialog", "Current dialog theme", "BSDDIALOG_THEME_DIALOG" },
- {"", false, 0, "BSDDialog", "Future default theme", "BSDDIALOG_THEME_DEFAULT"},
- {"", false, 0, "BlackWhite","Black and White theme", "BSDDIALOG_THEME_BLACKWHITE"},
- {"", false, 0, "Quit", "Exit", "Quit or Cancel to exit" }
+ {"", 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 ";
-
- if (bsddialog_init() == BSDDIALOG_ERROR)
- return BSDDIALOG_ERROR;
-
+ focusitem = -1;
while (true) {
- bsddialog_backtitle(&conf, "Theme Example");
-
- output = bsddialog_menu(&conf, "Choose theme", 15, 40, 4, 4, items, NULL);
+ output = bsddialog_menu(&conf, "Choose theme", 15, 45, 4, 4,
+ items, &focusitem);
if (output != BSDDIALOG_OK || items[3].on)
break;
if (items[0].on) {
- theme = BSDDIALOG_THEME_DIALOG;
- conf.menu.default_item = items[0].name;
- }
- else if (items[1].on) {
- theme = BSDDIALOG_THEME_BSDDIALOG;
- conf.menu.default_item = items[1].name;
- }
- else if (items[2].on) {
+ theme = BSDDIALOG_THEME_FLAT;
+ focusitem = 0;
+ } else if (items[1].on) {
+ theme = BSDDIALOG_THEME_3D;
+ focusitem = 1;
+ } else if (items[2].on) {
theme = BSDDIALOG_THEME_BLACKWHITE;
- conf.menu.default_item = items[2].name;
+ focusitem = 2;
}
-
bsddialog_set_default_theme(theme);
}
- bsddialog_end();
+ bsddialog_end();
- return output;
-}
+ return (0);
+} \ No newline at end of file
diff --git a/examples_library/timebox.c b/examples_library/timebox.c
index 117d45dcdb7b..a9354c99c9be 100644
--- a/examples_library/timebox.c
+++ b/examples_library/timebox.c
@@ -8,12 +8,10 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
+#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
-#include <bsddialog.h>
-
int main()
{
int output;
@@ -28,31 +26,19 @@ int main()
mm = localtm->tm_min;
ss = localtm->tm_sec;
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
+ }
bsddialog_initconf(&conf);
conf.title = "timebox";
- conf.bottomtitle = "Press TAB and arrows";
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_timebox(&conf, "Example", 10, 50, &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_ESC:
- printf("ESC\n");
- 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/examples_library/treeview.c b/examples_library/treeview.c
deleted file mode 100644
index 7fa3d229adf9..000000000000
--- a/examples_library/treeview.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-
- * SPDX-License-Identifier: CC0-1.0
- *
- * Written in 2021 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 <stdio.h>
-#include <string.h>
-
-#include <bsddialog.h>
-
-int main()
-{
- int i, output;
- struct bsddialog_conf conf;
- struct bsddialog_menuitem items[5] = {
- {"", false, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
- {"", false, 1, "Name 2", "Desc 2", "Bottom Desc 2"},
- {"", false, 1, "Name 3", "Desc 3", "Bottom Desc 3"},
- {"", false, 2, "Name 4", "Desc 4", "Bottom Desc 4"},
- {"", false, 1, "Name 5", "Desc 5", "Bottom Desc 5"}
- };
-
- bsddialog_initconf(&conf);
- conf.title = "radiolist";
- conf.menu.no_name = true;
- conf.menu.align_left = true;
-
- if (bsddialog_init() < 0)
- return -1;
-
- output = bsddialog_radiolist(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
- bsddialog_end();
-
- printf("Treeview:\n");
- for (i=0; i<5; i++)
- printf(" (%c) %s\n", items[i].on ? '*' : ' ', items[i].name);
-
-
- return output;
-}
diff --git a/examples_library/yesno.c b/examples_library/yesno.c
index 783fcf57cbb6..36cb59fa013b 100644
--- a/examples_library/yesno.c
+++ b/examples_library/yesno.c
@@ -8,25 +8,34 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
-#include <stdio.h>
-#include <string.h>
-
#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 = "yesno";
-
- if (bsddialog_init() < 0)
- return -1;
-
output = bsddialog_yesno(&conf, "Example", 7, 25);
-
bsddialog_end();
- return output;
-}
+ switch (output) {
+ case BSDDIALOG_ERROR:
+ printf("Error %s\n", bsddialog_geterror());
+ return (1);
+ case BSDDIALOG_YES:
+ printf("[YES]\n");
+ break;
+ case BSDDIALOG_NO:
+ printf("[NO]\n");
+ break;
+ }
+
+ return (0);
+} \ No newline at end of file
diff --git a/examples_utility/buildlist.sh b/examples_utility/buildlist.sh
deleted file mode 100755
index cefeea8f3c51..000000000000
--- a/examples_utility/buildlist.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-#-
-# SPDX-License-Identifier: CC0-1.0
-#
-# Written in 2021 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 --title buildlist --buildlist "Hello World!" 15 40 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 \
- 2>out.txt ; cat out.txt ; rm out.txt
diff --git a/examples_utility/calendar.sh b/examples_utility/calendar.sh
new file mode 100644
index 000000000000..a7ce4f1bb1d5
--- /dev/null
+++ b/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/examples_utility/checklist.sh b/examples_utility/checklist.sh
index 5f9a17cb64b1..7ff525cf765d 100755
--- a/examples_utility/checklist.sh
+++ b/examples_utility/checklist.sh
@@ -3,15 +3,36 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+ITEMS=$(./bsddialog --title " checklist " --checklist "Hello World!" 15 30 5 \
+ "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>&-)
-./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 \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $ITEMS"
+ ;;
+esac
diff --git a/examples_utility/datebox.sh b/examples_utility/datebox.sh
new file mode 100755
index 000000000000..bea4559dfbec
--- /dev/null
+++ b/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/examples_utility/form.sh b/examples_utility/form.sh
index 5d6b6ee1b606..ee25fa9cf352 100755
--- a/examples_utility/form.sh
+++ b/examples_utility/form.sh
@@ -3,17 +3,36 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
-./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 \
- 2>out.txt ; cat out.txt ; rm out.txt
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+FORMS=$(./bsddialog --title " form " --form "Hello World!" 12 40 5 \
+ 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
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $FORMS"
+ ;;
+esac
diff --git a/examples_utility/gauge.sh b/examples_utility/gauge.sh
index 82d15655efe2..a06a77034b75 100755
--- a/examples_utility/gauge.sh
+++ b/examples_utility/gauge.sh
@@ -3,26 +3,26 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
-input="A B C D E F G"
-total=`echo $input | awk '{print split($0, a)}'`
-curr=1
-for i in $input
+characters="A B C D E F G"
+total=`echo $characters | awk '{print split($0, a)}'`
+i=1
+for c in $characters
do
sleep 1
- perc="$(expr $(expr $curr "*" 100 ) "/" $total )"
- echo XXX
- echo $perc
- echo "[$curr/$total] Input: $i"
- echo XXX
- if [ $curr -eq $total ]
- then
- echo EOF
- fi
- curr=`expr $curr + 1`
-done | ./bsddialog --title gauge --gauge "[0/$total] Starting..." 10 70 0
-
+ echo XXX
+ echo "$(expr $(expr $i "*" 100) "/" $total)"
+ echo "[$i/$total] Char: $c"
+ echo XXX
+ if [ $i -eq $total ]
+ then
+ sleep 1
+ echo EOF
+ fi
+ i=`expr $i + 1`
+done | ./bsddialog --title " gauge " --gauge "[0/$total] Starting..." 10 70
diff --git a/examples_utility/infobox.sh b/examples_utility/infobox.sh
index 468ecff826fd..b782e8cbf69e 100755
--- a/examples_utility/infobox.sh
+++ b/examples_utility/infobox.sh
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
-
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
-./bsddialog --sleep 3 --title infobox --infobox "Hello World!\n3 seconds" 6 20
+./bsddialog --normal-screen --title " infobox " --infobox "Hello World!" 6 20
diff --git a/examples_utility/inputbox.sh b/examples_utility/inputbox.sh
index 27073468a478..756aec3c0241 100755
--- a/examples_utility/inputbox.sh
+++ b/examples_utility/inputbox.sh
@@ -3,10 +3,31 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+FORM=$(./bsddialog --title " inputbox " --inputbox "Hello World!" 12 40 init \
+3>&1 1>&2 2>&3 3>&-)
-./bsddialog --title " inputbox " --inputbox "Hello World!" 12 40 init \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $FORM"
+ ;;
+esac
diff --git a/examples_utility/menu.sh b/examples_utility/menu.sh
index 66c9f54beb4c..5b2f090037d8 100755
--- a/examples_utility/menu.sh
+++ b/examples_utility/menu.sh
@@ -3,15 +3,36 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+ITEM=$(./bsddialog --title " menu " --menu "Hello World!" 15 30 5 \
+ "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>&-)
-./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" \
- "Tag 5" "DESC 5 xyz" \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $ITEM"
+ ;;
+esac
diff --git a/examples_utility/mixedform.sh b/examples_utility/mixedform.sh
index 6677c20781ad..6b690e7e5b8c 100755
--- a/examples_utility/mixedform.sh
+++ b/examples_utility/mixedform.sh
@@ -3,13 +3,35 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+FORMS=$(./bsddialog --insecure --title " mixedform " \
+ --mixedform "Hello World!" 12 40 3 \
+ 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>&-)
-./bsddialog --insecure --title " mixedform " --mixedform "Hello World!" 12 40 5 \
- Label: 1 1 Entry 1 11 18 25 0 \
- Label: 2 1 Read-Only 2 11 18 25 2 \
- Password: 3 1 Value2 3 11 18 25 1 \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $FORMS"
+ ;;
+esac
diff --git a/examples_utility/mixedgauge.sh b/examples_utility/mixedgauge.sh
index ce867973859a..aa4ff2910cd9 100755
--- a/examples_utility/mixedgauge.sh
+++ b/examples_utility/mixedgauge.sh
@@ -3,32 +3,31 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
-
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
-input="A B C D E F G H"
-total=`echo $input | awk '{print split($0, a)}'`
-curr=1
-for i in $input
+perc=0
+mainperc=50
+while [ $perc -le 100 ]
do
- perc="$(expr $(expr $curr "*" 100 ) "/" $total )"
- curr=`expr $curr + 1`
- ./bsddialog --sleep 1 --title " mixedgauge " --mixedgauge "Example" 25 50 $perc \
- "Hidden!" 8 \
- "Label 1" 0 \
- "Label 2" 1 \
- "Label 3" 2 \
- "Label 4" 3 \
- "Label 5" 4 \
- "Label 6" 5 \
- "Label 7" 6 \
- "Label 8" 7 \
- "Label 9" 9 \
- "Label 10" 10 \
- "Label X" " -$perc"
- #sleep 1
-done
+ ./bsddialog --sleep 1 --title " mixedgauge " \
+ --mixedgauge "Example..." 20 45 $mainperc \
+ "Label 1" " -1" \
+ "Label 2" " -2" \
+ "Label 3" " -3" \
+ "Label 4" " -4" \
+ "Label 5" " -5" \
+ "Label 6" " -6" \
+ "Label 7" " -7" \
+ "Label 8" " -8" \
+ "Label 9" " -9" \
+ "Label 10" " -10" \
+ "Label 11" " -11" \
+ "Label X" $perc
+ perc=`expr $perc + 20`
+ mainperc=`expr $mainperc + 10`
+done
diff --git a/examples_utility/msgbox.sh b/examples_utility/msgbox.sh
index 49cb626f4055..cad3c9ecb72a 100755
--- a/examples_utility/msgbox.sh
+++ b/examples_utility/msgbox.sh
@@ -3,9 +3,26 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_ESC=5}
+
+./bsddialog --title " msgbox " --msgbox "Hello World!" 6 20
-./bsddialog --title msgbox --msgbox "Hello World!" 6 20
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK]"
+ ;;
+esac
diff --git a/examples_utility/passwordbox.sh b/examples_utility/passwordbox.sh
index 5c6a91e0f057..b43ef6f6b994 100755
--- a/examples_utility/passwordbox.sh
+++ b/examples_utility/passwordbox.sh
@@ -3,10 +3,32 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+FORM=$(./bsddialog --insecure --title " password " \
+ --passwordbox "Hello World!" 12 40 \
+3>&1 1>&2 2>&3 3>&-)
-./bsddialog --insecure --title " password " --passwordbox "Hello World!" 12 40 \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $FORM"
+ ;;
+esac
diff --git a/examples_utility/passwordform.sh b/examples_utility/passwordform.sh
index 5cfe0b0fa0a1..874a185ee66f 100755
--- a/examples_utility/passwordform.sh
+++ b/examples_utility/passwordform.sh
@@ -3,15 +3,37 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+FORMS=$(./bsddialog --insecure --title " passwordform " \
+ --passwordform "Example" 12 40 5 \
+ 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>&-)
-./bsddialog --insecure --title " passwordform " --passwordform "Example" 12 40 5 \
- Password1: 1 1 Value1 1 12 18 25 \
- Password2: 2 1 Value2 2 12 18 25 \
- Password3: 3 1 Value3 3 12 18 25 \
- Password4: 4 1 Value4 4 12 18 25 \
- Password5: 5 1 Value5 5 12 18 25 \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $FORMS"
+ ;;
+esac
diff --git a/examples_utility/pause.sh b/examples_utility/pause.sh
new file mode 100755
index 000000000000..225549dddffb
--- /dev/null
+++ b/examples_utility/pause.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2021 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_TIMEOUT=4}
+: ${BSDDIALOG_ESC=5}
+
+./bsddialog --title " pause " --pause "Hello World!" 7 35 10
+
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_TIMEOUT )
+ echo "[TIMEOUT]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK]"
+ ;;
+esac
diff --git a/examples_utility/radiolist.sh b/examples_utility/radiolist.sh
index c1c7724eb09d..359473abf35e 100755
--- a/examples_utility/radiolist.sh
+++ b/examples_utility/radiolist.sh
@@ -3,15 +3,36 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_OK=0}
+: ${BSDDIALOG_CANCEL=1}
+: ${BSDDIALOG_ESC=5}
+
+ITEM=$(./bsddialog --title " radiolist " --radiolist "Hello World!" 15 30 5 \
+ "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>&-)
-./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 \
- 2>out.txt ; cat out.txt ; rm out.txt
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_CANCEL )
+ echo "[Cancel]"
+ ;;
+ $BSDDIALOG_OK )
+ echo "[OK] $ITEM"
+ ;;
+esac
diff --git a/examples_utility/rangebox.sh b/examples_utility/rangebox.sh
new file mode 100644
index 000000000000..9b3213d8acad
--- /dev/null
+++ b/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/examples_utility/timebox.sh b/examples_utility/timebox.sh
new file mode 100755
index 000000000000..233434b29195
--- /dev/null
+++ b/examples_utility/timebox.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: CC0-1.0
+#
+# Written in 2021 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}
+
+TIME=$(./bsddialog --title " timebox " --timebox "Hello World!" 8 25 \
+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] $TIME"
+ ;;
+esac
diff --git a/examples_utility/treeview.sh b/examples_utility/treeview.sh
deleted file mode 100755
index 5286de673a1d..000000000000
--- a/examples_utility/treeview.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-#-
-# SPDX-License-Identifier: CC0-1.0
-#
-# Written in 2021 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 --title treeview --treeview "Hello World!" 15 40 5 \
- 0 "Tag 1" "DESC 1 xyz" off \
- 1 "Tag 2" "DESC 2 xyz" off \
- 2 "Tag 3" "DESC 3 xyz" on \
- 1 "Tag 4" "DESC 4 xyz" off \
- 1 "Tag 5" "DESC 5 xyz" off \
- 2>out.txt ; cat out.txt ; rm out.txt
diff --git a/examples_utility/yesno.sh b/examples_utility/yesno.sh
index 7d1d33530606..d384086657e6 100755
--- a/examples_utility/yesno.sh
+++ b/examples_utility/yesno.sh
@@ -3,9 +3,30 @@
# SPDX-License-Identifier: CC0-1.0
#
# Written in 2021 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/>.
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+: ${BSDDIALOG_ERROR=255}
+: ${BSDDIALOG_YES=0}
+: ${BSDDIALOG_NO=1}
+: ${BSDDIALOG_ESC=5}
+
+./bsddialog --title " yesno " --yesno "Hello World!" 6 25
-./bsddialog --title yesno --yesno "Hello World!" 6 25
+case $? in
+ $BSDDIALOG_ERROR )
+ exit 1
+ ;;
+ $BSDDIALOG_ESC )
+ echo "[ESC]"
+ ;;
+ $BSDDIALOG_NO )
+ echo "[NO]"
+ ;;
+ $BSDDIALOG_YES )
+ echo "[YES]"
+ ;;
+esac
diff --git a/lib/GNUMakefile b/lib/GNUmakefile
index 045b58828a07..7c7a9bc25ee4 100644
--- a/lib/GNUMakefile
+++ b/lib/GNUmakefile
@@ -1,17 +1,21 @@
# PUBLIC DOMAIN - NO WARRANTY, see:
-# <http://creativecommons.org/publicdomain/zero/1.0/>
+# <http://creativecommons.org/publicdomain/zero/1.0/>
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.1
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
-HEADERS = bsddialog.h bsddialog_theme.h
-SOURCES = barbox.c formbox.c infobox.c libbsddialog.c lib_util.c menubox.c \
- messagebox.c textbox.c theme.c timebox.c
+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)
-CFLAGS = -g -Wall -Werror -fpic
-LDFLAGS = -lform -lncurses -ltinfo
+
+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
diff --git a/lib/Makefile b/lib/Makefile
index 08d8db5191dc..252b33f79848 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,77 +1,44 @@
-# Any copyright is dedicated to the Public Domain, see:
+# PUBLIC DOMAIN - NO WARRANTY, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.0.1
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
-HEADERS = bsddialog.h bsddialog_theme.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}
-FBSDFLAGS= -O2 -pipe -std=gnu99 -Wno-format-zero-length \
- -fstack-protector-strong -Qunused-arguments
-CFLAGS = -fPIC -Wall -Wextra
+LIBRARY_A = lib${LIBRARY:=.a}
+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}
+
.if defined(DEBUG)
CFLAGS += -g
-.else
-CFLAGS += ${FBSDFLAGS}
.endif
-LDFLAGS = -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
- -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION}
+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
-INSTALL_PREFIX=/usr/local
LN = ln -s -f
RM = rm -f
-CP = cp
-GZIP = gzip -cn
-LDCONFIG = /sbin/ldconfig -m
-
-.if defined(PORTNCURSES)
-# PORT ncurses `make -DPORTNCURSES`
-CFLAGS += -DPORTNCURSES -I/usr/local/include
-LDFLAGS += -L/usr/local/lib -lform -lncurses -ltinfo
-.else
-# BASE ncurses
-LDFLAGS += -L/usr/lib -lform -lncurses -ltinfo
-.endif
-MAN= ${OUTPUT}.3
-GZIP= gzip -cn
-MANDIR= /usr/local/share/man/man3
-
-INSTALL= install
-RM= rm -f
-
-#all : man ${LIBRARY}
all : ${LIBRARY}
-${LIBRARY}: ${OBJECTS}
+${LIBRARY}: ${LIBRARY_SO} ${LIBRARY_A}
+
+${LIBRARY_SO}.${VERSION}: ${OBJECTS}
${CC} ${LDFLAGS} ${.ALLSRC} -o ${LIBRARY_SO}.${VERSION}
- # LN for devel
+
+${LIBRARY_SO}: ${LIBRARY_SO}.${VERSION}
${LN} ${LIBRARY_SO}.${VERSION} ${LIBRARY_SO}
+${LIBRARY_A}: ${OBJECTS}
+ ${AR} cr ${.TARGET} ${OBJECTS}
+ ${RANLIB} ${.TARGET}
+
.c.o:
${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
-man:
- ${GZIP} ${LIBRARY}.3 > ${LIBRARY}.3.gz
-
clean:
- ${RM} ${LIBRARY_SO}* *.o *~ *.gz
-
-
-install:
- ${CP} ${LIBRARY}.h ${INSTALL_PREFIX}/include
- ${CP} ${LIBRARY_SO}.${VERSION} ${INSTALL_PREFIX}/lib/
- ${LN} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}.${VERSION} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}
- ${LDCONFIG} ${INSTALL_PREFIX}/lib
- ${CP} ${LIBRARY}.3.gz ${INSTALL_PREFIX}/man/man3/
-
-unistall:
- ${RM} ${INSTALL_PREFIX}/include/${LIBRARY}.h
- ${RM} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}
- ${RM} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}.${VERSION}
- ${LDCONFIG} ${INSTALL_PREFIX}/lib
- ${RM} ${INSTALL_PREFIX}/man/man3/${LIBRARY}.3.gz
+ ${RM} ${LIBRARY_SO}* *.o *~ *.gz ${LIBRARY_A}
diff --git a/lib/barbox.c b/lib/barbox.c
index da4f0b72c1d6..cd9fee836f8a 100644
--- a/lib/barbox.c
+++ b/lib/barbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,648 +25,641 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
+#include <curses.h>
#include <stdlib.h>
#include <string.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <time.h>
+#include <unistd.h>
#include "bsddialog.h"
-#include "lib_util.h"
+#include "bsddialog_progressview.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-#define BARMARGIN 3
-#define MINBARWIDTH 10
-#define MINWIDTH (VBORDERS + MINBARWIDTH + BARMARGIN * 2)
-#define MINHEIGHT 7 /* without text */
-
-/* "Bar": gauge - mixedgauge - rangebox - pause */
-
-extern struct bsddialog_theme t;
-
-static void
-draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel,
- int label)
-{
- char labelstr[128];
- int i, blue_x, color;
-
- blue_x = (int)((perc*(size))/100);
-
- wmove(win, y, x);
- for (i = 0; i < size; 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);
- wmove(win, y, x + size/2 - 2);
- for (i=0; i < (int) strlen(labelstr); i++) {
- color = (blue_x + 1 <= size/2 - (int)strlen(labelstr)/2 + i ) ?
- t.bar.color : t.bar.f_color;
- wattron(win, color);
- waddch(win, labelstr[i]);
- wattroff(win, color);
- }
-}
-
-static int
-bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- char *text, struct buttons *bs)
+#define BARPADDING 2 /* widget border | BARPADDING | box bar */
+#define BOXBORDERS 2
+#define MIN_WBAR 15
+#define MIN_WBOX (BARPADDING + BOXBORDERS + MIN_WBAR + BARPADDING)
+#define MIN_WMGBAR 18
+#define MIN_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;
+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 maxword, maxline, nlines, buttonswidth;
-
- if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
- return BSDDIALOG_ERROR;
-
- buttonswidth = 0;
- if (bs != NULL) { /* gauge has not buttons */
- buttonswidth= bs->nbuttons * bs->sizebutton;
- if (bs->nbuttons > 0)
- buttonswidth += (bs->nbuttons-1) * t.button.space;
- }
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- *w = VBORDERS;
- /* buttons size */
- *w += buttonswidth;
- /* bar size */
- *w = MAX(*w, MINWIDTH);
- /* text size*/
- *w = MAX((int)(maxline + VBORDERS + t.text.hmargin * 2), *w);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- *w = MIN(*w, widget_max_width(conf));
- }
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = MINHEIGHT;
- if (maxword > 0)
- *h += 1;
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
- }
-
- return (0);
+ 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_checksize(char *text, int rows, int cols, struct buttons *bs)
+static void update_barbox(struct dialog *d, struct bar *b, bool buttons)
{
- int minheight, minwidth;
+ int y;
- minwidth = 0;
- if (bs != NULL) { /* gauge has not buttons */
- minwidth = bs->nbuttons * bs->sizebutton;
- if (bs->nbuttons > 0)
- minwidth += (bs->nbuttons-1) * t.button.space;
- }
- minwidth = MAX(minwidth + VBORDERS, MINBARWIDTH);
-
- if (cols< minwidth)
- RETURN_ERROR("Few cols for this widget");
-
- minheight = MINHEIGHT + ((text != NULL && strlen(text) > 0) ? 1 : 0);
- if (rows < minheight)
- RETURN_ERROR("Few rows for this mixedgauge");
-
- 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, char* text, int rows, int cols,
- unsigned int perc)
+bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int perc, int fd, const char *sep, const char *end)
{
- WINDOW *widget, *textpad, *bar, *shadow;
- char input[2048], ntext[2048], *pntext;
- int y, x, h, w, htextpad;
bool mainloop;
+ int fd2;
+ FILE *input;
+ char inputbuf[2048], ntext[2048], *pntext;
+ struct bar b;
+ struct dialog d;
+
+ 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%%";
+
+ input = NULL;
+ if (fd >= 0) {
+ CHECK_PTR(sep);
+ CHECK_PTR(end);
+
+ fd2 = dup(fd);
+ if ((input = fdopen(fd2, "r")) == NULL)
+ RETURN_FMTERROR("Cannot build FILE* from fd %d", fd);
+ }
- 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(text, h, w, NULL) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, false) != 0)
- return BSDDIALOG_ERROR;
-
- bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
-
+ perc = MIN(perc, 100);
mainloop = true;
while (mainloop) {
- wrefresh(widget);
- prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-4,
- x+w-1-t.text.hmargin);
- draw_perc_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) {
- scanf("%s", input);
- if (strcmp(input,"EOF") == 0) {
+ fscanf(input, "%s", inputbuf);
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
- if (strcmp(input,"XXX") == 0)
+ if (strcmp(inputbuf, sep) == 0)
break;
}
- scanf("%d", &perc);
- perc = perc < 0 ? 0 : perc;
- perc = perc > 100 ? 100 : perc;
- htextpad = 1;
- wclear(textpad);
+ if (mainloop == false)
+ break;
+ fscanf(input, "%d", &perc);
+ perc = MIN(perc, 100);
pntext = &ntext[0];
ntext[0] = '\0';
while (true) {
- scanf("%s", input);
- if (strcmp(input,"EOF") == 0) {
+ fscanf(input, "%s", inputbuf);
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
- if (strcmp(input,"XXX") == 0)
+ if (strcmp(inputbuf, sep) == 0)
break;
+ strcpy(pntext, inputbuf);
+ pntext += strlen(inputbuf); /* end string, no strlen */
pntext[0] = ' ';
pntext++;
- strcpy(pntext, input);
- pntext += strlen(input);
}
- print_textpad(conf, textpad, &htextpad, w-2-t.text.hmargin*2,
- ntext);
+ pntext[0] = '\0';
+ d.text = ntext;
}
- delwin(bar);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ if (input != NULL)
+ fclose(input);
+ delwin(b.win);
+ end_dialog(&d);
- return BSDDIALOG_OK;
+ return (BSDDIALOG_OK);
}
-int
-bsddialog_mixedgauge(struct bsddialog_conf *conf, char* text, int rows,
- int cols, unsigned int mainperc, unsigned int nminibars, char **minilabels,
- int *minipercs)
+/* Mixedgauge */
+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)
{
- WINDOW *widget, *textpad, *bar, *shadow;
- int i, output, miniperc, y, x, h, w, max_minbarlen;
- int maxword, maxline, nlines, htextpad, ypad;
- char states[12][16] = {
- "[ Succeeded ]", /* 0 */
- "[ Failed ]", /* 1 */
- "[ Passed ]", /* 2 */
- "[ Completed ]", /* 3 */
- "[ Checked ]", /* 4 */
- "[ Done ]", /* 5 */
- "[ Skipped ]", /* 6 */
- "[ In Progress ]", /* 7 */
- "(blank) ", /* 8 */
- "[ N/A ]", /* 9 */
- "[ Pending ]", /* 10 */
- "[ UNKNOWN ]", /* 10+ */
- };
-
- max_minbarlen = 0;
- for (i=0; i < (int)nminibars; i++)
- max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i]));
- max_minbarlen += 3 + 16 /* seps + [...] or mainbar */;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
-
- /* mixedgauge autosize */
- if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
- return BSDDIALOG_ERROR;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- w = max_minbarlen + HBORDERS;
- w = MAX(max_minbarlen, maxline + 4);
- w = MAX(w, (int)conf->auto_minwidth);
- w = MIN(w, widget_max_width(conf) - 1);
- }
- if (rows == BSDDIALOG_AUTOSIZE) {
- h = 5; /* borders + mainbar */
- h += nminibars;
- h += (strlen(text) > 0 ? 3 : 0);
- h = MAX(h, (int)conf->auto_minheight);
- h = MIN(h, widget_max_height(conf) -1);
- }
-
- /* mixedgauge checksize */
- if (w < max_minbarlen + 2)
- RETURN_ERROR("Few cols for this mixedgauge");
- if (h < 5 + (int)nminibars + (strlen(text) > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for this mixedgauge");
-
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- output = new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w,
- RAISED, &textpad, &htextpad, text, false);
- if (output == BSDDIALOG_ERROR)
- return output;
+ int i, miniperc, max_minibarlen;
+ 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_minibarlen = 0;
+ for (i = 0; i < (int)nminibars; i++)
+ max_minibarlen = MAX(max_minibarlen,
+ (int)strcols(CHECK_STR(minilabels[i])));
+ max_minibarlen += 3 + 16; /* seps + [...] */
+ max_minibarlen = MAX(max_minibarlen, MIN_WMGBOX); /* mainbar */
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (dialog_size_position(&d, nminibars + HBOX, max_minibarlen,
+ &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
+ return (BSDDIALOG_ERROR);
/* mini bars */
- for (i=0; i < (int)nminibars; i++) {
+ 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 == 8)
+ /* label */
+ if (color && miniperc >= 0)
+ wattron(d.widget, A_BOLD);
+ mvwaddstr(d.widget, i+1, 2, CHECK_STR(minilabels[i]));
+ if (color && miniperc >= 0)
+ wattroff(d.widget, A_BOLD);
+ /* perc */
+ if (miniperc == BSDDIALOG_MG_BLANK)
continue;
- mvwaddstr(widget, i+1, 2, minilabels[i]);
- if (miniperc > 10)
- mvwaddstr(widget, i+1, w-2-15, states[11]);
- else if (miniperc >= 0 && miniperc <= 10)
- mvwaddstr(widget, i+1, w-2-15, states[miniperc]);
- else { /* miniperc < 0 */
- miniperc = abs(miniperc);
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- draw_perc_bar(widget, i+1, 1+w-2-15, 13, miniperc,
- false, -1 /*unused*/);
+ 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)
+ minicolor = red;
+ else if (color && miniperc == BSDDIALOG_MG_DONE)
+ minicolor = green;
+ wattron(d.widget, minicolor);
+ miniperc = abs(miniperc + 1);
+ mvwaddstr(d.widget, i+1, 1+d.w-2-15, states[miniperc]);
+ wattroff(d.widget, minicolor);
}
}
+ wnoutrefresh(d.widget);
+
+ /* text */
+ ystext = MAX(d.h - BORDERS - htext - HBOX, (int)nminibars);
+ rtextpad(&d, 0, 0, ystext, HBOX);
- wrefresh(widget);
- ypad = y + h - 5 - htextpad;
- ypad = ypad < y+(int)nminibars ? y+nminibars : ypad;
- prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2);
-
/* main bar */
- bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED);
-
- draw_perc_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/);
+ 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);
+
+ doupdate();
+ /* getch(); to test with "alternate mode" */
+
+ delwin(b.win);
+ end_dialog(&d);
+
+ return (BSDDIALOG_OK);
+}
- wattron(bar, t.bar.color);
- mvwaddstr(bar, 0, 2, "Overall Progress");
- wattroff(bar, t.bar.color);
+int
+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 retval;
- wrefresh(bar);
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars,
+ minilabels, minipercs, false);
- /* getch(); port ncurses shows nothing */
+ return (retval);
+}
- delwin(bar);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+int
+bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct bsddialog_progviewconf *pvconf, unsigned int nminibar,
+ struct bsddialog_fileminibar *minibar)
+{
+ bool update;
+ int perc, retval, *minipercs;
+ unsigned int i, mainperc, totaltodo;
+ float readforsec;
+ const char **minilabels;
+ time_t tstart, told, tnew, refresh;
+
+ if ((minilabels = calloc(nminibar, sizeof(char*))) == NULL)
+ RETURN_ERROR("Cannot allocate memory for minilabels");
+ if ((minipercs = calloc(nminibar, sizeof(int))) == NULL)
+ RETURN_ERROR("Cannot allocate memory for minipercs");
+
+ totaltodo = 0;
+ for (i = 0; i < nminibar; i++) {
+ totaltodo += minibar[i].size;
+ minilabels[i] = minibar[i].label;
+ minipercs[i] = minibar[i].status;
+ }
- return BSDDIALOG_OK;
+ refresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1;
+ retval = BSDDIALOG_OK;
+ i = 0;
+ update = true;
+ time(&told);
+ tstart = told;
+ while (!(bsddialog_interruptprogview || bsddialog_abortprogview)) {
+ if (bsddialog_total_progview == 0 || totaltodo == 0)
+ mainperc = 0;
+ else
+ mainperc = (bsddialog_total_progview * 100) / totaltodo;
+
+ time(&tnew);
+ if (update || tnew > told + refresh) {
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc,
+ nminibar, minilabels, minipercs, true);
+ if (retval == BSDDIALOG_ERROR)
+ return (BSDDIALOG_ERROR);
+
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ readforsec = ((tnew - tstart) == 0) ? 0 :
+ bsddialog_total_progview / (float)(tnew - tstart);
+ printw(pvconf->fmtbottomstr, bsddialog_total_progview,
+ readforsec);
+ refresh();
+
+ time(&told);
+ update = false;
+ }
+
+ if (i >= nminibar)
+ break;
+ if (minibar[i].status == BSDDIALOG_MG_FAILED)
+ break;
+
+ perc = pvconf->callback(&minibar[i]);
+
+ if (minibar[i].status == BSDDIALOG_MG_DONE) { /*||perc >= 100)*/
+ minipercs[i] = BSDDIALOG_MG_DONE;
+ update = true;
+ i++;
+ } else if (minibar[i].status == BSDDIALOG_MG_FAILED ||
+ perc < 0) {
+ minipercs[i] = BSDDIALOG_MG_FAILED;
+ update = true;
+ } else /* perc >= 0 */
+ minipercs[i] = perc;
+ }
+
+ free(minilabels);
+ free(minipercs);
+ return (retval);
}
-int
-bsddialog_rangebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
- int min, int max, int *value)
+static int rangebox_redraw(struct dialog *d, struct bar *b, int *bigchange)
{
- WINDOW *widget, *textpad, *bar, *shadow;
- int i, y, x, h, w, htextpad;
- bool loop, buttupdate, barupdate;
- int input, currvalue, output, sizebar, bigchange, positions;
- float perc;
- struct buttons bs;
+ 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) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ 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);
+}
- if (value == NULL)
- RETURN_ERROR("*value cannot be NULL");
+int
+bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, int min, int max, int *value)
+{
+ 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, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_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(text, h, w, &bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
- x+w-1-t.text.hmargin);
-
- sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
- bigchange = MAX(1, sizebar/10);
-
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3,
- sizebar + 2, RAISED);
-
- loop = buttupdate = barupdate = true;
- while(loop) {
- if (buttupdate) {
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
- buttupdate = false;
- }
- if (barupdate) {
- perc = ((float)(currvalue - min)*100) / (positions-1);
- draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
- barupdate = false;
- wrefresh(bar);
+ 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 (rangebox_redraw(&d, &b, &bigchange) != 0)
+ return (BSDDIALOG_ERROR);
+
+ loop = true;
+ while (loop) {
+ if (b.toupdate) {
+ b.perc = ((float)(currvalue - min)*100) / (positions-1);
+ b.label = currvalue;
+ draw_bar(&b);
}
-
- 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 */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (conf->key.enable_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_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 KEY_UP:
if (currvalue < max) {
currvalue++;
- barupdate = true;
+ b.toupdate = true;
}
break;
case KEY_DOWN:
if (currvalue > min) {
currvalue--;
- barupdate = true;
+ b.toupdate = true;
}
break;
case KEY_F(1):
- if (conf->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No break! the terminal size can change */
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- 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(text, h, w, &bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
- bigchange = MAX(1, sizebar/10);
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARMARGIN);
- wresize(bar, 3, sizebar + 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
- x+w-1-t.text.hmargin);
-
- draw_borders(conf, bar, 3, sizebar + 2, RAISED);
-
- barupdate = true;
- buttupdate = true;
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
}
}
}
- delwin(bar);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ *value = currvalue;
+
+ delwin(b.win);
+ end_dialog(&d);
- return output;
+ return (retval);
+}
+
+static int pause_redraw(struct dialog *d, struct bar *b)
+{
+ 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) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
+
+ b->w = WBAR(d);
+ update_barbox(d, b, true);
+ b->toupdate = true;
+
+ return (0);
}
int
-bsddialog_pause(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int sec)
+bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *seconds)
{
- WINDOW *widget, *textpad, *bar, *shadow;
- int i, output, y, x, h, w, htextpad;
- bool loop, buttupdate, barupdate;
- int input, tout, sizebar;
- float perc;
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_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(text, h, w, &bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
- x+w-1-t.text.hmargin);
-
- sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3,
- sizebar + 2, RAISED);
-
- tout = sec;
+ 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, &b) != 0)
+ return (BSDDIALOG_ERROR);
+
+ tout = *seconds;
nodelay(stdscr, TRUE);
timeout(1000);
- loop = buttupdate = barupdate = true;
- while(loop) {
- if (barupdate) {
- perc = (float)tout * 100 / sec;
- draw_perc_bar(bar, 1, 1, sizebar, perc, true, tout);
- barupdate = false;
- wrefresh(bar);
+ loop = true;
+ while (loop) {
+ if (b.toupdate) {
+ b.perc = (float)tout * 100 / *seconds;
+ b.label = tout;
+ draw_bar(&b);
}
-
- if (buttupdate) {
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
- buttupdate = false;
- }
-
- 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 */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (conf->key.enable_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->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No break! the terminal size can change */
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (pause_redraw(&d, &b) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- 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(text, h, w, &bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARMARGIN);
- wresize(bar, 3, sizebar + 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
- x+w-1-t.text.hmargin);
-
- draw_borders(conf, bar, 3, sizebar + 2, RAISED);
-
- barupdate = true;
- buttupdate = true;
+ if (pause_redraw(&d, &b) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
}
}
}
-
nodelay(stdscr, FALSE);
- delwin(bar);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ *seconds = MAX(tout, 0);
+
+ delwin(b.win);
+ end_dialog(&d);
- return output;
+ return (retval);
}
diff --git a/lib/bsddialog.3 b/lib/bsddialog.3
index 7e1238f38e52..38885bfe3ea4 100644
--- a/lib/bsddialog.3
+++ b/lib/bsddialog.3
@@ -1,42 +1,1183 @@
-.Dd $Mdocdate$
-.Dt PROGNAME section
+.\"
+.\" 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
+.\" 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 July 28, 2023
+.Dt BSDDIALOG 3
.Os
.Sh NAME
-.Nm progname
-.Nd one line about what it does
-.\" .Sh LIBRARY
-.\" For sections 2, 3, and 9 only.
-.\" Not used in OpenBSD.
+.Nm bsddialog_backtitle ,
+.Nm bsddialog_calendar ,
+.Nm bsddialog_clear ,
+.Nm bsddialog_color ,
+.Nm bsddialog_color_attrs ,
+.Nm bsddialog_checklist ,
+.Nm bsddialog_datebox ,
+.Nm bsddialog_end ,
+.Nm bsddialog_form ,
+.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 ,
+.Nm bsddialog_msgbox ,
+.Nm bsddialog_pause ,
+.Nm bsddialog_radiolist ,
+.Nm bsddialog_rangebox ,
+.Nm bsddialog_refresh ,
+.Nm bsddialog_set_theme ,
+.Nm bsddialog_set_default_theme ,
+.Nm bsddialog_textbox ,
+.Nm bsddialog_timebox ,
+.Nm bsddialog_yesno
+.Nd TUI dialogs
+.Sh LIBRARY
+.Lb libbsddialog
.Sh SYNOPSIS
-.Nm progname
-.Op Fl options
-.Ar
+.In bsddialog.h
+.Ft int
+.Fn bsddialog_backtitle "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"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int menurows"
+.Fa "unsigned int nitems"
+.Fa "struct bsddialog_menuitem *items"
+.Fa "int *focusitem"
+.Fc
+.Ft void
+.Fn bsddialog_clear "unsigned int y"
+.Ft int
+.Fo bsddialog_datebox
+.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
+.Fn bsddialog_end "void"
+.Ft int
+.Fo bsddialog_form
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int formrows"
+.Fa "unsigned int nitems"
+.Fa "struct bsddialog_formitem *items"
+.Fa "int *focusitem"
+.Fc
+.Ft int
+.Fo bsddialog_gauge
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int perc"
+.Fa "int fd"
+.Fa "const char *sep"
+.Fa "const char *end"
+.Fc
+.Ft const char *
+.Fn bsddialog_geterror "void"
+.Ft int
+.Fo bsddialog_infobox
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fc
+.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
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int menurows"
+.Fa "unsigned int nitems"
+.Fa "struct bsddialog_menuitem *items"
+.Fa "int *focusitem"
+.Fc
+.Ft int
+.Fo bsddialog_mixedgauge
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int mainperc"
+.Fa "unsigned int nminibars"
+.Fa "char **minilabels"
+.Fa "int *minipercs"
+.Fc
+.Ft int
+.Fo bsddialog_mixedlist
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int menurows"
+.Fa "unsigned int ngroups"
+.Fa "struct bsddialog_menugroup *groups"
+.Fa "int *focuslist"
+.Fa "int *focusitem"
+.Fc
+.Ft int
+.Fo bsddialog_msgbox
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fc
+.Ft int
+.Fo bsddialog_pause
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int *seconds"
+.Fc
+.Ft int
+.Fo bsddialog_radiolist
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int menurows"
+.Fa "unsigned int nitems"
+.Fa "struct bsddialog_menuitem *items"
+.Fa "int *focusitem"
+.Fc
+.Ft int
+.Fo bsddialog_rangebox
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "int min"
+.Fa "int max"
+.Fa "int *value"
+.Fc
+.Ft void
+.Fn bsddialog_refresh "void"
+.Ft int
+.Fo bsddialog_textbox
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *file"
+.Fa "int rows"
+.Fa "int cols"
+.Fc
+.Ft int
+.Fo bsddialog_timebox
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int *hh"
+.Fa "unsigned int *mm"
+.Fa "unsigned int *ss"
+.Fc
+.Ft int
+.Fo bsddialog_yesno
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fc
+.In bsddialog_theme.h
+.Ft int
+.Fo bsddialog_color
+.Fa "enum bsddialog_color foreground"
+.Fa "enum bsddialog_color background"
+.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
+.Fn bsddialog_set_theme "struct bsddialog_theme *theme"
.Sh DESCRIPTION
The
-.Nm
-utility processes files ...
-.\" .Sh CONTEXT
-.\" For section 9 functions only.
-.\" .Sh IMPLEMENTATION NOTES
-.\" Not used in OpenBSD.
-.\" .Sh RETURN VALUES
-.\" For sections 2, 3, and 9 function return values only.
-.\" .Sh ENVIRONMENT
-.\" For sections 1, 6, 7, and 8 only.
-.\" .Sh FILES
-.\" .Sh EXIT STATUS
-.\" For sections 1, 6, and 8 only.
-.\" .Sh EXAMPLES
-.\" .Sh DIAGNOSTICS
-.\" For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
-.\" .Sh ERRORS
-.\" For sections 2, 3, 4, and 9 errno settings only.
-.\" .Sh SEE ALSO
-.\" .Xr foobar 1
-.\" .Sh STANDARDS
-.\" .Sh HISTORY
-.\" .Sh AUTHORS
-.\" .Sh CAVEATS
-.\" .Sh BUGS
-.\" .Sh SECURITY CONSIDERATIONS
-.\" Not used in OpenBSD.
+.Nm bsddialog
+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
+.Fn bsddialog_initconf
+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 .
+After the call is not possible to use the library functions.
+.Pp
+.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
+prints
+.Fa backtitle
+on the top of the screen.
+The function handles
+.Fa conf.ascii_lines
+and
+.Fa conf.no_lines
+described 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 a fixed size,
+.Dv BSDDIALOG_AUTOSIZE
+or
+.Dv BSDDIALOG_FULLSCREEN .
+.Fa conf
+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;
+ int *get_width;
+ bool no_lines;
+ bool shadow;
+ unsigned int sleep;
+ const char *title;
+ int y;
+ int x;
+ struct {
+ bool enable_esc;
+ const char *f1_file;
+ const char *f1_message;
+ } key;
+ struct {
+ unsigned int cols_per_row;
+ bool escape;
+ unsigned int tablen;
+ } text;
+ struct {
+ bool align_left;
+ bool no_desc;
+ bool no_name;
+ bool shortcut_buttons;
+ } menu;
+ struct {
+ 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;
+ const char *extra_label;
+ bool without_cancel;
+ const char *cancel_label;
+ bool default_cancel;
+ bool with_help;
+ const char *help_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
+ const char *default_label;
+ } button;
+};
+.Ed
+.Pp
+.Bl -column -compact
+.It Fa conf.ascii_lines
+ascii characters to draw lines, default wide characters.
+.It Fa conf.auto_minheight
+minimum height if
+.Fa rows
+is
+.Dv BSDDIALOG_AUTOSIZE .
+.It Fa conf.auto_minwidth
+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
+dialog subtitle.
+.It Fa conf.clear
+hide the dialog at exit.
+.It Fa conf.get_height
+if not
+.Dv NULL
+is set like the dialog height.
+.It Fa conf.get_width
+if not
+.Dv NULL
+is set like the dialog width.
+.It Fa conf.no_lines
+not draw lines.
+.It Fa conf.shadow
+draw shadow.
+.It Fa conf.sleep
+wait before to return, the value is in seconds.
+.It Fa conf.title
+dialog title.
+.It Fa conf.y
+dialog vertical position, 0 is top screen, can be
+.Dv BSDDIALOG_CENTER .
+.It Fa conf.x
+dialog horizontal position, 0 is left screen, can be
+.Dv BSDDIALOG_CENTER .
+.El
+.Pp
+.Bl -column -compact
+.It Fa conf.key.enable_esc
+enable
+.Dv ESC
+key to close the dialog.
+.It Fa conf.key.f1_file
+open a file in a textbox if F1 is pressed.
+.It Fa conf.key.f1_message
+build a msgbox with message if F1 is pressed.
+.El
+.Pp
+.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
+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.
+.It Fa conf.text.tablen
+tab length for
+.Fa text
+argument and
+.Fn bsddialog_textbox
+function.
+.El
+.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
+set label for OK button.
+.It Fa conf.button.with_extra
+add Extra button.
+.It Fa conf.button.extra_label
+set a label for Extra button.
+.It Fa conf.button.without_cancel
+disable Cancel button.
+.It Fa conf.button.cancel_label
+sets a label for Cancel button.
+.It Fa conf.button.default_cancel
+on startup focus on the Cancel button.
+.It Fa conf.button.with_help
+add Help button.
+.It Fa conf.button.help_label
+set a label for Help button.
+.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.right3_label
+add a button with the specified label.
+.It Fa conf.button.default_label
+focus on the button with the specified label.
+.El
+.Pp
+.Fn bsddialog_initconf
+initializes
+.Fa conf
+disabling each property, except
+.Fa conf.shadow
+to true,
+.Fa conf.y
+and
+.Fa conf.x
+to
+.Dv BSDDIALOG_CENTER ,
+.Fa conf.text.cols_per_row
+to
+.Dv 10 .
+.Pp
+.Fn bsddialog_calendar
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
+and
+.Fa day
+are default values on startup, selected date at exit.
+.Pp
+.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
+.Fn bsddialog_datebox
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
+and
+.Fa day
+are default values on startup, selected date at exit.
+The function can be customized by:
+.Bl -column -compact
+.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 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 {
+ const char *label;
+ unsigned int ylabel;
+ unsigned int xlabel;
+
+ const char *init;
+ unsigned int yfield;
+ unsigned int xfield;
+ unsigned int fieldlen;
+ unsigned int maxvaluelen;
+ char *value;
+
+ unsigned int flags;
+
+ const char *bottomdesc;
+};
+.Ed
+.Pp
+.Fa label
+is a string to describe the request at the position
+.Fa ylabel
+and
+.Fa xlabel .
+The field for the input is at the position
+.Fa yfield
+and
+.Fa xfield ,
+.Fa fieldlen
+is its graphical width, while
+.Fa maxvalelen
+is the maximum number of characters of the input string.
+.Fa init
+is the default field value.
+If no error occurs
+.Fa value
+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 field:
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Dv BSDDIALOG_FIELDREADONLY ,
+.Dv BSDDIALOG_FIELDNOCOLOR ,
+.Dv BSDDIALOG_FIELDCURSOREND ,
+.Dv BSDDIALOG_FIELDEXTEND ,
+.Dv BSDDIALOG_FIELDSINGLEBYTE .
+.Fa bottomdesc
+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.securech
+charachter to hide the input with
+.Dv BSDDIALOG_FIELDHIDDEN .
+.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
+is a
+.Em wchar_t*
+string.
+.El
+.Pp
+.Fn bsddialog_gauge
+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 sep
+from it, then the first string replaces
+.Fa perc
+and the following strings replace
+.Fa text
+until the next
+.Fa sep ,
+the loop ends reading
+.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 or 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
+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
+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 ,
+.Dv BSDDIALOG_MG_COMPLETED ,
+.Dv BSDDIALOG_MG_CHECKED ,
+.Dv BSDDIALOG_MG_DONE ,
+.Dv BSDDIALOG_MG_SKIPPED ,
+.Dv BSDDIALOG_MG_INPROGRESS ,
+.Dv BSDDIALOG_MG_BLANK
+to hide
+.Fa miniperc ,
+.Dv BSDDIALOG_MG_NA ,
+.Dv BSDDIALOG_MG_PENDING
+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
+.Fa min
+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.
+.Pp
+.Fn bsddialog_textbox
+opens and prints
+.Fa file .
+UP, DOWN, LEFT, RIGHT, HOME, END, PAGEUP and PAGEDOWN keys are available to
+navigate the file, TAB changes button.
+.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 Yes and No.
+.Ss Theme
+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
+API.
+.Pp
+.Bd -literal -offset indent -compact
+struct bsddialog_theme {
+ struct {
+ int color;
+ } screen;
+ struct {
+ int color;
+ unsigned int y;
+ unsigned int x;
+ } shadow;
+ struct {
+ int color;
+ bool delimtitle;
+ int titlecolor;
+ int lineraisecolor;
+ int linelowercolor;
+ int bottomtitlecolor;
+ 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 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 minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
+ int f_delimcolor;
+ int delimcolor;
+ int f_color;
+ int color;
+ int f_shortcutcolor;
+ int shortcutcolor;
+ } button;
+};
+.Ed
+.Pp
+A member with the
+.Dq f_
+refers to focus when an element can be in selected or not selected state.
+.Pp
+.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 ,
+.Dv BSDDIALOG_YELLOW ,
+.Dv BSDDIALOG_BLUE ,
+.Dv BSDDIALOG_MAGENTA ,
+.Dv BSDDIALOG_CYAN ,
+.Dv BSDDIALOG_WHITE .
+.Fa flags
+is an OR value:
+.Dv BSDDIALOG_BLINK ,
+.Dv BSDDIALOG_BOLD ,
+.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 runtime theme.
+Changes take effect only for dialogs built after
+the call.
+.Pp
+.Fn bsddialog_set_default_theme
+sets a library default theme like current theme, possible values:
+.Dv BSDDIALOG_THEME_BLACKWHITE ,
+.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
+if unsuccessful;
+otherwise, depending on the pressed button, the following values can be
+returned:
+.Dv BSDDIALOG_OK ,
+.Dv BSDDIALOG_CANCEL ,
+.Dv BSDDIALOG_HELP ,
+.Dv BSDDIALOG_EXTRA ,
+.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
+are aliases for
+.Dv BSDDIALOG_OK
+and
+.Dv BSDDIALOG_CANCEL ,
+respectively.
+.Pp
+The functions return
+.Dv BSDDIALOG_ESC
+if
+.Fa conf.key.enable_esc
+is enabled and the ESC key is pressed.
+.Pp
+.Fn bsddialog_pause
+returns
+.Dv BSDDIALOG_TIMEOUT
+if the timeout expires.
+.Sh EXAMPLES
+.Dq Yes-No Question
+Example:
+.Pp
+.Bd -literal -offset indent -compact
+int output;
+struct bsddialog_conf conf;
+
+if (bsddialog_init() == BSDDIALOG_ERROR)
+ return (1);
+
+bsddialog_initconf(&conf);
+conf.title = "yesno";
+output = bsddialog_yesno(&conf, "Example", 7, 25);
+
+bsddialog_end();
+
+switch (output) {
+case BSDDIALOG_YES:
+ printf("Yes\\n");
+ break;
+case BSDDIALOG_NO
+ printf("NO\\n");
+ break;
+case BSDDIALOG_ERROR:
+ printf("Error: %s\\n", bsddialog_geterror());
+ break;
+}
+.Ed
+.Pp
+Theme Example:
+.Pp
+.Bd -literal -offset indent -compact
+struct bsddialog_conf conf;
+struct bsddialog_theme theme;
+
+bsddialog_init();
+
+bsddialog_initconf(&conf);
+bsddialog_msgbox(&conf, "Default theme", 7, 25);
+
+bsddialog_get_theme(&theme);
+theme.screen.color = bsddialog_color(BSDDIALOG_RED, BSDDIALOG_GREEN,
+ BSDDIALOG_BOLD);
+bsddialog_set_theme(&theme);
+bsddialog_backtitle(&conf, "Red foreground and Green background");
+bsddialog_msgbox(&conf, "Change screen color", 7, 25);
+
+bsddialog_set_default_theme(BSDDIALOG_THEME_BLACKWHITE);
+bsddialog_msgbox(&conf, "Black and White theme", 7, 25);
+
+bsddialog_end();
+.Ed
+.Pp
+Mixedlist Example:
+.Pp
+.Bd -literal -offset indent -compact
+unsigned int i, j;
+struct bsddialog_conf conf;
+struct bsddialog_menuitem item;
+struct bsddialog_menuitem check[2] = {
+ { "1", true, 0, "Name 1", "Desc 1", "Check Bottom Desc 1" },
+ { "2", false, 0, "Name 2", "Desc 2", "Check Bottom Desc 2" }
+};
+struct bsddialog_menuitem sep[1] = {
+ { "3", true, 0, "Radiolist", "(desc)", "" }
+};
+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" }
+};
+struct bsddialog_menugroup group[3] = {
+ { BSDDIALOG_CHECKLIST, 2, check },
+ { BSDDIALOG_SEPARATOR, 1, sep },
+ { BSDDIALOG_RADIOLIST, 2, radio }
+};
+
+bsddialog_init();
+bsddialog_initconf(&conf);
+bsddialog_mixedlist(&conf, "Example", 20, 30, 11, 3, group, NULL,
+ NULL);
+bsddialog_end();
+
+for (i = 0; i < 3; i++) {
+ for (j = 0; j < group[i].nitems; j++) {
+ item = group[i].items[j];
+ switch (item.type) {
+ case BSDDIALOG_SEPARATOR:
+ printf("---- %s ----\\n", item.name);
+ break;
+ case BSDDIALOG_RADIOLIST:
+ printf(" (%c) %s\\n",
+ item.on ? '*' : ' ', item.name);
+ break;
+ case BSDDIALOG_CHECKLIST:
+ printf(" [%c] %s\\n",
+ item.on ? 'X' : ' ', item.name);
+ break;
+ }
+ }
+}
+.Ed
+.Sh SEE ALSO
+.Xr bsddialog 1 ,
+.Xr curses 3
+.Sh HISTORY
+The
+.Nm bsddialog
+library first appeared in
+.Fx 14.0 .
+.Sh AUTHORS
+.Nm bsddialog
+was written by
+.An Alfonso Sabato Siciliano Aq Mt asiciliano@FreeBSD.org .
diff --git a/lib/bsddialog.h b/lib/bsddialog.h
index 29b9b5240706..d997036b1f9f 100644
--- a/lib/bsddialog.h
+++ b/lib/bsddialog.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 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
@@ -30,189 +30,229 @@
#include <stdbool.h>
-#define LIBBSDDIALOG_VERSION "0.0.1"
-
-/* Exit status */
-#define BSDDIALOG_ERROR -1
-#define BSDDIALOG_OK 0
-#define BSDDIALOG_YES BSDDIALOG_OK
-#define BSDDIALOG_CANCEL 1
-#define BSDDIALOG_NO BSDDIALOG_CANCEL
-#define BSDDIALOG_HELP 2
-#define BSDDIALOG_EXTRA 3
-#define BSDDIALOG_ITEM_HELP 4
-#define BSDDIALOG_TIMEOUT 5
-#define BSDDIALOG_ESC 6
-#define BSDDIALOG_GENERIC1 7
-#define BSDDIALOG_GENERIC2 8
-
-/* size and position */
-#define BSDDIALOG_FULLSCREEN -1
-#define BSDDIALOG_AUTOSIZE 0
-#define BSDDIALOG_CENTER -1
+#define LIBBSDDIALOG_VERSION "1.0"
+
+/* Return values */
+#define BSDDIALOG_ERROR -1
+#define BSDDIALOG_OK 0
+#define BSDDIALOG_YES BSDDIALOG_OK
+#define BSDDIALOG_CANCEL 1
+#define BSDDIALOG_NO BSDDIALOG_CANCEL
+#define BSDDIALOG_HELP 2
+#define BSDDIALOG_EXTRA 3
+#define BSDDIALOG_TIMEOUT 4
+#define BSDDIALOG_ESC 5
+#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
+#define BSDDIALOG_AUTOSIZE 0
+#define BSDDIALOG_CENTER -1
+
+/* Mixedgauge */
+#define BSDDIALOG_MG_SUCCEEDED -1
+#define BSDDIALOG_MG_FAILED -2
+#define BSDDIALOG_MG_PASSED -3
+#define BSDDIALOG_MG_COMPLETED -4
+#define BSDDIALOG_MG_CHECKED -5
+#define BSDDIALOG_MG_DONE -6
+#define BSDDIALOG_MG_SKIPPED -7
+#define BSDDIALOG_MG_INPROGRESS -8
+#define BSDDIALOG_MG_BLANK -9
+#define BSDDIALOG_MG_NA -10
+#define BSDDIALOG_MG_PENDING -11
+
+/* Form */
+#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 aspect_ratio;
unsigned int auto_minheight;
unsigned int auto_minwidth;
- char *bottomtitle;
+ unsigned int auto_topmargin;
+ unsigned int auto_downmargin;
+ const char *bottomtitle;
bool clear;
- char *f1_file;
- char *f1_message;
- int *get_height;
- int *get_width;
+ int *get_height;
+ int *get_width;
bool no_lines;
bool shadow;
unsigned int sleep;
- char *title;
- int y;
- int x;
+ const char *title;
+ int y;
+ int x;
+ struct {
+ bool enable_esc;
+ const char *f1_file;
+ const char *f1_message;
+ } key;
struct {
- bool colors;
+ unsigned int cols_per_row;
+ bool escape;
+ unsigned int tablen;
} text;
struct {
bool align_left;
- char *default_item;
bool no_desc;
bool no_name;
bool shortcut_buttons;
} menu;
struct {
- int securech;
- bool value_withcancel;
- bool value_withextra;
- bool value_withhelp;
+ 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;
- char *ok_label;
+ const char *ok_label;
bool with_extra;
- char *extra_label;
+ const char *extra_label;
bool without_cancel;
- char *cancel_label;
+ const char *cancel_label;
bool default_cancel;
bool with_help;
- char *help_label;
- char *exit_label;
- char *generic1_label;
- char *generic2_label;
- char *default_label;
+ const char *help_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
+ const char *default_label;
} button;
};
struct bsddialog_menuitem {
- char *prefix;
+ const char *prefix;
bool on;
unsigned int depth;
- char *name;
- char *desc;
- char *bottomdesc;
+ const char *name;
+ const char *desc;
+ 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 {
- char *label;
+ const char *label;
unsigned int ylabel;
unsigned int xlabel;
- char *init;
+ const char *init;
unsigned int yfield;
unsigned int xfield;
unsigned int fieldlen;
unsigned int maxvaluelen;
- char *value; /* allocated memory */
-#define BSDDIALOG_FIELDHIDDEN 1U
-#define BSDDIALOG_FIELDREADONLY 2U
+ char *value;
unsigned int flags;
- char *bottomdesc;
+ const char *bottomdesc;
};
int bsddialog_init(void);
+int bsddialog_init_notheme(void);
+bool bsddialog_inmode(void);
int bsddialog_end(void);
-int bsddialog_backtitle(struct bsddialog_conf *conf, char *backtitle);
+int bsddialog_backtitle(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);
-/* widgets */
+/* Dialogs */
int
-bsddialog_buildlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem);
+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, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem);
+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, char* text, int rows, int cols,
- unsigned int *yy, unsigned int *mm, unsigned int *dd);
+bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
int
-bsddialog_form(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items);
+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);
int
-bsddialog_gauge(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int perc);
+bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int perc, int fd, const char *sep, const char *end);
int
-bsddialog_infobox(struct bsddialog_conf *conf, char* text, int rows, int cols);
+bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols);
int
-bsddialog_menu(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem);
+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
-bsddialog_mixedgauge(struct bsddialog_conf *conf, char* text, int rows,
- int cols, unsigned int mainperc, unsigned int nminibars, char **minilabels,
- int *minipercs);
+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
-bsddialog_mixedlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int ngroups, struct bsddialog_menugroup *groups,
- int *focuslist, int *focusitem);
+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
-bsddialog_msgbox(struct bsddialog_conf *conf, char* text, int rows, int cols);
+bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols);
int
-bsddialog_pause(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int sec);
+bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *seconds);
int
-bsddialog_radiolist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem);
+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
-bsddialog_rangebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
- int min, int max, int *value);
+bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, int min, int max, int *value);
int
-bsddialog_textbox(struct bsddialog_conf *conf, char* file, int rows, int cols);
+bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
+ int cols);
int
-bsddialog_timebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int *hh, unsigned int *mm, unsigned int *ss);
+bsddialog_timebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss);
int
-bsddialog_yesno(struct bsddialog_conf *conf, char* text, int rows, int cols);
+bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols);
#endif
diff --git a/lib/bsddialog_progressview.h b/lib/bsddialog_progressview.h
new file mode 100644
index 000000000000..5203b798bb07
--- /dev/null
+++ b/lib/bsddialog_progressview.h
@@ -0,0 +1,60 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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
+ * 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 _LIBBSDDIALOG_PROGRESSVIEW_H_
+#define _LIBBSDDIALOG_PROGRESSVIEW_H_
+
+/*
+ * Undocumented API, DO NOT USE!
+ * Please consider this file private: it is used by bsdinstall/distextract,
+ * could be deleted or changed in the future.
+ */
+
+extern bool bsddialog_interruptprogview;
+extern bool bsddialog_abortprogview;
+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 int size;
+ long long int read;
+};
+
+struct bsddialog_progviewconf {
+ const char *fmtbottomstr;
+ unsigned int refresh; /* in seconds */
+ int (*callback)(struct bsddialog_fileminibar *minibar);
+};
+
+int
+bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct bsddialog_progviewconf *pvconf, unsigned int nminibar,
+ struct bsddialog_fileminibar *minibar);
+
+#endif \ No newline at end of file
diff --git a/lib/bsddialog_theme.h b/lib/bsddialog_theme.h
index d20985e66b18..2071896b61f0 100644
--- a/lib/bsddialog_theme.h
+++ b/lib/bsddialog_theme.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 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
@@ -28,15 +28,22 @@
#ifndef _LIBBSDDIALOG_THEME_H_
#define _LIBBSDDIALOG_THEME_H_
-/* f_ focus/active element */
+/* color flags */
+#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 {
int color;
- } terminal;
+ } screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -45,49 +52,51 @@ struct bsddialog_theme {
int lineraisecolor;
int linelowercolor;
int bottomtitlecolor;
+ int arrowcolor;
} dialog;
struct {
- unsigned int hmargin;
- } text;
- struct {
- int arrowcolor;
+ 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 space;
- int leftch;
- int rightch;
- 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_DEFAULT,
- BSDDIALOG_THEME_DIALOG,
+ BSDDIALOG_THEME_FLAT
};
enum bsddialog_color {
@@ -98,18 +107,18 @@ enum bsddialog_color {
BSDDIALOG_BLUE,
BSDDIALOG_MAGENTA,
BSDDIALOG_CYAN,
- BSDDIALOG_WHITE,
+ BSDDIALOG_WHITE
};
-#define BSDDIALOG_BOLD 1U
-#define BSDDIALOG_REVERSE 2U
-#define BSDDIALOG_UNDERLINE 4U
-
int
-bsddialog_color(enum bsddialog_color background,
- enum bsddialog_color foreground, unsigned int flags);
+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);
-#endif
+#endif \ No newline at end of file
diff --git a/lib/datebox.c b/lib/datebox.c
new file mode 100644
index 000000000000..9f26b2d08093
--- /dev/null
+++ b/lib/datebox.c
@@ -0,0 +1,715 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 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,
+ conf->ascii_lines ? '^' : ACS_UARROW, l);
+ mvwhline(win, h-1, w/2 - l/2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 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, conf->ascii_lines ? '^' : ACS_UARROW, 4);
+ mvwhline(win, h-1, 15, conf->ascii_lines ? 'v' : ACS_DARROW, 4);
+ mvwvline(win, 3, 0, conf->ascii_lines ? '<' : ACS_LARROW, 3);
+ mvwvline(win, 3, w-1, conf->ascii_lines ? '>' : ACS_RARROW, 3);
+ 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_redraw(struct dialog *d, WINDOW *yy_win, WINDOW *mm_win,
+ WINDOW *dd_win)
+{
+ int ycal, xcal;
+
+ if (d->built) {
+ 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)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ 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_redraw(&d, 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_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_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 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_redraw(&d, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_RESIZE:
+ if (calendar_redraw(&d, 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_redraw(struct dialog *d, struct dateitem *di)
+{
+ int y, x;
+
+ if (d->built) {
+ 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 (d->built)
+ 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_redraw(&d, 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 KEY_RIGHT:
+ case '\t': /* TAB */
+ 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_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 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 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_redraw(&d, di) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_RESIZE:
+ if (datebox_redraw(&d, 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/lib/formbox.c b/lib/formbox.c
index fd497174a7ce..5e80471c6974 100644
--- a/lib/formbox.c
+++ b/lib/formbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,483 +25,899 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
+#include <curses.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#ifdef PORTNCURSES
-#include <ncurses/form.h>
-#else
-#include <form.h>
-#endif
-
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-#define REDRAWFORM 14021986 /* magic number */
-#define ISFIELDHIDDEN(item) (item.flags & BSDDIALOG_FIELDHIDDEN)
-#define ISFIELDREADONLY(item) (item.flags & BSDDIALOG_FIELDREADONLY)
-
-/* "Form": inputbox - passwordbox - form - passwordform - mixedform */
+enum field_action {
+ MOVE_CURSOR_BEGIN,
+ MOVE_CURSOR_END,
+ MOVE_CURSOR_RIGHT,
+ MOVE_CURSOR_LEFT,
+ DEL_LETTER
+};
-extern struct bsddialog_theme t;
+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 */
+};
-/* util struct for private buffer and view options */
-struct myfield {
- int len;
- char *buf;
- int pos;
- int size;
- bool secure;
- int securech;
- char *bottomdesc;
+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 nkitems */
+ 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].maxvaluelen == 0)
+ RETURN_FMTERROR("item %u [0-%u] maxvaluelen = 0",
+ i, nitems);
+ if (items[i].fieldlen == 0)
+ RETURN_FMTERROR("item %u [0-%u] fieldlen = 0",
+ i, nitems);
+ }
+ 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->len == mf->size)
- 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->len-1; 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;
- mf->len += 1;
- mf->buf[mf->len] = '\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;
+
+ 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;
+ }
- for (i=mf->pos; i<mf->len; i++) {
- mf->buf[i] = mf->buf[i+1];
+ break;
}
- last = mf->len > 0 ? mf->len -1 : 0;
- mf->buf[last] = '\0';
- mf->len = last;
+ return (change);
}
-static void print_bottomdesc(struct myfield *mf)
+static bool insertch(struct privateitem *item, wchar_t wch, wchar_t securewch)
{
+ int i;
- move(LINES-1, 2);
- clrtoeol();
- if (mf->bottomdesc != NULL) {
- addstr(mf->bottomdesc);
- refresh();
+ 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* alloc_wstomb(wchar_t *wstr)
+{
+ 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);
+
+ wcstombs(mbstr, wstr, nbytes);
+
+ return (mbstr);
}
static int
-form_handler(struct bsddialog_conf *conf, WINDOW *widget, int y, int cols,
- struct buttons bs, WINDOW *formwin, FORM *form, FIELD **cfield, int nitems,
+return_values(struct bsddialog_conf *conf, struct privateform *f,
struct bsddialog_formitem *items)
{
- bool loop, buttupdate, informwin = true;
- int i, input, output;
- struct myfield *mf;
-
- curs_set(2);
- pos_form_cursor(form);
- loop = buttupdate = true;
- bs.curr = -1;
- form_driver(form, REQ_END_LINE);
- form_driver(form, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = mf->len;
- while(loop) {
- if (buttupdate) {
- draw_buttons(widget, y, cols, bs, !informwin);
- wrefresh(widget);
- buttupdate = false;
+ 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;
+
+ for (i = 0; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ break;
+
+ 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();
+ }
+ }
+
+ /* 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,
+ conf->ascii_lines ? '^' : ACS_UARROW, 5);
+
+ if (f->y + f->viewrows < f->h)
+ mvwhline(f->box, h-1, (w / 2) - 2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 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_redraw(struct dialog *d, struct privateform *f, bool focusinform)
+{
+ unsigned int i;
+
+ if (d->built) {
+ 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)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ 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;
}
- wrefresh(formwin);
- input = getch();
+ 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 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);
+
+ 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;
+ }
+
+ form.formheight = formheight;
+ if (form_redraw(&d, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
+
+ changeitem = switchfocus = false;
+ loop = true;
+ while (loop) {
+ doupdate();
+ if ((wchtype = get_wch(&input)) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- if (informwin)
+ if (focusinform && conf->button.always_active == false)
break;
+ retval = BUTTONVALUE(d.bs);
loop = false;
- output = bs.value[bs.curr];
- if (output == BSDDIALOG_HELP &&
- conf->form.value_withhelp == false)
- break;
- if (output == BSDDIALOG_EXTRA &&
- conf->form.value_withextra == false)
- break;
- if (output == BSDDIALOG_CANCEL &&
- conf->form.value_withcancel == false)
- break;
- if (output == BSDDIALOG_GENERIC1 ||
- output == BSDDIALOG_GENERIC2)
- break;
-
- /* BSDDIALOG_OK */
- form_driver(form, REQ_NEXT_FIELD);
- form_driver(form, REQ_PREV_FIELD);
- for (i=0; i<nitems; i++) {
- mf = GETMYFIELD(cfield[i]);
- items[i].value = strdup(mf->buf);
- if (items[i].value == NULL)
- RETURN_ERROR("Cannot allocate memory "
- "for form value");
- }
break;
case 27: /* Esc */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
break;
case '\t': /* TAB */
- if (informwin) {
- bs.curr = 0;
- informwin = false;
- curs_set(0);
+ if (focusinform) {
+ switchfocus = true;
} else {
- bs.curr++;
- informwin = bs.curr >= (int) bs.nbuttons ?
- true : false;
- if (informwin) {
- curs_set(2);
- 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(form, 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->len)
- break;
- mf->pos += 1;
- form_driver(form, 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_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(form, REQ_PREV_FIELD);
- form_driver(form, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = mf->len;
- 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_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(form, REQ_NEXT_FIELD);
- form_driver(form, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = mf->len;
- 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(form, REQ_DEL_PREV);
- mf = GETMYFIELD2(form);
- mf->pos -= 1;
- 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(form, REQ_DEL_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->len-1 >= mf->pos)
- 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->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No Break */
+ curs_set(0);
+ if (f1help_dialog(conf) != 0) {
+ retval = BSDDIALOG_ERROR;
+ loop = false;
+ }
+ if (form_redraw(&d, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- output = REDRAWFORM;
- loop = false;
+ if (form_redraw(&d, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- /*
- * user input, add unicode chars to "public" buffer
- */
- if (informwin) {
- mf = GETMYFIELD2(form);
- if (mf->secure)
- form_driver(form, mf->securech);
- else
- form_driver(form, input);
- insertch(mf, input);
- }
- else {
- for (i = 0; i < (int) bs.nbuttons; i++) {
- if (tolower(input) ==
- tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
- }
+ if (wchtype == KEY_CODE_YES)
+ break;
+ if (focusinform) {
+ if (item->fieldonebyte && wctob(input) == EOF)
+ break;
+ /*
+ * 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);
+ DRAWITEM_TRICK(&form, form.sel, focusinform);
+ switchfocus = false;
}
- }
-
- curs_set(0);
-
- return output;
-}
-
-static void
-form_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- char *text, int linelen, unsigned int *formheight, int nitems,
- struct buttons bs)
-{
- int textrow, menusize;
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- *w = VBORDERS;
- /* buttons size */
- *w += bs.nbuttons * bs.sizebutton;
- *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* line size */
- *w = MAX(*w, linelen + 3);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /*
- * avoid terminal overflow,
- * -1 fix false negative with big menu over the terminal and
- * autosize, for example "portconfig /usr/ports/www/apache24/".
- */
- *w = MIN(*w, widget_max_width(conf)-1);
- }
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = HBORDERS + 2 /* buttons */ + textrow;
- if (*formheight == 0) {
- *h += nitems + 2;
- *h = MIN(*h, widget_max_height(conf));
- menusize = MIN(nitems + 2, *h - (HBORDERS + 2 + textrow));
- menusize -=2;
- *formheight = menusize < 0 ? 0 : menusize;
+ if (changeitem) {
+ 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;
}
- else /* h autosize with a fixed formheight */
- *h = *h + *formheight + 2;
-
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
- }
- else {
- if (*formheight == 0)
- *formheight = MIN(rows-6-textrow, nitems);
- }
-}
-
-static int
-form_checksize(int rows, int cols, char *text, int formheight, int nitems,
- struct buttons bs)
-{
- int mincols, textrow, formrows;
-
- mincols = VBORDERS;
- /* buttons */
- mincols += bs.nbuttons * bs.sizebutton;
- mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* line, comment to permet some cols hidden */
- /* mincols = MAX(mincols, linelen); */
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "\
- "labels + forms");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
-
- if (nitems > 0 && formheight == 0)
- RETURN_ERROR("fields > 0 but formheight == 0, probably "\
- "terminal too small");
+ } /* end while(loop) */
- 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, char* text, int rows, int cols,
- unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items)
-{
- WINDOW *widget, *formwin, *textpad, *shadow;
- int i, output, color, y, x, h, w, htextpad;
- FIELD **cfield;
- FORM *form;
- struct buttons bs;
- struct myfield *myfields;
- unsigned long maxline;
-
- /* disable form scrolling like dialog */
- if (formheight < nitems)
- formheight = nitems;
-
- 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);
- set_field_buffer(cfield[i], 0, items[i].init);
-
- myfields[i].pos = strlen(items[i].init);
- myfields[i].len = strlen(items[i].init);
- myfields[i].size = items[i].maxvaluelen;
- myfields[i].buf = malloc(myfields[i].size);
- memset(myfields[i].buf, 0, myfields[i].size);
- strcpy(myfields[i].buf, items[i].init);
- 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);
- /* field_opts_off(field[i], O_BS_OVERLOAD); */
-
- if (ISFIELDHIDDEN(items[i])) {
- /* field_opts_off(field[i], O_PUBLIC); old hidden */
- myfields[i].secure = true;
- myfields[i].securech = ' ';
- if (conf->form.securech != '\0')
- myfields[i].securech = conf->form.securech;
- }
- else myfields[i].secure = false;
+ curs_set(0);
- 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;
- }
- set_field_fore(cfield[i], color);
- set_field_back(cfield[i], color);
+ if (return_values(conf, &form, items) == BSDDIALOG_ERROR)
+ return (BSDDIALOG_ERROR);
- maxline = MAX(maxline, items[i].xlabel + strlen(items[i].label));
- maxline = MAX(maxline, items[i].xfield + items[i].fieldlen);
- }
- cfield[i] = NULL;
+ if (focusitem != NULL)
+ *focusitem = form.sel;
- /* 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);
+ if (form.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
}
-
- get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- form_autosize(conf, rows, cols, &h, &w, text, maxline, &formheight,
- nitems, bs);
- if (form_checksize(h, w, text, formheight, nitems, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
- y + h - formheight, x + 1 + w - t.text.hmargin);
-
- 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, h-2, w, bs, formwin, form,
- cfield, nitems, items);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
- y + h - formheight, x + 1 + w - t.text.hmargin);
-
- draw_borders(conf, formwin, formheight+2, w-2, LOWERED);
- /* wrefresh(formwin); */
- } while (output == REDRAWFORM);
-
- unpost_form(form);
- free_form(form);
- for (i=0; i < (int)nitems; i++) {
- free_field(cfield[i]);
- free(myfields[i].buf);
+ for (i = 0; i < form.nitems; i++) {
+ free(form.pritems[i].privwbuf);
+ free(form.pritems[i].pubwbuf);
}
- free(cfield);
- free(myfields);
-
- delwin(formwin);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ delwin(form.pad);
+ delwin(form.box);
+ end_dialog(&d);
- return output;
+ return (retval);
}
diff --git a/lib/infobox.c b/lib/infobox.c
deleted file mode 100644
index 7752d7eec190..000000000000
--- a/lib/infobox.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021 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>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
-
-#include "bsddialog.h"
-#include "lib_util.h"
-#include "bsddialog_theme.h"
-
-/* "Info": infobox */
-
-#define MIN_HEIGHT 3
-
-extern struct bsddialog_theme t;
-
-static int
-infobox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- char *text)
-{
- int maxword, maxline, nlines;
-
- if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
- return BSDDIALOG_ERROR;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- /* text size */
- *w = maxline + VBORDERS + t.text.hmargin * 2;
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- *w = MIN(*w, widget_max_width(conf));
- }
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = MIN_HEIGHT - 1;
- if (maxword > 0)
- *h += MIN(nlines, (int)(*w / GET_ASPECT_RATIO(conf)));
- *h = MAX(*h, MIN_HEIGHT);
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
- }
-
- return 0;
-}
-
-static int infobox_checksize(int rows, int cols)
-{
-
- if (cols < HBORDERS + 1 + (int) t.text.hmargin * 2)
- RETURN_ERROR("Few cols, infobox needs at least width 3 + text "\
- "margins");
-
- if (rows < 3)
- RETURN_ERROR("Infobox needs at least height 3");
-
- return 0;
-}
-
-int
-bsddialog_infobox(struct bsddialog_conf *conf, char* text, int rows, int cols)
-{
- WINDOW *shadow, *widget, *textpad;
- int y, x, h, w, htextpad;
-
- 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_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, false) != 0)
- return BSDDIALOG_ERROR;
-
- pnoutrefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-2, x+w-t.text.hmargin);
-
- doupdate();
-
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
-
- return (BSDDIALOG_OK);
-}
-
diff --git a/lib/lib_util.c b/lib/lib_util.c
index b9bb29ba58cf..9cfdd6f1a075 100644
--- a/lib/lib_util.c
+++ b/lib/lib_util.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,91 +25,210 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
+#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <wctype.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-extern struct bsddialog_theme t;
+/*
+ * -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);
+ */
-/* Error buffer */
+/*
+ * -1- Error and diagnostic
+ */
+#define ERRBUFLEN 1024
-#define ERRBUFLEN 1024
static char errorbuffer[ERRBUFLEN];
const char *get_error_string(void)
{
- return errorbuffer;
+ return (errorbuffer);
}
-void set_error_string(char *str)
+void set_error_string(const char *str)
{
-
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
-/* cleaner */
-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;
- /* no check: y, x, h and w are checked by the builders */
- if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL)
- RETURN_ERROR("Cannot hide the widget");
- wbkgd(clear, t.terminal.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];
- return 0;
+ ws[0] = wch;
+ ws[1] = L'\0';
+ mvwaddwstr(w, y, x, ws);
}
-/* F1 help */
-int f1help(struct bsddialog_conf *conf)
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
{
- int output;
- struct bsddialog_conf hconf;
+ 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;
+ }
- //memcpy(&hconf, conf, sizeof(struct bsddialog_conf));
- 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.colors = conf->text.colors;
+ if (cols != NULL)
+ *cols = ncol;
+ if (has_multi_col != NULL)
+ *has_multi_col = multicol;
- output = BSDDIALOG_OK;
- if (conf->f1_message != NULL)
- output = bsddialog_msgbox(&hconf, conf->f1_message, 0, 0);
+ return (0);
+}
- if (output != BSDDIALOG_ERROR && conf->f1_file != NULL)
- output = bsddialog_textbox(&hconf, conf->f1_file, 0, 0);
+unsigned int strcols(const char *mbstring)
+{
+ 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;
+ }
- return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+ return (ncol);
}
-/* Buttons */
-void
-draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
- bool shortkey)
+/*
+ * -3- Buttons
+ */
+static int buttons_min_width(struct buttons *bs)
+{
+ unsigned int width;
+
+ width = bs->nbuttons * bs->sizebutton;
+ if (bs->nbuttons > 0)
+ width += (bs->nbuttons - 1) * t.button.minmargin;
+
+ return (width);
+}
+
+static void
+draw_button(WINDOW *window, int y, int x, int size, const char *text,
+ wchar_t first, bool selected, bool shortcut)
{
int i, color_arrows, color_shortkey, color_button;
@@ -124,358 +243,556 @@ draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
}
wattron(window, color_arrows);
- mvwaddch(window, y, x, t.button.leftch);
+ mvwaddch(window, y, x, t.button.leftdelim);
wattroff(window, color_arrows);
wattron(window, color_button);
- for(i = 1; i < size - 1; i++)
+ for (i = 1; i < size - 1; i++)
waddch(window, ' ');
wattroff(window, color_button);
wattron(window, color_arrows);
- mvwaddch(window, y, x + i, t.button.rightch);
+ 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 (shortkey) {
+ 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, int y, int cols, struct buttons bs, bool shortkey)
+void draw_buttons(struct dialog *d)
{
- int i, x, start_x;
+ int i, x, startx, y;
+ unsigned int newmargin, margin, wbuttons;
+
+ y = d->h - 2;
- start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.button.space;
- start_x = cols/2 - start_x/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.space);
- draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i],
- i == bs.curr, shortkey);
+ 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, char *yesoklabel,
- char *extralabel, char *nocancellabel, char *helplabel)
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *cancellabel)
{
int i;
-#define SIZEBUTTON 8
-#define DEFAULT_BUTTON_LABEL LABEL_ok_label
+#define SIZEBUTTON 8
+#define DEFAULT_BUTTON_LABEL OK_LABEL
#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
+ wchar_t first;
+
+ d->bs.nbuttons = 0;
+ d->bs.curr = 0;
+ d->bs.sizebutton = 0;
+ d->bs.shortcut = shortcut;
+
+ 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 (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 (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 (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;
+ }
- bs->nbuttons = 0;
- bs->curr = 0;
- bs->sizebutton = 0;
+ 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 (yesoklabel != NULL && conf->button.without_ok == false) {
- bs->label[0] = yesoklabel;
- bs->value[0] = BSDDIALOG_OK;
- 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 (extralabel != NULL && conf->button.with_extra) {
- bs->label[bs->nbuttons] = extralabel;
- bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
- 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 (nocancellabel != NULL && conf->button.without_cancel == false) {
- bs->label[bs->nbuttons] = nocancellabel;
- bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
- if (conf->button.default_cancel)
- bs->curr = bs->nbuttons;
- bs->nbuttons += 1;
+ 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;
}
- if (helplabel != NULL && conf->button.with_help) {
- bs->label[bs->nbuttons] = helplabel;
- bs->value[bs->nbuttons] = BSDDIALOG_HELP;
- bs->nbuttons += 1;
+ 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;
}
- 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.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 (conf->button.generic2_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic2_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
- 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;
}
- if (bs->nbuttons == 0) {
- bs->label[0] = DEFAULT_BUTTON_LABEL;
- bs->value[0] = DEFAULT_BUTTON_VALUE;
- bs->nbuttons = 1;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
+ d->bs.first[i] = first;
}
- 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.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;
}
}
- 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;
+ 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;
}
-/* Text */
-static bool is_ncurses_attr(char *text)
+bool shortcut_buttons(wint_t key, struct buttons *bs)
{
+ bool match;
+ unsigned int i;
+
+ match = false;
+ for (i = 0; i < bs->nbuttons; i++) {
+ if (towlower(key) == towlower(bs->first[i])) {
+ bs->curr = i;
+ match = true;
+ break;
+ }
+ }
- if (strnlen(text, 3) < 3)
- return false;
+ return (match);
+}
- if (text[0] != '\\' || text[1] != 'Z')
- return false;
+/*
+ * -4- (Auto) Sizing and (Auto) Position
+ */
+static int widget_max_height(struct bsddialog_conf *conf)
+{
+ int maxheight;
+
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
+
+ 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");
+ }
- return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true);
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
+
+ return (maxheight);
}
-static bool check_set_ncurses_attr(WINDOW *win, char *text)
+static int widget_max_width(struct bsddialog_conf *conf)
{
-
- if (is_ncurses_attr(text) == false)
- return false;
+ int maxwidth;
- if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) {
- wattron(win, bsddialog_color( text[2] - '0', COLOR_WHITE, 0));
- return true;
- }
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
- switch (text[2]) {
- case 'n':
- 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;
+ if (conf->x > 0) {
+ maxwidth -= conf->x;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow "
+ "- x <= 0");
}
- return true;
+ return (maxwidth);
}
-static void
-print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- int i, j, len, reallen;
+ bool att;
- if(strlen(str) == 0)
- return;
+ if (wcsnlen(wtext, 3) < 3)
+ return (false);
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
+ return (false);
- len = reallen = strlen(str);
- if (color) {
- i=0;
- while (i < len) {
- if (is_ncurses_attr(str+i))
- reallen -= 3;
- i++;
- }
- }
+ att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
- 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_ncurses_attr(win, str+i)) {
- i += 3;
- } else {
- mvwaddch(win, *y, j, str[i]);
- i++;
- reallen--;
- j++;
- *x = j;
- }
- }
- }
+ return (att);
}
-int
-get_text_properties(struct bsddialog_conf *conf, char *text, int *maxword,
- int *maxline, int *nlines)
+#define NL -1
+#define WS -2
+#define TB -3
+
+struct textproperties {
+ int nword;
+ int *words;
+ uint8_t *wletters;
+ int maxwordcols;
+ int maxline;
+ bool hasnewline;
+};
+
+static int
+text_properties(struct bsddialog_conf *conf, const char *text,
+ struct textproperties *tp)
{
- int i, buflen, wordlen, linelen;
+ int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
+ wchar_t *wtext;
+
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
+
+ maxwords = 1024;
+ if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
+ RETURN_ERROR("Cannot alloc memory for text autosize");
+
+ 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 (tp->nword + 1 >= maxwords) {
+ maxwords += 1024;
+ tp->words = realloc(tp->words, maxwords * sizeof(int));
+ if (tp->words == NULL)
+ RETURN_ERROR("Cannot realloc memory for text "
+ "autosize");
+ }
+ if (wcschr(L"\t\n ", wtext[i]) != NULL) {
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
- buflen = strlen(text) + 1;
- *maxword = 0;
- wordlen = 0;
- for (i=0; i < buflen; i++) {
- if (text[i] == '\t' || text[i] == '\n' || text[i] == ' ' || text[i] == '\0')
- if (wordlen != 0) {
- *maxword = MAX(*maxword, wordlen);
- wordlen = 0;
- continue;
+ if (wordcols != 0) {
+ /* line */
+ currlinecols += wordcols;
+ /* word */
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ wordcols = 0;
}
- if (conf->text.colors && is_ncurses_attr(text + i))
- i += 3;
- else
- wordlen++;
- }
-
- *maxline = linelen = 0;
- *nlines = 1;
- for (i=0; i < buflen; i++) {
- switch (text[i]) {
- case '\n':
- *nlines = *nlines + 1;
- case '\0':
- *maxline = MAX(*maxline, linelen);
- linelen = 0;
- break;
- default:
- if (conf->text.colors && is_ncurses_attr(text + i))
- i += 3;
- else
- linelen++;
+
+ 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++;
}
}
- if (*nlines == 1 && *maxline == 0)
- *nlines = 0;
+ /* 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(buf);
+ free(wtext);
- return 0;
+ return (0);
}
-int
-print_textpad(struct bsddialog_conf *conf, WINDOW *pad, int *rows, int cols,
- char *text)
+static int
+text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
+ int maxrows, int mincols, bool increasecols, int *h, int *w)
{
- char *string;
- int i, j, x, y;
- bool loop;
+ int i, j, x, y, z, l, line, maxwidth, tablen;
- if ((string = malloc(strlen(text) + 1)) == NULL)
- RETURN_ERROR("Cannot build (analyze) text");
+ maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
- i = j = x = y = 0;
- loop = true;
- while (loop) {
- string[j] = text[i];
-
- if (string[j] == '\0' || string[j] == '\n' ||
- string[j] == '\t' || string[j] == ' ') {
- if (j != 0) {
- string[j] = '\0';
- print_str(pad, rows, &y, &x, cols, string,
- conf->text.colors);
- }
- }
+ if (increasecols) {
+ mincols = MAX(mincols, tp->maxwordcols);
+ mincols = MAX(mincols,
+ (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
+ mincols = MIN(mincols, maxwidth);
+ }
- switch (text[i]) {
- case '\0':
- loop = false;
- break;
- case '\n':
- j = -1;
- x = 0;
- y++;
- break;
- case '\t':
- for (j=0; j<4 /*tablen*/; j++) {
+ while (true) {
+ x = 0;
+ y = 1;
+ line=0;
+ 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++;
- if (x >= cols) {
+ }
+ break;
+ case NL:
+ y++;
+ x = 0;
+ break;
+ case WS:
+ x++;
+ if (x >= mincols) {
x = 0;
y++;
}
+ 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;
+ }
+ }
}
- j = -1;
- break;
- case ' ':
- x++;
- if (x >= cols) {
- x = 0;
- y++;
- }
- j = -1;
+ line = MAX(line, x);
}
- if (y >= *rows) { /* check for whitespaces */
- *rows = y + 1;
- wresize(pad, *rows, cols);
- }
-
- j++;
- i++;
+ if (increasecols == false)
+ break;
+ if (mincols >= maxwidth)
+ break;
+ if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
+ break;
+ mincols++;
}
- free(string);
+ *h = (tp->nword == 0) ? 0 : y;
+ *w = MIN(mincols, line); /* wtext can be less than mincols */
- return 0;
+ return (0);
}
-/* autosize */
+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)
+{
+ bool changewtext;
+ int wbuttons, maxhtext;
+ struct textproperties tp;
+
+ wbuttons = 0;
+ 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) - BORDERS - TEXTHMARGINS;
+ changewtext = false;
+ } else { /* fixed */
+ startwtext = cols - BORDERS - TEXTHMARGINS;
+ changewtext = false;
+ }
+
+ if (startwtext <= 0 && changewtext)
+ startwtext = 1;
-/*
- * max y, that is from 0 to LINES - 1 - t.shadowrows,
- * could not be max height but avoids problems with checksize
- */
-int widget_max_height(struct bsddialog_conf *conf)
+ /* 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);
+
+ free(tp.words);
+ free(tp.wletters);
+
+ return (0);
+}
+
+static int
+widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
+ bool withbuttons)
{
- int maxheight;
+ int min;
+
+ /* dialog borders */
+ min = BORDERS;
+
+ /* text */
+ min += htext;
+
+ /* specific widget lines without text */
+ min += hnotext;
- if ((maxheight = conf->shadow ? LINES - 1 - t.shadow.h : LINES - 1) <= 0)
- RETURN_ERROR("Terminal too small, LINES - shadow <= 0");
+ /* buttons */
+ if (withbuttons)
+ min += HBUTTONS; /* buttons and their up-border */
- if (conf->y > 0)
- if ((maxheight -= conf->y) <=0)
- RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0");
+ /* conf.auto_minheight */
+ min = MAX(min, (int)conf->auto_minheight);
- return maxheight;
+ return (min);
}
-/*
- * max x, that is from 0 to COLS - 1 - t.shadowcols,
- * * could not be max height but avoids problems with checksize
- */
-int widget_max_width(struct bsddialog_conf *conf)
+static int
+widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
+ struct buttons *bs)
+
{
- int maxwidth;
+ int min, delimtitle, wbottomtitle, wtitle;
- if ((maxwidth = conf->shadow ? COLS - 1 - t.shadow.w : COLS - 1) <= 0)
- RETURN_ERROR("Terminal too small, COLS - shadow <= 0");
- if (conf->x > 0)
- if ((maxwidth -= conf->x) <=0)
- RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0");
+ min = 0;
- return maxwidth;
+ /* buttons */
+ if (bs->nbuttons > 0)
+ min += buttons_min_width(bs);
+
+ /* text */
+ if (wtext > 0)
+ min = MAX(min, wtext + TEXTHMARGINS);
+
+ /* specific widget min width */
+ min = MAX(min, minwidget);
+
+ /* title */
+ if (conf->title != NULL) {
+ delimtitle = t.dialog.delimtitle ? 2 : 0;
+ wtitle = strcols(conf->title);
+ min = MAX(min, wtitle + 2 + delimtitle);
+ }
+
+ /* bottom title */
+ if (conf->bottomtitle != NULL) {
+ wbottomtitle = strcols(conf->bottomtitle);
+ min = MAX(min, wbottomtitle + 4);
+ }
+
+ /* dialog borders */
+ min += BORDERS;
+ /* conf.auto_minwidth */
+ min = MAX(min, (int)conf->auto_minwidth);
+
+ return (min);
}
int
@@ -484,295 +801,555 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
int maxheight, maxwidth;
if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
- return BSDDIALOG_ERROR;
+ return (BSDDIALOG_ERROR);
if (rows == BSDDIALOG_FULLSCREEN)
*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)
- return BSDDIALOG_ERROR;
+ return (BSDDIALOG_ERROR);
if (cols == BSDDIALOG_FULLSCREEN)
*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;
+ return (0);
}
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)
+{
+ 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);
+}
- if (conf->y == BSDDIALOG_CENTER)
- *y = LINES/2 - h/2;
+int
+set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
+{
+ 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 >= LINES)
+ else if (conf->y >= SCREENLINES)
RETURN_ERROR("Begin Y under the terminal");
else
*y = conf->y;
- if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > LINES)
- RETURN_ERROR("The lower of the box under the terminal "\
+ 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 = COLS/2 - 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 >= COLS)
+ else if (conf->x >= SCREENCOLS)
RETURN_ERROR("Begin X over the right of the terminal");
else
*x = conf->x;
- if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > COLS)
- RETURN_ERROR("The right of the box over the terminal "\
+ if ((*x + w + wshadow) > SCREENCOLS)
+ RETURN_ERROR("The right of the box over the terminal "
"(begin X + width (+ shadow) > terminal cols)");
- return 0;
+ 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)
{
- int leftcolor, rightcolor;
- int ls, rs, ts, bs, tl, tr, bl, br;
- int ltee, rtee;
-
- 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;
-
- if (conf->no_lines == false) {
- if (conf->ascii_lines) {
- ls = rs = '|';
- ts = bs = '-';
- tl = tr = bl = br = ltee = rtee = '+';
- }
- leftcolor = elev == RAISED ?
- t.dialog.lineraisecolor : t.dialog.linelowercolor;
- rightcolor = elev == RAISED ?
- t.dialog.linelowercolor : t.dialog.lineraisecolor;
- wattron(win, leftcolor);
- wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
- wattroff(win, leftcolor);
+ 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);
- 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);
- wattroff(win, rightcolor);
+ if (d->conf->shadow) {
+ mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
+ wrefresh(clear);
}
+
+ delwin(clear);
+
+ return (0);
}
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
- enum elevation elev)
+int f1help_dialog(struct bsddialog_conf *conf)
{
- WINDOW *win;
+ int output;
+ struct bsddialog_conf hconf;
- if ((win = newwin(rows, cols, y, x)) == NULL) {
- set_error_string("Cannot build boxed window");
- return NULL;
+ 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;
+
+ if (conf->no_lines)
+ return;
+
+ if (conf->ascii_lines) {
+ ls = rs = '|';
+ ts = bs = '-';
+ tl = tr = bl = br = ltee = rtee = '+';
+ } 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;
}
- wbkgd(win, t.dialog.color);
+ getmaxyx(win, h, w);
+ leftcolor = elev == RAISED ?
+ t.dialog.lineraisecolor : t.dialog.linelowercolor;
+ rightcolor = elev == RAISED ?
+ t.dialog.linelowercolor : t.dialog.lineraisecolor;
+
+ wattron(win, leftcolor);
+ wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
+ wattroff(win, leftcolor);
+
+ wattron(win, rightcolor);
+ mvwaddch(win, 0, w-1, tr);
+ mvwvline(win, 1, w-1, rs, h-2);
+ mvwaddch(win, h-1, w-1, br);
+ mvwhline(win, h-1, 1, bs, w-2);
+ wattroff(win, rightcolor);
+}
- draw_borders(conf, win, rows, cols, elev);
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev)
+{
+ wclear(win);
+ wresize(win, h, w);
+ mvwin(win, y, x);
+ draw_borders(conf, win, elev);
+}
- return win;
+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);
}
/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
+ * -6- Dialog init/build, update/draw, destroy
*/
-static int
-draw_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow,
- WINDOW *widget, int h, int w, enum elevation elev,
- WINDOW *textpad, int *htextpad, char *text, bool buttons)
+void end_dialog(struct dialog *d)
{
- int ts, ltee, rtee;
- int colordelimtitle;
+ if (d->conf->sleep > 0)
+ sleep(d->conf->sleep);
- ts = conf->ascii_lines ? '-' : ACS_HLINE;
- ltee = conf->ascii_lines ? '+' : ACS_LTEE;
- rtee = conf->ascii_lines ? '+' : ACS_RTEE;
- colordelimtitle = elev == RAISED ?
- t.dialog.lineraisecolor : t.dialog.linelowercolor;
+ delwin(d->textpad);
+ delwin(d->widget);
+ if (d->conf->shadow)
+ delwin(d->shadow);
- if (shadow != NULL)
- wnoutrefresh(shadow);
+ if (d->conf->clear)
+ hide_dialog(d);
- // move / resize now or the caller?
- draw_borders(conf, widget, h, w, elev);
+ if (d->conf->get_height != NULL)
+ *d->conf->get_height = d->h;
+ if (d->conf->get_width != NULL)
+ *d->conf->get_width = d->w;
+}
- if (conf->title != NULL) {
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, colordelimtitle);
- mvwaddch(widget, 0, w/2 - strlen(conf->title)/2 - 1, rtee);
- wattroff(widget, colordelimtitle);
- }
- 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, colordelimtitle);
- waddch(widget, ltee);
- wattroff(widget, colordelimtitle);
- }
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
+{
+ 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);
}
- 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);
+ 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;
}
- //if (textpad == NULL && text != NULL) /* no pad, text null for textbox */
- // print_text(conf, widget, 1, 2, w-3, text);
+ return (true);
+}
+
+static void
+print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
+ bool color)
+{
+ int i, j, len, reallen, wc;
+ wchar_t ws[2];
+
+ ws[1] = L'\0';
- if (buttons && 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);
+ len = wcslen(str);
+ if (color) {
+ reallen = 0;
+ i=0;
+ while (i < len) {
+ if (is_wtext_attr(str+i) == false) {
+ reallen += wcwidth(str[i]);
+ i++;
+ } else {
+ i +=3 ;
+ }
+ }
+ } else
+ reallen = wcswidth(str, len);
- wattron(widget, t.dialog.linelowercolor);
- mvwaddch(widget, h-3, w-1, rtee);
- wattroff(widget, t.dialog.linelowercolor);
+ 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_wtext_attr(win, str+i)) {
+ i += 3;
+ } else if (j + wcwidth(str[i]) > cols) {
+ break;
+ } else {
+ /* inline mvwaddwch() for efficiency */
+ ws[0] = str[i];
+ mvwaddwstr(win, *y, j, ws);
+ wc = wcwidth(str[i]);;
+ reallen -= wc;
+ j += wc;
+ i++;
+ *x = j;
+ }
+ }
}
+}
- wnoutrefresh(widget);
+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;
- if (textpad == NULL)
- return 0; /* widget_init() ends */
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- if (text != NULL) /* programbox etc */
- if (print_textpad(conf, textpad, htextpad,
- w - HBORDERS - t.text.hmargin * 2, 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;
-/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
- */
-int
-update_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow,
- WINDOW *widget, int h, int w, enum elevation elev,
- WINDOW *textpad, int *htextpad, char *text, bool buttons)
-{
- int error;
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = wtext[i];
- /* nothing for now */
+ 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);
+ }
- error = draw_widget_withtextpad(conf, shadow, widget, h, w,
- elev, textpad, htextpad, text, buttons);
+ 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;
+ }
- return error;
+ if (y >= rows) {
+ rows = y + 1;
+ wresize(pad, rows, cols);
+ }
+
+ j++;
+ i++;
+ }
+
+ free(wtext);
+ free(string);
+
+ return (0);
}
-/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
- */
-int
-new_widget_withtextpad(struct bsddialog_conf *conf, WINDOW **shadow,
- WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
- WINDOW **textpad, int *htextpad, char *text, bool buttons)
+int draw_dialog(struct dialog *d)
{
- int error;
+ int wtitle, wbottomtitle, 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);
- }
+ ts = d->conf->ascii_lines ? '-' : ACS_HLINE;
+ ltee = d->conf->ascii_lines ? '+' : ACS_LTEE;
+ rtee = d->conf->ascii_lines ? '+' : ACS_RTEE;
- if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == 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) { /* widget_init() */
- error = draw_widget_withtextpad(conf, *shadow, *widget, h, w,
- elev, NULL, NULL, text, buttons);
- return error;
+ 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);
+ mvwaddch(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);
+ waddch(d->widget, ltee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
}
- if (text != NULL) { /* programbox etc */
- *htextpad = 1;
- *textpad = newpad(*htextpad, w - HBORDERS - t.text.hmargin * 2);
- if (*textpad == NULL) {
- delwin(*textpad);
- if (conf->shadow)
- delwin(*shadow);
- RETURN_ERROR("Cannot build the pad window for text");
+ if (d->bs.nbuttons > 0) {
+ if (d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwaddch(d->widget, d->h-3, 0, ltee);
+ mvwhline(d->widget, d->h-3, 1, ts, d->w-2);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+
+ wattron(d->widget, t.dialog.linelowercolor);
+ mvwaddch(d->widget, d->h-3, d->w-1, rtee);
+ wattroff(d->widget, t.dialog.linelowercolor);
}
- wbkgd(*textpad, t.dialog.color);
+ draw_buttons(d);
}
- error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev,
- *textpad, htextpad, text, buttons);
+ 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);
+ }
- return error;
-}
+ wnoutrefresh(d->widget);
-void
-end_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *window, int h, int w,
- WINDOW *textpad, WINDOW *shadow)
-{
- int y, x;
+ wclear(d->textpad);
+ /* `infobox "" 0 2` fails but text is empty and textpad remains 1 1 */
+ wresize(d->textpad, 1, d->w - BORDERS - TEXTHMARGINS);
- getbegyx(window, y, x); /* for clear, add y & x to args? */
+ if (print_textpad(d->conf, d->textpad, d->text) != 0)
+ return (BSDDIALOG_ERROR);
- if (conf->sleep > 0)
- sleep(conf->sleep);
+ d->built = true;
- if (textpad != NULL)
- delwin(textpad);
+ return (0);
+}
- delwin(window);
+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->shadow)
- delwin(shadow);
+ if ((d->widget = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW widget");
+ wbkgd(d->widget, t.dialog.color);
- if (conf->clear)
- hide_widget(y, x, h, w, shadow != NULL);
+ /* 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);
- if (conf->get_height != NULL)
- *conf->get_height = h;
- if (conf->get_width != NULL)
- *conf->get_width = w;
-}
+ return (0);
+} \ No newline at end of file
diff --git a/lib/lib_util.h b/lib/lib_util.h
index 2c552a36c6a9..1a502147c441 100644
--- a/lib/lib_util.h
+++ b/lib/lib_util.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 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
@@ -28,109 +28,136 @@
#ifndef _LIBBSDDIALOG_UTIL_H_
#define _LIBBSDDIALOG_UTIL_H_
-/*
- * Utils to implement widgets - Internal library API - Dafult values
- */
-
-#define HBORDERS 2
-#define VBORDERS 2
-
-/* ncurses has not a Ctrl key macro */
-#define KEY_CTRL(x) ((x) & 0x1f)
+#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"
-/* Set default aspect ratio to 9 */
-#define GET_ASPECT_RATIO(conf) (conf->aspect_ratio > 0 ? conf->aspect_ratio : 9)
+/* 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(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 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 DRAW_BUTTONS(d) do { \
+ draw_buttons(&d); \
+ wnoutrefresh(d.widget); \
} while (0)
-/* Buttons */
-#define LABEL_cancel_label "Cancel"
-#define LABEL_exit_label "EXIT"
-#define LABEL_extra_label "Extra"
-#define LABEL_help_label "Help"
-#define LABEL_ok_label "OK"
-#define BUTTONLABEL(l) (conf->button.l != NULL ? conf->button.l : LABEL_ ##l)
+/* internal types */
+enum elevation { RAISED, LOWERED };
-#define MAXBUTTONS 6 /* yes|ok + extra + no|cancel + help + 2 generics */
struct buttons {
unsigned int nbuttons;
- char *label[MAXBUTTONS];
+#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 */
};
-void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs, char *yesoklabel,
- char *extralabel, char *nocancellabel, char *helplabel);
+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;
+};
-void
-draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
- bool shortkey);
+/* error and diagnostic */
+const char *get_error_string(void);
+void set_error_string(const char *string);
+void set_fmt_error_string(const char *fmt, ...);
-void
-draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey);
+/* 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);
-/* help window with F1 key */
-int f1help(struct bsddialog_conf *conf);
+/* 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);
-/* cleaner */
-int hide_widget(int y, int x, int h, int w, bool withshadow);
+/* widget utils */
+int hide_dialog(struct dialog *d);
+int f1help_dialog(struct bsddialog_conf *conf);
-/* (auto) size and (auto) position */
-int
-get_text_properties(struct bsddialog_conf *conf, char *text, int *maxword,
- int *maxline, int *nlines);
+void
+draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev);
-int widget_max_height(struct bsddialog_conf *conf);
-int widget_max_width(struct bsddialog_conf *conf);
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev);
-int
-set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w);
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext);
+/* (auto) sizing and (auto) position */
int
-set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
+set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w);
-/* widget builders */
int
-print_textpad(struct bsddialog_conf *conf, WINDOW *pad, int *rows, int cols,
- char *text);
+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);
-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_widget_withtextpad(struct bsddialog_conf *conf, WINDOW **shadow,
- WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
- WINDOW **textpad, int *htextpad, char *text, bool buttons);
+/* dialog */
+void end_dialog(struct dialog *d);
+int draw_dialog(struct dialog *d);
int
-update_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow,
- WINDOW *widget, int h, int w, enum elevation elev, WINDOW *textpad,
- int *htextpad, char *text, bool buttons);
-
-void
-end_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *window, int h, int w,
- WINDOW *textpad, WINDOW *shadow);
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d);
#endif
diff --git a/lib/libbsddialog.c b/lib/libbsddialog.c
index a3cbe6bf9748..755a469b126c 100644
--- a/lib/libbsddialog.c
+++ b/lib/libbsddialog.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,123 +25,128 @@
* SUCH DAMAGE.
*/
-#include <stdlib.h>
+#include <curses.h>
#include <string.h>
-#include <unistd.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-/*
- * This file implements public functions not related to a specific dialog.
- * utils.h/c: private functions to implement the library.
- * theme.h/c: public API related to themes.
- * Dialogs implementation:
- * infobox.c infobox
- * messgebox.c msgbox - yesno
- * menubox.c buildlist - checklist - menu - mixedlist - radiolist
- * formbox.c inputbox - passwordbox - form - passwordform - mixedform
- * barbox.c gauge - mixedgauge - rangebox - pause
- * textbox.c textbox
- * timebox.c timebox - calendar
- */
+#define DEFAULT_COLS_PER_ROW 10 /* Default conf.text.columns_per_row */
-extern struct bsddialog_theme t;
+static bool in_bsddialog_mode = false;
-int bsddialog_init(void)
+int bsddialog_init_notheme(void)
{
- int i, j, c = 1, error = OK;
+ int i, j, c, error;
set_error_string("");
- if(initscr() == NULL)
- RETURN_ERROR("Cannot init ncurses (initscr)");
+ if (initscr() == NULL)
+ RETURN_ERROR("Cannot init curses (initscr)");
+ error = OK;
error += keypad(stdscr, TRUE);
nl();
error += cbreak();
error += noecho();
curs_set(0);
- if(error != OK) {
+ if (error != OK) {
bsddialog_end();
- RETURN_ERROR("Cannot init ncurses (keypad and cursor)");
+ RETURN_ERROR("Cannot init curses (keypad and cursor)");
}
+ in_bsddialog_mode = true;
+ c = 1;
error += start_color();
- for (i=0; i<8; i++)
- for(j=0; j<8; j++) {
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
error += init_pair(c, i, j);
c++;
+ }
}
- if(error != OK) {
- bsddialog_end();
- RETURN_ERROR("Cannot init ncurses (colors)");
- }
- if (bsddialog_set_default_theme(BSDDIALOG_THEME_DEFAULT) != 0) {
+ 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);
}
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_end(void)
{
-
if (endwin() != OK)
- RETURN_ERROR("Cannot end ncurses (endwin)");
+ RETURN_ERROR("Cannot end curses (endwin)");
+ in_bsddialog_mode = false;
- return (0);
+ return (BSDDIALOG_OK);
}
-int bsddialog_backtitle(struct bsddialog_conf *conf, char *backtitle)
+int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle)
{
+ CHECK_PTR(conf);
- mvaddstr(0, 1, backtitle);
+ move(0, 1);
+ clrtoeol();
+ addstr(CHECK_STR(backtitle));
if (conf->no_lines != true)
- mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE, COLS-2);
+ mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE,
+ SCREENCOLS - 2);
refresh();
- return (0);
+ return (BSDDIALOG_OK);
}
-const char *bsddialog_geterror(void)
+bool bsddialog_inmode(void)
{
+ return (in_bsddialog_mode);
+}
+const char *bsddialog_geterror(void)
+{
return (get_error_string());
}
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 (0);
+ return (BSDDIALOG_OK);
}
-int bsddialog_clearterminal(void)
+void bsddialog_refresh(void)
{
-
- if (clear() != OK)
- RETURN_ERROR("Cannot clear the terminal");
refresh();
-
- return (0);
}
+
+void bsddialog_clear(unsigned int y)
+{
+ move(y, 0);
+ clrtobot();
+ refresh();
+} \ No newline at end of file
diff --git a/lib/menubox.c b/lib/menubox.c
index 147fa66c8c27..b6213aa8f997 100644
--- a/lib/menubox.c
+++ b/lib/menubox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,30 +25,14 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <string.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <curses.h>
+#include <stdlib.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
-
-/* "Menu": checklist - menu - mixedlist - radiolist - buildlist */
-
-#define DEPTHSPACE 4
-#define MIN_HEIGHT VBORDERS + 6 /* 2 buttons 1 text 3 menu */
-
-extern struct bsddialog_theme t;
+#include "lib_util.h"
enum menumode {
- BUILDLISTMODE,
CHECKLISTMODE,
MENUMODE,
MIXEDLISTMODE,
@@ -56,1103 +40,710 @@ 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 {
+ 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;
+ wchar_t shortcut;
};
-static int checkradiolist(int nitems, struct bsddialog_menuitem *items)
-{
- int i, error;
-
- error = 0;
- for (i=0; i<nitems; i++) {
- if (error > 0)
- items[i].on = false;
+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;
+};
- if (items[i].on == true)
- error++;
+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 (error == 0 ? 0 : -1);
+ return (mode);
}
-static int checkmenu(int nitems, struct bsddialog_menuitem *items) // useful?
+static int
+build_privatemenu(struct bsddialog_conf *conf, struct privatemenu *m,
+ enum menumode mode, unsigned int ngroups,
+ struct bsddialog_menugroup *groups)
{
- int i, error;
+ bool onetrue;
+ int i, j, abs;
+ unsigned int maxsepstr, maxprefix, selectorlen, maxdepth;
+ unsigned int maxname, maxdesc;
+ struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
+
+ /* 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;
+ }
+
+ /* 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);
+
+ abs++;
+ }
+ }
- error = 0;
- for (i=0; i<nitems; i++) {
- if (items[i].on == true)
- error++;
+ /* 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;
+ }
- items[i].on = false;
+ 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;
- return (error == 0 ? 0 : -1);
+ 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
-getfirst(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
- int *rel)
+set_return_on(struct privatemenu *m, struct bsddialog_menugroup *groups)
{
- int i, a;
+ int i;
+ struct privateitem *pritem;
- *abs = *rel = *group = -1;
- a = 0;
- for (i=0; i<ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a += groups[i].nitems;
+ for(i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == SEPARATORMODE)
continue;
- }
- if (groups[i].nitems != 0) {
- *group = i;
- *abs = a;
- *rel = 0;
- break;
- }
+ pritem = &m->pritems[i];
+ groups[pritem->group].items[pritem->index].on = pritem->on;
}
}
-static void
-getfirst_with_default(struct bsddialog_conf *conf, int ngroups,
- struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
+static int getprev(struct privateitem *pritems, int abs)
{
- int i, j, a;
- struct bsddialog_menuitem *item;
+ int i;
- getfirst(ngroups, groups, abs, group, rel);
- if (*abs < 0)
- return;
-
- a = *abs;
-
- for (i=*group; i<ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a += groups[i].nitems;
+ for (i = abs - 1; i >= 0; i--) {
+ if (pritems[i].type == SEPARATORMODE)
continue;
- }
- for (j = 0; j < (int) groups[i].nitems; j++) {
- item = &groups[i].items[j];
- if (conf->menu.default_item != NULL && item->name != NULL) {
- if (strcmp(item->name, conf->menu.default_item) == 0) {
- *abs = a;
- *group = i;
- *rel = j;
- return;
- }
- }
- a++;
- }
+ return (i);
}
+
+ return (abs);
}
-static void
-getlast(int totnitems, int ngroups, struct bsddialog_menugroup *groups,
- int *abs, int *group, int *rel)
+static int getnext(int npritems, struct privateitem *pritems, int abs)
{
- int i, a;
+ int i;
- a = totnitems - 1;
- for (i = ngroups-1; i>=0; i--) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a -= groups[i].nitems;
+ for (i = abs + 1; i < npritems; i++) {
+ if (pritems[i].type == SEPARATORMODE)
continue;
- }
- if (groups[i].nitems != 0) {
- *group = i;
- *abs = a;
- *rel = groups[i].nitems - 1;
- break;
- }
+ return (i);
}
+
+ return (abs);
}
-static void
-getnext(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
- int *rel)
+static int
+getfirst_with_default(int npritems, struct privateitem *pritems, int ngroups,
+ struct bsddialog_menugroup *groups, int *focusgroup, int *focusitem)
{
- int i, a;
-
- if (*abs < 0 || *group < 0 || *rel < 0)
- return;
-
- if (*rel + 1 < (int) groups[*group].nitems) {
- *rel = *rel + 1;
- *abs = *abs + 1;
- return;
+ int i, abs;
+
+ if ((abs = getnext(npritems, pritems, -1)) < 0)
+ return (abs);
+
+ if (focusgroup == NULL || focusitem == NULL)
+ return (abs);
+ if (*focusgroup < 0 || *focusgroup >= ngroups)
+ return (abs);
+ if (groups[*focusgroup].type == BSDDIALOG_SEPARATOR)
+ return (abs);
+ if (*focusitem < 0 || *focusitem >= (int)groups[*focusgroup].nitems)
+ return (abs);
+
+ for (i = abs; i < npritems; i++) {
+ if (pritems[i].group == *focusgroup &&
+ pritems[i].index == *focusitem)
+ return (i);
}
- if (*group + 1 > ngroups)
- return;
-
- a = *abs;
- for (i = *group + 1; i < ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a += groups[i].nitems;
- continue;
- }
- if (groups[i].nitems != 0) {
- *group = i;
- *abs = a + 1;
- *rel = 0;
- break;
- }
- }
+ return (abs);
}
-static void
-getfastnext(int menurows, int ngroups, struct bsddialog_menugroup *groups,
- int *abs, int *group, int *rel)
+static int
+getfastnext(int menurows, int npritems, struct privateitem *pritems, int abs)
{
int a, start, i;
- start = *abs;
+ start = abs;
i = menurows;
do {
- a = *abs;
- getnext(ngroups, groups, abs, group, rel);
+ a = abs;
+ abs = getnext(npritems, pritems, abs);
i--;
- } while (*abs != a && *abs < start + menurows && i > 0);
-}
-
-static void
-getprev(struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
-{
- int i, a;
+ } while (abs != a && abs < start + menurows && i > 0);
- if (*abs < 0 || *group < 0 || *rel < 0)
- return;
-
- if (*rel > 0) {
- *rel = *rel - 1;
- *abs = *abs - 1;
- return;
- }
-
- if (*group - 1 < 0)
- return;
-
- a = *abs;
- for (i = *group - 1; i >= 0; i--) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a -= (int) groups[i].nitems;
- continue;
- }
- if (groups[i].nitems != 0) {
- *group = i;
- *abs = a - 1;
- *rel = (int) groups[i].nitems - 1;
- break;
- }
- }
+ return (abs);
}
-static void
-getfastprev(int menurows, struct bsddialog_menugroup *groups, int *abs,
- int *group, int *rel)
+static int
+getfastprev(int menurows, struct privateitem *pritems, int abs)
{
int a, start, i;
- start = *abs;
+ start = abs;
i = menurows;
do {
- a = *abs;
- getprev(groups, abs, group, rel);
+ a = abs;
+ abs = getprev(pritems, abs);
i--;
- } while (*abs != a && *abs > start - menurows && i > 0);
+ } while (abs != a && abs > start - menurows && i > 0);
+
+ return (abs);
}
-static bool
-getnextshortcut(struct bsddialog_conf *conf, enum menumode mode, int ngroups,
- struct bsddialog_menugroup *groups, int *abs, int *group, int *rel,
- int key)
+static int
+getnextshortcut(int npritems, struct privateitem *pritems, int abs, wint_t key)
{
- int i, j, a, ch, ng, nr, na;
- bool mainloop;
+ int i, next;
- if (*abs < 0 || ngroups < 0 || *rel < 0 || mode == BUILDLISTMODE)
- return false;
-
- na = a = -1;
- mainloop = true;
- for (i = 0; i < ngroups && mainloop; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- a += groups[i].nitems;
+ next = -1;
+ for (i = 0; i < npritems; i++) {
+ if (pritems[i].type == SEPARATORMODE)
continue;
+ if (pritems[i].shortcut == (wchar_t)key) {
+ if (i > abs)
+ return (i);
+ if (i < abs && next == -1)
+ next = i;
}
- for (j = 0; j < (int)groups[i].nitems; j++) {
- a++;
- if (a == *abs)
- continue;
-
- if (conf->menu.no_name)
- ch = groups[i].items[j].desc[0];
- else
- ch = groups[i].items[j].name[0];
-
- if (ch == key) {
- if (a < *abs && na == -1) {
- na = a;
- ng = i;
- nr = j;
- }
- if (a > *abs) {
- na = a;
- ng = i;
- nr = j;
- mainloop = false;
- break;
- }
- }
- }
- }
-
- if (na != -1) {
- *abs = na;
- *group = ng;
- *rel = nr;
- return (true);
}
- return (false);
+ 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)
{
+ int i, linech, realw, labellen;
+ const char *desc, *name;
- 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;
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type != SEPARATORMODE)
+ continue;
+ if (conf->no_lines == false) {
+ wattron(m->pad, t.menu.desccolor);
+ linech = conf->ascii_lines ? '-' : ACS_HLINE;
+ mvwhline(m->pad, i, 0, linech, m->line);
+ wattroff(m->pad, t.menu.desccolor);
+ }
+ 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);
}
-
- return mode;
}
static void
-drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
- struct bsddialog_menuitem item, enum menumode mode, struct lineposition pos,
- bool curr)
+drawitem(struct bsddialog_conf *conf, struct privatemenu *m, int y, bool focus)
{
- int colordesc, colorname, colorshortcut, linech;
- char *shortcut;
+ int colordesc, colorname, colorshortcut;
+ struct privateitem *pritem;
- if (mode == SEPARATORMODE) {
- if (conf->no_lines == false) {
- wattron(pad, t.menu.desccolor);
- linech = conf->ascii_lines ? '-' : ACS_HLINE;
- mvwhline(pad, y, 0, linech, pos.line);
- wattroff(pad, t.menu.desccolor);
- }
- wmove(pad, y, pos.line/2 - (strlen(item.name)+strlen(item.desc))/2);
- wattron(pad, t.menu.namesepcolor);
- waddstr(pad, item.name);
- wattroff(pad, t.menu.namesepcolor);
- if (strlen(item.name) > 0 && strlen(item.desc) > 0)
- waddch(pad, ' ');
- wattron(pad, t.menu.descsepcolor);
- waddstr(pad, item.desc);
- wattroff(pad, t.menu.descsepcolor);
- return;
- }
+ 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, t.menu.selectorcolor);
- if (mode == CHECKLISTMODE)
- wprintw(pad, "[%c]", item.on ? 'X' : ' ');
- if (mode == RADIOLISTMODE)
- wprintw(pad, "(%c)", item.on ? '*' : ' ');
- wattroff(pad, 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(m->pad, "[%c]", pritem->on ? 'X' : ' ');
+ if (pritem->type == RADIOLISTMODE)
+ wprintw(m->pad, "(%c)", pritem->on ? '*' : ' ');
+ wattroff(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
/* name */
- colorname = curr ? t.menu.f_namecolor : t.menu.namecolor;
- if (mode != BUILDLISTMODE && conf->menu.no_name == false) {
- wattron(pad, colorname);
- mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.name);
- wattroff(pad, colorname);
+ colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
+ if (conf->menu.no_name == false) {
+ wattron(m->pad, colorname);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth, pritem->name);
+ wattroff(m->pad, colorname);
}
/* description */
- if (mode == BUILDLISTMODE) {
- if (curr == false)
- colordesc = item.on ? t.menu.namecolor : t.menu.desccolor;
- else
- colordesc = t.menu.f_namecolor;
- }
- else {
- if (conf->menu.no_name)
- colordesc = curr ? t.menu.f_namecolor : t.menu.namecolor;
- else
- colordesc = curr ? t.menu.f_desccolor : t.menu.desccolor;
- }
- if (mode == BUILDLISTMODE || conf->menu.no_desc == false) {
- wattron(pad, colordesc);
- if (conf->menu.no_name)
- mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.desc);
- else
- mvwaddstr(pad, y, pos.xdesc, item.desc);
- wattroff(pad, colordesc);
- }
-
- /* shortcut */
- if (mode != BUILDLISTMODE && conf->menu.shortcut_buttons == false) {
- colorshortcut = curr ? t.menu.f_shortcutcolor : t.menu.shortcutcolor;
- wattron(pad, colorshortcut);
+ if (conf->menu.no_name)
+ colordesc = focus ? t.menu.f_namecolor : t.menu.namecolor;
+ else
+ colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
+ if (conf->menu.no_desc == false) {
+ wattron(m->pad, colordesc);
if (conf->menu.no_name)
- shortcut = item.desc;
+ mvwaddstr(m->pad, y, m->xname + pritem->depth,
+ pritem->desc);
else
- shortcut = item.name;
- wmove(pad, y, pos.xname + item.depth * DEPTHSPACE);
- if (shortcut != NULL && shortcut[0] != '\0')
- waddch(pad, shortcut[0]);
- wattroff(pad, colorshortcut);
-}
-
- /* bottom description */
- move(LINES-1, 2);
- clrtoeol();
- if (item.bottomdesc != NULL) {
- addstr(item.bottomdesc);
- refresh();
+ mvwaddstr(m->pad, y, m->xdesc, pritem->desc);
+ wattroff(m->pad, colordesc);
}
-}
-static void
-menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- char *text, int linelen, unsigned int *menurows, int nitems,
- struct buttons bs)
-{
- int textrow, menusize;
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- *w = VBORDERS;
- /* buttons size */
- *w += bs.nbuttons * bs.sizebutton;
- *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* line size */
- *w = MAX(*w, linelen + 6);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /*
- * avoid terminal overflow,
- * -1 fix false negative with big menu over the terminal and
- * autosize, for example "portconfig /usr/ports/www/apache24/".
- */
- *w = MIN(*w, widget_max_width(conf)-1);
+ /* shortcut */
+ if (conf->menu.shortcut_buttons == false) {
+ colorshortcut = focus ?
+ t.menu.f_shortcutcolor : t.menu.shortcutcolor;
+ wattron(m->pad, colorshortcut);
+ mvwaddwch(m->pad, y, m->xname + pritem->depth, pritem->shortcut);
+ wattroff(m->pad, colorshortcut);
}
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = HBORDERS + 2 /* buttons */ + textrow;
-
- if (*menurows == 0) {
- *h += nitems + 2;
- *h = MIN(*h, widget_max_height(conf));
- menusize = MIN(nitems + 2, *h - (HBORDERS + 2 + textrow));
- menusize -=2;
- *menurows = menusize < 0 ? 0 : menusize;
+ /* bottom description */
+ if (m->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (focus) {
+ attron(t.menu.bottomdesccolor);
+ addstr(pritem->bottomdesc);
+ attroff(t.menu.bottomdesccolor);
+ refresh();
}
- else /* h autosize with a fixed menurows */
- *h = *h + *menurows + 2;
-
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
- /* avoid menurows overflow */
- /* manual: with rows=autosize menurows!=0 is maxmenurows */
- *menurows = MIN(*h - 6 - textrow, (int)*menurows);
- }
- else {
- if (*menurows == 0)
- *menurows = MIN(rows-6-textrow, nitems);
}
}
-static int
-menu_checksize(int rows, int cols, char *text, int menurows, int nitems,
- struct buttons bs)
+static void update_menubox(struct bsddialog_conf *conf, struct privatemenu *m)
{
- int mincols, textrow, menusize;
+ int h, w;
- mincols = VBORDERS;
- /* buttons */
- mincols += bs.nbuttons * bs.sizebutton;
- mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* line, comment to permet some cols hidden */
- /* mincols = MAX(mincols, linelen); */
+ draw_borders(conf, m->box, LOWERED);
+ getmaxyx(m->box, h, w);
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "\
- "name+descripion of the items");
+ if (m->nitems > (int)m->menurows) {
+ wattron(m->box, t.dialog.arrowcolor);
+ if (m->ypad > 0)
+ mvwhline(m->box, 0, 2,
+ conf->ascii_lines ? '^' : ACS_UARROW, 3);
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+ if ((m->ypad + (int)m->menurows) < m->nitems)
+ mvwhline(m->box, h-1, 2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 3);
- if (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, probably terminal "\
- "too small");
-
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this menus");
-
- return 0;
+ mvwprintw(m->box, h-1, w-6, "%3d%%",
+ 100 * (m->ypad + m->menurows) / m->nitems);
+ wattroff(m->box, t.dialog.arrowcolor);
+ }
}
-/* 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 menu_size_position(struct dialog *d, struct privatemenu *m)
{
-
- draw_borders(conf, menuwin, h, w, LOWERED);
-
- if (totnitems > (int) menurows) {
- wattron(menuwin, t.menu.arrowcolor);
-
- if (ymenupad > 0)
- mvwprintw(menuwin, 0, 2, "^^^");
-
- if ((int) (ymenupad + menurows) < totnitems)
- mvwprintw(menuwin, h-1, 2, "vvv");
-
- wattroff(menuwin, t.menu.arrowcolor);
-
- mvwprintw(menuwin, h-1, w-10, "%3d%%",
- 100 * (ymenupad + menurows) / totnitems);
- }
+ int htext, hmenu;
+
+ 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 */
+ /*
+ * algo 1: notext = 1 (grows vertically).
+ * algo 2: notext = hmenu (grows horizontally, better for little term).
+ */
+ 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;
+
+ /*
+ * 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);
+
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
}
-static int
-do_mixedlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, enum menumode mode, int ngroups,
- struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
+static int mixedlist_redraw(struct dialog *d, struct privatemenu *m)
{
- WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
- int i, j, y, x, h, w, htextpad, output, input;
- int ymenupad, ys, ye, xs, xe, abs, g, rel, totnitems;
- bool loop, automenurows, shortcut_buttons;
- struct buttons bs;
- struct bsddialog_menuitem *item;
- enum menumode currmode;
- struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- shortcut_buttons = conf->menu.shortcut_buttons;
-
- automenurows = menurows == BSDDIALOG_AUTOSIZE ? true : false;
-
- totnitems = 0;
- for (i=0; i < ngroups; i++) {
- currmode = getmode(mode, groups[i]);
- if (currmode == RADIOLISTMODE)
- checkradiolist(groups[i].nitems, groups[i].items);
-
- if (currmode == MENUMODE)
- checkmenu(groups[i].nitems, groups[i].items);
-
- if (currmode == RADIOLISTMODE || currmode == CHECKLISTMODE)
- pos.selectorlen = 3;
-
- for (j=0; j < (int) groups[i].nitems; j++) {
- totnitems++;
- item = &groups[i].items[j];
-
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- pos.maxsepstr = MAX(pos.maxsepstr,
- strlen(item->name) + strlen(item->desc));
- continue;
- }
-
- 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 *= DEPTHSPACE;
-
- 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, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
- totnitems, bs);
- 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 (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
- y + h - menurows, x + 1 + w - t.text.hmargin);
-
- 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);
-
- ymenupad = 0;
- for (i=0; i<ngroups; i++) {
- currmode = getmode(mode, groups[i]);
- for (j=0; j < (int) groups[i].nitems; j++) {
- item = &groups[i].items[j];
- drawitem(conf, menupad, ymenupad, *item, currmode, pos,
- false);
- ymenupad++;
- }
- }
- getfirst_with_default(conf, ngroups, groups, &abs, &g, &rel);
- currmode = getmode(mode, groups[g]);
- item = &groups[g].items[rel];
- drawitem(conf, menupad, abs, *item, currmode, pos, 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;
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
- else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
+ m->menurows = m->apimenurows;
+ if (menu_size_position(d, m) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2/*bmenu*/ + m->menurows + HBUTTONS);
+
+ /* selected item in view*/
+ if (m->ypad > m->sel && m->ypad > 0)
+ m->ypad = m->sel;
+ if ((int)(m->ypad + m->menurows) <= m->sel)
+ m->ypad = m->sel - m->menurows + 1;
+ /* lower pad after a terminal expansion */
+ if (m->ypad > 0 && (m->nitems - m->ypad) < (int)m->menurows)
+ m->ypad = m->nitems - m->menurows;
+
+ update_box(d->conf, m->box, d->y + d->h - 5 - m->menurows, d->x + 2,
+ m->menurows+2, d->w-4, LOWERED);
+ update_menubox(d->conf, m);
+ wnoutrefresh(m->box);
+
+ m->ys = d->y + d->h - 5 - m->menurows + 1;
+ m->ye = d->y + d->h - 5 ;
+ if (d->conf->menu.align_left || (int)m->line > d->w - 6) {
+ m->xs = d->x + 3;
+ m->xe = m->xs + d->w - 7;
+ } else { /* center */
+ m->xs = d->x + 3 + (d->w-6)/2 - m->line/2;
+ m->xe = m->xs + d->w - 5;
}
+ drawseparators(d->conf, m); /* uses xe - xs */
+ pnoutrefresh(m->pad, m->ypad, 0, m->ys, m->xs, m->ye, m->xe);
- ymenupad = 0; /* now ymenupad is pminrow for prefresh() */
- 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);
-
- draw_buttons(widget, h-2, w, bs, shortcut_buttons);
- wrefresh(widget);
+ return (0);
+}
+static int
+do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
+ unsigned int menurows, enum menumode mode, unsigned int ngroups,
+ struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
+{
+ bool loop, changeitem;
+ int i, next, retval;
+ wint_t input;
+ struct privatemenu m;
+ struct dialog d;
+
+ 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 (build_privatemenu(conf, &m, mode, ngroups, groups) != 0)
+ return (BSDDIALOG_ERROR);
+
+ 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);
+
+ 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 (m.sel >= 0)
+ drawitem(d.conf, &m, m.sel, true);
+ m.ypad = 0;
+ m.apimenurows = menurows;
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
+
+ changeitem = false;
loop = true;
- while(loop) {
- input = getch();
+ while (loop) {
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
- if (currmode == MENUMODE)
- item->on = true;
+ 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 */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (conf->key.enable_esc) {
+ 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, h-2, w, bs, shortcut_buttons);
- 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, h-2, w, bs, shortcut_buttons);
- wrefresh(widget);
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, h-2, w, bs, shortcut_buttons);
- wrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
- case KEY_CTRL('E'): /* add conf->menu.extrahelpkey ? */
case KEY_F(1):
- if (conf->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No break! the terminal size can change */
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- menurows = automenurows ? 0 : menurows;
- menu_autosize(conf, rows, cols, &h, &w, text, pos.line,
- &menurows, totnitems, bs);
- 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;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- draw_buttons(widget, h-2, w, bs, shortcut_buttons);
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
- y + h - menurows, x + 1 + w - t.text.hmargin);
-
- 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;
- }
-
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
-
- refresh();
-
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
break;
}
- if (abs < 0)
+ if (m.sel < 0)
continue;
switch(input) {
case KEY_HOME:
+ next = getnext(m.nitems, m.pritems, -1);
+ changeitem = next != m.sel;
+ break;
case KEY_UP:
+ next = getprev(m.pritems, m.sel);
+ changeitem = next != m.sel;
+ break;
case KEY_PPAGE:
- if (abs == 0) /* useless, just to save cpu refresh */
- break;
- drawitem(conf, menupad, abs, *item, currmode, pos, false);
- if (input == KEY_HOME)
- getfirst(ngroups, groups, &abs, &g, &rel);
- else if (input == KEY_UP)
- getprev(groups, &abs, &g, &rel);
- else /* input == KEY_PPAGE*/
- getfastprev(menurows, groups, &abs, &g, &rel);
- item = &groups[g].items[rel];
- currmode= getmode(mode, groups[g]);
- drawitem(conf, menupad, abs, *item, currmode, pos, true);
- if (ymenupad > abs && ymenupad > 0)
- ymenupad = abs;
- update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
- menurows, ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ next = getfastprev(m.menurows, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_END:
+ next = getprev(m.pritems, m.nitems);
+ changeitem = next != m.sel;
+ break;
case KEY_DOWN:
+ next = getnext(m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
+ break;
case KEY_NPAGE:
- if (abs == totnitems -1)
- break; /* useless, just to save cpu refresh */
- drawitem(conf, menupad, abs, *item, currmode, pos, false);
- if (input == KEY_END)
- getlast(totnitems, ngroups, groups, &abs, &g, &rel);
- else if (input == KEY_DOWN)
- getnext(ngroups, groups, &abs, &g, &rel);
- else /* input == KEY_NPAGE*/
- getfastnext(menurows, ngroups, groups, &abs, &g, &rel);
- item = &groups[g].items[rel];
- currmode= getmode(mode, groups[g]);
- drawitem(conf, menupad, abs, *item, currmode, pos, true);
- 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);
+ next = getfastnext(m.menurows, m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case ' ': /* Space */
- if (currmode == MENUMODE)
- break;
- else if (currmode == CHECKLISTMODE)
- item->on = !item->on;
- else { /* RADIOLISTMODE */
- for (i=0; i < (int) groups[g].nitems; i++)
- if (groups[g].items[i].on == true && i != rel) {
- groups[g].items[i].on = false;
- drawitem(conf, menupad,
- abs - rel + i, groups[g].items[i],
- currmode, pos, false);
+ 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 != m.sel && m.pritems[i].on) {
+ m.pritems[i].on = false;
+ drawitem(conf, &m, i, false);
}
- item->on = !item->on;
+ }
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
}
- drawitem(conf, menupad, abs, *item, currmode, pos, 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_buttons) {
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- if (currmode == MENUMODE)
- item->on = true;
- loop = false;
- }
+ 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;
}
- drawitem(conf, menupad, abs, *item, currmode, pos, false);
- getnextshortcut(conf, currmode, ngroups, groups, &abs,
- &g, &rel, input);
- item = &groups[g].items[rel];
- currmode = getmode(mode, groups[g]);
- drawitem(conf, menupad, abs, *item, currmode, pos, 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);
+ /* shourtcut items */
+ next = getnextshortcut(m.nitems, m.pritems, m.sel,
+ input);
+ 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) */
+
+ set_return_on(&m, groups);
if (focuslist != NULL)
- *focuslist = g;
+ *focuslist = m.sel < 0 ? -1 : m.pritems[m.sel].group;
if (focusitem !=NULL)
- *focusitem = rel;
+ *focusitem = m.sel < 0 ? -1 : m.pritems[m.sel].index;
- delwin(menupad);
- delwin(menuwin);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ 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
- */
-
-int bsddialog_mixedlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int ngroups, struct bsddialog_menugroup *groups,
- int *focuslist, int *focusitem)
+/* API */
+int
+bsddialog_mixedlist(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int menurows, unsigned int ngroups,
+ struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
{
- 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
-bsddialog_checklist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem)
+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;
+ 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,
- 1, &group, NULL, focusitem);
+ 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
-bsddialog_menu(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem)
+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;
+ 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,
- &group, NULL, focusitem);
+ 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
-bsddialog_radiolist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem)
+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;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_RADIOLIST /* unused */, nitems, items};
-
- output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
- 1, &group, NULL, focusitem);
-
- return output;
-}
-
-/* todo */
-static int buildlist_autosize(int rows, int cols)
-{
-
- if (cols == BSDDIALOG_AUTOSIZE)
- RETURN_ERROR("Unimplemented cols autosize for buildlist");
-
- if (rows == BSDDIALOG_AUTOSIZE)
- RETURN_ERROR("Unimplemented rows autosize for buildlist");
-
- return 0;
-}
-
-/* to improve */
-static int
-buildlist_checksize(int rows, int cols, char *text, int menurows, int nitems,
- struct buttons bs)
-{
- int mincols, textrow, menusize;
-
- mincols = VBORDERS;
- /* buttons */
- mincols += bs.nbuttons * bs.sizebutton;
- mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* line, comment to permet some cols hidden */
- /* 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 (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, probably terminal "\
- "too small");
-
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this menus");
-
- return 0;
-}
-
-int
-bsddialog_buildlist(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
- int *focusitem)
-{
- WINDOW *widget, *textpad, *leftwin, *leftpad, *rightwin, *rightpad, *shadow;
- int output, i, x, y, h, w, htextpad, input;
- bool loop, buttupdate, padsupdate, startleft;
- int nlefts, nrights, leftwinx, rightwinx, winsy, padscols, curr;
- enum side {LEFT, RIGHT} currV;
- int currH;
- struct buttons bs;
- struct lineposition pos = {0,0,0,0,0,0,0,0,0,0};
-
- startleft = false;
- for (i=0; i<nitems; i++) {
- pos.line = MAX(pos.line, strlen(items[i].desc));
- if (items[i].on == false)
- startleft = true;
- }
-
- get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- if (buildlist_autosize(rows, cols) != 0)
- return BSDDIALOG_ERROR;
- if (buildlist_checksize(h, w, text, menurows, nitems, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + t.text.hmargin,
- y + h - menurows, x + 1 + w - t.text.hmargin);
-
- winsy = y + h - 5 - menurows;
- leftwinx = x+2;
- leftwin = new_boxed_window(conf, winsy, leftwinx, menurows+2, (w-5)/2,
- LOWERED);
- rightwinx = x + w - 2 -(w-5)/2;
- rightwin = new_boxed_window(conf, winsy, rightwinx, menurows+2,
- (w-5)/2, LOWERED);
-
- wrefresh(leftwin);
- wrefresh(rightwin);
-
- padscols = (w-5)/2 - 2;
- leftpad = newpad(nitems, pos.line);
- rightpad = newpad(nitems, pos.line);
- wbkgd(leftpad, t.dialog.color);
- wbkgd(rightpad, t.dialog.color);
-
- currH = 0;
- currV = startleft ? LEFT : RIGHT;
- loop = buttupdate = padsupdate = true;
- while(loop) {
- if (buttupdate) {
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
- buttupdate = false;
- }
-
- if (padsupdate) {
- werase(leftpad);
- werase(rightpad);
- curr = -1;
- nlefts = nrights = 0;
- for (i=0; i<nitems; i++) {
- if (items[i].on == false) {
- if (currV == LEFT && currH == nlefts)
- curr = i;
- drawitem(conf, leftpad, nlefts, items[i],
- BUILDLISTMODE, pos, curr == i);
- nlefts++;
- } else {
- if (currV == RIGHT && currH == nrights)
- curr = i;
- drawitem(conf, rightpad, nrights, items[i],
- BUILDLISTMODE, pos, curr == i);
- nrights++;
- }
- }
- prefresh(leftpad, 0, 0, winsy+1, leftwinx+1,
- winsy+1+menurows, leftwinx + 1 + padscols);
- prefresh(rightpad, 0, 0, winsy+1, rightwinx+1,
- winsy+1+menurows, rightwinx + 1 + padscols);
- padsupdate = false;
- }
-
- input = getch();
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
- output = bs.value[bs.curr];
- loop = false;
- break;
- case 27: /* Esc */
- output = BSDDIALOG_ERROR;
- loop = false;
- break;
- case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
- break;
- }
-
- if (nitems <= 0)
- continue;
-
- switch(input) {
- case KEY_LEFT:
- if (currV == RIGHT && nrights > 0) {
- currV = LEFT;
- currH = 0;
- padsupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (currV == LEFT && nrights > 0) {
- currV = RIGHT;
- currH = 0;
- padsupdate = true;
- }
- break;
- case KEY_UP:
- currH = (currH > 0) ? currH - 1 : 0;
- padsupdate = true;
- break;
- case KEY_DOWN:
- if (currV == LEFT)
- currH = (currH < nlefts-1) ? currH +1 : currH;
- else
- currH = (currH < nrights-1)? currH +1 : currH;
- padsupdate = true;
- break;
- case ' ': /* Space */
- items[curr].on = ! items[curr].on;
- if (currV == LEFT) {
- if (nlefts > 1)
- currH = currH > 0 ? currH-1 : 0;
- else {
- currH = 0;
- currV = RIGHT;
- }
- } else {
- if (nrights > 1)
- currH = currH > 0 ? currH-1 : 0;
- else {
- currH = 0;
- currV = LEFT;
- }
- }
- padsupdate = true;
- break;
- default:
-
- break;
- }
- }
-
- if(focusitem != NULL)
- *focusitem = curr;
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items, 0};
- delwin(leftpad);
- delwin(leftwin);
- delwin(rightpad);
- delwin(rightwin);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ 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/lib/messagebox.c b/lib/messagebox.c
index e2b91e1bdc5c..fc18ff8a61d2 100644
--- a/lib/messagebox.c
+++ b/lib/messagebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,261 +25,202 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <string.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <curses.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-/* "Message": msgbox - yesno */
-
-#define AUTO_WIDTH (COLS / 3U)
-/*
- * Min height = 5: 2 up & down borders + 2 label & up border buttons + 1 line
- * for text, at least 1 line is important for widget_withtextpad_init() to avoid
- * "Cannot build the pad window for text".
- */
-#define MIN_HEIGHT 5
-
-extern struct bsddialog_theme t;
+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 */
+};
-static int
-message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- char *text, struct buttons bs)
+static void textupdate(struct dialog *d, struct scroll *s)
{
- int maxword, maxline, nlines, line;
-
- if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
- return BSDDIALOG_ERROR;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- *w = VBORDERS;
- /* buttons size */
- *w += bs.nbuttons * bs.sizebutton;
- *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* text size */
- line = MIN(maxline + VBORDERS + t.text.hmargin * 2, AUTO_WIDTH);
- line = MAX(line, (int) (maxword + VBORDERS + t.text.hmargin * 2));
- *w = MAX(*w, line);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- *w = MIN(*w, widget_max_width(conf));
- }
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = MIN_HEIGHT - 1;
- if (maxword > 0)
- *h += MAX(nlines, (int)(*w / GET_ASPECT_RATIO(conf)));
- *h = MAX(*h, MIN_HEIGHT);
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
+ 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);
}
-
- return 0;
-}
-
-static int message_checksize(int rows, int cols, struct buttons bs)
-{
- int mincols;
-
- mincols = VBORDERS;
- mincols += bs.nbuttons * bs.sizebutton;
- mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "\
- "for borders, buttons and spaces between buttons");
-
- if (rows < MIN_HEIGHT)
- RETURN_ERROR("Msgbox and Yesno need at least height 5");
-
- return 0;
+ rtextpad(d, s->ypad, 0, 0, HBUTTONS);
}
-static void
-buttonsupdate(WINDOW *widget, int h, int w, struct buttons bs, bool shortkey)
+static int message_size_position(struct dialog *d, int *htext)
{
- draw_buttons(widget, h-2, w, bs, shortkey);
- wnoutrefresh(widget);
+ int minw;
+
+ 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, int y, int x, int h, int w, WINDOW *textpad,
- int htextpad, int textrow)
+static int message_draw(struct dialog *d, struct scroll *s)
{
+ int unused;
- if (htextpad > h - 4) {
- mvwprintw(widget, h-3, w-6, "%3d%%",
- 100 * (textrow+h-4)/ htextpad);
- wnoutrefresh(widget);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
-
- pnoutrefresh(textpad, textrow, 0, y+1, x+2, y+h-4, x+w-2);
+ if (message_size_position(d, &s->htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+
+ s->printrows = d->h - BORDER - HBUTTONS - BORDER;
+ s->ypad = 0;
+ getmaxyx(d->textpad, s->htextpad, unused);
+ unused++; /* fix unused error */
+
+ return (0);
}
static int
-do_widget(struct bsddialog_conf *conf, char *text, int rows, int cols,
- struct buttons bs, bool shortkey)
+do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
+ const char *oklabel, const char *cancellabel)
{
- WINDOW *widget, *textpad, *shadow;
bool loop;
- int i, y, x, h, w, input, output, htextpad, textrow;
-
- 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)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
+ int retval;
+ wint_t input;
+ struct scroll s;
+ struct dialog d;
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, oklabel, cancellabel);
+ s.htext = -1;
+ if(message_draw(&d, &s) != 0)
+ return (BSDDIALOG_ERROR);
- textrow = 0;
loop = true;
- buttonsupdate(widget, h, w, bs, shortkey);
- textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
- while(loop) {
+ 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 */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (d.conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttonsupdate(widget, h, w, bs, shortkey);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
- case KEY_F(1):
- if (conf->f1_file == NULL && conf->f1_message == NULL)
- break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No break! the terminal size can change */
- case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- 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)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- buttonsupdate(widget, h, w, bs, shortkey);
- textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
-
- /* Important to fix grey lines expanding screen */
- refresh();
+ case KEY_LEFT:
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_UP:
- if (textrow == 0)
- break;
- textrow--;
- textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+ if (s.ypad > 0)
+ s.ypad--;
break;
case KEY_DOWN:
- if (textrow + h - 4 >= htextpad)
- break;
- textrow++;
- textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+ if (s.ypad + s.printrows < s.htextpad)
+ s.ypad++;
break;
- case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- buttonsupdate(widget, h, w, bs, shortkey);
- }
+ case KEY_HOME:
+ s.ypad = 0;
break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttonsupdate(widget, h, w, bs, shortkey);
- }
+ case KEY_END:
+ s.ypad = MAX(s.htextpad - s.printrows, 0);
break;
- default:
- if (shortkey == false)
+ 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 (d.conf->key.f1_file == NULL &&
+ d.conf->key.f1_message == NULL)
break;
-
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
+ if (f1help_dialog(d.conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if(message_draw(&d, &s) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_RESIZE:
+ if(message_draw(&d, &s) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ default:
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
}
}
}
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ end_dialog(&d);
- return output;
+ return (retval);
}
/* API */
-
int
-bsddialog_msgbox(struct bsddialog_conf *conf, char* text, int rows, int cols)
+bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
{
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- NULL /* nocancel */, BUTTONLABEL(help_label));
-
- return (do_widget(conf, text, rows, cols, bs, true));
+ return (do_message(conf, text, rows, cols, OK_LABEL, NULL));
}
int
-bsddialog_yesno(struct bsddialog_conf *conf, char* text, int rows, int cols)
+bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
{
- struct buttons bs;
-
- get_buttons(conf, &bs,
- conf->button.ok_label == NULL ? "Yes" : conf->button.ok_label,
- BUTTONLABEL(extra_label),
- conf->button.cancel_label == NULL ? "No" : conf->button.cancel_label,
- BUTTONLABEL(help_label));
+ return (do_message(conf, text, rows, cols, "Yes", "No"));
+}
- return (do_widget(conf, text, rows, cols, bs, true));
+int
+bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
+{
+ int htext;
+ struct dialog d;
+
+ 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/lib/textbox.c b/lib/textbox.c
index 22dd21470c3a..edd58d0a820e 100644
--- a/lib/textbox.c
+++ b/lib/textbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,225 +25,246 @@
* SUCH DAMAGE.
*/
-
-#include <sys/param.h>
-
-#include <string.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <curses.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-/* "Text": textbox */
-
-#define BUTTON_TEXTBOX "EXIT"
-
-extern struct bsddialog_theme t;
-
-static void
-textbox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- int hpad, int wpad)
+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 = VBORDERS;
- /* buttons size */
- *w += strlen(BUTTON_TEXTBOX) + 2 /* text delims*/;
- /* text size */
- *w = MAX(*w, wpad + VBORDERS);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- *w = MIN(*w, widget_max_width(conf)-1); /* again -1, fix util.c */
+ chtype arrowch, borderch;
+
+ if (d->conf->no_lines)
+ borderch = ' ';
+ else if (d->conf->ascii_lines)
+ borderch = '|';
+ else
+ borderch = ACS_VLINE;
+
+ if (st->xpad > 0) {
+ arrowch = d->conf->ascii_lines ? '<' : ACS_LARROW;
+ arrowch |= t.dialog.arrowcolor;
+ } else {
+ arrowch = borderch;
+ arrowch |= t.dialog.lineraisecolor;
}
+ mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4);
+
+ if (st->xpad + d->w - 2 - st->margin < st->wpad) {
+ arrowch = d->conf->ascii_lines ? '>' : ACS_RARROW;
+ arrowch |= t.dialog.arrowcolor;
+ } else {
+ arrowch = borderch;
+ arrowch |= t.dialog.linelowercolor;
+ }
+ mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4);
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = hpad + 4; /* HBORDERS + button border */
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf));
+ 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)
+static int textbox_size_position(struct dialog *d, struct scrolltext *st)
{
- int mincols;
-
- mincols = VBORDERS + strlen(BUTTON_TEXTBOX) + 2 /* text delims */;
-
- if (cols < mincols)
- RETURN_ERROR("Few cols for the textbox");
-
- if (rows < 4 /* HBORDERS + button*/ + (hpad > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for the textbox");
+ int minw;
+
+ 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);
+
+ return (0);
+}
- return 0;
+static int textbox_draw(struct dialog *d, struct scrolltext *st)
+{
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (textbox_size_position(d, st) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+
+ 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, char* file, int rows, int cols)
+bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
+ int cols)
{
- WINDOW *widget, *pad, *shadow;
- int i, input, y, x, h, w, hpad, wpad, ypad, xpad, ys, ye, xs, xe, printrows;
- char buf[BUFSIZ], *exitbutt;
+ bool loop, has_multicol_ch;
+ int i, retval;
+ unsigned int defaulttablen, linecols;
+ wint_t input;
+ char buf[BUFSIZ];
FILE *fp;
- bool loop;
- int output;
+ 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");
-
- hpad = 1;
- wpad = 1;
- pad = newpad(hpad, wpad);
- wbkgd(pad, t.dialog.color);
+ 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);
+
+ 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);
+ while (fgets(buf, BUFSIZ, fp) != NULL) {
+ 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 */
+
+ if (textbox_draw(&d, &st) != 0)
+ return (BSDDIALOG_ERROR);
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad);
- if (textbox_checksize(h, w, hpad) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- NULL, NULL, NULL, true) != 0)
- return BSDDIALOG_ERROR;
-
- exitbutt = conf->button.exit_label == NULL ? BUTTON_TEXTBOX : conf->button.exit_label;
- draw_button(widget, h-2, (w-2)/2 - strlen(exitbutt)/2, strlen(exitbutt)+2,
- exitbutt, true, false);
-
- wrefresh(widget);
-
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h-4;
loop = true;
- while(loop) {
- prefresh(pad, ypad, xpad, ys, xs, ye, xe);
- input = getch();
+ while (loop) {
+ updateborders(&d, &st);
+ /*
+ * 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 = BSDDIALOG_OK;
loop = false;
break;
case 27: /* Esc */
- output = BSDDIALOG_ESC;
- loop = false;
+ if (conf->key.enable_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;
- ypad = ypad + printrows > hpad ? hpad - printrows : ypad;
+ 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->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- /* No break! the terminal size can change */
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (textbox_draw(&d, &st) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return BSDDIALOG_ERROR;
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad);
- if (textbox_checksize(h, w, hpad) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h - 4;
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, NULL, NULL, NULL, true) != 0)
- return BSDDIALOG_ERROR;
-
- draw_button(widget, h-2, (w-2)/2 - strlen(exitbutt)/2,
- strlen(exitbutt)+2, exitbutt, true, false);
-
- wrefresh(widget); /* for button */
-
- /* Important to fix grey lines expanding screen */
- refresh();
+ if (textbox_draw(&d, &st) != 0)
+ return (BSDDIALOG_ERROR);
break;
}
}
- end_widget_withtextpad(conf, widget, h, w, pad, shadow);
+ delwin(st.pad);
+ end_dialog(&d);
- return output;
+ return (retval);
}
diff --git a/lib/theme.c b/lib/theme.c
index 3bcd8ee8fc53..04f85b2455fa 100644
--- a/lib/theme.c
+++ b/lib/theme.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,151 +25,124 @@
* SUCH DAMAGE.
*/
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
+#include <curses.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#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
- .terminal.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),
-
- .text.hmargin = 1,
-
- .menu.arrowcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget) | A_BOLD,
- .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_YELLOW, 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.space = 3,
- .button.leftch = '[',
- .button.rightch = ']',
- .button.f_delimcolor = GET_COLOR(COLOR_WHITE, bgcurr),
- .button.delimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .button.f_color = GET_COLOR(COLOR_WHITE, bgcurr) | A_UNDERLINE,
- .button.color = GET_COLOR(COLOR_BLACK, bgwidget) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(COLOR_BLACK, bgcurr) | A_UNDERLINE,
- .button.shortcutcolor = GET_COLOR(COLOR_YELLOW, 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 bk COLOR_BLACK
-#define fg COLOR_WHITE
- .terminal.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),
-
- .text.hmargin = 1,
-
- .menu.arrowcolor = GET_COLOR(fg, bk),
- .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.space = 3,
- .button.leftch = '[',
- .button.rightch = ']',
- .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
+ .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 = 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 = {
- .terminal.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,
-
- .text.hmargin = 1,
-
- .menu.arrowcolor = GET_COLOR(COLOR_GREEN, COLOR_WHITE),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget) | A_BOLD,
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
- .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
- .menu.f_namecolor = GET_COLOR(COLOR_YELLOW, COLOR_BLUE) | A_BOLD,
- .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .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) | A_BOLD,
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE) | A_BOLD,
-
- .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.space = 3,
- .button.leftch = '<',
- .button.rightch = '>',
+ .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,
@@ -181,41 +154,46 @@ static struct bsddialog_theme dialogtheme = {
static void
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->terminal.color = src->terminal.color;
dst->dialog.delimtitle = src->dialog.delimtitle;
dst->dialog.titlecolor = src->dialog.titlecolor;
dst->dialog.lineraisecolor = src->dialog.lineraisecolor;
dst->dialog.linelowercolor = src->dialog.linelowercolor;
dst->dialog.color = src->dialog.color;
dst->dialog.bottomtitlecolor = src->dialog.bottomtitlecolor;
+ dst->dialog.arrowcolor = src->dialog.arrowcolor;
- dst->text.hmargin = src->text.hmargin;
-
- dst->menu.arrowcolor = src->menu.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.space = src->button.space;
- dst->button.leftch = src->button.leftch;
- dst->button.rightch = src->button.rightch;
+ 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;
dst->button.delimcolor = src->button.delimcolor;
dst->button.f_color = src->button.f_color;
@@ -223,66 +201,88 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->button.f_shortcutcolor = src->button.f_shortcutcolor;
dst->button.shortcutcolor = src->button.shortcutcolor;
- bkgd(dst->terminal.color);
- refresh();
+ bkgd(dst->screen.color);
}
/* 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);
+ refresh();
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
{
-
- if (newtheme == BSDDIALOG_THEME_DEFAULT) {
- bsddialog_set_theme(&dialogtheme);
- t.dialog.lineraisecolor = t.dialog.linelowercolor;
+ 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);
+ refresh();
+
+ return (BSDDIALOG_OK);
}
int
-bsddialog_color(enum bsddialog_color background,
- enum bsddialog_color foreground, unsigned int flags)
+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(background, foreground) | 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/lib/timebox.c b/lib/timebox.c
index 2597cbf0c152..d683f9552b50 100644
--- a/lib/timebox.c
+++ b/lib/timebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,511 +25,207 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/ncurses.h>
-#else
-#include <ncurses.h>
-#endif
-
-#include <ctype.h>
-#include <string.h>
+#include <curses.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-#define MINWDATE 25 /* 23 wins + 2 VBORDERS */
-#define MINWTIME 16 /*14 wins + 2 VBORDERS */
-#define MINHEIGHT 8 /* 2 for text */
-
-/* "Time": timebox - datebox */
+#define MINWTIME 14 /* 3 windows and their borders */
+#define HBOX 3
+#define WBOX 4
-extern struct bsddialog_theme t;
+struct clock {
+ unsigned int max;
+ unsigned int value;
+ WINDOW *win;
+};
-static int
-datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int minw, char *text, struct buttons bs)
+static void
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value,
+ bool focus)
{
- int maxword, maxline, nlines, line;
-
- if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
- return BSDDIALOG_ERROR;
-
- if (cols == BSDDIALOG_AUTOSIZE) {
- *w = VBORDERS;
- /* buttons size */
- *w += bs.nbuttons * bs.sizebutton;
- *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- /* text size */
- line = maxline + VBORDERS + t.text.hmargin * 2;
- line = MAX(line, (int) (maxword + VBORDERS + t.text.hmargin * 2));
- *w = MAX(*w, line);
- /* date windows */
- *w = MAX(*w, minw);
- /* conf.auto_minwidth */
- *w = MAX(*w, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- *w = MIN(*w, widget_max_width(conf) -1);
+ draw_borders(conf, win, LOWERED);
+ if (focus) {
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, 1, conf->ascii_lines ? '^' : ACS_UARROW, 2);
+ mvwhline(win, 2, 1, conf->ascii_lines ? 'v' : ACS_DARROW, 2);
+ wattroff(win, t.dialog.arrowcolor);
}
- if (rows == BSDDIALOG_AUTOSIZE) {
- *h = MINHEIGHT;
- if (maxword > 0)
- *h += MAX(nlines, (int)(*w / GET_ASPECT_RATIO(conf)));
- /* conf.auto_minheight */
- *h = MAX(*h, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- *h = MIN(*h, widget_max_height(conf) -1);
- }
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ mvwprintw(win, 1, 1, "%02u", value);
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
- return 0;
+ wnoutrefresh(win);
}
-static int
-datetime_checksize(int rows, int cols, char *text, int minw, struct buttons bs)
+static int timebox_redraw(struct dialog *d, struct clock *c)
{
- int mincols;
-
- mincols = VBORDERS;
- mincols += bs.nbuttons * bs.sizebutton;
- mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
- mincols = MAX(minw, mincols);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols for this timebox/datebox");
-
- if (rows < MINHEIGHT + (strlen(text) > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for this timebox/datebox");
+ int y, x;
- return 0;
+ if (d->built) {
+ 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)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ 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);
}
-int bsddialog_timebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int *hh, unsigned int *mm, unsigned int *ss)
+/* API */
+int
+bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
+ int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
{
- WINDOW *widget, *textpad, *shadow;
- int i, input, output, y, x, h, w, sel, htextpad;
- struct buttons bs;
- bool loop;
- 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] = {
+ bool loop, focusbuttons;
+ 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;
+ CHECK_PTR(hh);
+ CHECK_PTR(mm);
+ CHECK_PTR(ss);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ 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);
}
-
- get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
-
- 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, text, MINWTIME, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- draw_buttons(widget, h-2, w, bs, true);
-
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- 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 = 0;
- curs_set(2);
- loop = true;
- while(loop) {
- for (i=0; i<3; i++) {
- mvwprintw(c[i].win, 1, 1, "%2d", c[i].value);
- wrefresh(c[i].win);
- }
- wmove(c[sel].win, 1, 2);
- wrefresh(c[sel].win);
-
- input = getch();
+ if (timebox_redraw(&d, c) != 0)
+ return (BSDDIALOG_ERROR);
+
+ sel = -1;
+ loop = focusbuttons = true;
+ while (loop) {
+ 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 */
- output = bs.value[bs.curr];
- if (output == BSDDIALOG_OK) {
- *hh = c[0].value;
- *mm = c[1].value;
- *ss = c[2].value;
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
}
- loop = false;
break;
case 27: /* Esc */
- output = BSDDIALOG_ESC;
- loop = false;
- break;
- case '\t': /* TAB */
- sel = (sel + 1) % 3;
- break;
- case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
}
break;
case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
- }
- break;
- case KEY_UP:
- c[sel].value = c[sel].value < c[sel].max ? c[sel].value + 1 : 0;
- break;
- case KEY_DOWN:
- c[sel].value = c[sel].value > 0 ? c[sel].value - 1 : c[sel].max;
- break;
- case KEY_F(1):
- if (conf->f1_file == NULL && conf->f1_message == NULL)
- break;
- curs_set(0);
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- curs_set(2);
- /* No break! the terminal size can change */
- case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- 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, text, MINWTIME, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- mvwaddch(widget, h - 5, w/2 + 2, ':');
-
- draw_buttons(widget, h-2, w, bs, true);
-
- 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:
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
- }
- }
- }
-
- curs_set(0);
-
- for (i=0; i<3; i++)
- delwin(c[i].win);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
-
- return output;
-}
-
-int
-bsddialog_datebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
- unsigned int *yy, unsigned int *mm, unsigned int *dd)
-{
- WINDOW *widget, *textpad, *shadow;
- int i, input, output, y, x, h, w, sel, htextpad;
- struct buttons bs;
- bool loop;
- struct calendar {
- int max;
- int value;
- WINDOW *win;
- unsigned int x;
- };
- struct month {
- 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, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
- BUTTONLABEL(cancel_label), BUTTONLABEL(help_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, text, MINWDATE, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
- &textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- draw_buttons(widget, h-2, w, bs, true);
-
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- 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);
-
- sel = 2;
- curs_set(2);
- loop = 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);
- }
- wmove(c[sel].win, 1, c[sel].x);
- wrefresh(c[sel].win);
-
- input = getch();
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
- output = bs.value[bs.curr];
- if (output == BSDDIALOG_OK) {
- *yy = c[0].value;
- *mm = c[1].value;
- *dd = c[2].value;
- }
- loop = false;
- break;
- case 27: /* Esc */
- output = BSDDIALOG_ESC;
- loop = false;
- break;
case '\t': /* TAB */
- sel = (sel + 1) % 3;
- break;
- case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
+ 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_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, h-2, w, bs, true);
- wrefresh(widget);
+ 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 KEY_UP:
- 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;
+ if (focusbuttons) {
+ sel = 0;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
+ } else {
+ c[sel].value = c[sel].value > 0 ?
+ c[sel].value - 1 : c[sel].max;
+ }
break;
case KEY_DOWN:
- 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;
+ if (focusbuttons)
+ break;
+ c[sel].value = c[sel].value < c[sel].max ?
+ c[sel].value + 1 : 0;
break;
case KEY_F(1):
- if (conf->f1_file == NULL && conf->f1_message == NULL)
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
break;
- curs_set(0);
- if (f1help(conf) != 0)
- return BSDDIALOG_ERROR;
- curs_set(2);
- /* No break! the terminal size can change */
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (timebox_redraw(&d, c) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
case KEY_RESIZE:
- hide_widget(y, x, h, w,conf->shadow);
-
- /*
- * Unnecessary, but, when the columns decrease the
- * following "refresh" seem not work
- */
- 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)
- return BSDDIALOG_ERROR;
- if (datetime_checksize(h, w, text, MINWDATE, bs) != 0)
- return BSDDIALOG_ERROR;
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return BSDDIALOG_ERROR;
-
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
-
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
-
- htextpad = 1;
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
-
- if(update_widget_withtextpad(conf, shadow, widget, h, w,
- RAISED, textpad, &htextpad, text, true) != 0)
- return BSDDIALOG_ERROR;
-
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- mvwaddch(widget, h - 5, w/2 + 7, '/');
-
- draw_buttons(widget, h-2, w, bs, true);
-
- 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();
+ if (timebox_redraw(&d, c) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- for (i = 0; i < (int) bs.nbuttons; i++)
- if (tolower(input) == tolower((bs.label[i])[0])) {
- output = bs.value[i];
- loop = false;
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
}
}
}
- curs_set(0);
+ *hh = c[0].value;
+ *mm = c[1].value;
+ *ss = c[2].value;
- for (i=0; i<3; i++)
+ for (i = 0; i < 3; i++)
delwin(c[i].win);
- end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+ end_dialog(&d);
- return output;
+ return (retval);
}
diff --git a/utility/GNUmakefile b/utility/GNUmakefile
new file mode 100644
index 000000000000..518ec0d912d6
--- /dev/null
+++ b/utility/GNUmakefile
@@ -0,0 +1,33 @@
+# 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)
+
+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)
+
+$(OUTPUT): $(OBJECTS)
+ $(CC) $^ -o $@ $(LDFLAGS)
+
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ $(RM) $(OUTPUT) *.o *~
diff --git a/utility/Makefile b/utility/Makefile
new file mode 100644
index 000000000000..ab51b46a25be
--- /dev/null
+++ b/utility/Makefile
@@ -0,0 +1,33 @@
+# 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}
+
+.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}
+
+${OUTPUT}: ${OBJECTS}
+ ${CC} ${LDFLAGS} ${OBJECTS} -o ${.PREFIX}
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+clean:
+ ${RM} ${OUTPUT} *.o *~ *.core *.gz
diff --git a/utility/bsddialog.1 b/utility/bsddialog.1
new file mode 100644
index 000000000000..653f91a3f122
--- /dev/null
+++ b/utility/bsddialog.1
@@ -0,0 +1,907 @@
+.\"
+.\" 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
+.\" 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 July 25, 2023
+.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
+If available set alternate screen mode, see
+.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
+If available set normal screen mode, see
+.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 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
+with graphical length
+.Ar fieldlen ,
+.Ar maxletters
+is the maximum input length.
+The field can be customized, if
+.Ar fieldlen
+is negative the field is read only and its absolute value is the field length.
+If
+.Ar maxletters
+is 0 it is the absolute value of
+.Ar fieldlen .
+.Ar init
+is a default value.
+.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 with graphical length
+.Ar fieldlen
+at the position
+.Ar yfield
+and
+.Ar xfield ,
+.Ar maxletters
+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,
+.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.
+UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to scroll the text.
+.It Fl Fl passwordbox Ar text Ar rows Ar cols Op Ar init
+Dialog to get a password,
+.Ar init
+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, 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 .
+UP, DOWN, LEFT, RIGHT, HOME, END, PAGEUP and PAGEDOWN keys are available to
+navigate the file, TAB changes button.
+.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 .
+UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to scroll the text.
+.El
+.Sh ENVIRONMENT
+The following environment variables take effect only on startup, other options
+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
+Right2 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
+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/utility/bsddialog.c b/utility/bsddialog.c
new file mode 100644
index 000000000000..d4d1fc3e0f3a
--- /dev/null
+++ b/utility/bsddialog.c
@@ -0,0 +1,338 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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
+ * 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/utility/util.h b/utility/util.h
new file mode 100644
index 000000000000..2750c2ee6951
--- /dev/null
+++ b/utility/util.h
@@ -0,0 +1,125 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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
+ * 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/utility/util_builders.c b/utility/util_builders.c
new file mode 100644
index 000000000000..2dfa20cb0f86
--- /dev/null
+++ b/utility/util_builders.c
@@ -0,0 +1,768 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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
+ * 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 <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 = (u_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 = (u_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 = (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)
+ 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 = (u_int)strtoul(argv[0], NULL, 10);
+ mm = (u_int)strtoul(argv[1], NULL, 10);
+ yy = (u_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 = (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 (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 ?
+ (u_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 = (u_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 = (u_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 = (u_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 = (u_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 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++) {
+ dprintf(opt->output_fd, "%s\n", items[i].value);
+ free(items[i].value);
+ }
+}
+
+int form_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, "--form missing <formheight>");
+ formheight = (u_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 = (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 = 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, focusitem;
+ unsigned int i, j, formheight, nitems, sizeitem;
+ struct bsddialog_formitem *items;
+
+ if (argc < 1)
+ exit_error(true, "--mixedform missing <formheight>");
+ formheight = (u_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 = (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 = 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 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 = (u_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 = (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 = 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/utility/util_cli.c b/utility/util_cli.c
new file mode 100644
index 000000000000..22bed6550fb5
--- /dev/null
+++ b/utility/util_cli.c
@@ -0,0 +1,841 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * 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
+ * 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,
+ 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},
+ {"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:
+ 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/utility/util_theme.c b/utility/util_theme.c
new file mode 100644
index 000000000000..c313d743252b
--- /dev/null
+++ b/utility/util_theme.c
@@ -0,0 +1,451 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 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;
+ }
+}