aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUMakefile28
-rw-r--r--LICENSE24
-rw-r--r--Makefile49
-rw-r--r--README.md160
-rw-r--r--bsddialog.c1263
-rw-r--r--lib/GNUMakefile31
-rw-r--r--lib/Makefile73
-rw-r--r--lib/barbox.c369
-rw-r--r--lib/bsddialog.h257
-rw-r--r--lib/bsddialog_theme.h96
-rw-r--r--lib/commandbox.c211
-rw-r--r--lib/editorbox.c45
-rw-r--r--lib/filebox.c52
-rw-r--r--lib/formbox.c396
-rw-r--r--lib/infobox.c114
-rw-r--r--lib/lib_util.c996
-rw-r--r--lib/lib_util.h146
-rw-r--r--lib/libbsddialog.c142
-rw-r--r--lib/menubox.c1015
-rw-r--r--lib/messagebox.c278
-rw-r--r--lib/textbox.c280
-rw-r--r--lib/theme.c286
-rw-r--r--lib/timebox.c241
-rw-r--r--library_examples/buildlist.c44
-rw-r--r--library_examples/checklist.c44
-rwxr-xr-xlibrary_examples/compile10
-rw-r--r--library_examples/infobox.c32
-rw-r--r--library_examples/menu.c44
-rw-r--r--library_examples/mixedlist.c71
-rw-r--r--library_examples/msgbox.c42
-rw-r--r--library_examples/ports.c97
-rw-r--r--library_examples/radiolist.c44
-rw-r--r--library_examples/theme.c67
-rw-r--r--library_examples/treeview.c44
-rw-r--r--library_examples/yesno.c32
-rw-r--r--screenshot.pngbin0 -> 11050 bytes
-rwxr-xr-xutility_examples/gauge_example.sh20
-rwxr-xr-xutility_examples/info_example.sh3
-rwxr-xr-xutility_examples/menu_example.sh41
-rwxr-xr-xutility_examples/message_example.sh5
-rwxr-xr-xutility_examples/mixedform_example.sh25
-rwxr-xr-xutility_examples/mixedgauge_example.sh24
42 files changed, 7241 insertions, 0 deletions
diff --git a/GNUMakefile b/GNUMakefile
new file mode 100644
index 000000000000..7480ae33ec21
--- /dev/null
+++ b/GNUMakefile
@@ -0,0 +1,28 @@
+# PUBLIC DOMAIN - NO WARRANTY, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written by Alfonso Sabato Siciliano
+
+OUTPUT= bsddialog
+SOURCES= bsddialog.c
+OBJECTS= $(SOURCES:.c=.o)
+LIBPATH= ./lib
+LIBBSDDIALOG= $(LIBPATH)/libbsddialog.so
+CFLAGS= -g -Wall -I$(LIBPATH)
+LDFLAGS= -Wl,-rpath=$(LIBPATH) -L$(LIBPATH) -lbsddialog
+RM = rm -f
+
+all : $(OUTPUT)
+
+$(OUTPUT): $(LIBBSDDIALOG) $(OBJECTS)
+ $(CC) $^ -o $@ $(LDFLAGS)
+
+${LIBBSDDIALOG}:
+ make -C ${LIBPATH} -f GNUMakefile
+
+%.o: %.c $(LIBBSDDIALOG)
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ make -C ${LIBPATH} -f GNUMakefile clean
+ $(RM) $(OUTPUT) *.o *~
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000000..434f1782e537
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+BSD 2-Clause License
+
+Copyright (c) 2021, Alfonso Sabato Siciliano
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000000..295aa927e4c5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,49 @@
+# Any copyright is dedicated to the Public Domain, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written by Alfonso Sabato Siciliano
+
+OUTPUT= bsddialog
+SOURCES= bsddialog.c
+OBJECTS= ${SOURCES:.c=.o}
+LIBPATH= ${.CURDIR}/lib
+LIBBSDDIALOG= ${LIBPATH}/libbsddialog.so
+
+CFLAGS= -Wall -I${LIBPATH}
+LDFLAGS= -Wl,-rpath=${LIBPATH} -L${LIBPATH} -lbsddialog
+
+BINDIR= /usr/local/bin
+MAN= ${OUTPUT}.1
+GZIP= gzip -cn
+MANDIR= /usr/local/share/man/man1
+
+INSTALL= install
+RM= rm -f
+
+all : ${OUTPUT}
+
+${OUTPUT}: ${LIBBSDDIALOG} ${OBJECTS}
+ ${CC} ${LDFLAGS} ${OBJECTS} -o ${.PREFIX}
+
+${LIBBSDDIALOG}:
+.if defined(PORTNCURSES)
+ make -C ${LIBPATH} -DPORTNCURSES
+.else
+ make -C ${LIBPATH}
+.endif
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+install:
+ ${INSTALL} -s -m 555 ${OUTPUT} ${BINDIR}
+ ${GZIP} ${MAN} > ${MAN}.gz
+ ${INSTALL} -m 444 ${MAN}.gz ${MANDIR}
+
+unistall:
+ ${RM} ${BINDIR}/${OUTPUT}
+ ${RM} ${MANDIR}/${MAN}.gz
+
+clean:
+ make -C ${LIBPATH} clean
+ ${RM} ${OUTPUT} *.o *~ *.core ${MAN}.gz
diff --git a/README.md b/README.md
new file mode 100644
index 000000000000..1d34f3b51099
--- /dev/null
+++ b/README.md
@@ -0,0 +1,160 @@
+# BSDDialog
+
+**Work In Progress!**
+
+This project provides **bsddialog** and **libbsddialog**, an utility and a
+library to build scripts and tools with *TUI Widgets*.
+
+Description:
+<https://www.freebsd.org/status/report-2021-04-2021-06/#_bsddialog_tui_widgets>
+
+
+## Getting Started
+
+FreeBSD:
+
+```
+% git clone https://gitlab.com/alfix/bsddialog.git
+% cd bsddialog
+% make
+% ./bsddialog --msgbox "Hello World!" 8 20
+```
+
+If you are using XFCE install
+[devel/ncurses](https://www.freshports.org/devel/ncurses/)
+
+```
+% sudo pkg install ncurses
+% git clone https://gitlab.com/alfix/bsddialog.git
+% cd bsddialog
+% make -DPORTNCURSES
+% ./bsddialog --msgbox "Hello World!" 8 20
+```
+
+Linux:
+
+```
+% git clone https://gitlab.com/alfix/bsddialog.git
+% cd bsddialog
+% make -GNUMakefile
+% ./bsddialog --msgbox "Hello World!" 8 20
+```
+
+Output:
+
+![screenshot](screenshot.png)
+
+
+Examples utility:
+```
+% ./bsddialog --title msgbox --msgbox "Hello World!" 5 30
+% ./bsddialog --theme default --title msgbox --msgbox "Hello World!" 5 30
+% ./bsddialog --begin-y 2 --title yesno --yesno "Hello World!" 5 30
+% ./bsddialog --ascii-lines --pause "Hello World!" 8 50 5
+% ./bsddialog --checklist "Space to select" 0 0 0 Name1 Desc1 off Name2 Desc2 on Name3 Desc3 off
+% ./bsddialog --backtitle "TITLE" --title yesno --hline "bsddialog" --yesno "Hello World!" 5 25
+% ./bsddialog --extra-button --help-button --defaultno --yesno "Hello World!" 0 0
+```
+
+Examples library:
+```
+% cd library_examples
+% sh compile
+% ./buildlist
+% ./infobox
+% ./menu
+% ./mixedlist
+% ./msgbox
+% ./ports
+% ./radiolist
+% ./theme
+% ./treeview
+% ./yesno
+```
+
+Use Cases:
+
+ - [portconfig](https://gitlab.com/alfix/portconfig)
+
+
+## Features
+
+**Common Options:**
+
+--ascii-lines, --aspect *ratio* (for infobox, msgbox and yesno),
+--backtitle *backtitle*, --begin-x *x* (--begin *y y*),
+(--begin *y x*), --cancel-label *string*, -clear (test with multiple widgets),
+--colors, --date-format *format*, --default-button *string*, --defaultno,
+--default-item *string*,
+--exit-label *string*, --extra-button, --extra-label *string*,
+--hfile *filename* (for completed widgets), n--help-button,
+--help-label *string*, --help-status, --help-tags, --hline *string*, --ignore,
+--item-help, --no-cancel, --nocancel, --no-label *string*, --no-items,
+--no-lines, --no-ok,
+--nook, --no-shadow, --no-tags, --ok-label *string*, --output-fd *fd*,
+--output-separator *string*, --print-version,
+--print-size (todo move lib -> utility), --quoted (quotes all != dialog),
+--print-maxsize, --shadow, --single-quoted (add --quote-with *ch*?),
+--separator *string* (alias --output-separator *string*),
+--separate-output (rename --separate-output-withnl?), --sleep *secs*, --stderr,
+--stdout, --theme *string* ("bsddialog", "dialog", "blackwhite" and "magenta"),
+--time-format *format*, --title *title*, --version, --yes-label *string*.
+
+**Widgets:**
+
+ infobox (do not clear the screen), msgbox,
+ yesno (dialog renames "yes/no" -> "ok/cancel" with --extra-button --help-button).
+ checklist, radiolist, menu, mixedlist, treeview and textbox.
+
+## TODO
+
+**Common Options:**
+
+| Option | Status | Note |
+| ---------------------------- | ----------- | ------------------------------- |
+| --cr-wrap | Coding | |
+| --help | In progress | |
+| --input-fd *fd* | | |
+| --insecure | | |
+| --keep-tite | | |
+| --keep-window | | |
+| --last-key | | |
+| --max-input *size* | | |
+| --no-collapse | Coding | |
+| --no-kill | | |
+| --no-nl-expand | Coding | |
+| --tab-correct | | |
+| --tab-len *n* | | |
+| --trim | Coding | |
+
+
+To evaluate / Not planned in the short term: --column-separator *string*,
+--create-rc *file*, --iso-week, --no-mouse, --print-text-only *str h w*,
+--print-text-size *str h w*, --reorder, -scrollbar, --separate-widget *string*,
+--size-err, --timeout *secs*,--trace *filename*, --visit-items,
+--week-start *day*.
+
+
+**Widgets:**
+
+| Widget | Status | Note |
+|--------------- | ----------- | ----------------------------------------------|
+| --buildlist | In progress | todo autosize, resize, F1 |
+| --calendar | In progress | todo autosize, resize, F1, leap year, year <=0, month days |
+| --editbox | | |
+| --form | In progress | implemented via --mixedform |
+| --gauge | In progress | |
+| --inputbox | In progress | implemented via --mixedform, todo \<init\> |
+| --mixedform | In progress | todo autosize, resize, F1 |
+| --mixedgauge | In progress | todo autosize, resize, F1 |
+| --passwordbox | In progress | implemented via --mixedform, todo \<init\> |
+| --passwordform | In progress | implemented via --mixedform |
+| --pause | In progress | todo autosize, resize, F1 |
+| --prgbox | In progress | add command opts |
+| --programbox | Coding | |
+| --progressbox | | |
+| --rangebox | In progress | todo autosize, resize, F1, PAGE-UP/PAGE-DOWN/HOME/END keys |
+| --timebox | In progress | todo autosize, resize, F1 |
+
+To evaluate / Not planned in the short term: tailbox (textbox/fseek), tailboxbg,
+dselect, fselect, inputmenu.
diff --git a/bsddialog.c b/bsddialog.c
new file mode 100644
index 000000000000..249f1d3c4f3a
--- /dev/null
+++ b/bsddialog.c
@@ -0,0 +1,1263 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#define BSDDIALOG_VERSION "0.1 devel"
+
+enum OPTS {
+ /* Common options */
+ ASCII_LINES,
+ ASPECT_RATIO,
+ BACKTITLE,
+ BEGIN_X,
+ BEGIN_Y,
+ CANCEL_LABEL,
+ CLEAR,
+ COLORS,
+ /*COLUMN_SEPARATOR,*/
+ CR_WRAP,
+ /*CREATE_RC,*/
+ DATE_FORMAT,
+ DEFAULTNO,
+ DEFAULT_BUTTON,
+ DEFAULT_ITEM,
+ EXIT_LABEL,
+ EXTRA_BUTTON,
+ EXTRA_LABEL,
+ HELP,
+ HELP_BUTTON,
+ HELP_LABEL,
+ HELP_STATUS,
+ HELP_TAGS,
+ HFILE,
+ HLINE,
+ IGNORE,
+ /*INPUT_FD,*/
+ /*INSECURE,*/
+ ITEM_HELP,
+ ITEM_PREFIX,
+ /*KEEP_TITE,*/
+ /*KEEP_WINDOW,*/
+ /*LAST_KEY,*/
+ /*MAX_INPUT,*/
+ NO_CANCEL,
+ NOCANCEL,
+ NO_COLLAPSE,
+ NO_ITEMS,
+ /*NO_KILL,*/
+ NO_LABEL,
+ NO_LINES,
+ /*NO_MOUSE,*/
+ NO_NL_EXPAND,
+ NO_OK,
+ NOOK,
+ NO_TAGS,
+ NO_SHADOW,
+ OK_LABEL,
+ OUTPUT_FD,
+ OUTPUT_SEPARATOR,
+ PRINT_MAXSIZE,
+ PRINT_SIZE,
+ PRINT_VERSION,
+ QUOTED,
+ /*SCROLLBAR,*/
+ SEPARATE_OUTPUT,
+ /*SEPARATE_WIDGET,*/
+ SEPARATOR,
+ SHADOW,
+ SINGLE_QUOTED,
+ /*SIZE_ERR,*/
+ SLEEP,
+ STDERR,
+ STDOUT,
+ /*TAB_CORRECT,*/
+ /*TAB_LEN,*/
+ THEME,
+ TIME_FORMAT,
+ /*TIMEOUT,*/
+ TITLE,
+ /*TRACE,*/
+ TRIM,
+ VERSION,
+ /*VISIT_ITEMS,*/
+ YES_LABEL,
+ /* Widgets */
+ BUILDLIST,
+ CALENDAR,
+ CHECKLIST,
+ DSELECT,
+ EDITBOX,
+ FORM,
+ FSELECT,
+ GAUGE,
+ INFOBOX,
+ INPUTBOX,
+ INPUTMENU,
+ MENU,
+ MIXEDFORM,
+ MIXEDGAUGE,
+ MSGBOX,
+ PASSWORDBOX,
+ PASSWORDFORM,
+ PAUSE,
+ PRGBOX,
+ PROGRAMBOX,
+ PROGRESSBOX,
+ RADIOLIST,
+ RANGEBOX,
+ TAILBOX,
+ TAILBOXBG,
+ TEXTBOX,
+ TIMEBOX,
+ TREEVIEW,
+ YESNO,
+};
+
+/* libbsddialog does not support NULL string for now */
+static char *nostring = "";
+/* Menus flags and options */
+static bool item_prefix_flag, item_bottomdesc_flag, item_output_sepnl_flag;
+static bool item_singlequote_flag, list_items_on_flag, item_tag_help_flag;
+static bool item_always_quote_flag;
+static char *item_output_sep_flag;
+/* Time and calendar options */
+static char *date_fmt_flag, *time_fmt_flag;
+/* General flags and options */
+static int output_fd_flag;
+
+void usage(void);
+/* widgets */
+#define BUILDER_ARGS struct bsddialog_conf conf, char* text, int rows, \
+ int cols, int argc, char **argv
+int buildlist_builder(BUILDER_ARGS);
+int calendar_builder(BUILDER_ARGS);
+int checklist_builder(BUILDER_ARGS);
+int dselect_builder(BUILDER_ARGS);
+int editbox_builder(BUILDER_ARGS);
+int form_builder(BUILDER_ARGS);
+int fselect_builder(BUILDER_ARGS);
+int gauge_builder(BUILDER_ARGS);
+int infobox_builder(BUILDER_ARGS);
+int inputbox_builder(BUILDER_ARGS);
+int inputmenu_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 prgbox_builder(BUILDER_ARGS);
+int programbox_builder(BUILDER_ARGS);
+int progressbox_builder(BUILDER_ARGS);
+int radiolist_builder(BUILDER_ARGS);
+int rangebox_builder(BUILDER_ARGS);
+int tailbox_builder(BUILDER_ARGS);
+int tailboxbg_builder(BUILDER_ARGS);
+int textbox_builder(BUILDER_ARGS);
+int timebox_builder(BUILDER_ARGS);
+int treeview_builder(BUILDER_ARGS);
+int yesno_builder(BUILDER_ARGS);
+
+void usage(void)
+{
+
+ printf("usage: bsddialog --help\n"\
+ " bsddialog --version\n"\
+ " bsddialog [--<common-opts>] --<widget> <text> "\
+ "<height> <width> [--<widget-opts>]\n");
+}
+
+int main(int argc, char *argv[argc])
+{
+ char *text, *backtitle_flag, *theme_flag;
+ int input, rows, cols, output, getH, getW;
+ int (*widgetbuilder)(BUILDER_ARGS) = NULL;
+ bool ignore_flag, print_maxsize_flag;
+ struct winsize ws;
+ struct bsddialog_conf conf;
+
+ bsddialog_initconf(&conf);
+
+ backtitle_flag = NULL;
+ theme_flag = NULL;
+ output_fd_flag = STDERR_FILENO;
+ print_maxsize_flag = false;
+ ignore_flag = false;
+
+ item_output_sepnl_flag = item_singlequote_flag = false;
+ item_prefix_flag = item_bottomdesc_flag = false;
+ list_items_on_flag = item_tag_help_flag = false;
+ item_always_quote_flag = false;
+ item_output_sep_flag = NULL;
+
+ date_fmt_flag = time_fmt_flag = NULL;
+
+ /* options descriptor */
+ struct option longopts[] = {
+ /* common options */
+ { "ascii-lines", no_argument, NULL, ASCII_LINES },
+ { "aspect", required_argument, NULL, ASPECT_RATIO },
+ { "backtitle_flag", required_argument, NULL, BACKTITLE },
+ { "begin-x", required_argument, NULL, BEGIN_X },
+ { "begin-y", required_argument, NULL, BEGIN_Y },
+ { "cancel-label", required_argument, NULL, CANCEL_LABEL },
+ { "clear", no_argument, NULL, CLEAR },
+ { "colors", no_argument, NULL, COLORS },
+ /*{ "column-separator", required_argument, NULL, COLUMN_SEPARATOR },*/
+ { "cr-wrap", no_argument, NULL, CR_WRAP },
+ /*{ "create-rc", required_argument, NULL, CREATE_RC },*/
+ { "date-format", required_argument, NULL, DATE_FORMAT },
+ { "defaultno", no_argument, NULL, DEFAULTNO },
+ { "default-button", required_argument, NULL, DEFAULT_BUTTON },
+ { "default-item", required_argument, NULL, DEFAULT_ITEM },
+ { "exit-label", required_argument, NULL, EXIT_LABEL },
+ { "extra-button", no_argument, NULL, EXTRA_BUTTON },
+ { "extra-label", required_argument, NULL, EXTRA_LABEL },
+ { "help", no_argument, NULL, HELP },
+ { "help-button", no_argument, NULL, HELP_BUTTON },
+ { "help-label", required_argument, NULL, HELP_LABEL },
+ { "help-status", no_argument, NULL, HELP_STATUS },
+ { "help-tags", no_argument, NULL, HELP_TAGS },
+ { "hfile", required_argument, NULL, HFILE },
+ { "hline", required_argument, NULL, HLINE },
+ { "ignore", no_argument, NULL, IGNORE },
+ /*{ "input-fd", required_argument, NULL, INPUT_FD },*/
+ /*{ "insecure", no_argument, NULL, INSECURE },*/
+ { "item-help", no_argument, NULL, ITEM_HELP },
+ /*{ "keep-tite", no_argument, NULL, KEEP_TITE },*/
+ /*{ "keep-window", no_argument, NULL, KEEP_WINDOW },*/
+ /*{ "last-key", no_argument, NULL, LAST_KEY },*/
+ /*{ "max-input", required_argument, NULL, MAX_INPUT },*/
+ { "no-cancel", no_argument, NULL, NO_CANCEL },
+ { "nocancel", no_argument, NULL, NOCANCEL },
+ { "no-collapse", no_argument, NULL, NO_COLLAPSE },
+ { "no-items", no_argument, NULL, NO_ITEMS },
+ /*{ "no-kill", no_argument, NULL, NO_KILL },*/
+ { "no-label", required_argument, NULL, NO_LABEL },
+ { "no-lines", no_argument, NULL, NO_LINES },
+ /*{ "no-mouse", no_argument, NULL, NO_MOUSE },*/
+ { "no-nl-expand", no_argument, NULL, NO_NL_EXPAND },
+ { "no-ok", no_argument, NULL, NO_OK },
+ { "nook ", no_argument, NULL, NOOK },
+ { "no-tags", no_argument, NULL, NO_TAGS },
+ { "no-shadow", no_argument, NULL, NO_SHADOW },
+ { "ok-label", required_argument, NULL, OK_LABEL },
+ { "output-fd", required_argument, NULL, OUTPUT_FD },
+ { "separator", required_argument, NULL, SEPARATOR },
+ { "output-separator", required_argument, NULL, OUTPUT_SEPARATOR },
+ { "print-maxsize", no_argument, NULL, PRINT_MAXSIZE },
+ { "print-size", no_argument, NULL, PRINT_SIZE },
+ { "print-version", no_argument, NULL, PRINT_VERSION },
+ { "quoted", no_argument, NULL, QUOTED },
+ /*{ "scrollbar", no_argument, NULL, SCROLLBAR},*/
+ { "separate-output", no_argument, NULL, SEPARATE_OUTPUT },
+ /*{ "separate-widget", required_argument, NULL, SEPARATE_WIDGET },*/
+ { "shadow", no_argument, NULL, SHADOW },
+ { "single-quoted", no_argument, NULL, SINGLE_QUOTED },
+ /*{ "size-err", no_argument, NULL, SIZE_ERR },*/
+ { "sleep", required_argument, NULL, SLEEP },
+ { "stderr", no_argument, NULL, STDERR },
+ { "stdout", no_argument, NULL, STDOUT },
+ /*{ "tab-correct", no_argument, NULL, TAB_CORRECT },*/
+ /*{ "tab-len", required_argument, NULL, TAB_LEN },*/
+ { "theme_flag", required_argument, NULL, THEME },
+ { "time-format", required_argument, NULL, TIME_FORMAT },
+ /*{ "timeout", required_argument, NULL, TIMEOUT },*/
+ { "title", required_argument, NULL, TITLE },
+ /*{ "trace", required_argument, NULL, TRACE },*/
+ { "trim", no_argument, NULL, TRIM },
+ { "version", no_argument, NULL, VERSION },
+ /*{ "visit-items", no_argument, NULL, VISIT_ITEMS },*/
+ { "yes-label", required_argument, NULL, YES_LABEL },
+ /* Widgets */
+ { "buildlist", no_argument, NULL, BUILDLIST },
+ { "calendar", no_argument, NULL, CALENDAR },
+ { "checklist", no_argument, NULL, CHECKLIST },
+ { "dselect", no_argument, NULL, DSELECT },
+ { "editbox", no_argument, NULL, EDITBOX },
+ { "form", no_argument, NULL, FORM },
+ { "fselect", no_argument, NULL, FSELECT },
+ { "gauge", no_argument, NULL, GAUGE },
+ { "infobox", no_argument, NULL, INFOBOX },
+ { "inputbox", no_argument, NULL, INPUTBOX },
+ { "inputmenu", no_argument, NULL, INPUTMENU },
+ { "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 },
+ { "prgbox", no_argument, NULL, PRGBOX },
+ { "programbox", no_argument, NULL, PROGRAMBOX },
+ { "progressbox", no_argument, NULL, PROGRESSBOX },
+ { "radiolist", no_argument, NULL, RADIOLIST },
+ { "rangebox", no_argument, NULL, RANGEBOX },
+ { "tailbox", no_argument, NULL, TAILBOX },
+ { "tailboxbg", no_argument, NULL, TAILBOXBG },
+ { "textbox", no_argument, NULL, TEXTBOX },
+ { "timebox", no_argument, NULL, TIMEBOX },
+ { "treeview", no_argument, NULL, TREEVIEW },
+ { "yesno", no_argument, NULL, YESNO },
+ /* END */
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((input = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+ switch (input) {
+ /* Common options */
+ case ASCII_LINES:
+ conf.ascii_lines = true;
+ break;
+ case ASPECT_RATIO:
+ conf.aspect_ratio = atoi(optarg);
+ if (conf.aspect_ratio < 1) {
+ printf("Error: aspect cannot be < 1");
+ return (BSDDIALOG_ERROR);
+ }
+ break;
+ case BACKTITLE:
+ backtitle_flag = optarg;
+ break;
+ case BEGIN_X:
+ conf.x = atoi(optarg);
+ if (conf.x < BSDDIALOG_CENTER) {
+ printf("Error: --begin-x %d, cannot be < %d",
+ conf.x, BSDDIALOG_CENTER);
+ return (BSDDIALOG_ERROR);
+ }
+ break;
+ case BEGIN_Y:
+ conf.y = atoi(optarg);
+ if (conf.y < BSDDIALOG_CENTER) {
+ printf("Error: --begin-y %d, cannot be < %d",
+ conf.y, BSDDIALOG_CENTER);
+ return (BSDDIALOG_ERROR);
+ }
+ break;
+ case CANCEL_LABEL:
+ conf.button.cancel_label = optarg;
+ break;
+ case CLEAR:
+ conf.clear = true;
+ break;
+ case COLORS:
+ conf.text.colors = true;
+ break;
+ case CR_WRAP:
+ conf.text.cr_wrap = true;
+ break;
+ case DATE_FORMAT:
+ date_fmt_flag = optarg;
+ break;
+ case DEFAULT_BUTTON:
+ conf.button.default_label = optarg;
+ break;
+ case DEFAULT_ITEM:
+ conf.menu.default_item = optarg;
+ break;
+ case DEFAULTNO:
+ conf.button.defaultno = true;
+ break;
+ case EXIT_LABEL:
+ conf.button.exit_label = optarg;
+ break;
+ case EXTRA_BUTTON:
+ conf.button.extra_button = true;
+ break;
+ case EXTRA_LABEL:
+ conf.button.extra_label = optarg;
+ break;
+ case HELP:
+ usage();
+ printf("\n");
+ printf("See \'man 1 bsddialog\' for more information.\n");
+ return (BSDDIALOG_YESOK);
+ case HELP_BUTTON:
+ conf.button.help_button = true;
+ break;
+ case HELP_LABEL:
+ conf.button.help_label = optarg;
+ break;
+ case HELP_STATUS:
+ list_items_on_flag = true;
+ break;
+ case HELP_TAGS:
+ item_tag_help_flag = true;
+ break;
+ case HFILE:
+ conf.hfile = optarg;
+ break;
+ case HLINE:
+ conf.hline = optarg;
+ break;
+ case IGNORE:
+ ignore_flag = true;
+ break;
+ case ITEM_HELP:
+ item_bottomdesc_flag = true;
+ break;
+ case NO_ITEMS:
+ conf.menu.no_items = true;
+ break;
+ case ITEM_PREFIX:
+ item_prefix_flag = true;
+ break;
+ case NOCANCEL:
+ case NO_CANCEL:
+ conf.button.no_cancel = true;
+ break;
+ case NO_COLLAPSE:
+ conf.text.no_collapse = true;
+ break;
+ case NO_LABEL:
+ conf.button.no_label = optarg;
+ break;
+ case NO_LINES:
+ conf.no_lines = true;
+ break;
+ case NO_NL_EXPAND:
+ conf.text.no_nl_expand = true;
+ break;
+ case NOOK:
+ case NO_OK:
+ conf.button.no_ok = true;
+ break;
+ case NO_TAGS:
+ conf.menu.no_tags = true;
+ break;
+ case NO_SHADOW:
+ conf.shadow = false;
+ break;
+ case OK_LABEL:
+ conf.button.ok_label = optarg;
+ break;
+ case OUTPUT_FD:
+ output_fd_flag = atoi(optarg);
+ break;
+ case SEPARATOR:
+ case OUTPUT_SEPARATOR:
+ item_output_sep_flag = optarg;
+ break;
+ case QUOTED:
+ item_always_quote_flag = true;
+ break;
+ case PRINT_MAXSIZE:
+ print_maxsize_flag = true;
+ break;
+ case PRINT_SIZE:
+ conf.get_height = &getH;;
+ conf.get_width = &getW;
+ break;
+ case PRINT_VERSION:
+ printf("bsddialog version %s\n", BSDDIALOG_VERSION);
+ break;
+ case SEPARATE_OUTPUT:
+ item_output_sepnl_flag = true;
+ break;
+ case SHADOW:
+ conf.shadow = true;
+ break;
+ case SINGLE_QUOTED:
+ item_singlequote_flag = true;
+ break;
+ case SLEEP:
+ conf.sleep = atoi(optarg);
+ break;
+ case STDERR:
+ output_fd_flag = STDERR_FILENO;
+ break;
+ case STDOUT:
+ output_fd_flag = STDOUT_FILENO;
+ break;
+ case THEME:
+ theme_flag = optarg;
+ break;
+ case TIME_FORMAT:
+ time_fmt_flag = optarg;
+ break;
+ case TITLE:
+ conf.title = optarg;
+ break;
+ case TRIM:
+ conf.text.trim = true;
+ break;
+ case VERSION:
+ printf("bsddialog version %s\n", BSDDIALOG_VERSION);
+ return (BSDDIALOG_YESOK);
+ case YES_LABEL:
+ conf.button.yes_label = optarg;
+ break;
+ /* Widgets */
+ case BUILDLIST:
+ widgetbuilder = buildlist_builder;
+ break;
+ case CALENDAR:
+ widgetbuilder = calendar_builder;
+ break;
+ case CHECKLIST:
+ widgetbuilder = checklist_builder;
+ break;
+ case DSELECT:
+ widgetbuilder = dselect_builder;
+ break;
+ case EDITBOX:
+ widgetbuilder = editbox_builder;
+ break;
+ case FORM:
+ widgetbuilder = form_builder;
+ break;
+ case FSELECT:
+ widgetbuilder = fselect_builder;
+ break;
+ case GAUGE:
+ widgetbuilder = gauge_builder;
+ break;
+ case INFOBOX:
+ widgetbuilder = infobox_builder;
+ break;
+ case INPUTBOX:
+ widgetbuilder = inputbox_builder;
+ break;
+ case INPUTMENU:
+ widgetbuilder = inputmenu_builder;
+ break;
+ case MENU:
+ widgetbuilder = menu_builder;
+ break;
+ case MIXEDFORM:
+ widgetbuilder = mixedform_builder;
+ break;
+ case MIXEDGAUGE:
+ widgetbuilder = mixedgauge_builder;
+ break;
+ case MSGBOX:
+ widgetbuilder = msgbox_builder;
+ break;
+ case PAUSE:
+ widgetbuilder = pause_builder;
+ break;
+ case PASSWORDBOX:
+ widgetbuilder = passwordbox_builder;
+ break;
+ case PASSWORDFORM:
+ widgetbuilder = passwordform_builder;
+ break;
+ case PRGBOX:
+ widgetbuilder = prgbox_builder;
+ break;
+ case PROGRAMBOX:
+ widgetbuilder = programbox_builder;
+ break;
+ case PROGRESSBOX:
+ widgetbuilder = progressbox_builder;
+ break;
+ case RADIOLIST:
+ widgetbuilder = radiolist_builder;
+ break;
+ case RANGEBOX:
+ widgetbuilder = rangebox_builder;
+ break;
+ case TAILBOX:
+ widgetbuilder = tailbox_builder;
+ break;
+ case TAILBOXBG:
+ widgetbuilder = tailboxbg_builder;
+ break;
+ case TEXTBOX:
+ widgetbuilder = textbox_builder;
+ break;
+ case TIMEBOX:
+ widgetbuilder = timebox_builder;
+ break;
+ case TREEVIEW:
+ widgetbuilder = treeview_builder;
+ break;
+ case YESNO:
+ widgetbuilder = yesno_builder;
+ break;
+ /* Error */
+ default:
+ if (ignore_flag == false) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (print_maxsize_flag) {
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+ dprintf(output_fd_flag, "MaxSize: %d, %d\n", ws.ws_row, ws.ws_col);
+ if (argc == 0)
+ return (BSDDIALOG_YESOK);
+ }
+
+ if (argc < 3) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+ text = argv[0];
+ rows = atoi(argv[1]);
+ cols = atoi(argv[2]);
+ argc -= 3;
+ argv += 3;
+
+ if(bsddialog_init() != 0) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return (BSDDIALOG_ERROR);
+ }
+
+ if (theme_flag != NULL) {
+ if (strcmp(theme_flag, "bsddialog") == 0)
+ bsddialog_set_default_theme(BSDDIALOG_THEME_BSDDIALOG);
+ else if (strcmp(theme_flag, "blackwhite") == 0)
+ bsddialog_set_default_theme(BSDDIALOG_THEME_BLACKWHITE);
+ else if (strcmp(theme_flag, "dialog") == 0)
+ bsddialog_set_default_theme(BSDDIALOG_THEME_DIALOG);
+ else if (strcmp(theme_flag, "magenta") == 0)
+ bsddialog_set_default_theme(BSDDIALOG_THEME_MAGENTA);
+ else
+ bsddialog_set_default_theme(BSDDIALOG_THEME_DIALOG);
+ }
+
+ if (backtitle_flag != NULL)
+ bsddialog_backtitle(conf, backtitle_flag);
+
+ output = BSDDIALOG_YESOK;
+ if (widgetbuilder != NULL)
+ output = widgetbuilder(conf, text, rows, cols, argc, argv);
+
+ bsddialog_end();
+
+ if (conf.get_height != NULL && conf.get_width != NULL &&
+ output != BSDDIALOG_ERROR)
+ dprintf(output_fd_flag, "Widget size: (%d - %d)\n",
+ *conf.get_height, *conf.get_width);
+
+ /* debug & devel */
+ printf("[Debug] Exit status: %d ", output);
+ switch (output) {
+ case BSDDIALOG_ERROR: printf("ERROR"); break;
+ case BSDDIALOG_YESOK: printf("YESOK"); break;
+ case BSDDIALOG_NOCANCEL: printf("NOCANCEL"); break;
+ case BSDDIALOG_HELP: printf("HELP"); break;
+ case BSDDIALOG_EXTRA: printf("EXTRA"); break;
+ case BSDDIALOG_ITEM_HELP: printf("ITEM_HELP");break;
+ case BSDDIALOG_ESC: printf("ESC"); break;
+ default: printf("Unknow status! Bug!"); break;
+ }
+ printf("\n");
+
+ if (output == BSDDIALOG_ERROR)
+ printf("Error: %s\n", bsddialog_geterror());
+
+ return (output);
+}
+
+int calendar_builder(BUILDER_ARGS)
+{
+ int output;
+ unsigned int yy, mm, dd;
+ time_t cal;
+ struct tm *localtm;
+ char stringdate[1024];
+
+ time(&cal);
+ localtm = localtime(&cal);
+ yy = localtm->tm_year + 1900;
+ mm = localtm->tm_mon;
+ dd = localtm->tm_mday;
+
+ /* --calendar text h w [year month day] */
+ if (argc == 3) {
+ yy = atoi(argv[0]) + 1900;
+ yy = yy > 9999 ? 9999 : yy;
+ mm = atoi(argv[1]);
+ mm = mm > 12 ? 12 : mm;
+ dd = atoi(argv[2]);
+ dd = dd > 31 ? 31 : dd;
+ }
+
+ output = bsddialog_calendar(conf, text, rows, cols, &yy, &mm, &dd);
+ if (output != BSDDIALOG_YESOK)
+ return (output);
+
+ if (date_fmt_flag == NULL) {
+ dprintf(output_fd_flag, "%u/%u/%u", yy, mm, dd);
+ }
+ else {
+ time(&cal);
+ localtm = localtime(&cal);
+ localtm->tm_year = yy - 1900;
+ localtm->tm_mon = mm;
+ localtm->tm_mday = dd;
+ strftime(stringdate, 1024, date_fmt_flag, localtm);
+ dprintf(output_fd_flag, "%s", stringdate);
+ }
+
+ return (output);
+}
+
+int dselect_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_dselect(conf, text, rows, cols);
+
+ return (output);
+}
+
+int editbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_editbox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int form_builder(BUILDER_ARGS)
+{
+ int output, formheight;
+
+ if (argc < 1 || (((argc-1) % 8) != 0) ) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ formheight = atoi(argv[0]);
+
+ output = bsddialog_form(conf, text, rows, cols, formheight, argc-1,
+ argv + 1);
+
+ return (output);
+}
+
+int fselect_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_fselect(conf, text, rows, cols);
+
+ return (output);
+}
+
+int gauge_builder(BUILDER_ARGS)
+{
+ int output /* always BSDDIALOG_YESOK */, perc;
+
+ perc = argc > 0 ? atoi (argv[0]) : 0;
+ perc = perc < 0 ? 0 : perc;
+ perc = perc > 100 ? 100 : perc;
+
+ output = bsddialog_gauge(conf, text, rows, cols, perc);
+
+ return (output);
+}
+
+int infobox_builder(BUILDER_ARGS)
+{
+ int output; /* always BSDDIALOG_YESOK */
+
+ output = bsddialog_infobox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int inputbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_inputbox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int inputmenu_builder(BUILDER_ARGS)
+{
+
+ return (BSDDIALOG_ERROR);
+}
+
+int mixedform_builder(BUILDER_ARGS)
+{
+ int output, formheight;
+
+ if (argc < 1 || (((argc-1) % 9) != 0) ) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ formheight = atoi(argv[0]);
+
+ output = bsddialog_mixedform(conf, text, rows, cols, formheight, argc-1,
+ argv + 1);
+
+ return (output);
+}
+
+int mixedgauge_builder(BUILDER_ARGS)
+{
+ int output /* always BSDDIALOG_YESOK */, perc;
+
+ if (argc < 1 || (((argc-1) % 2) != 0) ) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ perc = atoi(argv[0]);
+ perc = perc < 0 ? 0 : perc;
+ perc = perc > 100 ? 100 : perc;
+
+ output = bsddialog_mixedgauge(conf, text, rows, cols, perc,
+ argc-1, argv + 1);
+
+ return (output);
+}
+
+int msgbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_msgbox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int passwordbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_passwordbox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int passwordform_builder(BUILDER_ARGS)
+{
+ int output, formheight;
+
+ if (argc < 1 || (((argc-1) % 8) != 0) ) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ formheight = atoi(argv[0]);
+
+ output = bsddialog_passwordform(conf, text, rows, cols, formheight,
+ argc-1, argv + 1);
+
+ return (output);
+}
+
+int pause_builder(BUILDER_ARGS)
+{
+ int output, sec;
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ sec = atoi(argv[0]);
+ output = bsddialog_pause(conf, text, rows, cols, sec);
+
+ return (output);
+}
+
+int prgbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ output = bsddialog_prgbox(conf, strlen(text) == 0 ? NULL : text, rows,
+ cols, argv[0]);
+
+ return (output);
+}
+
+int programbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_programbox(conf, strlen(text) == 0 ? NULL : text, rows, cols);
+
+ return (output);
+}
+
+int progressbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_progressbox(conf, strlen(text) == 0 ? NULL : text, rows, cols);
+
+ return (output);
+}
+
+int rangebox_builder(BUILDER_ARGS)
+{
+ int output, min, max, value;
+
+ if (argc < 2)
+ return (BSDDIALOG_ERROR);
+
+ min = atoi(argv[0]);
+ max = atoi(argv[1]);
+
+ if (argc > 2) {
+ value = atoi(argv[2]);
+ value = value < min ? min : value;
+ value = value > max ? max : value;
+ }
+ else
+ value = min;
+
+ output = bsddialog_rangebox(conf, text, rows, cols, min, max, &value);
+
+ dprintf(output_fd_flag, "%d", value);
+
+ return (output);
+}
+
+int tailbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_tailbox(conf, text, rows, cols);
+
+ return (output);
+}
+
+int tailboxbg_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_tailboxbg(conf, text, rows, cols);
+
+ return output;
+}
+
+int textbox_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_textbox(conf, text, rows, cols);
+
+ return output;
+}
+
+int timebox_builder(BUILDER_ARGS)
+{
+ int output;
+ unsigned int hh, mm, ss;
+ time_t clock;
+ struct tm *localtm;
+ char stringtime[1024];
+
+ time(&clock);
+ localtm = localtime(&clock);
+ hh = localtm->tm_hour;
+ mm = localtm->tm_min;
+ ss = localtm->tm_sec;
+
+ /* --timebox text h w [hour minute second] */
+ if (argc == 3) {
+ hh = atoi(argv[0]);
+ hh = hh > 23 ? 23 : hh;
+ mm = atoi(argv[1]);
+ mm = mm > 60 ? 60 : mm;
+ ss = atoi(argv[2]);
+ ss = ss > 60 ? 60 : ss;
+ }
+
+ output = bsddialog_timebox(conf, text, rows, cols, &hh, &mm, &ss);
+ if (output != BSDDIALOG_YESOK)
+ return output;
+
+ if (time_fmt_flag == NULL) {
+ dprintf(output_fd_flag, "%u:%u:%u", hh, mm, ss);
+ }
+ else {
+ time(&clock);
+ localtm = localtime(&clock);
+ localtm->tm_hour = hh;
+ localtm->tm_min = mm;
+ localtm->tm_sec = ss;
+ strftime(stringtime, 1024, time_fmt_flag, localtm);
+ dprintf(output_fd_flag, "%s", stringtime);
+ }
+
+ return (output);
+}
+
+int yesno_builder(BUILDER_ARGS)
+{
+ int output;
+
+ output = bsddialog_yesno(conf, text, rows, cols);
+
+ return output;
+}
+
+/* MENU */
+static int
+get_menu_items(int argc, char **argv, bool setprefix, bool setdepth,
+ bool setname, bool setdesc, bool setstatus, bool sethelp, int *nitems,
+ struct bsddialog_menuitem *items)
+{
+ int i, j, sizeitem;
+
+ sizeitem = 0;
+ if (setprefix) sizeitem++;
+ if (setdepth) sizeitem++;
+ if (setname) sizeitem++;
+ if (setdesc) sizeitem++;
+ if (setstatus) sizeitem++;
+ if (sethelp) sizeitem++;
+ if ((argc % sizeitem) != 0) {
+ printf("Error: Menu/Checklist/Treeview/Radiolist bad #args\n");
+ return (BSDDIALOG_ERROR);
+ }
+
+ *nitems = argc / sizeitem;
+ j = 0;
+ for (i=0; i<*nitems; i++) {
+ items[i].prefix = setprefix ? argv[j++] : nostring;
+ items[i].depth = setdepth ? atoi(argv[j++]) : 0;
+ items[i].name = setname ? argv[j++] : nostring;
+ items[i].desc = setdesc ? argv[j++] : nostring;
+ if (setstatus)
+ items[i].on = strcmp(argv[j++], "on") == 0 ? true : false;
+ else
+ items[i].on = false;
+ items[i].bottomdesc = sethelp ? argv[j++] : nostring;
+ }
+
+ return (BSDDIALOG_YESOK);
+}
+
+static void
+print_selected_items(struct bsddialog_conf conf, int output, int nitems,
+ struct bsddialog_menuitem *items, int focusitem)
+{
+ int i;
+ bool sep, toquote;
+ char *sepstr, quotech, *helpvalue;
+
+ sep = false;
+ quotech = item_singlequote_flag ? '\'' : '"';
+ sepstr = item_output_sep_flag != NULL ? item_output_sep_flag : " ";
+
+ if (output == BSDDIALOG_HELP && focusitem >= 0) {
+ dprintf(output_fd_flag, "HELP ");
+
+ helpvalue = items[focusitem].name;
+ if (item_bottomdesc_flag && item_tag_help_flag == false)
+ helpvalue = items[focusitem].bottomdesc;
+
+ toquote = item_always_quote_flag || strchr(helpvalue, ' ') != NULL;
+
+ if (toquote)
+ dprintf(output_fd_flag, "%c", quotech);
+ dprintf(output_fd_flag, "%s", helpvalue);
+ if (toquote)
+ dprintf(output_fd_flag, "%c", quotech);
+
+ if (list_items_on_flag == false)
+ return;
+
+ sep = true;
+ }
+
+ if (output != BSDDIALOG_YESOK && list_items_on_flag == false)
+ return;
+
+ for (i = 0; i < nitems; i++) {
+ if (items[i].on == false)
+ continue;
+
+ if (sep == true) {
+ dprintf(output_fd_flag, "%s", sepstr);
+ if (item_output_sepnl_flag)
+ dprintf(output_fd_flag, "\n");
+ }
+ sep = true;
+
+ toquote = item_always_quote_flag || strchr(items[i].name, ' ') != NULL;
+
+ if (toquote)
+ dprintf(output_fd_flag, "%c", quotech);
+ dprintf(output_fd_flag, "%s", items[i].name);
+ if (toquote)
+ dprintf(output_fd_flag, "%c", quotech);
+ }
+}
+
+int buildlist_builder(BUILDER_ARGS)
+{
+ int output, menurows, nitems, focusitem;
+ struct bsddialog_menuitem items[100];
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ menurows = atoi(argv[0]);
+
+ output = get_menu_items(argc-1, argv+1, item_prefix_flag, false, true,
+ true, true, item_bottomdesc_flag, &nitems, items);
+ if (output != 0)
+ return (output);
+
+ output = bsddialog_buildlist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+ if (output == BSDDIALOG_ERROR)
+ return (BSDDIALOG_ERROR);
+
+ print_selected_items(conf, output, nitems, items, focusitem);
+
+ return output;
+}
+
+int checklist_builder(BUILDER_ARGS)
+{
+ int output, menurows, nitems, focusitem;
+ struct bsddialog_menuitem items[100];
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ menurows = atoi(argv[0]);
+
+ output = get_menu_items(argc-1, argv+1, item_prefix_flag, false, true,
+ true, true, item_bottomdesc_flag, &nitems, items);
+ if (output != 0)
+ return output;
+
+ output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_selected_items(conf, output, nitems, items, focusitem);
+
+ return output;
+}
+
+int menu_builder(BUILDER_ARGS)
+{
+ int output, menurows, nitems, focusitem;
+ struct bsddialog_menuitem items[100];
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ menurows = atoi(argv[0]);
+
+ output = get_menu_items(argc-1, argv+1, item_prefix_flag, false, true,
+ true, false, item_bottomdesc_flag, &nitems, items);
+ if (output != 0)
+ return output;
+
+ output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_selected_items(conf, output, nitems, items, focusitem);
+
+ return output;
+}
+
+int radiolist_builder(BUILDER_ARGS)
+{
+ int output, menurows, nitems, focusitem;
+ struct bsddialog_menuitem items[100];
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ menurows = atoi(argv[0]);
+
+ output = get_menu_items(argc-1, argv+1, item_prefix_flag, false, true,
+ true, true, item_bottomdesc_flag, &nitems, items);
+ if (output != 0)
+ return output;
+
+ output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_selected_items(conf, output, nitems, items, focusitem);
+
+ return output;
+}
+
+int treeview_builder(BUILDER_ARGS)
+{
+ int output, menurows, nitems, focusitem;
+ struct bsddialog_menuitem items[100];
+
+ if (argc < 1) {
+ usage();
+ return (BSDDIALOG_ERROR);
+ }
+
+ menurows = atoi(argv[0]);
+
+ output = get_menu_items(argc-1, argv+1, item_prefix_flag, true, true,
+ true, true, item_bottomdesc_flag, &nitems, items);
+ if (output != 0)
+ return output;
+
+ output = bsddialog_treeview(conf, text, rows, cols, menurows, nitems,
+ items, &focusitem);
+
+ print_selected_items(conf, output, nitems, items, focusitem);
+
+ return output;
+}
diff --git a/lib/GNUMakefile b/lib/GNUMakefile
new file mode 100644
index 000000000000..26dbdce9d4a0
--- /dev/null
+++ b/lib/GNUMakefile
@@ -0,0 +1,31 @@
+# PUBLIC DOMAIN - NO WARRANTY, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written by Alfonso Sabato Siciliano
+
+VERSION = 0.1
+LIBRARY = bsddialog
+LIBRARY_SO = lib${LIBRARY:=.so}
+HEADERS = bsddialog.h bsddialog_theme.h
+SOURCES = barbox.c editorbox.c formbox.c lib_util.c menubox.c textbox.c \
+ timebox.c commandbox.c filebox.c infobox.c libbsddialog.c messagebox.c \
+ theme.c
+OBJECTS = $(SOURCES:.c=.o)
+CFLAGS = -g -Wall -Werror -fpic
+LDFLAGS = -lform -lncurses -ltinfo
+LIBFLAG = -shared
+
+RM = rm -f
+LN = ln -s -f
+
+all : $(LIBRARY)
+
+$(LIBRARY): $(OBJECTS)
+ $(CC) $(LIBFLAG) $^ -o $(LIBRARY_SO).$(VERSION) $(LDFLAGS)
+ ${LN} ${LIBRARY_SO}.${VERSION} ${LIBRARY_SO}
+
+%.o: %.c $(HEADERS)
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ $(RM) $(LIBRARY_SO)* *.o *~
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 000000000000..74b6bc174a38
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,73 @@
+# Any copyright is dedicated to the Public Domain, see:
+# <http://creativecommons.org/publicdomain/zero/1.0/>
+#
+# Written by Alfonso Sabato Siciliano
+
+VERSION = 0.1
+LIBRARY = bsddialog
+LIBRARY_SO = lib${LIBRARY:=.so}
+HEADERS = bsddialog.h bsddialog_theme.h
+SOURCES = barbox.c editorbox.c formbox.c lib_util.c menubox.c textbox.c \
+ timebox.c commandbox.c filebox.c infobox.c libbsddialog.c messagebox.c \
+ theme.c
+OBJECTS= ${SOURCES:.c=.o}
+FBSDFLAGS= -O2 -pipe -std=gnu99 -Wno-format-zero-length \
+ -fstack-protector-strong -Qunused-arguments
+CFLAGS = -I/usr/local/include -fPIC -Wall -Wextra ${FBSDFLAGS}
+LDFLAGS = -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION}
+
+INSTALL_PREFIX=/usr/local
+LN = ln -s -f
+RM = rm -f
+CP = cp
+GZIP = gzip -cn
+LDCONFIG = /sbin/ldconfig -m
+
+.if defined(PORTNCURSES)
+# PORT ncurses `make -DPORTNCURSES` or `make -D PORTNCURSES`
+CFLAGS += -DPORTNCURSES -I/usr/local/include
+LDFLAGS += -L/usr/local/lib -lform -lncurses -ltinfo
+.else
+# BASE ncurses
+LDFLAGS += -L/usr/lib -lform -lncurses -ltinfo
+.endif
+
+MAN= ${OUTPUT}.3
+GZIP= gzip -cn
+MANDIR= /usr/local/share/man/man3
+
+INSTALL= install
+RM= rm -f
+
+#all : man ${LIBRARY}
+all : ${LIBRARY}
+
+${LIBRARY}: ${OBJECTS}
+ ${CC} ${LDFLAGS} ${.ALLSRC} -o ${LIBRARY_SO}.${VERSION}
+ # LN for devel
+ ${LN} ${LIBRARY_SO}.${VERSION} ${LIBRARY_SO}
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+man:
+ ${GZIP} ${LIBRARY}.3 > ${LIBRARY}.3.gz
+
+clean:
+ ${RM} ${LIBRARY_SO}* *.o *~ *.gz
+
+
+install:
+ ${CP} ${LIBRARY}.h ${INSTALL_PREFIX}/include
+ ${CP} ${LIBRARY_SO}.${VERSION} ${INSTALL_PREFIX}/lib/
+ ${LN} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}.${VERSION} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}
+ ${LDCONFIG} ${INSTALL_PREFIX}/lib
+ ${CP} ${LIBRARY}.3.gz ${INSTALL_PREFIX}/man/man3/
+
+unistall:
+ ${RM} ${INSTALL_PREFIX}/include/${LIBRARY}.h
+ ${RM} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}
+ ${RM} ${INSTALL_PREFIX}/lib/${LIBRARY_SO}.${VERSION}
+ ${LDCONFIG} ${INSTALL_PREFIX}/lib
+ ${RM} ${INSTALL_PREFIX}/man/man3/${LIBRARY}.3.gz
diff --git a/lib/barbox.c b/lib/barbox.c
new file mode 100644
index 000000000000..bb341605d6f5
--- /dev/null
+++ b/lib/barbox.c
@@ -0,0 +1,369 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Bar": gauge - mixedgauge - rangebox - pause */
+
+extern struct bsddialog_theme t;
+
+static void
+draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel, int label)
+{
+ char labelstr[128];
+ int i, blue_x, color;
+
+ blue_x = (int)((perc*(size))/100);
+
+ wmove(win, y, x);
+ for (i = 0; i < size; i++) {
+ color = (i <= blue_x) ? t.currbarcolor : t.barcolor;
+ wattron(win, color);
+ waddch(win, ' ');
+ wattroff(win, color);
+ }
+
+ if (withlabel)
+ sprintf(labelstr, "%d", label);
+ else
+ sprintf(labelstr, "%3d%%", perc);
+ wmove(win, y, x + size/2 - 2);
+ for (i=0; i < (int) strlen(labelstr); i++) {
+ color = ( (blue_x + 1) <= (size/2 - (int) strlen(labelstr)/2 + i) ) ?
+ t.barcolor : t.currbarcolor;
+ wattron(win, color);
+ waddch(win, labelstr[i]);
+ wattroff(win, color);
+ }
+}
+
+int bsddialog_gauge(struct bsddialog_conf conf, char* text, int rows, int cols, int perc)
+{
+ WINDOW *widget, *bar, *shadow;
+ char input[2048];
+ int i, y, x;
+ bool mainloop = true;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ false) <0)
+ return -1;
+
+ bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED);
+
+ wrefresh(widget);
+ wrefresh(bar);
+
+ while (mainloop) {
+ draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/);
+
+ wrefresh(widget);
+ wrefresh(bar);
+
+ while (true) {
+ scanf("%s", input);
+ if (strcmp(input,"EOF") == 0) {
+ mainloop = false;
+ break;
+ }
+ if (strcmp(input,"XXX") == 0)
+ break;
+ }
+ scanf("%d", &perc);
+ perc = perc < 0 ? 0 : perc;
+ perc = perc > 100 ? 100 : perc;
+ i = 2;
+ wmove(widget, 1, 1);
+ wclrtoeol(widget);
+ while (true) {
+ scanf("%s", input);
+ if (strcmp(input,"EOF") == 0) {
+ mainloop = false;
+ break;
+ }
+ if (strcmp(input,"XXX") == 0)
+ break;
+ //print_text(conf, widget, 1, 1, cols-2, input);
+ mvwaddstr(widget, 1, i, input);
+ i = i + strlen(input) + 1;
+ wrefresh(widget);
+ }
+ }
+
+ delwin(bar);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return BSDDIALOG_YESOK;
+}
+
+int bsddialog_mixedgauge(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int perc, int argc, char **argv)
+{
+ WINDOW *widget, *bar, *shadow;
+ int i, miniperc, y, x;
+ char states[11][16] = {
+ "[ Succeeded ]",
+ "[ Failed ]",
+ "[ Passed ]",
+ "[ Completed ]",
+ "[ Checked ]",
+ "[ Done ]",
+ "[ Skipped ]",
+ "[ In Progress ]",
+ "!!! BLANK !!!",
+ "[ N/A ]",
+ "[ UNKNOWN ]",};
+
+ if (new_widget(conf, &widget, &y, &x, NULL, &rows, &cols, &shadow,
+ false) <0)
+ return -1;
+
+ bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED);
+
+ /* mini bars */
+ for (i=0; i < (argc/2); i++) {
+ miniperc = atol(argv[i*2 + 1]);
+ if (miniperc == 8)
+ continue;
+ mvwaddstr(widget, i+1, 2, argv[i*2]);
+ if (miniperc > 9)
+ mvwaddstr(widget, i+1, cols-2-15, states[10]);
+ else if (miniperc >= 0 && miniperc <= 9)
+ mvwaddstr(widget, i+1, cols-2-15, states[miniperc]);
+ else { //miniperc < 0
+ miniperc = abs(miniperc);
+ mvwaddstr(widget, i+1, cols-2-15, "[ ]");
+ draw_perc_bar(widget, i+1, 1+cols-2-15, 13, miniperc,
+ false, -1 /*unused*/);
+ }
+ }
+
+ print_text(conf, widget, rows-6, 2, cols-2, text);
+
+ /* main bar */
+ draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/);
+
+ wattron(bar, t.barcolor);
+ mvwaddstr(bar, 0, 2, "Overall Progress");
+ wattroff(bar, t.barcolor);
+
+ wrefresh(widget);
+ wrefresh(bar);
+
+ getch();
+
+ delwin(bar);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return BSDDIALOG_YESOK;
+}
+
+int
+bsddialog_rangebox(struct bsddialog_conf conf, char* text, int rows, int cols, int min,
+ int max, int *value)
+{
+ WINDOW *widget, *bar, *shadow;
+ int y, x;
+ bool loop, buttupdate, barupdate;
+ int input, currvalue, output, sizebar;
+ float perc;
+ int positions = max - min + 1;
+ struct buttons bs;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ if (value == NULL)
+ RETURN_ERROR("*value == NULL");
+
+ currvalue = *value;
+ sizebar = cols - 16;
+ loop = buttupdate = barupdate = true;
+ while(loop) {
+ if (barupdate) {
+ perc = ((float)(currvalue - min)*100) / ((float)positions-1);
+ draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
+ barupdate = false;
+ wrefresh(bar);
+ }
+
+ if (buttupdate) {
+ draw_buttons(widget, rows-2, cols, bs, true);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+
+ input = getch();
+ switch(input) {
+ case 10: // Enter
+ output = bs.value[bs.curr]; // values -> outputs
+ *value = currvalue;
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': // TAB
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ buttupdate = true;
+ 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;
+ }
+ break;
+ case KEY_UP:
+ if (currvalue < max) {
+ currvalue++;
+ barupdate = true;
+ }
+ break;
+ case KEY_DOWN:
+ if (currvalue > min) {
+ currvalue--;
+ barupdate = true;
+ }
+ break;
+ }
+ }
+
+ delwin(bar);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
+
+int bsddialog_pause(struct bsddialog_conf conf, char* text, int rows, int cols, int sec)
+{
+ WINDOW *widget, *bar, *shadow;
+ int output, y, x;
+ bool loop, buttupdate, barupdate;
+ int input, currvalue, sizebar;
+ float perc;
+ struct buttons bs;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ currvalue = sec;
+ sizebar = cols-16;
+ nodelay(stdscr, TRUE);
+ timeout(1000);
+ //wtimeout(buttwin, 2);
+ loop = buttupdate = barupdate = true;
+ while(loop) {
+ if (barupdate) {
+ perc = ((float)(currvalue*100)) / ((float)sec);
+ draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
+ barupdate = false;
+ wrefresh(bar);
+ }
+
+ if (buttupdate) {
+ draw_buttons(widget, rows-2, cols, bs, true);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+
+ input = getch();
+ if(input < 0) {
+ currvalue--;
+ if (currvalue < 0) {
+ output = BSDDIALOG_ERROR;
+ break;
+ }
+ else {
+ barupdate = true;
+ continue;
+ }
+ }
+ switch(input) {
+ case 10: // Enter
+ output = bs.value[bs.curr]; // values -> outputs
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': // TAB
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ buttupdate = true;
+ 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;
+ }
+ break;
+ }
+ }
+
+ nodelay(stdscr, FALSE);
+
+ delwin(bar);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
+
diff --git a/lib/bsddialog.h b/lib/bsddialog.h
new file mode 100644
index 000000000000..e6c2cc67f581
--- /dev/null
+++ b/lib/bsddialog.h
@@ -0,0 +1,257 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSDDIALOG_H_
+#define _BSDDIALOG_H_
+
+#include <stdbool.h>
+
+/* Exit status */
+#define BSDDIALOG_ERROR -1
+#define BSDDIALOG_YESOK 0
+#define BSDDIALOG_NOCANCEL 1
+#define BSDDIALOG_HELP 2
+#define BSDDIALOG_EXTRA 3
+#define BSDDIALOG_ITEM_HELP 4
+#define BSDDIALOG_ESC 5
+
+/* size and position */
+#define BSDDIALOG_FULLSCREEN -1
+#define BSDDIALOG_AUTOSIZE 0
+#define BSDDIALOG_CENTER -1
+
+struct bsddialog_conf {
+ /* conf.* */
+ bool ascii_lines;
+ int aspect_ratio;
+ int x;
+ int y;
+ bool clear;
+ int *get_height;
+ int *get_width;
+ char *hfile;
+ char *hline;
+ /*int input_fd;*/
+ /*bool keep_tite;*/
+ /*bool keep_window;*/
+ /*bool last_key;*/
+ /*int max_input;*/
+ /*bool no_kill;*/
+ bool no_lines;
+ /*bool no_mouse; useful?*/
+ /*bool scrollbar; useful?*/
+ /*char *separate_witget;*/
+ bool shadow;
+ /*bool size_err;*/
+ int sleep;
+ /*int timeout;*/
+ char *title;
+ /* conf.text.* */
+ struct {
+ bool colors;
+ bool cr_wrap;
+ bool no_collapse;
+ bool no_nl_expand;
+ /*bool tab_correct; textbox?*/
+ /*int tab_len; textbox?*/
+ bool trim;
+ } text;
+ /* conf.form.* */
+ /*struct {
+ bool insecure;
+ } form;*/
+ /* conf.menu.* */
+ struct {
+ bool align_left;
+ char *colums_separator;
+ char *default_item; /*delete, add int *focus to API?*/
+ bool no_items;
+ bool no_tags;
+ /*bool visit_items;*/
+ } menu;
+ /* conf.button.* */
+ struct {
+ char *cancel_label;
+ bool defaultno;
+ char *default_label;
+ char *exit_label;
+ bool extra_button;
+ char *extra_label;
+ bool help_button;
+ char *help_label;
+ bool no_cancel;
+ char *no_label;
+ bool no_ok;
+ char *ok_label;
+ char *yes_label;
+ } button;
+};
+
+struct bsddialog_menuitem {
+ char *prefix;
+ bool on;
+ int depth;
+ char *name;
+ char *desc;
+ char *bottomdesc;
+};
+
+enum bsddialog_grouptype {
+ BSDDIALOG_CHECKLIST,
+ BSDDIALOG_RADIOLIST,
+ BSDDIALOG_SEPARATOR,
+};
+
+struct bsddialog_menugroup {
+ enum bsddialog_grouptype type;
+ unsigned int nitems;
+ struct bsddialog_menuitem *items;
+};
+
+int bsddialog_init(void);
+int bsddialog_end(void);
+int bsddialog_backtitle(struct bsddialog_conf conf, char *backtitle);
+const char *bsddialog_geterror(void);
+int bsddialog_terminalheight(void);
+int bsddialog_terminalwidth(void);
+void bsddialog_initconf(struct bsddialog_conf *conf);
+
+/* widgets */
+int
+bsddialog_buildlist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem);
+
+int
+bsddialog_calendar(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int *yy, unsigned int *mm, unsigned int *dd);
+
+int
+bsddialog_checklist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem);
+
+int
+bsddialog_dselect(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_editbox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int bsddialog_form(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int argc, char **argv);
+
+int
+bsddialog_fselect(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_gauge(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int perc);
+
+int
+bsddialog_infobox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_inputbox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_inputmenu(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_menu(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem);
+
+int
+bsddialog_mixedform(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int argc, char **argv);
+
+int
+bsddialog_mixedgauge(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int perc, int argc, char **argv);
+
+int
+bsddialog_mixedlist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int ngroups, struct bsddialog_menugroup *groups,
+ int *focuslist, int *focusitem);
+
+int
+bsddialog_msgbox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_passwordbox(struct bsddialog_conf conf, char* text, int rows,
+ int cols);
+
+int
+bsddialog_passwordform(struct bsddialog_conf conf, char* text, int rows,
+ int cols, int formheight, int argc, char **argv);
+
+int
+bsddialog_pause(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int sec);
+
+int
+bsddialog_prgbox(struct bsddialog_conf conf, char* text, int rows, int cols,
+ char *command);
+
+int
+bsddialog_programbox(struct bsddialog_conf conf, char* text, int rows,
+ int cols);
+
+int
+bsddialog_progressbox(struct bsddialog_conf conf, char* text, int rows,
+ int cols);
+
+int
+bsddialog_radiolist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem);
+
+int
+bsddialog_rangebox(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int min, int max, int *value);
+
+int
+bsddialog_tailbox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_tailboxbg(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_textbox(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+int
+bsddialog_timebox(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int *hh, unsigned int *mm, unsigned int *ss);
+
+int
+bsddialog_treeview(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem);
+
+int bsddialog_yesno(struct bsddialog_conf conf, char* text, int rows, int cols);
+
+#endif
diff --git a/lib/bsddialog_theme.h b/lib/bsddialog_theme.h
new file mode 100644
index 000000000000..b39b8840bce8
--- /dev/null
+++ b/lib/bsddialog_theme.h
@@ -0,0 +1,96 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBBSDDIALOG_THEME_H_
+#define _LIBBSDDIALOG_THEME_H_
+
+enum bsddialog_color {
+ BSDDIALOG_BLACK = 0,
+ BSDDIALOG_RED,
+ BSDDIALOG_GREEN,
+ BSDDIALOG_YELLOW,
+ BSDDIALOG_BLUE,
+ BSDDIALOG_MAGENTA,
+ BSDDIALOG_CYAN,
+ BSDDIALOG_WHITE,
+};
+
+struct bsddialog_theme {
+ int shadowcolor;
+ unsigned int shadowrows;
+ unsigned int shadowcols;
+
+ int backgroundcolor;
+ bool surroundtitle;
+ int titlecolor;
+ int lineraisecolor;
+ int linelowercolor;
+ int widgetcolor;
+
+ unsigned int texthmargin;
+
+ int curritemcolor;
+ int itemcolor;
+ int currtagcolor;
+ int tagcolor;
+ int namesepcolor;
+ int descsepcolor;
+
+ int currfieldcolor;
+ int fieldcolor;
+ int fieldreadonlycolor;
+
+ int currbarcolor;
+ int barcolor;
+
+ unsigned int buttonspace;
+ int buttleftch;
+ int buttrightchar;
+ int currbuttdelimcolor;
+ int buttdelimcolor;
+ int currbuttoncolor;
+ int buttoncolor;
+ int currshortkeycolor;
+ int shortkeycolor;
+
+ int bottomtitlecolor;
+};
+
+enum bsddialog_default_theme {
+ BSDDIALOG_THEME_BLACKWHITE,
+ BSDDIALOG_THEME_BSDDIALOG,
+ BSDDIALOG_THEME_DEFAULT,
+ BSDDIALOG_THEME_DIALOG,
+ BSDDIALOG_THEME_MAGENTA,
+};
+
+int bsddialog_color(enum bsddialog_color background, enum bsddialog_color foreground);
+struct bsddialog_theme bsddialog_get_theme();
+void bsddialog_set_theme(struct bsddialog_theme theme);
+int bsddialog_set_default_theme(enum bsddialog_default_theme theme);
+
+#endif
diff --git a/lib/commandbox.c b/lib/commandbox.c
new file mode 100644
index 000000000000..e5d65166e230
--- /dev/null
+++ b/lib/commandbox.c
@@ -0,0 +1,211 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Command": prgbox - programbox - progressbox */
+
+#define MAXINPUT 2048 /* in bsddialoh.h? in bsddialog.c get/set static maxinput? */
+
+extern struct bsddialog_theme t;
+
+static int
+command_handler(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey)
+{
+ bool loop, update;
+ int i, input;
+ int output;
+
+ loop = update = true;
+ while(loop) {
+ if (update) {
+ draw_buttons(window, y, cols, bs, shortkey);
+ update = false;
+ }
+ wrefresh(window);
+ input = getch();
+ switch (input) {
+ case 10: /* Enter */
+ output = bs.value[bs.curr];
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': /* TAB */
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ update = true;
+ break;
+ case KEY_LEFT:
+ if (bs.curr > 0) {
+ bs.curr--;
+ update = true;
+ }
+ break;
+ case KEY_RIGHT:
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ update = true;
+ }
+ break;
+ default:
+ if (shortkey) {
+ for (i = 0; i < (int) bs.nbuttons; i++)
+ if (input == (bs.label[i])[0]) {
+ output = bs.value[i];
+ loop = false;
+ }
+ }
+ }
+ }
+
+ return output;
+}
+
+int
+bsddialog_prgbox(struct bsddialog_conf conf, char* text, int rows, int cols, char *command)
+{
+ char line[MAXINPUT];
+ WINDOW *widget, *pad, *shadow;
+ int i, y, x, padrows, padcols, ys, ye, xs, xe;
+ int output;
+ int pipefd[2];
+ struct buttons bs;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ NULL, BUTTONLABEL(help_label));
+
+ if (text != NULL && conf.no_lines == false) {
+ print_text(conf, widget, 1, 1, cols-2, text);
+ mvwhline(widget, 2, 2, conf.ascii_lines ? '-' : ACS_HLINE, cols -4);
+ wrefresh(widget);
+ }
+
+ padrows = text == NULL ? rows - 4 : rows - 6;
+ padcols = cols - 2;
+ ys = text == NULL ? y + 1 : y + 3;
+ xs = x + 1;
+ ye = ys + padrows;
+ xe = xs + padcols;
+
+ pad = newpad(padrows, padcols);
+ wbkgd(pad, t.widgetcolor);
+
+ pipe(pipefd);
+ if (fork() == 0)
+ {
+ close(pipefd[0]); // close reading
+
+ dup2(pipefd[1], 1); // send stdout to the pipe
+ dup2(pipefd[1], 2); // send stderr to the pipe
+
+ close(pipefd[1]); // this descriptor is no longer needed
+
+ //const char *ls="/bin/ls";
+ execl(command, command, NULL);
+ return 0;
+ }
+ else
+ {
+ close(pipefd[1]); // close write
+
+ i = 0;
+ while (read(pipefd[0], line, MAXINPUT) != 0) {
+ mvwaddstr(pad, i, 0, line);
+ prefresh(pad, 0, 0, ys, xs, ye, xe);
+ i++;
+ }
+ }
+
+ output = command_handler(widget, rows-2, cols, bs, true);
+
+ return output;
+}
+
+int bsddialog_programbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ char line[MAXINPUT];
+ WINDOW *widget, *pad, *shadow;
+ int i, y, x, padrows, padcols, ys, ye, xs, xe, output;
+ struct buttons bs;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ if (text != NULL && conf.no_lines == false) {
+ mvwhline(widget, 2, 2, conf.ascii_lines ? '-' : ACS_HLINE, cols -4);
+ wrefresh(widget);
+ }
+
+ padrows = text == NULL ? rows - 4 : rows - 6;
+ padcols = cols - 2;
+ ys = text == NULL ? y + 1 : y + 3;
+ xs = x + 1;
+ ye = ys + padrows;
+ xe = xs + padcols;
+
+ pad = newpad(padrows, padcols);
+
+ i = 0;
+ //while (fgets(line, MAXINPUT, stdin) != NULL) {
+ while(getstr(line) != ERR){
+ mvwaddstr(pad, i, 0, line);
+ prefresh(pad, 0, 0, ys, xs, ye, xe);
+ i++;
+ }
+
+ output = command_handler(widget, rows-2, cols, bs, true);
+
+ return output;
+}
+
+int bsddialog_progressbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ text = "Progressbox unimplemented";
+ bsddialog_msgbox(conf, text, rows, cols);
+ RETURN_ERROR(text);
+}
+
diff --git a/lib/editorbox.c b/lib/editorbox.c
new file mode 100644
index 000000000000..b0f57908aa0e
--- /dev/null
+++ b/lib/editorbox.c
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+
+/* "Editor": editbox */
+
+int bsddialog_editbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ text = "Editbox unimplemented";
+ bsddialog_msgbox(conf, text, rows, cols);
+ RETURN_ERROR(text);
+}
+
diff --git a/lib/filebox.c b/lib/filebox.c
new file mode 100644
index 000000000000..b951f4e0d0f0
--- /dev/null
+++ b/lib/filebox.c
@@ -0,0 +1,52 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+
+/* "File": dselect - fselect */
+
+int bsddialog_dselect(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ text = "Dselect unimplemented";
+ bsddialog_msgbox(conf, text, rows, cols);
+ RETURN_ERROR(text);
+}
+
+int bsddialog_fselect(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ text = "Fselect unimplemented";
+ bsddialog_msgbox(conf, text, rows, cols);
+ RETURN_ERROR(text);
+}
+
diff --git a/lib/formbox.c b/lib/formbox.c
new file mode 100644
index 000000000000..f636db7990dd
--- /dev/null
+++ b/lib/formbox.c
@@ -0,0 +1,396 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#include <ncurses/form.h>
+#else
+#include <curses.h>
+#include <form.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Form": inputbox - passwordbox - form - passwordform - mixedform */
+
+extern struct bsddialog_theme t;
+
+int bsddialog_inputmenu(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ text = "Inputbox unimplemented";
+ bsddialog_msgbox(conf, text, rows, cols);
+ RETURN_ERROR(text);
+}
+
+#define ITEMHIDDEN 0x1
+#define ISITEMHIDDEN(item) (item.itemflags & 0x1)
+#define ITEMREADONLY 0x2
+#define ISITEMREADONLY(item) (item.itemflags & 0x2)
+struct formitem {
+ char *label;
+ unsigned int ylabel;
+ unsigned int xlabel;
+ char *item;
+ unsigned int yitem;
+ unsigned int xitem;
+ int itemlen;
+ unsigned int inputlen;
+ unsigned int itemflags;
+};
+
+static int
+mixedform_handler(WINDOW *widget, int y, int cols, struct buttons bs,
+ bool shortkey, WINDOW *entry, FORM *form, FIELD **field, int nitems
+ /*struct formitem *items*/)
+{
+ bool loop, buttupdate, inentry = true;
+ int input, output;
+
+ curs_set(2);
+ pos_form_cursor(form);
+ loop = buttupdate = true;
+ bs.curr = -1;
+ while(loop) {
+ if (buttupdate) {
+ draw_buttons(widget, y, cols, bs, shortkey);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+ wrefresh(entry);
+ input = getch();
+ switch(input) {
+ case 10: // Enter
+ if (inentry)
+ break;
+ output = bs.value[bs.curr]; // values -> buttvalues
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_PREV_FIELD);
+ /* add a struct for forms */
+ /*for (i=0; i<nitems; i++) {
+ bufp = field_buffer(field[i], 0);
+ dprintf(fd, "\n+%s", bufp);
+ bufp = field_buffer(field[i], 1);
+ dprintf(fd, "-%s+", bufp);
+ }*/
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': // TAB
+ if (inentry) {
+ bs.curr = 0;
+ inentry = false;
+ curs_set(0);
+ } else {
+ bs.curr++;
+ inentry = bs.curr >= (int) bs.nbuttons ? true : false;
+ if (inentry) {
+ curs_set(2);
+ pos_form_cursor(form);
+ }
+ }
+ buttupdate = true;
+ break;
+ case KEY_LEFT:
+ if (inentry) {
+ form_driver(form, REQ_PREV_CHAR);
+ } else {
+ if (bs.curr > 0) {
+ bs.curr--;
+ buttupdate = true;
+ }
+ }
+ break;
+ case KEY_RIGHT:
+ if (inentry) {
+ form_driver(form, REQ_NEXT_CHAR);
+ } else {
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ buttupdate = true;
+ }
+ }
+ break;
+ case KEY_UP:
+ if (nitems < 2)
+ break;
+ set_field_fore(current_field(form), t.fieldcolor);
+ set_field_back(current_field(form), t.fieldcolor);
+ form_driver(form, REQ_PREV_FIELD);
+ form_driver(form, REQ_END_LINE);
+ set_field_fore(current_field(form), t.currfieldcolor);
+ set_field_back(current_field(form), t.currfieldcolor);
+ break;
+ case KEY_DOWN:
+ if (nitems < 2)
+ break;
+ set_field_fore(current_field(form), t.fieldcolor);
+ set_field_back(current_field(form), t.fieldcolor);
+ form_driver(form, REQ_NEXT_FIELD);
+ form_driver(form, REQ_END_LINE);
+ set_field_fore(current_field(form), t.currfieldcolor);
+ set_field_back(current_field(form), t.currfieldcolor);
+ break;
+ case KEY_BACKSPACE:
+ form_driver(form, REQ_DEL_PREV);
+ break;
+ case KEY_DC:
+ form_driver(form, REQ_DEL_CHAR);
+ break;
+ default:
+ if (inentry) {
+ form_driver(form, input);
+ }
+ break;
+ }
+ }
+
+ curs_set(0);
+
+ return output;
+}
+
+static int
+do_mixedform(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int nitems, struct formitem *items)
+{
+ WINDOW *widget, *entry, *shadow;
+ int i, output, color, y, x;
+ FIELD **field;
+ FORM *form;
+ struct buttons bs;
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ entry = new_boxed_window(conf, y + rows - 3 - formheight -2, x +1,
+ formheight+2, cols-2, LOWERED);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ field = calloc(nitems + 1, sizeof(FIELD*));
+ for (i=0; i < nitems; i++) {
+ field[i] = new_field(1, items[i].itemlen, items[i].yitem-1, items[i].xitem-1, 0, 1);
+ field_opts_off(field[i], O_STATIC);
+ set_max_field(field[i], items[i].inputlen);
+ set_field_buffer(field[i], 0, items[i].item);
+ set_field_buffer(field[i], 1, items[i].item);
+ field_opts_off(field[i], O_AUTOSKIP);
+ field_opts_off(field[i], O_BLANK);
+ //field_opts_off(field[i], O_BS_OVERLOAD);
+
+ if (ISITEMHIDDEN(items[i]))
+ field_opts_off(field[i], O_PUBLIC);
+
+ if (ISITEMREADONLY(items[i])) {
+ field_opts_off(field[i], O_EDIT);
+ field_opts_off(field[i], O_ACTIVE);
+ color = t.fieldreadonlycolor;
+ } else {
+ color = i == 0 ? t.currfieldcolor : t.fieldcolor;
+ }
+ set_field_fore(field[i], color);
+ set_field_back(field[i], color);
+ }
+ field[i] = NULL;
+
+ if (nitems == 1) {// inputbox or passwordbox
+ set_field_fore(field[0], t.widgetcolor);
+ set_field_back(field[0], t.widgetcolor);
+ }
+
+ form = new_form(field);
+ set_form_win(form, entry);
+ set_form_sub(form, derwin(entry, nitems, cols-4, 1, 1));
+ post_form(form);
+
+ for (i=0; i < nitems; i++)
+ mvwaddstr(entry, items[i].ylabel, items[i].xlabel, items[i].label);
+
+ wrefresh(entry);
+
+ output = mixedform_handler(widget, rows-2, cols, bs, true, entry, form,
+ field, nitems /*,items*/);
+
+ unpost_form(form);
+ free_form(form);
+ for (i=0; i < nitems; i++)
+ free_field(field[i]);
+ free(field);
+
+ delwin(entry);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
+
+int bsddialog_inputbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ int output;
+ struct formitem item;
+
+ item.label = "";
+ item.ylabel = 0;
+ item.xlabel = 0;
+ item.item = ""; // TODO add argv
+ item.yitem = 1;
+ item.xitem = 1;
+ item.itemlen = cols-4;
+ item.inputlen = 2048; // todo conf.sizeinput
+ item.itemflags = 0;
+
+ output = do_mixedform(conf, text, rows, cols, 1, 1, &item);
+
+ return output;
+}
+
+int bsddialog_passwordbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ int output;
+ struct formitem item;
+
+ item.label = "";
+ item.ylabel = 0;
+ item.xlabel = 0;
+ item.item = ""; // TODO add argv
+ item.yitem = 1;
+ item.xitem = 1;
+ item.itemlen = cols-4;
+ item.inputlen = 2048; // todo conf.sizeinput
+ item.itemflags = ITEMHIDDEN;
+
+ output = do_mixedform(conf, text, rows, cols, 1, 1, &item);
+
+ return output;
+}
+
+int
+bsddialog_mixedform(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int argc, char **argv)
+{
+ int i, output, nitems;
+ struct formitem items[128];
+
+ if ((argc % 9) != 0)
+ return (-1);
+
+ nitems = argc / 9;
+ for (i=0; i<nitems; i++) {
+ items[i].label = argv[9*i];
+ items[i].ylabel = atoi(argv[9*i+1]);
+ items[i].xlabel = atoi(argv[9*i+2]);
+ items[i].item = argv[9*i+3];
+ items[i].yitem = atoi(argv[9*i+4]);
+ items[i].xitem = atoi(argv[9*i+5]);
+ items[i].itemlen = atoi(argv[9*i+6]);
+ items[i].inputlen = atoi(argv[9*i+7]);
+ items[i].itemflags = atoi(argv[9*i+8]);
+ }
+
+ output = do_mixedform(conf, text, rows, cols, formheight, nitems, items);
+
+ return output;
+}
+
+int
+bsddialog_form(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int argc, char **argv)
+{
+ int i, output, nitems, itemlen, inputlen;
+ unsigned int flags = 0;
+ struct formitem items[128];
+
+ if ((argc % 8) != 0)
+ return (-1);
+
+ nitems = argc / 8;
+ for (i=0; i<nitems; i++) {
+ items[i].label = argv[8*i];
+ items[i].ylabel = atoi(argv[8*i+1]);
+ items[i].xlabel = atoi(argv[8*i+2]);
+ items[i].item = argv[8*i+3];
+ items[i].yitem = atoi(argv[8*i+4]);
+ items[i].xitem = atoi(argv[8*i+5]);
+
+ itemlen = atoi(argv[8*i+6]);
+ items[i].itemlen = abs(itemlen);
+
+ inputlen = atoi(argv[8*i+7]);
+ items[i].inputlen = inputlen == 0 ? abs(itemlen) : inputlen;
+
+ flags = flags | (itemlen < 0 ? ITEMREADONLY : 0);
+ items[i].itemflags = flags;
+ }
+
+ output = do_mixedform(conf, text, rows, cols, formheight, nitems, items);
+
+ return output;
+}
+
+int
+bsddialog_passwordform(struct bsddialog_conf conf, char* text, int rows, int cols,
+ int formheight, int argc, char **argv)
+{
+ int i, output, nitems, itemlen, inputlen;
+ unsigned int flags = ITEMHIDDEN;
+ struct formitem items[128];
+
+ if ((argc % 8) != 0)
+ return (-1);
+
+ nitems = argc / 8;
+ for (i=0; i<nitems; i++) {
+ items[i].label = argv[8*i];
+ items[i].ylabel = atoi(argv[8*i+1]);
+ items[i].xlabel = atoi(argv[8*i+2]);
+ items[i].item = argv[8*i+3];
+ items[i].yitem = atoi(argv[8*i+4]);
+ items[i].xitem = atoi(argv[8*i+5]);
+
+ itemlen = atoi(argv[8*i+6]);
+ items[i].itemlen = abs(itemlen);
+
+ inputlen = atoi(argv[8*i+7]);
+ items[i].inputlen = inputlen == 0 ? abs(itemlen) : inputlen;
+
+ flags = flags | (itemlen < 0 ? ITEMREADONLY : 0);
+ items[i].itemflags = flags;
+ }
+
+ output = do_mixedform(conf, text, rows, cols, formheight, nitems, items);
+
+ return output;
+}
+
diff --git a/lib/infobox.c b/lib/infobox.c
new file mode 100644
index 000000000000..0d3eca86a258
--- /dev/null
+++ b/lib/infobox.c
@@ -0,0 +1,114 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Info": infobox */
+
+#define MIN_HEIGHT 3
+
+extern struct bsddialog_theme t;
+
+static int
+infobox_autosize(struct bsddialog_conf conf, int rows, int cols, int *h, int *w,
+ char *text)
+{
+ int maxword, maxline, nlines;
+
+ if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ /* text size */
+ *w = maxline + VBORDERS + t.texthmargin * 2;
+ /* avoid terminal overflow */
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = MIN_HEIGHT - 1;
+ if (maxword > 0)
+ *h += MIN(nlines, (*w / GET_ASPECT_RATIO(conf)));
+ *h = MAX(*h, MIN_HEIGHT);
+ /* avoid terminal overflow */
+ *h = MIN(*h, widget_max_height(conf));
+ }
+
+ return 0;
+}
+
+static int infobox_checksize(int rows, int cols)
+{
+
+ if (cols < HBORDERS + 1 + (int) t.texthmargin * 2)
+ RETURN_ERROR("Few cols, infobox needs at least width 3 + text "\
+ "margins");
+
+ if (rows < 3)
+ RETURN_ERROR("Infobox needs at least height 3");
+
+ return 0;
+}
+
+int
+bsddialog_infobox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ WINDOW *shadow, *widget, *textpad;
+ int y, x, h, w, htextpad;
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ if (infobox_autosize(conf, rows, cols, &h, &w, text) != 0)
+ return BSDDIALOG_ERROR;
+ if (infobox_checksize(h, w) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
+ &textpad, &htextpad, text, false) != 0)
+ return BSDDIALOG_ERROR;
+
+ pnoutrefresh(textpad, 0, 0, y+1, x+1+t.texthmargin, y+h-2, x+w-t.texthmargin);
+
+ doupdate();
+
+ end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+
+ return (BSDDIALOG_YESOK);
+}
+
diff --git a/lib/lib_util.c b/lib/lib_util.c
new file mode 100644
index 000000000000..a1cdac1169c4
--- /dev/null
+++ b/lib/lib_util.c
@@ -0,0 +1,996 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+extern struct bsddialog_theme t;
+
+/* Error buffer */
+
+#define ERRBUFLEN 1024
+static char errorbuffer[ERRBUFLEN];
+
+const char *get_error_string(void)
+{
+ return errorbuffer;
+}
+
+void set_error_string(char *str)
+{
+
+ strncpy(errorbuffer, str, ERRBUFLEN-1);
+}
+
+/* cleaner */
+int hide_widget(int y, int x, int h, int w, bool withshadow)
+{
+ WINDOW *clear;
+
+ /* no check: y, x, h and w are checked by the builders */
+ if ((clear = newwin(h, w, y + t.shadowrows, x + t.shadowcols)) == NULL)
+ RETURN_ERROR("Cannot hide the widget");
+ wbkgd(clear, t.backgroundcolor);
+
+ if (withshadow)
+ wrefresh(clear);
+
+ mvwin(clear, y, x);
+ wrefresh(clear);
+
+ delwin(clear);
+
+ return 0;
+}
+
+/* F1 help */
+int f1help(struct bsddialog_conf conf)
+{
+ char *file = conf.hfile;
+ char *title = conf.title;
+ int output;
+
+ conf.hfile = NULL;
+ conf.clear = true;
+ conf.y = BSDDIALOG_CENTER;
+ conf.x = BSDDIALOG_CENTER;
+ conf.title = "HELP";
+ conf.sleep = 0;
+
+ output = bsddialog_textbox(conf, file, BSDDIALOG_AUTOSIZE,
+ BSDDIALOG_AUTOSIZE);
+ conf.hfile = file;
+ conf.title = title;
+
+ return output;
+}
+
+/* Buttons */
+void
+draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
+ bool shortkey)
+{
+ int i, color_arrows, color_shortkey, color_button;
+
+ if (selected) {
+ color_arrows = t.currbuttdelimcolor;
+ color_shortkey = t.currshortkeycolor;
+ color_button = t.currbuttoncolor;
+ } else {
+ color_arrows = t.buttdelimcolor;
+ color_shortkey = t.shortkeycolor;
+ color_button = t.buttoncolor;
+ }
+
+ wattron(window, color_arrows);
+ mvwaddch(window, y, x, t.buttleftch);
+ wattroff(window, color_arrows);
+ wattron(window, color_button);
+ for(i = 1; i < size - 1; i++)
+ waddch(window, ' ');
+ wattroff(window, color_button);
+ wattron(window, color_arrows);
+ mvwaddch(window, y, x + i, t.buttrightchar);
+ wattroff(window, color_arrows);
+
+ x = x + 1 + ((size - 2 - strlen(text))/2);
+ wattron(window, color_button);
+ mvwaddstr(window, y, x, text);
+ wattroff(window, color_button);
+
+ if (shortkey) {
+ wattron(window, color_shortkey);
+ mvwaddch(window, y, x, text[0]);
+ wattroff(window, color_shortkey);
+ }
+}
+
+void
+draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey)
+{
+ int i, x, start_x;
+
+ start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.buttonspace;
+ start_x = cols/2 - start_x/2;
+
+ for (i = 0; i < (int) bs.nbuttons; i++) {
+ x = i * (bs.sizebutton + t.buttonspace);
+ draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i],
+ i == bs.curr, shortkey);
+ }
+}
+
+void
+get_buttons(struct bsddialog_conf conf, struct buttons *bs, char *yesoklabel,
+ char *extralabel, char *nocancellabel, char *helplabel)
+{
+ int i;
+#define SIZEBUTTON 8
+#define DEFAULT_BUTTON_LABEL LABEL_ok_label
+#define DEFAULT_BUTTON_VALUE BSDDIALOG_YESOK
+
+
+ bs->nbuttons = 0;
+ bs->curr = 0;
+ bs->sizebutton = 0;
+
+ if (yesoklabel != NULL && conf.button.no_ok == false) {
+ bs->label[0] = yesoklabel;
+ bs->value[0] = BSDDIALOG_YESOK;
+ bs->nbuttons += 1;
+ }
+
+ if (extralabel != NULL && conf.button.extra_button) {
+ bs->label[bs->nbuttons] = extralabel;
+ bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
+ bs->nbuttons += 1;
+ }
+
+ if (nocancellabel != NULL && conf.button.no_cancel == false) {
+ bs->label[bs->nbuttons] = nocancellabel;
+ bs->value[bs->nbuttons] = BSDDIALOG_NOCANCEL;
+ if (conf.button.defaultno)
+ bs->curr = bs->nbuttons;
+ bs->nbuttons += 1;
+ }
+
+ if (helplabel != NULL && conf.button.help_button) {
+ bs->label[bs->nbuttons] = helplabel;
+ bs->value[bs->nbuttons] = BSDDIALOG_HELP;
+ bs->nbuttons += 1;
+ }
+
+ if (bs->nbuttons == 0) {
+ bs->label[0] = DEFAULT_BUTTON_LABEL;
+ bs->value[0] = DEFAULT_BUTTON_VALUE;
+ 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;
+ }
+ }
+
+ bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
+ for (i=1; i < (int) bs->nbuttons; i++)
+ bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
+ bs->sizebutton += 2;
+}
+
+/* Text */
+
+// old text, to delete in the future
+enum token { TEXT, WS, END };
+
+static bool check_set_ncurses_attr(WINDOW *win, char *text)
+{
+ bool isattr;
+ int colors[8] = {
+ COLOR_BLACK,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW,
+ COLOR_BLUE,
+ COLOR_MAGENTA,
+ COLOR_CYAN,
+ COLOR_WHITE
+ };
+
+ if (text[0] == '\0' || text[0] != '\\')
+ return false;
+ if (text[1] == '\0' || text[1] != 'Z')
+ return false;
+ if (text[2] == '\0')
+ return false;
+
+ if ((text[2] - 48) >= 0 && (text[2] - 48) < 8) {
+ // tocheck: import BSD_COLOR
+ // tofix color background
+ wattron(win, COLOR_PAIR(colors[text[2] - 48] * 8 + COLOR_WHITE + 1));
+ return true;
+ }
+
+ isattr = true;
+ switch (text[2]) {
+ case 'n':
+ wattrset(win, A_NORMAL);
+ break;
+ case 'b':
+ wattron(win, A_BOLD);
+ break;
+ case 'B':
+ wattroff(win, A_BOLD);
+ break;
+ case 'r':
+ wattron(win, A_REVERSE);
+ break;
+ case 'R':
+ wattroff(win, A_REVERSE);
+ break;
+ case 'u':
+ wattron(win, A_UNDERLINE);
+ break;
+ case 'U':
+ wattroff(win, A_UNDERLINE);
+ break;
+ default:
+ isattr = false;
+ }
+
+ return isattr;
+}
+
+static bool isws(int ch)
+{
+
+ return (ch == ' ' || ch == '\t' || ch == '\n');
+}
+
+static int
+next_token(char *text, char *valuestr)
+{
+ int i, j;
+ enum token tok;
+
+ i = j = 0;
+
+ if (text[0] == '\0')
+ return END;
+
+ while (text[i] != '\0') {
+ if (isws(text[i])) {
+ if (i == 0) {
+ valuestr[0] = text[i];
+ valuestr[1] = '\0';
+ tok = WS;
+ }
+ break;
+ }
+
+ valuestr[j] = text[i];
+ j++;
+ valuestr[j] = '\0';
+ i++;
+ tok = TEXT;
+ }
+
+ return tok;
+}
+
+static void
+print_string(WINDOW *win, int *y, int *x, int minx, int maxx, char *str, bool color)
+{
+ int i, j, len, reallen;
+
+ if(strlen(str) == 0)
+ return;
+
+ len = reallen = strlen(str);
+ if (color) {
+ i=0;
+ while (i < len) {
+ if (check_set_ncurses_attr(win, str+i))
+ reallen -= 3;
+ i++;
+ }
+ }
+
+ i = 0;
+ while (i < len) {
+ if (*x + reallen > maxx) {
+ *y = (*x != minx ? *y+1 : *y);
+ *x = minx;
+ }
+ j = *x;
+ while (j < maxx && i < len) {
+ if (color && check_set_ncurses_attr(win, str+i)) {
+ i += 3;
+ } else {
+ mvwaddch(win, *y, j, str[i]);
+ i++;
+ reallen--;
+ j++;
+ *x = j;
+ }
+ }
+ }
+}
+
+void
+print_text(struct bsddialog_conf conf, WINDOW *pad, int starty, int minx, int maxx,
+ char *text)
+{
+ char *valuestr;
+ int x, y;
+ bool loop;
+ enum token tok;
+
+ valuestr = malloc(strlen(text) + 1);
+
+ x = minx;
+ y = starty;
+ loop = true;
+ while (loop) {
+ tok = next_token(text, valuestr);
+ switch (tok) {
+ case END:
+ loop = false;
+ break;
+ case WS:
+ text += strlen(valuestr);
+ print_string(pad, &y, &x, minx, maxx, valuestr, false /*useless*/);
+ break;
+ case TEXT:
+ text += strlen(valuestr);
+ print_string(pad, &y, &x, minx, maxx, valuestr, conf.text.colors);
+ break;
+ }
+ }
+
+ free(valuestr);
+}
+
+// new text funcs
+
+static bool is_ncurses_attr(char *text)
+{
+ bool isattr;
+
+ if (strnlen(text, 3) < 3)
+ return false;
+
+ if (text[0] != '\\' || text[1] != 'Z')
+ return false;
+
+ if ((text[2] - '0') >= 0 && (text[2] - '0') < 8)
+ return true;
+
+ isattr = text[2] == 'n' || text[2] == 'b' || text[2] == 'B' ||
+ text[2] == 'r' || text[2] == 'R' || text[2] == 'u' ||
+ text[2] == 'U';
+
+ return isattr;
+}
+
+static void
+print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color)
+{
+ int i, j, len, reallen;
+
+ if(strlen(str) == 0)
+ return;
+
+ len = reallen = strlen(str);
+ if (color) {
+ i=0;
+ while (i < len) {
+ if (is_ncurses_attr(str+i))
+ reallen -= 3;
+ i++;
+ }
+ }
+
+ i = 0;
+ while (i < len) {
+ if (*x + reallen > cols) {
+ *y = (*x != 0 ? *y+1 : *y);
+ if (*y >= *rows) {
+ *rows = *y + 1;
+ wresize(win, *rows, cols);
+ }
+ *x = 0;
+ }
+ j = *x;
+ while (j < cols && i < len) {
+ if (color && check_set_ncurses_attr(win, str+i)) {
+ i += 3;
+ } else {
+ mvwaddch(win, *y, j, str[i]);
+ i++;
+ reallen--;
+ j++;
+ *x = j;
+ }
+ }
+ }
+}
+
+static void prepare_text(struct bsddialog_conf conf, char *text, char *buf)
+{
+ int i, j;
+
+ i = j = 0;
+ while (text[i] != '\0') {
+ switch (text[i]) {
+ case '\\':
+ buf[j] = '\\';
+ switch (text[i+1]) {
+ case '\\':
+ i++;
+ break;
+ case 'n':
+ if (conf.text.no_nl_expand) {
+ j++;
+ buf[j] = 'n';
+ } else
+ buf[j] = '\n';
+ i++;
+ break;
+ case 't':
+ if (conf.text.no_collapse) {
+ j++;
+ buf[j] = 't';
+ } else
+ buf[j] = '\t';
+ i++;
+ break;
+ }
+ break;
+ case '\n':
+ buf[j] = conf.text.cr_wrap ? ' ' : '\n';
+ break;
+ case '\t':
+ buf[j] = conf.text.no_collapse ? '\t' : ' ';
+ break;
+ default:
+ buf[j] = text[i];
+ }
+ i++;
+ j += (buf[j] == ' ' && conf.text.trim && j > 0 && buf[j-1] == ' ') ?
+ 0 : 1;
+ }
+ buf[j] = '\0';
+}
+
+int
+get_text_properties(struct bsddialog_conf conf, char *text, int *maxword,
+ int *maxline, int *nlines)
+{
+ char *buf;
+ int i, buflen, wordlen, linelen;
+
+ if ((buf = malloc(strlen(text) + 1)) == NULL)
+ RETURN_ERROR("Cannot building a buffer to find the properties "\
+ "of the text properties");
+
+ prepare_text(conf, text, buf);
+
+ buflen = strlen(buf) + 1;
+ *maxword = 0;
+ wordlen = 0;
+ for (i=0; i < buflen; i++) {
+ if (buf[i] == '\t' || buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\0')
+ if (wordlen != 0) {
+ *maxword = MAX(*maxword, wordlen);
+ wordlen = 0;
+ continue;
+ }
+ if (conf.text.colors && is_ncurses_attr(buf + i))
+ i += 3;
+ else
+ wordlen++;
+ }
+
+ *maxline = linelen = 0;
+ *nlines = 1;
+ for (i=0; i < buflen; i++) {
+ switch (buf[i]) {
+ case '\n':
+ *nlines = *nlines + 1;
+ case '\0':
+ *maxline = MAX(*maxline, linelen);
+ linelen = 0;
+ break;
+ default:
+ if (conf.text.colors && is_ncurses_attr(buf + i))
+ i += 3;
+ else
+ linelen++;
+ }
+ }
+ if (*nlines == 1 && *maxline == 0)
+ *nlines = 0;
+
+ free(buf);
+
+ return 0;
+}
+
+static int
+print_textpad(struct bsddialog_conf conf, WINDOW *pad, int *rows, int cols, char *text)
+{
+ char *buf, *string;
+ int i, j, x, y;
+ bool loop;
+
+ if ((buf = malloc(strlen(text) + 1)) == NULL)
+ RETURN_ERROR("Cannot build (analyze) text");
+
+ prepare_text(conf, text, buf);
+
+ if ((string = malloc(strlen(text) + 1)) == NULL) {
+ free(buf);
+ RETURN_ERROR("Cannot build (analyze) text");
+ }
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = buf[i];
+
+ if (string[j] == '\0' || string[j] == '\n' ||
+ string[j] == '\t' || string[j] == ' ') {
+ if (j != 0) {
+ string[j] = '\0';
+ print_str(pad, rows, &y, &x, cols, string, conf.text.colors);
+ }
+ }
+
+ switch (buf[i]) {
+ case '\0':
+ loop = false;
+ break;
+ case '\n':
+ j = -1;
+ x = 0;
+ y++;
+ break;
+ case '\t':
+ for (j=0; j<4 /*tablen*/; j++) {
+ x++;
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ }
+ j = -1;
+ break;
+ case ' ':
+ x++;
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ j = -1;
+ }
+
+ if (y >= *rows) { /* check for whitespaces */
+ *rows = y + 1;
+ wresize(pad, *rows, cols);
+ }
+
+ j++;
+ i++;
+ }
+
+ free(string);
+ free(buf);
+
+ return 0;
+}
+
+/* autosize */
+
+/*
+ * max y, that is from 0 to LINES - 1 - t.shadowrows,
+ * could not be max height but avoids problems with checksize
+ */
+int widget_max_height(struct bsddialog_conf conf)
+{
+ int maxheight;
+
+ if ((maxheight = conf.shadow ? LINES - 1 - t.shadowrows : LINES - 1) <= 0)
+ RETURN_ERROR("Terminal too small, LINES - shadow <= 0");
+
+ if (conf.y > 0)
+ if ((maxheight -= conf.y) <=0)
+ RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0");
+
+ return maxheight;
+}
+
+/*
+ * max x, that is from 0 to COLS - 1 - t.shadowcols,
+ * * could not be max height but avoids problems with checksize
+ */
+int widget_max_width(struct bsddialog_conf conf)
+{
+ int maxwidth;
+
+ if ((maxwidth = conf.shadow ? COLS - 1 - t.shadowcols : COLS - 1) <= 0)
+ RETURN_ERROR("Terminal too small, COLS - shadow <= 0");
+ if (conf.x > 0)
+ if ((maxwidth -= conf.x) <=0)
+ RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0");
+
+ return maxwidth;
+}
+
+int
+set_widget_size(struct bsddialog_conf conf, int rows, int cols, int *h, int *w)
+{
+ int maxheight, maxwidth;
+
+ if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
+ return BSDDIALOG_ERROR;
+
+ if (rows == BSDDIALOG_FULLSCREEN)
+ *h = maxheight;
+ else if (rows < BSDDIALOG_FULLSCREEN)
+ RETURN_ERROR("Negative (less than -1) height");
+ else if (rows > BSDDIALOG_AUTOSIZE) {
+ if ((*h = rows) > maxheight)
+ RETURN_ERROR("Height too big (> terminal height - "\
+ "shadow");
+ }
+ /* rows == AUTOSIZE: each widget has to set its size */
+
+ if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
+ return BSDDIALOG_ERROR;
+
+ if (cols == BSDDIALOG_FULLSCREEN)
+ *w = maxwidth;
+ else if (cols < BSDDIALOG_FULLSCREEN)
+ RETURN_ERROR("Negative (less than -1) width");
+ else if (cols > BSDDIALOG_AUTOSIZE) {
+ if ((*w = cols) > maxwidth)
+ RETURN_ERROR("Width too big (> terminal width - shadow)");
+ }
+ /* cols == AUTOSIZE: each widget has to set its size */
+
+ return 0;
+}
+
+int
+set_widget_position(struct bsddialog_conf conf, int *y, int *x, int h, int w)
+{
+
+ if (conf.y == BSDDIALOG_CENTER)
+ *y = LINES/2 - h/2;
+ else if (conf.y < BSDDIALOG_CENTER)
+ RETURN_ERROR("Negative begin y (less than -1)");
+ else if (conf.y >= LINES)
+ RETURN_ERROR("Begin Y under the terminal");
+ else
+ *y = conf.y;
+
+ if ((*y + h + (conf.shadow ? (int) t.shadowrows : 0)) > LINES)
+ RETURN_ERROR("The lower of the box under the terminal "\
+ "(begin Y + height (+ shadow) > terminal lines)");
+
+
+ if (conf.x == BSDDIALOG_CENTER)
+ *x = COLS/2 - w/2;
+ else if (conf.x < BSDDIALOG_CENTER)
+ RETURN_ERROR("Negative begin x (less than -1)");
+ else if (conf.x >= COLS)
+ RETURN_ERROR("Begin X over the right of the terminal");
+ else
+ *x = conf.x;
+
+ if ((*x + w + (conf.shadow ? (int) t.shadowcols : 0)) > COLS)
+ RETURN_ERROR("The right of the box over the terminal "\
+ "(begin X + width (+ shadow) > terminal cols)");
+
+ return 0;
+}
+
+/* Widgets builders */
+void
+draw_borders(struct bsddialog_conf conf, WINDOW *win, int rows, int cols,
+ enum elevation elev)
+{
+ int leftcolor, rightcolor;
+ int ls, rs, ts, bs, tl, tr, bl, br;
+ int ltee, rtee;
+
+ ls = rs = ACS_VLINE;
+ ts = bs = ACS_HLINE;
+ tl = ACS_ULCORNER;
+ tr = ACS_URCORNER;
+ bl = ACS_LLCORNER;
+ br = ACS_LRCORNER;
+ ltee = ACS_LTEE;
+ rtee = ACS_RTEE;
+
+ if (conf.no_lines == false) {
+ if (conf.ascii_lines) {
+ ls = rs = '|';
+ ts = bs = '-';
+ tl = tr = bl = br = ltee = rtee = '+';
+ }
+ leftcolor = elev == RAISED ? t.lineraisecolor : t.linelowercolor;
+ rightcolor = elev == RAISED ? t.linelowercolor : t.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);
+ wattroff(win, rightcolor);
+ }
+}
+
+WINDOW *
+new_boxed_window(struct bsddialog_conf conf, int y, int x, int rows, int cols,
+ enum elevation elev)
+{
+ WINDOW *win;
+
+ if ((win = newwin(rows, cols, y, x)) == NULL) {
+ set_error_string("Cannot build boxed window");
+ return NULL;
+ }
+
+ wbkgd(win, t.widgetcolor);
+
+ draw_borders(conf, win, rows, cols, elev);
+
+ return win;
+}
+
+/*
+ * `enum elevation elev` could be useless because it should be always RAISED,
+ * to check at the end.
+ */
+static int
+draw_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow,
+ WINDOW *widget, int h, int w, enum elevation elev,
+ WINDOW *textpad, int *htextpad, char *text, bool buttons)
+{
+ int ts, ltee, rtee;
+ int colorsurroundtitle;
+
+ ts = conf.ascii_lines ? '-' : ACS_HLINE;
+ ltee = conf.ascii_lines ? '+' : ACS_LTEE;
+ rtee = conf.ascii_lines ? '+' : ACS_RTEE;
+ colorsurroundtitle = elev == RAISED ? t.lineraisecolor : t.linelowercolor;
+
+ if (shadow != NULL)
+ wnoutrefresh(shadow);
+
+ // move / resize now or the caller?
+ draw_borders(conf, widget, h, w, elev);
+
+ if (conf.title != NULL) {
+ if (t.surroundtitle && conf.no_lines == false) {
+ wattron(widget, colorsurroundtitle);
+ mvwaddch(widget, 0, w/2 - strlen(conf.title)/2 - 1, rtee);
+ wattroff(widget, colorsurroundtitle);
+ }
+ wattron(widget, t.titlecolor);
+ mvwaddstr(widget, 0, w/2 - strlen(conf.title)/2, conf.title);
+ wattroff(widget, t.titlecolor);
+ if (t.surroundtitle && conf.no_lines == false) {
+ wattron(widget, colorsurroundtitle);
+ waddch(widget, ltee);
+ wattroff(widget, colorsurroundtitle);
+ }
+ }
+
+ if (conf.hline != NULL) {
+ wattron(widget, t.bottomtitlecolor);
+ wmove(widget, h - 1, w/2 - strlen(conf.hline)/2 - 1);
+ waddch(widget, '[');
+ waddstr(widget, conf.hline);
+ waddch(widget, ']');
+ wattroff(widget, t.bottomtitlecolor);
+ }
+
+ if (textpad == NULL && text != NULL) /* no pad, text null for textbox */
+ print_text(conf, widget, 1, 2, w-3, text);
+
+ if (buttons && conf.no_lines == false) {
+ wattron(widget, t.lineraisecolor);
+ mvwaddch(widget, h-3, 0, ltee);
+ mvwhline(widget, h-3, 1, ts, w-2);
+ wattroff(widget, t.lineraisecolor);
+
+ wattron(widget, t.linelowercolor);
+ mvwaddch(widget, h-3, w-1, rtee);
+ wattroff(widget, t.linelowercolor);
+ }
+
+ wnoutrefresh(widget);
+
+ if (textpad == NULL)
+ return 0; /* widget_init() ends */
+
+ if (text != NULL) /* programbox etc */
+ if (print_textpad(conf, textpad, htextpad,
+ w - HBORDERS - t.texthmargin * 2, text) !=0)
+ return BSDDIALOG_ERROR;
+
+ return 0;
+}
+
+/*
+ * `enum elevation elev` could be useless because it should be always RAISED,
+ * to check at the end.
+ */
+int
+update_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow,
+ WINDOW *widget, int h, int w, enum elevation elev,
+ WINDOW *textpad, int *htextpad, char *text, bool buttons)
+{
+ int error;
+
+ /* nothing for now */
+
+ error = draw_widget_withtextpad(conf, shadow, widget, h, w,
+ elev, textpad, htextpad, text, buttons);
+
+ return error;
+}
+
+/*
+ * `enum elevation elev` could be useless because it should be always RAISED,
+ * to check at the end.
+ */
+int
+new_widget_withtextpad(struct bsddialog_conf conf, WINDOW **shadow,
+ WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
+ WINDOW **textpad, int *htextpad, char *text, bool buttons)
+{
+ int error;
+
+ if (conf.shadow) {
+ *shadow = newwin(h, w, y + t.shadowrows, x + t.shadowcols);
+ if (*shadow == NULL)
+ RETURN_ERROR("Cannot build shadow");
+ wbkgd(*shadow, t.shadowcolor);
+ }
+
+ if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == NULL) {
+ if (conf.shadow)
+ delwin(*shadow);
+ return BSDDIALOG_ERROR;
+ }
+
+ if (textpad == NULL) { /* widget_init() */
+ error = draw_widget_withtextpad(conf, *shadow, *widget, h, w,
+ elev, NULL, NULL, text, buttons);
+ return error;
+ }
+
+ if (text != NULL) { /* programbox etc */
+ *htextpad = 1;
+ *textpad = newpad(*htextpad, w - HBORDERS - t.texthmargin * 2);
+ if (*textpad == NULL) {
+ delwin(*textpad);
+ if (conf.shadow)
+ delwin(*shadow);
+ RETURN_ERROR("Cannot build the pad window for text");
+ }
+ wbkgd(*textpad, t.widgetcolor);
+ }
+
+ error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev,
+ *textpad, htextpad, text, buttons);
+
+ return error;
+}
+
+int
+new_widget(struct bsddialog_conf conf, WINDOW **widget, int *y, int *x,
+ char *text, int *h, int *w, WINDOW **shadow, bool buttons)
+{
+
+ // to delete (each widget has to check its x,y,h,w)
+ if (*h <= 0)
+ ; /* todo */
+
+ if (*w <= 0)
+ ; /* todo */
+
+ *y = (conf.y < 0) ? (LINES/2 - *h/2) : conf.y;
+ *x = (conf.x < 0) ? (COLS/2 - *w/2) : conf.x;
+
+ if (new_widget_withtextpad(conf, shadow, widget, *y, *x, *h, *w, RAISED,
+ NULL, NULL, text, buttons) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (conf.shadow)
+ wrefresh(*shadow);
+
+ wrefresh(*widget);
+
+ return 0;
+}
+
+void
+end_widget_withtextpad(struct bsddialog_conf conf, WINDOW *window, int h, int w,
+ WINDOW *textpad, WINDOW *shadow)
+{
+ int y, x;
+
+ getbegyx(window, y, x); /* for clear, add y & x to args? */
+
+ if (conf.sleep > 0)
+ sleep(conf.sleep);
+
+ if (textpad != NULL)
+ delwin(textpad);
+
+ delwin(window);
+
+ if (conf.shadow)
+ delwin(shadow);
+
+ if (conf.clear)
+ hide_widget(y, x, h, w, shadow != NULL);
+
+ if (conf.get_height != NULL)
+ *conf.get_height = h;
+ if (conf.get_width != NULL)
+ *conf.get_width = w;
+}
+
+void
+end_widget(struct bsddialog_conf conf, WINDOW *window, int h, int w,
+ WINDOW *shadow)
+{
+
+ end_widget_withtextpad(conf, window, h, w, NULL, shadow);
+}
diff --git a/lib/lib_util.h b/lib/lib_util.h
new file mode 100644
index 000000000000..b6fe1dd86b59
--- /dev/null
+++ b/lib/lib_util.h
@@ -0,0 +1,146 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LIBBSDDIALOG_UTIL_H_
+#define _LIBBSDDIALOG_UTIL_H_
+
+/*
+ * Utils to implement widgets - Internal library API
+ */
+
+#define HBORDERS 2
+#define VBORDERS 2
+
+/* ncurses has not a Ctrl key macro */
+#define KEY_CTRL(x) ((x) & 0x1f)
+
+/* Set default aspect ratio to 9 */
+#define GET_ASPECT_RATIO(conf) (conf.aspect_ratio > 0 ? conf.aspect_ratio : 9)
+
+/* debug */
+#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
+ mvprintw(y, x, fmt, __VA_ARGS__); \
+ refresh(); \
+} while (0)
+
+/* error buffer */
+const char *get_error_string(void);
+void set_error_string(char *string);
+
+#define RETURN_ERROR(str) do { \
+ set_error_string(str); \
+ return BSDDIALOG_ERROR; \
+} while (0)
+
+/* Buttons */
+#define LABEL_cancel_label "Cancel"
+#define LABEL_exit_label "EXIT"
+#define LABEL_extra_label "Extra"
+#define LABEL_help_label "Help"
+#define LABEL_no_label "No"
+#define LABEL_ok_label "OK"
+#define LABEL_yes_label "Yes"
+#define BUTTONLABEL(l) (conf.button.l != NULL ? conf.button.l : LABEL_ ##l)
+
+#define MAXBUTTONS 4 /* yes|ok - extra - no|cancel - help */
+struct buttons {
+ unsigned int nbuttons;
+ char *label[MAXBUTTONS];
+ int value[MAXBUTTONS];
+ int curr;
+ unsigned int sizebutton; /* including left and right delimiters */
+};
+
+void
+get_buttons(struct bsddialog_conf conf, struct buttons *bs, char *yesoklabel,
+ char *extralabel, char *nocancellabel, char *helplabel);
+
+void
+draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
+ bool shortkey);
+
+void
+draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey);
+
+/* help window with F1 key */
+int f1help(struct bsddialog_conf conf);
+
+/* cleaner */
+int hide_widget(int y, int x, int h, int w, bool withshadow);
+
+/* (auto) size and (auto) position */
+int
+get_text_properties(struct bsddialog_conf conf, char *text, int *maxword,
+ int *maxline, int *nlines);
+
+int widget_max_height(struct bsddialog_conf conf);
+int widget_max_width(struct bsddialog_conf conf);
+
+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);
+
+/* widget builders */
+void
+print_text(struct bsddialog_conf conf, WINDOW *pad, int starty, int minx,
+ int maxx, char *text);
+
+enum elevation { RAISED, LOWERED };
+
+void
+draw_borders(struct bsddialog_conf conf, WINDOW *win, int rows, int cols,
+ enum elevation elev);
+
+WINDOW *
+new_boxed_window(struct bsddialog_conf conf, int y, int x, int rows, int cols,
+ enum elevation elev);
+
+int
+new_widget_withtextpad(struct bsddialog_conf conf, WINDOW **shadow,
+ WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
+ WINDOW **textpad, int *htextpad, char *text, bool buttons);
+
+int
+update_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow,
+ WINDOW *widget, int h, int w, enum elevation elev, WINDOW *textpad,
+ int *htextpad, char *text, bool buttons);
+
+void
+end_widget_withtextpad(struct bsddialog_conf conf, WINDOW *window, int h, int w,
+ WINDOW *textpad, WINDOW *shadow);
+
+int
+new_widget(struct bsddialog_conf conf, WINDOW **widget, int *y, int *x,
+ char *text, int *h, int *w, WINDOW **shadow, bool buttons);
+
+void
+end_widget(struct bsddialog_conf conf, WINDOW *window, int h, int w,
+ WINDOW *shadow);
+
+#endif
diff --git a/lib/libbsddialog.c b/lib/libbsddialog.c
new file mode 100644
index 000000000000..a5866f39bea9
--- /dev/null
+++ b/lib/libbsddialog.c
@@ -0,0 +1,142 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/*
+ * This file implements some public function not related to a specific widget.
+ * utils.h/c provides private functions to implement the library.
+ * theme.h/c is public API related to theme.
+ * Widgets implementation:
+ * infobox.c infobox
+ * messgebox.c msgbox - yesno
+ * menubox.c buildlist - checklist - menu - mixedlist - radiolist - treeview
+ * formbox.c inputbox - passwordbox - form - passwordform - mixedform
+ * editorbox.c editbox
+ * barbox.c gauge - mixedgauge - rangebox - pause
+ * timebox.c timebox - calendar
+ * commandbox.c prgbox - programbox - progressbox
+ * tailbox.c tailbox - tailboxbg - textbox
+ * filebox.c dselect - fselect
+ */
+
+extern struct bsddialog_theme t;
+
+int bsddialog_init(void)
+{
+ int i, j, c = 1, error = OK;
+
+ set_error_string("");
+
+ if(initscr() == NULL)
+ RETURN_ERROR("Cannot init ncurses (initscr)");
+
+ error += keypad(stdscr, TRUE);
+ nl();
+ error += cbreak();
+ error += noecho();
+ curs_set(0);
+ if(error != OK) {
+ bsddialog_end();
+ RETURN_ERROR("Cannot init ncurses (keypad and cursor)");
+ }
+
+ error += start_color();
+ for (i=0; i<8; i++)
+ for(j=0; j<8; j++) {
+ error += init_pair(c, i, j);
+ c++;
+ }
+ if(error != OK) {
+ bsddialog_end();
+ RETURN_ERROR("Cannot init ncurses (colors)");
+ }
+
+ if (bsddialog_set_default_theme(BSDDIALOG_THEME_DIALOG) != 0)
+ error = BSDDIALOG_ERROR;
+
+ return error;
+}
+
+int bsddialog_end(void)
+{
+
+ if (endwin() != OK)
+ RETURN_ERROR("Cannot end ncurses (endwin)");
+
+ return 0;
+}
+
+int bsddialog_backtitle(struct bsddialog_conf conf, char *backtitle)
+{
+
+ mvaddstr(0, 1, backtitle);
+ if (conf.no_lines != true)
+ mvhline(1, 1, conf.ascii_lines ? '-' : ACS_HLINE, COLS-2);
+
+ refresh();
+
+ return 0;
+}
+
+const char *bsddialog_geterror(void)
+{
+
+ return get_error_string();
+}
+
+int bsddialog_terminalheight(void)
+{
+
+ return LINES;
+}
+
+int bsddialog_terminalwidth(void)
+{
+
+ return COLS;
+}
+
+void bsddialog_initconf(struct bsddialog_conf *conf)
+{
+
+ memset(conf, 0, sizeof(struct bsddialog_conf));
+ conf->x = conf->y = BSDDIALOG_CENTER;
+ conf->shadow = true;
+}
diff --git a/lib/menubox.c b/lib/menubox.c
new file mode 100644
index 000000000000..523e41fdeb1b
--- /dev/null
+++ b/lib/menubox.c
@@ -0,0 +1,1015 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Menu": checklist - menu - mixedlist - radiolist - treeview - buildlist */
+
+#define DEPTHSPACE 4
+#define MIN_HEIGHT VBORDERS + 6 /* 2 buttons 1 text 3 menu */
+
+extern struct bsddialog_theme t;
+
+enum menumode {
+ BUILDLISTMODE,
+ CHECKLISTMODE,
+ MENUMODE,
+ MIXEDLISTMODE,
+ RADIOLISTMODE,
+ 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;
+};
+
+static int checkradiolist(int nitems, struct bsddialog_menuitem *items)
+{
+ int i, error;
+
+ error = 0;
+ for (i=0; i<nitems; i++) {
+ if (error > 0)
+ items[i].on = false;
+
+ if (items[i].on == true)
+ error++;
+ }
+
+ return (error == 0 ? 0 : -1);
+}
+
+static int checkmenu(int nitems, struct bsddialog_menuitem *items) // useful?
+{
+ int i, error;
+
+ error = 0;
+ for (i=0; i<nitems; i++) {
+ if (items[i].on == true)
+ error++;
+
+ items[i].on = false;
+ }
+
+ return (error == 0 ? 0 : -1);
+}
+
+static void
+getfirst(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
+ int *rel)
+{
+ int i, a;
+
+ *abs = *rel = *group = -1;
+ a = 0;
+ for (i=0; i<ngroups; i++) {
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ a += groups[i].nitems;
+ continue;
+ }
+ if (groups[i].nitems != 0) {
+ *group = i;
+ *abs = a;
+ *rel = 0;
+ break;
+ }
+ }
+}
+
+static void
+getfirst_with_default(struct bsddialog_conf conf, int ngroups,
+ struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
+{
+ int i, j, a;
+ struct bsddialog_menuitem *item;
+
+ getfirst(ngroups, groups, abs, group, rel);
+ if (*abs < 0)
+ return;
+
+ a = *abs;
+
+ for (i=*group; i<ngroups; i++) {
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ a += groups[i].nitems;
+ continue;
+ }
+ for (j = 0; j < (int) groups[i].nitems; j++) {
+ item = &groups[i].items[j];
+ if (conf.menu.default_item != NULL && item->name != NULL) {
+ if (strcmp(item->name, conf.menu.default_item) == 0) {
+ *abs = a;
+ *group = i;
+ *rel = j;
+ return;
+ }
+ }
+ a++;
+ }
+ }
+}
+
+static void
+getlast(int totnitems, int ngroups, struct bsddialog_menugroup *groups,
+ int *abs, int *group, int *rel)
+{
+ int i, a;
+
+ a = totnitems - 1;
+ for (i = ngroups-1; i>=0; i--) {
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ a -= groups[i].nitems;
+ continue;
+ }
+ if (groups[i].nitems != 0) {
+ *group = i;
+ *abs = a;
+ *rel = groups[i].nitems - 1;
+ break;
+ }
+ }
+}
+
+static void
+getnext(int ngroups, struct bsddialog_menugroup *groups, int *abs, int *group,
+ int *rel)
+{
+ int i, a;
+
+ if (*abs < 0 || *group < 0 || *rel < 0)
+ return;
+
+ if (*rel + 1 < (int) groups[*group].nitems) {
+ *rel = *rel + 1;
+ *abs = *abs + 1;
+ return;
+ }
+
+ if (*group + 1 > ngroups)
+ return;
+
+ a = *abs;
+ for (i = *group + 1; i < ngroups; i++) {
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ a += groups[i].nitems;
+ continue;
+ }
+ if (groups[i].nitems != 0) {
+ *group = i;
+ *abs = a + 1;
+ *rel = 0;
+ break;
+ }
+ }
+}
+
+static void
+getfastnext(int menurows, int ngroups, struct bsddialog_menugroup *groups,
+ int *abs, int *group, int *rel)
+{
+ int a, start, i;
+
+ start = *abs;
+ i = menurows;
+ do {
+ a = *abs;
+ getnext(ngroups, groups, abs, group, rel);
+ i--;
+ } while (*abs != a && *abs < start + menurows && i > 0);
+}
+
+static void
+getprev(struct bsddialog_menugroup *groups, int *abs, int *group, int *rel)
+{
+ int i, a;
+
+ if (*abs < 0 || *group < 0 || *rel < 0)
+ return;
+
+ if (*rel > 0) {
+ *rel = *rel - 1;
+ *abs = *abs - 1;
+ return;
+ }
+
+ if (*group - 1 < 0)
+ return;
+
+ a = *abs;
+ for (i = *group - 1; i >= 0; i--) {
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ a -= (int) groups[i].nitems;
+ continue;
+ }
+ if (groups[i].nitems != 0) {
+ *group = i;
+ *abs = a - 1;
+ *rel = (int) groups[i].nitems - 1;
+ break;
+ }
+ }
+}
+
+static void
+getfastprev(int menurows, struct bsddialog_menugroup *groups, int *abs,
+ int *group, int *rel)
+{
+ int a, start, i;
+
+ start = *abs;
+ i = menurows;
+ do {
+ a = *abs;
+ getprev(groups, abs, group, rel);
+ i--;
+ } while (*abs != a && *abs > start - menurows && i > 0);
+}
+
+static enum menumode
+getmode(enum menumode mode, struct bsddialog_menugroup group)
+{
+
+ if (mode == MIXEDLISTMODE) {
+ if (group.type == BSDDIALOG_SEPARATOR)
+ mode = SEPARATORMODE;
+ else if (group.type == BSDDIALOG_RADIOLIST)
+ mode = RADIOLISTMODE;
+ else if (group.type == BSDDIALOG_CHECKLIST)
+ mode = CHECKLISTMODE;
+ }
+
+ return mode;
+}
+
+static void
+drawitem(struct bsddialog_conf conf, WINDOW *pad, int y,
+ struct bsddialog_menuitem item, enum menumode mode, struct lineposition pos,
+ bool curr)
+{
+ int color, colorname, linech;
+
+ color = curr ? t.curritemcolor : t.itemcolor;
+ colorname = curr ? t.currtagcolor : t.tagcolor;
+
+ if (mode == SEPARATORMODE) {
+ if (conf.no_lines == false) {
+ wattron(pad, t.itemcolor);
+ linech = conf.ascii_lines ? '-' : ACS_HLINE;
+ mvwhline(pad, y, 0, linech, pos.line);
+ wattroff(pad, t.itemcolor);
+ }
+ wmove(pad, y, pos.line/2 - (strlen(item.name)+strlen(item.desc))/2);
+ wattron(pad, t.namesepcolor);
+ waddstr(pad, item.name);
+ wattroff(pad, t.namesepcolor);
+ if (strlen(item.name) > 0 && strlen(item.desc) > 0)
+ waddch(pad, ' ');
+ wattron(pad, t.descsepcolor);
+ waddstr(pad, item.desc);
+ wattroff(pad, t.descsepcolor);
+ return;
+ }
+
+ /* prefix */
+ if (item.prefix != NULL && item.prefix[0] != '\0')
+ mvwaddstr(pad, y, 0, item.prefix);
+
+ /* selector */
+ wmove(pad, y, pos.xselector);
+ wattron(pad, color);
+ if (mode == CHECKLISTMODE)
+ wprintw(pad, "[%c]", item.on ? 'X' : ' ');
+ if (mode == RADIOLISTMODE)
+ wprintw(pad, "(%c)", item.on ? '*' : ' ');
+ wattroff(pad, color);
+
+ /* name */
+ if (mode != BUILDLISTMODE && conf.menu.no_tags == false) {
+ wattron(pad, colorname);
+ mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.name);
+ wattroff(pad, colorname);
+ }
+
+ /* description */
+ if (conf.menu.no_items == false) {
+ if ((mode == BUILDLISTMODE || conf.menu.no_tags) && curr == false)
+ color = item.on ? t.tagcolor : t.itemcolor;
+ wattron(pad, color);
+ if (conf.menu.no_tags)
+ mvwaddstr(pad, y, pos.xname + item.depth * DEPTHSPACE, item.desc);
+ else
+ mvwaddstr(pad, y, pos.xdesc, item.desc);
+ wattroff(pad, color);
+ }
+
+ /* bottom desc (item help) */
+ if (item.bottomdesc != NULL && item.bottomdesc[0] != '\0') {
+ move(LINES-1, 2);
+ clrtoeol();
+ addstr(item.bottomdesc);
+
+ refresh();
+ }
+}
+
+static void
+menu_autosize(struct bsddialog_conf conf, int rows, int cols, int *h, int *w,
+ char *text, int linelen, unsigned int *menurows, int nitems,
+ struct buttons bs)
+{
+ int textrow, menusize;
+
+ textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = VBORDERS;
+ /* buttons size */
+ *w += bs.nbuttons * bs.sizebutton;
+ *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.buttonspace : 0;
+ /* line size */
+ *w = MAX(*w, linelen + 6);
+ /*
+ * avoid terminal overflow,
+ * -1 fix false negative with big menu over the terminal and
+ * autosize, for example "portconfig /usr/ports/www/apache24/".
+ */
+ *w = MIN(*w, widget_max_width(conf)-1);
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = HBORDERS + 2 /* buttons */ + textrow;
+
+ if (*menurows == 0) {
+ *h += nitems + 2;
+ *h = MIN(*h, widget_max_height(conf));
+ menusize = MIN(nitems + 2, *h - (HBORDERS + 2 + textrow));
+ menusize -=2;
+ *menurows = menusize < 0 ? 0 : menusize;
+ }
+ else /* h autosize with a fixed menurows */
+ *h = *h + *menurows + 2;
+
+ /* avoid terminal overflow */
+ *h = MIN(*h, widget_max_height(conf));
+ }
+ else {
+ if (*menurows == 0)
+ *menurows = MIN(rows-6-textrow, nitems);
+ }
+}
+
+static int
+menu_checksize(int rows, int cols, char *text, int menurows, int nitems,
+ struct buttons bs)
+{
+ int mincols, textrow, menusize;
+
+ mincols = VBORDERS;
+ /* buttons */
+ mincols += bs.nbuttons * bs.sizebutton;
+ mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.buttonspace : 0;
+ /* line, comment to permet some cols hidden */
+ /* mincols = MAX(mincols, linelen); */
+
+ if (cols < mincols)
+ RETURN_ERROR("Few cols, width < size buttons or "\
+ "name+descripion of the items");
+
+ textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+
+ if (nitems > 0 && menurows == 0)
+ RETURN_ERROR("items > 0 but menurows == 0, probably terminal "\
+ "too small");
+
+ menusize = nitems > 0 ? 3 : 0;
+ if (rows < 2 + 2 + menusize + textrow)
+ RETURN_ERROR("Few lines for this menus");
+
+ return 0;
+}
+
+/* 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)
+{
+
+ if (totnitems > (int) menurows) {
+ draw_borders(conf, menuwin, h, w, LOWERED);
+
+ if (ymenupad > 0) {
+ wattron(menuwin, t.lineraisecolor);
+ mvwprintw(menuwin, 0, 2, "^^");
+ wattroff(menuwin, t.lineraisecolor);
+ }
+ if ((int) (ymenupad + menurows) < totnitems) {
+ wattron(menuwin, t.linelowercolor);
+ mvwprintw(menuwin, h-1, 2, "vv");
+ wattroff(menuwin, t.linelowercolor);
+ }
+
+ mvwprintw(menuwin, h-1, w-10, "%3d%%",
+ 100 * (ymenupad + menurows) / totnitems);
+ }
+}
+
+static int
+do_mixedlist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, enum menumode mode, int ngroups,
+ struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
+{
+ WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
+ int i, j, y, x, h, w, htextpad, output, input;
+ int ymenupad, ys, ye, xs, xe, abs, g, rel, totnitems;
+ bool loop, automenurows;
+ struct buttons bs;
+ struct bsddialog_menuitem *item;
+ enum menumode currmode;
+ struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ automenurows = menurows == BSDDIALOG_AUTOSIZE ? true : false;
+
+ totnitems = 0;
+ for (i=0; i < ngroups; i++) {
+ currmode = getmode(mode, groups[i]);
+ if (currmode == RADIOLISTMODE)
+ checkradiolist(groups[i].nitems, groups[i].items);
+
+ if (currmode == MENUMODE)
+ checkmenu(groups[i].nitems, groups[i].items);
+
+ if (currmode == RADIOLISTMODE || currmode == CHECKLISTMODE)
+ pos.selectorlen = 3;
+
+ for (j=0; j < (int) groups[i].nitems; j++) {
+ totnitems++;
+ item = &groups[i].items[j];
+
+ if (groups[i].type == BSDDIALOG_SEPARATOR) {
+ pos.maxsepstr = MAX(pos.maxsepstr,
+ strlen(item->name) + strlen(item->desc));
+ continue;
+ }
+
+ pos.maxprefix = MAX(pos.maxprefix, strlen(item->prefix));
+ pos.maxdepth = MAX((int) pos.maxdepth, item->depth);
+ pos.maxname = MAX(pos.maxname, strlen(item->name));
+ pos.maxdesc = MAX(pos.maxdesc, strlen(item->desc));
+ }
+ }
+ pos.maxname = conf.menu.no_tags ? 0 : pos.maxname;
+ pos.maxdesc = conf.menu.no_items ? 0 : pos.maxdesc;
+ pos.maxdepth *= DEPTHSPACE;
+
+ pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
+ pos.xname = pos.xselector + pos.selectorlen + (pos.selectorlen > 0 ? 1 : 0);
+ pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
+ pos.xdesc += (pos.maxname != 0 ? 1 : 0);
+ pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
+
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
+ totnitems, bs);
+ if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
+ &textpad, &htextpad, text, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ prefresh(textpad, 0, 0, y + 1, x + 1 + t.texthmargin,
+ y + h - menurows, x + 1 + w - t.texthmargin);
+
+ menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
+ menurows+2, w-4, LOWERED);
+
+ menupad = newpad(totnitems, pos.line);
+ wbkgd(menupad, t.widgetcolor);
+
+ getfirst_with_default(conf, ngroups, groups, &abs, &g, &rel);
+ ymenupad = 0;
+ for (i=0; i<ngroups; i++) {
+ currmode = getmode(mode, groups[i]);
+ for (j=0; j < (int) groups[i].nitems; j++) {
+ item = &groups[i].items[j];
+ drawitem(conf, menupad, ymenupad, *item, currmode,
+ pos, ymenupad == abs);
+ ymenupad++;
+ }
+ }
+
+ 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; /* now ymenupad is pminrow for prefresh() */
+ if ((int)(ymenupad + menurows) - 1 < abs)
+ ymenupad = abs - menurows + 1;
+ update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows, ymenupad);
+ wrefresh(menuwin);
+ prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+
+ draw_buttons(widget, h-2, w, bs, true);
+ wrefresh(widget);
+
+ item = &groups[g].items[rel];
+ currmode = getmode(mode, groups[g]);
+ loop = true;
+ while(loop) {
+ input = getch();
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ output = bs.value[bs.curr];
+ if (currmode == MENUMODE)
+ item->on = true;
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': /* TAB */
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ draw_buttons(widget, h-2, w, bs, true);
+ wrefresh(widget);
+ break;
+ case KEY_LEFT:
+ if (bs.curr > 0) {
+ bs.curr--;
+ draw_buttons(widget, h-2, w, bs, true);
+ wrefresh(widget);
+ }
+ break;
+ case KEY_RIGHT:
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ draw_buttons(widget, h-2, w, bs, true);
+ wrefresh(widget);
+ }
+ break;
+ case KEY_CTRL('E'): /* add conf.menu.extrahelpkey ? */
+ case KEY_F(1):
+ if (conf.hfile == NULL)
+ break;
+ if (f1help(conf) != 0)
+ return BSDDIALOG_ERROR;
+ /* No break! the terminal size can change */
+ case KEY_RESIZE:
+ hide_widget(y, x, h, w,conf.shadow);
+
+ /*
+ * Unnecessary, but, when the columns decrease the
+ * following "refresh" seem not work
+ */
+ refresh();
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ menurows = automenurows ? 0 : menurows;
+ menu_autosize(conf, rows, cols, &h, &w, text, pos.line,
+ &menurows, totnitems, bs);
+ if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ wclear(shadow);
+ mvwin(shadow, y + t.shadowrows, x + t.shadowcols);
+ wresize(shadow, h, w);
+
+ wclear(widget);
+ mvwin(widget, y, x);
+ wresize(widget, h, w);
+
+ htextpad = 1;
+ wclear(textpad);
+ wresize(textpad, 1, w - HBORDERS - t.texthmargin * 2);
+
+ if(update_widget_withtextpad(conf, shadow, widget, h, w,
+ RAISED, textpad, &htextpad, text, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ draw_buttons(widget, h-2, w, bs, true);
+ wrefresh(widget);
+
+ prefresh(textpad, 0, 0, y + 1, x + 1 + t.texthmargin,
+ y + h - menurows, x + 1 + w - t.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;
+ }
+
+ if ((int)(ymenupad + menurows) - 1 < abs)
+ ymenupad = abs - menurows + 1;
+ prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+
+ refresh();
+
+ break;
+ default:
+ for (i = 0; i < (int) bs.nbuttons; i++)
+ if (tolower(input) == tolower((bs.label[i])[0])) {
+ output = bs.value[i];
+ loop = false;
+ }
+
+ }
+
+ if (abs < 0)
+ continue;
+ switch(input) {
+ case KEY_HOME:
+ case KEY_UP:
+ case KEY_PPAGE:
+ if (abs == 0) /* useless, just to save cpu refresh */
+ break;
+ drawitem(conf, menupad, abs, *item, currmode, pos, false);
+ if (input == KEY_HOME)
+ getfirst(ngroups, groups, &abs, &g, &rel);
+ else if (input == KEY_UP)
+ getprev(groups, &abs, &g, &rel);
+ else /* input == KEY_PPAGE*/
+ getfastprev(menurows, groups, &abs, &g, &rel);
+ item = &groups[g].items[rel];
+ currmode= getmode(mode, groups[g]);
+ drawitem(conf, menupad, abs, *item, currmode, pos, true);
+ if (ymenupad > abs && ymenupad > 0)
+ ymenupad = abs;
+ update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
+ menurows, ymenupad);
+ wrefresh(menuwin);
+ prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ break;
+ case KEY_END:
+ case KEY_DOWN:
+ case KEY_NPAGE:
+ if (abs == totnitems -1)
+ break; /* useless, just to save cpu refresh */
+ drawitem(conf, menupad, abs, *item, currmode, pos, false);
+ if (input == KEY_END)
+ getlast(totnitems, ngroups, groups, &abs, &g, &rel);
+ else if (input == KEY_DOWN)
+ getnext(ngroups, groups, &abs, &g, &rel);
+ else /* input == KEY_NPAGE*/
+ getfastnext(menurows, ngroups, groups, &abs, &g, &rel);
+ item = &groups[g].items[rel];
+ currmode= getmode(mode, groups[g]);
+ drawitem(conf, menupad, abs, *item, currmode, pos, true);
+ if ((int)(ymenupad + menurows) <= abs)
+ ymenupad = abs - menurows + 1;
+ update_menuwin(conf, menuwin, menurows+2, w-4, totnitems,
+ menurows, ymenupad);
+ wrefresh(menuwin);
+ prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ break;
+ case ' ': /* Space */
+ if (currmode == MENUMODE)
+ break;
+ else if (currmode == CHECKLISTMODE)
+ item->on = !item->on;
+ else { /* RADIOLISTMODE */
+ if (item->on == true)
+ break;
+ for (i=0; i < (int) groups[g].nitems; i++)
+ if (groups[g].items[i].on == true) {
+ groups[g].items[i].on = false;
+ drawitem(conf, menupad,
+ abs - rel + i, groups[g].items[i],
+ currmode, pos, false);
+ }
+ item->on = true;
+ }
+ drawitem(conf, menupad, abs, *item, currmode, pos, true);
+ prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ }
+ }
+
+ if (focuslist != NULL)
+ *focuslist = g;
+ if (focusitem !=NULL)
+ *focusitem = rel;
+
+ delwin(menupad);
+ delwin(menuwin);
+ end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+
+ return output;
+}
+
+/*
+ * API
+ */
+
+int bsddialog_mixedlist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int ngroups, struct bsddialog_menugroup *groups,
+ int *focuslist, int *focusitem)
+{
+ int output;
+
+ output = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
+ ngroups, groups, focuslist, focusitem);
+
+ return output;
+}
+
+int
+bsddialog_checklist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem)
+{
+ int output;
+ struct bsddialog_menugroup group = {
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+
+ output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
+ 1, &group, NULL, focusitem);
+
+ return output;
+}
+
+int
+bsddialog_menu(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem)
+{
+ int output;
+ struct bsddialog_menugroup group = {
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items};
+
+ output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
+ &group, NULL, focusitem);
+
+ return output;
+}
+
+int
+bsddialog_radiolist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem)
+{
+ int output;
+ struct bsddialog_menugroup group = {
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items};
+
+ output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
+ 1, &group, NULL, focusitem);
+
+ return output;
+}
+
+int
+bsddialog_treeview(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem)
+{
+ int output;
+ struct bsddialog_menugroup group = {
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items};
+
+ conf.menu.no_tags = true;
+ conf.menu.align_left = true;
+
+ output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
+ 1, &group, NULL, focusitem);
+
+ return output;
+}
+
+int
+bsddialog_buildlist(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int menurows, int nitems, struct bsddialog_menuitem *items,
+ int *focusitem)
+{
+ WINDOW *widget, *leftwin, *leftpad, *rightwin, *rightpad, *shadow;
+ int output, i, x, y, input;
+ bool loop, buttupdate, padsupdate, startleft;
+ int nlefts, nrights, leftwinx, rightwinx, winsy, padscols, curr;
+ enum side {LEFT, RIGHT} currV;
+ int currH;
+ struct buttons bs;
+ struct lineposition pos = {0,0,0,0,0,0,0,0,0,0};
+
+ startleft = false;
+ for (i=0; i<nitems; i++) {
+ pos.line = MAX(pos.line, strlen(items[i].desc));
+ if (items[i].on == false)
+ startleft = true;
+ }
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ winsy = y + rows - 5 - menurows;
+ leftwinx = x+2;
+ leftwin = new_boxed_window(conf, winsy, leftwinx, menurows+2, (cols-5)/2,
+ LOWERED);
+ rightwinx = x + cols - 2 -(cols-5)/2;
+ rightwin = new_boxed_window(conf, winsy, rightwinx, menurows+2,
+ (cols-5)/2, LOWERED);
+
+ wrefresh(leftwin);
+ wrefresh(rightwin);
+
+ padscols = (cols-5)/2 - 2;
+ leftpad = newpad(nitems, pos.line);
+ rightpad = newpad(nitems, pos.line);
+ wbkgd(leftpad, t.widgetcolor);
+ wbkgd(rightpad, t.widgetcolor);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ currH = 0;
+ currV = startleft ? LEFT : RIGHT;
+ loop = buttupdate = padsupdate = true;
+ while(loop) {
+ if (buttupdate) {
+ draw_buttons(widget, rows-2, cols, bs, true);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+
+ if (padsupdate) {
+ werase(leftpad);
+ werase(rightpad);
+ curr = -1;
+ nlefts = nrights = 0;
+ for (i=0; i<nitems; i++) {
+ if (items[i].on == false) {
+ if (currV == LEFT && currH == nlefts)
+ curr = i;
+ drawitem(conf, leftpad, nlefts, items[i],
+ BUILDLISTMODE, pos, curr == i);
+ nlefts++;
+ } else {
+ if (currV == RIGHT && currH == nrights)
+ curr = i;
+ drawitem(conf, rightpad, nrights, items[i],
+ BUILDLISTMODE, pos, curr == i);
+ nrights++;
+ }
+ }
+ prefresh(leftpad, 0, 0, winsy+1, leftwinx+1,
+ winsy+1+menurows, leftwinx + 1 + padscols);
+ prefresh(rightpad, 0, 0, winsy+1, rightwinx+1,
+ winsy+1+menurows, rightwinx + 1 + padscols);
+ padsupdate = false;
+ }
+
+ input = getch();
+ switch(input) {
+ case 10: // Enter
+ output = bs.value[bs.curr]; // -> buttvalues[selbutton]
+ loop = false;
+ break;
+ case 27: // Esc
+ output = BSDDIALOG_ERROR;
+ loop = false;
+ break;
+ case '\t': // TAB
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ buttupdate = true;
+ break;
+ }
+
+ if (nitems <= 0)
+ continue;
+
+ switch(input) {
+ case KEY_LEFT:
+ if (currV == RIGHT && nrights > 0) {
+ currV = LEFT;
+ currH = 0;
+ padsupdate = true;
+ }
+ break;
+ case KEY_RIGHT:
+ if (currV == LEFT && nrights > 0) {
+ currV = RIGHT;
+ currH = 0;
+ padsupdate = true;
+ }
+ break;
+ case KEY_UP:
+ currH = (currH > 0) ? currH - 1 : 0;
+ padsupdate = true;
+ break;
+ case KEY_DOWN:
+ if (currV == LEFT)
+ currH = (currH < nlefts-1) ? currH +1 : currH;
+ else
+ currH = (currH < nrights-1)? currH +1 : currH;
+ padsupdate = true;
+ break;
+ case ' ': // Space
+ items[curr].on = ! items[curr].on;
+ if (currV == LEFT) {
+ if (nlefts > 1)
+ currH = currH > 0 ? currH-1 : 0;
+ else {
+ currH = 0;
+ currV = RIGHT;
+ }
+ } else {
+ if (nrights > 1)
+ currH = currH > 0 ? currH-1 : 0;
+ else {
+ currH = 0;
+ currV = LEFT;
+ }
+ }
+ padsupdate = true;
+ break;
+ default:
+
+ break;
+ }
+ }
+
+ if(focusitem != NULL)
+ *focusitem = curr;
+
+ delwin(leftpad);
+ delwin(leftwin);
+ delwin(rightpad);
+ delwin(rightwin);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
diff --git a/lib/messagebox.c b/lib/messagebox.c
new file mode 100644
index 000000000000..2920986b48a8
--- /dev/null
+++ b/lib/messagebox.c
@@ -0,0 +1,278 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Message": msgbox - yesno */
+
+#define AUTO_WIDTH (COLS / 3U)
+/*
+ * Min height = 5: 2 up & down borders + 2 label & up border buttons + 1 line
+ * for text, at least 1 line is important for widget_withtextpad_init() to avoid
+ * "Cannot build the pad window for text".
+ */
+#define MIN_HEIGHT 5
+
+extern struct bsddialog_theme t;
+
+static int
+message_autosize(struct bsddialog_conf conf, int rows, int cols, int *h, int *w,
+ char *text, struct buttons bs)
+{
+ int maxword, maxline, nlines, line;
+
+ if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = VBORDERS;
+ /* buttons size */
+ *w += bs.nbuttons * bs.sizebutton;
+ *w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.buttonspace : 0;
+ /* text size */
+ line = MIN(maxline + VBORDERS + t.texthmargin * 2, AUTO_WIDTH);
+ line = MAX(line, (int) (maxword + VBORDERS + t.texthmargin * 2));
+ *w = MAX(*w, line);
+ /* avoid terminal overflow */
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = MIN_HEIGHT - 1;
+ if (maxword > 0)
+ *h += MAX(nlines, (*w / GET_ASPECT_RATIO(conf)));
+ *h = MAX(*h, MIN_HEIGHT);
+ /* avoid terminal overflow */
+ *h = MIN(*h, widget_max_height(conf));
+ }
+
+ return 0;
+}
+
+static int message_checksize(int rows, int cols, struct buttons bs)
+{
+ int mincols;
+
+ mincols = VBORDERS;
+ mincols += bs.nbuttons * bs.sizebutton;
+ mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.buttonspace : 0;
+
+ if (cols < mincols)
+ RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "\
+ "for borders, buttons and spaces between buttons");
+
+ if (rows < MIN_HEIGHT)
+ RETURN_ERROR("Msgbox and Yesno need at least height 5");
+
+ return 0;
+}
+
+static void
+buttonsupdate(WINDOW *widget, int h, int w, struct buttons bs, bool shortkey)
+{
+ draw_buttons(widget, h-2, w, bs, shortkey);
+ wnoutrefresh(widget);
+}
+
+static void
+textupdate(WINDOW *widget, int y, int x, int h, int w, WINDOW *textpad,
+ int htextpad, int textrow)
+{
+
+ if (htextpad > h - 4) {
+ mvwprintw(widget, h-3, w-6, "%3d%%",
+ 100 * (textrow+h-4)/ htextpad);
+ wnoutrefresh(widget);
+ }
+
+ pnoutrefresh(textpad, textrow, 0, y+1, x+2, y+h-4, x+w-2);
+}
+
+static int
+do_widget(struct bsddialog_conf conf, char *text, int rows, int cols,
+ struct buttons bs, bool shortkey)
+{
+ WINDOW *widget, *textpad, *shadow;
+ bool loop;
+ int i, y, x, h, w, input, output, htextpad, textrow;
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (message_checksize(h, w, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
+ &textpad, &htextpad, text, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ textrow = 0;
+ loop = true;
+ buttonsupdate(widget, h, w, bs, shortkey);
+ textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+ while(loop) {
+ doupdate();
+ input = getch();
+ switch (input) {
+ case 10: /* Enter */
+ output = bs.value[bs.curr];
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': /* TAB */
+ bs.curr = (bs.curr + 1) % bs.nbuttons;
+ buttonsupdate(widget, h, w, bs, shortkey);
+ break;
+ case KEY_F(1):
+ if (conf.hfile == NULL)
+ break;
+ if (f1help(conf) != 0)
+ return BSDDIALOG_ERROR;
+ /* No break! the terminal size can change */
+ case KEY_RESIZE:
+ hide_widget(y, x, h, w,conf.shadow);
+
+ /*
+ * Unnecessary, but, when the columns decrease the
+ * following "refresh" seem not work
+ */
+ refresh();
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (message_checksize(h, w, bs) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ wclear(shadow);
+ mvwin(shadow, y + t.shadowrows, x + t.shadowcols);
+ wresize(shadow, h, w);
+
+ wclear(widget);
+ mvwin(widget, y, x);
+ wresize(widget, h, w);
+
+ htextpad = 1;
+ wclear(textpad);
+ wresize(textpad, 1, w - HBORDERS - t.texthmargin * 2);
+
+ if(update_widget_withtextpad(conf, shadow, widget, h, w,
+ RAISED, textpad, &htextpad, text, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ buttonsupdate(widget, h, w, bs, shortkey);
+ textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+
+ /* Important to fix grey lines expanding screen */
+ refresh();
+ break;
+ case KEY_UP:
+ if (textrow == 0)
+ break;
+ textrow--;
+ textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+ break;
+ case KEY_DOWN:
+ if (textrow + h - 4 >= htextpad)
+ break;
+ textrow++;
+ textupdate(widget, y, x, h, w, textpad, htextpad, textrow);
+ break;
+ case KEY_LEFT:
+ if (bs.curr > 0) {
+ bs.curr--;
+ buttonsupdate(widget, h, w, bs, shortkey);
+ }
+ break;
+ case KEY_RIGHT:
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ buttonsupdate(widget, h, w, bs, shortkey);
+ }
+ break;
+ default:
+ if (shortkey == false)
+ break;
+
+ for (i = 0; i < (int) bs.nbuttons; i++)
+ if (tolower(input) == tolower((bs.label[i])[0])) {
+ output = bs.value[i];
+ loop = false;
+ }
+ }
+ }
+
+ end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
+
+ return output;
+}
+
+/* API */
+
+int
+bsddialog_msgbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ struct buttons bs;
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ NULL /* nocancel */, BUTTONLABEL(help_label));
+
+ return (do_widget(conf, text, rows, cols, bs, true));
+}
+
+int
+bsddialog_yesno(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+ struct buttons bs;
+
+ get_buttons(conf, &bs, BUTTONLABEL(yes_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(no_label), BUTTONLABEL(help_label));
+
+ return (do_widget(conf, text, rows, cols, bs, true));
+}
diff --git a/lib/textbox.c b/lib/textbox.c
new file mode 100644
index 000000000000..2874aa5832b9
--- /dev/null
+++ b/lib/textbox.c
@@ -0,0 +1,280 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+
+#include <string.h>
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+/* "Text": tailbox - tailboxbg - textbox */
+
+#define BUTTON_TEXTBOX "HELP"
+
+extern struct bsddialog_theme t;
+
+enum textmode { TAILMODE, TAILBGMODE, TEXTMODE};
+
+static void
+textbox_autosize(struct bsddialog_conf conf, int rows, int cols, int *h, int *w,
+ int hpad, int wpad)
+{
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = VBORDERS;
+ /* buttons size */
+ *w += strlen(BUTTON_TEXTBOX) + 2 /* text delims*/;
+ /* text size */
+ *w = MAX(*w, wpad + VBORDERS);
+ /* avoid terminal overflow */
+ *w = MIN(*w, widget_max_width(conf)-1); /* again -1, fix util.c */
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = hpad + 4; /* HBORDERS + button border */
+ /* avoid terminal overflow */
+ *h = MIN(*h, widget_max_height(conf));
+ }
+}
+
+static int textbox_checksize(int rows, int cols, int hpad, int wpad)
+{
+ int mincols;
+
+ mincols = VBORDERS + strlen(BUTTON_TEXTBOX) + 2 /* text delims */;
+
+ if (cols < mincols)
+ RETURN_ERROR("Few cols for the textbox");
+
+ if (rows < 4 /* HBORDERS + button*/ + (hpad > 0 ? 1 : 0))
+ RETURN_ERROR("Few rows for the textbox");
+
+ return 0;
+}
+
+static int
+do_textbox(enum textmode mode, struct bsddialog_conf conf, char* path, int rows, int cols)
+{
+ WINDOW *widget, *pad, *shadow;
+ int i, input, y, x, h, w, hpad, wpad, ypad, xpad, ys, ye, xs, xe, printrows;
+ char buf[BUFSIZ], *exitbutt;
+ FILE *fp;
+ bool loop;
+ int output;
+
+ if (mode == TAILMODE || mode == TAILBGMODE) {
+ bsddialog_msgbox(conf, "Tailbox and Tailboxbg unimplemented", rows, cols);
+ RETURN_ERROR("Tailbox and Tailboxbg unimplemented");
+ }
+
+ if ((fp = fopen(path, "r")) == NULL)
+ RETURN_ERROR("Cannot open file");
+ /*if (mode == TAILMODE) {
+ fseek (fp, 0, SEEK_END);
+ i = nlines = 0;
+ while (i < hpad) {
+ line = ;
+ }
+ for (i=hpad-1; i--; i>=0) {
+ }
+ }*/
+ hpad = 1;
+ wpad = 1;
+ pad = newpad(hpad, wpad);
+ wbkgd(pad, t.widgetcolor);
+ i = 0;
+ while(fgets(buf, BUFSIZ, fp) != NULL) {
+ if ((int) strlen(buf) > wpad) {
+ wpad = strlen(buf);
+ wresize(pad, hpad, wpad);
+ }
+ if (i > hpad-1) {
+ hpad++;
+ wresize(pad, hpad, wpad);
+ }
+ mvwaddstr(pad, i, 0, buf);
+ i++;
+ }
+ fclose(fp);
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad);
+ if (textbox_checksize(h, w, hpad, wpad) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
+ NULL, NULL, NULL, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ exitbutt = conf.button.exit_label == NULL ? BUTTON_TEXTBOX : conf.button.exit_label;
+ draw_button(widget, h-2, (w-2)/2 - strlen(exitbutt)/2, strlen(exitbutt)+2,
+ exitbutt, true, true);
+
+ wrefresh(widget);
+
+ ys = y + 1;
+ xs = x + 1;
+ ye = ys + h - 5;
+ xe = xs + w - 3;
+ ypad = xpad = 0;
+ printrows = h-4;
+ loop = true;
+ while(loop) {
+ prefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ input = getch();
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ output = BSDDIALOG_YESOK;
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case KEY_HOME:
+ ypad = 0;
+ break;
+ case KEY_END:
+ ypad = hpad - printrows;
+ ypad = ypad < 0 ? 0 : ypad;
+ break;
+ case KEY_PPAGE:
+ ypad -= printrows;
+ ypad = ypad < 0 ? 0 : ypad;
+ break;
+ case KEY_NPAGE:
+ ypad += printrows;
+ ypad = ypad + printrows > hpad ? hpad - printrows : ypad;
+ break;
+ case '0':
+ xpad = 0;
+ case KEY_LEFT:
+ case 'h':
+ xpad = xpad > 0 ? xpad - 1 : 0;
+ break;
+ case KEY_RIGHT:
+ case 'l':
+ xpad = (xpad + w-2) < wpad-1 ? xpad + 1 : xpad;
+ break;
+ case KEY_UP:
+ case 'k':
+ ypad = ypad > 0 ? ypad - 1 : 0;
+ break;
+ case KEY_DOWN:
+ case'j':
+ ypad = ypad + printrows <= hpad -1 ? ypad + 1 : ypad;
+ break;
+ case KEY_F(1):
+ if (conf.hfile == NULL)
+ break;
+ if (f1help(conf) != 0)
+ return BSDDIALOG_ERROR;
+ /* No break! the terminal size can change */
+ case KEY_RESIZE:
+ hide_widget(y, x, h, w,conf.shadow);
+
+ /*
+ * Unnecessary, but, when the columns decrease the
+ * following "refresh" seem not work
+ */
+ refresh();
+
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return BSDDIALOG_ERROR;
+ textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad);
+ if (textbox_checksize(h, w, hpad, wpad) != 0)
+ return BSDDIALOG_ERROR;
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return BSDDIALOG_ERROR;
+
+ wclear(shadow);
+ mvwin(shadow, y + t.shadowrows, x + t.shadowcols);
+ wresize(shadow, h, w);
+
+ wclear(widget);
+ mvwin(widget, y, x);
+ wresize(widget, h, w);
+
+ ys = y + 1;
+ xs = x + 1;
+ ye = ys + h - 5;
+ xe = xs + w - 3;
+ ypad = xpad = 0;
+ printrows = h - 4;
+
+ if(update_widget_withtextpad(conf, shadow, widget, h, w,
+ RAISED, NULL, NULL, NULL, true) != 0)
+ return BSDDIALOG_ERROR;
+
+ draw_button(widget, h-2, (w-2)/2 - strlen(exitbutt)/2,
+ strlen(exitbutt)+2, exitbutt, true, true);
+
+ wrefresh(widget); /* for button */
+
+ /* Important to fix grey lines expanding screen */
+ refresh();
+ break;
+ }
+ }
+
+ end_widget_withtextpad(conf, widget, h, w, pad, shadow);
+
+ return output;
+}
+
+int bsddialog_tailbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+
+ return (do_textbox(TAILMODE, conf, text, rows, cols));
+}
+
+int bsddialog_tailboxbg(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+
+ return (do_textbox(TAILBGMODE, conf, text, rows, cols));
+}
+
+
+int bsddialog_textbox(struct bsddialog_conf conf, char* text, int rows, int cols)
+{
+
+ return (do_textbox(TEXTMODE, conf, text, rows, cols));
+}
+
diff --git a/lib/theme.c b/lib/theme.c
new file mode 100644
index 000000000000..7c27a85af74f
--- /dev/null
+++ b/lib/theme.c
@@ -0,0 +1,286 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+#include "bsddialog_theme.h"
+
+#define GET_COLOR(bg, fg) (COLOR_PAIR(bg * 8 + fg +1))
+
+struct bsddialog_theme t;
+
+static struct bsddialog_theme bsddialogtheme = {
+#define bgwidget COLOR_WHITE
+#define bgcurr COLOR_YELLOW
+ .shadowcolor = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadowrows = 1,
+ .shadowcols = 2,
+
+ .backgroundcolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+ .surroundtitle = true,
+ .titlecolor = GET_COLOR(COLOR_YELLOW, bgwidget),
+ .lineraisecolor = GET_COLOR(COLOR_BLACK, bgwidget),
+ .linelowercolor = GET_COLOR(COLOR_BLACK, bgwidget),
+ .widgetcolor = GET_COLOR(COLOR_BLACK, bgwidget),
+
+ .texthmargin = 1,
+
+ .curritemcolor = GET_COLOR(COLOR_WHITE, bgcurr),
+ .itemcolor = GET_COLOR(COLOR_BLACK, bgwidget),
+ .currtagcolor = GET_COLOR(COLOR_BLACK, bgcurr),
+ .tagcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
+ .namesepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
+ .descsepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
+
+ .currfieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
+ .fieldreadonlycolor = GET_COLOR(COLOR_CYAN,COLOR_WHITE),
+
+ .currbarcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .barcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+
+ .buttonspace = 3,
+ .buttleftch = '[',
+ .buttrightchar = ']',
+ .currbuttdelimcolor = GET_COLOR(COLOR_WHITE, bgcurr),
+ .buttdelimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
+ .currbuttoncolor = GET_COLOR(COLOR_WHITE, bgcurr) | A_UNDERLINE,
+ .buttoncolor = GET_COLOR(COLOR_BLACK, bgwidget) | A_UNDERLINE,
+ .currshortkeycolor = GET_COLOR(COLOR_BLACK, bgcurr) | A_UNDERLINE,
+ .shortkeycolor = GET_COLOR(COLOR_YELLOW, bgwidget) | A_UNDERLINE,
+
+ .bottomtitlecolor= GET_COLOR(COLOR_BLACK, bgwidget)
+};
+
+static struct bsddialog_theme blackwhite = {
+#define bk COLOR_BLACK
+#define fg COLOR_WHITE
+ .shadowcolor = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadowrows = 1,
+ .shadowcols = 2,
+
+ .backgroundcolor = GET_COLOR(fg, bk),
+ .surroundtitle = true,
+ .titlecolor = GET_COLOR(fg, bk),
+ .lineraisecolor = GET_COLOR(fg, bk),
+ .linelowercolor = GET_COLOR(fg, bk),
+ .widgetcolor = GET_COLOR(fg, bk),
+
+ .texthmargin = 1,
+
+ .curritemcolor = GET_COLOR(fg, bk) | A_REVERSE,
+ .itemcolor = GET_COLOR(fg, bk),
+ .currtagcolor = GET_COLOR(fg, bk) | A_REVERSE,
+ .tagcolor = GET_COLOR(fg, bk),
+ .namesepcolor = GET_COLOR(fg, bk),
+ .descsepcolor = GET_COLOR(fg, bk),
+
+ .currfieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
+ .fieldcolor = GET_COLOR(fg, bk),
+ .fieldreadonlycolor = GET_COLOR(fg, bk),
+
+ .currbarcolor = GET_COLOR(fg, bk) | A_REVERSE,
+ .barcolor = GET_COLOR(fg, bk),
+
+ .buttonspace = 3,
+ .buttleftch = '[',
+ .buttrightchar = ']',
+ .currbuttdelimcolor = GET_COLOR(fg, bk),
+ .buttdelimcolor = GET_COLOR(fg, bk),
+ .currbuttoncolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
+ .buttoncolor = GET_COLOR(fg, bk) | A_UNDERLINE,
+ .currshortkeycolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
+ .shortkeycolor = GET_COLOR(fg, bk) | A_UNDERLINE,
+
+ .bottomtitlecolor= GET_COLOR(fg, bk)
+};
+
+static struct bsddialog_theme dialogtheme = {
+ .shadowcolor = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadowrows = 1,
+ .shadowcols = 2,
+
+ .backgroundcolor = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
+ .surroundtitle = false,
+ .titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
+ .lineraisecolor = GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD,
+ .linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
+ .widgetcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+
+ .texthmargin = 1,
+
+ .curritemcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .itemcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
+ .currtagcolor = GET_COLOR(COLOR_YELLOW,COLOR_BLUE) | A_BOLD,
+ .tagcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
+ .namesepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .descsepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+
+ .currfieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .fieldreadonlycolor = GET_COLOR(COLOR_CYAN,COLOR_WHITE)| A_BOLD,
+
+ .currbarcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .barcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
+
+ .buttonspace = 3,
+ .buttleftch = '<',
+ .buttrightchar = '>',
+ .currbuttdelimcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .buttdelimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .currbuttoncolor = GET_COLOR(COLOR_YELLOW, COLOR_BLUE) | A_BOLD,
+ .buttoncolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .currshortkeycolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .shortkeycolor = GET_COLOR(COLOR_RED, COLOR_WHITE) | A_BOLD,
+
+ .bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD
+};
+
+static struct bsddialog_theme magentatheme = {
+ .shadowcolor = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadowrows = 1,
+ .shadowcols = 2,
+
+ .backgroundcolor = GET_COLOR(COLOR_WHITE, COLOR_MAGENTA) | A_BOLD,
+ .surroundtitle = true,
+ .titlecolor = GET_COLOR(COLOR_RED, COLOR_CYAN),
+ .lineraisecolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+ .widgetcolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+
+ .texthmargin = 1,
+
+ .curritemcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .itemcolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN) | A_BOLD,
+ .currtagcolor = GET_COLOR(COLOR_YELLOW,COLOR_BLUE) | A_BOLD,
+ .tagcolor = GET_COLOR(COLOR_BLUE, COLOR_CYAN) | A_BOLD,
+ .namesepcolor = GET_COLOR(COLOR_RED, COLOR_CYAN) | A_BOLD,
+ .descsepcolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN) | A_BOLD,
+
+ .currfieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .fieldreadonlycolor = GET_COLOR(COLOR_CYAN,COLOR_WHITE)| A_BOLD,
+
+ .currbarcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .barcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
+
+ .buttonspace = 3,
+ .buttleftch = '<',
+ .buttrightchar = '>',
+ .currbuttdelimcolor = GET_COLOR(COLOR_WHITE, COLOR_RED) | A_BOLD,
+ .buttdelimcolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+ .currbuttoncolor = GET_COLOR(COLOR_WHITE, COLOR_RED),
+ .buttoncolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+ .currshortkeycolor = GET_COLOR(COLOR_WHITE, COLOR_RED) | A_BOLD,
+ .shortkeycolor = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
+
+ .bottomtitlecolor= GET_COLOR(COLOR_BLACK, COLOR_CYAN) | A_BOLD
+};
+
+void bsddialog_set_theme(struct bsddialog_theme newtheme)
+{
+ t.shadowcolor = newtheme.shadowcolor;
+ t.shadowrows = newtheme.shadowrows;
+ t.shadowcols = newtheme.shadowcols;
+
+ t.backgroundcolor = newtheme.backgroundcolor;
+ t.surroundtitle = newtheme.surroundtitle;
+ t.titlecolor = newtheme.titlecolor;
+ t.lineraisecolor = newtheme.lineraisecolor;
+ t.linelowercolor = newtheme.linelowercolor;
+ t.widgetcolor = newtheme.widgetcolor;
+
+ t.texthmargin = newtheme.texthmargin;
+
+ t.curritemcolor = newtheme.curritemcolor;
+ t.itemcolor = newtheme.itemcolor;
+ t.currtagcolor = newtheme.currtagcolor;
+ t.tagcolor = newtheme.tagcolor;
+ t.namesepcolor = newtheme.namesepcolor;
+ t.descsepcolor = newtheme.descsepcolor;
+
+ t.currfieldcolor = newtheme.currfieldcolor;
+ t.fieldcolor = newtheme.fieldcolor;
+ t.fieldreadonlycolor = newtheme.fieldreadonlycolor;
+
+ t.currbarcolor = newtheme.currbarcolor;
+ t.barcolor = newtheme.barcolor;
+
+ t.buttonspace = newtheme.buttonspace;
+ t.buttleftch = newtheme.buttleftch;
+ t.buttrightchar = newtheme.buttrightchar;
+ t.currbuttdelimcolor = newtheme.currbuttdelimcolor;
+ t.buttdelimcolor = newtheme.buttdelimcolor;
+ t.currbuttoncolor = newtheme.currbuttoncolor;
+ t.buttoncolor = newtheme.buttoncolor;
+ t.currshortkeycolor = newtheme.currshortkeycolor;
+ t.shortkeycolor = newtheme.shortkeycolor;
+
+ t.bottomtitlecolor = newtheme.bottomtitlecolor;
+
+ bkgd(t.backgroundcolor);
+
+ refresh();
+}
+
+int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
+{
+
+ if (newtheme == BSDDIALOG_THEME_DEFAULT)
+ bsddialog_set_theme(dialogtheme);
+ 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 if (newtheme == BSDDIALOG_THEME_MAGENTA)
+ bsddialog_set_theme(magentatheme);
+ else
+ RETURN_ERROR("Unknow default theme");
+
+ return 0;
+}
+
+int
+bsddialog_color(enum bsddialog_color background, enum bsddialog_color foreground)
+{
+
+ return GET_COLOR(background, foreground);
+}
+
+struct bsddialog_theme bsddialog_get_theme()
+{
+
+ return t;
+}
diff --git a/lib/timebox.c b/lib/timebox.c
new file mode 100644
index 000000000000..f7abfd8c0f31
--- /dev/null
+++ b/lib/timebox.c
@@ -0,0 +1,241 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef PORTNCURSES
+#include <ncurses/curses.h>
+#else
+#include <curses.h>
+#endif
+
+#include "bsddialog.h"
+#include "lib_util.h"
+
+/* "Time": timebox - calendar */
+
+int bsddialog_timebox(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int *hh, unsigned int *mm, unsigned int *ss)
+{
+ WINDOW *widget, *shadow;
+ int i, input, output, y, x, sel;
+ struct buttons bs;
+ bool loop, buttupdate;
+
+ if (hh == NULL || mm == NULL || ss == NULL)
+ RETURN_ERROR("hh or mm or ss == NULL");
+
+ struct myclockstruct {
+ unsigned int max;
+ unsigned int curr;
+ WINDOW *win;
+ } c[3] = { {23, *hh, NULL}, {59, *mm, NULL}, {59, *ss, NULL} };
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ c[0].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 7, 3, 4, LOWERED);
+ mvwaddch(widget, rows - 5, cols/2 - 3, ':');
+ c[1].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 2, 3, 4, LOWERED);
+ mvwaddch(widget, rows - 5, cols/2 + 2, ':');
+ c[2].win = new_boxed_window(conf, y + rows - 6, x + cols/2 + 3, 3, 4, LOWERED);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ sel=0;
+ curs_set(2);
+ loop = buttupdate = true;
+ while(loop) {
+ if (buttupdate) {
+ draw_buttons(widget, rows-2, cols, bs, true);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+
+ for (i=0; i<3; i++) {
+ mvwprintw(c[i].win, 1, 1, "%2d", c[i].curr);
+ wrefresh(c[i].win);
+ }
+ wmove(c[sel].win, 1, 2);
+ wrefresh(c[sel].win);
+
+ input = getch();
+ switch(input) {
+ case 10: /* Enter */
+ output = bs.value[bs.curr];
+ if (output == BSDDIALOG_YESOK) {
+ *hh = c[0].curr - 1900;
+ *mm = c[1].curr;
+ *ss = c[2].curr;
+ }
+ loop = false;
+ break;
+ case 27: /* Esc */
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': /* TAB */
+ sel = (sel + 1) % 3;
+ break;
+ case KEY_LEFT:
+ if (bs.curr > 0) {
+ bs.curr--;
+ buttupdate = true;
+ }
+ break;
+ case KEY_RIGHT:
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ buttupdate = true;
+ }
+ break;
+ case KEY_UP:
+ c[sel].curr = c[sel].curr < c[sel].max ? c[sel].curr + 1 : 0;
+ break;
+ case KEY_DOWN:
+ c[sel].curr = c[sel].curr > 0 ? c[sel].curr - 1 : c[sel].max;
+ break;
+ }
+ }
+
+ curs_set(0);
+
+ for (i=0; i<3; i++)
+ delwin(c[i].win);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
+
+int bsddialog_calendar(struct bsddialog_conf conf, char* text, int rows, int cols,
+ unsigned int *yy, unsigned int *mm, unsigned int *dd)
+{
+ WINDOW *widget, *shadow;
+ int i, input, output, y, x, sel;
+ struct buttons bs;
+ bool loop, buttupdate;
+
+ if (yy == NULL || mm == NULL || dd == NULL)
+ RETURN_ERROR("yy or mm or dd == NULL");
+
+ struct calendar {
+ unsigned int max;
+ unsigned int curr;
+ WINDOW *win;
+ unsigned int x;
+ } c[3] = {{9999, *yy, NULL, 4 }, {12, *mm, NULL, 9 }, {31, *dd, NULL, 2 }};
+ struct month {
+ char *name;
+ unsigned int days;
+ } m[12] = {
+ { "January", 30 }, { "February", 30 }, { "March", 30 },
+ { "April", 30 }, { "May", 30 }, { "June", 30 },
+ { "July", 30 }, { "August", 30 }, { "September", 30 },
+ { "October", 30 }, { "November", 30 }, { "December", 30 }
+ };
+
+ if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
+ true) <0)
+ return -1;
+
+ c[0].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 12, 3, 6, LOWERED);
+ mvwaddch(widget, rows - 5, cols/2 - 6, '/');
+ c[1].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 5, 3, 11, LOWERED);
+ mvwaddch(widget, rows - 5, cols/2 + 6, '/');
+ c[2].win = new_boxed_window(conf, y + rows - 6, x + cols/2 + 7, 3, 4, LOWERED);
+
+ wrefresh(widget);
+
+ get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
+ BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
+
+ sel=2;
+ curs_set(2);
+ loop = buttupdate = true;
+ while(loop) {
+ if (buttupdate) {
+ draw_buttons(widget, rows-2, cols, bs, true);
+ wrefresh(widget);
+ buttupdate = false;
+ }
+
+ mvwprintw(c[0].win, 1, 1, "%4d", c[0].curr);
+ mvwprintw(c[1].win, 1, 1, "%9s", m[c[1].curr-1].name);
+ mvwprintw(c[2].win, 1, 1, "%2d", c[2].curr);
+ for (i=0; i<3; i++) {
+ wrefresh(c[i].win);
+ }
+ wmove(c[sel].win, 1, c[sel].x);
+ wrefresh(c[sel].win);
+
+ input = getch();
+ switch(input) {
+ case 10: // Enter
+ output = bs.value[bs.curr]; // values -> outputs
+ if (output == BSDDIALOG_YESOK) {
+ *yy = c[0].curr - 1900;
+ *mm = c[1].curr;
+ *dd = c[2].curr;
+ }
+ loop = false;
+ break;
+ case 27: // Esc
+ output = BSDDIALOG_ESC;
+ loop = false;
+ break;
+ case '\t': // TAB
+ sel = (sel + 1) % 3;
+ break;
+ case KEY_LEFT:
+ if (bs.curr > 0) {
+ bs.curr--;
+ buttupdate = true;
+ }
+ break;
+ case KEY_RIGHT:
+ if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ buttupdate = true;
+ }
+ break;
+ case KEY_UP:
+ c[sel].curr = c[sel].curr < c[sel].max ? c[sel].curr + 1 : 1;
+ break;
+ case KEY_DOWN:
+ c[sel].curr = c[sel].curr > 1 ? c[sel].curr - 1 : c[sel].max;
+ break;
+ }
+ }
+
+ curs_set(0);
+
+ for (i=0; i<3; i++)
+ delwin(c[i].win);
+ end_widget(conf, widget, rows, cols, shadow);
+
+ return output;
+}
diff --git a/library_examples/buildlist.c b/library_examples/buildlist.c
new file mode 100644
index 000000000000..f5d991bcb2e6
--- /dev/null
+++ b/library_examples/buildlist.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int i, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem items[5] = {
+ {"", false, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"", true, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"", false, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"", true, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"", false, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "radiolist";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_buildlist(conf, "Example", 15, 30, 5, 5, items, NULL);
+
+ bsddialog_end();
+
+ printf("Buildlist:\n");
+ for (i=0; i<5; i++)
+ printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
+
+
+ return output;
+}
diff --git a/library_examples/checklist.c b/library_examples/checklist.c
new file mode 100644
index 000000000000..104c2285a6e1
--- /dev/null
+++ b/library_examples/checklist.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int i, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem items[5] = {
+ {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "checklist";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_checklist(conf, "Example", 15, 30, 5, 5, items, NULL);
+
+ bsddialog_end();
+
+ printf("Checklist:\n");
+ for (i=0; i<5; i++)
+ printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
+
+
+ return output;
+}
diff --git a/library_examples/compile b/library_examples/compile
new file mode 100755
index 000000000000..3215dceb72b6
--- /dev/null
+++ b/library_examples/compile
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+libpath=../lib
+examples="buildlist menu treeview checklist radiolist mixedlist theme \
+ infobox yesno msgbox ports"
+
+for e in $examples
+do
+ cc -g -Wall -I$libpath ${e}.c -o $e -L$libpath -lbsddialog -Wl,-rpath=$libpath
+done
diff --git a/library_examples/infobox.c b/library_examples/infobox.c
new file mode 100644
index 000000000000..8def8a482920
--- /dev/null
+++ b/library_examples/infobox.c
@@ -0,0 +1,32 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int output;
+ struct bsddialog_conf conf;
+
+ bsddialog_initconf(&conf);
+ conf.title = "infobox";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_infobox(conf, "Example", 7, 20);
+
+ bsddialog_end();
+
+ return output;
+}
diff --git a/library_examples/menu.c b/library_examples/menu.c
new file mode 100644
index 000000000000..04306e8317f4
--- /dev/null
+++ b/library_examples/menu.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int i, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem items[5] = {
+ {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "menu";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_menu(conf, "Example", 15, 30, 5, 5, items, NULL);
+
+ bsddialog_end();
+
+ printf("Menu:\n");
+ for (i=0; i<5; i++)
+ printf(" [%c] %s\n", items[i].on ? 'X' : ' ', items[i].name);
+
+
+ return output;
+}
diff --git a/library_examples/mixedlist.c b/library_examples/mixedlist.c
new file mode 100644
index 000000000000..8b918b707869
--- /dev/null
+++ b/library_examples/mixedlist.c
@@ -0,0 +1,71 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+/* Actually this is an example for mixedmenu to reproduce dialog4ports(1) */
+int main()
+{
+ int i, j, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem item;
+ struct bsddialog_menuitem check[5] = {
+ { "+", true, 0, "Name 1", "Desc 1", "Bottom Desc 1" },
+ { "" , false, 0, "Name 2", "Desc 2", "Bottom Desc 2" },
+ { "+", true, 0, "Name 3", "Desc 3", "Bottom Desc 3" },
+ { "" , false, 0, "Name 4", "Desc 4", "Bottom Desc 4" },
+ { "+", true, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
+ };
+ struct bsddialog_menuitem sep[1] = {
+ { "", true, 0, "Radiolist", "(desc)", "" }
+ };
+ struct bsddialog_menuitem radio[5] = {
+ { "", true, 0, "Name 1", "Desc 1", "Bottom Desc 1" },
+ { "+", false, 0, "Name 2", "Desc 2", "Bottom Desc 2" },
+ { "", false, 0, "Name 3", "Desc 3", "Bottom Desc 3" },
+ { "+", false, 0, "Name 4", "Desc 4", "Bottom Desc 4" },
+ { "", false, 0, "Name 5", "Desc 5", "Bottom Desc 5" }
+ };
+ struct bsddialog_menugroup group[3] = {
+ { BSDDIALOG_CHECKLIST, 5, check },
+ { BSDDIALOG_SEPARATOR, 1, sep },
+ { BSDDIALOG_RADIOLIST, 5, radio }
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "mixedmenu";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_mixedlist(conf, "dialog4ports", 20, 30, 11, 3, group,
+ NULL,NULL);
+
+ bsddialog_end();
+
+ printf("Mixedlist (dialog4ports):\n");
+ for (i=0; i<3; i++) {
+ for (j=0; j<group[i].nitems; j++) {
+ item = group[i].items[j];
+ if (group[i].type == BSDDIALOG_SEPARATOR)
+ printf("----- %s -----\n", item.name);
+ else if (group[i].type == BSDDIALOG_RADIOLIST)
+ printf(" (%c) %s\n", item.on ? '*' : ' ', item.name);
+ else /* BSDDIALOG_PORTCHECKLIST */
+ printf(" [%c] %s\n", item.on ? 'X' : ' ', item.name);
+ }
+ }
+
+
+ return output;
+}
diff --git a/library_examples/msgbox.c b/library_examples/msgbox.c
new file mode 100644
index 000000000000..93ac5201425e
--- /dev/null
+++ b/library_examples/msgbox.c
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int input;
+ struct bsddialog_conf conf;
+
+ /* Configuration */
+ bsddialog_initconf(&conf);
+ conf.title = "msgbox";
+
+ /* Run BSDDialog */
+ if (bsddialog_init() == BSDDIALOG_ERROR) {
+ printf("Error: %s\n", bsddialog_geterror());
+ return -1;
+ }
+ input = bsddialog_msgbox(conf, "Example", 7, 20);
+ bsddialog_end();
+
+ /* User Input */
+ printf("User input: ");
+ switch (input) {
+ case BSDDIALOG_ERROR: printf("Error %s\n", bsddialog_geterror()); break;
+ case BSDDIALOG_YESOK: printf("OK\n"); break;
+ case BSDDIALOG_ESC: printf("ESC\n"); break;
+ }
+
+ return input;
+}
diff --git a/library_examples/ports.c b/library_examples/ports.c
new file mode 100644
index 000000000000..1a5c514490e7
--- /dev/null
+++ b/library_examples/ports.c
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+/* Actually this is an example for mixedmenu to reproduce dialog4ports(1) */
+int main()
+{
+ int i, j, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem item;
+
+ struct bsddialog_menuitem check1[5] = {
+ { "+", true, 0, "CSCOPE", "cscope support", "" },
+ { "+", true, 0, "DEFAULT_VIMRC", "Install bundled vimrc as default setting", "" },
+ { "", false, 0, "MAKE_JOBS", "Enable parallel build", "" },
+ { "", true, 0, "NLS", "Native Language Support", "" },
+ { "+", false, 0, "XTERM_SAVE", "Restore xterm screen after exit", "" }
+ };
+ struct bsddialog_menuitem sep1[1] = {
+ { "", true, 0, "Optional language bindings", "", "" }
+ };
+ struct bsddialog_menuitem check2[6] = {
+ { "", false, 0, "LUA", "Lua scripting language support", "" },
+ { "+", true, 0, "PERL", "Perl scripting language support", "" },
+ { "", true, 0, "PYTHON", "Python bindings or support", "" },
+ { "+", true, 0, "RUBY", "Ruby bindings or support", "" },
+ { "", false, 0, "SCHEME", "MzScheme (Racket) bindings", "" },
+ { "", false, 0, "TCL", "Tcl scripting language support", "" }
+ };
+ struct bsddialog_menuitem sep2[1] = {
+ { "", true, 0, "CTAGS", "", "" }
+ };
+ struct bsddialog_menuitem radio1[3] = {
+ { "+", false, 0, "CTAGS_BASE", "Use system ctags", "" },
+ { "", true, 0, "CTAGS_EXUBERANT", "Use exctags instead of ctags", "" },
+ { "", false, 0, "CTAGS_UNIVERSAL", "Use uctags instead of ctags", "" }
+ };
+ struct bsddialog_menuitem sep3[1] = {
+ { "", true, 0, "User interface", "", "" }
+ };
+ struct bsddialog_menuitem radio2[7] = {
+ { "", false, 0, "ATHENA", "Athena GUI toolkit", "" },
+ { "", false, 0, "CONSOLE","Console/terminal mode", "" },
+ { "", false, 0, "GNOME", "GNOME desktop environment support", "" },
+ { "", false, 0, "GTK2", "GTK+ 2 GUI toolkit support", "" },
+ { "", true, 0, "GTK3", "GTK+ 3 GUI toolkit support", "" },
+ { "", false, 0, "MOTIF", "Motif widget library support", "" },
+ { "", false, 0, "X11", "X11 (graphics) support", "" }
+ };
+
+ struct bsddialog_menugroup group[7] = {
+ { BSDDIALOG_CHECKLIST, 5, check1 },
+ { BSDDIALOG_SEPARATOR, 1, sep1 },
+ { BSDDIALOG_CHECKLIST, 6, check2 },
+ { BSDDIALOG_SEPARATOR, 1, sep2 },
+ { BSDDIALOG_RADIOLIST, 3, radio1 },
+ { BSDDIALOG_SEPARATOR, 1, sep3 },
+ { BSDDIALOG_RADIOLIST, 7, radio2 },
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "vim-8.2.2569";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_mixedlist(conf, "", 0, 0, 0, 7, group, NULL,NULL);
+
+ bsddialog_end();
+
+ printf("Options:\n");
+ for (i=0; i<7; i++) {
+ for (j=0; j<group[i].nitems; j++) {
+ item = group[i].items[j];
+ if (group[i].type == BSDDIALOG_SEPARATOR)
+ printf("----- %s -----\n", item.name);
+ else if (group[i].type == BSDDIALOG_RADIOLIST)
+ printf(" (%c) %s\n", item.on ? '*' : ' ', item.name);
+ else /* BSDDIALOG_PORTCHECKLIST */
+ printf(" [%c] %s\n", item.on ? 'X' : ' ', item.name);
+ }
+ }
+
+
+ return output;
+}
diff --git a/library_examples/radiolist.c b/library_examples/radiolist.c
new file mode 100644
index 000000000000..39570d4b6602
--- /dev/null
+++ b/library_examples/radiolist.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int i, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem items[5] = {
+ {"", true, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"", false, 0, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"", true, 0, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"", false, 0, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"", true, 0, "Name 5", "Desc 5", "Bottom Desc 5"}
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "radiolist";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_radiolist(conf, "Example", 15, 30, 5, 5, items, NULL);
+
+ bsddialog_end();
+
+ printf("Radiolist:\n");
+ for (i=0; i<5; i++)
+ printf(" (%c) %s\n", items[i].on ? '*' : ' ', items[i].name);
+
+
+ return output;
+}
diff --git a/library_examples/theme.c b/library_examples/theme.c
new file mode 100644
index 000000000000..56ed4459cacb
--- /dev/null
+++ b/library_examples/theme.c
@@ -0,0 +1,67 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+int main()
+{
+ int output;
+ struct bsddialog_conf conf;
+ enum bsddialog_default_theme theme;
+ struct bsddialog_menuitem items[5] = {
+ {"", false, 0, "Dialog", "Current dialog theme", "BSDDIALOG_THEME_DIALOG" },
+ {"", false, 0, "BSDDialog", "Future default theme", "BSDDIALOG_THEME_DEFAULT"},
+ {"", false, 0, "BlackWhite","Black and White theme", "BSDDIALOG_THEME_BLACKWHITE"},
+ {"", false, 0, "Magenta", "Testing", "BSDDIALOG_THEME_MAGENTA"},
+ {"", false, 0, "Quit", "Exit", "Quit or Cancel to exit" }
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = " Theme ";
+
+ if (bsddialog_init() == BSDDIALOG_ERROR)
+ return BSDDIALOG_ERROR;
+
+ while (true) {
+ bsddialog_backtitle(conf, "Theme Example");
+
+ output = bsddialog_menu(conf, "Choose theme", 15, 40, 5, 5, items, NULL);
+
+ if (output != BSDDIALOG_YESOK || items[4].on)
+ break;
+
+ if (items[0].on) {
+ theme = BSDDIALOG_THEME_DIALOG;
+ conf.menu.default_item = items[0].name;
+ }
+ else if (items[1].on) {
+ theme = BSDDIALOG_THEME_BSDDIALOG;
+ conf.menu.default_item = items[1].name;
+ }
+ else if (items[2].on) {
+ theme = BSDDIALOG_THEME_BLACKWHITE;
+ conf.menu.default_item = items[2].name;
+ }
+ else if (items[3].on) {
+ theme = BSDDIALOG_THEME_MAGENTA;
+ conf.menu.default_item = items[3].name;
+ }
+
+ bsddialog_set_default_theme(theme);
+ }
+
+ bsddialog_end();
+
+ return output;
+}
diff --git a/library_examples/treeview.c b/library_examples/treeview.c
new file mode 100644
index 000000000000..d4c7afb4a1d0
--- /dev/null
+++ b/library_examples/treeview.c
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int i, output;
+ struct bsddialog_conf conf;
+ struct bsddialog_menuitem items[5] = {
+ {"", false, 0, "Name 1", "Desc 1", "Bottom Desc 1"},
+ {"", false, 1, "Name 2", "Desc 2", "Bottom Desc 2"},
+ {"", false, 1, "Name 3", "Desc 3", "Bottom Desc 3"},
+ {"", false, 2, "Name 4", "Desc 4", "Bottom Desc 4"},
+ {"", false, 1, "Name 5", "Desc 5", "Bottom Desc 5"}
+ };
+
+ bsddialog_initconf(&conf);
+ conf.title = "radiolist";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_treeview(conf, "Example", 15, 30, 5, 5, items, NULL);
+
+ bsddialog_end();
+
+ printf("Treeview:\n");
+ for (i=0; i<5; i++)
+ printf(" (%c) %s\n", items[i].on ? '*' : ' ', items[i].name);
+
+
+ return output;
+}
diff --git a/library_examples/yesno.c b/library_examples/yesno.c
new file mode 100644
index 000000000000..035b65c69a12
--- /dev/null
+++ b/library_examples/yesno.c
@@ -0,0 +1,32 @@
+/*-
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * Written in 2021 by Alfonso Sabato Siciliano.
+ * To the extent possible under law, the author has dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty, see:
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <bsddialog.h>
+
+int main()
+{
+ int output;
+ struct bsddialog_conf conf;
+
+ bsddialog_initconf(&conf);
+ conf.title = "yesno";
+
+ if (bsddialog_init() < 0)
+ return -1;
+
+ output = bsddialog_yesno(conf, "Example", 7, 25);
+
+ bsddialog_end();
+
+ return output;
+}
diff --git a/screenshot.png b/screenshot.png
new file mode 100644
index 000000000000..940a56c722e7
--- /dev/null
+++ b/screenshot.png
Binary files differ
diff --git a/utility_examples/gauge_example.sh b/utility_examples/gauge_example.sh
new file mode 100755
index 000000000000..b17f20274c79
--- /dev/null
+++ b/utility_examples/gauge_example.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+input="A B C D E F G"
+total=`echo $input | awk '{print split($0, a)}'`
+curr=1
+for i in $input
+do
+ sleep 1
+ perc="$(expr $(expr $curr "*" 100 ) "/" $total )"
+ echo XXX
+ echo $perc
+ echo "[$curr/$total] Input: $i"
+ echo XXX
+ if [ $curr -eq $total ]
+ then
+ echo EOF
+ fi
+ curr=`expr $curr + 1`
+done | ./bsddialog --title gauge --gauge "[0/$total] Starting..." 10 70 0
+
diff --git a/utility_examples/info_example.sh b/utility_examples/info_example.sh
new file mode 100755
index 000000000000..a57afa5fad88
--- /dev/null
+++ b/utility_examples/info_example.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./bsddialog --sleep 5 --title infobox --infobox "Hello World!\n5 seconds" 6 20 \ No newline at end of file
diff --git a/utility_examples/menu_example.sh b/utility_examples/menu_example.sh
new file mode 100755
index 000000000000..dc41279a6b71
--- /dev/null
+++ b/utility_examples/menu_example.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+./bsddialog --title menu --menu "Hello World!" 15 30 5 \
+ "Tag 1" "DESC 1 xyz" \
+ "Tag 2" "DESC 2 xyz" \
+ "Tag 3" "DESC 3 xyz" \
+ "Tag 4" "DESC 4 xyz" \
+ "Tag 5" "DESC 5 xyz" \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --title checklist --checklist "Hello World!" 15 30 5 \
+ "Tag 1" "DESC 1 xyz" on \
+ "Tag 2" "DESC 2 xyz" off \
+ "Tag 3" "DESC 3 xyz" on \
+ "Tag 4" "DESC 4 xyz" off \
+ "Tag 5" "DESC 5 xyz" on \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --title radiolist --radiolist "Hello World!" 15 30 5 \
+ "Tag 1" "DESC 1 xyz" off \
+ "Tag 2" "DESC 2 xyz" off \
+ "Tag 3" "DESC 3 xyz" on \
+ "Tag 4" "DESC 4 xyz" off \
+ "Tag 5" "DESC 5 xyz" off \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --title buildlist --buildlist "Hello World!" 15 40 5 \
+ "Tag 1" "DESC 1 xyz" off \
+ "Tag 2" "DESC 2 xyz" off \
+ "Tag 3" "DESC 3 xyz" on \
+ "Tag 4" "DESC 4 xyz" off \
+ "Tag 5" "DESC 5 xyz" off \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --title treeview --treeview "Hello World!" 15 40 5 \
+ 0 "Tag 1" "DESC 1 xyz" off \
+ 1 "Tag 2" "DESC 2 xyz" off \
+ 2 "Tag 3" "DESC 3 xyz" on \
+ 1 "Tag 4" "DESC 4 xyz" off \
+ 1 "Tag 5" "DESC 5 xyz" off \
+ 2>out.txt ; cat out.txt ; rm out.txt
diff --git a/utility_examples/message_example.sh b/utility_examples/message_example.sh
new file mode 100755
index 000000000000..ac9dcc6e48b6
--- /dev/null
+++ b/utility_examples/message_example.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+./bsddialog --title msgbox --msgbox "Hello World!" 6 20
+
+./bsddialog --title yesno --yesno "Hello World!" 6 25 \ No newline at end of file
diff --git a/utility_examples/mixedform_example.sh b/utility_examples/mixedform_example.sh
new file mode 100755
index 000000000000..079805996dad
--- /dev/null
+++ b/utility_examples/mixedform_example.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+./bsddialog --title mixedform --mixedform "Hello World!" 12 40 5 \
+ Label: 1 1 Entry 1 11 18 25 0 \
+ Label: 2 1 Read-Only 2 11 18 25 2 \
+ Password: 3 1 Value2 3 11 18 25 1 \
+ Password: 4 1 Value4 4 11 18 25 3 \
+ Label5: 5 1 Value5 5 11 18 25 4 \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --backtitle "BSD-2-Clause Licese" --title " form " --form "Hello World!" 12 40 5 \
+ Label1: 1 1 Value1 1 9 18 25 \
+ Label2: 2 1 Value2 2 9 18 25 \
+ Label3: 3 1 Value3 3 9 18 25 \
+ Label4: 4 1 Value4 4 9 18 25 \
+ Label5: 5 1 Value5 5 9 18 25 \
+ 2>out.txt ; cat out.txt ; rm out.txt
+
+./bsddialog --title passwordform --passwordform "Hello World!" 12 40 5 \
+ Password1: 1 1 Value1 1 12 18 25 \
+ Password2: 2 1 Value2 2 12 18 25 \
+ Password3: 3 1 Value3 3 12 18 25 \
+ Password4: 4 1 Value4 4 12 18 25 \
+ Password5: 5 1 Value5 5 12 18 25 \
+ 2>out.txt ; cat out.txt ; rm out.txt
diff --git a/utility_examples/mixedgauge_example.sh b/utility_examples/mixedgauge_example.sh
new file mode 100755
index 000000000000..900639f9ee84
--- /dev/null
+++ b/utility_examples/mixedgauge_example.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+input="A B C D E F G H"
+total=`echo $input | awk '{print split($0, a)}'`
+curr=1
+for i in $input
+do
+ perc="$(expr $(expr $curr "*" 100 ) "/" $total )"
+ curr=`expr $curr + 1`
+ ./bsddialog --title " mixedgauge " --mixedgauge "Hello World! Press <ENTER>" 20 35 $perc \
+ "Hidden!" 8 \
+ "Label 1" 0 \
+ "Label 2" 1 \
+ "Label 3" 2 \
+ "Label 4" 3 \
+ "Label 5" 4 \
+ "Label 6" 5 \
+ "Label 7" 6 \
+ "Label 8" 7 \
+ "Label 9" 9 \
+ "Label X" -- -$perc
+ #sleep 1
+done
+