From 857c66bb5f3c5651b012beb1b5ea6ba39354ea94 Mon Sep 17 00:00:00 2001 From: Baptiste Daroussin Date: Wed, 24 Nov 2021 09:42:13 +0100 Subject: [PATCH] bsddialog: import snapshot as of 2021-11-24 --- GNUMakefile | 28 + LICENSE | 24 + Makefile | 49 + README.md | 160 +++ bsddialog.c | 1263 ++++++++++++++++++++++++ lib/GNUMakefile | 31 + lib/Makefile | 73 ++ lib/barbox.c | 369 +++++++ lib/bsddialog.h | 257 +++++ lib/bsddialog_theme.h | 96 ++ lib/commandbox.c | 211 ++++ lib/editorbox.c | 45 + lib/filebox.c | 52 + lib/formbox.c | 396 ++++++++ lib/infobox.c | 114 +++ lib/lib_util.c | 996 +++++++++++++++++++ lib/lib_util.h | 146 +++ lib/libbsddialog.c | 142 +++ lib/menubox.c | 1015 +++++++++++++++++++ lib/messagebox.c | 278 ++++++ lib/textbox.c | 280 ++++++ lib/theme.c | 286 ++++++ lib/timebox.c | 241 +++++ library_examples/buildlist.c | 44 + library_examples/checklist.c | 44 + library_examples/compile | 10 + library_examples/infobox.c | 32 + library_examples/menu.c | 44 + library_examples/mixedlist.c | 71 ++ library_examples/msgbox.c | 42 + library_examples/ports.c | 97 ++ library_examples/radiolist.c | 44 + library_examples/theme.c | 67 ++ library_examples/treeview.c | 44 + library_examples/yesno.c | 32 + screenshot.png | Bin 0 -> 11050 bytes utility_examples/gauge_example.sh | 20 + utility_examples/info_example.sh | 3 + utility_examples/menu_example.sh | 41 + utility_examples/message_example.sh | 5 + utility_examples/mixedform_example.sh | 25 + utility_examples/mixedgauge_example.sh | 24 + 42 files changed, 7241 insertions(+) create mode 100644 GNUMakefile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 bsddialog.c create mode 100644 lib/GNUMakefile create mode 100644 lib/Makefile create mode 100644 lib/barbox.c create mode 100644 lib/bsddialog.h create mode 100644 lib/bsddialog_theme.h create mode 100644 lib/commandbox.c create mode 100644 lib/editorbox.c create mode 100644 lib/filebox.c create mode 100644 lib/formbox.c create mode 100644 lib/infobox.c create mode 100644 lib/lib_util.c create mode 100644 lib/lib_util.h create mode 100644 lib/libbsddialog.c create mode 100644 lib/menubox.c create mode 100644 lib/messagebox.c create mode 100644 lib/textbox.c create mode 100644 lib/theme.c create mode 100644 lib/timebox.c create mode 100644 library_examples/buildlist.c create mode 100644 library_examples/checklist.c create mode 100755 library_examples/compile create mode 100644 library_examples/infobox.c create mode 100644 library_examples/menu.c create mode 100644 library_examples/mixedlist.c create mode 100644 library_examples/msgbox.c create mode 100644 library_examples/ports.c create mode 100644 library_examples/radiolist.c create mode 100644 library_examples/theme.c create mode 100644 library_examples/treeview.c create mode 100644 library_examples/yesno.c create mode 100644 screenshot.png create mode 100755 utility_examples/gauge_example.sh create mode 100755 utility_examples/info_example.sh create mode 100755 utility_examples/menu_example.sh create mode 100755 utility_examples/message_example.sh create mode 100755 utility_examples/mixedform_example.sh create mode 100755 utility_examples/mixedgauge_example.sh 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: +# +# +# 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: +# +# +# 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: + + + +## 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 \ | +| --mixedform | In progress | todo autosize, resize, F1 | +| --mixedgauge | In progress | todo autosize, resize, F1 | +| --passwordbox | In progress | implemented via --mixedform, todo \ | +| --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 + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 [--] -- "\ + " [--]\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: +# +# +# 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: +# +# +# 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 +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 + +/* 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 + +#ifdef PORTNCURSES +#include +#else +#include +#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 +#else +#include +#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 +#else +#include +#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 + +#ifdef PORTNCURSES +#include +#include +#else +#include +#include +#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= (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 + +#ifdef PORTNCURSES +#include +#else +#include +#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 + +#include +#include +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 +#include +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 + +#include +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 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; iname != 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 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 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 + +#include +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 + +#include + +#ifdef PORTNCURSES +#include +#else +#include +#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 +#else +#include +#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 +#else +#include +#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: + * . + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +/* 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. + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +/* 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. + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include +#include + +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: + * . + */ + +#include +#include + +#include + +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: + * . + */ + +#include +#include + +#include + +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 0000000000000000000000000000000000000000..940a56c722e762ed54ab8746d764677e9339bc6a GIT binary patch literal 11050 zcmeHtX;f3$wr&(H%2J`u^{9n3IaQ(@MW6&B^ysmKN+D2+fJhUSCP)_~LI_QwWtEg7 zA|QPeEd-=jy3i#-DGhA`(gX+)kPw;x0YVazkmRmZ-8bGFXrAUqB#`{qXONG+0)7u4s z1l=31X-h-MmKa#h7!oZYR#&~cn0DiQV&EsT^v-4|SiQl=2FENd^ya0-$yQ9-%RxP7 zyDGT>3hNmC)wj=Y6t}cUhDL^qtHW0qRdQEE)|D$SfBWsGA9@D_5}N8xDVim;drZXy-(Hr{CyC8X@DRl)mkkPy-K@o$QhYO?Z?RlrkH^hD>(5_z) zt>y2T)#V7OJx$YRX4o`jqZe(&&hYTt+-V-+*A?Kt(A*0f+nl~E;2 zlni?y`nsSN2JnqJKE3Z%YHJnIU8?XB6Icpot5wvX!e_@cR3}gTeGy`b=-C&0a^#Sl zsSt%BV#I9kt+9qw{%Eg5DkqKMP!e~duM6<%ODzCmVRz%Gf zc>Y)yk;GAbehchIcd{MX)I=xYR88B)5B5A;2n-A19@^vlN6}VGTQBnK3A|Att zk-*=$D4BLR5>|?KbCU>H@|3f`+ZLDAxCjehBWYWVl$VZKhRKalD=Lgm7OxK0V*vMM{u8+EKf-T7;dT3SL4%hRaR#Vw|wx>#Z3^!>cVBXIo z6K67>iEu%D4~*H|J9^>3mnK{qRdO3WgQN!y2+bsh!Q6{q5glwrU4zCqx1NZH@d_6j zc}-tDgO}^}WYq-CEI>kgD{9EONk*h^L=%eZ&WeS^jf}mt9zV1W{TBo&^nPhQ>GmhG zSl*D1o`e~p>bGBYsP|xMB=#+LR?>Exnl6r1g;dKVa~jQD!)E-_<~ALwXdAOovsf?? z%T3ekq~WcB5`+#7g~MPv5?BS>f{FMJ3bI>7E>I`&NXkdNWd(Rt`mAaU2^-2e+C04h zGLijLPfa%nlf{Kpvs=tBu~Xvvr3Ae!rm#5 z+Z?^FnW(cdvbi{^e_t*?Qh0xAyX1<8sI%HC<@>Z={Oz}a^X8JZj>|riNB!(q%D38Mll46WC*t}eC#GqNk_p{I#XmpIGGIUymTgTOb+%l9;Cob2?3Asu-k z)dO*l>AxTg1{U($gr*jK4P&LRWOJ!G;+~@>d2OhL>2r%iWv)d5`tH@epRzLRW4^r0 zsEcxu7MM!c_ZLQ*q2$~4M5%CbkZl(0?x6=SFCUQ)PE{c3y6}LxarJAyiW5PagRK}| z19MACS&70c)ZKl2e8OAiN}EOZ%CL*YSw~1ooZqs1yZhhXhqZ=5Mn3fI&Td~A3jgB++`w#|o@d$COu`%k(B&76xMk|S**Ua+oe10!Eb5fqy8aWWa3hfKr z;fom|JqbuTU4$NJMq<{^XiE4A>g>am?WpKU?01IE3wz5}2af9D+4VysBPG=|(}cSm zOGT}|CYijo+(2nVY>t^k$^+6hR~75(Wag#Wu%VLb{(9k3U!?{<%v|ojg7s9ySK7E7 z$R&~7cheGFOHph1|9}?AVnWRJthLmOeqPtG^pDU<2#sDPSlYz7jGE9X-x^WGlRSPS zQD=1R*_$V|9G*vLd3kx7gzZ5g={GbqXj>j=7lz6Z$VgQ#~Wpp(m%Rmr8C z<)UI=O<0W$bRJ>Wd;v{78A09_RCw_tAo6OEx)utwA~P>sev6EseO4Kd4Tv7UO>L7A z)Vfw%R~p6p>+6W*IVUl*sBWXZeo?%pM_XRF4Qce!lwL^aZQ4`yBxS@GzPJ#EUq=(h z|0a>Miao-YUO1JT%VtYQ2%wB=8pLls#4ZlDB5CH*y;TJBE(Rt3oUgCohvUmj7UK}e zS!vUf7b8^eGX#LX@v!Eee94{i%8LqIf*0vNIUyFc<{Sd9tlTK7d0SRl*<0!?{ocJM zcyeCz&dSGQK9(5gC6C5nD{xERp#Su8f2n2CAtN}0<}=uUX1MeGL3#{QL=T`psDetJ znY%ClYgugIb;45paNMygY$)`Ma@-e;cXxMRiIsv%dfn=%A1HJ;Ki7glo`2<*AQATb z>SHN)tp(Sv6}hl*)zjc@b6*1La`yBtH3;O#efLx#kiVW+4!;k|Y6sQul6&RV=C=%H zIhK#;)dyAIpP7U4%JK6W8krCDvS66*JsddK{e)0t+L(df18Kv#g)OSoP-YUv+@tuA z`brdw+`QI?-uNYnoDK4qlOO--r9A?*->EM{muD%=-X8o~6(-J3w~hFrx@l8?48tSA zvPE*$(!kE?b7R=we>KbDEpf>OJ7lWtmvG+LG}#I-Wnm-6H{)mcNR)s-q7^by+2uK( zPwa}al`fjp&AxuIV(H*T$ZH(;4WZM)l`Ov}*2Yw*Xw|*%&9Q1=+u~G}*Hqj;X3-Hn zE((26NN8nH@sD+lbp~?MZip|U(L5s1#>`5Y?^Y?6wKqJ8O8n<=j`S-JE$l+p~!(jBhIFyL-(H4 z*GDhJrfyZR|$STv2EnJpMyK8}q0)YXi=G1aD){W;`% zPw4Gw-L79}I{0*|PTkuLT!OU3Aw@?sVIr;Akv|{D>*>zWucKz49z##)RB05Ap{w}6 zr=$7P^|v(oDR?z3_gwO-7hY(QVwXDClQmyfN}wgETR){0wEBOtjUxs(9-Wd4FOoSe z+ly1ujYfgchWlnLhre||yz$H7&~K@hnpP+y!>dmZA3oK&b$d2V*T}#Vu$sPZ-&raw z)K8+2qX4L6ZE_iyBxFrxW#}DWBrW!oTY;tNwMPHNkJ}qG))_HL#$^S9Vrj*m%RG!ObU%#Kf;YfEu&u4>`F)#IG;cRLm!d=6=EQT|w=b6@HbM+PXTr#T`jqs}g6^de(u%R$)F;8q0 zRFze}>U6=$lZJ*FFbio%igntBBt$nTNJ>UF2x^17sxxnj6uEW})um05L>09+%RDHw zpV#98=l^0A_N_zhB47Bf4J#(n3-VYKa{d)}ca9JtxAZ`WR=i`TEG#y(6OoG_1H`|V zDh!C*)Rb!n&GYJ-c`FA!oSk{TBx6vO9&6iJlHvs2&%DB&2velGm~}^u25DzJ?*Vk~ zZQ0;uFR#4AoIWMvHxcKC@EdAy$5fXoi1c~RBYnM6kh*1MWnI~qii}rYDEh)M+s3T6 z?T@-$S%xHQ$IMe*&K-%!b52fV+?<o~;^M>Q zT`uSz7kp-j9{wnNu-?eLwg18izyV~{YHsF1Hz#qKkZiAkTjyOg!bG1G8z zI{TzPiMj{UF9d57O)1VgONUA|!zt1ND(6=sv~fVd<#PEMJ%)5uXWJ7zyT#viyMD^e z&0mwdM*cp7qOTssg!Gy3U&TiR)3$m&lQR=GW=jKzKA0|8jl|tqy5MlcH)L(r3!j!K z7a2K)&o^OYXq=3xpuI@cN;{CE$TG_@fIqR3yvmQFVLjWnib0UWYRE0eDI_jNyhXMB z$d=?;q2gBGI0SQ-K!7-y;3k@^&BLwOmn0K?-r*7EPB zFrV&Dh}u=kY7kP#!Rd1<{LaT3VTa5+9_;T+O{94-7umsur zY5=>HN}1El@=4A!Iy3fOi@=YQ%I!L+on)%d` z;H7!a6NI8}vD8tEXqGFG;?BbE$B6ct6D(Wss3^&_dFQVG9wHIqAo>30AlS zq?!%;X)-yy%wj%F@leWf5lv)~jz6Z;jz)J+#W{TsxMpFjB zEZ#{rVQuUe*pas{bdk>c@MI5gM(D7IMD0kEaQ84Yh81VUem`(uRs9DapM*mE4c`tg z0WD8)GdLs!Cdqcr$Ow~Pd9G_Ae03Dvkqn!gl0rL4BD<#*6nR5(H8Y>z$of42y@II$ zjZQpD$il1)=RO3L05OF{7UDQ#%S4`S7;c|I!JDJXjn>IGv%yRW>mDHL@wcf)#4(G) zIQcL3L;_we1|{AcZX7I16~CLOJEvVNkpHMe4=nR7s&Djk5fdwEXxxlzEA!h42@3HN zxRE;^sP)MY=yCEq67&IVgA9vMy)1h`GHVG( z)0nSPkGf74IpBmz%vuHRKzb#q9L=w?>kDsPP1_-p5*N3-y$MwtqVJpmBQK#>D&#N8kErPruyC6=CM9 zS**#Ru{}I-R=ni#AYWW(n~s-mH(N+1sl~Om#yo4zt2?}rup(wG3$DlhRO6eAx7=9R zTpH7-Y>&B&2X^WzZ;4+_>xq0v(aL%xDBKu))>l9TqR+(%ByW3$E@JOL@IenQWMWvL zp>z{6i3te&;Dmj!-T&`Pq586n6Wrm>Joftgnb?wkGEePF{|+ksWuSnpq8^Ckn!{H zo97E%6~FM!WQ*LD8=&wi$*}}vQ8mhE;#o^ei#30_PC13dY(4jBn5RP_ku!b>>D_Y2 z^AM#TAfOtv+{32P|H=6HxV3Zwy~re@iWoIR!^89Mckiu@6)f%3IrI0)mWGwQef8g= zDb&*VxVJB!Q{{EmHvcEEeSE=I+xl)&(3eIAt9&sQts5q~rMo}F>cB&3Zrztz@o9`b@#G?mY__tPL z!xqacs=J$R&qj{kNHoPNfa+afBOLWB5)th~o`_N%bh?VOd~>_f^^l!Uzt)_<&t-T7 zE|0#k`1I@1@koD2$`t#nxg6Q!wAK_#nRobqi{<6IMhiOO~EoQ%3J9pys zjgHH%u7m7^y@yT(T~&oNssiWMe{93@jRU%$^=6+w3IsL{Sh%{40j$708~t4ehq_%pOSX#fB*jL3NP!Yua2x4mm7!w_zgDmz8|j2? zUGN+*!>^WwlQt}@L)vV?#`S*z%z+j*q0m4 z=r{yk)WE zVvg}KIB-ciD3K2sP4)g1Kv8LrHB2H0onUivDUbda2d&iECsu|@hmD-W!ordQ<2MH! z(8@jATAQ(uZ4R1*j=tVraIgy=FoVP-MC?|*eze57AlKE!CMun~y+ySHB9EJ4)AUbw zcvCiTvp{qFiIdSi=`OZ82ld@wmXsV<~DqYhZ(C4XlAE59%;M{Y$I;P;N^S* z66~G@zt_a|(xp@oKX!ahUr+t5K{H7Y7#j{`2Yq6HT{0>w_*8&4JhSf*@mtHBxorPR)Ku4*B)5ZjSlwn?=&xkV$UH$Zi_& z69E|IPs_IeV!*9UNuI$N??$5b$d@p$rFB4AHCbC9K+kmM6kuctFb(s`mMF&*9h++n z2uP#dPT(;RHscFnzlDT^Xzq3ft%!1;%3MnWC7X+y*0{xw#Vcmajkz9^*v$p|9uRti z;NmH-#>xv!kR%?l!sQ&0!@Y$zR*BltS2=xoj4#ctcx~tkp;g3m`=LJmHITrbwf^u} za7Ys*4na}eqoNwxcf@G_hdIRS6=0pp<_x4}4)AZYXNsrdi|;~4xPT$MS9^~IjVU!v zK*{cKN2)xfS6Tfp&YNIXCx(WG{6&)(`d*{9r?&=6iou?sVh8iCHLy6|q_LrOcW_|Y z(qd^u*^Vrlt0|ampjq>K`|Q7j%&oKi@4A0w6MIJo%T5iXyv9!&P2{z<)HMt2AAgk! z_WH~?&o9MhBm&{MU(@WAh=s>1FI4-q27>I!v5AX5WavG*a3VO2#ELS*v{|h-`Eh!4 z27|_y$Le6seLm4+$7E6w>r)P7)E1zbdyJ@+RiIZG^9@T(!)$y?GE$;Njuj>xWI$S? zPHfP9foRk(<<9Da1#BwDPbXn>0C=;t3-edzM6B{Ucwe?As_k@7ra=#yZj+@M-t@Ih zBIvP|E)Ra1{R*VkAtT@X(|#Xx;SbcIg}_;rK)Aa!T`$1p#kKKbs8+^6f}H?K?AaU{ zpcB9Lc6&VqKfyL*DdeL0@sOIyKWxQ5I&xP3V)nORD}fHTb|1>FZe0z&N*;8!G8J1G zsC>4sQ_pt&p)zejBw;|aj+O}+r2xbYuAzXG)C1Qmc;7@FfY70$r6FnAV$uaTbDI?T|CvZaXCW^PI0(s=899bU=^do zToa6*PG)U!91-$beRD|Ii{F0x286_{I|~Kk9nkMiMjuWp;AY`uk}!d6=WE&8k$sO z>;FY%{yeGqKU+U@-*!i%N&4}q&0S1l9%^-A4-+;I-9{7%V0iG}fgP_+n*n{&Ze4A8m}9~3d|-#d_Nc9p>2Lhv z=1TI^fPClRzcfUg-{w<`y@<~HMWUsK=$ZhcaQ~D7GfFiFncBu5zLT1))>?W2z#|iU-y8X zuqTgY{Wk|~0aX{ysBREv;jw1$jfR?J+VYqUs0_6ib0YDvBAn@A-zK2vv^cc(#R!Jc zpuifjfn@>jezsj{1fNVe0U!MJ`qI$*X2A%O|0$`08D)o%eB9bx9JJui*K}L4#HHR5 zZ&_)&4muXPR2}AKM%vPnsd&+a2j@-Ia2lBp<~}7+8@P|XxZaT0VW5PZab#3y?EeeD z*r=~}g-CgtWK@`{s&n<3E|wnm048q2D@0{uXnJvuX@v&>8CVG!SCPE0o%^(X$8%5n z-o^5(SPx;0w2AW;$XoY&M2B|-GPvvag zKCRJ)8E$Sa-dYwi^UlMp314u)Ip#S0V>3D-(@0e70vRVLC%23$587&}UWL+4Dyn>> zQEqPUKTCn9W$0Uhof`MPGr$_hoQ3=fZq3OwOaM~~?BW2NHXw{VHlfq2P7 zF)qKqbFJlg1SBZ)LXvOSdG#t;enAR8-oL#3q;Yg;jTUYToLiyrR+KL4@UR=ZjSplS zxtKtp-%}k4Ex5NM#z*O0W^tBnuCB#q|2fas(>`J@BIWxOodRRLygXhZMZ+Xb%y7-j zIG*;JD6Hv`%30}Ol+UE#w=dd?niKgOJq`PC~=bL;DkDR_| zieCqW_$gE_}5O?duzJ!>x6dTiX*jmm8u(&pu76jSL9WNw{;X zNS#+%wwU|q(JU-xViKbs8j1C?T6nHqD_ylQxf4W;W*vqwb?&MBcvl@C!-(JNXyvSR zDEe3Lr7J()=&HY!1f$$k-Rg9R?o+jEa&$=9aaI)=&3vPdTe}B%V%d!Fr`;8>H$rYl zshunG zTN(M+%Eb0Ed<(@e*q8bC(P+1s2SPlyqh_y7O^ literal 0 HcmV?d00001 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 " 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 +