aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2023-10-04 15:43:22 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2023-10-04 15:43:22 +0000
commite56a937c3e111672afff33346941fb618792308b (patch)
tree30c822cfcf3e71b313414b9e1c64d48732b39ebb
parent9f24fda5a8e7ab8243e71473c7e2dc98b4877e64 (diff)
downloadsrc-vendor/bsddialog.tar.gz
src-vendor/bsddialog.zip
bsddialog: Import version 1.0vendor/bsddialog/1.0vendor/bsddialog
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG194
-rw-r--r--GNUMakefile28
-rw-r--r--LICENSE2
-rw-r--r--Makefile62
-rw-r--r--README.md35
-rw-r--r--bsddialog.c1687
-rw-r--r--examples_library/calendar.c22
-rw-r--r--examples_library/checklist.c11
-rwxr-xr-xexamples_library/compile2
-rw-r--r--examples_library/datebox.c21
-rw-r--r--examples_library/form.c11
-rw-r--r--examples_library/gauge.c57
-rw-r--r--examples_library/infobox.c6
-rw-r--r--examples_library/menu.c11
-rw-r--r--examples_library/mixedgauge.c79
-rw-r--r--examples_library/mixedlist.c21
-rw-r--r--examples_library/msgbox.c9
-rw-r--r--examples_library/pause.c21
-rw-r--r--examples_library/radiolist.c14
-rw-r--r--examples_library/rangebox.c7
-rw-r--r--examples_library/theme.c46
-rw-r--r--examples_library/timebox.c18
-rw-r--r--examples_library/yesno.c11
-rwxr-xr-xexamples_utility/checklist.sh16
-rwxr-xr-xexamples_utility/datebox.sh34
-rwxr-xr-xexamples_utility/form.sh4
-rwxr-xr-xexamples_utility/infobox.sh2
-rwxr-xr-xexamples_utility/inputbox.sh5
-rwxr-xr-xexamples_utility/menu.sh13
-rwxr-xr-xexamples_utility/mixedform.sh4
-rwxr-xr-xexamples_utility/mixedgauge.sh10
-rwxr-xr-xexamples_utility/passwordbox.sh4
-rwxr-xr-xexamples_utility/passwordform.sh4
-rwxr-xr-xexamples_utility/radiolist.sh18
-rw-r--r--examples_utility/rangebox.sh33
-rw-r--r--lib/GNUmakefile (renamed from lib/GNUMakefile)15
-rw-r--r--lib/Makefile49
-rw-r--r--lib/barbox.c705
-rw-r--r--lib/bsddialog.3626
-rw-r--r--lib/bsddialog.h44
-rw-r--r--lib/bsddialog_progressview.h8
-rw-r--r--lib/bsddialog_theme.h28
-rw-r--r--lib/calendarbox.c520
-rw-r--r--lib/datebox.c715
-rw-r--r--lib/formbox.c940
-rw-r--r--lib/infobox.c96
-rw-r--r--lib/lib_util.c1157
-rw-r--r--lib/lib_util.h169
-rw-r--r--lib/libbsddialog.c38
-rw-r--r--lib/menubox.c837
-rw-r--r--lib/messagebox.c250
-rw-r--r--lib/textbox.c268
-rw-r--r--lib/theme.c254
-rw-r--r--lib/timebox.c479
-rw-r--r--util_theme.c353
-rw-r--r--util_theme.h36
-rw-r--r--utility/GNUmakefile33
-rw-r--r--utility/Makefile33
-rw-r--r--utility/bsddialog.1 (renamed from bsddialog.1)345
-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
65 files changed, 6874 insertions, 6171 deletions
diff --git a/.gitignore b/.gitignore
index 8b8ec9d4ae0b..c8fc68ed8a0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,8 +12,10 @@ 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/msgbox
examples_library/pause
diff --git a/CHANGELOG b/CHANGELOG
index 883fe1016d01..e6295768d906 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,173 @@
+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:
@@ -6,19 +176,19 @@
* 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 becames its alias).
- * add: --no-descriptions (--no-items becames its alias).
- * add: --help-print-name (--help-tags becames its alias).
- * add: --item-bottom-desc (--item-help becames its 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 enables "\t" in text.
+ * 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 becames alias for --clear-screen.
+ * 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.
@@ -41,9 +211,9 @@
* 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 becames at most menurows (depending on text).
- * change: fixed-rows becames at most rows, min(rows, screenH - shadow).
- * change: fixed-cols becames at most cols, min(cols, screenW - shadow).
+ * 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).
@@ -55,9 +225,9 @@
* 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 enables focus switching: buttons / input
- components. Available for: --form, --inputbox, --mixedform,
- --passwordform, --passwordbox, --timebox and --datebox.
+ * 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.
diff --git a/GNUMakefile b/GNUMakefile
deleted file mode 100644
index 7da4d64deecf..000000000000
--- a/GNUMakefile
+++ /dev/null
@@ -1,28 +0,0 @@
-# PUBLIC DOMAIN - NO WARRANTY, see:
-# <http://creativecommons.org/publicdomain/zero/1.0/>
-#
-# Written in 2021 by Alfonso Sabato Siciliano
-
-OUTPUT= bsddialog
-SOURCES= bsddialog.c util_theme.c
-OBJECTS= $(SOURCES:.c=.o)
-LIBPATH= ./lib
-LIBBSDDIALOG= $(LIBPATH)/libbsddialog.so
-CFLAGS= -Wall -Wextra -I$(LIBPATH)
-LDFLAGS= -ltinfo -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 f24be045375b..d19ad87fca1f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 2-Clause License
-Copyright (c) 2021-2022, Alfonso Sabato Siciliano
+Copyright (c) 2021-2023, Alfonso Sabato Siciliano
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/Makefile b/Makefile
index 28162c5e90b3..884cfa1b3e60 100644
--- a/Makefile
+++ b/Makefile
@@ -1,50 +1,38 @@
# PUBLIC DOMAIN - NO WARRANTY, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>
#
-# Written in 2021 by Alfonso Sabato Siciliano
+# Written in 2023 by Alfonso Sabato Siciliano
-OUTPUT= bsddialog
-SOURCES= bsddialog.c util_theme.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+= -I${LIBPATH} -std=gnu99 -Wall -Wextra -Werror
-# `make -DDEBUG`
-.if defined(DEBUG)
-CFLAGS= -g -Wall -I${LIBPATH}
-LIBDEBUG= -DDEBUG
-.endif
-LDFLAGS+= -ltinfow -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}:
- make -C ${LIBPATH} ${LIBDEBUG}
-
-.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 59af7072e7f5..f4846ec07745 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
-# BSDDialog 0.4
+# BSDDialog 1.0
This project provides **bsddialog** and **libbsddialog**, an utility
and a library to build scripts and tools with TUI dialogs and widgets.
+
+
+## Demo
+
[Screenshots](https://www.flickr.com/photos/alfonsosiciliano/albums/72157720215006074).
## Getting Started
-FreeBSD:
+FreeBSD and Linux:
```
% git clone https://gitlab.com/alfix/bsddialog.git
@@ -16,15 +20,6 @@ FreeBSD:
% ./bsddialog --msgbox "Hello World!" 8 20
```
-Linux:
-
-```
-% git clone https://gitlab.com/alfix/bsddialog.git
-% cd bsddialog
-% make -f GNUMakefile
-% ./bsddialog --msgbox "Hello World!" 8 20
-```
-
Output:
![screenshot](screenshot.png)
@@ -60,6 +55,7 @@ in the _Public Domain_ to build new projects:
```
% sh ./examples_utility/calendar.sh
% sh ./examples_utility/checklist.sh
+% sh ./examples_utility/datebox.sh
% sh ./examples_utility/form.sh
% sh ./examples_utility/gauge.sh
% sh ./examples_utility/infobox.sh
@@ -72,6 +68,7 @@ in the _Public Domain_ to build new projects:
% sh ./examples_utility/passwordform.sh
% sh ./examples_utility/pause.sh
% sh ./examples_utility/radiolist.sh
+% sh ./examples_utility/rangebox.sh
% sh ./examples_utility/timebox.sh
% sh ./examples_utility/yesno.sh
```
@@ -100,8 +97,10 @@ in the _Public Domain_ to build new projects:
% ./checklist
% ./datebox
% ./form
+% ./gauge
% ./infobox
% ./menu
+% ./mixedgauge
% ./mixedlist
% ./msgbox
% ./pause
@@ -114,7 +113,19 @@ in the _Public Domain_ to build new projects:
## 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.c b/bsddialog.c
deleted file mode 100644
index b9b2810dc62f..000000000000
--- a/bsddialog.c
+++ /dev/null
@@ -1,1687 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/ioctl.h>
-
-#include <getopt.h>
-#include <locale.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <term.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <bsddialog.h>
-#include <bsddialog_theme.h>
-
-#include "util_theme.h"
-
-enum OPTS {
- /* Options */
- ALTERNATE_SCREEN = '?' + 1,
- AND_DIALOG,
- ASCII_LINES,
- BACKTITLE,
- BEGIN_X,
- BEGIN_Y,
- BIKESHED,
- CANCEL_LABEL,
- CLEAR_DIALOG,
- CLEAR_SCREEN,
- COLORS,
- COLUMNS_PER_ROW,
- CR_WRAP,
- DATE_FORMAT,
- DEFAULT_BUTTON,
- DEFAULT_ITEM,
- DEFAULT_NO,
- DISABLE_ESC,
- ESC_RETURNCANCEL,
- EXIT_LABEL,
- EXTRA_BUTTON,
- EXTRA_LABEL,
- GENERIC_BUTTON1,
- GENERIC_BUTTON2,
- HELP_BUTTON,
- HELP_LABEL,
- HELP_PRINT_NAME,
- HELP_STATUS,
- HFILE,
- HLINE,
- HMSG,
- IGNORE,
- INSECURE,
- ITEM_BOTTOM_DESC,
- ITEM_DEPTH,
- ITEM_PREFIX,
- LOAD_THEME,
- MAX_INPUT,
- NO_CANCEL,
- NO_DESCRIPTIONS,
- NO_LINES,
- NO_NAMES,
- NO_OK,
- NO_SHADOW,
- NORMAL_SCREEN,
- OK_LABEL,
- OUTPUT_FD,
- OUTPUT_SEPARATOR,
- PRINT_MAXSIZE,
- PRINT_SIZE,
- PRINT_VERSION,
- QUOTED,
- SAVE_THEME,
- SEPARATE_OUTPUT,
- SHADOW,
- SINGLE_QUOTED,
- SLEEP,
- STDERR,
- STDOUT,
- SWITCH_BUTTONS,
- TAB_ESCAPE,
- TAB_LEN,
- TEXT_UNCHANGED,
- THEME,
- 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-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, COLORS},
- {"columns-per-row", required_argument, NULL, COLUMNS_PER_ROW},
- {"cr-wrap", no_argument, NULL, CR_WRAP},
- {"date-format", required_argument, NULL, DATE_FORMAT},
- {"defaultno", no_argument, NULL, DEFAULT_NO},
- {"default-button", required_argument, NULL, DEFAULT_BUTTON},
- {"default-item", required_argument, NULL, DEFAULT_ITEM},
- {"default-no", no_argument, NULL, DEFAULT_NO},
- {"disable-esc", no_argument, NULL, DISABLE_ESC},
- {"esc-return-cancel", no_argument, NULL, ESC_RETURNCANCEL},
- {"exit-label", required_argument, NULL, EXIT_LABEL},
- {"extra-button", no_argument, NULL, EXTRA_BUTTON},
- {"extra-label", required_argument, NULL, EXTRA_LABEL},
- {"generic-button1", required_argument, NULL, GENERIC_BUTTON1},
- {"generic-button2", required_argument, NULL, GENERIC_BUTTON2},
- {"help-button", no_argument, NULL, HELP_BUTTON},
- {"help-label", required_argument, NULL, HELP_LABEL},
- {"help-print-name", no_argument, NULL, HELP_PRINT_NAME},
- {"help-status", no_argument, NULL, HELP_STATUS},
- {"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},
- {"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-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},
- {"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-unchanged", no_argument, NULL, TEXT_UNCHANGED},
- {"theme", required_argument, NULL, THEME},
- {"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}
-};
-
-/* Menus options */
-static bool item_prefix_opt;
-static bool item_bottomdesc_opt;
-static bool item_output_sepnl_opt;
-static bool item_singlequote_opt;
-static bool list_items_on_opt;
-static bool item_help_print_name_opt;
-static bool item_always_quote_opt;
-static bool item_depth_opt;
-static char *item_output_sep_opt;
-static char *item_default_opt;
-/* Date and Time options */
-static char *date_fmt_opt;
-static char *time_fmt_opt;
-/* Forms options */
-static int unsigned max_input_form_opt;
-/* General options */
-static bool esc_return_cancel_opt;
-static bool ignore_opt;
-static int output_fd_opt;
-static int getH_opt;
-static int getW_opt;
-/* Text option */
-static bool cr_wrap_opt;
-static bool tab_escape_opt;
-static bool text_unchanged_opt;
-/* Theme and Screen options*/
-static bool bikeshed_opt;
-static enum bsddialog_default_theme theme_opt;
-static char *backtitle_opt;
-static bool clear_screen_opt;
-static char *loadthemefile;
-static char *savethemefile;
-static const char *screen_mode_opt;
-
-/* Functions */
-#define UNUSED_PAR(x) UNUSED_ ## x __attribute__((__unused__))
-static void custom_text(char *text, char *buf);
-static void usage(void);
-/* Dialogs */
-#define BUILDER_ARGS struct bsddialog_conf *conf, char* text, int rows, \
- int cols, int argc, char **argv
-static int calendar_builder(BUILDER_ARGS);
-static int checklist_builder(BUILDER_ARGS);
-static int datebox_builder(BUILDER_ARGS);
-static int form_builder(BUILDER_ARGS);
-static int gauge_builder(BUILDER_ARGS);
-static int infobox_builder(BUILDER_ARGS);
-static int inputbox_builder(BUILDER_ARGS);
-static int menu_builder(BUILDER_ARGS);
-static int mixedform_builder(BUILDER_ARGS);
-static int mixedgauge_builder(BUILDER_ARGS);
-static int msgbox_builder(BUILDER_ARGS);
-static int passwordbox_builder(BUILDER_ARGS);
-static int passwordform_builder(BUILDER_ARGS);
-static int pause_builder(BUILDER_ARGS);
-static int radiolist_builder(BUILDER_ARGS);
-static int rangebox_builder(BUILDER_ARGS);
-static int textbox_builder(BUILDER_ARGS);
-static int timebox_builder(BUILDER_ARGS);
-static int treeview_builder(BUILDER_ARGS);
-static int yesno_builder(BUILDER_ARGS);
-
-/* init, exit and internals */
-static bool in_bsddialog_mode;
-static bool mandatory_dialog;
-static int (*dialogbuilder)(BUILDER_ARGS);
-
-static void exit_error(const char *errstr, bool with_usage)
-{
- if (in_bsddialog_mode)
- bsddialog_end();
-
- printf("Error: %s.\n\n", errstr);
- if (with_usage) {
- printf("See \'bsddialog --help\' or \'man 1 bsddialog\' ");
- printf("for more information.\n");
- }
-
- exit (255);
-}
-
-static void sigint_handler(int UNUSED_PAR(sig))
-{
- bsddialog_end();
-
- exit(255);
-}
-
-static void start_bsddialog_mode(void)
-{
- if (in_bsddialog_mode)
- return;
-
- if (bsddialog_init() != BSDDIALOG_OK)
- exit_error(bsddialog_geterror(), false);
-
- in_bsddialog_mode = true;
- signal(SIGINT, sigint_handler);
-}
-
-static void error_args(const char *dialog, int argc, char **argv)
-{
- int i;
-
- if (in_bsddialog_mode)
- 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 (255);
-}
-
-static void usage(void)
-{
- printf("usage: bsddialog --help\n");
- printf(" bsddialog --version\n");
- printf(" bsddialog [--<opt>] --<dialog> <text> <rows> <cols> "
- "[<arg>]\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, --calendar,"
- " --cancel-label <label>, --clear-dialog,\n --clear-screen,"
- " --colors, --columns-per-row <columns>, --cr-wrap,\n"
- " --date-format <format>, --default-button <label>,"
- " --default-item <name>,\n --default-no, --disable-esc,"
- " --esc-return-cancel, --exit-label <label>,\n --extra-button,"
- " --extra-label <label>, --generic-button1 <label>,\n"
- " --generic-button2 <label>, --help-button, --help-label <label>,\n"
- " --help-print-name, --help-status, --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-label <label>,"
- " --output-fd <fd>,\n --output-separator <sep>, --print-maxsize,"
- " --print-size, --print-version,\n --quoted, --save-theme <file>,"
- " --separate-output, --separator <sep>, --shadow,\n"
- " --single-quoted, --sleep <secs>, --stderr, --stdout,"
- " --tab-escape,\n --tab-len <spaces>, --text-unchanged,"
- " --switch-buttons,\n --theme <blackwhite|bsddialog|flat|dialog>,"
- " --time-format <format>,\n --title <title>,"
- " --yes-label <label>.\n");
- printf("\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");
-}
-
-static int parseargs(int argc, char **argv, struct bsddialog_conf *conf)
-{
- int arg, parsed, i;
- struct winsize ws;
-
- bsddialog_initconf(conf);
- conf->key.enable_esc = true;
- conf->menu.on_without_ok = true;
- conf->form.value_without_ok = true;
- conf->button.always_active = true;
-
- dialogbuilder = NULL;
-
- backtitle_opt = NULL;
- theme_opt = -1;
- output_fd_opt = STDERR_FILENO;
- ignore_opt = false;
- cr_wrap_opt = false;
- tab_escape_opt = false;
- text_unchanged_opt = false;
- esc_return_cancel_opt = false;
- bikeshed_opt = false;
- savethemefile = NULL;
- loadthemefile = NULL;
- clear_screen_opt = false;
- screen_mode_opt = NULL;
-
- item_output_sepnl_opt = false;
- item_singlequote_opt = false;
- item_prefix_opt = false;
- item_bottomdesc_opt = false;
- item_depth_opt = false;
- list_items_on_opt = false;
- item_help_print_name_opt = false;
- item_always_quote_opt = false;
- item_output_sep_opt = NULL;
- item_default_opt = NULL;
-
- date_fmt_opt = NULL;
- time_fmt_opt = NULL;
-
- max_input_form_opt = 2048;
-
- 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:
- screen_mode_opt = "smcup";
- break;
- case AND_DIALOG:
- if (dialogbuilder == NULL)
- exit_error("--and-dialog without previous "
- "--<dialog>", true);
- break;
- case ASCII_LINES:
- conf->ascii_lines = true;
- break;
- case BACKTITLE:
- backtitle_opt = 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("--begin-x < -1", false);
- break;
- case BEGIN_Y:
- conf->y = (int)strtol(optarg, NULL, 10);
- if (conf->y < BSDDIALOG_CENTER)
- exit_error("--begin-y < -1", false);
- conf->auto_topmargin = 0;
- break;
- case BIKESHED:
- bikeshed_opt = true;
- break;
- case CANCEL_LABEL:
- conf->button.cancel_label = optarg;
- break;
- case CLEAR_DIALOG:
- conf->clear = true;
- break;
- case CLEAR_SCREEN:
- mandatory_dialog = false;
- clear_screen_opt = true;
- break;
- case COLORS:
- conf->text.highlight = true;
- break;
- case COLUMNS_PER_ROW:
- conf->text.cols_per_row =
- (u_int)strtoul(optarg, NULL, 10);
- break;
- case CR_WRAP:
- cr_wrap_opt = true;
- break;
- case DATE_FORMAT:
- date_fmt_opt = optarg;
- break;
- case DEFAULT_BUTTON:
- conf->button.default_label = optarg;
- break;
- case DEFAULT_ITEM:
- item_default_opt = optarg;
- break;
- case DEFAULT_NO:
- conf->button.default_cancel = true;
- break;
- case DISABLE_ESC:
- conf->key.enable_esc = false;
- break;
- case ESC_RETURNCANCEL:
- esc_return_cancel_opt = true;
- break;
- case EXIT_LABEL:
- conf->button.ok_label = optarg;
- break;
- case EXTRA_BUTTON:
- conf->button.with_extra = true;
- break;
- case EXTRA_LABEL:
- conf->button.extra_label = optarg;
- break;
- case GENERIC_BUTTON1:
- conf->button.generic1_label = optarg;
- break;
- case GENERIC_BUTTON2:
- conf->button.generic2_label = optarg;
- break;
- case HELP_BUTTON:
- conf->button.with_help = true;
- break;
- case HELP_LABEL:
- conf->button.help_label = optarg;
- break;
- case HELP_PRINT_NAME:
- item_help_print_name_opt = true;
- break;
- case HELP_STATUS:
- list_items_on_opt = 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:
- ignore_opt = true;
- break;
- case INSECURE:
- conf->form.securech = '*';
- break;
- case ITEM_BOTTOM_DESC:
- item_bottomdesc_opt = true;
- break;
- case ITEM_DEPTH:
- item_depth_opt = true;
- break;
- case ITEM_PREFIX:
- item_prefix_opt = true;
- break;
- case LOAD_THEME:
- loadthemefile = optarg;
- break;
- case MAX_INPUT:
- max_input_form_opt = (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:
- screen_mode_opt = "rmcup";
- break;
- case OK_LABEL:
- conf->button.ok_label = optarg;
- break;
- case OUTPUT_FD:
- output_fd_opt = (int)strtol(optarg, NULL, 10);
- break;
- case OUTPUT_SEPARATOR:
- item_output_sep_opt = optarg;
- break;
- case QUOTED:
- item_always_quote_opt = true;
- break;
- case PRINT_MAXSIZE:
- mandatory_dialog = false;
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
- dprintf(output_fd_opt, "MaxSize: %d, %d\n",
- ws.ws_row, ws.ws_col);
- break;
- case PRINT_SIZE:
- conf->get_height = &getH_opt;
- conf->get_width = &getW_opt;
- break;
- case PRINT_VERSION:
- mandatory_dialog = false;
- dprintf(output_fd_opt, "Version: %s\n",
- LIBBSDDIALOG_VERSION);
- break;
- case SAVE_THEME:
- mandatory_dialog = false;
- savethemefile = optarg;
- break;
- case SEPARATE_OUTPUT:
- item_output_sepnl_opt = true;
- break;
- case SHADOW:
- conf->shadow = true;
- break;
- case SINGLE_QUOTED:
- item_singlequote_opt = true;
- break;
- case SLEEP:
- conf->sleep = (u_int)strtoul(optarg, NULL, 10);
- break;
- case STDERR:
- output_fd_opt = STDERR_FILENO;
- break;
- case STDOUT:
- output_fd_opt = STDOUT_FILENO;
- break;
- case SWITCH_BUTTONS:
- conf->button.always_active = false;
- break;
- case TAB_ESCAPE:
- tab_escape_opt = true;
- break;
- case TAB_LEN:
- conf->text.tablen = (u_int)strtoul(optarg, NULL, 10);
- break;
- case TEXT_UNCHANGED:
- text_unchanged_opt = true;
- break;
- case THEME:
- if (strcasecmp(optarg, "bsddialog") == 0)
- theme_opt = BSDDIALOG_THEME_BSDDIALOG;
- else if (strcasecmp(optarg, "blackwhite") == 0)
- theme_opt = BSDDIALOG_THEME_BLACKWHITE;
- else if (strcasecmp(optarg, "flat") == 0)
- theme_opt = BSDDIALOG_THEME_FLAT;
- else if (strcasecmp(optarg, "dialog") == 0)
- theme_opt = BSDDIALOG_THEME_DIALOG;
- else
- exit_error("--theme: <unknown> theme", false);
- break;
- case TIME_FORMAT:
- time_fmt_opt = optarg;
- break;
- case TITLE:
- conf->title = optarg;
- break;
- /* Dialogs */
- case CALENDAR:
- if (dialogbuilder != NULL)
- exit_error("unexpected --calendar", true);
- dialogbuilder = calendar_builder;
- break;
- case CHECKLIST:
- if (dialogbuilder != NULL)
- exit_error("unexpected --checklist", true);
- dialogbuilder = checklist_builder;
- conf->auto_downmargin = 1;
- break;
- case DATEBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --datebox", true);
- dialogbuilder = datebox_builder;
- break;
- case FORM:
- if (dialogbuilder != NULL)
- exit_error("unexpected --form", true);
- dialogbuilder = form_builder;
- conf->auto_downmargin = 1;
- break;
- case GAUGE:
- if (dialogbuilder != NULL)
- exit_error("unexpected --gauge", true);
- dialogbuilder = gauge_builder;
- break;
- case INFOBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --infobox", true);
- dialogbuilder = infobox_builder;
- break;
- case INPUTBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --inputbox", true);
- dialogbuilder = inputbox_builder;
- conf->auto_downmargin = 1;
- break;
- case MENU:
- if (dialogbuilder != NULL)
- exit_error("unexpected --menu", true);
- dialogbuilder = menu_builder;
- conf->auto_downmargin = 1;
- break;
- case MIXEDFORM:
- if (dialogbuilder != NULL)
- exit_error("unexpected --mixedform", true);
- dialogbuilder = mixedform_builder;
- conf->auto_downmargin = 1;
- break;
- case MIXEDGAUGE:
- if (dialogbuilder != NULL)
- exit_error("unexpected --mixedgauge", true);
- dialogbuilder = mixedgauge_builder;
- break;
- case MSGBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --msgbox", true);
- dialogbuilder = msgbox_builder;
- break;
- case PAUSE:
- if (dialogbuilder != NULL)
- exit_error("unexpected --pause", true);
- dialogbuilder = pause_builder;
- break;
- case PASSWORDBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --passwordbox", true);
- dialogbuilder = passwordbox_builder;
- conf->auto_downmargin = 1;
- break;
- case PASSWORDFORM:
- if (dialogbuilder != NULL)
- exit_error("unexpected --passwordform", true);
- dialogbuilder = passwordform_builder;
- conf->auto_downmargin = 1;
- break;
- case RADIOLIST:
- if (dialogbuilder != NULL)
- exit_error("unexpected --radiolist", true);
- dialogbuilder = radiolist_builder;
- conf->auto_downmargin = 1;
- break;
- case RANGEBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --rangebox", true);
- dialogbuilder = rangebox_builder;
- break;
- case TEXTBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --textbox", true);
- dialogbuilder = textbox_builder;
- break;
- case TIMEBOX:
- if (dialogbuilder != NULL)
- exit_error("unexpected --timebox", true);
- dialogbuilder = timebox_builder;
- break;
- case TREEVIEW:
- if (dialogbuilder != NULL)
- exit_error("unexpected --treeview", true);
- dialogbuilder = treeview_builder;
- conf->auto_downmargin = 1;
- break;
- case YESNO:
- if (dialogbuilder != NULL)
- exit_error("unexpected --yesno", true);
- dialogbuilder = yesno_builder;
- break;
- default: /* Error */
- if (ignore_opt == true)
- break;
- exit_error("--ignore to continue", true);
- }
- }
-
- return (parsed);
-}
-
-int main(int argc, char *argv[argc])
-{
- int i, rows, cols, retval, parsed, nargc, firstoptind;
- char *text, **nargv, *pn;
- struct bsddialog_conf conf;
-
- setlocale(LC_ALL, "");
-
- in_bsddialog_mode = false;
- mandatory_dialog = true;
- 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);
- }
- }
-
- while (true) {
- parsed = parseargs(argc, argv, &conf);
- nargc = argc - parsed;
- nargv = argv + parsed;
- argc = parsed - optind;
- argv += optind;
-
- if (mandatory_dialog && dialogbuilder == NULL)
- exit_error("expected a --<dialog>", true);
-
- if (dialogbuilder == NULL && argc > 0)
- error_args("(no --<dialog>)", argc, argv);
-
- /* --print-maxsize or --print-version */
- if (mandatory_dialog == false && savethemefile == NULL &&
- clear_screen_opt == false)
- return (BSDDIALOG_OK);
-
- /* --<dialog>, --save-theme or clear-screen */
- if (dialogbuilder != NULL) {
- if (argc < 3)
- exit_error("expected <text> <rows> <cols>",
- true);
- if ((text = strdup(argv[0])) == NULL)
- exit_error("cannot allocate text", false);
- if (dialogbuilder != textbox_builder)
- custom_text(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 (screen_mode_opt != NULL) {
- screen_mode_opt = tigetstr(screen_mode_opt);
- if (screen_mode_opt != NULL &&
- screen_mode_opt != (char*)-1) {
- tputs(screen_mode_opt, 1, putchar);
- fflush(stdout);
- /* only to refresh, useless in the library */
- bsddialog_clearterminal();
- }
- }
-
- /* theme */
- if (theme_opt >= 0)
- bsddialog_set_default_theme(theme_opt);
- if (loadthemefile != NULL)
- loadtheme(loadthemefile);
- if (bikeshed_opt)
- bikeshed(&conf);
- if (savethemefile != NULL)
- savetheme(savethemefile, LIBBSDDIALOG_VERSION);
-
- /* backtitle and dialog */
- if (dialogbuilder == NULL)
- break;
- if (backtitle_opt != NULL)
- if(bsddialog_backtitle(&conf, backtitle_opt))
- exit_error(bsddialog_geterror(), false);
- retval = dialogbuilder(&conf, text, rows, cols, argc, argv);
- free(text);
- if (retval == BSDDIALOG_ERROR)
- exit_error(bsddialog_geterror(), false);
- if (retval == BSDDIALOG_ESC && esc_return_cancel_opt)
- retval = BSDDIALOG_CANCEL;
- if (conf.get_height != NULL && conf.get_width != NULL)
- dprintf(output_fd_opt, "DialogSize: %d, %d\n",
- *conf.get_height, *conf.get_width);
- if (clear_screen_opt)
- bsddialog_clearterminal();
- clear_screen_opt = 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 (in_bsddialog_mode) {
- /* --clear-screen can be a single option */
- if (clear_screen_opt)
- bsddialog_clearterminal();
- bsddialog_end();
- }
- /* end bsddialog terminal mode */
-
- return (retval);
-}
-
-void custom_text(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 = cr_wrap_opt;
- }
- if (text_unchanged_opt) {
- 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 (tab_escape_opt) {
- buf[j] = '\t';
- } else {
- j++;
- buf[j] = 't';
- }
- i++;
- break;
- }
- break;
- case '\n':
- buf[j] = crwrap ? '\n' : ' ';
- break;
- case '\t':
- buf[j] = text_unchanged_opt ? '\t' : ' ';
- break;
- default:
- buf[j] = text[i];
- }
- i++;
- if (!trim || buf[j] != ' ' || j == 0 || buf[j-1] != ' ')
- j++;
- }
- buf[j] = '\0';
-}
-
-/* Dialogs */
-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("--gauge", argc - 1, argv + 1);
- }
-
- output = bsddialog_gauge(conf, text, rows, cols, perc, STDIN_FILENO,
- "XXX");
-
- return (output);
-}
-
-int infobox_builder(BUILDER_ARGS)
-{
- if (argc > 0)
- error_args("--infobox", argc, argv);
-
- return (bsddialog_infobox(conf, text, rows, cols));
-}
-
-int mixedgauge_builder(BUILDER_ARGS)
-{
- int output, *minipercs;
- unsigned int i, mainperc, nminibars;
- const char **minilabels;
-
- if (argc < 1 || (((argc-1) % 2) != 0) )
- exit_error("bad --mixedgauge arguments", true);
-
- 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("Cannot allocate memory for minilabels", false);
- if ((minipercs = calloc(nminibars, sizeof(int))) == NULL)
- exit_error("Cannot allocate memory for minipercs", false);
-
- for (i = 0; i < nminibars; i++) {
- minilabels[i] = argv[i * 2];
- minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
- }
-
- output = bsddialog_mixedgauge(conf, text, rows, cols, mainperc,
- nminibars, minilabels, minipercs);
-
- return (output);
-}
-
-int msgbox_builder(BUILDER_ARGS)
-{
- if (argc > 0)
- error_args("--msgbox", argc, argv);
-
- return (bsddialog_msgbox(conf, text, rows, cols));
-}
-
-int pause_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int secs;
-
- if (argc == 0)
- exit_error("--pause missing <seconds>", true);
- if (argc > 1)
- error_args("--pause", 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("--rangebox missing <min> <max> [<init>]", true);
- 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);
- dprintf(output_fd_opt, "%d", value);
-
- return (output);
-}
-
-int textbox_builder(BUILDER_ARGS)
-{
- if (argc > 0)
- error_args("--textbox", argc, argv);
-
- return (bsddialog_textbox(conf, text, rows, cols));
-}
-
-int yesno_builder(BUILDER_ARGS)
-{
- if (argc > 0)
- error_args("--yesno", argc, argv);
-
- return (bsddialog_yesno(conf, text, rows, cols));
-}
-
-/* CALENDAR, DATE and TIME */
-static int date(BUILDER_ARGS, bool is_datebox)
-{
- int ret;
- unsigned int yy, mm, dd;
- time_t cal;
- struct tm *localtm;
- char stringdate[1024];
- const char *name;
-
- name = is_datebox ? "--datebox" : "--calendar";
- time(&cal);
- localtm = localtime(&cal);
- yy = localtm->tm_year + 1900;
- mm = localtm->tm_mon + 1;
- dd = localtm->tm_mday;
-
- if (argc > 3) {
- error_args(name, argc - 3, argv + 3);
- } else if (argc == 3) {
- 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 (yy < 1900)
- yy = 1900;
- /* max yy check is in lib */
- }
-
- if (is_datebox)
- ret = bsddialog_datebox(conf, text, rows, cols, &yy, &mm, &dd);
- else
- ret = bsddialog_calendar(conf, text, rows, cols, &yy, &mm, &dd);
- if (ret != BSDDIALOG_OK)
- return (ret);
-
- if (date_fmt_opt != NULL) {
- time(&cal);
- localtm = localtime(&cal);
- localtm->tm_year = yy - 1900;
- localtm->tm_mon = mm - 1;
- localtm->tm_mday = dd;
- strftime(stringdate, 1024, date_fmt_opt, localtm);
- dprintf(output_fd_opt, "%s", stringdate);
- } else if (bikeshed_opt && (dd % 2 == 0)) {
- dprintf(output_fd_opt, "%u/%u/%u", dd, mm, yy);
- } else {
- dprintf(output_fd_opt, "%02u/%02u/%u", dd, mm, yy);
- }
-
- return (ret);
-}
-
-int calendar_builder(BUILDER_ARGS)
-{
- if (rows == 2) {
- /*
- * (bsdconfig/share/dialog.subr:1352) f_dialog_calendar_size()
- * computes height 2 for `dialog --calendar' in
- * (bsdconfig/usermgmt/share/user_input.subr:517)
- * f_dialog_input_expire_password() and
- * (bsdconfig/usermgmt/share/user_input.subr:660)
- * f_dialog_input_expire_account().
- * Use height auto-sizing that is min height like dialog,
- * documented in bsddialog(1).
- */
- rows = 0;
- }
-
- return (date(conf, text, rows, cols, argc, argv, false));
-}
-
-int datebox_builder(BUILDER_ARGS)
-{
- return (date(conf, text, rows, cols, argc, argv, true));
-}
-
-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 (output != BSDDIALOG_OK)
- return (output);
-
- if (time_fmt_opt != NULL) {
- time(&clock);
- localtm = localtime(&clock);
- localtm->tm_hour = hh;
- localtm->tm_min = mm;
- localtm->tm_sec = ss;
- strftime(stringtime, 1024, time_fmt_opt, localtm);
- dprintf(output_fd_opt, "%s", stringtime);
- } else if (bikeshed_opt && (ss % 2 == 0)) {
- dprintf(output_fd_opt, "%u:%u:%u", hh, mm, ss);
- } else {
- dprintf(output_fd_opt, "%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)
-{
- 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("\"menu\" bad arguments items number", true);
-
- *nitems = argc / sizeitem;
-
- *items = calloc(*nitems, sizeof(struct bsddialog_menuitem));
- if (items == NULL)
- exit_error("cannot allocate memory \"menu\" items", false);
-
- j = 0;
- for (i = 0; i < *nitems; i++) {
- (*items)[i].prefix = setprefix ? argv[j++] : "";
- (*items)[i].depth = setdepth ?
- (u_int)strtoul(argv[j++], NULL, 0) : 0;
- (*items)[i].name = setname ? argv[j++] : "";
- (*items)[i].desc = setdesc ? argv[j++] : "";
- if (setstatus)
- (*items)[i].on = strcmp(argv[j++], "on") == 0 ?
- true : false;
- else
- (*items)[i].on = false;
- (*items)[i].bottomdesc = sethelp ? argv[j++] : "";
-
- if (item_default_opt != NULL && *focusitem == -1)
- if (strcmp((*items)[i].name, item_default_opt) == 0)
- *focusitem = i;
- }
-}
-
-static void
-print_menu_items(int output, int nitems, struct bsddialog_menuitem *items,
- int focusitem, bool ismenu)
-{
- bool sep, sepfirst, seplast, toquote;
- int i;
- char quotech;
- const char *focusname, *sepstr;
-
- sep = false;
- quotech = item_singlequote_opt ? '\'' : '"';
-
- if (output == BSDDIALOG_ERROR || output == BSDDIALOG_CANCEL ||
- output == BSDDIALOG_ESC)
- return;
-
- if (output == BSDDIALOG_HELP) {
- dprintf(output_fd_opt, "HELP ");
-
- if (focusitem >= 0) {
- focusname = items[focusitem].name;
- if (item_bottomdesc_opt &&
- item_help_print_name_opt == false)
- focusname = items[focusitem].bottomdesc;
-
- toquote = false;
- if (strchr(focusname, ' ') != NULL) {
- toquote = item_always_quote_opt;
- if (ismenu == false &&
- item_output_sepnl_opt == false)
- toquote = true;
- }
- if (toquote) {
- dprintf(output_fd_opt, "%c%s%c",
- quotech, focusname, quotech);
- } else
- dprintf(output_fd_opt, "%s", focusname);
- }
-
- if (ismenu || list_items_on_opt == false)
- return;
- sep = true;
- }
-
- sepfirst = false;
- if ((sepstr = item_output_sep_opt) == NULL)
- sepstr = item_output_sepnl_opt ? "\n" : " ";
- else
- sepfirst = true;
-
- seplast = false;
- if (item_output_sepnl_opt) {
- sepfirst = false;
- seplast = true;
- }
-
- for (i = 0; i < nitems; i++) {
- if (items[i].on == false)
- continue;
-
- if (sep || sepfirst)
- dprintf(output_fd_opt, "%s", sepstr);
- sep = false;
-
- toquote = false;
- if (strchr(items[i].name, ' ') != NULL) {
- toquote = item_always_quote_opt;
- if (ismenu == false && item_output_sepnl_opt == false)
- toquote = true;
- }
- if (toquote)
- dprintf(output_fd_opt, "%c%s%c",
- quotech, items[i].name, quotech);
- else
- dprintf(output_fd_opt, "%s", items[i].name);
-
- if (seplast)
- dprintf(output_fd_opt, "%s", sepstr);
- }
-}
-
-int checklist_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1)
- exit_error("--checklist missing <menurows>", true);
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
- true, true, item_bottomdesc_opt, &nitems, &items, &focusitem);
-
- output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem, false);
-
- free(items);
-
- return (output);
-}
-
-int menu_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1)
- exit_error("--menu missing <menurows>", true);
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
- true, false, item_bottomdesc_opt, &nitems, &items, &focusitem);
-
- output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem, true);
-
- free(items);
-
- return (output);
-}
-
-int radiolist_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1)
- exit_error("--radiolist missing <menurows>", true);
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- get_menu_items(argc-1, argv+1, item_prefix_opt, item_depth_opt, true,
- true, true, item_bottomdesc_opt, &nitems, &items, &focusitem);
-
- output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
- items, &focusitem);
-
- print_menu_items(output, nitems, items, focusitem, false);
-
- free(items);
-
- return (output);
-}
-
-int treeview_builder(BUILDER_ARGS)
-{
- int output, focusitem;
- unsigned int menurows, nitems;
- struct bsddialog_menuitem *items;
-
- if (argc < 1)
- exit_error("--treeview missing <menurows>", true);
- menurows = (u_int)strtoul(argv[0], NULL, 10);
-
- get_menu_items(argc-1, argv+1, item_prefix_opt, true, true, true, true,
- item_bottomdesc_opt, &nitems, &items, &focusitem);
-
- 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, false);
-
- free(items);
-
- return (output);
-}
-
-/* FORM */
-static void
-print_form_items(int output, int nitems, struct bsddialog_formitem *items)
-{
- int i;
-
- if (output == BSDDIALOG_ERROR)
- return;
-
- for (i = 0; i < nitems; i++) {
- dprintf(output_fd_opt, "%s\n", items[i].value);
- free(items[i].value);
- }
-}
-
-int form_builder(BUILDER_ARGS)
-{
- int output, fieldlen, valuelen;
- unsigned int i, j, flags, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- if (argc < 1)
- exit_error("--form missing <formheight>", true);
- formheight = (u_int)strtoul(argv[0], NULL, 10);
-
- argc--;
- argv++;
- sizeitem = item_bottomdesc_opt ? 9 : 8;
- if (argc % sizeitem != 0)
- exit_error("--form bad number of arguments items", true);
-
- nitems = argc / sizeitem;
- if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
- exit_error("cannot allocate memory for form items", false);
- j = 0;
- for (i = 0; i < nitems; i++) {
- items[i].label = argv[j++];
- items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].init = argv[j++];
- items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
-
- fieldlen = (int)strtol(argv[j++], NULL, 10);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = (int)strtol(argv[j++], NULL, 10);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags = (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
-
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
-
-int inputbox_builder(BUILDER_ARGS)
-{
- int output;
- struct bsddialog_formitem item;
-
- 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 = max_input_form_opt;
- item.flags = BSDDIALOG_FIELDNOCOLOR;
- item.flags |= BSDDIALOG_FIELDCURSOREND;
- item.flags |= BSDDIALOG_FIELDEXTEND;
- item.bottomdesc = "";
-
- output = bsddialog_form(conf, text, rows, cols, 1, 1, &item);
- print_form_items(output, 1, &item);
-
- return (output);
-}
-
-int mixedform_builder(BUILDER_ARGS)
-{
- int output;
- unsigned int i, j, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- if (argc < 1)
- exit_error("--mixedform missing <formheight>", true);
- formheight = (u_int)strtoul(argv[0], NULL, 10);
-
- argc--;
- argv++;
- sizeitem = item_bottomdesc_opt ? 10 : 9;
- if (argc % sizeitem != 0)
- exit_error("--mixedform bad number of arguments items", true);
-
- nitems = argc / sizeitem;
- if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
- exit_error("cannot allocate memory for form items", false);
- j = 0;
- for (i = 0; i < nitems; i++) {
- items[i].label = argv[j++];
- items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].init = argv[j++];
- items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].fieldlen = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].maxvaluelen = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].flags = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
-
-int passwordbox_builder(BUILDER_ARGS)
-{
- int output;
- struct bsddialog_formitem item;
-
- 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 = max_input_form_opt;
- 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);
- print_form_items(output, 1, &item);
-
- return (output);
-}
-
-int passwordform_builder(BUILDER_ARGS)
-{
- int output, fieldlen, valuelen;
- unsigned int i, j, flags, formheight, nitems, sizeitem;
- struct bsddialog_formitem *items;
-
- if (argc < 1)
- exit_error("--passwordform missing <formheight>", true);
- formheight = (u_int)strtoul(argv[0], NULL, 10);
-
- argc--;
- argv++;
- sizeitem = item_bottomdesc_opt ? 9 : 8;
- if (argc % sizeitem != 0)
- exit_error("--passwordform bad arguments items number", true);
-
- flags = BSDDIALOG_FIELDHIDDEN;
- nitems = argc / sizeitem;
- if ((items = calloc(nitems, sizeof(struct bsddialog_formitem))) == NULL)
- exit_error("cannot allocate memory for form items", false);
- j = 0;
- for (i = 0; i < nitems; i++) {
- items[i].label = argv[j++];
- items[i].ylabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xlabel = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].init = argv[j++];
- items[i].yfield = (u_int)strtoul(argv[j++], NULL, 10);
- items[i].xfield = (u_int)strtoul(argv[j++], NULL, 10);
-
- fieldlen = (int)strtol(argv[j++], NULL, 10);
- items[i].fieldlen = abs(fieldlen);
-
- valuelen = (int)strtol(argv[j++], NULL, 10);
- items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
-
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
- items[i].flags = flags;
-
- items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
- }
-
- output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
- items);
- print_form_items(output, nitems, items);
- free(items);
-
- return (output);
-}
diff --git a/examples_library/calendar.c b/examples_library/calendar.c
index 33e38c69a81b..5899fc4986fd 100644
--- a/examples_library/calendar.c
+++ b/examples_library/calendar.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
int main()
@@ -31,25 +30,16 @@ int main()
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();
-
- switch (output) {
- case BSDDIALOG_OK:
- printf("Date: %u/%u/%u", yy, mm, dd);
- break;
- case BSDDIALOG_CANCEL:
- printf("Cancel");
- break;
- case BSDDIALOG_ERROR:
- printf("Error: %s", bsddialog_geterror());
- break;
+ if (output == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
}
- printf("\n");
- return (output);
+ 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 6d860b91a076..a2b178d14270 100644
--- a/examples_library/checklist.c
+++ b/examples_library/checklist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,27 +27,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "checklist";
output = bsddialog_checklist(&conf, "Example", 15, 30, 5, 5, items,
NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Checklist:\n");
for (i = 0; i < 5; i++)
printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/compile b/examples_library/compile
index 4cb6d23bd6a6..9025f35426d9 100755
--- a/examples_library/compile
+++ b/examples_library/compile
@@ -10,7 +10,7 @@
libpath=../lib
examples="menu checklist radiolist mixedlist theme infobox yesno msgbox \
- datebox form timebox rangebox pause calendar"
+ datebox form timebox rangebox pause calendar gauge mixedgauge"
rm -f $examples
diff --git a/examples_library/datebox.c b/examples_library/datebox.c
index 7f0138688d53..e0741319d388 100644
--- a/examples_library/datebox.c
+++ b/examples_library/datebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
int main()
@@ -31,25 +30,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "datebox";
output = bsddialog_datebox(&conf, "Example", 9, 35, &yy, &mm, &dd);
-
bsddialog_end();
-
- switch (output) {
- case BSDDIALOG_OK:
- printf("Date: %u/%u/%u", yy, mm, dd);
- break;
- case BSDDIALOG_CANCEL:
- printf("Cancel");
- break;
- case BSDDIALOG_ERROR:
- printf("Error: %s", bsddialog_geterror());
- break;
+ if (output == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
}
- printf("\n");
+ printf("Date: %u/%u/%u\n", yy, mm, dd);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/form.c b/examples_library/form.c
index 4780fb68d121..4c6336610852 100644
--- a/examples_library/form.c
+++ b/examples_library/form.c
@@ -12,7 +12,6 @@
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#define H BSDDIALOG_FIELDHIDDEN
#define RO BSDDIALOG_FIELDREADONLY
@@ -37,23 +36,17 @@ int main()
bsddialog_initconf(&conf);
conf.title = "form";
conf.form.securech = '*';
- output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items);
+ output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items, NULL);
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
for (i = 0; i < 3; i++) {
printf("%s \"%s\"\n", items[i].label, items[i].value);
free(items[i].value);
}
- return (output);
+ 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 7334cd7536bf..bbd7f665d5a6 100644
--- a/examples_library/infobox.c
+++ b/examples_library/infobox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,18 +20,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "infobox";
conf.sleep = 3;
output = bsddialog_infobox(&conf, "Example\n(3 seconds)", 7, 20);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/menu.c b/examples_library/menu.c
index 044e0030a010..5c4941f6d5de 100644
--- a/examples_library/menu.c
+++ b/examples_library/menu.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,26 +27,18 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "menu";
output = bsddialog_menu(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Menu:\n");
for (i = 0; i < 5; i++)
printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/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 30198d20a155..6d286996931b 100644
--- a/examples_library/mixedlist.c
+++ b/examples_library/mixedlist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -40,34 +39,26 @@ int main()
{ "", false, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
};
struct bsddialog_menugroup group[4] = {
- { BSDDIALOG_SEPARATOR, 1, sep1 },
- { BSDDIALOG_CHECKLIST, 5, check },
- { BSDDIALOG_SEPARATOR, 2, sep2 },
- { BSDDIALOG_RADIOLIST, 5, radio }
+ { BSDDIALOG_SEPARATOR, 1, sep1, 0 },
+ { BSDDIALOG_CHECKLIST, 5, check, 0 },
+ { BSDDIALOG_SEPARATOR, 2, sep2, 0 },
+ { BSDDIALOG_RADIOLIST, 5, radio, 0 }
};
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "mixedlist";
output = bsddialog_mixedlist(&conf, "Example", 20, 0, 13, 4, group,
NULL, NULL);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Mixedlist:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < group[i].nitems; j++) {
@@ -83,5 +74,5 @@ int main()
}
}
- return (output);
-} \ No newline at end of file
+ return (0);
+}
diff --git a/examples_library/msgbox.c b/examples_library/msgbox.c
index 7d14073143ca..988e2976ee8e 100644
--- a/examples_library/msgbox.c
+++ b/examples_library/msgbox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,21 +20,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "msgbox";
output = bsddialog_msgbox(&conf, "Example", 7, 20);
-
bsddialog_end();
switch (output) {
case BSDDIALOG_ERROR:
printf("Error %s\n", bsddialog_geterror());
- break;
+ return (1);
case BSDDIALOG_OK:
- printf("OK\n");
+ printf("[OK]\n");
break;
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/pause.c b/examples_library/pause.c
index 1cd64f24a0cd..fd79d33aa4c0 100644
--- a/examples_library/pause.c
+++ b/examples_library/pause.c
@@ -10,38 +10,37 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
int output;
+ unsigned int sec;
struct bsddialog_conf conf;
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "pause";
- output = bsddialog_pause(&conf, "Example", 8, 50, 10);
-
+ sec = 10;
+ output = bsddialog_pause(&conf, "Example", 8, 50, &sec);
bsddialog_end();
switch (output) {
+ case BSDDIALOG_ERROR:
+ printf("Error: %s\n", bsddialog_geterror());
+ return (1);
case BSDDIALOG_OK:
- printf("OK\n");
+ printf("[OK] remaining time: %u\n", sec);
break;
case BSDDIALOG_CANCEL:
- printf("Cancel\n");
- break;
- case BSDDIALOG_ERROR:
- printf("Error: %s\n", bsddialog_geterror());
+ printf("[Cancel] remaining time: %u\n", sec);
break;
case BSDDIALOG_TIMEOUT:
printf("Timeout\n");
break;
}
- return (output);
-} \ No newline at end of file
+ return (0);
+}
diff --git a/examples_library/radiolist.c b/examples_library/radiolist.c
index ac8ed5bb4064..09df32ac2e74 100644
--- a/examples_library/radiolist.c
+++ b/examples_library/radiolist.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -28,26 +27,19 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "radiolist";
- output = bsddialog_radiolist(&conf, "Example", 15, 30, 5, 5, items, NULL);
-
+ output = bsddialog_radiolist(&conf, "Example", 15, 30, 5, 5, items,
+ NULL);
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
printf("Radiolist:\n");
for (i = 0; i < 5; i++)
printf(" (%c) %s\n", items[i].on ? '*' : ' ', items[i].name);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/rangebox.c b/examples_library/rangebox.c
index 8e6bf91c35a6..50498c459fc6 100644
--- a/examples_library/rangebox.c
+++ b/examples_library/rangebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,20 +20,16 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "rangebox";
value = 5;
output = bsddialog_rangebox(&conf, "Example", 8, 50, 0, 10, &value);
-
bsddialog_end();
-
if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
printf("Value: %d\n", value);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/theme.c b/examples_library/theme.c
index fcc5fd5cc31a..689633e624ed 100644
--- a/examples_library/theme.c
+++ b/examples_library/theme.c
@@ -11,64 +11,54 @@
#include <bsddialog.h>
#include <bsddialog_theme.h>
#include <stdio.h>
-#include <string.h>
int main()
{
int output, focusitem;
struct bsddialog_conf conf;
enum bsddialog_default_theme theme;
- struct bsddialog_menuitem items[5] = {
- {"", false, 0, "Flat", "dialog-like",
- "BSDDIALOG_THEME_FLAT" },
- {"", false, 0, "Dialog", "dialog clone",
- "BSDDIALOG_THEME_DIALOG" },
- {"", false, 0, "BSDDialog", "new theme",
- "BSDDIALOG_THEME_BSDDIALOG" },
- {"", false, 0, "BlackWhite","black and white",
- "BSDDIALOG_THEME_BLACKWHITE" },
- {"", false, 0, "Quit", "Exit", "Quit or Cancel to exit" }
+ struct bsddialog_menuitem items[4] = {
+ {"", false, 0, "Flat", "default flat theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_FLAT" },
+ {"", false, 0, "3D", "pseudo 3D theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_3D" },
+ {"", false, 0, "BlackWhite","black and white theme",
+ "enum bsddialog_default_theme BSDDIALOG_THEME_BLACKWHITE" },
+ {"", false, 0, "Quit", "Exit", "Quit, Cancel or ESC to exit" }
};
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
-
+ conf.ascii_lines = true;
bsddialog_backtitle(&conf, "Theme Example");
-
+ bsddialog_initconf(&conf);
+ conf.key.enable_esc = true;
conf.title = " Theme ";
focusitem = -1;
while (true) {
- output = bsddialog_menu(&conf, "Choose theme", 15, 45, 5, 5,
+ output = bsddialog_menu(&conf, "Choose theme", 15, 45, 4, 4,
items, &focusitem);
- if (output != BSDDIALOG_OK || items[4].on)
+ if (output != BSDDIALOG_OK || items[3].on)
break;
if (items[0].on) {
theme = BSDDIALOG_THEME_FLAT;
focusitem = 0;
- }
- else if (items[1].on) {
- theme = BSDDIALOG_THEME_DIALOG;
+ } else if (items[1].on) {
+ theme = BSDDIALOG_THEME_3D;
focusitem = 1;
- }
- else if (items[2].on) {
- theme = BSDDIALOG_THEME_BSDDIALOG;
- focusitem = 2;
- }
- else if (items[3].on) {
+ } else if (items[2].on) {
theme = BSDDIALOG_THEME_BLACKWHITE;
- focusitem = 3;
+ focusitem = 2;
}
-
bsddialog_set_default_theme(theme);
}
bsddialog_end();
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/timebox.c b/examples_library/timebox.c
index f06986423558..a9354c99c9be 100644
--- a/examples_library/timebox.c
+++ b/examples_library/timebox.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
#include <time.h>
int main()
@@ -31,24 +30,15 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "timebox";
output = bsddialog_timebox(&conf, "Example", 9, 35, &hh, &mm, &ss);
-
bsddialog_end();
-
- switch (output) {
- case BSDDIALOG_OK:
- printf("Time: [%u:%u:%u]\n", hh, mm, ss);
- break;
- case BSDDIALOG_CANCEL:
- printf("Cancel\n");
- break;
- case BSDDIALOG_ERROR:
+ if (output == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
- break;
+ return (1);
}
+ printf("Time: %u:%u:%u\n", hh, mm, ss);
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_library/yesno.c b/examples_library/yesno.c
index 364a6c77fc26..36cb59fa013b 100644
--- a/examples_library/yesno.c
+++ b/examples_library/yesno.c
@@ -10,7 +10,6 @@
#include <bsddialog.h>
#include <stdio.h>
-#include <string.h>
int main()
{
@@ -21,24 +20,22 @@ int main()
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "yesno";
output = bsddialog_yesno(&conf, "Example", 7, 25);
-
bsddialog_end();
switch (output) {
case BSDDIALOG_ERROR:
printf("Error %s\n", bsddialog_geterror());
- break;
+ return (1);
case BSDDIALOG_YES:
- printf("YES\n");
+ printf("[YES]\n");
break;
case BSDDIALOG_NO:
- printf("NO\n");
+ printf("[NO]\n");
break;
}
- return (output);
+ return (0);
} \ No newline at end of file
diff --git a/examples_utility/checklist.sh b/examples_utility/checklist.sh
index fefabc282c80..7ff525cf765d 100755
--- a/examples_utility/checklist.sh
+++ b/examples_utility/checklist.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEMS=$(./bsddialog --title " checklist " --checklist "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" on \
- "Tag 2" "DESC 2 xyz" off \
- "Tag 3" "DESC 3 xyz" on \
- "Tag 4" "DESC 4 xyz" off \
- "Tag 5" "DESC 5 xyz" on \
+ "1 Name" "DESC 1 xyz" on \
+ "2 Name" "DESC 2 xyz" off \
+ "3 Name" "DESC 3 xyz" on \
+ "4 Name" "DESC 4 xyz" off \
+ "5 Name" "DESC 5 xyz" on \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -27,12 +27,12 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] focus: $ITEMS"
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] focus: $ITEMS"
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK] Selected: $ITEMS"
+ echo "[OK] $ITEMS"
;;
esac
diff --git a/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 783993d3db30..ee25fa9cf352 100755
--- a/examples_utility/form.sh
+++ b/examples_utility/form.sh
@@ -33,8 +33,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/examples_utility/infobox.sh b/examples_utility/infobox.sh
index ff39ad4d5f0e..b782e8cbf69e 100755
--- a/examples_utility/infobox.sh
+++ b/examples_utility/infobox.sh
@@ -9,4 +9,4 @@
# worldwide. This software is distributed without any warranty, see:
# <http://creativecommons.org/publicdomain/zero/1.0/>.
-./bsddialog --sleep 3 --title " infobox " --infobox "Hello World!\n3 secs" 6 20
+./bsddialog --normal-screen --title " infobox " --infobox "Hello World!" 6 20
diff --git a/examples_utility/inputbox.sh b/examples_utility/inputbox.sh
index a359a3b8e833..756aec3c0241 100755
--- a/examples_utility/inputbox.sh
+++ b/examples_utility/inputbox.sh
@@ -28,9 +28,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORM"
;;
esac
-
-echo "$FORM"
-
diff --git a/examples_utility/menu.sh b/examples_utility/menu.sh
index 002a82f6a870..5b2f090037d8 100755
--- a/examples_utility/menu.sh
+++ b/examples_utility/menu.sh
@@ -15,10 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEM=$(./bsddialog --title " menu " --menu "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" \
- "Tag 2" "DESC 2 xyz" \
- "Tag 3" "DESC 3 xyz" \
- "Tag 4" "DESC 4 xyz" \
+ "1 Name" "DESC 1 xyz" \
+ "2 Name" "DESC 2 xyz" \
+ "3 Name" "DESC 3 xyz" \
+ "4 Name" "DESC 4 xyz" \
+ "5 Name" "DESC 5 xyz" \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -26,10 +27,10 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] $ITEM"
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] $ITEM"
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
echo "[OK] $ITEM"
diff --git a/examples_utility/mixedform.sh b/examples_utility/mixedform.sh
index 8a96fa8d9e72..6b690e7e5b8c 100755
--- a/examples_utility/mixedform.sh
+++ b/examples_utility/mixedform.sh
@@ -32,8 +32,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/examples_utility/mixedgauge.sh b/examples_utility/mixedgauge.sh
index e98ff70614db..aa4ff2910cd9 100755
--- a/examples_utility/mixedgauge.sh
+++ b/examples_utility/mixedgauge.sh
@@ -10,11 +10,11 @@
# <http://creativecommons.org/publicdomain/zero/1.0/>.
perc=0
+mainperc=50
while [ $perc -le 100 ]
do
./bsddialog --sleep 1 --title " mixedgauge " \
- --mixedgauge "Example..." 20 45 $perc \
- "(Hidden)" " -9" \
+ --mixedgauge "Example..." 20 45 $mainperc \
"Label 1" " -1" \
"Label 2" " -2" \
"Label 3" " -3" \
@@ -23,9 +23,11 @@ do
"Label 6" " -6" \
"Label 7" " -7" \
"Label 8" " -8" \
- "Label 9" " -10" \
- "Label 10" " -11" \
+ "Label 9" " -9" \
+ "Label 10" " -10" \
+ "Label 11" " -11" \
"Label X" $perc
perc=`expr $perc + 20`
+ mainperc=`expr $mainperc + 10`
done
diff --git a/examples_utility/passwordbox.sh b/examples_utility/passwordbox.sh
index 0f93a13c877c..b43ef6f6b994 100755
--- a/examples_utility/passwordbox.sh
+++ b/examples_utility/passwordbox.sh
@@ -29,8 +29,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORM"
;;
esac
-
-echo "$FORM"
diff --git a/examples_utility/passwordform.sh b/examples_utility/passwordform.sh
index 9bfe11a28645..874a185ee66f 100755
--- a/examples_utility/passwordform.sh
+++ b/examples_utility/passwordform.sh
@@ -34,8 +34,6 @@ case $? in
echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $FORMS"
;;
esac
-
-echo "$FORMS"
diff --git a/examples_utility/radiolist.sh b/examples_utility/radiolist.sh
index 9de483369c75..359473abf35e 100755
--- a/examples_utility/radiolist.sh
+++ b/examples_utility/radiolist.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
ITEM=$(./bsddialog --title " radiolist " --radiolist "Hello World!" 15 30 5 \
- "Tag 1" "DESC 1 xyz" off \
- "Tag 2" "DESC 2 xyz" off \
- "Tag 3" "DESC 3 xyz" on \
- "Tag 4" "DESC 4 xyz" off \
- "Tag 5" "DESC 5 xyz" off \
+ "1 Name" "DESC 1 xyz" off \
+ "2 Name" "DESC 2 xyz" off \
+ "3 Name" "DESC 3 xyz" on \
+ "4 Name" "DESC 4 xyz" off \
+ "5 Name" "DESC 5 xyz" off \
3>&1 1>&2 2>&3 3>&-)
case $? in
@@ -27,14 +27,12 @@ case $? in
exit 1
;;
$BSDDIALOG_ESC )
- echo "[ESC] focus "
+ echo "[ESC]"
;;
$BSDDIALOG_CANCEL )
- echo "[Cancel] focus "
+ echo "[Cancel]"
;;
$BSDDIALOG_OK )
- echo "[OK]"
+ echo "[OK] $ITEM"
;;
esac
-
-echo "$ITEM"
diff --git a/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/lib/GNUMakefile b/lib/GNUmakefile
index 3c31c78fdf88..7c7a9bc25ee4 100644
--- a/lib/GNUMakefile
+++ b/lib/GNUmakefile
@@ -3,16 +3,19 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.4
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
-SOURCES = barbox.c calendarbox.c formbox.c infobox.c libbsddialog.c \
- lib_util.c menubox.c messagebox.c textbox.c theme.c timebox.c
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
OBJECTS = $(SOURCES:.c=.o)
-CFLAGS = -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE -D_GNU_SOURCE -Wall -Wextra \
- -Wno-implicit-fallthrough -Werror -fpic
-LDFLAGS = -lncursesw -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 0f536fb38743..252b33f79848 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -3,39 +3,27 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.4
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
LIBRARY_A = lib${LIBRARY:=.a}
HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
-SOURCES = barbox.c calendarbox.c formbox.c infobox.c libbsddialog.c \
- lib_util.c menubox.c messagebox.c textbox.c theme.c timebox.c
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
OBJECTS = ${SOURCES:.c=.o}
-CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
- -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
- -L/usr/lib -lncursesw -ltinfow
.if defined(DEBUG)
-# `make -DDEBUG`
-CFLAGS = -g -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-.else
-CFLAGS += -std=gnu99 -fstack-protector-strong
+CFLAGS += -g
.endif
+CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra -std=gnu99 \
+ -fstack-protector-strong
+LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
+ -L/usr/lib -lncursesw -ltinfow
-LOCALBASE = /usr/local
LN = ln -s -f
RM = rm -f
-CP = cp
-GZIP = gzip -cn
-LDCONFIG = /sbin/ldconfig -m
-MAN = ${OUTPUT}.3
-GZIP = gzip -cn
-MANDIR = ${LOCALBASE}/share/man/man3
-INSTALL = install
-RM = rm -f
-all : man ${LIBRARY}
+all : ${LIBRARY}
${LIBRARY}: ${LIBRARY_SO} ${LIBRARY_A}
@@ -52,24 +40,5 @@ ${LIBRARY_A}: ${OBJECTS}
.c.o:
${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
-man:
- ${GZIP} ${LIBRARY}.3 > ${LIBRARY}.3.gz
-
clean:
${RM} ${LIBRARY_SO}* *.o *~ *.gz ${LIBRARY_A}
-
-
-install:
- ${INSTALL} -m 644 ${HEADERS} ${LOCALBASE}/include
- ${INSTALL} -m 644 -s ${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/
- ${INSTALL} -l rs ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${INSTALL} -m 644 ${LIBRARY_A} ${LOCALBASE}/lib
- ${LDCONFIG} ${LOCALBASE}/lib
- ${INSTALL} -m 644 ${LIBRARY}.3.gz ${MANDIR}
-
-unistall:
- ${RM} ${LOCALBASE}/include/${LIBRARY}*.h
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION}
- ${LDCONFIG} ${LOCALBASE}/lib
- ${RM} ${MANDIR}/${LIBRARY}.3.gz
diff --git a/lib/barbox.c b/lib/barbox.c
index 71759839a709..cd9fee836f8a 100644
--- a/lib/barbox.c
+++ b/lib/barbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,9 +25,6 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
@@ -39,139 +36,138 @@
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define BARPADDING 2
-#define MINBARLEN 15
-#define MINBARWIDTH (2 + 2 * BARPADDING + MINBARLEN)
-#define MINMGBARLEN 18
-#define MINMGBARWIDTH (2 + 2 * BARPADDING + MINMGBARLEN)
+#define BARPADDING 2 /* 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;
-int bsddialog_total_progview;
-
-static void
-draw_bar(WINDOW *win, int y, int x, int barlen, int perc, bool withlabel,
- int label)
+long long int bsddialog_total_progview;
+
+static const char states[12][14] = {
+ " Succeeded ", /* -1 */
+ " Failed ", /* -2 */
+ " Passed ", /* -3 */
+ " Completed ", /* -4 */
+ " Checked ", /* -5 */
+ " Done ", /* -6 */
+ " Skipped ", /* -7 */
+ " In Progress ", /* -8 */
+ "(blank) ", /* -9 */
+ " N/A ", /* -10 */
+ " Pending ", /* -11 */
+ " UNKNOWN ", /* < -11, no API */
+};
+
+struct bar {
+ bool toupdate;
+ WINDOW *win;
+ int y; /* bar y in win */
+ int x; /* bar x in win */
+ int w; /* width in win */
+ int perc; /* barlen = (w * perc) / 100 */
+ const char* fmt; /* format for label */
+ int label; /* rangebox and pause perc!=label */
+};
+
+static void draw_bar(struct bar *b)
{
- int i, blue_x, color, stringlen;
- char labelstr[128];
-
- blue_x = perc > 0 ? (perc * barlen) / 100 : -1;
-
- wmove(win, y, x);
- for (i = 0; i < barlen; i++) {
- color = (i <= blue_x) ? t.bar.f_color : t.bar.color;
- wattron(win, color);
- waddch(win, ' ');
- wattroff(win, color);
- }
-
- if (withlabel)
- sprintf(labelstr, "%d", label);
- else
- sprintf(labelstr, "%3d%%", perc);
- stringlen = (int)strlen(labelstr); /* number, always 1-byte-ch string */
- wmove(win, y, x + barlen/2 - stringlen/2);
- for (i = 0; i < stringlen; i++) {
- color = (blue_x + 1 <= barlen/2 - stringlen/2 + i ) ?
- t.bar.color : t.bar.f_color;
- wattron(win, color);
- waddch(win, labelstr[i]);
- wattroff(win, color);
- }
-}
-
-static int
-bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, struct buttons *bs)
-{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, bs, 3, MINBARWIDTH,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, MINBARWIDTH, bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* bar */, bs != NULL);
-
- return (0);
+ 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(int rows, int cols, struct buttons *bs)
+static void update_barbox(struct dialog *d, struct bar *b, bool buttons)
{
- int minheight, minwidth;
-
- minwidth = 0;
- if (bs != NULL) /* gauge has not buttons */
- minwidth = buttons_min_width(*bs);
-
- minwidth = MAX(minwidth, MINBARWIDTH);
- minwidth += VBORDERS;
-
- if (cols < minwidth)
- RETURN_ERROR("Few cols to draw bar and/or buttons");
+ int y;
- minheight = HBORDERS + 3;
- if (bs != NULL)
- minheight += 2;
- if (rows < minheight)
- RETURN_ERROR("Few rows to draw bar");
-
- return (0);
+ y = d->y + d->h - BORDER - HBOX;
+ if (buttons)
+ y -= HBUTTONS;
+ update_box(d->conf, b->win, y, d->x + BORDER + BARPADDING, HBOX,
+ WBOX(d), RAISED);
}
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep)
+ int cols, unsigned int perc, int fd, const char *sep, const char *end)
{
bool mainloop;
- int y, x, h, w, fd2;
+ int fd2;
FILE *input;
- WINDOW *widget, *textpad, *bar, *shadow;
char inputbuf[2048], ntext[2048], *pntext;
+ struct bar b;
+ struct dialog d;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, NULL) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, NULL) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, NULL,
- false) != 0)
- return (BSDDIALOG_ERROR);
-
- bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
+ 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_ERROR("Cannot build FILE* from fd");
+ RETURN_FMTERROR("Cannot build FILE* from fd %d", fd);
}
+ perc = MIN(perc, 100);
mainloop = true;
while (mainloop) {
- wrefresh(widget);
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-4,
- x+w-1-TEXTHMARGIN);
- draw_borders(conf, bar, 3, w-6, RAISED);
- draw_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/);
- wrefresh(bar);
+ if (d.built) {
+ hide_dialog(&d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(&d, HBOX, MIN_WBOX, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d))
+ return (BSDDIALOG_ERROR);
+ if (d.built)
+ refresh(); /* fix grey lines expanding screen */
+ TEXTPAD(&d, HBOX);
+ update_barbox(&d, &b, false);
+ b.w = WBAR(&d);
+ b.perc = b.label = perc;
+ b.toupdate = true;
+ draw_bar(&b);
+ doupdate();
if (input == NULL) /* that is fd < 0 */
break;
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
@@ -181,12 +177,12 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
if (mainloop == false)
break;
fscanf(input, "%d", &perc);
- perc = perc > 100 ? 100 : perc;
+ perc = MIN(perc, 100);
pntext = &ntext[0];
ntext[0] = '\0';
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
@@ -198,15 +194,13 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
pntext++;
}
pntext[0] = '\0';
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- ntext, NULL, false) != 0)
- return (BSDDIALOG_ERROR);
+ d.text = ntext;
}
if (input != NULL)
fclose(input);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
@@ -217,120 +211,95 @@ do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols,
unsigned int mainperc, unsigned int nminibars, const char **minilabels,
int *minipercs, bool color)
{
- int i, retval, miniperc, y, x, h, w, ypad, max_minbarlen;
- int htextpad, htext, wtext;
- int colorperc, red, green;
- WINDOW *widget, *textpad, *bar, *shadow;
- char states[12][14] = {
- " Succeeded ", /* -1 */
- " Failed ", /* -2 */
- " Passed ", /* -3 */
- " Completed ", /* -4 */
- " Checked ", /* -5 */
- " Done ", /* -6 */
- " Skipped ", /* -7 */
- " In Progress ", /* -8 */
- "(blank) ", /* -9 */
- " N/A ", /* -10 */
- " Pending ", /* -11 */
- " UNKNOWN ", /* < -11, no API */
- };
+ int i, miniperc, 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_minbarlen = 0;
+ max_minibarlen = 0;
for (i = 0; i < (int)nminibars; i++)
- max_minbarlen = MAX(max_minbarlen, (int)strcols(minilabels[i]));
- max_minbarlen += 3 + 16; /* seps + [...] */
- max_minbarlen = MAX(max_minbarlen, MINMGBARWIDTH); /* mainbar */
+ 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 (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
-
- /* mixedgauge autosize */
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, nminibars + 3,
- max_minbarlen, &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
- if (cols == BSDDIALOG_AUTOSIZE)
- w = widget_min_width(conf, wtext, max_minbarlen, NULL);
- if (rows == BSDDIALOG_AUTOSIZE)
- h = widget_min_height(conf, htext, nminibars + 3, false);
-
- /* mixedgauge checksize */
- if (w < max_minbarlen + 2)
- RETURN_ERROR("Few cols for this mixedgauge");
- if (h < 5 + (int)nminibars)
- RETURN_ERROR("Few rows for this mixedgauge");
-
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (dialog_size_position(&d, nminibars + HBOX, max_minibarlen,
+ &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
return (BSDDIALOG_ERROR);
-
- retval = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false);
- if (retval == BSDDIALOG_ERROR)
- return (retval);
/* mini bars */
+ b.win = d.widget;
+ b.x = 1 + d.w - 2 - 15;
+ b.w = 13;
+ b.fmt = "%3d%%";
+ b.toupdate = false;
for (i = 0; i < (int)nminibars; i++) {
miniperc = minipercs[i];
- if (miniperc == BSDDIALOG_MG_BLANK)
- continue;
/* label */
- if (color && (miniperc >= 0))
- wattron(widget, A_BOLD);
- mvwaddstr(widget, i+1, 2, minilabels[i]);
- if (color && (miniperc >= 0))
- wattroff(widget, A_BOLD);
+ 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 < -11)
- mvwaddstr(widget, i+1, w-2-15, states[11]);
- else if (miniperc < 0) {
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- colorperc = -1;
+ if (miniperc == BSDDIALOG_MG_BLANK)
+ continue;
+ mvwaddstr(d.widget, i+1, d.w-2-15, "[ ]");
+ if (miniperc >= 0) {
+ b.y = i + 1;
+ b.perc = b.label = MIN(miniperc, 100);
+ draw_bar(&b);
+ } else { /* miniperc < 0 */
+ if (miniperc < BSDDIALOG_MG_PENDING)
+ miniperc = -12; /* UNKNOWN */
+ minicolor = t.dialog.color;
if (color && miniperc == BSDDIALOG_MG_FAILED)
- colorperc = red;
- if (color && miniperc == BSDDIALOG_MG_DONE)
- colorperc = green;
- if (colorperc != -1)
- wattron(widget, colorperc);
+ minicolor = red;
+ else if (color && miniperc == BSDDIALOG_MG_DONE)
+ minicolor = green;
+ wattron(d.widget, minicolor);
miniperc = abs(miniperc + 1);
- mvwaddstr(widget, i+1, 1+w-2-15, states[miniperc]);
- if (colorperc != -1)
- wattroff(widget, colorperc);
- }
- else { /* miniperc >= 0 */
- if (miniperc > 100)
- miniperc = 100;
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- draw_bar(widget, i+1, 1+w-2-15, 13, miniperc, false,
- -1 /*unused*/);
+ mvwaddstr(d.widget, i+1, 1+d.w-2-15, states[miniperc]);
+ wattroff(d.widget, minicolor);
}
}
+ wnoutrefresh(d.widget);
- wrefresh(widget);
- getmaxyx(textpad, htextpad, i /* unused */);
- ypad = y + h - 4 - htextpad;
- ypad = ypad < y+(int)nminibars ? y+(int)nminibars : ypad;
- prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2);
+ /* text */
+ ystext = MAX(d.h - BORDERS - htext - HBOX, (int)nminibars);
+ rtextpad(&d, 0, 0, ystext, HBOX);
/* main bar */
- bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED);
-
- draw_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/);
+ 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);
- wattron(bar, t.bar.color);
- mvwaddstr(bar, 0, 2, "Overall Progress");
- wattroff(bar, t.bar.color);
-
- wrefresh(bar);
-
- /* getch(); alternate mode (port devel/ncurses) shows nothing */
+ doupdate();
+ /* getch(); to test with "alternate mode" */
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
@@ -414,7 +383,8 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
minipercs[i] = BSDDIALOG_MG_DONE;
update = true;
i++;
- } else if (minibar[i].status == BSDDIALOG_MG_FAILED || perc < 0) {
+ } else if (minibar[i].status == BSDDIALOG_MG_FAILED ||
+ perc < 0) {
minipercs[i] = BSDDIALOG_MG_FAILED;
update = true;
} else /* perc >= 0 */
@@ -426,73 +396,73 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
return (retval);
}
+static int rangebox_redraw(struct dialog *d, struct bar *b, int *bigchange)
+{
+ 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);
+}
+
int
bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
int cols, int min, int max, int *value)
{
- bool loop, buttupdate, barupdate;
- int y, x, h, w;
- int currvalue, retval, sizebar, bigchange, positions;
+ bool loop;
+ int currvalue, retval, bigchange, positions;
wint_t input;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- if (value == NULL)
- RETURN_ERROR("*value cannot be NULL");
+ struct bar b;
+ struct dialog d;
+ CHECK_PTR(value);
if (min >= max)
- RETURN_ERROR("min >= max");
+ RETURN_FMTERROR("min (%d) >= max (%d)", min, max);
+ if (*value < min)
+ RETURN_FMTERROR("value (%d) < min (%d)", *value, min);
+ if (*value > max)
+ RETURN_FMTERROR("value (%d) > max (%d)", *value, max);
currvalue = *value;
positions = max - min + 1;
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%d";
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
-
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
-
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
+ if (b.toupdate) {
+ b.perc = ((float)(currvalue - min)*100) / (positions-1);
+ b.label = currvalue;
+ draw_bar(&b);
}
- if (barupdate) {
- perc = ((float)(currvalue - min)*100) / (positions-1);
- draw_bar(bar, 1, 1, sizebar, perc, true, currvalue);
- barupdate = false;
- wrefresh(bar);
- }
-
+ doupdate();
if (get_wch(&input) == ERR)
continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- retval = bs.value[bs.curr];
- *value = currvalue;
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
@@ -502,159 +472,132 @@ bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
}
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->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget,y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_RESIZE:
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, RAISED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *value = currvalue;
+
+ delwin(b.win);
+ end_dialog(&d);
return (retval);
}
-int
-bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int sec)
+static int pause_redraw(struct dialog *d, struct bar *b)
{
- bool loop, buttupdate, barupdate;
- int retval, y, x, h, w, tout, sizebar;
- wint_t input;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MIN_WBOX, NULL) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (draw_dialog(d) != 0)
return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
+ b->w = WBAR(d);
+ update_barbox(d, b, true);
+ b->toupdate = true;
- doupdate();
+ return (0);
+}
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
+int
+bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *seconds)
+{
+ bool loop;
+ int retval, tout;
+ wint_t input;
+ struct bar b;
+ struct dialog d;
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
+ 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 = sec;
+ tout = *seconds;
nodelay(stdscr, TRUE);
timeout(1000);
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (barupdate) {
- perc = (float)tout * 100 / sec;
- draw_bar(bar, 1, 1, sizebar, perc, true, tout);
- barupdate = false;
- wrefresh(bar);
+ if (b.toupdate) {
+ b.perc = (float)tout * 100 / *seconds;
+ b.label = tout;
+ draw_bar(&b);
}
-
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
- }
-
+ doupdate();
if (get_wch(&input) == ERR) { /* timeout */
tout--;
if (tout < 0) {
@@ -662,14 +605,14 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
break;
}
else {
- barupdate = true;
+ b.toupdate = true;
continue;
}
}
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- retval = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
@@ -679,72 +622,44 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
+ if (pause_redraw(&d, &b) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget,y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_RESIZE:
+ if (pause_redraw(&d, &b) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, LOWERED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
-
nodelay(stdscr, FALSE);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *seconds = MAX(tout, 0);
+
+ delwin(b.win);
+ end_dialog(&d);
return (retval);
-} \ No newline at end of file
+}
diff --git a/lib/bsddialog.3 b/lib/bsddialog.3
index 9cc68a90ff62..38885bfe3ea4 100644
--- a/lib/bsddialog.3
+++ b/lib/bsddialog.3
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+.\" Copyright (c) 2021-2023 Alfonso Sabato Siciliano
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -22,13 +22,13 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 23, 2022
+.Dd July 28, 2023
.Dt BSDDIALOG 3
.Os
.Sh NAME
.Nm bsddialog_backtitle ,
.Nm bsddialog_calendar ,
-.Nm bsddialog_clearterminal ,
+.Nm bsddialog_clear ,
.Nm bsddialog_color ,
.Nm bsddialog_color_attrs ,
.Nm bsddialog_checklist ,
@@ -43,6 +43,7 @@
.Nm bsddialog_init ,
.Nm bsddialog_init_notheme ,
.Nm bsddialog_initconf ,
+.Nm bsddialog_inmode ,
.Nm bsddialog_menu ,
.Nm bsddialog_mixedgauge ,
.Nm bsddialog_mixedlist ,
@@ -50,6 +51,7 @@
.Nm bsddialog_pause ,
.Nm bsddialog_radiolist ,
.Nm bsddialog_rangebox ,
+.Nm bsddialog_refresh ,
.Nm bsddialog_set_theme ,
.Nm bsddialog_set_default_theme ,
.Nm bsddialog_textbox ,
@@ -68,9 +70,9 @@
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int *yy"
-.Fa "unsigned int *mm"
-.Fa "unsigned int *dd"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
.Fc
.Ft int
.Fo bsddialog_checklist
@@ -83,17 +85,17 @@
.Fa "struct bsddialog_menuitem *items"
.Fa "int *focusitem"
.Fc
-.Ft int
-.Fn bsddialog_clearterminal "void"
+.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 *yy"
-.Fa "unsigned int *mm"
-.Fa "unsigned int *dd"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
.Fc
.Ft int
.Fn bsddialog_end "void"
@@ -106,6 +108,7 @@
.Fa "unsigned int formrows"
.Fa "unsigned int nitems"
.Fa "struct bsddialog_formitem *items"
+.Fa "int *focusitem"
.Fc
.Ft int
.Fo bsddialog_gauge
@@ -116,6 +119,7 @@
.Fa "unsigned int perc"
.Fa "int fd"
.Fa "const char *sep"
+.Fa "const char *end"
.Fc
.Ft const char *
.Fn bsddialog_geterror "void"
@@ -130,6 +134,8 @@
.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
@@ -179,7 +185,7 @@
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int seconds"
+.Fa "unsigned int *seconds"
.Fc
.Ft int
.Fo bsddialog_radiolist
@@ -202,6 +208,8 @@
.Fa "int max"
.Fa "int *value"
.Fc
+.Ft void
+.Fn bsddialog_refresh "void"
.Ft int
.Fo bsddialog_textbox
.Fa "struct bsddialog_conf *conf"
@@ -251,8 +259,7 @@
.Sh DESCRIPTION
The
.Nm bsddialog
-library provides an API to build Text User Interface dialogs and widgets: to
-display messages, to get input and to inform about a computation status.
+library provides an API to build Text User Interface dialogs and widgets.
.Pp
.Fn bsddialog_init
initializes the library, the only functions that can be called before is
@@ -260,10 +267,7 @@ initializes the library, the only functions that can be called before is
described later.
After the initialization the input and output should be handled via the library
API.
-.Fn bsddialog_end
-restores the screen like before
-.Fn bsddialog_init ,
-then it is not possible to use the library functions.
+.Pp
.Fn bsddialog_init_notheme
is equivalent to
.Fn bsddialog_init
@@ -271,41 +275,64 @@ except it does not set the default graphical theme; see
.Sx Theme
subsection to set a theme explicitly.
.Pp
-.Fn bsddialog_error
-returns a string to describe the last error, it should be called after a
-.Dv BSDDIALOG_ERROR
-returned value.
-.Fn bsddialog_clearterminal
-clears the screen.
+.Fn bsddialog_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, it is possible to set
+on the top of the screen.
+The function handles
.Fa conf.ascii_lines
and
-.Fa conf.no_lines ;
-.Fa conf
-is described later.
+.Fa conf.no_lines
+described later.
.Pp
-Each
-.Fa char*
-argument has to be a well terminated string, it can be a multibyte character
-string depending on current locale, see
-.Xr setlocale 3 .
+.Fn bsddialog_error
+returns a string to describe the last error.
+The function should be called after a
+.Dv BSDDIALOG_ERROR
+returned value.
+.Pp
+.Fn bsddialog_clear
+clears the screen from
+.Fa y .
+.Pp
+.Fn bsddialog_refresh
+useful to refresh the screen after a terminal mode change, see
+.Xr terminfo 5 .
.Ss Dialogs
The dialogs have common arguments.
.Fa text
is a string printed inside the dialog.
+Each
+.Fa char*
+parameter can be a multibyte character string depending on current locale, see
+.Xr setlocale 3 .
.Fa rows
and
.Fa cols
-are height and width, their value can be between 2 and the screen size,
+are height and width, their value can be a fixed size,
.Dv BSDDIALOG_AUTOSIZE
or
.Dv BSDDIALOG_FULLSCREEN .
.Fa conf
-is a struct to customize the dialog, it does not set global properties to the
-library.
+is a struct to customize the current dialog, it does not set global properties
+to the library.
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_conf {
@@ -331,24 +358,28 @@ struct bsddialog_conf {
} key;
struct {
unsigned int cols_per_row;
- bool highlight;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
char securech;
char *securembch;
bool value_wchar;
- bool value_without_ok;
} 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;
@@ -358,8 +389,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -396,7 +428,7 @@ is
or
.Dv BSDDIALOG_FULLSCREEN .
.It Fa conf.bottomtitle
-subtitle at the dialog bottom side.
+dialog subtitle.
.It Fa conf.clear
hide the dialog at exit.
.It Fa conf.get_height
@@ -414,36 +446,35 @@ draw shadow.
.It Fa conf.sleep
wait before to return, the value is in seconds.
.It Fa conf.title
-title at the top dialog side.
+dialog title.
.It Fa conf.y
-vertical position, 0 is top screen size, can be
+dialog vertical position, 0 is top screen, can be
.Dv BSDDIALOG_CENTER .
.It Fa conf.x
-horizontal position, 0 is left screen side, can be
+dialog horizontal position, 0 is left screen, can be
.Dv BSDDIALOG_CENTER .
.El
.Pp
.Bl -column -compact
.It Fa conf.key.enable_esc
-enables
+enable
.Dv ESC
key to close the dialog.
.It Fa conf.key.f1_file
-file to open if F1 is pressed.
+open a file in a textbox if F1 is pressed.
.It Fa conf.key.f1_message
-message to display if F1 is pressed.
+build a msgbox with message if F1 is pressed.
.El
.Pp
.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
+with autosizing, default
.Dv 10 .
-.It Fa conf.text.highlight
-enables highlights for
-.Fa text ,
-properly the following sequences are considered escapes:
+.It Fa conf.text.escape
+enable escapes in
+.Fa text :
.It Dq \eZ0
black.
.It Dq \eZ1
@@ -460,14 +491,26 @@ magenta.
cyan.
.It Dq \eZ7
white.
-.It Dq \eZr
-reverse foreground and background.
-.It Dq \eZR
-disable reverse.
.It Dq \eZb
bold.
.It Dq \eZB
disable bold.
+.It Dq \eZd
+Half bright.
+.It Dq \eZD
+disable half bright.
+.It Dq \eZk
+Blink.
+.It Dq \eZK
+disable blinking.
+.It Dq \eZr
+reverse foreground and background.
+.It Dq \eZR
+disable reverse.
+.It Dq \eZs
+Highlight.
+.It Dq \eZS
+disable highlighting.
.It Dq \eZu
underline.
.It Dq \eZU
@@ -484,13 +527,19 @@ function.
.Pp
.Bl -column -compact
.It Fa conf.button.always_active
-buttons always active, avoidind focus switch between buttons and input fields or
+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
@@ -509,9 +558,11 @@ on startup focus on the Cancel button.
add Help button.
.It Fa conf.button.help_label
set a label for Help button.
-.It Fa conf.button.generic1_label
+.It Fa conf.button.right1_label
add a button with the specified label.
-.It Fa conf.button.generic2_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.
@@ -532,143 +583,35 @@ to
to
.Dv 10 .
.Pp
-.Fn bsddialog_infobox
-builds a dialog without buttons and returns instantly.
-.Fn bsddialog_msgbox
-builds a dialog with OK button.
-.Fn bsddialog_yesno
-provides a dialog for a
-.Dq Yes-No Question ,
-the labels on buttons are Yes and No.
-.Pp
-.Fn bsddialog_pause
-builds a dialog waiting until the timeout in
-.Fa seconds
-expires or a button is pressed.
-.Pp
.Fn bsddialog_calendar
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fn bsddialog_datebox
-build a dialog to select a date,
-.Fa yy ,
-.Fa mm ,
-and
-.Fa dd
+.Fa day
are default values on startup, selected date at exit.
-.Fn bsddialog_timebox
-builds a dialog to choose a time,
-.Fa hh ,
-.Fa mm ,
-and
-.Fa ss
-are default values on startup, selected time at exit.
.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu
-and
-.Fn bsddialog_radiolist
-build dialogs to select some item from a list via the SPACE key, an item is
-defined like:
+.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
-.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 strings to describe the item and are printed on its row,
-.Fa bottomdesc
-is printed on the bottom side of the screen,
-.Fa depth
-is a margin between the
-.Fa prefix
-and
-.Fa name
-useful to implement a
-.Dq treeview,
-.Fa on
-is set to
-.Dv true
-if the item is selected,
-.Dv false
-otherwise.
-.Fa items
-is an array of items of
-.Fa nitem
-elements,
-.Fa menurows
-specifies the graphical fixed height of the list, if
-.Fa cols
-is set to
-.Dv BSDDIALOG_AUTOSIZE
-.Fa menurows
-specifies a maximum value.
-Finally, if not
-.Dv NULL ,
-.Fa focusitem
-specifies the default item on startup and the last focused item at exit, could
-be a negative value if no item is focused.
-.Pp
-.Fn bsddialog_mixedlist
-builds a dialog with collections of checklists, radiolists and separators.
-A collection is a set defined like:
-.Pp
-.Bd -literal -offset indent -compact
-enum bsddialog_menutype {
- BSDDIALOG_CHECKLIST,
- BSDDIALOG_RADIOLIST,
- BSDDIALOG_SEPARATOR,
-};
-
-struct bsddialog_menugroup {
- enum bsddialog_menutype type;
- unsigned int nitems;
- struct bsddialog_menuitem *items;
-};
-.Ed
-.Pp
-.Fa groups
-is an array of sets of
-.Fa ngroups
-elements.
-.Fa menurows
-is the graphical height size for the list.
-If not
-.Dv NULL ,
-.Fa focuslist
-and
-.Fa focusitem
-specify the default item on startup and the last focused item at exit, could be
-a negative value if no item is focused.
-.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu ,
-.Fn bsddialog_mixedlist
+.Fn bsddialog_datebox
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fn bsddialog_radiolist
-can be costomizated by:
+.Fa day
+are default values on startup, selected date at exit.
+The function can be customized by:
.Bl -column -compact
-.It Fa conf.menu.align_left
-aligns items to left, default center.
-.It Fa conf.menu.no_desc
-hide description.
-.It Fa conf.menu.no_name
-hide names.
-.It Fa conf.menu.on_without_ok
-set items
-.Fa on
-also if the OK button is not pressed.
-.It Fa conf.menu.shortcut_buttons
-enable shortcut keys on buttons, default on items.
+.It Fa conf.date.format
+date format user interface, possible values:
+.Dq d/m/y ,
+.Dq m/d/y ,
+.Dq y/m/d .
.El
.Pp
.Fn bsddialog_form
@@ -676,11 +619,16 @@ builds a dialog to display an array of
.Fa items
of
.Fa nitems
-elements to get strings in input.
+elements to get input strings.
.Fa formrows
-specifies the graphical height for the box around the items,
+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
@@ -703,7 +651,7 @@ struct bsddialog_formitem {
.Ed
.Pp
.Fa label
-is a string to describe the request, it is printed at the position
+is a string to describe the request at the position
.Fa ylabel
and
.Fa xlabel .
@@ -717,22 +665,20 @@ is its graphical width, while
is the maximum number of characters of the input string.
.Fa init
is the default field value.
-If the OK button is pressed
+If no error occurs
.Fa value
-is the allocated memory with the current field string, its size depends on
-the current locale.
+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
+is an OR value to set the field:
.Dv BSDDIALOG_FIELDHIDDEN ,
.Dv BSDDIALOG_FIELDREADONLY ,
.Dv BSDDIALOG_FIELDNOCOLOR ,
.Dv BSDDIALOG_FIELDCURSOREND ,
-.Dv BSDDIALOG_FIELDEXTEND
-and
+.Dv BSDDIALOG_FIELDEXTEND ,
.Dv BSDDIALOG_FIELDSINGLEBYTE .
-flags for the field.
.Fa bottomdesc
-is printed on the bottom side of the screen if the item is focused.
+is printed at bottom screen if the item is focused.
.Pp
.Fn bsddialog_form
can be customized by:
@@ -751,38 +697,108 @@ the allocated
is a
.Em wchar_t*
string.
-.It Fa conf.form.value_without_ok
-allocate memory and set
-.Fa value
-also if the OK button is not pressed.
.El
.Pp
.Fn bsddialog_gauge
-builds a dialog with a bar to shows
-.Fa perc ,
-if the file descriptor
+builds a dialog with a bar to show
+.Fa perc .
+If the file descriptor
.Fa fd
is greater or equal to 0 the dialog waits to read
-.Fa separator
+.Fa sep
from it, then the first string replaces
.Fa perc
and the following strings replace
.Fa text
until the next
-.Fa separator ,
+.Fa sep ,
the loop ends reading
-.Dv EOF .
+.Fa end .
+.Pp
+.Fn bsddialog_infobox
+builds a dialog without buttons and returns instantly.
+.Pp
+.Fn bsddialog_menu
+builds a dialog to select an item from a list via SPACE 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
-draws a main bar with the
+builds a dialog with a main bar with the
.Fa mainperc
percentage and
.Fa nminibars
each one with a
.Fa minilabel
and a
+.Fa miniperc .
.Fa miniperc
-with a value between 0 and 100 or
+can be: a positive value to print a bar with a percentace, a negative constant
.Dv BSDDIALOG_MG_SUCCEEDED ,
.Dv BSDDIALOG_MG_FAILED ,
.Dv BSDDIALOG_MG_PASSED ,
@@ -791,11 +807,69 @@ with a value between 0 and 100 or
.Dv BSDDIALOG_MG_DONE ,
.Dv BSDDIALOG_MG_SKIPPED ,
.Dv BSDDIALOG_MG_INPROGRESS ,
-.Dv BSDDIALOG_MG_BLANK ,
-.Dv BSDDIALOG_MG_NA
-or
+.Dv BSDDIALOG_MG_BLANK
+to hide
+.Fa miniperc ,
+.Dv BSDDIALOG_MG_NA ,
.Dv BSDDIALOG_MG_PENDING
-to print a descriptive string.
+to print a descriptive string, otherwise
+.Dq "UNKNOWN"
+is printed.
+.Pp
+.Fn bsddialog_mixedlist
+builds a dialog with collections of checklists, radiolists and separators.
+A collection is a set defined like:
+.Pp
+.Bd -literal -offset indent -compact
+enum bsddialog_menutype {
+ BSDDIALOG_CHECKLIST,
+ BSDDIALOG_RADIOLIST,
+ BSDDIALOG_SEPARATOR,
+};
+
+struct bsddialog_menugroup {
+ enum bsddialog_menutype type;
+ unsigned int nitems;
+ struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
+};
+.Ed
+.Pp
+.Fa groups
+is an array of sets of
+.Fa ngroups
+elements.
+.Fa menurows
+is the graphical height size for the list.
+If not
+.Dv NULL ,
+.Fa focuslist
+and
+.Fa focusitem
+specify the default item on startup and the last focused item at exit, could be
+a negative value if no item is focused.
+The dialog can be customized by
+.Fa conf.menu.* ,
+see
+.Fn bsddialog_menu .
+.Pp
+.Fn bsddialog_msgbox
+builds a dialog with OK button.
+.Pp
+.Fn bsddialog_pause
+builds a dialog waiting until the timeout in
+.Fa seconds
+expires or a button is pressed.
+At exit
+.Fa seconds
+is set like remaining time.
+.Pp
+.Fn bsddialog_radiolist
+builds dialogs to select at most an item from a list via the SPACE key, can be
+customized by
+.Fa conf.menu.* .
+See
+.Fn bsddialog_menu .
.Pp
.Fn bsddialog_rangebox
to select a value between
@@ -809,12 +883,28 @@ and PAGEDOWN can change it.
.Pp
.Fn bsddialog_textbox
opens and prints
-.Fa file
-in a dialog, the UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to
-navigate the file.
-OK button is renamed EXIT.
+.Fa file .
+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
+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
@@ -840,17 +930,19 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
@@ -867,32 +959,27 @@ struct bsddialog_theme {
unsigned int maxmargin;
char leftdelim;
char rightdelim;
- int delimcolor;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
.Ed
.Pp
A member with the
.Dq f_
-prefix refers to an element with focus.
-.Pp
-.Fn bsddialog_get_theme
-sets
-.Fa theme
-like the current theme.
+refers to focus when an element can be in selected or not selected state.
.Pp
-A color can be set by the value returned by
-.Fn bsddialog_color ,
-Possible values for
-.Fa background
-and
-.Fa foreground
-are:
+.Fn bsddialog_color
+generates and returns a color to set a
+.Fa struct bsddialog_theme
+color member.
+An
+.Fa enum bsddialog_color
+can be:
.Dv BSDDIALOG_BLACK ,
.Dv BSDDIALOG_RED ,
.Dv BSDDIALOG_GREEN ,
@@ -900,31 +987,30 @@ are:
.Dv BSDDIALOG_BLUE ,
.Dv BSDDIALOG_MAGENTA ,
.Dv BSDDIALOG_CYAN ,
-and
-.Dv BSDDIALOG_WHITE ,
+.Dv BSDDIALOG_WHITE .
.Fa flags
-specifies OR-flags, possible values:
+is an OR value:
+.Dv BSDDIALOG_BLINK ,
.Dv BSDDIALOG_BOLD ,
-.Dv BSDDIALOG_REVERSE
-and
+.Dv BSDDIALOG_HALFBRIGHT ,
+.Dv BSDDIALOG_HIGHLIGHT ,
+.Dv BSDDIALOG_REVERSE ,
.Dv BSDDIALOG_UNDERLINE .
+.Pp
.Fn bsddialog_color_attrs
-gets the properties of a color.
+sets, if not NULL,
+.Fa foreground ,
+.Fa background ,
+.Fa flags ,
+like the properties of
+.Fa color ,
+see
+.Fn bsddialog_color .
.Pp
-.Fn bsddialog_set_theme
+.Fn bsddialog_get_theme
sets
.Fa theme
-like current theme, the changes takes effect only for dialogs built after the
-call.
-.Pp
-The library provides predefined themes:
-.Dv BSDDIALOG_THEME_BLACKWHITE ,
-.Dv BSDDIALOG_THEME_BSDDIALOG ,
-.Dv BSDDIALOG_THEME_FLAT
-and
-.Dv BSDDIALOG_THEME_DIALOG ,
-they can be set via
-.Fn bsddialog_set_default_theme .
+like the current runtime theme.
.Pp
.Fn bsddialog_hascolors
returns
@@ -932,6 +1018,20 @@ returns
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
@@ -942,9 +1042,12 @@ returned:
.Dv BSDDIALOG_CANCEL ,
.Dv BSDDIALOG_HELP ,
.Dv BSDDIALOG_EXTRA ,
-.Dv BSDDIALOG_GENERIC1
-or
-.Dv BSDDIALOG_GENERIC2 .
+.Dv BSDDIALOG_LEFT1 ,
+.Dv BSDDIALOG_LEFT2 ,
+.Dv BSDDIALOG_LEFT3 ,
+.Dv BSDDIALOG_RIGHT1 ,
+.Dv BSDDIALOG_RIGHT2 ,
+.Dv BSDDIALOG_RIGHT3 .
.Dv BSDDIALOG_YES
and
.Dv BSDDIALOG_NO
@@ -990,6 +1093,7 @@ case BSDDIALOG_NO
break;
case BSDDIALOG_ERROR:
printf("Error: %s\\n", bsddialog_geterror());
+ break;
}
.Ed
.Pp
diff --git a/lib/bsddialog.h b/lib/bsddialog.h
index ce6aac6d4632..d997036b1f9f 100644
--- a/lib/bsddialog.h
+++ b/lib/bsddialog.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,9 +30,9 @@
#include <stdbool.h>
-#define LIBBSDDIALOG_VERSION "0.4"
+#define LIBBSDDIALOG_VERSION "1.0"
-/* Exit status */
+/* Return values */
#define BSDDIALOG_ERROR -1
#define BSDDIALOG_OK 0
#define BSDDIALOG_YES BSDDIALOG_OK
@@ -42,8 +42,12 @@
#define BSDDIALOG_EXTRA 3
#define BSDDIALOG_TIMEOUT 4
#define BSDDIALOG_ESC 5
-#define BSDDIALOG_GENERIC1 6
-#define BSDDIALOG_GENERIC2 7
+#define BSDDIALOG_LEFT1 6
+#define BSDDIALOG_LEFT2 7
+#define BSDDIALOG_LEFT3 8
+#define BSDDIALOG_RIGHT1 9
+#define BSDDIALOG_RIGHT2 10
+#define BSDDIALOG_RIGHT3 11
/* Size and position */
#define BSDDIALOG_FULLSCREEN -1
@@ -94,24 +98,28 @@ struct bsddialog_conf {
} key;
struct {
unsigned int cols_per_row;
- bool highlight;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
char securech;
char *securembch;
bool value_wchar;
- bool value_without_ok;
} 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;
@@ -121,8 +129,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -146,6 +155,7 @@ struct bsddialog_menugroup {
enum bsddialog_menutype type;
unsigned int nitems;
struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
};
struct bsddialog_formitem {
@@ -166,16 +176,18 @@ struct bsddialog_formitem {
int bsddialog_init(void);
int bsddialog_init_notheme(void);
+bool bsddialog_inmode(void);
int bsddialog_end(void);
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle);
int bsddialog_initconf(struct bsddialog_conf *conf);
-int bsddialog_clearterminal(void);
+void bsddialog_clear(unsigned int y);
+void bsddialog_refresh(void);
const char *bsddialog_geterror(void);
/* Dialogs */
int
bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd);
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
int
bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
@@ -184,16 +196,16 @@ bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
int
bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd);
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
int
bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items);
+ struct bsddialog_formitem *items, int *focusitem);
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep);
+ int cols, unsigned int perc, int fd, const char *sep, const char *end);
int
bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
@@ -220,7 +232,7 @@ bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int
bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int seconds);
+ int cols, unsigned int *seconds);
int
bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
diff --git a/lib/bsddialog_progressview.h b/lib/bsddialog_progressview.h
index 0cd9368a1040..5203b798bb07 100644
--- a/lib/bsddialog_progressview.h
+++ b/lib/bsddialog_progressview.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,14 +36,14 @@
extern bool bsddialog_interruptprogview;
extern bool bsddialog_abortprogview;
-extern int bsddialog_total_progview;
+extern long long int bsddialog_total_progview;
struct bsddialog_fileminibar {
const char *path;
const char *label;
int status; /* next if BSDDIALOG_MG_DONE or BSDDIALOG_MG_FAILED */
- long long size;
- long long read;
+ long long int size;
+ long long int read;
};
struct bsddialog_progviewconf {
diff --git a/lib/bsddialog_theme.h b/lib/bsddialog_theme.h
index 2f20d7b5a79c..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-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,9 +29,12 @@
#define _LIBBSDDIALOG_THEME_H_
/* color flags */
-#define BSDDIALOG_BOLD 1U
-#define BSDDIALOG_REVERSE 2U
-#define BSDDIALOG_UNDERLINE 4U
+#define BSDDIALOG_BLINK 1U
+#define BSDDIALOG_BOLD 2U
+#define BSDDIALOG_HALFBRIGHT 4U
+#define BSDDIALOG_HIGHLIGHT 8U
+#define BSDDIALOG_REVERSE 16U
+#define BSDDIALOG_UNDERLINE 32U
struct bsddialog_theme {
struct {
@@ -52,17 +55,19 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
@@ -79,20 +84,19 @@ struct bsddialog_theme {
unsigned int maxmargin;
char leftdelim;
char rightdelim;
- int delimcolor;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
enum bsddialog_default_theme {
+ BSDDIALOG_THEME_3D,
BSDDIALOG_THEME_BLACKWHITE,
- BSDDIALOG_THEME_BSDDIALOG,
- BSDDIALOG_THEME_FLAT,
- BSDDIALOG_THEME_DIALOG
+ BSDDIALOG_THEME_FLAT
};
enum bsddialog_color {
diff --git a/lib/calendarbox.c b/lib/calendarbox.c
deleted file mode 100644
index 3b55b26a13b8..000000000000
--- a/lib/calendarbox.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-
-#include <curses.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "bsddialog.h"
-#include "bsddialog_theme.h"
-#include "lib_util.h"
-
-#define MINHCAL 13
-#define MINWCAL 36 /* 34 calendar, 1 + 1 margins */
-#define MINYEAR 1900
-#define MAXYEAR 999999999
-
-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);
-}
-
-enum operation {
- UP_DAY,
- DOWN_DAY,
- LEFT_DAY,
- RIGHT_DAY,
- UP_MONTH,
- DOWN_MONTH,
- UP_YEAR,
- DOWN_YEAR
-};
-
-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 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
-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, h, w, 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++;
- }
- }
-
- wrefresh(win);
-}
-
-static void
-drawsquare(struct bsddialog_conf *conf, WINDOW *win, const char *fmt,
- const void *value, bool focus)
-{
- int h, w;
-
- getmaxyx(win, h, w);
- draw_borders(conf, win, h, w, RAISED);
- if (focus) {
- wattron(win, t.dialog.arrowcolor);
- mvwhline(win, 0, 7, conf->ascii_lines ? '^' : ACS_UARROW, 3);
- mvwhline(win, 2, 7, conf->ascii_lines ? 'v' : ACS_DARROW, 3);
- wattroff(win, t.dialog.arrowcolor);
- }
-
- if (focus)
- wattron(win, t.menu.f_namecolor);
- if (strchr(fmt, 's') != NULL)
- mvwprintw(win, 1, 1, fmt, (const char*)value);
- else
- mvwprintw(win, 1, 1, fmt, *((const int*)value));
- if (focus)
- wattroff(win, t.menu.f_namecolor);
-
- wrefresh(win);
-}
-
-static int
-calendar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text, struct buttons bs)
-{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, MINHCAL, MINWCAL,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, MINWCAL, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, MINHCAL, true);
-
- return (0);
-}
-
-static int calendar_checksize(int rows, int cols, struct buttons bs)
-{
- int mincols;
-
- mincols = MAX(MINWCAL, buttons_min_width(bs));
- mincols += VBORDERS;
-
- if (cols < mincols)
- RETURN_ERROR("Few cols for this calendar (at least 38)");
-
- if (rows < MINHCAL + 2 + 2) /* 2 buttons + 2 borders */
- RETURN_ERROR("Few rows for calendar (at least 17)");
-
- return (0);
-}
-
-int
-bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
-{
- bool loop, focusbuttons;
- int retval, y, x, h, w, sel, ycal, xcal, year, month, day;
- wint_t input;
- WINDOW *widget, *textpad, *shadow, *yearwin, *monthwin, *daywin;
- struct buttons bs;
- const char *m[12] = {
- "January", "February", "March", "April", "May", "June", "July",
- "August", "September", "October", "November", "December"
- };
-
- if (yy == NULL || mm == NULL || dd == NULL)
- RETURN_ERROR("yy / mm / dd cannot be NULL");
-
- year = *yy > MAXYEAR ? MAXYEAR : *yy;
- if (year < MINYEAR)
- year = MINYEAR;
- month = *mm > 12 ? 12 : *mm;
- if (month == 0)
- month = 1;
- day = *dd == 0 ? 1 : *dd;
- if(day > month_days(year, month))
- day = month_days(year, month);
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (calendar_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (calendar_checksize(h, w, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-17, x+w-2);
- doupdate();
-
- ycal = y + h - 15;
- xcal = x + w/2 - 17;
- mvwaddstr(widget, h - 16, w/2 - 17, "Month");
- monthwin = new_boxed_window(conf, ycal, xcal, 3, 17, RAISED);
- mvwaddstr(widget, h - 16, w/2, "Year");
- yearwin = new_boxed_window(conf, ycal, xcal + 17, 3, 17, RAISED);
- daywin = new_boxed_window(conf, ycal + 3, xcal, 9, 34, RAISED);
-
- wrefresh(widget);
-
- sel = -1;
- loop = focusbuttons = true;
- while (loop) {
- drawsquare(conf, monthwin, "%15s", m[month - 1], sel == 0);
- drawsquare(conf, yearwin, "%15d", &year, sel == 1);
- print_calendar(conf, daywin, year, month, day, sel == 2);
-
- if (get_wch(&input) == ERR)
- continue;
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
- if (focusbuttons || conf->button.always_active) {
- retval = bs.value[bs.curr];
- loop = false;
- }
- break;
- case 27: /* Esc */
- if (conf->key.enable_esc) {
- retval = BSDDIALOG_ESC;
- loop = false;
- }
- break;
- case '\t': /* TAB */
- if (focusbuttons) {
- bs.curr++;
- if (bs.curr >= (int)bs.nbuttons) {
- focusbuttons = false;
- sel = 0;
- bs.curr = conf->button.always_active ?
- 0 : -1;
- }
- } else {
- sel++;
- if (sel > 2) {
- focusbuttons = true;
- sel = -1;
- bs.curr = 0;
- }
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_RIGHT:
- if (focusbuttons) {
- bs.curr++;
- if (bs.curr >= (int)bs.nbuttons) {
- focusbuttons = false;
- sel = 0;
- bs.curr = conf->button.always_active ?
- 0 : -1;
- }
- } else if (sel == 2) {
- datectl(RIGHT_DAY, &year, &month, &day);
- } else { /* Month or Year*/
- sel++;
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_LEFT:
- if (focusbuttons) {
- bs.curr--;
- if (bs.curr < 0) {
- focusbuttons = false;
- sel = 2;
- bs.curr = conf->button.always_active ?
- 0 : -1;
- }
- } else if (sel == 2) {
- datectl(LEFT_DAY, &year, &month, &day);
- } else if (sel == 1) {
- sel = 0;
- } else { /* sel = 0, Month */
- focusbuttons = true;
- sel = -1;
- bs.curr = 0;
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_UP:
- if (focusbuttons) {
- sel = 2;
- focusbuttons = false;
- bs.curr = conf->button.always_active ? 0 : -1;
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- } else if (sel == 0) {
- datectl(UP_MONTH, &year, &month, &day);
- } else if (sel == 1) {
- datectl(UP_YEAR, &year, &month, &day);
- } else { /* sel = 2 */
- datectl(UP_DAY, &year, &month, &day);
- }
- break;
- case KEY_DOWN:
- if (focusbuttons) {
- break;
- } else if (sel == 0) {
- datectl(DOWN_MONTH, &year, &month, &day);
- } else if (sel == 1) {
- datectl(DOWN_YEAR, &year, &month, &day);
- } else { /* sel = 2 */
- datectl(DOWN_DAY, &year, &month, &day);
- }
- break;
- case KEY_HOME:
- datectl(UP_MONTH, &year, &month, &day);
- break;
- case KEY_END:
- datectl(DOWN_MONTH, &year, &month, &day);
- break;
- case KEY_PPAGE:
- datectl(UP_YEAR, &year, &month, &day);
- break;
- case KEY_NPAGE:
- datectl(DOWN_YEAR, &year, &month, &day);
- break;
- case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
- break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (calendar_autosize(conf, rows, cols, &h, &w, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (calendar_checksize(h, w, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-17, x+w-2);
- doupdate();
-
- ycal = y + h - 15;
- xcal = x + w/2 - 17;
- mvwaddstr(widget, h - 16, w/2 - 17, "Month");
- mvwin(monthwin, ycal, xcal);
- mvwaddstr(widget, h - 16, w/2, "Year");
- mvwin(yearwin, ycal, xcal + 17);
- mvwin(daywin, ycal + 3, xcal);
- wrefresh(widget);
-
- /* Important to avoid grey lines expanding screen */
- refresh();
- break;
- default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
- loop = false;
- }
- }
- }
-
- if (retval == BSDDIALOG_OK) {
- *yy = year;
- *mm = month;
- *dd = day;
- }
-
- delwin(yearwin);
- delwin(monthwin);
- delwin(daywin);
- end_dialog(conf, shadow, widget, textpad);
-
- return (retval);
-} \ 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 5b1d2ab61de2..5e80471c6974 100644
--- a/lib/formbox.c
+++ b/lib/formbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,18 +25,23 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include <wchar.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
+enum field_action {
+ MOVE_CURSOR_BEGIN,
+ MOVE_CURSOR_END,
+ MOVE_CURSOR_RIGHT,
+ MOVE_CURSOR_LEFT,
+ DEL_LETTER
+};
+
struct privateitem {
const char *label; /* formitem.label */
unsigned int ylabel; /* formitem.ylabel */
@@ -63,39 +68,157 @@ struct privateitem {
};
struct privateform {
- WINDOW *border;
-
+ 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 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 */
+ 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 */
};
-enum operation {
- MOVE_CURSOR_BEGIN,
- MOVE_CURSOR_END,
- MOVE_CURSOR_RIGHT,
- MOVE_CURSOR_LEFT,
- DEL_LETTER
-};
+static int
+build_privateform(struct bsddialog_conf*conf, unsigned int nitems,
+ struct bsddialog_formitem *items, struct privateform *f)
+{
+ bool insecurecursor;
+ int mbchsize;
+ unsigned int i, j, itemybeg, itemxbeg, tmp;
+ wchar_t *winit;
+ struct privateitem *item;
-static bool fieldctl(struct privateitem *item, enum operation op)
+ /* 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' ';
+ }
+
+ /* 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;
+ }
+
+ 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;
+ }
+
+ return (0);
+}
+
+static bool fieldctl(struct privateitem *item, enum field_action act)
{
bool change;
int width, oldwidth, nextwidth, cols;
unsigned int i;
change = false;
- switch (op){
+ switch (act){
case MOVE_CURSOR_BEGIN:
if (item->pos == 0 && item->xcursor == 0)
break;
@@ -191,71 +314,7 @@ static bool fieldctl(struct privateitem *item, enum operation op)
return (change);
}
-static void
-drawitem(struct privateform *form, struct privateitem *item, bool focus)
-{
- int color;
- unsigned int n, cols;
-
- /* Label */
- wattron(form->pad, t.dialog.color);
- mvwaddstr(form->pad, item->ylabel, item->xlabel, item->label);
- wattroff(form->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(form->pad, color);
- mvwhline(form->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(form->pad, item->yfield, item->xfield,
- &item->pubwbuf[item->xposdraw], n);
- wattroff(form->pad, color);
-
- /* Bottom Desc */
- 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(form->pad, item->yfield, item->xfield + item->xcursor);
-
- prefresh(form->pad, form->y, 0, form->ys, form->xs, form->ye, form->xe);
-}
-
-/*
- * 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(form,item,focus) do { \
- drawitem(form, item, !focus); \
- drawitem(form, item, focus); \
-} while (0)
-
-static bool
-insertch(struct privateform *form, struct privateitem *item, wchar_t wch)
+static bool insertch(struct privateitem *item, wchar_t wch, wchar_t securewch)
{
int i;
@@ -268,7 +327,7 @@ insertch(struct privateform *form, struct privateitem *item, wchar_t wch)
}
item->privwbuf[item->pos] = wch;
- item->pubwbuf[item->pos] = item->secure ? form->securewch : wch;
+ item->pubwbuf[item->pos] = item->secure ? securewch : wch;
item->nletters += 1;
item->privwbuf[item->nletters] = L'\0';
item->pubwbuf[item->nletters] = L'\0';
@@ -296,25 +355,40 @@ static char* alloc_wstomb(wchar_t *wstr)
}
static int
-return_values(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_formitem *apiitems, struct privateitem *items)
+return_values(struct bsddialog_conf *conf, struct privateform *f,
+ struct bsddialog_formitem *items)
{
- int i;
+ unsigned int i;
- if (output != BSDDIALOG_OK && conf->form.value_without_ok == false)
- return (output);
+ 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);
- for (i = 0; i < nitems; i++) {
- if (conf->form.value_wchar) {
- apiitems[i].value = (char*)wcsdup(items[i].privwbuf);
- } else {
- apiitems[i].value = alloc_wstomb(items[i].privwbuf);
- }
- if (apiitems[i].value == NULL)
- RETURN_ERROR("Cannot allocate memory for form value");
+ if (items[i].value == NULL)
+ RETURN_FMTERROR(
+ "Cannot allocate memory for item[%d].value", i);
}
- return (output);
+ 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)
@@ -371,323 +445,277 @@ nextitem(unsigned int nitems, struct privateitem *items, int curritem)
return (curritem);
}
-static void
-redrawbuttons(WINDOW *window, struct buttons *bs, bool focus, bool shortcut)
+static void redrawbuttons(struct dialog *d, bool focus, bool shortcut)
{
int selected;
- selected = bs->curr;
+ selected = d->bs.curr;
if (focus == false)
- bs->curr = -1;
- draw_buttons(window, *bs, shortcut);
- wrefresh(window);
- bs->curr = selected;
+ d->bs.curr = -1;
+ d->bs.shortcut = shortcut;
+ draw_buttons(d);
+ d->bs.curr = selected;
}
static void
-update_formborders(struct bsddialog_conf *conf, struct privateform *form)
+drawitem(struct privateform *f, int idx, bool focus)
{
- int h, w;
+ int color;
+ unsigned int n, cols;
+ struct privateitem *item;
- getmaxyx(form->border, h, w);
- draw_borders(conf, form->border, h, w, LOWERED);
+ item = &f->pritems[idx];
- if (form->viewrows < form->h) {
- wattron(form->border, t.dialog.arrowcolor);
- if (form->y > 0)
- mvwhline(form->border, 0, (w / 2) - 2,
- conf->ascii_lines ? '^' : ACS_UARROW, 5);
+ /* Label */
+ wattron(f->pad, t.dialog.color);
+ mvwaddstr(f->pad, item->ylabel, item->xlabel, item->label);
+ wattroff(f->pad, t.dialog.color);
- if (form->y + form->viewrows < form->h)
- mvwhline(form->border, h-1, (w / 2) - 2,
- conf->ascii_lines ? 'v' : ACS_DARROW, 5);
- wattroff(form->border, t.dialog.arrowcolor);
- wrefresh(form->border);
- }
-}
+ /* 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]);
-/* use menu autosizing, linelen = form.w, nitems = form.h */
-static int
-menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *menurows, int nitems,
- struct buttons bs)
-{
- int htext, wtext, menusize, notext;
-
- notext = 2;
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- /* algo 1): grows vertically */
- /* notext = 1; */
- /* algo 2): grows horizontally, better with little screens */
- notext += nitems;
- notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
- } else
- notext += *menurows;
-
- if (text_size(conf, rows, cols, text, &bs, notext, linelen + 4, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
+ }
+ mvwaddnwstr(f->pad, item->yfield, item->xfield,
+ &item->pubwbuf[item->xposdraw], n);
+ wattroff(f->pad, color);
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 4, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *menurows = menusize - 2 < 0 ? 0 : menusize - 2;
- } else /* h autosize with fixed menurows */
- menusize = *menurows + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- } else { /* fixed rows */
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- if (*h - 6 - htext <= 0)
- *menurows = 0; /* form_checksize() will check */
- else
- *menurows = MIN(*h-6-htext, nitems);
+ /* 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();
}
}
- /* avoid menurows overflow and menurows becomes at most menurows */
- if (*h - 6 - htext <= 0)
- *menurows = 0; /* form_checksize() will check */
- else
- *menurows = MIN(*h - 6 - htext, (int)*menurows);
-
- return (0);
+ /* Cursor */
+ curs_set((focus && item->cursor) ? 1 : 0);
+ wmove(f->pad, item->yfield, item->xfield + item->xcursor);
}
-static int
-form_checksize(int rows, int cols, const char *text, struct privateform *form,
- int nitems, struct buttons bs)
-{
- int mincols, textrow, menusize;
-
- /* cols */
- mincols = VBORDERS;
- mincols += buttons_min_width(bs);
- mincols = MAX(mincols, (int)form->w + 6);
-
- if (cols < mincols)
- RETURN_ERROR("Form width, cols < buttons or xlabels/xfields");
+/*
+ * 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)
- /* rows */
- if (nitems > 0 && form->viewrows == 0)
- RETURN_ERROR("items > 0 but viewrows == 0, if formheight = 0 "
- "terminal too small");
+static void update_formbox(struct bsddialog_conf *conf, struct privateform *f)
+{
+ int h, w;
- if (form->viewrows < form->minviewrows)
- RETURN_ERROR("Few formheight rows, if formheight = 0 terminal "
- "too small");
+ getmaxyx(f->box, h, w);
+ draw_borders(conf, f->box, LOWERED);
- textrow = text != NULL && text[0] != '\0' ? 1 : 0;
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this form");
+ 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);
- return (0);
+ 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 *form, struct privateitem *item)
+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);
- if (form->y > yup && form->y > 0)
- form->y = yup;
- if ((int)(form->y + form->viewrows) - 1 < (int)ydown)
- form->y = ydown - form->viewrows + 1;
+ /* 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;
}
-/* API */
-int
-bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *apiitems)
+static int form_size_position(struct dialog *d, struct privateform *f)
{
- bool switchfocus, changeitem, focusinform, insecurecursor, loop;
- int curritem, mbchsize, next, retval, y, x, h, w, wchtype;
- unsigned int i, j, itemybeg, itemxbeg, tmp;
- wchar_t *winit;
- wint_t input;
- WINDOW *widget, *textpad, *shadow;
- struct privateitem *items, *item;
- struct buttons bs;
- struct privateform form;
+ int htext, hform;
- for (i = 0; i < nitems; i++) {
- if (apiitems[i].maxvaluelen == 0)
- RETURN_ERROR("maxvaluelen cannot be zero");
- if (apiitems[i].fieldlen == 0)
- RETURN_ERROR("fieldlen cannot be zero");
- }
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
- insecurecursor = false;
- if (conf->form.securembch != NULL) {
- mbchsize = mblen(conf->form.securembch, MB_LEN_MAX);
- if(mbtowc(&form.securewch, conf->form.securembch, mbchsize) < 0)
- RETURN_ERROR("Cannot convert securembch to wchar_t");
- insecurecursor = true;
- } else if (conf->form.securech != '\0') {
- form.securewch = btowc(conf->form.securech);
- insecurecursor = true;
+ /* 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 {
- form.securewch = L' ';
+ f->viewrows = MIN(d->h - BORDERS - htext - HBUTTONS, hform) - 2;
}
- if ((items = malloc(nitems * sizeof(struct privateitem))) == NULL)
- RETURN_ERROR("Cannot allocate internal items");
- form.h = form.w = form.minviewrows = 0;
- for (i = 0; i < nitems; i++) {
- item = &items[i];
- item->label = apiitems[i].label;
- item->ylabel = apiitems[i].ylabel;
- item->xlabel = apiitems[i].xlabel;
- item->yfield = apiitems[i].yfield;
- item->xfield = apiitems[i].xfield;
- item->secure = apiitems[i].flags & BSDDIALOG_FIELDHIDDEN;
- item->readonly = apiitems[i].flags & BSDDIALOG_FIELDREADONLY;
- item->fieldnocolor = apiitems[i].flags & BSDDIALOG_FIELDNOCOLOR;
- item->extendfield = apiitems[i].flags & BSDDIALOG_FIELDEXTEND;
- item->fieldonebyte = apiitems[i].flags &
- BSDDIALOG_FIELDSINGLEBYTE;
- item->cursorend = apiitems[i].flags & BSDDIALOG_FIELDCURSOREND;
- item->bottomdesc = apiitems[i].bottomdesc;
- if (item->readonly || (item->secure && !insecurecursor))
- item->cursor = false;
- else
- item->cursor = true;
+ /* 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);
- item->maxletters = apiitems[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 (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
- if ((winit = alloc_mbstows(apiitems[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] = form.securewch;
- }
+ return (0);
+}
- item->fieldcols = apiitems[i].fieldlen;
- item->xposdraw = 0;
- item->xcursor = 0;
- item->pos = 0;
+static int
+form_redraw(struct dialog *d, struct privateform *f, bool focusinform)
+{
+ unsigned int i;
- form.h = MAX(form.h, items[i].ylabel);
- form.h = MAX(form.h, items[i].yfield);
- form.w = MAX(form.w, items[i].xlabel + strcols(items[i].label));
- form.w = MAX(form.w, items[i].xfield + items[i].fieldcols);
- if (i == 0) {
- itemybeg = MIN(items[i].ylabel, items[i].yfield);
- itemxbeg = MIN(items[i].xlabel, items[i].xfield);
- } else {
- tmp = MIN(items[i].ylabel, items[i].yfield);
- itemybeg = MIN(itemybeg, tmp);
- tmp = MIN(items[i].xlabel, items[i].xfield);
- itemxbeg = MIN(itemxbeg, tmp);
- }
- tmp = abs((int)items[i].ylabel - (int)items[i].yfield);
- form.minviewrows = MAX(form.minviewrows, tmp);
- }
- if (nitems > 0) {
- form.h = form.h + 1 - itemybeg;
- form.w -= itemxbeg;
- form.minviewrows += 1;
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
- form.wmin = form.w;
- for (i = 0; i < nitems; i++) {
- items[i].ylabel -= itemybeg;
- items[i].yfield -= itemybeg;
- items[i].xlabel -= itemxbeg;
- items[i].xfield -= itemxbeg;
+ 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;
+ }
+ if (f->pritems[i].cursorend)
+ fieldctl(&f->pritems[i], MOVE_CURSOR_END);
}
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
- form.viewrows = formheight;
+ wresize(f->pad, f->h, f->w);
+ for (i = 0; i < f->nitems; i++)
+ drawitem(f, i, false);
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_autosize(conf, rows, cols, &h, &w, text, form.w,
- &form.viewrows, form.h, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (form_checksize(h, w, text, &form, nitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
+ 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 (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
+ 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);
+ }
- doupdate();
+ return (0);
+}
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - form.viewrows, x + 1 + w - TEXTHMARGIN);
+/* 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;
- form.border = new_boxed_window(conf, y + h - 5 - form.viewrows, x + 2,
- form.viewrows + 2, w - 4, LOWERED);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
- for (i = 0; i < nitems; i++) {
- if (items[i].extendfield) {
- form.w = w - 6;
- items[i].fieldcols = form.w - items[i].xfield;
- }
- if (items[i].cursorend)
- fieldctl(item, MOVE_CURSOR_END);
- }
+ if (build_privateform(conf, nitems, items, &form) != 0)
+ return (BSDDIALOG_ERROR);
- form.pad = newpad(form.h, form.w);
+ 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);
- form.ys = y + h - 5 - form.viewrows + 1;
- form.ye = y + h - 5 ;
- if ((int)form.w >= w - 6) { /* left */
- form.xs = x + 3;
- form.xe = form.xs + w - 7;
- } else { /* center */
- form.xs = x + 3 + (w-6)/2 - form.w/2;
- form.xe = form.xs + w - 5;
- }
-
- curritem = -1;
- for (i=0 ; i < nitems; i++) {
- DRAWITEM_TRICK(&form, &items[i], false);
- if (curritem == -1 && items[i].readonly == false)
- curritem = i;
- }
- if (curritem != -1) {
+ set_first_with_default(&form, focusitem);
+ if (form.sel != -1) {
focusinform = true;
- redrawbuttons(widget, &bs, conf->button.always_active, false);
form.y = 0;
- item = &items[curritem];
- curriteminview(&form, item);
- update_formborders(conf, &form);
- wrefresh(form.border);
- DRAWITEM_TRICK(&form, item, true);
+ item = &form.pritems[form.sel];
} else {
item = NULL;
focusinform = false;
- wrefresh(form.border);
}
+ 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) {
@@ -695,14 +723,12 @@ bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
case 10: /* Enter */
if (focusinform && conf->button.always_active == false)
break;
- retval = return_values(conf, bs.value[bs.curr],
- nitems, apiitems, items);
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- retval = return_values(conf, BSDDIALOG_ESC,
- nitems, apiitems, items);
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -710,70 +736,72 @@ bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
if (focusinform) {
switchfocus = true;
} else {
- if (bs.curr + 1 < (int)bs.nbuttons) {
- bs.curr++;
+ if (d.bs.curr + 1 < (int)d.bs.nbuttons) {
+ d.bs.curr++;
} else {
- bs.curr = 0;
- if (curritem != -1) {
+ d.bs.curr = 0;
+ if (form.sel != -1) {
switchfocus = true;
}
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
}
break;
case KEY_LEFT:
if (focusinform) {
if(fieldctl(item, MOVE_CURSOR_LEFT))
- DRAWITEM_TRICK(&form, item, true);
- } else if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- } else if (curritem != -1) {
+ 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 (focusinform) {
if(fieldctl(item, MOVE_CURSOR_RIGHT))
- DRAWITEM_TRICK(&form, item, true);
- } else if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- } else if (curritem != -1) {
+ 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 (focusinform) {
- next = previtem(nitems, items, curritem);
- changeitem = curritem != next;
- } else if (curritem != -1) {
+ next = previtem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
+ } else if (form.sel != -1) {
switchfocus = true;
}
break;
case KEY_DOWN:
if (focusinform == false)
break;
- if (nitems == 1) {
+ if (form.nitems == 1) {
switchfocus = true;
} else {
- next = nextitem(nitems, items, curritem);
- changeitem = curritem != next;
+ next = nextitem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
}
break;
case KEY_PPAGE:
if (focusinform) {
- next = firstitem(nitems, items);
- changeitem = curritem != next;
+ next = firstitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
}
break;
case KEY_NPAGE:
if (focusinform) {
- next = lastitem(nitems, items);
- changeitem = curritem != next;
+ next = lastitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
}
break;
case KEY_BACKSPACE:
@@ -782,99 +810,41 @@ bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
break;
if(fieldctl(item, MOVE_CURSOR_LEFT))
if(fieldctl(item, DEL_LETTER))
- DRAWITEM_TRICK(&form, item, true);
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_DC:
if (focusinform == false)
break;
if(fieldctl(item, DEL_LETTER))
- DRAWITEM_TRICK(&form, item, true);
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_HOME:
if (focusinform == false)
break;
if(fieldctl(item, MOVE_CURSOR_BEGIN))
- DRAWITEM_TRICK(&form, item, true);
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_END:
if (focusinform == false)
break;
if (fieldctl(item, MOVE_CURSOR_END))
- DRAWITEM_TRICK(&form, item, true);
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
curs_set(0);
- if (f1help(conf) != 0) {
+ if (f1help_dialog(conf) != 0) {
retval = BSDDIALOG_ERROR;
loop = false;
}
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- form.viewrows = formheight;
- form.w = form.wmin;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_autosize(conf, rows, cols, &h, &w, text, form.w,
- &form.viewrows, form.h, bs) != 0)
+ if (form_redraw(&d, &form, focusinform) != 0)
return (BSDDIALOG_ERROR);
- if (form_checksize(h, w, text, &form, nitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ break;
+ case KEY_RESIZE:
+ if (form_redraw(&d, &form, focusinform) != 0)
return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - form.viewrows, x + 1 + w - TEXTHMARGIN);
-
- wclear(form.border);
- mvwin(form.border, y + h - 5 - form.viewrows, x + 2);
- wresize(form.border, form.viewrows + 2, w - 4);
-
- for (i = 0; i < nitems; i++) {
- fieldctl(&items[i], MOVE_CURSOR_BEGIN);
- if (items[i].extendfield) {
- form.w = w - 6;
- items[i].fieldcols =
- form.w - items[i].xfield;
- }
- if (items[i].cursorend)
- fieldctl(&items[i], MOVE_CURSOR_END);
- }
-
- form.ys = y + h - 5 - form.viewrows + 1;
- form.ye = y + h - 5 ;
- if ((int)form.w >= w - 6) { /* left */
- form.xs = x + 3;
- form.xe = form.xs + w - 7;
- } else { /* center */
- form.xs = x + 3 + (w-6)/2 - form.w/2;
- form.xe = form.xs + w - 5;
- }
-
- if (curritem != -1) {
- redrawbuttons(widget, &bs,
- conf->button.always_active || !focusinform,
- !focusinform);
- curriteminview(&form, item);
- update_formborders(conf, &form);
- wrefresh(form.border);
- /* drawitem just to prefresh() pad */
- DRAWITEM_TRICK(&form, item, focusinform);
- } else {
- wrefresh(form.border);
- }
break;
default:
if (wchtype == KEY_CODE_YES)
@@ -887,55 +857,67 @@ bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
* because the cursor remains on the new letter,
* "if" and "while" update the positions.
*/
- if(insertch(&form, item, input)) {
+ if(insertch(item, input, form.securewch)) {
fieldctl(item, MOVE_CURSOR_RIGHT);
/*
* no if(fieldctl), update always
* because it fails with maxletters.
*/
- DRAWITEM_TRICK(&form, item, true);
+ DRAWITEM_TRICK(&form, form.sel, true);
}
} else {
- if (shortcut_buttons(input, &bs)) {
- retval = return_values(conf,
- bs.value[bs.curr], nitems, apiitems,
- items);
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
break;
- } /* end switch handler */
+ } /* end switch get_wch() */
if (switchfocus) {
focusinform = !focusinform;
- bs.curr = 0;
- redrawbuttons(widget, &bs,
+ d.bs.curr = 0;
+ redrawbuttons(&d,
conf->button.always_active || !focusinform,
!focusinform);
- DRAWITEM_TRICK(&form, item, focusinform);
+ wnoutrefresh(d.widget);
+ DRAWITEM_TRICK(&form, form.sel, focusinform);
switchfocus = false;
}
if (changeitem) {
- DRAWITEM_TRICK(&form, item, false);
- curritem = next;
- item = &items[curritem];
+ DRAWITEM_TRICK(&form, form.sel, false);
+ form.sel = next;
+ item = &form.pritems[form.sel];
curriteminview(&form, item);
- update_formborders(conf, &form);
- DRAWITEM_TRICK(&form, item, true);
+ update_formbox(conf, &form);
+ wnoutrefresh(form.box);
+ DRAWITEM_TRICK(&form, form.sel, true);
changeitem = false;
}
- } /* end while handler */
+ } /* end while(loop) */
curs_set(0);
- delwin(form.pad);
- delwin(form.border);
- for (i = 0; i < nitems; i++) {
- free(items[i].privwbuf);
- free(items[i].pubwbuf);
+ if (return_values(conf, &form, items) == BSDDIALOG_ERROR)
+ return (BSDDIALOG_ERROR);
+
+ if (focusitem != NULL)
+ *focusitem = form.sel;
+
+ if (form.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
}
- end_dialog(conf, shadow, widget, textpad);
+ for (i = 0; i < form.nitems; i++) {
+ free(form.pritems[i].privwbuf);
+ free(form.pritems[i].pubwbuf);
+ }
+ delwin(form.pad);
+ delwin(form.box);
+ end_dialog(&d);
return (retval);
}
diff --git a/lib/infobox.c b/lib/infobox.c
deleted file mode 100644
index c8a0b6e90c8e..000000000000
--- a/lib/infobox.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-
-#include <curses.h>
-
-#include "bsddialog.h"
-#include "lib_util.h"
-
-static int
-infobox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text)
-{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, 0, 1, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, TEXTHMARGINS + 1, NULL);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, false);
-
- return (0);
-}
-
-static int infobox_checksize(int rows, int cols)
-{
- if (cols < HBORDERS)
- RETURN_ERROR("Few cols, infobox needs at least width 2");
-
- if (rows < VBORDERS)
- RETURN_ERROR("Infobox needs at least height 2");
-
- return (0);
-}
-
-/* API */
-int
-bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols)
-{
- int y, x, h, w;
- WINDOW *shadow, *widget, *textpad;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_autosize(conf, rows, cols, &h, &w, text) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_checksize(h, w) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-2,
- x+w-TEXTHMARGIN);
-
- doupdate();
-
- end_dialog(conf, shadow, widget, textpad);
-
- return (BSDDIALOG_OK);
-} \ No newline at end of file
diff --git a/lib/lib_util.c b/lib/lib_util.c
index d8c0f1d21b42..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-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,23 +25,82 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <wchar.h>
#include <wctype.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define ERRBUFLEN 1024 /* Error buffer len */
+/*
+ * -1- Error and diagnostic
+ *
+ * get_error_string();
+ * set_error_string();
+ * set_fmt_error_string();
+ *
+ * ----------------------------------------------------
+ * -2- (Unicode) Multicolumn character strings
+ *
+ * alloc_mbstows();
+ * mvwaddwch();
+ * str_props();
+ * strcols();
+ *
+ * ----------------------------------------------------
+ * -3- Buttons
+ *
+ * [static] buttons_min_width();
+ * [static] draw_button();
+ * draw_buttons();
+ * set_buttons(); (to call 1 time after prepare_dialog()).
+ * shortcut_buttons();
+ *
+ * ----------------------------------------------------
+ * -4- (Auto) Sizing and (Auto) Position
+ *
+ * [static] widget_max_height(conf);
+ * [static] widget_max_width(struct bsddialog_conf *conf)
+ * [static] is_wtext_attr();
+ * [static] text_properties();
+ * [static] text_autosize();
+ * [static] text_size();
+ * [static] widget_min_height(conf, htext, hnotext, bool buttons);
+ * [static] widget_min_width(conf, wtext, minw, buttons);
+ * set_widget_size();
+ * set_widget_autosize(); (not for all dialogs).
+ * widget_checksize(); (not for all dialogs).
+ * set_widget_position();
+ * dialog_size_position(struct dialog); (not for all dialogs).
+ *
+ * ----------------------------------------------------
+ * -5- (Dialog) Widget components and utils
+ *
+ * hide_dialog(struct dialog);
+ * f1help_dialog(conf);
+ * draw_borders(conf, win, elev);
+ * update_box(conf, win, y, x, h, w, elev);
+ * rtextpad(); (helper for pnoutrefresh(textpad)).
+ *
+ * ----------------------------------------------------
+ * -6- Dialog init/build, update/draw, destroy
+ *
+ * end_dialog(struct dialog);
+ * [static] check_set_wtext_attr();
+ * [static] print_string(); (word wrapping).
+ * [static] print_textpad();
+ * draw_dialog(struct dialog);
+ * prepare_dialog(struct dialog);
+ */
+
+/*
+ * -1- Error and diagnostic
+ */
+#define ERRBUFLEN 1024
-/* Error */
static char errorbuffer[ERRBUFLEN];
const char *get_error_string(void)
@@ -54,7 +113,18 @@ void set_error_string(const char *str)
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
-/* Unicode */
+void set_fmt_error_string(const char *fmt, ...)
+{
+ va_list arg_ptr;
+
+ va_start(arg_ptr, fmt);
+ vsnprintf(errorbuffer, ERRBUFLEN-1, fmt, arg_ptr);
+ va_end(arg_ptr);
+}
+
+/*
+ * -2- (Unicode) Multicolumn character strings
+ */
wchar_t* alloc_mbstows(const char *mbstring)
{
size_t charlen, nchar;
@@ -85,7 +155,6 @@ void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
ws[0] = wch;
ws[1] = L'\0';
mvwaddwstr(w, y, x, ws);
-
}
int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
@@ -143,52 +212,20 @@ unsigned int strcols(const char *mbstring)
return (ncol);
}
-/* Clear */
-int hide_widget(int y, int x, int h, int w, bool withshadow)
-{
- WINDOW *clear;
-
- if ((clear = newwin(h, w, y + t.shadow.y, x + t.shadow.x)) == NULL)
- RETURN_ERROR("Cannot hide the widget");
- wbkgd(clear, t.screen.color);
-
- if (withshadow)
- wrefresh(clear);
-
- mvwin(clear, y, x);
- wrefresh(clear);
-
- delwin(clear);
-
- return (0);
-}
-
-/* F1 help */
-int f1help(struct bsddialog_conf *conf)
+/*
+ * -3- Buttons
+ */
+static int buttons_min_width(struct buttons *bs)
{
- int output;
- struct bsddialog_conf hconf;
-
- bsddialog_initconf(&hconf);
- hconf.title = "HELP";
- hconf.button.ok_label = "EXIT";
- hconf.clear = true;
- hconf.ascii_lines = conf->ascii_lines;
- hconf.no_lines = conf->no_lines;
- hconf.shadow = conf->shadow;
- hconf.text.highlight = conf->text.highlight;
-
- output = BSDDIALOG_OK;
- if (conf->key.f1_message != NULL)
- output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+ unsigned int width;
- if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
- output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+ width = bs->nbuttons * bs->sizebutton;
+ if (bs->nbuttons > 0)
+ width += (bs->nbuttons - 1) * t.button.minmargin;
- return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+ return (width);
}
-/* Buttons */
static void
draw_button(WINDOW *window, int y, int x, int size, const char *text,
wchar_t first, bool selected, bool shortcut)
@@ -228,125 +265,138 @@ draw_button(WINDOW *window, int y, int x, int size, const char *text,
}
}
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut)
+void draw_buttons(struct dialog *d)
{
- int i, x, startx, y, rows, cols;
+ int i, x, startx, y;
unsigned int newmargin, margin, wbuttons;
- getmaxyx(window, rows, cols);
- y = rows - 2;
+ y = d->h - 2;
- newmargin = cols - VBORDERS - (bs.nbuttons * bs.sizebutton);
- newmargin /= (bs.nbuttons + 1);
+ 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(bs);
+ wbuttons = buttons_min_width(&d->bs);
} else {
margin = newmargin;
- wbuttons = bs.nbuttons * bs.sizebutton;
- wbuttons += (bs.nbuttons + 1) * margin;
+ wbuttons = d->bs.nbuttons * d->bs.sizebutton;
+ wbuttons += (d->bs.nbuttons + 1) * margin;
}
- startx = (cols)/2 - wbuttons/2 + newmargin;
- for (i = 0; i < (int)bs.nbuttons; i++) {
- x = i * (bs.sizebutton + margin);
- draw_button(window, y, startx + x, bs.sizebutton, bs.label[i],
- bs.first[i], i == bs.curr, shortcut);
+ startx = d->w/2 - wbuttons/2 + newmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ x = i * (d->bs.sizebutton + margin);
+ draw_button(d->widget, y, startx + x, d->bs.sizebutton,
+ d->bs.label[i], d->bs.first[i], i == d->bs.curr,
+ d->bs.shortcut);
}
}
void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel)
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *cancellabel)
{
int i;
#define SIZEBUTTON 8
-#define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL
+#define DEFAULT_BUTTON_LABEL OK_LABEL
#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
wchar_t first;
- bs->nbuttons = 0;
- bs->curr = 0;
- bs->sizebutton = 0;
+ d->bs.nbuttons = 0;
+ d->bs.curr = 0;
+ d->bs.sizebutton = 0;
+ d->bs.shortcut = shortcut;
- if (yesoklabel != NULL && conf->button.without_ok == false) {
- bs->label[0] = conf->button.ok_label != NULL ?
- conf->button.ok_label : yesoklabel;
- bs->value[0] = BSDDIALOG_OK;
- bs->nbuttons += 1;
+ if (d->conf->button.left1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT1;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_extra) {
- bs->label[bs->nbuttons] = conf->button.extra_label != NULL ?
- conf->button.extra_label : "Extra";
- bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
- bs->nbuttons += 1;
+ if (d->conf->button.left2_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left2_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT2;
+ d->bs.nbuttons += 1;
}
- if (nocancellabel != NULL && conf->button.without_cancel == false) {
- bs->label[bs->nbuttons] = conf->button.cancel_label ?
- conf->button.cancel_label : nocancellabel;
- bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
- if (conf->button.default_cancel)
- bs->curr = bs->nbuttons;
- bs->nbuttons += 1;
+ if (d->conf->button.left3_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left3_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT3;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_help) {
- bs->label[bs->nbuttons] = conf->button.help_label != NULL ?
- conf->button.help_label : "Help";
- bs->value[bs->nbuttons] = BSDDIALOG_HELP;
- bs->nbuttons += 1;
+ if (oklabel != NULL && d->conf->button.without_ok == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.ok_label != NULL ?
+ d->conf->button.ok_label : oklabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_OK;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic1_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic1_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1;
- bs->nbuttons += 1;
+ if (d->conf->button.with_extra) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.extra_label != NULL ?
+ d->conf->button.extra_label : "Extra";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_EXTRA;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic2_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic2_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
- bs->nbuttons += 1;
+ if (cancellabel != NULL && d->conf->button.without_cancel == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.cancel_label ?
+ d->conf->button.cancel_label : cancellabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_CANCEL;
+ if (d->conf->button.default_cancel)
+ d->bs.curr = d->bs.nbuttons;
+ d->bs.nbuttons += 1;
}
- if (bs->nbuttons == 0) {
- bs->label[0] = DEFAULT_BUTTON_LABEL;
- bs->value[0] = DEFAULT_BUTTON_VALUE;
- bs->nbuttons = 1;
+ if (d->conf->button.with_help) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.help_label != NULL ?
+ d->conf->button.help_label : "Help";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_HELP;
+ d->bs.nbuttons += 1;
}
- for (i = 0; i < (int)bs->nbuttons; i++) {
- mbtowc(&first, bs->label[i], MB_CUR_MAX);
- bs->first[i] = first;
+ 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 (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.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;
}
- bs->sizebutton = MAX(SIZEBUTTON - 2, strcols(bs->label[0]));
- for (i = 1; i < (int)bs->nbuttons; i++)
- bs->sizebutton = MAX(bs->sizebutton, strcols(bs->label[i]));
- bs->sizebutton += 2;
-}
+ 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;
+ }
-int buttons_min_width(struct buttons bs)
-{
- unsigned int width;
+ if (d->bs.nbuttons == 0) {
+ d->bs.label[0] = DEFAULT_BUTTON_LABEL;
+ d->bs.value[0] = DEFAULT_BUTTON_VALUE;
+ d->bs.nbuttons = 1;
+ }
- width = bs.nbuttons * bs.sizebutton;
- if (bs.nbuttons > 0)
- width += (bs.nbuttons - 1) * t.button.minmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
+ d->bs.first[i] = first;
+ }
- return (width);
+ if (d->conf->button.default_label != NULL) {
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ if (strcmp(d->conf->button.default_label,
+ d->bs.label[i]) == 0)
+ d->bs.curr = i;
+ }
+ }
+
+ d->bs.sizebutton = MAX(SIZEBUTTON - 2, strcols(d->bs.label[0]));
+ for (i = 1; i < (int)d->bs.nbuttons; i++)
+ d->bs.sizebutton = MAX(d->bs.sizebutton, strcols(d->bs.label[i]));
+ d->bs.sizebutton += 2;
}
bool shortcut_buttons(wint_t key, struct buttons *bs)
@@ -366,182 +416,71 @@ bool shortcut_buttons(wint_t key, struct buttons *bs)
return (match);
}
-/* Text */
-static bool is_wtext_attr(const wchar_t *wtext)
-{
- if (wcsnlen(wtext, 3) < 3)
- return (false);
-
- if (wtext[0] != L'\\' || wtext[1] != L'Z')
- return (false);
-
- return (wcschr(L"nbBrRuU01234567", wtext[2]) == NULL ? false : true);
-}
-
-static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
+/*
+ * -4- (Auto) Sizing and (Auto) Position
+ */
+static int widget_max_height(struct bsddialog_conf *conf)
{
- enum bsddialog_color bg;
+ int maxheight;
- if (is_wtext_attr(wtext) == false)
- return (false);
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
- if ((wtext[2] - L'0') >= 0 && (wtext[2] - L'0') < 8) {
- bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
- wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
- return (true);
+ if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
+ RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
+ else if (conf->y == BSDDIALOG_CENTER) {
+ maxheight -= conf->auto_topmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - top "
+ "margins <= 0");
+ } else if (conf->y > 0) {
+ maxheight -= conf->y;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - "
+ "shadow - y <= 0");
}
- switch (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'r':
- wattron(win, A_REVERSE);
- break;
- case L'R':
- wattroff(win, A_REVERSE);
- break;
- case L'u':
- wattron(win, A_UNDERLINE);
- break;
- case L'U':
- wattroff(win, A_UNDERLINE);
- break;
- }
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
- return (true);
+ return (maxheight);
}
-/* Word Wrapping */
-static void
-print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
- bool color)
+static int widget_max_width(struct bsddialog_conf *conf)
{
- int i, j, len, reallen, wc;
- wchar_t ws[2];
-
- ws[1] = L'\0';
+ int maxwidth;
- 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
- reallen = wcswidth(str, len);
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
- i = 0;
- while (i < len) {
- if (*x + reallen > cols) {
- *y = (*x != 0 ? *y+1 : *y);
- if (*y >= *rows) {
- *rows = *y + 1;
- wresize(win, *rows, cols);
- }
- *x = 0;
- }
- j = *x;
- while (j < cols && i < len) {
- if (color && check_set_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;
- }
- }
+ if (conf->x > 0) {
+ maxwidth -= conf->x;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow "
+ "- x <= 0");
}
+
+ return (maxwidth);
}
-static int
-print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- bool loop;
- int i, j, z, rows, cols, x, y, tablen;
- wchar_t *wtext, *string;
-
- if ((wtext = alloc_mbstows(text)) == NULL)
- RETURN_ERROR("Cannot allocate/print text in wchar_t*");
-
- if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
- RETURN_ERROR("Cannot build (analyze) text");
-
- getmaxyx(pad, rows, cols);
- tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
-
- i = j = x = y = 0;
- loop = true;
- while (loop) {
- string[j] = wtext[i];
-
- 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.highlight);
- }
-
- switch (wtext[i]) {
- case L'\0':
- loop = false;
- break;
- case L'\n':
- x = 0;
- y++;
- j = -1;
- break;
- case L'\t':
- for (z = 0; z < tablen; z++) {
- if (x >= cols) {
- x = 0;
- y++;
- }
- x++;
- }
- j = -1;
- break;
- case L' ':
- x++;
- if (x >= cols) {
- x = 0;
- y++;
- }
- j = -1;
- }
-
- if (y >= rows) {
- rows = y + 1;
- wresize(pad, rows, cols);
- }
+ bool att;
- j++;
- i++;
- }
+ if (wcsnlen(wtext, 3) < 3)
+ return (false);
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
+ return (false);
- free(wtext);
- free(string);
+ att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
- return (0);
+ return (att);
}
-/* Text Autosize */
#define NL -1
#define WS -2
#define TB -3
@@ -582,7 +521,7 @@ text_properties(struct bsddialog_conf *conf, const char *text,
wordcols = 0;
l = 0;
for (i = 0; i < wtextlen; i++) {
- if (conf->text.highlight && is_wtext_attr(wtext + i)) {
+ if (conf->text.escape && is_wtext_attr(wtext + i)) {
i += 2; /* +1 for update statement */
continue;
}
@@ -650,20 +589,19 @@ text_properties(struct bsddialog_conf *conf, const char *text,
return (0);
}
-
static int
text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
int maxrows, int mincols, bool increasecols, int *h, int *w)
{
int i, j, x, y, z, l, line, maxwidth, tablen;
- maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS;
+ maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
if (increasecols) {
mincols = MAX(mincols, tp->maxwordcols);
mincols = MAX(mincols,
- (int)conf->auto_minwidth - HBORDERS - TEXTHMARGINS);
+ (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
mincols = MIN(mincols, maxwidth);
}
@@ -736,7 +674,7 @@ text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
return (0);
}
-int
+static int
text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
{
@@ -745,16 +683,16 @@ text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
struct textproperties tp;
wbuttons = 0;
- if (bs != NULL)
- wbuttons = buttons_min_width(*bs);
+ if (bs->nbuttons > 0)
+ wbuttons = buttons_min_width(bs);
/* Rows */
if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
- maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext;
+ maxhtext = widget_max_height(conf) - BORDERS - rowsnotext;
} else { /* fixed */
- maxhtext = rows - VBORDERS - rowsnotext;
+ maxhtext = rows - BORDERS - rowsnotext;
}
- if (bs != NULL)
+ if (bs->nbuttons > 0)
maxhtext -= 2;
if (maxhtext <= 0)
maxhtext = 1; /* text_autosize() computes always htext */
@@ -764,21 +702,23 @@ text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
changewtext = true;
} else if (cols == BSDDIALOG_FULLSCREEN) {
- startwtext = widget_max_width(conf) - VBORDERS - TEXTHMARGINS;
+ startwtext = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
changewtext = false;
} else { /* fixed */
- startwtext = cols - VBORDERS - TEXTHMARGINS;
+ startwtext = cols - BORDERS - TEXTHMARGINS;
changewtext = false;
}
if (startwtext <= 0 && changewtext)
startwtext = 1;
- if (startwtext <= 0)
- RETURN_ERROR("Fullscreen or fixed cols to print text <=0");
/* Sizing calculation */
if (text_properties(conf, text, &tp) != 0)
return (BSDDIALOG_ERROR);
+ if (tp.nword > 0 && startwtext <= 0)
+ RETURN_FMTERROR("(fixed cols or fullscreen) "
+ "needed at least %d cols to draw text",
+ BORDERS + TEXTHMARGINS + 1);
if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
wtext) != 0)
return (BSDDIALOG_ERROR);
@@ -789,84 +729,32 @@ text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
return (0);
}
-/* Widget size and position */
-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");
- }
-
- maxheight -= conf->auto_downmargin;
- if (maxheight <= 0)
- RETURN_ERROR("Terminal too small, screen lines - Down margins "
- "<= 0");
-
- return (maxheight);
-}
-
-int widget_max_width(struct bsddialog_conf *conf)
-{
- int maxwidth;
-
- maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
-
- if (conf->x > 0) {
- maxwidth -= conf->x;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow "
- "- x <= 0");
- }
-
- return (maxwidth);
-}
-
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
+static int
+widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
bool withbuttons)
{
int min;
- min = 0;
-
- /* buttons */
- if (withbuttons)
- min += 2; /* buttons and border */
+ /* dialog borders */
+ min = BORDERS;
/* text */
min += htext;
- /* specific widget min height */
- min += minwidget;
+ /* specific widget lines without text */
+ min += hnotext;
+
+ /* buttons */
+ if (withbuttons)
+ min += HBUTTONS; /* buttons and their up-border */
- /* dialog borders */
- min += HBORDERS;
/* conf.auto_minheight */
min = MAX(min, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_height(conf));
return (min);
}
-int
+static int
widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
struct buttons *bs)
@@ -876,8 +764,8 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
min = 0;
/* buttons */
- if (bs != NULL)
- min += buttons_min_width(*bs);
+ if (bs->nbuttons > 0)
+ min += buttons_min_width(bs);
/* text */
if (wtext > 0)
@@ -900,11 +788,9 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
}
/* dialog borders */
- min += VBORDERS;
+ min += BORDERS;
/* conf.auto_minwidth */
min = MAX(min, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_width(conf));
return (min);
}
@@ -940,6 +826,58 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
}
int
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw)
+{
+ int htext, wtext;
+
+ if (rows == BSDDIALOG_AUTOSIZE || cols == BSDDIALOG_AUTOSIZE ||
+ rowstext != NULL) {
+ if (text_size(conf, rows, cols, text, bs, hnotext, minw,
+ &htext, &wtext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (rowstext != NULL)
+ *rowstext = htext;
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = widget_min_height(conf, htext, hnotext, bs->nbuttons > 0);
+ *h = MIN(*h, widget_max_height(conf));
+ }
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = widget_min_width(conf, wtext, minw, bs);
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ return (0);
+}
+
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw)
+{
+ int minheight, minwidth;
+
+ minheight = BORDERS + hnotext;
+ if (bs->nbuttons > 0)
+ minheight += HBUTTONS;
+ if (h < minheight)
+ RETURN_FMTERROR("Current rows: %d, needed at least: %d",
+ h, minheight);
+
+ minwidth = 0;
+ if (bs->nbuttons > 0)
+ minwidth = buttons_min_width(bs);
+ minwidth = MAX(minwidth, minw);
+ minwidth += BORDERS;
+ if (w < minwidth)
+ RETURN_FMTERROR("Current cols: %d, nedeed at least %d",
+ w, minwidth);
+
+ return (0);
+}
+
+int
set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
{
int hshadow = conf->shadow ? (int)t.shadow.y : 0;
@@ -980,11 +918,70 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
return (0);
}
-/* Widgets build, update, destroy */
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev)
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext)
+{
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, htext, &d->bs, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (widget_checksize(d->h, d->w, &d->bs, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
+}
+
+/*
+ * -5- Widget components and utilities
+ */
+int hide_dialog(struct dialog *d)
+{
+ WINDOW *clear;
+
+ if ((clear = newwin(d->h, d->w, d->y, d->x)) == NULL)
+ RETURN_ERROR("Cannot hide the widget");
+ wbkgd(clear, t.screen.color);
+ wrefresh(clear);
+
+ if (d->conf->shadow) {
+ mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
+ wrefresh(clear);
+ }
+
+ delwin(clear);
+
+ return (0);
+}
+
+int f1help_dialog(struct bsddialog_conf *conf)
+{
+ int output;
+ struct bsddialog_conf hconf;
+
+ bsddialog_initconf(&hconf);
+ hconf.title = "HELP";
+ hconf.button.ok_label = "EXIT";
+ hconf.clear = true;
+ hconf.ascii_lines = conf->ascii_lines;
+ hconf.no_lines = conf->no_lines;
+ hconf.shadow = conf->shadow;
+ hconf.text.escape = conf->text.escape;
+
+ output = BSDDIALOG_OK;
+ if (conf->key.f1_message != NULL)
+ output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+
+ if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
+ output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+
+ return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+}
+
+void draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev)
{
+ int h, w;
int leftcolor, rightcolor;
int ls, rs, ts, bs, tl, tr, bl, br, ltee, rtee;
@@ -1006,199 +1003,353 @@ draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
rtee = ACS_RTEE;
}
+ 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, 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);
+ 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);
}
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
enum elevation elev)
{
- WINDOW *win;
+ wclear(win);
+ wresize(win, h, w);
+ mvwin(win, y, x);
+ draw_borders(conf, win, elev);
+}
- if ((win = newwin(rows, cols, y, x)) == NULL) {
- set_error_string("Cannot build boxed window");
- return (NULL);
- }
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext)
+{
+ pnoutrefresh(d->textpad, ytext, xtext,
+ d->y + BORDER + upnotext,
+ d->x + BORDER + TEXTHMARGIN,
+ d->y + d->h - 1 - downnotext - BORDER,
+ d->x + d->w - TEXTHMARGIN - BORDER);
+}
+
+/*
+ * -6- Dialog init/build, update/draw, destroy
+ */
+void end_dialog(struct dialog *d)
+{
+ if (d->conf->sleep > 0)
+ sleep(d->conf->sleep);
- wbkgd(win, t.dialog.color);
+ delwin(d->textpad);
+ delwin(d->widget);
+ if (d->conf->shadow)
+ delwin(d->shadow);
- draw_borders(conf, win, rows, cols, elev);
+ if (d->conf->clear)
+ hide_dialog(d);
- return (win);
+ if (d->conf->get_height != NULL)
+ *d->conf->get_height = d->h;
+ if (d->conf->get_width != NULL)
+ *d->conf->get_width = d->w;
}
-static int
-draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons)
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
{
- int h, w, wtitle, wbottomtitle, ts, ltee, rtee;
+ enum bsddialog_color bg;
+
+ if (is_wtext_attr(wtext) == false)
+ return (false);
+
+ if ((wtext[2] >= L'0') && (wtext[2] <= L'7')) {
+ bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
+ wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
+ return (true);
+ }
+
+ 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;
+ }
- ts = conf->ascii_lines ? '-' : ACS_HLINE;
- ltee = conf->ascii_lines ? '+' : ACS_LTEE;
- rtee = conf->ascii_lines ? '+' : ACS_RTEE;
+ return (true);
+}
- getmaxyx(widget, h, w);
+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];
- if (conf->shadow)
- wnoutrefresh(shadow);
+ ws[1] = L'\0';
- draw_borders(conf, widget, h, w, RAISED);
+ 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);
- if (conf->title != NULL) {
- if ((wtitle = strcols(conf->title)) < 0)
- return (BSDDIALOG_ERROR);
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, 0, w/2 - wtitle/2 -1, rtee);
- wattroff(widget, t.dialog.lineraisecolor);
+ 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;
}
- wattron(widget, t.dialog.titlecolor);
- mvwaddstr(widget, 0, w/2 - wtitle/2, conf->title);
- wattroff(widget, t.dialog.titlecolor);
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- waddch(widget, ltee);
- wattroff(widget, t.dialog.lineraisecolor);
+ 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;
+ }
}
}
+}
- if (bs != NULL) {
- if (conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, h-3, 0, ltee);
- mvwhline(widget, h-3, 1, ts, w-2);
- wattroff(widget, t.dialog.lineraisecolor);
-
- wattron(widget, t.dialog.linelowercolor);
- mvwaddch(widget, h-3, w-1, rtee);
- wattroff(widget, t.dialog.linelowercolor);
- }
- draw_buttons(widget, *bs, shortcutbuttons);
- }
+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 (conf->bottomtitle != NULL) {
- if ((wbottomtitle = strcols(conf->bottomtitle)) < 0)
- return (BSDDIALOG_ERROR);
- wattron(widget, t.dialog.bottomtitlecolor);
- wmove(widget, h - 1, w/2 - wbottomtitle/2 - 1);
- waddch(widget, ' ');
- waddstr(widget, conf->bottomtitle);
- waddch(widget, ' ');
- wattroff(widget, t.dialog.bottomtitlecolor);
- }
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- wnoutrefresh(widget);
+ if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
+ RETURN_ERROR("Cannot build (analyze) text");
- if (textpad != NULL && text != NULL) /* textbox */
- if (print_textpad(conf, textpad, text) !=0)
- return (BSDDIALOG_ERROR);
+ getmaxyx(pad, rows, cols);
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
- return (0);
-}
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = wtext[i];
-int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons)
-{
- int error;
+ 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);
+ }
- if (conf->shadow) {
- wclear(shadow);
- mvwin(shadow, y + t.shadow.y, x + t.shadow.x);
- wresize(shadow, h, w);
- }
+ switch (wtext[i]) {
+ case L'\0':
+ loop = false;
+ break;
+ case L'\n':
+ x = 0;
+ y++;
+ j = -1;
+ break;
+ case L'\t':
+ for (z = 0; z < tablen; z++) {
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ x++;
+ }
+ j = -1;
+ break;
+ case L' ':
+ x++;
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ j = -1;
+ }
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
+ if (y >= rows) {
+ rows = y + 1;
+ wresize(pad, rows, cols);
+ }
- if (textpad != NULL) {
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - TEXTHMARGINS);
+ j++;
+ i++;
}
- error = draw_dialog(conf, shadow, widget, textpad, text, bs,
- shortcutbuttons);
+ free(wtext);
+ free(string);
- return (error);
+ return (0);
}
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons)
+int draw_dialog(struct dialog *d)
{
- int error;
+ int wtitle, wbottomtitle, ts, ltee, rtee;
- if (conf->shadow) {
- *shadow = newwin(h, w, y + t.shadow.y, x + t.shadow.x);
- 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 (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 ((*widget = new_boxed_window(conf, y, x, h, w, RAISED)) == NULL) {
- if (conf->shadow)
- delwin(*shadow);
- return (BSDDIALOG_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 (textpad != NULL && text != NULL) { /* textbox */
- *textpad = newpad(1, w - HBORDERS - TEXTHMARGINS);
- if (*textpad == NULL) {
- delwin(*widget);
- if (conf->shadow)
- delwin(*shadow);
- RETURN_ERROR("Cannot build the pad window for text");
+ 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_dialog(conf, *shadow, *widget,
- textpad == NULL ? NULL : *textpad, text, bs, shortcutbuttons);
+ 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_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad)
-{
- int y, x, h, w;
+ 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(widget, y, x);
- getmaxyx(widget, h, w);
+ 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(widget);
+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, conf->shadow);
+ /* 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 17ea0e0d1368..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-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,117 +28,136 @@
#ifndef _LIBBSDDIALOG_UTIL_H_
#define _LIBBSDDIALOG_UTIL_H_
-#define HBORDERS 2
-#define VBORDERS 2
+#define BORDER 1
+#define BORDERS (BORDER + BORDER)
#define TEXTHMARGIN 1
#define TEXTHMARGINS (TEXTHMARGIN + TEXTHMARGIN)
+#define HBUTTONS 2
+#define OK_LABEL "OK"
+#define CANCEL_LABEL "Cancel"
-/* theme utils */
+/* 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)
-
-/* date */
-#define ISLEAP(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
-
-/* unicode */
-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);
-
-/* error buffer */
-const char *get_error_string(void);
-void set_error_string(const char *string);
-
-#define RETURN_ERROR(str) do { \
- set_error_string(str); \
- return (BSDDIALOG_ERROR); \
+/* error and diagnostic */
+#define RETURN_ERROR(str) do { \
+ set_error_string(str); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+#define RETURN_FMTERROR(fmt, ...) do { \
+ set_fmt_error_string(fmt, __VA_ARGS__); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+/* check ptr */
+#define CHECK_PTR(p) do { \
+ if (p == NULL) \
+ RETURN_ERROR("*" #p " is NULL"); \
+} while (0)
+#define CHECK_ARRAY(nitem, a) do { \
+ if(nitem > 0 && a == NULL) \
+ RETURN_FMTERROR(#nitem " is %d but *" #a " is NULL", nitem); \
+} while (0)
+/* widget utils */
+#define 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 */
+/* internal types */
+enum elevation { RAISED, LOWERED };
+
struct buttons {
unsigned int nbuttons;
-#define MAXBUTTONS 6 /* ok + extra + cancel + help + 2 generics */
+#define MAXBUTTONS 10 /* 3left + ok + extra + cancel + help + 3 right */
const char *label[MAXBUTTONS];
+ bool shortcut;
wchar_t first[MAXBUTTONS];
int value[MAXBUTTONS];
int curr;
+#define BUTTONVALUE(bs) bs.value[bs.curr]
unsigned int sizebutton; /* including left and right delimiters */
};
-#define BUTTON_OK_LABEL "OK"
-#define BUTTON_CANCEL_LABEL "Cancel"
-void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel);
-
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut);
-
-int buttons_min_width(struct buttons bs);
-bool shortcut_buttons(wint_t key, struct buttons *bs);
+struct dialog {
+ bool built; /* true after the first draw_dialog() */
+ struct bsddialog_conf *conf; /* Checked API conf */
+ WINDOW *widget; /* Size and position refer to widget */
+ int y, x; /* Current position, API conf.[y|x]: -1, >=0 */
+ int rows, cols; /* API rows and cols: -1, 0, >0 */
+ int h, w; /* Current height and width */
+ const char *text; /* Checked API text, at least "" */
+ WINDOW *textpad; /* Fake for textbox */
+ struct buttons bs; /* bs.nbuttons = 0 for no buttons */
+ WINDOW *shadow;
+};
-/* help window with F1 key */
-int f1help(struct bsddialog_conf *conf);
+/* error and diagnostic */
+const char *get_error_string(void);
+void set_error_string(const char *string);
+void set_fmt_error_string(const char *fmt, ...);
-/* cleaner */
-int hide_widget(int y, int x, int h, int w, bool withshadow);
+/* multicolumn character string */
+unsigned int strcols(const char *mbstring);
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col);
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch);
+wchar_t* alloc_mbstows(const char *mbstring);
-/* (auto) size and (auto) position */
-#define SCREENLINES (getmaxy(stdscr))
-#define SCREENCOLS (getmaxx(stdscr))
+/* buttons */
+void
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *canclabel);
+void draw_buttons(struct dialog *d);
+bool shortcut_buttons(wint_t key, struct buttons *bs);
-int
-text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
- struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext);
+/* widget utils */
+int hide_dialog(struct dialog *d);
+int f1help_dialog(struct bsddialog_conf *conf);
-int widget_max_height(struct bsddialog_conf *conf);
-int widget_max_width(struct bsddialog_conf *conf);
+void
+draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev);
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
- bool withbuttons);
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev);
-int
-widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
- struct buttons *bs);
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext);
+/* (auto) sizing and (auto) position */
int
set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h,
int *w);
int
-set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw);
-/* widget builders */
-enum elevation { RAISED, LOWERED };
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw);
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev);
+int
+set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
- enum elevation elev);
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext);
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons);
+/* dialog */
+void end_dialog(struct dialog *d);
+int draw_dialog(struct dialog *d);
int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons);
-
-void
-end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad);
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d);
#endif
diff --git a/lib/libbsddialog.c b/lib/libbsddialog.c
index 73c1f5c2dd57..755a469b126c 100644
--- a/lib/libbsddialog.c
+++ b/lib/libbsddialog.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,15 +26,15 @@
*/
#include <curses.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define COLSPERROW 10 /* Default conf.text.columns_per_row */
+#define DEFAULT_COLS_PER_ROW 10 /* Default conf.text.columns_per_row */
+
+static bool in_bsddialog_mode = false;
int bsddialog_init_notheme(void)
{
@@ -55,6 +55,7 @@ int bsddialog_init_notheme(void)
bsddialog_end();
RETURN_ERROR("Cannot init curses (keypad and cursor)");
}
+ in_bsddialog_mode = true;
c = 1;
error += start_color();
@@ -83,6 +84,7 @@ int bsddialog_init(void)
if (bsddialog_set_default_theme(theme) != 0) {
bsddialog_end();
+ in_bsddialog_mode = false;
return (BSDDIALOG_ERROR);
}
@@ -93,15 +95,18 @@ int bsddialog_end(void)
{
if (endwin() != OK)
RETURN_ERROR("Cannot end curses (endwin)");
+ in_bsddialog_mode = false;
return (BSDDIALOG_OK);
}
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle)
{
+ CHECK_PTR(conf);
+
move(0, 1);
clrtoeol();
- addstr(backtitle);
+ addstr(CHECK_STR(backtitle));
if (conf->no_lines != true)
mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE,
SCREENCOLS - 2);
@@ -111,6 +116,11 @@ int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle)
return (BSDDIALOG_OK);
}
+bool bsddialog_inmode(void)
+{
+ return (in_bsddialog_mode);
+}
+
const char *bsddialog_geterror(void)
{
return (get_error_string());
@@ -118,25 +128,25 @@ const char *bsddialog_geterror(void)
int bsddialog_initconf(struct bsddialog_conf *conf)
{
- if (conf == NULL)
- RETURN_ERROR("conf is NULL");
- if (sizeof(*conf) != sizeof(struct bsddialog_conf))
- RETURN_ERROR("Bad conf size");
+ CHECK_PTR(conf);
memset(conf, 0, sizeof(struct bsddialog_conf));
conf->y = BSDDIALOG_CENTER;
conf->x = BSDDIALOG_CENTER;
conf->shadow = true;
- conf->text.cols_per_row = COLSPERROW;
+ conf->text.cols_per_row = DEFAULT_COLS_PER_ROW;
return (BSDDIALOG_OK);
}
-int bsddialog_clearterminal(void)
+void bsddialog_refresh(void)
{
- if (clear() != OK)
- RETURN_ERROR("Cannot clear the terminal");
refresh();
+}
- return (BSDDIALOG_OK);
+void bsddialog_clear(unsigned int y)
+{
+ move(y, 0);
+ clrtobot();
+ refresh();
} \ No newline at end of file
diff --git a/lib/menubox.c b/lib/menubox.c
index bd06a9e37df2..b6213aa8f997 100644
--- a/lib/menubox.c
+++ b/lib/menubox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,19 +25,13 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define MIN_HEIGHT VBORDERS + 6 /* 2 buttons 1 text 3 menu */
-
enum menumode {
CHECKLISTMODE,
MENUMODE,
@@ -46,47 +40,155 @@ enum menumode {
SEPARATORMODE
};
-struct lineposition {
- unsigned int maxsepstr;
- unsigned int maxprefix;
- unsigned int xselector;
- unsigned int selectorlen;
- unsigned int maxdepth;
- unsigned int xname;
- unsigned int maxname;
- unsigned int xdesc;
- unsigned int maxdesc;
- unsigned int line;
-};
-
struct privateitem {
- bool on;
- int group;
- int index;
+ const char *prefix;
+ bool on; /* menu changes, not API on */
+ unsigned int depth;
+ const char *name;
+ const char *desc;
+ const char *bottomdesc;
+ int group; /* index menu in menugroup */
+ int index; /* real item index inside its menu */
enum menumode type;
- struct bsddialog_menuitem *item;
+ wchar_t shortcut;
};
-static void
-set_on_output(struct bsddialog_conf *conf, int output, int ngroups,
- struct bsddialog_menugroup *groups, struct privateitem *pritems)
+struct privatemenu {
+ WINDOW *box; /* only for borders */
+ WINDOW *pad; /* pad for the private items */
+ int ypad; /* start pad line */
+ int ys, ye, xs, xe; /* pad pos */
+ unsigned int xselector; /* [] */
+ unsigned int xname; /* real x: xname + item.depth */
+ unsigned int xdesc; /* real x: xdesc + item.depth */
+ unsigned int line; /* wpad: prefix [] depth name desc */
+ unsigned int apimenurows;
+ unsigned int menurows; /* real menurows after menu_size_position() */
+ int nitems; /* total nitems (all groups * all items) */
+ struct privateitem *pritems;
+ int sel; /* current focus item, can be -1 */
+ bool hasbottomdesc;
+};
+
+static enum menumode
+getmode(enum menumode mode, struct bsddialog_menugroup group)
{
+ if (mode == MIXEDLISTMODE) {
+ if (group.type == BSDDIALOG_SEPARATOR)
+ mode = SEPARATORMODE;
+ else if (group.type == BSDDIALOG_RADIOLIST)
+ mode = RADIOLISTMODE;
+ else if (group.type == BSDDIALOG_CHECKLIST)
+ mode = CHECKLISTMODE;
+ }
+
+ return (mode);
+}
+
+static int
+build_privatemenu(struct bsddialog_conf *conf, struct privatemenu *m,
+ enum menumode mode, unsigned int ngroups,
+ struct bsddialog_menugroup *groups)
+{
+ bool onetrue;
int i, j, abs;
+ unsigned int maxsepstr, maxprefix, selectorlen, maxdepth;
+ unsigned int maxname, maxdesc;
+ struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- if (output != BSDDIALOG_OK && !conf->menu.on_without_ok)
- return;
+ /* nitems and fault checks */
+ CHECK_ARRAY(ngroups, groups);
+ m->nitems = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ CHECK_ARRAY(groups[i].nitems, groups[i].items);
+ m->nitems += (int)groups[i].nitems;
+ }
- for(i = abs = 0; i < ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- abs += groups[i].nitems;
- continue;
- }
+ /* alloc and set private items */
+ m->pritems = calloc(m->nitems, sizeof (struct privateitem));
+ if (m->pritems == NULL)
+ RETURN_ERROR("Cannot allocate memory for internal menu items");
+ m->hasbottomdesc = false;
+ abs = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ onetrue = false;
+ for (j = 0; j < (int)groups[i].nitems; j++) {
+ item = &groups[i].items[j];
+ pritem = &m->pritems[abs];
+
+ if (getmode(mode, groups[i]) == MENUMODE) {
+ m->pritems[abs].on = false;
+ } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
+ m->pritems[abs].on = onetrue ? false : item->on;
+ if (m->pritems[abs].on)
+ onetrue = true;
+ } else { /* CHECKLISTMODE */
+ m->pritems[abs].on = item->on;
+ }
+ pritem->group = i;
+ pritem->index = j;
+ pritem->type = getmode(mode, groups[i]);
+
+ pritem->prefix = CHECK_STR(item->prefix);
+ pritem->depth = item->depth;
+ pritem->name = CHECK_STR(item->name);
+ pritem->desc = CHECK_STR(item->desc);
+ pritem->bottomdesc = CHECK_STR(item->bottomdesc);
+ if (item->bottomdesc != NULL)
+ m->hasbottomdesc = true;
+
+ mbtowc(&pritem->shortcut, conf->menu.no_name ?
+ pritem->desc : pritem->name, MB_CUR_MAX);
- for(j = 0; j < (int)groups[i].nitems; j++) {
- groups[i].items[j].on = pritems[abs].on;
abs++;
}
}
+
+ /* positions */
+ m->xselector = m->xname = m->xdesc = m->line = 0;
+ maxsepstr = maxprefix = selectorlen = maxdepth = maxname = maxdesc = 0;
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == RADIOLISTMODE ||
+ m->pritems[i].type == CHECKLISTMODE)
+ selectorlen = 4;
+
+ if (m->pritems[i].type == SEPARATORMODE) {
+ maxsepstr = MAX(maxsepstr,
+ strcols(m->pritems[i].name) +
+ strcols(m->pritems[i].desc));
+ continue;
+ }
+
+ maxprefix = MAX(maxprefix, strcols(m->pritems[i].prefix));
+ maxdepth = MAX(maxdepth, m->pritems[i].depth);
+ maxname = MAX(maxname, strcols(m->pritems[i].name));
+ maxdesc = MAX(maxdesc, strcols(m->pritems[i].desc));
+ }
+ maxname = conf->menu.no_name ? 0 : maxname;
+ maxdesc = conf->menu.no_desc ? 0 : maxdesc;
+
+ m->xselector = maxprefix + (maxprefix != 0 ? 1 : 0);
+ m->xname = m->xselector + selectorlen;
+ m->xdesc = maxdepth + m->xname + maxname;
+ m->xdesc += (maxname != 0 ? 1 : 0);
+ m->line = MAX(maxsepstr + 3, m->xdesc + maxdesc);
+
+ return (0);
+}
+
+static void
+set_return_on(struct privatemenu *m, struct bsddialog_menugroup *groups)
+{
+ int i;
+ struct privateitem *pritem;
+
+ for(i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == SEPARATORMODE)
+ continue;
+ pritem = &m->pritems[i];
+ groups[pritem->group].items[pritem->index].on = pritem->on;
+ }
}
static int getprev(struct privateitem *pritems, int abs)
@@ -175,26 +277,17 @@ getfastprev(int menurows, struct privateitem *pritems, int abs)
}
static int
-getnextshortcut(struct bsddialog_conf *conf, int npritems,
- struct privateitem *pritems, int abs, wint_t key)
+getnextshortcut(int npritems, struct privateitem *pritems, int abs, wint_t key)
{
int i, next;
- wchar_t wch;
next = -1;
for (i = 0; i < npritems; i++) {
if (pritems[i].type == SEPARATORMODE)
continue;
-
- if (conf->menu.no_name)
- mbtowc(&wch, pritems[i].item->desc, MB_CUR_MAX);
- else
- mbtowc(&wch, pritems[i].item->name, MB_CUR_MAX);
-
- if (wch == (wchar_t)key) {
+ if (pritems[i].shortcut == (wchar_t)key) {
if (i > abs)
return (i);
-
if (i < abs && next == -1)
next = i;
}
@@ -203,81 +296,64 @@ getnextshortcut(struct bsddialog_conf *conf, int npritems,
return (next != -1 ? next : abs);
}
-static enum menumode
-getmode(enum menumode mode, struct bsddialog_menugroup group)
+static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m)
{
- if (mode == MIXEDLISTMODE) {
- if (group.type == BSDDIALOG_SEPARATOR)
- mode = SEPARATORMODE;
- else if (group.type == BSDDIALOG_RADIOLIST)
- mode = RADIOLISTMODE;
- else if (group.type == BSDDIALOG_CHECKLIST)
- mode = CHECKLISTMODE;
- }
-
- return (mode);
-}
-
-static void
-drawseparators(struct bsddialog_conf *conf, WINDOW *pad, int linelen,
- int nitems, struct privateitem *pritems)
-{
- int i, linech, labellen;
+ int i, linech, realw, labellen;
const char *desc, *name;
- for (i = 0; i < nitems; i++) {
- if (pritems[i].type != SEPARATORMODE)
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type != SEPARATORMODE)
continue;
if (conf->no_lines == false) {
- wattron(pad, t.menu.desccolor);
+ wattron(m->pad, t.menu.desccolor);
linech = conf->ascii_lines ? '-' : ACS_HLINE;
- mvwhline(pad, i, 0, linech, linelen);
- wattroff(pad, t.menu.desccolor);
+ mvwhline(m->pad, i, 0, linech, m->line);
+ wattroff(m->pad, t.menu.desccolor);
}
- name = pritems[i].item->name;
- desc = pritems[i].item->desc;
+ name = m->pritems[i].name;
+ desc = m->pritems[i].desc;
+ realw = m->xe - m->xs;
labellen = strcols(name) + strcols(desc) + 1;
- wmove(pad, i, labellen < linelen ? linelen/2 - labellen/2 : 0);
- wattron(pad, t.menu.namesepcolor);
- waddstr(pad, name);
- wattroff(pad, t.menu.namesepcolor);
+ 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(pad, ' ');
- wattron(pad, t.menu.descsepcolor);
- waddstr(pad, desc);
- wattroff(pad, t.menu.descsepcolor);
+ waddch(m->pad, ' ');
+ wattron(m->pad, t.menu.sepdesccolor);
+ waddstr(m->pad, desc);
+ wattroff(m->pad, t.menu.sepdesccolor);
}
}
static void
-drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
- struct lineposition pos, struct privateitem *pritem, bool focus)
+drawitem(struct bsddialog_conf *conf, struct privatemenu *m, int y, bool focus)
{
int colordesc, colorname, colorshortcut;
- wchar_t shortcut;
- struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- item = pritem->item;
+ pritem = &m->pritems[y];
/* prefix */
- if (item->prefix != NULL && item->prefix[0] != '\0')
- mvwaddstr(pad, y, 0, item->prefix);
+ wattron(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
+ mvwaddstr(m->pad, y, 0, pritem->prefix);
+ wattroff(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
/* selector */
- wmove(pad, y, pos.xselector);
- wattron(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wmove(m->pad, y, m->xselector);
+ wattron(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
if (pritem->type == CHECKLISTMODE)
- wprintw(pad, "[%c]", pritem->on ? 'X' : ' ');
+ wprintw(m->pad, "[%c]", pritem->on ? 'X' : ' ');
if (pritem->type == RADIOLISTMODE)
- wprintw(pad, "(%c)", pritem->on ? '*' : ' ');
- wattroff(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wprintw(m->pad, "(%c)", pritem->on ? '*' : ' ');
+ wattroff(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
/* name */
colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
if (conf->menu.no_name == false) {
- wattron(pad, colorname);
- mvwaddstr(pad, y, pos.xname + item->depth, item->name);
- wattroff(pad, colorname);
+ wattron(m->pad, colorname);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth, pritem->name);
+ wattroff(m->pad, colorname);
}
/* description */
@@ -287,142 +363,137 @@ drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
if (conf->menu.no_desc == false) {
- wattron(pad, colordesc);
+ wattron(m->pad, colordesc);
if (conf->menu.no_name)
- mvwaddstr(pad, y, pos.xname + item->depth, item->desc);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth,
+ pritem->desc);
else
- mvwaddstr(pad, y, pos.xdesc, item->desc);
- wattroff(pad, colordesc);
+ mvwaddstr(m->pad, y, m->xdesc, pritem->desc);
+ wattroff(m->pad, colordesc);
}
/* shortcut */
if (conf->menu.shortcut_buttons == false) {
colorshortcut = focus ?
t.menu.f_shortcutcolor : t.menu.shortcutcolor;
- wattron(pad, colorshortcut);
-
- if (conf->menu.no_name)
- mbtowc(&shortcut, item->desc, MB_CUR_MAX);
- else
- mbtowc(&shortcut, item->name, MB_CUR_MAX);
- mvwaddwch(pad, y, pos.xname + item->depth, shortcut);
- wattroff(pad, colorshortcut);
+ wattron(m->pad, colorshortcut);
+ mvwaddwch(m->pad, y, m->xname + pritem->depth, pritem->shortcut);
+ wattroff(m->pad, colorshortcut);
}
/* bottom description */
- move(SCREENLINES - 1, 2);
- clrtoeol();
- if (item->bottomdesc != NULL && focus) {
- attron(t.menu.bottomdesccolor);
- addstr(item->bottomdesc);
- attroff(t.menu.bottomdesccolor);
- refresh();
+ if (m->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (focus) {
+ attron(t.menu.bottomdesccolor);
+ addstr(pritem->bottomdesc);
+ attroff(t.menu.bottomdesccolor);
+ refresh();
+ }
}
}
-/* 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 void update_menubox(struct bsddialog_conf *conf, struct privatemenu *m)
{
- draw_borders(conf, menuwin, h, w, LOWERED);
+ int h, w;
+
+ draw_borders(conf, m->box, LOWERED);
+ getmaxyx(m->box, h, w);
- if (totnitems > (int)menurows) {
- wattron(menuwin, t.dialog.arrowcolor);
- if (ymenupad > 0)
- mvwhline(menuwin, 0, 2,
+ 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);
- if ((ymenupad + (int)menurows) < totnitems)
- mvwhline(menuwin, h-1, 2,
+ if ((m->ypad + (int)m->menurows) < m->nitems)
+ mvwhline(m->box, h-1, 2,
conf->ascii_lines ? 'v' : ACS_DARROW, 3);
- mvwprintw(menuwin, h-1, w-6, "%3d%%",
- 100 * (ymenupad + menurows) / totnitems);
- wattroff(menuwin, t.dialog.arrowcolor);
+ mvwprintw(m->box, h-1, w-6, "%3d%%",
+ 100 * (m->ypad + m->menurows) / m->nitems);
+ wattroff(m->box, t.dialog.arrowcolor);
}
}
-static int
-menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *menurows, int nitems,
- struct buttons bs)
+static int menu_size_position(struct dialog *d, struct privatemenu *m)
{
- int htext, wtext, menusize, notext;
-
- notext = 2;
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- /* algo 1): grows vertically */
- /* notext = 1; */
- /* algo 2): grows horizontally, better with little screens */
- notext += nitems;
- notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
- } else
- notext += *menurows;
-
- if (text_size(conf, rows, cols, text, &bs, notext, linelen + 4, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
+ int htext, hmenu;
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 4, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *menurows = menusize - 2 < 0 ? 0 : menusize - 2;
- } else /* h autosize with fixed menurows */
- menusize = *menurows + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- } else { /* fixed rows */
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- if (*h - 6 - htext <= 0)
- *menurows = 0; /* menu_checksize() will check */
- else
- *menurows = MIN(*h-6-htext, nitems);
- }
- }
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
- /* avoid menurows overflow and menurows becomes at most menurows */
- if (*h - 6 - htext <= 0)
- *menurows = 0; /* menu_checksize() will check */
+ 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
- *menurows = MIN(*h - 6 - htext, (int)*menurows);
-
- return (0);
-}
+ m->menurows = MIN(d->h - BORDERS - htext - HBUTTONS, hmenu) - 2;
-static int
-menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
- struct buttons bs)
-{
- int mincols, textrow, menusize;
-
- mincols = VBORDERS;
- /* buttons */
- mincols += buttons_min_width(bs);
/*
- * linelen check, comment to allow some hidden col otherwise portconfig
- * could not show big menus like www/apache24
+ * no minw=linelen to avoid big menu fault, then some col can be
+ * hidden (example portconfig www/apache24).
*/
- /* mincols = MAX(mincols, linelen); */
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "name + descripion of the items");
+ if (widget_checksize(d->h, d->w, &d->bs,
+ 2 /* border box */ + MIN(m->menurows, 1), 0) != 0)
+ return (BSDDIALOG_ERROR);
- textrow = text != NULL && text[0] != '\0' ? 1 : 0;
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
- if (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, if menurows = 0 "
- "terminal too small");
+ return (0);
+}
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this menus");
+static int mixedlist_redraw(struct dialog *d, struct privatemenu *m)
+{
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ m->menurows = m->apimenurows;
+ if (menu_size_position(d, m) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2/*bmenu*/ + m->menurows + HBUTTONS);
+
+ /* selected item in view*/
+ if (m->ypad > m->sel && m->ypad > 0)
+ m->ypad = m->sel;
+ if ((int)(m->ypad + m->menurows) <= m->sel)
+ m->ypad = m->sel - m->menurows + 1;
+ /* lower pad after a terminal expansion */
+ if (m->ypad > 0 && (m->nitems - m->ypad) < (int)m->menurows)
+ m->ypad = m->nitems - m->menurows;
+
+ update_box(d->conf, m->box, d->y + d->h - 5 - m->menurows, d->x + 2,
+ m->menurows+2, d->w-4, LOWERED);
+ update_menubox(d->conf, m);
+ wnoutrefresh(m->box);
+
+ m->ys = d->y + d->h - 5 - m->menurows + 1;
+ m->ye = d->y + d->h - 5 ;
+ if (d->conf->menu.align_left || (int)m->line > d->w - 6) {
+ m->xs = d->x + 3;
+ m->xe = m->xs + d->w - 7;
+ } else { /* center */
+ m->xs = d->x + 3 + (d->w-6)/2 - m->line/2;
+ m->xe = m->xs + d->w - 5;
+ }
+ drawseparators(d->conf, m); /* uses xe - xs */
+ pnoutrefresh(m->pad, m->ypad, 0, m->ys, m->xs, m->ye, m->xe);
return (0);
}
@@ -432,332 +503,185 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
unsigned int menurows, enum menumode mode, unsigned int ngroups,
struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
{
- bool loop, onetrue, movefocus, automenurows, shortcut_butts;
- int i, j, y, x, h, w, retval;
- int ymenupad, ys, ye, xs, xe, abs, next, totnitems;
+ bool loop, changeitem;
+ int i, next, retval;
wint_t input;
- WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
- struct buttons bs;
- struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- struct bsddialog_menuitem *item;
- struct privateitem *pritems;
-
- shortcut_butts = conf->menu.shortcut_buttons;
-
- automenurows = (menurows == BSDDIALOG_AUTOSIZE) ? true : false;
-
- totnitems = 0;
- for (i = 0; i < (int)ngroups; i++) {
- if (getmode(mode, groups[i]) == RADIOLISTMODE ||
- getmode(mode, groups[i]) == CHECKLISTMODE)
- pos.selectorlen = 3;
-
- for (j = 0; j < (int)groups[i].nitems; j++) {
- totnitems++;
- item = &groups[i].items[j];
+ struct privatemenu m;
+ struct dialog d;
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- pos.maxsepstr = MAX(pos.maxsepstr,
- strcols(item->name) + strcols(item->desc));
- continue;
- }
-
- pos.maxprefix = MAX(pos.maxprefix,strcols(item->prefix));
- pos.maxdepth = MAX(pos.maxdepth, item->depth);
- pos.maxname = MAX(pos.maxname, strcols(item->name));
- pos.maxdesc = MAX(pos.maxdesc, strcols(item->desc));
- }
- }
- pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
- pos.maxdesc = conf->menu.no_desc ? 0 : pos.maxdesc;
-
- pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
- pos.xname = pos.xselector + pos.selectorlen +
- (pos.selectorlen > 0 ? 1 : 0);
- pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
- pos.xdesc += (pos.maxname != 0 ? 1 : 0);
- pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
- totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
+ set_buttons(&d, conf->menu.shortcut_buttons, OK_LABEL, CANCEL_LABEL);
+ if (d.conf->menu.no_name && d.conf->menu.no_desc)
+ RETURN_ERROR("Both conf.menu.no_name and conf.menu.no_desc");
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- shortcut_butts) != 0)
+ if (build_privatemenu(conf, &m, mode, ngroups, groups) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN, y + h - menurows,
- x + 1 + w - TEXTHMARGIN);
+ 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);
- menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
- menurows + 2, w - 4, LOWERED);
-
- menupad = newpad(totnitems, pos.line);
- wbkgd(menupad, t.dialog.color);
-
- if ((pritems = calloc(totnitems, sizeof (struct privateitem))) == NULL)
- RETURN_ERROR("Cannot allocate memory for internal menu items");
-
- abs = 0;
- for (i = 0; i < (int)ngroups; i++) {
- onetrue = false;
- for (j = 0; j < (int)groups[i].nitems; j++) {
- item = &groups[i].items[j];
-
- if (getmode(mode, groups[i]) == MENUMODE) {
- pritems[abs].on = false;
- } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
- pritems[abs].on = onetrue ? false : item->on;
- if (pritems[abs].on)
- onetrue = true;
- } else {
- pritems[abs].on = item->on;
- }
- pritems[abs].group = i;
- pritems[abs].index = j;
- pritems[abs].type = getmode(mode, groups[i]);
- pritems[abs].item = item;
-
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs++;
- }
- }
- drawseparators(conf, menupad, MIN((int)pos.line, w-6), totnitems,
- pritems);
- abs = getfirst_with_default(totnitems, pritems, ngroups, groups,
+ for (i = 0; i < m.nitems; i++)
+ drawitem(conf, &m, i, false);
+ m.sel = getfirst_with_default(m.nitems, m.pritems, ngroups, groups,
focuslist, focusitem);
- if (abs >= 0)
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- ymenupad = 0;
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows,
- ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ if (m.sel >= 0)
+ drawitem(d.conf, &m, m.sel, true);
+ m.ypad = 0;
+ m.apimenurows = menurows;
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
- movefocus = false;
+ changeitem = false;
loop = true;
while (loop) {
+ doupdate();
if (get_wch(&input) == ERR)
continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- retval = bs.value[bs.curr];
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, retval, ngroups, groups, pritems);
+ retval = BUTTONVALUE(d.bs);
+ if (m.sel >= 0 && m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
retval = BSDDIALOG_ESC;
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, retval, ngroups, groups,
- pritems);
+ if (m.sel >= 0 &&
+ m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- menurows = automenurows ? 0 : menurows;
- if (menu_autosize(conf, rows, cols, &h, &w, text,
- pos.line, &menurows, totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems,
- bs) != 0)
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, shortcut_butts) != 0)
+ break;
+ case KEY_RESIZE:
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
-
- wclear(menuwin);
- mvwin(menuwin, y + h - 5 - menurows, x + 2);
- wresize(menuwin,menurows+2, w-4);
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- drawseparators(conf, menupad, MIN((int)pos.line, w-6),
- totnitems, pritems);
-
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
-
- refresh();
-
break;
}
- if (abs < 0)
+ if (m.sel < 0)
continue;
switch(input) {
case KEY_HOME:
- next = getnext(totnitems, pritems, -1);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, -1);
+ changeitem = next != m.sel;
break;
case KEY_UP:
- next = getprev(pritems, abs);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_PPAGE:
- next = getfastprev(menurows, pritems, abs);
- movefocus = next != abs;
+ next = getfastprev(m.menurows, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_END:
- next = getprev(pritems, totnitems);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.nitems);
+ changeitem = next != m.sel;
break;
case KEY_DOWN:
- next = getnext(totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_NPAGE:
- next = getfastnext(menurows, totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getfastnext(m.menurows, m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case ' ': /* Space */
- if (pritems[abs].type == MENUMODE) {
- retval = bs.value[bs.curr];
- pritems[abs].on = true;
- set_on_output(conf, retval, ngroups, groups,
- pritems);
+ if (m.pritems[m.sel].type == MENUMODE) {
+ retval = BUTTONVALUE(d.bs);
+ m.pritems[m.sel].on = true;
loop = false;
- } else if (pritems[abs].type == CHECKLISTMODE) {
- pritems[abs].on = !pritems[abs].on;
+ } else if (m.pritems[m.sel].type == CHECKLISTMODE) {
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
} else { /* RADIOLISTMODE */
- for (i = abs - pritems[abs].index;
- i < totnitems &&
- pritems[i].group == pritems[abs].group;
+ for (i = m.sel - m.pritems[m.sel].index;
+ i < m.nitems &&
+ m.pritems[i].group == m.pritems[m.sel].group;
i++) {
- if (i != abs && pritems[i].on) {
- pritems[i].on = false;
- drawitem(conf, menupad, i, pos,
- &pritems[i], false);
+ if (i != m.sel && m.pritems[i].on) {
+ m.pritems[i].on = false;
+ drawitem(conf, &m, i, false);
}
}
- pritems[abs].on = !pritems[abs].on;
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
}
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ drawitem(conf, &m, m.sel, true);
+ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
break;
default:
- if (shortcut_butts) {
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
- if (pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, retval, ngroups,
- groups, pritems);
+ if (conf->menu.shortcut_buttons) {
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ if (m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
}
/* shourtcut items */
- next = getnextshortcut(conf, totnitems, pritems, abs,
+ next = getnextshortcut(m.nitems, m.pritems, m.sel,
input);
- movefocus = next != abs;
- } /* end switch handler */
-
- if (movefocus) {
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs = next;
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- if (ymenupad > abs && ymenupad > 0)
- ymenupad = abs;
- if ((int)(ymenupad + menurows) <= abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
- movefocus = false;
+ 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 handler */
+ } /* end while(loop) */
+
+ set_return_on(&m, groups);
if (focuslist != NULL)
- *focuslist = abs < 0 ? -1 : pritems[abs].group;
+ *focuslist = m.sel < 0 ? -1 : m.pritems[m.sel].group;
if (focusitem !=NULL)
- *focusitem = abs < 0 ? -1 : pritems[abs].index;
+ *focusitem = m.sel < 0 ? -1 : m.pritems[m.sel].index;
- delwin(menupad);
- delwin(menuwin);
- end_dialog(conf, shadow, widget, textpad);
- free(pritems);
+ if (m.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ }
+ delwin(m.pad);
+ delwin(m.box);
+ end_dialog(&d);
+ free(m.pritems);
return (retval);
}
@@ -783,8 +707,9 @@ bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
{
int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
retval = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
1, &group, &focuslist, focusitem);
@@ -798,8 +723,9 @@ bsddialog_menu(struct bsddialog_conf *conf, const char *text, int rows,
{
int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
retval = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
&group, &focuslist, focusitem);
@@ -813,8 +739,9 @@ bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
{
int retval, focuslist = 0;
struct bsddialog_menugroup group = {
- BSDDIALOG_RADIOLIST /* unused */, nitems, items};
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items, 0};
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
retval = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
1, &group, &focuslist, focusitem);
diff --git a/lib/messagebox.c b/lib/messagebox.c
index 7063ea9d273e..fc18ff8a61d2 100644
--- a/lib/messagebox.c
+++ b/lib/messagebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,209 +25,165 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-static int
-message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text, bool *hastext, struct buttons bs)
-{
- int htext, wtext;
+struct scroll {
+ int ypad; /* y scrollable pad */
+ int htext; /* real h text to draw, to use with htextpad */
+ int htextpad; /* h textpad, draw_dialog() set at least 1 */
+ int printrows; /* h - BORDER - HBUTTONS - BORDER */
+};
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE ||
- hastext != NULL) {
- if (text_size(conf, rows, cols, text, &bs, 0, 1, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
- if (hastext != NULL)
- *hastext = htext > 0 ? true : false;
+static void textupdate(struct dialog *d, struct scroll *s)
+{
+ if (s->htext > 0 && s->htextpad > s->printrows) {
+ wattron(d->widget, t.dialog.arrowcolor);
+ mvwprintw(d->widget, d->h - HBUTTONS - BORDER,
+ d->w - 4 - TEXTHMARGIN - BORDER,
+ "%3d%%", 100 * (s->ypad + s->printrows) / s->htextpad);
+ wattroff(d->widget, t.dialog.arrowcolor);
+ wnoutrefresh(d->widget);
}
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, true);
-
- return (0);
+ rtextpad(d, s->ypad, 0, 0, HBUTTONS);
}
-static int
-message_checksize(int rows, int cols, bool hastext, struct buttons bs)
+static int message_size_position(struct dialog *d, int *htext)
{
- int mincols;
-
- mincols = VBORDERS;
- mincols += buttons_min_width(bs);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "
- "for borders, buttons and spaces between buttons");
+ int minw;
- if (rows < HBORDERS + 2 /* buttons */)
- RETURN_ERROR("Msgbox and Yesno need at least 4 rows");
- if (hastext && rows < HBORDERS + 2 /*buttons*/ + 1 /* text row */)
- RETURN_ERROR("Msgbox and Yesno with text need at least 5 rows");
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, (*htext < 0) ? htext : NULL, &d->bs, 0, 0) != 0)
+ return (BSDDIALOG_ERROR);
+ minw = (*htext > 0) ? 1 + TEXTHMARGINS : 0 ;
+ if (widget_checksize(d->h, d->w, &d->bs, MIN(*htext, 1), minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
return (0);
}
-static void
-textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad,
- bool hastext)
+static int message_draw(struct dialog *d, struct scroll *s)
{
- int y, x, h, w;
-
- getbegyx(widget, y, x);
- getmaxyx(widget, h, w);
+ int unused;
- if (hastext && htextpad > h - 4) {
- wattron(widget, t.dialog.arrowcolor);
- mvwprintw(widget, h-3, w-6, "%3d%%",
- 100 * (ytextpad+h-4)/ htextpad);
- wattroff(widget, t.dialog.arrowcolor);
- wnoutrefresh(widget);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
+ 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 */
- pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2);
+ 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_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
- struct buttons bs)
+ const char *oklabel, const char *cancellabel)
{
- bool hastext, loop;
- int y, x, h, w, retval, ytextpad, htextpad, printrows, unused;
- WINDOW *widget, *textpad, *shadow;
+ bool loop;
+ int retval;
wint_t input;
+ struct scroll s;
+ struct dialog d;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text, &hastext, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, hastext, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, oklabel, cancellabel);
+ s.htext = -1;
+ if(message_draw(&d, &s) != 0)
return (BSDDIALOG_ERROR);
- printrows = h - 4;
- ytextpad = 0;
- getmaxyx(textpad, htextpad, unused);
- unused++; /* fix unused error */
loop = true;
while (loop) {
- textupdate(widget, textpad, htextpad, ytextpad, hastext);
+ textupdate(&d, &s);
doupdate();
if (get_wch(&input) == ERR)
continue;
switch (input) {
case KEY_ENTER:
case 10: /* Enter */
- retval = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
- if (conf->key.enable_esc) {
+ if (d.conf->key.enable_esc) {
retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int)bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_UP:
- if (ytextpad > 0)
- ytextpad--;
+ if (s.ypad > 0)
+ s.ypad--;
break;
case KEY_DOWN:
- if (ytextpad + printrows < htextpad)
- ytextpad++;
+ if (s.ypad + s.printrows < s.htextpad)
+ s.ypad++;
break;
case KEY_HOME:
- ytextpad = 0;
+ s.ypad = 0;
break;
case KEY_END:
- ytextpad = htextpad - printrows;
- ytextpad = ytextpad < 0 ? 0 : ytextpad;
+ s.ypad = MAX(s.htextpad - s.printrows, 0);
break;
case KEY_PPAGE:
- ytextpad -= printrows;
- ytextpad = ytextpad < 0 ? 0 : ytextpad;
+ s.ypad = MAX(s.ypad - s.printrows, 0);
break;
case KEY_NPAGE:
- ytextpad += printrows;
- if (ytextpad + printrows > htextpad)
- ytextpad = htextpad - printrows;
+ s.ypad += s.printrows;
+ if (s.ypad + s.printrows > s.htextpad)
+ s.ypad = s.htextpad - s.printrows;
break;
case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
+ if (d.conf->key.f1_file == NULL &&
+ d.conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (f1help_dialog(d.conf) != 0)
return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text,
- NULL, bs) != 0)
+ if(message_draw(&d, &s) != 0)
return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, hastext, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_RESIZE:
+ if(message_draw(&d, &s) != 0)
return (BSDDIALOG_ERROR);
-
- printrows = h - 4;
- getmaxyx(textpad, htextpad, unused);
- ytextpad = 0;
- textupdate(widget, textpad, htextpad, ytextpad, hastext);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
return (retval);
}
@@ -237,20 +193,34 @@ int
bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL);
-
- return (do_message(conf, text, rows, cols, bs));
+ return (do_message(conf, text, rows, cols, OK_LABEL, NULL));
}
int
bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
+ return (do_message(conf, text, rows, cols, "Yes", "No"));
+}
- get_buttons(conf, &bs, "Yes", "No");
+int
+bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
+{
+ int htext;
+ struct dialog d;
- return (do_message(conf, text, rows, cols, bs));
-} \ No newline at end of file
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ htext = -1;
+ if (message_size_position(&d, &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
+ return (BSDDIALOG_ERROR);
+ TEXTPAD(&d, 0);
+ doupdate();
+
+ end_dialog(&d);
+
+ return (BSDDIALOG_OK);
+}
diff --git a/lib/textbox.c b/lib/textbox.c
index 0c6d53a8cad0..edd58d0a820e 100644
--- a/lib/textbox.c
+++ b/lib/textbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,166 +25,177 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-static void
-updateborders(struct bsddialog_conf *conf, WINDOW *widget, int padmargin,
- int hpad, int wpad, int ypad, int xpad)
+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)
{
- int h, w;
chtype arrowch, borderch;
- getmaxyx(widget, h, w);
-
- if (conf->no_lines)
+ if (d->conf->no_lines)
borderch = ' ';
- else if (conf->ascii_lines)
+ else if (d->conf->ascii_lines)
borderch = '|';
else
borderch = ACS_VLINE;
- if (xpad > 0) {
- arrowch = conf->ascii_lines ? '<' : ACS_LARROW;
- arrowch |= A_ATTRIBUTES & t.dialog.arrowcolor;
+ if (st->xpad > 0) {
+ arrowch = d->conf->ascii_lines ? '<' : ACS_LARROW;
+ arrowch |= t.dialog.arrowcolor;
} else {
arrowch = borderch;
- arrowch |= A_ATTRIBUTES & t.dialog.lineraisecolor;
+ arrowch |= t.dialog.lineraisecolor;
}
- mvwvline(widget, (h / 2) - 2, 0, arrowch, 4);
+ mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4);
- if (xpad + w-2-padmargin < wpad) {
- arrowch = conf->ascii_lines ? '>' : ACS_RARROW;
- arrowch |= A_ATTRIBUTES & t.dialog.arrowcolor;
+ 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 |= A_ATTRIBUTES & t.dialog.linelowercolor;
+ arrowch |= t.dialog.linelowercolor;
}
- mvwvline(widget, (h / 2) - 2, w - 1, arrowch, 4);
+ mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4);
- if (hpad > h - 4) {
- wattron(widget, t.dialog.arrowcolor);
- mvwprintw(widget, h-3, w-6, "%3d%%", 100 * (ypad+h-4)/ hpad);
- wattroff(widget, t.dialog.arrowcolor);
+ 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 void
-textbox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int hpad, int wpad, int padmargin, struct buttons bs)
+static int textbox_size_position(struct dialog *d, struct scrolltext *st)
{
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, 0, wpad + padmargin, &bs);
+ int minw;
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, 0, hpad, true);
+ 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);
}
-static int
-textbox_checksize(int rows, int cols, int hpad, struct buttons bs)
+static int textbox_draw(struct dialog *d, struct scrolltext *st)
{
- int mincols;
-
- mincols = VBORDERS;
- mincols += buttons_min_width(bs);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols for the textbox");
+ 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 */
- if (rows < 4 /* HBORDERS + button*/ + (hpad > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for the textbox");
+ st->ys = d->y + 1;
+ st->xs = (st->margin == 0) ? d->x + 1 : d->x + 2;
+ st->ye = st->ys + d->h - 5;
+ st->xe = st->xs + d->w - 3 - st->margin;
+ st->ypad = st->xpad = 0;
+ st->printrows = d->h-4;
return (0);
}
/* API */
int
-bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
+bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
int cols)
{
- bool loop, has_multi_col;
- int i, retval, y, x, h, w;
- int hpad, wpad, ypad, xpad, ys, ye, xs, xe, padmargin, printrows;
+ bool loop, has_multicol_ch;
+ int i, retval;
unsigned int defaulttablen, linecols;
wint_t input;
char buf[BUFSIZ];
FILE *fp;
- struct buttons bs;
- WINDOW *shadow, *widget, *pad;
+ struct scrolltext st;
+ struct dialog d;
+ if (file == NULL)
+ RETURN_ERROR("*file is NULL");
if ((fp = fopen(file, "r")) == NULL)
- RETURN_ERROR("Cannot open file");
+ RETURN_FMTERROR("Cannot open file \"%s\"", file);
+
+ if (prepare_dialog(conf, "" /* fake */, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, "EXIT", NULL);
defaulttablen = TABSIZE;
- set_tabsize((conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen);
- hpad = 1;
- wpad = 1;
- pad = newpad(hpad, wpad);
- wbkgd(pad, t.dialog.color);
- padmargin = 0;
+ 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 (str_props(buf, &linecols, &has_multi_col) != 0)
+ if (str_props(buf, &linecols, &has_multicol_ch) != 0)
continue;
- if ((int)linecols > wpad) {
- wpad = linecols;
- wresize(pad, hpad, wpad);
+ 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_multi_col)
- padmargin = 2;
+ if (has_multicol_ch)
+ st.margin = 2;
}
fclose(fp);
- set_tabsize(defaulttablen);
+ set_tabsize(defaulttablen); /* reset because it is curses global */
- get_buttons(conf, &bs, "EXIT", NULL);
- bs.curr = 0;
- bs.nbuttons = 1;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad, padmargin, bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, NULL, NULL, &bs,
- true) != 0)
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
- ys = y + 1;
- xs = (padmargin == 0) ? x + 1 : x + 2;
- ye = ys + h - 5;
- xe = xs + w - 3 - padmargin;
- ypad = xpad = 0;
- printrows = h-4;
loop = true;
while (loop) {
- updateborders(conf, widget, padmargin, hpad, wpad, ypad, xpad);
+ updateborders(&d, &st);
/*
* Overflow multicolumn charchter right border:
* wnoutrefresh(widget);
* pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
* doupdate();
*/
- wrefresh(widget);
- prefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ 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 */
@@ -197,84 +208,63 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
loop = false;
}
break;
+ case '\t': /* TAB */
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
+ break;
case KEY_HOME:
- ypad = 0;
+ st.ypad = 0;
break;
case KEY_END:
- ypad = hpad - printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.hpad - st.printrows, 0);
break;
case KEY_PPAGE:
- ypad -= printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.ypad - st.printrows, 0);
break;
case KEY_NPAGE:
- ypad += printrows;
- if (ypad + printrows > hpad)
- ypad = hpad - printrows;
+ st.ypad += st.printrows;
+ if (st.ypad + st.printrows > st.hpad)
+ st.ypad = st.hpad - st.printrows;
break;
case '0':
- xpad = 0;
+ st.xpad = 0;
+ break;
case KEY_LEFT:
case 'h':
- xpad = xpad > 0 ? xpad - 1 : 0;
+ st.xpad = MAX(st.xpad - 1, 0);
break;
case KEY_RIGHT:
case 'l':
- xpad = (xpad + w-2-padmargin) < wpad ? xpad + 1 : xpad;
+ if (st.xpad + d.w - 2 - st.margin < st.wpad)
+ st.xpad++;
break;
case KEY_UP:
case 'k':
- ypad = ypad > 0 ? ypad - 1 : 0;
+ st.ypad = MAX(st.ypad - 1, 0);
break;
case KEY_DOWN:
case'j':
- ypad = ypad + printrows <= hpad -1 ? ypad + 1 : ypad;
+ if (st.ypad + st.printrows <= st.hpad -1)
+ st.ypad++;
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad,
- padmargin, bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- ys = y + 1;
- xs = (padmargin == 0) ? x + 1 : x + 2;
- ye = ys + h - 5;
- xe = xs + w - 3 - padmargin;
- ypad = xpad = 0;
- printrows = h - 4;
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- NULL, NULL, &bs, true) != 0)
+ break;
+ case KEY_RESIZE:
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
- default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
- loop = false;
- }
}
}
- end_dialog(conf, shadow, widget, pad);
+ delwin(st.pad);
+ end_dialog(&d);
return (retval);
}
diff --git a/lib/theme.c b/lib/theme.c
index 6e53eb356825..04f85b2455fa 100644
--- a/lib/theme.c
+++ b/lib/theme.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,132 +32,104 @@
#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 = {
- .screen.color = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
-
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.y = 1,
- .shadow.x = 2,
-
- .dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
- .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),
- .dialog.arrowcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
-
- .menu.f_selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_YELLOW),
- .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .menu.f_namecolor = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
- .menu.namecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .menu.namesepcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
- .menu.descsepcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
- .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_YELLOW),
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
-
- .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),
- .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
-
- .bar.f_color = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
- .bar.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+struct flag_converter {
+ unsigned int public;
+ unsigned int private;
+};
- .button.minmargin = 1,
- .button.maxmargin = 5,
- .button.leftdelim = '[',
- .button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .button.delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .button.f_color = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
- .button.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .button.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_YELLOW),
- .button.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE)
+static struct flag_converter flagconv[NFLAGS] = {
+ {BSDDIALOG_BLINK, A_BLINK},
+ {BSDDIALOG_BOLD, A_BOLD},
+ {BSDDIALOG_HALFBRIGHT, A_DIM},
+ {BSDDIALOG_HIGHLIGHT, A_STANDOUT},
+ {BSDDIALOG_REVERSE, A_REVERSE},
+ {BSDDIALOG_UNDERLINE, A_UNDERLINE}
};
static struct bsddialog_theme blackwhite = {
-#define fg COLOR_WHITE
-#define bk COLOR_BLACK
- .screen.color = GET_COLOR(fg, bk),
+ .screen.color = WHITE,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.y = 1,
- .shadow.x = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(fg, bk),
- .dialog.lineraisecolor = GET_COLOR(fg, bk),
- .dialog.linelowercolor = GET_COLOR(fg, bk),
- .dialog.color = GET_COLOR(fg, bk),
- .dialog.bottomtitlecolor = GET_COLOR(fg, bk),
- .dialog.arrowcolor = GET_COLOR(fg, bk),
-
- .menu.f_selectorcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.selectorcolor = GET_COLOR(fg, bk),
- .menu.f_desccolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.desccolor = GET_COLOR(fg, bk),
- .menu.f_namecolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.namecolor = GET_COLOR(fg, bk),
- .menu.namesepcolor = GET_COLOR(fg, bk),
- .menu.descsepcolor = GET_COLOR(fg, bk),
- .menu.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .menu.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE,
- .menu.bottomdesccolor = GET_COLOR(fg, bk),
-
- .form.f_fieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .form.fieldcolor = GET_COLOR(fg, bk),
- .form.readonlycolor = GET_COLOR(fg, bk),
- .form.bottomdesccolor = GET_COLOR(fg, bk),
-
- .bar.f_color = GET_COLOR(fg, bk) | A_REVERSE,
- .bar.color = GET_COLOR(fg, bk),
+ .dialog.titlecolor = WHITE,
+ .dialog.lineraisecolor = WHITE,
+ .dialog.linelowercolor = WHITE,
+ .dialog.color = WHITE,
+ .dialog.bottomtitlecolor = WHITE,
+ .dialog.arrowcolor = WHITE,
+
+ .menu.f_prefixcolor = WHITE,
+ .menu.prefixcolor = WHITE,
+ .menu.f_selectorcolor = BLACK,
+ .menu.selectorcolor = WHITE,
+ .menu.f_desccolor = BLACK,
+ .menu.desccolor = WHITE,
+ .menu.f_namecolor = BLACK,
+ .menu.namecolor = WHITE,
+ .menu.f_shortcutcolor = BLACK | A_UNDERLINE,
+ .menu.shortcutcolor = WHITE | A_UNDERLINE,
+ .menu.bottomdesccolor = WHITE,
+ .menu.sepnamecolor = WHITE,
+ .menu.sepdesccolor = WHITE,
+
+ .form.f_fieldcolor = BLACK,
+ .form.fieldcolor = WHITE,
+ .form.readonlycolor = WHITE,
+ .form.bottomdesccolor = WHITE,
+
+ .bar.f_color = BLACK,
+ .bar.color = WHITE,
.button.minmargin = 1,
.button.maxmargin = 5,
.button.leftdelim = '[',
.button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(fg, bk),
- .button.delimcolor = GET_COLOR(fg, bk),
- .button.f_color = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.color = GET_COLOR(fg, bk) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE
+ .button.f_delimcolor = WHITE,
+ .button.delimcolor = WHITE,
+ .button.f_color = BLACK,
+ .button.color = WHITE,
+ .button.f_shortcutcolor = BLACK | A_UNDERLINE | A_BOLD,
+ .button.shortcutcolor = WHITE | A_UNDERLINE | A_BOLD
};
-static struct bsddialog_theme dialogtheme = {
+static struct bsddialog_theme flat = {
.screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.y = 1,
- .shadow.x = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
- .dialog.delimtitle = false,
+ .dialog.delimtitle = true,
.dialog.titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .dialog.lineraisecolor = GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD,
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
+ .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
.dialog.arrowcolor = GET_COLOR(COLOR_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.namesepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.descsepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
.menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
.menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
.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,
@@ -169,8 +141,8 @@ static struct bsddialog_theme dialogtheme = {
.button.minmargin = 1,
.button.maxmargin = 5,
- .button.leftdelim = '<',
- .button.rightdelim = '>',
+ .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,
@@ -196,17 +168,19 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->dialog.bottomtitlecolor = src->dialog.bottomtitlecolor;
dst->dialog.arrowcolor = src->dialog.arrowcolor;
+ dst->menu.f_prefixcolor = src->menu.f_prefixcolor;
+ dst->menu.prefixcolor = src->menu.prefixcolor;
dst->menu.f_selectorcolor = src->menu.f_selectorcolor;
dst->menu.selectorcolor = src->menu.selectorcolor;
dst->menu.f_desccolor = src->menu.f_desccolor;
dst->menu.desccolor = src->menu.desccolor;
dst->menu.f_namecolor = src->menu.f_namecolor;
dst->menu.namecolor = src->menu.namecolor;
- dst->menu.namesepcolor = src->menu.namesepcolor;
- dst->menu.descsepcolor = src->menu.descsepcolor;
dst->menu.f_shortcutcolor = src->menu.f_shortcutcolor;
dst->menu.shortcutcolor = src->menu.shortcutcolor;
dst->menu.bottomdesccolor = src->menu.bottomdesccolor;
+ dst->menu.sepnamecolor = src->menu.sepnamecolor;
+ dst->menu.sepdesccolor = src->menu.sepdesccolor;
dst->form.f_fieldcolor = src->form.f_fieldcolor;
dst->form.fieldcolor = src->form.fieldcolor;
@@ -228,17 +202,12 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->button.shortcutcolor = src->button.shortcutcolor;
bkgd(dst->screen.color);
- refresh();
}
/* API */
int bsddialog_get_theme(struct bsddialog_theme *theme)
{
- if (theme == NULL)
- RETURN_ERROR("theme is NULL");
- if (sizeof(*theme) != sizeof(struct bsddialog_theme))
- RETURN_ERROR("Bad suze struct bsddialog_theme");
-
+ CHECK_PTR(theme);
set_theme(theme, &t);
return (BSDDIALOG_OK);
@@ -246,34 +215,31 @@ int bsddialog_get_theme(struct bsddialog_theme *theme)
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 (BSDDIALOG_OK);
}
int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
{
- if (newtheme == BSDDIALOG_THEME_FLAT) {
- bsddialog_set_theme(&dialogtheme);
- t.dialog.lineraisecolor = t.dialog.linelowercolor;
- t.dialog.delimtitle = true;
- t.button.leftdelim = '[';
- t.button.rightdelim = ']';
- t.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE);
+ 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");
+ refresh();
return (BSDDIALOG_OK);
}
@@ -282,43 +248,41 @@ int
bsddialog_color(enum bsddialog_color foreground,
enum bsddialog_color background, unsigned int flags)
{
- unsigned int cursesflags = 0;
+ unsigned int i, f;
- if (flags & BSDDIALOG_BOLD)
- cursesflags |= A_BOLD;
- if (flags & BSDDIALOG_REVERSE)
- cursesflags |= A_REVERSE;
- if (flags & BSDDIALOG_UNDERLINE)
- cursesflags |= A_UNDERLINE;
+ f = 0;
+ for (i=0; i < NFLAGS; i++)
+ if (flags & flagconv[i].public)
+ f |= flagconv[i].private;
- return (GET_COLOR(foreground, background) | cursesflags);
+ return (GET_COLOR(foreground, background) | f);
}
int
bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
enum bsddialog_color *background, unsigned int *flags)
{
- unsigned int flag;
- short f, b;
-
- flag = 0U;
- flag |= (color & A_BOLD) ? BSDDIALOG_BOLD : 0U;
- flag |= (color & A_REVERSE) ? BSDDIALOG_REVERSE : 0U;
- flag |= (color & A_UNDERLINE) ? BSDDIALOG_UNDERLINE : 0U;
- if (flags != NULL)
- *flags = flag;
-
- if (pair_content(PAIR_NUMBER(color), &f, &b) != OK)
+ 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 = f;
+ *foreground = fg;
if (background != NULL)
- *background = b;
+ *background = bg;
return (BSDDIALOG_OK);
}
bool bsddialog_hascolors(void)
{
- return hastermcolors;
-} \ No newline at end of file
+ return (hastermcolors);
+}
diff --git a/lib/timebox.c b/lib/timebox.c
index 53989bb97157..d683f9552b50 100644
--- a/lib/timebox.c
+++ b/lib/timebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,158 +25,114 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define MINWDATE 23 /* 3 windows and their borders */
#define MINWTIME 14 /* 3 windows and their borders */
+#define HBOX 3
+#define WBOX 4
+
+struct clock {
+ unsigned int max;
+ unsigned int value;
+ WINDOW *win;
+};
static void
-drawsquare(struct bsddialog_conf *conf, WINDOW *win, const char *fmt,
- const void *value, bool focus)
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value,
+ bool focus)
{
- int h, l, w;
-
- getmaxyx(win, h, w);
- draw_borders(conf, win, h, w, LOWERED);
+ draw_borders(conf, win, LOWERED);
if (focus) {
- l = 2 + w%2;
wattron(win, t.dialog.arrowcolor);
- mvwhline(win, 0, w/2 - l/2,
- conf->ascii_lines ? '^' : ACS_UARROW, l);
- mvwhline(win, h-1, w/2 - l/2,
- conf->ascii_lines ? 'v' : ACS_DARROW, l);
+ mvwhline(win, 0, 1, conf->ascii_lines ? '^' : ACS_UARROW, 2);
+ mvwhline(win, 2, 1, conf->ascii_lines ? 'v' : ACS_DARROW, 2);
wattroff(win, t.dialog.arrowcolor);
}
if (focus)
wattron(win, t.menu.f_namecolor);
- if (strchr(fmt, 's') != NULL)
- mvwprintw(win, 1, 1, fmt, (const char*)value);
- else
- mvwprintw(win, 1, 1, fmt, *((const int*)value));
+ mvwprintw(win, 1, 1, "%02u", value);
if (focus)
wattroff(win, t.menu.f_namecolor);
- wrefresh(win);
+ wnoutrefresh(win);
}
-static int
-datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int minw, const char *text, struct buttons bs)
+static int timebox_redraw(struct dialog *d, struct clock *c)
{
- int htext, wtext;
+ int y, x;
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 3, minw, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, minw, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* windows */, true);
-
- return (0);
-}
-
-static int
-datetime_checksize(int rows, int cols, int minw, struct buttons bs)
-{
- int mincols;
-
- mincols = VBORDERS;
- mincols += buttons_min_width(bs);
- mincols = MAX(minw, mincols);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols for this timebox/datebox");
-
- if (rows < 7) /* 2 button + 2 borders + 3 windows */
- RETURN_ERROR("Few rows for this timebox/datebox, at least 7");
+ if (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);
}
+/* API */
int
bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
{
bool loop, focusbuttons;
- int i, retval, y, x, h, w, sel;
+ int i, retval, sel;
wint_t input;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct myclockstruct {
- unsigned int max;
- unsigned int value;
- WINDOW *win;
- };
-
- if (hh == NULL || mm == NULL || ss == NULL)
- RETURN_ERROR("hh / mm / ss cannot be NULL");
-
- struct myclockstruct c[3] = {
+ struct dialog d;
+ struct clock c[3] = {
{23, *hh, NULL},
{59, *mm, NULL},
{59, *ss, NULL}
};
- for (i = 0 ; i < 3; i++) {
- if (c[i].value > c[i].max)
- c[i].value = c[i].max;
- }
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, bs) != 0)
+ CHECK_PTR(hh);
+ CHECK_PTR(mm);
+ CHECK_PTR(ss);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ for (i=0; i<3; i++) {
+ if ((c[i].win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_FMTERROR("Cannot build WINDOW for time[%d]", i);
+ wbkgd(c[i].win, t.dialog.color);
+ c[i].value = MIN(c[i].value, c[i].max);
+ }
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 7, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 2, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 3, 3, 4, LOWERED);
-
- wrefresh(widget);
-
sel = -1;
loop = focusbuttons = true;
while (loop) {
for (i = 0; i < 3; i++)
- drawsquare(conf, c[i].win, "%02d", &c[i].value,
- sel == i);
-
+ drawsquare(conf, c[i].win, c[i].value, sel == i);
+ doupdate();
if (get_wch(&input) == ERR)
continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
if (focusbuttons || conf->button.always_active) {
- retval = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
break;
@@ -189,49 +145,49 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
case KEY_RIGHT:
case '\t': /* TAB */
if (focusbuttons) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
+ d.bs.curr++;
+ focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
true : false;
if (focusbuttons == false) {
sel = 0;
- bs.curr = conf->button.always_active ? 0 : -1;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel++;
focusbuttons = sel > 2 ? true : false;
if (focusbuttons) {
- bs.curr = 0;
+ d.bs.curr = 0;
}
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
+ d.bs.curr--;
+ focusbuttons = d.bs.curr < 0 ? false : true;
if (focusbuttons == false) {
sel = 2;
- bs.curr = conf->button.always_active ? 0 : -1;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel--;
focusbuttons = sel < 0 ? true : false;
if (focusbuttons)
- bs.curr = (int)bs.nbuttons - 1;
+ d.bs.curr = (int)d.bs.nbuttons - 1;
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ DRAW_BUTTONS(d);
break;
case KEY_UP:
if (focusbuttons) {
sel = 0;
focusbuttons = false;
- bs.curr = conf->button.always_active ? 0 : -1;
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- } else { c[sel].value = c[sel].value > 0 ?
- c[sel].value - 1 : c[sel].max;
+ 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:
@@ -244,297 +200,32 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWTIME, text, bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, bs) != 0)
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 7);
- wclear(c[1].win);
- mvwin(c[1].win, y + h - 6, x + w/2 - 2);
- wclear(c[2].win);
- mvwin(c[2].win, y + h - 6, x + w/2 + 3);
-
- /* Important to avoid grey lines expanding screen */
- refresh();
break;
- default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
- loop = false;
- }
- }
- }
-
- if (retval == BSDDIALOG_OK) {
- *hh = c[0].value;
- *mm = c[1].value;
- *ss = c[2].value;
- }
-
- for (i = 0; i < 3; i++)
- delwin(c[i].win);
- end_dialog(conf, shadow, widget, textpad);
-
- return (retval);
-}
-
-int
-bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
-{
- bool loop, focusbuttons;
- int i, retval, y, x, h, w, sel;
- wint_t input;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct calendar {
- int max;
- int value;
- WINDOW *win;
- unsigned int x;
- };
- struct month {
- const char *name;
- unsigned int days;
- };
-
- if (yy == NULL || mm == NULL || dd == NULL)
- RETURN_ERROR("yy / mm / dd cannot be NULL");
-
- struct calendar c[3] = {
- {9999, *yy, NULL, 4 },
- {12, *mm, NULL, 9 },
- {31, *dd, NULL, 2 }
- };
-
- struct month m[12] = {
- { "January", 31 }, { "February", 28 }, { "March", 31 },
- { "April", 30 }, { "May", 31 }, { "June", 30 },
- { "July", 31 }, { "August", 31 }, { "September", 30 },
- { "October", 31 }, { "November", 30 }, { "December", 31 }
- };
-
- 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 && ISLEAP(c[0].value))
- c[2].max = 29;
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 11, 3, 6, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 4, 3, 11, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 8, 3, 4, LOWERED);
-
- wrefresh(widget);
-
- sel = -1;
- loop = focusbuttons = true;
- while (loop) {
- drawsquare(conf, c[0].win, "%4d", &c[0].value, sel == 0);
- drawsquare(conf, c[1].win, "%9s", m[c[1].value-1].name,
- sel == 1);
- drawsquare(conf, c[2].win, "%02d", &c[2].value, sel == 2);
-
- if (get_wch(&input) == ERR)
- continue;
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
- if (focusbuttons || conf->button.always_active) {
- retval = bs.value[bs.curr];
- 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) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
- true : false;
- if (focusbuttons == false) {
- sel = 0;
- bs.curr = conf->button.always_active ? 0 : -1;
- }
- } else {
- sel++;
- focusbuttons = sel > 2 ? true : false;
- if (focusbuttons) {
- bs.curr = 0;
- }
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_LEFT:
- if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
- if (focusbuttons == false) {
- sel = 2;
- bs.curr = conf->button.always_active ? 0 : -1;
- }
- } else {
- sel--;
- focusbuttons = sel < 0 ? true : false;
- if (focusbuttons)
- bs.curr = (int)bs.nbuttons - 1;
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_UP:
- if (focusbuttons) {
- sel = 0;
- focusbuttons = false;
- bs.curr = conf->button.always_active ? 0 : -1;
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- } else {
- 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 && ISLEAP(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
- }
- break;
- case KEY_DOWN:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value < c[sel].max ?
- c[sel].value + 1 : 1;
- /* if mount change */
- c[2].max = m[c[1].value -1].days;
- /* if year change */
- if (c[1].value == 2 && ISLEAP(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
- break;
- case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
- break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWDATE, text, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 11);
- wclear(c[1].win);
- mvwin(c[1].win, y + h - 6, x + w/2 - 4);
- wclear(c[2].win);
- mvwin(c[2].win, y + h - 6, x + w/2 + 8);
-
- /* Important to avoid grey lines expanding screen */
- refresh();
break;
default:
- if (shortcut_buttons(input, &bs)) {
- retval = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- if (retval == BSDDIALOG_OK) {
- *yy = c[0].value;
- *mm = c[1].value;
- *dd = c[2].value;
- }
+ *hh = c[0].value;
+ *mm = c[1].value;
+ *ss = c[2].value;
for (i = 0; i < 3; i++)
delwin(c[i].win);
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
return (retval);
-} \ No newline at end of file
+}
diff --git a/util_theme.c b/util_theme.c
deleted file mode 100644
index caf62852e9f3..000000000000
--- a/util_theme.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <bsddialog.h>
-#include <bsddialog_theme.h>
-
-#include "util_theme.h"
-
-static struct bsddialog_theme t;
-static char title[1024];
-
-enum typeprop {
- BOOL,
- CHAR,
- INT,
- UINT,
- COLOR
-};
-
-struct property {
- const char* name;
- enum typeprop type;
- void *value;
-};
-
-#define NPROPERTY 38
-static struct property p[NPROPERTY] = {
- { "theme.screen.color", COLOR, &t.screen.color },
-
- { "theme.shadow.color", COLOR, &t.shadow.color },
- { "theme.shadow.y", UINT, &t.shadow.y },
- { "theme.shadow.x", UINT, &t.shadow.x },
-
- { "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 },
-
- { "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.namesepcolor", COLOR, &t.menu.namesepcolor},
- { "theme.menu.descsepcolor", COLOR, &t.menu.descsepcolor},
- { "theme.menu.f_shortcutcolor", COLOR, &t.menu.f_shortcutcolor},
- { "theme.menu.shortcutcolor", COLOR, &t.menu.shortcutcolor},
- { "theme.menu.bottomdesccolor", COLOR, &t.menu.bottomdesccolor},
-
- { "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},
-
- { "theme.bar.f_color", COLOR, &t.bar.f_color},
- { "theme.bar.color", COLOR, &t.bar.color},
-
- { "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.delimcolor", COLOR, &t.button.delimcolor},
- { "theme.button.f_delimcolor", COLOR, &t.button.f_delimcolor},
- { "theme.button.color", COLOR, &t.button.color},
- { "theme.button.f_color", COLOR, &t.button.f_color},
- { "theme.button.shortcutcolor", COLOR, &t.button.shortcutcolor},
- { "theme.button.f_shortcutcolor", COLOR, &t.button.f_shortcutcolor}
-};
-
-static const char *color[8] = {
- "black",
- "red",
- "green",
- "yellow",
- "blue",
- "magenta",
- "cyan",
- "white"
-};
-
-#define EXIT_FMTERROR(fmt, ...) do { \
- bsddialog_end(); \
- printf("Error: "); \
- printf(fmt, __VA_ARGS__); \
- printf(".\n"); \
- exit (255); \
-} while (0)
-
-void savetheme(const char *file, const char *version)
-{
- int i;
- unsigned int flags;
- enum bsddialog_color bg, fg;
- time_t clock;
- FILE *fp;
-
- if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
- EXIT_FMTERROR("cannot save theme: %s", bsddialog_geterror());
-
- if(time(&clock) < 0)
- EXIT_FMTERROR("%s", "cannot save profile getting current time");
-
- if ((fp = fopen(file, "w")) == NULL)
- EXIT_FMTERROR("cannot open %s to save profile", file);
-
- fprintf(fp, "### bsddialog theme - %s", ctime(&clock));
- fputs("# Refer to bsddialog(3) manual for theme.* properties\n", fp);
- fprintf(fp, "version %s\n", version);
-
- for (i = 0; i < NPROPERTY; i++) {
- switch (p[i].type) {
- case CHAR:
- fprintf(fp, "%s %c\n", p[i].name, *((char*)p[i].value));
- break;
- case INT:
- fprintf(fp, "%s %d\n", p[i].name, *((int*)p[i].value));
- break;
- case UINT:
- fprintf(fp, "%s %u\n", p[i].name,
- *((unsigned int*)p[i].value));
- break;
- case BOOL:
- fprintf(fp, "%s %s\n", p[i].name,
- *((bool*)p[i].value) ? "true" : "false");
- break;
- case COLOR:
- bsddialog_color_attrs(*(int*)p[i].value, &fg, &bg,
- &flags);
- fprintf(fp, "%s %s %s%s%s%s\n",
- p[i].name, color[fg], color[bg],
- flags & BSDDIALOG_BOLD ? " bold" : "",
- flags & BSDDIALOG_REVERSE ? " reverse" : "",
- flags & BSDDIALOG_UNDERLINE ? " underline" : "");
- break;
- }
- }
-
- fclose(fp);
-}
-
-void setdeftheme(enum bsddialog_default_theme theme)
-{
- if (bsddialog_set_default_theme(theme) != BSDDIALOG_OK)
- EXIT_FMTERROR("%s", bsddialog_geterror());
-}
-
-void loadtheme(const char *file)
-{
- bool boolvalue;
- char charvalue, *value;
- char line[BUFSIZ], name[BUFSIZ], c1[BUFSIZ], c2[BUFSIZ];
- int i, j, intvalue, flags;
- unsigned int uintvalue;
- enum bsddialog_color bg, fg;
- FILE *fp;
-
- if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
- EXIT_FMTERROR("Cannot get current theme: %s",
- bsddialog_geterror());
-
- if((fp = fopen(file, "r")) == NULL)
- EXIT_FMTERROR("Cannot open theme \"%s\"", file);
-
-#define EXIT_ERROR(name, error) do { \
- fclose(fp); \
- EXIT_FMTERROR("%s for \"%s\"", error, name); \
-} while (0)
-
- while(fgets(line, BUFSIZ, fp) != NULL) {
- if(line[0] == '#' || line[0] == '\n')
- continue; /* superfluous, only for efficiency */
- sscanf(line, "%s", name);
- for (i = 0; i < NPROPERTY; i++) {
- if (strcmp(name, p[i].name) == 0) {
- value = &line[strlen(name)];
- break;
- }
- }
- if (i >= NPROPERTY) {
- if (strcmp(name, "version") == 0)
- continue;
- EXIT_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)
- EXIT_ERROR(p[i].name, "Cannot get a char");
- *((int*)p[i].value) = charvalue;
- break;
- case INT:
- if (sscanf(value, "%d", &intvalue) != 1)
- EXIT_ERROR(p[i].name, "Cannot get a int");
- *((int*)p[i].value) = intvalue;
- break;
- case UINT:
- if (sscanf(value, "%u", &uintvalue) != 1)
- EXIT_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)
- EXIT_ERROR(p[i].name, "Cannot get 2 colors");
- /* Foreground */
- for (j = 0; j < 8 ; j++)
- if ((strstr(c1, color[j])) != NULL)
- break;
- if ((fg = j) > 7)
- EXIT_ERROR(p[i].name, "Bad foreground");
- /* Background */
- for (j = 0; j < 8 ; j++)
- if ((value = strstr(c2, color[j])) != NULL)
- break;
- if ((bg = j) > 7)
- EXIT_ERROR(p[i].name, "Bad background");
- /* Flags */
- flags = 0;
- if (strstr(value, "bold") != NULL)
- flags |= BSDDIALOG_BOLD;
- if (strstr(value, "reverse") != NULL)
- flags |= BSDDIALOG_REVERSE;
- if (strstr(value, "underline") != NULL)
- flags |= BSDDIALOG_UNDERLINE;
- *((int*)p[i].value) = bsddialog_color(fg, bg, flags);
- break;
- }
- }
-
- fclose(fp);
-
- bsddialog_set_theme(&t);
-}
-
-void bikeshed(struct bsddialog_conf *conf)
-{
- int margin, i;
- int colors[8] = {0, 0, 0, 0 ,0 ,0 , 0, 0};
- enum bsddialog_color col[6];
- time_t clock;
-
- time(&clock);
- srand(clock);
-
- /* theme */
- if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
- EXIT_FMTERROR("%s", bsddialog_geterror());
-
- 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() % 2 == 0) ? 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_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.namesepcolor = bsddialog_color(col[1], col[5], 0);
- t.menu.descsepcolor = bsddialog_color(col[1], 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.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,
- t.button.leftdelim = '[',
- t.button.rightdelim = ']',
- 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_FMTERROR("%s", bsddialog_geterror());
-
- /* conf */
- conf->button.always_active = (rand() % 2 == 0) ? true : false;
- 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;
- }
-}
diff --git a/util_theme.h b/util_theme.h
deleted file mode 100644
index bf51447dfb2c..000000000000
--- a/util_theme.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _BSDDIALOG_UTILITY_THEME_H_
-#define _BSDDIALOG_UTILITY_THEME_H_
-
-void savetheme(const char *file, const char *version);
-void loadtheme(const char *file);
-void setdeftheme(enum bsddialog_default_theme theme);
-void bikeshed(struct bsddialog_conf *conf);
-
-#endif
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/bsddialog.1 b/utility/bsddialog.1
index 759fe6dc3fff..653f91a3f122 100644
--- a/bsddialog.1
+++ b/utility/bsddialog.1
@@ -1,6 +1,5 @@
.\"
-.\"
-.\" Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+.\" Copyright (c) 2021-2023 Alfonso Sabato Siciliano
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -23,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 23, 2022
+.Dd July 25, 2023
.Dt BSDDIALOG 1
.Os
.Sh NAME
@@ -31,9 +30,7 @@
.Nd TUI dialogs
.Sh SYNOPSIS
.Nm
-.Fl Fl help
-.Nm
-.Fl Fl version
+.Fl Fl help | Fl Fl version
.Nm
.Op Fl Fl option
.Fl Fl dialog
@@ -41,7 +38,9 @@
.Ar rows
.Ar cols
.Op Ar dialog-argument
+.Op Fl Fl option
.Nm
+\&...
.Fl Fl dialog1
.Ar ...
.Oo Fl Fl and-dialog
@@ -51,25 +50,31 @@
.Sh DESCRIPTION
The
.Nm bsddialog
-utility builds Text User Interface dialogs and widgets: to display messages,
-to get input and to inform about a computation status.
+utility builds Text User Interface dialogs and widgets.
.Pp
-The options
+The option
.Fl Fl help
-and
+prints a brief list of features and exits.
+The option
.Fl Fl version
-print the list of options and the version, respectively, then exit.
+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
-is a message printed inside the dialog.
+to print a message inside,
.Ar rows
and
.Ar cols
-are the height and width, 0 for autosize and -1 for fullscreen.
+to set height and width,
+.Dv 0
+for autosize and
+.Dv -1
+for fullscreen.
.Pp
-The possible input got from the user interface is printed to standard error.
+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.
@@ -80,18 +85,37 @@ If available set alternate screen mode, see
.It Fl Fl ascii-lines
Ascii characters to draw lines.
.It Fl Fl backtitle Ar backtitle
-Title on the top side of the screen.
+Screen title.
.It Fl Fl begin-x Ar x
-Dialog horizontal position, 0 is the left screen side, -1 center.
+Set dialog horizontal position,
+.Dv -1
+center,
+.Dv 0
+left screen.
.It Fl Fl begin-y Ar y
-Dialog vertical position, 0 is the top screen side, -1 center.
+Set dialog vertical position,
+.Dv -1
+center,
+.Dv 0
+top screen.
.It Fl Fl bikeshed
Random settings.
-Colors.
-Delimiter and margins around the title.
-Buttons always active or TAB to switch focus with input components, see
+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 or date output.
+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
@@ -99,41 +123,7 @@ button.
.It Fl Fl clear-dialog
Hide the dialog at exit.
.It Fl Fl clear-screen
-Clear the screen, after the dialog exit if a dialog is built.
-.It Fl Fl colors
-Enable highlights for text, the following sequences are considered escapes:
-.Bl -column -compact
-.It Dq \eZ0
-black.
-.It Dq \eZ1
-red.
-.It Dq \eZ2
-green.
-.It Dq \eZ3
-yellow.
-.It Dq \eZ4
-blue.
-.It Dq \eZ5
-magenta.
-.It Dq \eZ6
-cyan.
-.It Dq \eZ7
-white.
-.It Dq \eZr
-reverse foreground and background.
-.It Dq \eZR
-disable reverse.
-.It Dq \eZb
-bold.
-.It Dq \eZB
-disable bold.
-.It Dq \eZu
-underline.
-.It Dq \eZU
-disable underline.
-.It Dq \eZn
-restore normal text.
-.El
+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 .
@@ -144,13 +134,20 @@ 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
+.Fl Fl calendar .
.It Fl Fl default-button Ar label
Focus on the button with
.Ar label
@@ -167,48 +164,74 @@ or
button on startup.
.It Fl Fl disable-esc
Disable ESC key to quit.
-.It Fl Fl esc-return-cancel
-ESC key returns
-.Dq Cancel
-button value.
+.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 generic-button1 Ar label
+.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 generic-button2 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 Help button is pressed also
+Print the name of the focused item if the
+.Dq Help
+button is pressed also
with
.Fl Fl item-bottom-desc .
-.It Fl Fl help-status
-Print also the selected items if the
-.Dq Help
-button is pressed.
.It Fl Fl hfile Ar filename
Open
.Ar filename
-in a Textbox if F1 key is pressed,
+in a Textbox if F1 key is pressed.
.It Fl Fl hline Ar string
Dialog subtitle.
.It Fl Fl hmsg Ar string
@@ -220,7 +243,7 @@ Do not exit with unknown options.
.It Fl Fl insecure
Print
.Sq *
-to hide passwords while typing; whitespace otherwise.
+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.
@@ -234,7 +257,7 @@ Load theme from
.It Fl Fl max-input Ar size
Maximum length of the input for
.Fl Fl inputbox
-ans
+and
.Fl Fl passwordbox ,
default 2048.
.It Fl Fl no-cancel
@@ -242,11 +265,15 @@ Do not show
.Dq Cancel
button.
.It Fl Fl no-descriptions
-Do not display items desciption, for Checklist, Menu, Radiolist or Treeview.
+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.
+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
@@ -259,30 +286,52 @@ Set
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 whitespace.
+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 widget at exit.
+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
-Separate selected items with a new line and avoid to quote.
+Print selected items separated by a new line and avoid to quote.
.It Fl Fl shadow
-Show a pseudo shadow for the dialog, enabled by default.
+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
@@ -294,7 +343,7 @@ 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
-enables focus switching between buttons and input components pressing TAB,
+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 ,
@@ -314,24 +363,78 @@ with a tab in
.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
-By default the
+Disable
+.Ar text
+modification.
+By default
.Ar text
-is changed before to be printed.
+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.
-This option disable the
-.Ar text
-modification.
.It Fl Fl theme Ar theme
-Set a graphical style: blackwhite, bsddialog, flat or dialog.
+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
@@ -398,7 +501,7 @@ following strings replace
until the next
.Dq XXX ,
the loop ends reading
-.Dv EOF .
+.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
@@ -444,11 +547,12 @@ for autosize.
Ar miniperc Oc ...
Dialog to show a main bar to represent
.Ar mainperc
-from 0 to 100 and some mini bar with a
+from 0 to 100.
+Some mini bar with a
.Ar minilabel
string and a
.Ar miniperc
-with value from 0 and 100 or negative to print a descriptive string: -1
+with a value from 0 and 100 or negative to print a descriptive string: -1
.Dq Succeeded ,
-2
.Dq Failed ,
@@ -465,16 +569,19 @@ with value from 0 and 100 or negative to print a descriptive string: -1
-8
.Dq \&In Progress ,
-9
-a blank line,
+to hide
+.Fa miniperc ,
-10
.Dq N/A ,
-11
-.Dq Pending .
+.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 navigate the text.
+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
@@ -486,9 +593,9 @@ Dialog to get a list of passwords, equivalent to
.Fl Fl form
except typed characters are hidden.
.It Fl Fl pause Ar text Ar rows Ar cols Ar seconds
-Dialog runs until the timeout in
+Dialog runs until
.Ar seconds
-expires or a button is pressed.
+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.
@@ -514,8 +621,9 @@ is the default value, the keys UP, DOWN, HOME, END, PAGEUP and PAGEDOWN can
change it.
.It Fl Fl textbox Ar file Ar rows Ar cols
Opens and prints
-.Ar file
-the UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to navigate;
+.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 .
@@ -536,8 +644,29 @@ buttons are renamed
.Dq Yes
and
.Dq \&No .
-UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to navigate the text.
+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
@@ -566,9 +695,17 @@ Timeout.
.It 5
ESC key.
.It 6
-Generic 1 button.
+Left1 generic button.
.It 7
-Generic 2 button.
+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:
@@ -595,6 +732,7 @@ Multi-dialog:
.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
@@ -641,8 +779,10 @@ 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
@@ -655,7 +795,9 @@ Obsolete Equivalent
--yes-label --ok-label
.Ed
.Sh SEE ALSO
-.Xr bsddialog 3
+.Xr bsddialog 3 ,
+.Xr strftime 3 ,
+.Xr terminfo 5
.Sh HISTORY
The
.Nm bsddialog
@@ -668,7 +810,7 @@ was written by
.Aq Mt asiciliano@FreeBSD.org .
.Pp
.Nm bsddialog
-provides a subset of the functionality described in the
+provides also a subset of the functionality described in the
.Nm dialog
manual.
The following features were reimplemented:
@@ -757,8 +899,9 @@ Compatibility is not a priority for future development.
.An Baptiste Daroussin
.Aq Mt bapt@FreeBSD.org ,
.An \&Ed Maste
-.Aq Mt emaste@FreeBSD.org
-and
+.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;
+ }
+}