aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfonso S. Siciliano <asiciliano@FreeBSD.org>2022-09-03 14:36:16 +0000
committerAlfonso S. Siciliano <asiciliano@FreeBSD.org>2022-09-03 14:36:16 +0000
commit2c9fd7655ba54e7239f528e1af9fe09662de9b03 (patch)
treefe1ff8f189880e6177658fee195a574d5ae6ebe7
parent2f8d4418415511460bd7b3b3e532f6b328cf993f (diff)
contrib/bsddialog: Import version 0.3vendor/bsddialog/0.3
New features overview: * Unicode. User interface handles multi-column characters. API can handle char* like a multibyte character string. Internally wide characters are used for keyboard input, to adapt word wrapping and dynamic text auto-sizing for multi-column characters. * Forms refactoring. Complete rewrite deleting libformw dependency. * Theme. New utility options to save and load custom theme at run-time. * TUI navigation. Added keys to navigate input components. Changed default focus behavior of input dialogs to be LGPL-dialog-like; a new option can set the previous whiptail-like behavior. See /usr/src/contrib/bsddialog/CHANGELOG '2022-08-29 Version 0.3' for more detailed information.
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG77
-rw-r--r--GNUMakefile2
-rw-r--r--Makefile2
-rw-r--r--README.md25
-rw-r--r--bsddialog.1216
-rw-r--r--bsddialog.c260
-rwxr-xr-xexamples_library/compile4
-rw-r--r--examples_library/datebox.c4
-rw-r--r--examples_library/form.c12
-rw-r--r--examples_library/formw.c61
-rw-r--r--examples_library/timebox.c4
-rwxr-xr-xexamples_utility/form.sh10
-rwxr-xr-xexamples_utility/mixedform.sh6
-rwxr-xr-xexamples_utility/passwordform.sh10
-rw-r--r--lib/GNUMakefile6
-rw-r--r--lib/Makefile4
-rw-r--r--lib/barbox.c78
-rw-r--r--lib/bsddialog.3172
-rw-r--r--lib/bsddialog.h20
-rw-r--r--lib/bsddialog_theme.h17
-rw-r--r--lib/formbox.c1145
-rw-r--r--lib/infobox.c6
-rw-r--r--lib/lib_util.c551
-rw-r--r--lib/lib_util.h16
-rw-r--r--lib/libbsddialog.c19
-rw-r--r--lib/menubox.c155
-rw-r--r--lib/messagebox.c63
-rw-r--r--lib/textbox.c117
-rw-r--r--lib/theme.c187
-rw-r--r--lib/timebox.c190
-rw-r--r--util_theme.c356
-rw-r--r--util_theme.h35
33 files changed, 2670 insertions, 1162 deletions
diff --git a/.gitignore b/.gitignore
index 62f7b594a708..10a6663fbb47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ examples_library/checklist
examples_library/datebox
examples_library/form
examples_library/formw
+examples_library/margin
examples_library/menu
examples_library/mixedlist
examples_library/radiolist
@@ -19,6 +20,7 @@ examples_library/rangebox
examples_library/sade
examples_library/timebox
examples_library/yesno
+examples_library/u_msgbox
*.gz
lib/libbsddialog.so*
BSDDIALOG.geany
diff --git a/CHANGELOG b/CHANGELOG
index 22eb3342cfe2..d6de6928c111 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,77 @@
-2022-03-02 version 0.2
+2022-08-29 Version 0.3
+
+ Utility:
+ * add: --textbox accepts options for the first button.
+ * add: --columns-per-row option for text autosizing.
+ * add: --load-theme option to read and set a custom theme at runtime.
+ * add: --save-theme option to save current theme.
+ * add: --bikeshed option for random settings.
+ * add: --switch-buttons enables focus switching: buttons / input
+ components. Available for: --form, --inputbox, --mixedform,
+ --passwordform, --passwordbox, --timebox and --datebox.
+ * change: rename --esc-cancelvalue to --esc-return-cancel.
+ * change: form field value is printed like multibyte charachter string,
+ previously widechar string.
+ * fix: --hline with empty string.
+ * fix: avoid to overlay the backtitle by setting a top margin.
+ * fix: avoid to overlay down shadow with menus and forms bottomdesc
+ by setting a down margin.
+ * fix: --form read-only flag with multiple fields.
+
+ Library:
+ * add: conf.auto_topmargin and conf.auto_downmargin.
+ * add: bsddialog_textbox() accepts conf.button.* for the first button.
+ * add: bsddialog_textbox() arrows and percentage.
+ * add: conf.text.cols_per_row to set a ratio for text autosizing.
+ * add: timebox and datebox arrows and focus background for boxes.
+ * add: timebox and datebox UP key to switch focus.
+ * add: bsddialog_init_notheme() in bsddialo_theme.h.
+ * add: bsddialog_hascolors() in bsddialo_theme.h.
+ * add: theme.form.bottomdesccolor and theme.menu.bottomdesccolor.
+ * add: conf.button.always_active to disable buttons/input-boxes switch.
+ * add: dynamic buttons margin.
+ - add: theme.button.minmargin and theme.button.maxmargin.
+ - delete: theme.button.hmargin.
+ * add: Unicode.
+ - UI handles multicolumn charachters: backtitle, title,
+ text (word wrapping, autosizing), menus (shortcuts, name, desc),
+ forms (label, field), textbox, mixedgauge (minilabel),
+ buttons (label, shortcuts), bottomtitle.
+ - API handles char* arguments like multibyte charachter string,
+ depending on the current locale.
+ - Internally wide charachters are used to get input from keyboard
+ and to adapt word wrapping and dynamic text autosizing to
+ muticolumn charachters.
+ * refactoring: (rewrite) form.c.
+ - delete: libformw dep implementing its features from scratch.
+ - delete: maxvaluelen >= valuelen constraint.
+ - delete: conf.form.enable_wchar, get always unicode (wchar) input.
+ - add: KEY_HOME, KEY_END, KEY_PPAGE, KEY_NPAGE keys in field.
+ - add: KEY_UP can move focus from buttons to fields.
+ - add: KEY_DOWN can move focus from item to buttons, if nitem is 1.
+ - add: conf.form.securembch secure multibyte charachter.
+ - add: BSDDIALOG_FIELDNOCOLOR for formitem.flags.
+ - add: BSDDIALOG_FIELDCURSOREND for formitem.flags.
+ - add: BSDDIALOG_FIELDEXTEND for formitem.flags.
+ - add: BSDDIALOG_FIELDSINGLEBYTE for formitem.flags.
+ - add: resizing and refresh after KEY_RESIZE (SIGWINCH).
+ - add: items scrolling.
+ - add: conf.form.value_wchar, value is wchar_t* instead of MB-char*.
+ - add: formheight autosizing.
+ - add: dynamic item position.
+ * fix: bsddialog_gauge() with fd < 0.
+ * fix: internal segmentation fault with disabled shadow.
+ * fix: bsddialog_gauge() refresh new text.
+ * fix: center position without shadow.
+ * fix: bsddialog_infobox() with zero text length.
+ * fix: text wrapping with more than 1024 words.
+ * fix: rename theme.shadow.h to theme.shadow.y.
+ * fix: rename theme.shadow.w to theme.shadow.x.
+ * fix: menurows autosize with fixed rows improving text_size().
+ * fix: messagebox.c scrolling and checksize without text.
+
+
+2022-03-02 Version 0.2
Utility:
* add: (this) CHANGELOG.
@@ -31,7 +104,7 @@
* improve: "menus" colors for accessibility.
-2022-01-27 version 0.1
+2022-01-27 Version 0.1
* Common-Options: --ascii-lines, --backtitle <backtitle>, --begin-x <x>,
--begin-y <y>, --cancel-label <label>, --clear, --colors, --cr-wrap,
diff --git a/GNUMakefile b/GNUMakefile
index ad3d4f55f4a7..d57c6248d02d 100644
--- a/GNUMakefile
+++ b/GNUMakefile
@@ -4,7 +4,7 @@
# Written in 2021 by Alfonso Sabato Siciliano
OUTPUT= bsddialog
-SOURCES= bsddialog.c
+SOURCES= bsddialog.c util_theme.c
OBJECTS= $(SOURCES:.c=.o)
LIBPATH= ./lib
LIBBSDDIALOG= $(LIBPATH)/libbsddialog.so
diff --git a/Makefile b/Makefile
index 5d5d0cc923a5..344233581d30 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# Written in 2021 by Alfonso Sabato Siciliano
OUTPUT= bsddialog
-SOURCES= bsddialog.c
+SOURCES= bsddialog.c util_theme.c
OBJECTS= ${SOURCES:.c=.o}
LIBPATH= ${.CURDIR}/lib
LIBBSDDIALOG= ${LIBPATH}/libbsddialog.so
diff --git a/README.md b/README.md
index 3a814b38ddb4..016995b232ae 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,13 @@
-# BSDDialog 0.2
+# BSDDialog 0.3
-
-This project provides **bsddialog** and **libbsddialog**, an utility and a
-library to build scripts and tools with TUI dialogs and widgets.
+This project provides **bsddialog** and **libbsddialog**, an utility
+and a library to build scripts and tools with TUI dialogs and widgets.
## Intro
Briefly:
-<https://www.freebsd.org/status/report-2021-04-2021-06/#_bsddialog_tui_widgets>
+<https://www.freebsd.org/status/report-2021-04-2021-06/bsddialog/>
Utility:
<https://alfonsosiciliano.gitlab.io/posts/2021-12-07-bsddialog.html>
@@ -31,6 +30,15 @@ FreeBSD:
% ./bsddialog --msgbox "Hello World!" 8 20
```
+Linux:
+
+```
+% git clone https://gitlab.com/alfix/bsddialog.git
+% cd bsddialog
+% make -f GNUMakefile
+% ./bsddialog --msgbox "Hello World!" 8 20
+```
+
Output:
![screenshot](screenshot.png)
@@ -101,6 +109,7 @@ in the _Public Domain_ to build new projects:
```
% cd examples_library
% sh compile
+% ./checklist
% ./datebox
% ./form
% ./infobox
@@ -114,4 +123,10 @@ in the _Public Domain_ to build new projects:
% ./timebox
% ./yesno
```
+
+
+## TODO and Ideas
+ - menubar feature
+ - key callback
+ - Right-To-Left text
diff --git a/bsddialog.1 b/bsddialog.1
index c87b760d2ea3..0bf8dd9dc3af 100644
--- a/bsddialog.1
+++ b/bsddialog.1
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 3, 2022
+.Dd August 29, 2022
.Dt BSDDIALOG 1
.Os
.Sh NAME
@@ -74,6 +74,13 @@ Title on the top side of the screen.
Dialog horizontal position, 0 is the left screen side, -1 center.
.It Fl Fl begin-y Ar y
Dialog vertical position, 0 is the top screen side, -1 center.
+.It Fl Fl bikeshed
+Random settings.
+Colors.
+Delimiter and margins around the title.
+Buttons always active or TAB to switch focus with input components, see
+.Fl Fl switch-buttons .
+Zero padding with time or date output.
.It Fl Fl cancel-label Ar label
Label for the
.Dq Cancel
@@ -100,7 +107,7 @@ cyan.
.It Dq \eZ7
white.
.It Dq \eZr
-reverse foreground and background colors.
+reverse foreground and background.
.It Dq \eZR
disable reverse.
.It Dq \eZb
@@ -112,8 +119,11 @@ underline.
.It Dq \eZU
disable underline.
.It Dq \eZn
-restore to normal text.
+restore normal text.
.El
+.It Fl Fl columns-per-row Ar columns
+Try to set the number of columns for a row of text with autosizing; default
+.Dv 10 .
.It Fl Fl cr-wrap
Replace new line with a space in
.Ar text .
@@ -141,7 +151,7 @@ Equivalent to
.Fl Fl default-no .
.It Fl Fl disable-esc
Disable ESC key to quit.
-.It Fl Fl esc-cancelvalue
+.It Fl Fl esc-return-cancel
Exits with the
.Dq Cancel
button value if the ESC key is pressed.
@@ -197,8 +207,7 @@ Do not exit with unknown options.
.It Fl Fl insecure
Print
.Sq *
-to hide passwords while typing, default space
-.Sq " " .
+to hide passwords while typing; whitespace otherwise.
.It Fl Fl item-depth
Specify a margin for items, available for Checklist, Menu and Radiolist.
.It Fl Fl item-help
@@ -206,9 +215,12 @@ Set a help string for each element of a Checklist, Form, Menu, Mixedform,
Passwordform, Radiolist and Treeview to display at the bottom screen side.
.It Fl Fl item-prefix
Set a string to prefix each item of a Checklist, Menu, Radiolist or Treeview.
+.It Fl Fl load-theme Ar file
+Load theme from
+.Ar file .
.It Fl Fl max-input Ar size
Maximum length of the input for
-.Fl Fl input-box
+.Fl Fl inputbox
ans
.Fl Fl passwordbox ,
default 2048.
@@ -262,6 +274,8 @@ Print Dialog height and widget at exit.
Print version.
.It Fl Fl quoted
Quote items in output, default only when necessary.
+.It Fl Fl save-theme Ar file
+Save the current theme.
.It Fl Fl separate-output
Separate selected items with a new line and avoid to quote.
.It Fl Fl separator Ar sep
@@ -279,6 +293,18 @@ seconds to close the dialog.
Print input from user interface to standand error, default.
.It Fl Fl stdout
Print input from user interface to standard output.
+.It Fl Fl switch-buttons
+enables focus switching between buttons and input components pressing TAB,
+otherwise buttons are always active and ENTER key closes the dialog.
+Suitable for:
+.Fl Fl form ,
+.Fl Fl inputbox ,
+.Fl Fl mixedform ,
+.Fl Fl passwordbox ,
+.Fl Fl passwordform ,
+.Fl Fl timebox
+and
+.Fl Fl datebox .
.It Fl Fl tab-len Ar spaces
Number of spaces to print a TAB in
.Ar text .
@@ -319,7 +345,7 @@ is the graphical height of the list, 0 for autosize.
.It Fl Fl datebox Ar text Ar rows Ar cols Op Ar year Ar month Ar day
Dialog to select a date.
.It Fl Fl form Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
-Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxvaluelen Oc ...
+Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters Oc ...
Dialog to get a list of strings via forms.
A form has a
.Ar label
@@ -333,19 +359,21 @@ and
.Ar xfield
with graphical length
.Ar fieldlen ,
-.Ar maxvaluelen
+.Ar maxletters
is the maximum input length.
The field can be customized, if
.Ar fieldlen
-is 0 its length is the absolute value of
-.Ar maxvaluelen ,
-if
-.Ar maxvaluelen
-is negative the field is read only,
+is negative the field is read only and its absolute value is the field length.
+If
+.Ar maxletters
+is 0 it is the absolute value of
+.Ar fieldlen .
.Ar init
is a default value.
.Ar formrows
-is the graphical height of the list, has to be at least the number of forms.
+is the graphical height of the list,
+.Dv 0
+for autosize.
.It Fl Fl gauge Ar text Ar rows Ar cols Op Ar percentage
Dialog with a bar to shows
.Ar percentage ,
@@ -374,7 +402,7 @@ The name of the selected item is printed to standard error.
.Ar menurows
is the graphical height of the list, 0 for autosize.
.It Fl Fl mixedform Ar text Ar rows Ar cols Ar formrows Oo Ar label Ar ylabel \
-Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxvaluelen Ar flag Oc ...
+Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters Ar flag Oc ...
Dialog to get a list of strings via forms.
A form has a
.Ar label
@@ -388,7 +416,7 @@ at the position
.Ar yfield
and
.Ar xfield ,
-.Ar maxvaluelen
+.Ar maxletters
is the maximum input length,
.Ar init
is a default value,
@@ -396,7 +424,9 @@ is a default value,
can be 0 for normal field, 1 to hide the typed characters and 2 to set the
field read only.
.Ar formrows
-is the graphical height of the list, has to be at least the number of forms.
+is the graphical height of the list,
+.Dv 0
+for autosize.
.It Fl Fl mixedgauge Ar text Ar rows Ar cols Ar mainperc Oo Ar minilabel \
Ar miniperc Oc ...
Dialog to show a main bar to represent
@@ -436,7 +466,8 @@ Dialog to get a password,
.Ar init
is the default value.
.It Fl Fl passwordform Ar text Ar rows Ar cols Ar formrows Oo Ar label \
-Ar ylabel Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar valuelen Oc ...
+Ar ylabel Ar xlabel Ar init Ar yfield Ar xfield Ar fieldlen Ar maxletters \
+Oc ...
Dialog to get a list of passwords, equivalent to
.Fl Fl form
except typed characters are hidden.
@@ -531,14 +562,39 @@ Backtitle, title and message:
Yes-No Question and theme:
.Dl bsddialog --theme blackwhite --yesno Question 10 30
.Pp
+Save a custom theme:
+.Dl bsddialog --save-theme mytheme.txt --infobox \*qSaving theme...\*q 0 0
+.Pp
+Load a custom theme:
+.Dl bsddialog --load-theme mytheme.txt --infobox \*qCustom theme\*q 0 0
+.Pp
Checklist:
.Dl bsddialog --checklist Checklist 0 0 3 N1 \&D1 off N2 D2 on N3 D3 off
.Pp
+Form:
+.Dl bsddialog --form Form 0 0 0 L1: 0 0 X 0 4 20 25 L2: 1 0 Y 1 4 20 25
+.Pp
+Bikeshed:
+.Dl bsddialog --bikeshed --inputbox Example 0 0
+.Pp
Mixedgauge:
-.Dl bsddialog --sleep 3 --mixedgauge Example 10 30 60 L1 "\(dq" -1" L2 30
+.Dl bsddialog --sleep 3 --mixedgauge Example 10 30 60 L1 \*q -1\*q L2 30
.Pp
-Form:
-.Dl bsddialog --form Form 0 0 2 L1: 1 1 X 1 5 20 25 L2: 2 1 X 2 5 20 25
+Mixedgauge script:
+.Bd -literal -offset indent -compact
+perc=0
+while [ $perc -le 100 ]
+do
+ bsddialog --sleep 1 --title Mixedgauge \e
+ --mixedgauge "\enExample...\en" 0 0 $perc \e
+ "Hidden" " -9" \e
+ "Label 1" " -4" \e
+ "Label 2" " -4" \e
+ "Label 3" $perc
+
+ perc=`expr $perc + 20`
+done
+.Ed
.Pp
Gauge script:
.Bd -literal -offset indent -compact
@@ -558,22 +614,6 @@ do
i=`expr $i + 1`
done | bsddialog --title Gauge --gauge "Starting..." 10 70
.Ed
-.Pp
-Mixedgauge script:
-.Bd -literal -offset indent -compact
-perc=0
-while [ $perc -le 100 ]
-do
- bsddialog --sleep 1 --title Mixedgauge \e
- --mixedgauge "\enExample...\en" 0 0 $perc \e
- "Hidden" " -9" \e
- "Label 1" " -4" \e
- "Label 2" " -4" \e
- "Label 3" $perc
-
- perc=`expr $perc + 20`
-done
-.Ed
.Sh SEE ALSO
.Xr bsddialog 3
.Sh HISTORY
@@ -584,7 +624,99 @@ utility first appeared in
.Sh AUTHORS
.Nm bsddialog
was written by
-.An Alfonso Sabato Siciliano Aq Mt alf.siciliano@gmail.com .
-.Sh BUGS
-Forms do not resize the dialog after a terminal change and do not provide
-scrolling for items. \ No newline at end of file
+.An Alfonso Sabato Siciliano
+.Aq Mt asiciliano@FreeBSD.org .
+.Pp
+.Nm bsddialog
+provides a subset of the functionality described in the
+.Nm dialog
+manual.
+The following features were reimplemented:
+.Pp
+Common options:
+.Fl Fl ascii-lines ,
+.Fl Fl backtitle ,
+.Fl Fl cancel-label ,
+.Fl Fl clear ,
+.Fl Fl colors ,
+.Fl Fl cr-wrap ,
+.Fl Fl date-format ,
+.Fl Fl defaultno ,
+.Fl Fl default-button ,
+.Fl Fl default-no ,
+.Fl Fl default-item ,
+.Fl Fl exit-label ,
+.Fl Fl extra-button ,
+.Fl Fl extra-label ,
+.Fl Fl help ,
+.Fl Fl help-button ,
+.Fl Fl help-label ,
+.Fl Fl help-status ,
+.Fl Fl help-tags ,
+.Fl Fl hfile ,
+.Fl Fl hline ,
+.Fl Fl ignore ,
+.Fl Fl insecure ,
+.Fl Fl item-help ,
+.Fl Fl max-input ,
+.Fl Fl no-cancel ,
+.Fl Fl nocancel ,
+.Fl Fl no-collapse ,
+.Fl Fl no-items ,
+.Fl Fl no-label ,
+.Fl Fl no-lines ,
+.Fl Fl no-nl-expand ,
+.Fl Fl no-ok ,
+.Fl Fl nook ,
+.Fl Fl no-shadow ,
+.Fl Fl no-tags ,
+.Fl Fl ok-label ,
+.Fl Fl output-fd ,
+.Fl Fl output-separator ,
+.Fl Fl print-maxsize ,
+.Fl Fl print-size ,
+.Fl Fl print-version ,
+.Fl Fl quoted ,
+.Fl Fl separate-output ,
+.Fl Fl separator ,
+.Fl Fl shadow ,
+.Fl Fl single-quoted ,
+.Fl Fl sleep ,
+.Fl Fl stderr ,
+.Fl Fl stdout ,
+.Fl Fl tab-len ,
+.Fl Fl time-format ,
+.Fl Fl title ,
+.Fl Fl trim ,
+.Fl Fl version ,
+.Fl Fl yes-label .
+.Pp
+Dialogs:
+.Fl Fl checklist ,
+.Fl Fl form ,
+.Fl Fl gauge ,
+.Fl Fl infobox ,
+.Fl Fl inputbox ,
+.Fl Fl menu ,
+.Fl Fl mixedform ,
+.Fl Fl mixedgauge ,
+.Fl Fl msgbox ,
+.Fl Fl passwordbox ,
+.Fl Fl passwordform ,
+.Fl Fl pause ,
+.Fl Fl radiolist ,
+.Fl Fl rangebox ,
+.Fl Fl textbox ,
+.Fl Fl timebox ,
+.Fl Fl treeview ,
+.Fl Fl yesno .
+.Pp
+Some feature differs in input, output, or behavior.
+Compatibility is not a priority for future development.
+.Sh THANKS TO
+.An Baptiste Daroussin
+.Aq Mt bapt@FreeBSD.org
+and
+.An \&Ed Maste
+.Aq Mt emaste@FreeBSD.org
+for suggestions, help, and testing.
diff --git a/bsddialog.c b/bsddialog.c
index a902d751dab0..bfd6d8dbc5b7 100644
--- a/bsddialog.c
+++ b/bsddialog.c
@@ -39,7 +39,9 @@
#include <bsddialog.h>
#include <bsddialog_theme.h>
-#define BSDDIALOG_VERSION "0.2"
+#include "util_theme.h"
+
+#define BSDDIALOG_VERSION "0.3"
enum OPTS {
/* Common options */
@@ -47,16 +49,18 @@ enum OPTS {
BACKTITLE,
BEGIN_X,
BEGIN_Y,
+ BIKESHED,
CANCEL_LABEL,
CLEAR,
COLORS,
+ COLUMNS_PER_ROW,
CR_WRAP,
DATE_FORMAT,
DEFAULT_BUTTON,
DEFAULT_ITEM,
DEFAULT_NO,
DISABLE_ESC,
- ESC_CANCELVALUE,
+ ESC_RETURNCANCEL,
EXIT_LABEL,
EXTRA_BUTTON,
EXTRA_LABEL,
@@ -75,6 +79,7 @@ enum OPTS {
ITEM_DEPTH,
ITEM_HELP,
ITEM_PREFIX,
+ LOAD_THEME,
MAX_INPUT,
NO_CANCEL,
NO_COLLAPSE,
@@ -91,12 +96,14 @@ enum OPTS {
PRINT_SIZE,
PRINT_VERSION,
QUOTED,
+ SAVE_THEME,
SEPARATE_OUTPUT,
SHADOW,
SINGLE_QUOTED,
SLEEP,
STDERR,
STDOUT,
+ SWITCH_BUTTONS,
TAB_LEN,
THEME,
TIME_FORMAT,
@@ -136,15 +143,16 @@ static char *date_fmt_opt, *time_fmt_opt;
static int unsigned max_input_form_opt;
/* General options */
static int output_fd_opt;
+bool bikeshed_opt;
+/* Functions */
+static void sigint_handler(int sig);
static void
custom_text(bool cr_wrap, bool no_collapse, bool no_nl_expand, bool trim,
char *text, char *buf);
-
-static void sigint_handler(int sig);
-
+static void errorexit(char *errbuf);
/* Dialogs */
-#define BUILDER_ARGS struct bsddialog_conf conf, char* text, int rows, \
+#define BUILDER_ARGS struct bsddialog_conf *conf, char* text, int rows, \
int cols, int argc, char **argv, char *errbuf
static int checklist_builder(BUILDER_ARGS);
static int datebox_builder(BUILDER_ARGS);
@@ -176,23 +184,24 @@ static void usage(void)
printf("Common Options:\n");
printf("--ascii-lines, --backtitle <backtitle>, --begin-x <x>, "
- "--begin-y <y>, --cancel-label <label>, --clear, --colors, "
- "--cr-wrap, --date-format <format>, --defaultno, "
- "--default-button <label>, --default-no, --default-item <name>, "
- "--disable-esc, --esc-cancelvalue, --exit-label <label>, "
- "--extra-button, --extra-label <label>, "
- "--generic-button1 <label>, --generic-button2 <label>, --help, "
- "--help-button, --help-label <label>, --help-status, --help-tags, "
- "--hfile <filename>, --hline <string>, --hmsg <string>, --ignore, "
- "--insecure, --item-depth, --item-help, --items-prefix, "
- "--max-input <size>, --no-cancel, --nocancel, --no-collapse, "
- "--no-items, --no-label <label>, --no-lines, --no-nl-expand, "
- "--no-ok, --nook, --no-shadow, --no-tags, --ok-label <label>, "
- "--output-fd <fd>, --output-separator <sep>, --print-maxsize, "
- "--print-size, --print-version, --quoted, --separate-output, "
- "--separator <sep>, --shadow, --single-quoted, --sleep <secs>, "
- "--stderr, --stdout, --tab-len <spaces>, "
- "--theme <blackwhite|bsddialog|flat|dialog>, "
+ "--begin-y <y>, --bikeshed, --cancel-label <label>, --clear, "
+ "--colors, --columns-per-row <columns>, --cr-wrap, "
+ "--date-format <format>, --default-button <label>, "
+ "--default-item <name>, --default-no, --disable-esc, "
+ "--esc-return-cancel, --exit-label <label>, --extra-button, "
+ "--extra-label <label>, --generic-button1 <label>, "
+ "--generic-button2 <label>, --help, --help-button, "
+ "--help-label <label>, --help-status, --help-tags, --hfile <file>, "
+ "--hline <string>, --hmsg <string>, --ignore, --insecure, "
+ "--item-depth, --item-help, --item-prefix, --load-theme <file>, "
+ "--max-input <size>, --no-cancel, --no-collapse, --no-items, "
+ "--no-label <label>, --no-lines, --no-nl-expand, --no-ok, "
+ "--no-shadow, --no-tags, --ok-label <label>, --output-fd <fd>, "
+ "--output-separator <sep>, --print-maxsize, --print-size, "
+ "--print-version, --quoted, --save-theme <file>, "
+ "--separate-output, --separator <sep>, --shadow, --single-quoted, "
+ "--sleep <secs>, --stderr, --stdout, --tab-len <spaces>, "
+ "--switch-buttons, --theme <blackwhite|bsddialog|flat|dialog>, "
"--time-format <format>, --title <title>, --trim, --version, "
"--yes-label <label>.\n");
printf("\n");
@@ -202,14 +211,14 @@ static void usage(void)
"<on|off>] ...\n");
printf("--datebox <text> <rows> <cols> [<yy> <mm> <dd>]\n");
printf("--form <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxvaluelen>] "
+ "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters>] "
"...\n");
printf("--gauge <text> <rows> <cols> [<perc>]\n");
printf("--infobox <text> <rows> <cols>\n");
printf("--inputbox <text> <rows> <cols> [init]\n");
printf("--menu <text> <rows> <cols> <menurows> [<name> <desc>] ...\n");
printf("--mixedform <text> <rows> <cols> <formrows> [<label> <ylabel> "
- "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxvaluelen> "
+ "<xlabel> <init> <yfield> <xfield> <fieldlen> <maxletters> "
"<0|1|2>] ...\n");
printf("--mixedgauge <text> <rows> <cols> <mainperc> [<minilabel> "
"<miniperc>] ...\n");
@@ -217,7 +226,7 @@ static void usage(void)
printf("--passwordbox <text> <rows> <cols> [init]\n");
printf("--passwordform <text> <rows> <cols> <formrows> [<label> "
"<ylabel> <xlabel> <init> <yfield> <xfield> <fieldlen> "
- "<maxvaluelen>] ...\n");
+ "<maxletters>] ...\n");
printf("--pause <text> <rows> <cols> <secs>\n");
printf("--radiolist <text> <rows> <cols> <menurows> [<name> <desc> "
"<on|off>] ...\n");
@@ -235,11 +244,12 @@ static void usage(void)
int main(int argc, char *argv[argc])
{
bool cr_wrap_opt, no_collapse_opt, no_nl_expand_opt, trim_opt;
- bool esc_cancelvalue_opt, ignore_opt, print_maxsize_opt;;
- int input, rows, cols, output, getH, getW;
+ bool esc_return_cancel_opt, ignore_opt, print_maxsize_opt;
+ bool textfromfile;
+ int input, rows, cols, retval, getH, getW;
int (*dialogbuilder)(BUILDER_ARGS) = NULL;
enum bsddialog_default_theme theme_opt;
- char *text, *backtitle_opt;
+ char *text, *backtitle_opt, *loadthemefile, *savethemefile;
char errorbuilder[1024];
struct winsize ws;
struct bsddialog_conf conf;
@@ -250,7 +260,7 @@ int main(int argc, char *argv[argc])
conf.key.enable_esc = true;
conf.menu.on_without_ok = true;
conf.form.value_without_ok = true;
- conf.form.enable_wchar = true;
+ conf.button.always_active = true;
backtitle_opt = NULL;
theme_opt = BSDDIALOG_THEME_FLAT;
@@ -258,8 +268,12 @@ int main(int argc, char *argv[argc])
print_maxsize_opt = false;
ignore_opt = false;
cr_wrap_opt = no_collapse_opt = no_nl_expand_opt = trim_opt = false;
- esc_cancelvalue_opt = false;
+ esc_return_cancel_opt = false;
+ textfromfile = false;
+ bikeshed_opt = false;
errorbuilder[0] = '\0';
+ savethemefile = NULL;
+ loadthemefile = NULL;
item_output_sepnl_opt = item_singlequote_opt = false;
item_prefix_opt = item_bottomdesc_opt = item_depth_opt = false;
@@ -279,6 +293,7 @@ int main(int argc, char *argv[argc])
{"backtitle", required_argument, NULL, BACKTITLE},
{"begin-x", required_argument, NULL, BEGIN_X},
{"begin-y", required_argument, NULL, BEGIN_Y},
+ {"bikeshed", no_argument, NULL, BIKESHED},
{"cancel-label", required_argument, NULL, CANCEL_LABEL},
{"clear", no_argument, NULL, CLEAR},
{"colors", no_argument, NULL, COLORS},
@@ -289,7 +304,7 @@ int main(int argc, char *argv[argc])
{"default-item", required_argument, NULL, DEFAULT_ITEM},
{"default-no", no_argument, NULL, DEFAULT_NO},
{"disable-esc", no_argument, NULL, DISABLE_ESC},
- {"esc-cancelvalue", no_argument, NULL, ESC_CANCELVALUE},
+ {"esc-return-cancel",no_argument, NULL, ESC_RETURNCANCEL},
{"exit-label", required_argument, NULL, EXIT_LABEL},
{"extra-button", no_argument, NULL, EXTRA_BUTTON},
{"extra-label", required_argument, NULL, EXTRA_LABEL},
@@ -308,6 +323,7 @@ int main(int argc, char *argv[argc])
{"item-depth", no_argument, NULL, ITEM_DEPTH},
{"item-help", no_argument, NULL, ITEM_HELP},
{"item-prefix", no_argument, NULL, ITEM_PREFIX},
+ {"load-theme", required_argument, NULL, LOAD_THEME},
{"max-input", required_argument, NULL, MAX_INPUT},
{"no-cancel", no_argument, NULL, NO_CANCEL},
{"nocancel", no_argument, NULL, NO_CANCEL},
@@ -327,6 +343,8 @@ int main(int argc, char *argv[argc])
{"print-size", no_argument, NULL, PRINT_SIZE},
{"print-version", no_argument, NULL, PRINT_VERSION},
{"quoted", no_argument, NULL, QUOTED},
+ {"columns-per-row", required_argument, NULL, COLUMNS_PER_ROW},
+ {"save-theme", required_argument, NULL, SAVE_THEME},
{"separate-output", no_argument, NULL, SEPARATE_OUTPUT},
{"separator", required_argument, NULL, OUTPUT_SEPARATOR},
{"shadow", no_argument, NULL, SHADOW},
@@ -334,6 +352,7 @@ int main(int argc, char *argv[argc])
{"sleep", required_argument, NULL, SLEEP},
{"stderr", no_argument, NULL, STDERR},
{"stdout", no_argument, NULL, STDOUT},
+ {"switch-buttons", no_argument, NULL, SWITCH_BUTTONS},
{"tab-len", required_argument, NULL, TAB_LEN},
{"theme", required_argument, NULL, THEME},
{"time-format", required_argument, NULL, TIME_FORMAT},
@@ -373,6 +392,8 @@ int main(int argc, char *argv[argc])
break;
case BACKTITLE:
backtitle_opt = optarg;
+ if (conf.y == BSDDIALOG_CENTER)
+ conf.auto_topmargin = 2;
break;
case BEGIN_X:
conf.x = (int)strtol(optarg, NULL, 10);
@@ -389,6 +410,10 @@ int main(int argc, char *argv[argc])
conf.y, BSDDIALOG_CENTER);
return (255);
}
+ conf.auto_topmargin = 0;
+ break;
+ case BIKESHED:
+ bikeshed_opt = true;
break;
case CANCEL_LABEL:
conf.button.cancel_label = optarg;
@@ -399,6 +424,10 @@ int main(int argc, char *argv[argc])
case COLORS:
conf.text.highlight = true;
break;
+ case COLUMNS_PER_ROW:
+ conf.text.cols_per_row =
+ (u_int)strtoul(optarg, NULL, 10);
+ break;
case CR_WRAP:
cr_wrap_opt = true;
break;
@@ -417,8 +446,8 @@ int main(int argc, char *argv[argc])
case DISABLE_ESC:
conf.key.enable_esc = false;
break;
- case ESC_CANCELVALUE:
- esc_cancelvalue_opt = true;
+ case ESC_RETURNCANCEL:
+ esc_return_cancel_opt = true;
break;
case EXIT_LABEL:
conf.button.ok_label = optarg;
@@ -454,7 +483,8 @@ int main(int argc, char *argv[argc])
conf.key.f1_file = optarg;
break;
case HLINE:
- conf.bottomtitle = optarg;
+ if (optarg[0] != '\0')
+ conf.bottomtitle = optarg;
break;
case HMSG:
conf.key.f1_message = optarg;
@@ -474,6 +504,9 @@ int main(int argc, char *argv[argc])
case ITEM_PREFIX:
item_prefix_opt = true;
break;
+ case LOAD_THEME:
+ loadthemefile = optarg;
+ break;
case MAX_INPUT:
max_input_form_opt = (u_int)strtoul(optarg, NULL, 10);
break;
@@ -523,6 +556,9 @@ int main(int argc, char *argv[argc])
case PRINT_VERSION:
printf("bsddialog version %s\n", BSDDIALOG_VERSION);
break;
+ case SAVE_THEME:
+ savethemefile = optarg;
+ break;
case SEPARATE_OUTPUT:
item_output_sepnl_opt = true;
break;
@@ -541,6 +577,9 @@ int main(int argc, char *argv[argc])
case STDOUT:
output_fd_opt = STDOUT_FILENO;
break;
+ case SWITCH_BUTTONS:
+ conf.button.always_active = false;
+ break;
case TAB_LEN:
conf.text.tablen = (u_int)strtoul(optarg, NULL, 10);
break;
@@ -574,12 +613,14 @@ int main(int argc, char *argv[argc])
/* Dialogs */
case CHECKLIST:
dialogbuilder = checklist_builder;
+ conf.auto_downmargin = 1;
break;
case DATEBOX:
dialogbuilder = datebox_builder;
break;
case FORM:
dialogbuilder = form_builder;
+ conf.auto_downmargin = 1;
break;
case GAUGE:
dialogbuilder = gauge_builder;
@@ -589,12 +630,15 @@ int main(int argc, char *argv[argc])
break;
case INPUTBOX:
dialogbuilder = inputbox_builder;
+ conf.auto_downmargin = 1;
break;
case MENU:
dialogbuilder = menu_builder;
+ conf.auto_downmargin = 1;
break;
case MIXEDFORM:
dialogbuilder = mixedform_builder;
+ conf.auto_downmargin = 1;
break;
case MIXEDGAUGE:
dialogbuilder = mixedgauge_builder;
@@ -607,24 +651,29 @@ int main(int argc, char *argv[argc])
break;
case PASSWORDBOX:
dialogbuilder = passwordbox_builder;
+ conf.auto_downmargin = 1;
break;
case PASSWORDFORM:
dialogbuilder = passwordform_builder;
+ conf.auto_downmargin = 1;
break;
case RADIOLIST:
dialogbuilder = radiolist_builder;
+ conf.auto_downmargin = 1;
break;
case RANGEBOX:
dialogbuilder = rangebox_builder;
break;
case TEXTBOX:
dialogbuilder = textbox_builder;
+ textfromfile = true;
break;
case TIMEBOX:
dialogbuilder = timebox_builder;
break;
case TREEVIEW:
dialogbuilder = treeview_builder;
+ conf.auto_downmargin = 1;
break;
case YESNO:
dialogbuilder = yesno_builder;
@@ -652,7 +701,7 @@ int main(int argc, char *argv[argc])
usage();
return (255);
}
- if (dialogbuilder == textbox_builder)
+ if (textfromfile) /* textbox */
text = argv[0];
else {
if ((text = malloc(strlen(argv[0]) + 1)) == NULL) {
@@ -670,45 +719,52 @@ int main(int argc, char *argv[argc])
/* bsddialog terminal mode */
if (bsddialog_init() != 0) {
printf("Error: %s\n", bsddialog_geterror());
- return (BSDDIALOG_ERROR);
+ return (255);
}
signal(SIGINT, sigint_handler);
if (theme_opt != BSDDIALOG_THEME_FLAT)
- bsddialog_set_default_theme(theme_opt);
+ if (bsddialog_set_default_theme(theme_opt) != BSDDIALOG_OK)
+ errorexit(NULL);
+ if (loadthemefile != NULL)
+ if (loadtheme(loadthemefile, errorbuilder) != BSDDIALOG_OK)
+ errorexit(errorbuilder);
+ if (bikeshed_opt)
+ if (bikeshed(&conf, errorbuilder) != BSDDIALOG_OK)
+ errorexit(errorbuilder);
if (backtitle_opt != NULL)
- bsddialog_backtitle(&conf, backtitle_opt);
+ if( bsddialog_backtitle(&conf, backtitle_opt))
+ errorexit(NULL);
- errorbuilder[0] = '\0';
- output = BSDDIALOG_OK;
- if (dialogbuilder != NULL)
- output = dialogbuilder(conf, text, rows, cols, argc, argv,
+ if (dialogbuilder != NULL) {
+ retval = dialogbuilder(&conf, text, rows, cols, argc, argv,
errorbuilder);
+ if (retval == BSDDIALOG_ERROR)
+ errorexit(errorbuilder);
+ } else
+ retval = BSDDIALOG_OK;
- if (dialogbuilder != textbox_builder)
- free(text);
+ if (savethemefile != NULL)
+ if (savetheme(savethemefile, errorbuilder, BSDDIALOG_VERSION) !=
+ BSDDIALOG_OK)
+ errorexit(errorbuilder);
bsddialog_end();
/* end bsddialog terminal mode */
- if (output == BSDDIALOG_ERROR) {
- if (errorbuilder[0] != '\0')
- printf("Error: %s\n", errorbuilder);
- else
- printf("Error: %s\n", bsddialog_geterror());
- return (255);
- }
+ if (textfromfile == false)
+ free(text);
if (conf.get_height != NULL && conf.get_width != NULL)
dprintf(output_fd_opt, "Dialog size: (%d - %d)\n",
*conf.get_height, *conf.get_width);
- if (output == BSDDIALOG_ESC && esc_cancelvalue_opt)
- output = BSDDIALOG_CANCEL;
+ if (retval == BSDDIALOG_ESC && esc_return_cancel_opt)
+ retval = BSDDIALOG_CANCEL;
- return (output);
+ return (retval);
}
void sigint_handler(int sig)
@@ -718,6 +774,18 @@ void sigint_handler(int sig)
exit(255);
}
+void errorexit(char *errbuf)
+{
+ bsddialog_end();
+
+ if (errbuf != NULL && errbuf[0] != '\0')
+ printf("Error: %s\n", errbuf);
+ else
+ printf("Error: %s\n", bsddialog_geterror());
+
+ exit(255);
+}
+
void
custom_text(bool cr_wrap, bool no_collapse, bool no_nl_expand, bool trim,
char *text, char *buf)
@@ -780,7 +848,7 @@ int gauge_builder(BUILDER_ARGS)
else
perc = 0;
- output = bsddialog_gauge(&conf, text, rows, cols, perc, STDIN_FILENO,
+ output = bsddialog_gauge(conf, text, rows, cols, perc, STDIN_FILENO,
"XXX");
return (output);
@@ -790,7 +858,7 @@ int infobox_builder(BUILDER_ARGS)
{
int output;
- output = bsddialog_infobox(&conf, text, rows, cols);
+ output = bsddialog_infobox(conf, text, rows, cols);
return (output);
}
@@ -826,7 +894,7 @@ int mixedgauge_builder(BUILDER_ARGS)
minipercs[i] = (int)strtol(argv[i * 2 + 1], NULL, 10);
}
- output = bsddialog_mixedgauge(&conf, text, rows, cols, mainperc,
+ output = bsddialog_mixedgauge(conf, text, rows, cols, mainperc,
nminibars, minilabels, minipercs);
return (output);
@@ -836,7 +904,7 @@ int msgbox_builder(BUILDER_ARGS)
{
int output;
- output = bsddialog_msgbox(&conf, text, rows, cols);
+ output = bsddialog_msgbox(conf, text, rows, cols);
return (output);
}
@@ -852,7 +920,7 @@ int pause_builder(BUILDER_ARGS)
}
secs = (u_int)strtoul(argv[0], NULL, 10);
- output = bsddialog_pause(&conf, text, rows, cols, secs);
+ output = bsddialog_pause(conf, text, rows, cols, secs);
return (output);
}
@@ -878,7 +946,7 @@ int rangebox_builder(BUILDER_ARGS)
else
value = min;
- output = bsddialog_rangebox(&conf, text, rows, cols, min, max, &value);
+ output = bsddialog_rangebox(conf, text, rows, cols, min, max, &value);
dprintf(output_fd_opt, "%d", value);
@@ -889,7 +957,7 @@ int textbox_builder(BUILDER_ARGS)
{
int output;
- output = bsddialog_textbox(&conf, text, rows, cols);
+ output = bsddialog_textbox(conf, text, rows, cols);
return (output);
}
@@ -898,7 +966,7 @@ int yesno_builder(BUILDER_ARGS)
{
int output;
- output = bsddialog_yesno(&conf, text, rows, cols);
+ output = bsddialog_yesno(conf, text, rows, cols);
return (output);
}
@@ -924,13 +992,11 @@ int datebox_builder(BUILDER_ARGS)
dd = (u_int)strtoul(argv[2], NULL, 10);
}
- output = bsddialog_datebox(&conf, text, rows, cols, &yy, &mm, &dd);
+ output = bsddialog_datebox(conf, text, rows, cols, &yy, &mm, &dd);
if (output != BSDDIALOG_OK)
return (output);
- if (date_fmt_opt == NULL) {
- dprintf(output_fd_opt, "%u/%u/%u", yy, mm, dd);
- } else {
+ if (date_fmt_opt != NULL) {
time(&cal);
localtm = localtime(&cal);
localtm->tm_year = yy - 1900;
@@ -938,6 +1004,10 @@ int datebox_builder(BUILDER_ARGS)
localtm->tm_mday = dd;
strftime(stringdate, 1024, date_fmt_opt, localtm);
dprintf(output_fd_opt, "%s", stringdate);
+ } else if (bikeshed_opt && (dd % 2 == 0)) {
+ dprintf(output_fd_opt, "%u/%u/%u", yy, mm, dd);
+ } else {
+ dprintf(output_fd_opt, "%u/%02u/%02u", yy, mm, dd);
}
return (output);
@@ -963,13 +1033,11 @@ int timebox_builder(BUILDER_ARGS)
ss = (u_int)strtoul(argv[2], NULL, 10);
}
- output = bsddialog_timebox(&conf, text, rows, cols, &hh, &mm, &ss);
+ output = bsddialog_timebox(conf, text, rows, cols, &hh, &mm, &ss);
if (output != BSDDIALOG_OK)
return (output);
- if (time_fmt_opt == NULL) {
- dprintf(output_fd_opt, "%u:%u:%u", hh, mm, ss);
- } else {
+ if (time_fmt_opt != NULL) {
time(&clock);
localtm = localtime(&clock);
localtm->tm_hour = hh;
@@ -977,6 +1045,10 @@ int timebox_builder(BUILDER_ARGS)
localtm->tm_sec = ss;
strftime(stringtime, 1024, time_fmt_opt, localtm);
dprintf(output_fd_opt, "%s", stringtime);
+ } else if (bikeshed_opt && (ss % 2 == 0)) {
+ dprintf(output_fd_opt, "%u:%u:%u", hh, mm, ss);
+ } else {
+ dprintf(output_fd_opt, "%02u:%02u:%02u", hh, mm, ss);
}
return (output);
@@ -1116,7 +1188,7 @@ int checklist_builder(BUILDER_ARGS)
if (output != 0)
return (output);
- output = bsddialog_checklist(&conf, text, rows, cols, menurows, nitems,
+ output = bsddialog_checklist(conf, text, rows, cols, menurows, nitems,
items, &focusitem);
print_menu_items(output, nitems, items, focusitem);
@@ -1145,7 +1217,7 @@ int menu_builder(BUILDER_ARGS)
if (output != 0)
return (output);
- output = bsddialog_menu(&conf, text, rows, cols, menurows, nitems,
+ output = bsddialog_menu(conf, text, rows, cols, menurows, nitems,
items, &focusitem);
print_menu_items(output, nitems, items, focusitem);
@@ -1174,7 +1246,7 @@ int radiolist_builder(BUILDER_ARGS)
if (output != 0)
return (output);
- output = bsddialog_radiolist(&conf, text, rows, cols, menurows, nitems,
+ output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
items, &focusitem);
print_menu_items(output, nitems, items, focusitem);
@@ -1203,10 +1275,10 @@ int treeview_builder(BUILDER_ARGS)
if (output != 0)
return (output);
- conf.menu.no_name = true;
- conf.menu.align_left = true;
+ conf->menu.no_name = true;
+ conf->menu.align_left = true;
- output = bsddialog_radiolist(&conf, text, rows, cols, menurows, nitems,
+ output = bsddialog_radiolist(conf, text, rows, cols, menurows, nitems,
items, &focusitem);
print_menu_items(output, nitems, items, focusitem);
@@ -1238,7 +1310,7 @@ print_form_items(int output, int nitems, struct bsddialog_formitem *items)
return;
for (i = 0; i < nitems; i++) {
- dprintf(output_fd_opt, "%ls\n", (wchar_t*)items[i].value);
+ dprintf(output_fd_opt, "%s\n", items[i].value);
free(items[i].value);
}
}
@@ -1256,7 +1328,6 @@ int form_builder(BUILDER_ARGS)
}
formheight = (u_int)strtoul(argv[0], NULL, 10);
- flags = 0;
argc--;
argv++;
@@ -1279,13 +1350,13 @@ int form_builder(BUILDER_ARGS)
valuelen = (int)strtol(argv[j++], NULL, 10);
items[i].maxvaluelen = valuelen == 0 ? abs(fieldlen) : valuelen;
- flags |= (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
+ flags = (fieldlen < 0 ? BSDDIALOG_FIELDREADONLY : 0);
items[i].flags = flags;
items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
}
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
items);
print_form_items(output, nitems, items);
free(items);
@@ -1302,14 +1373,16 @@ int inputbox_builder(BUILDER_ARGS)
item.ylabel = 0;
item.xlabel = 0;
item.init = argc > 0 ? argv[0] : "";
- item.yfield = 1;
- item.xfield = 1;
- item.fieldlen = cols > 4 ? cols-4 : 25;
+ item.yfield = 0;
+ item.xfield = 0;
+ item.fieldlen = 1;
item.maxvaluelen = max_input_form_opt > 0 ? max_input_form_opt : 2048;
- item.flags = 0;
+ item.flags = BSDDIALOG_FIELDNOCOLOR;
+ item.flags |= BSDDIALOG_FIELDCURSOREND;
+ item.flags |= BSDDIALOG_FIELDEXTEND;
item.bottomdesc = "";
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
+ output = bsddialog_form(conf, text, rows, cols, 1, 1, &item);
print_form_items(output, 1, &item);
return (output);
@@ -1349,7 +1422,7 @@ int mixedform_builder(BUILDER_ARGS)
items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
}
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
items);
print_form_items(output, nitems, items);
free(items);
@@ -1366,14 +1439,17 @@ int passwordbox_builder(BUILDER_ARGS)
item.ylabel = 0;
item.xlabel = 0;
item.init = argc > 0 ? argv[0] : "";
- item.yfield = 1;
- item.xfield = 1;
- item.fieldlen = cols > 4 ? cols-4 : 25;
+ item.yfield = 0;
+ item.xfield = 0;
+ item.fieldlen = 1;
item.maxvaluelen = max_input_form_opt > 0 ? max_input_form_opt : 2048;
item.flags = BSDDIALOG_FIELDHIDDEN;
+ item.flags |= BSDDIALOG_FIELDNOCOLOR;
+ item.flags |= BSDDIALOG_FIELDCURSOREND;
+ item.flags |= BSDDIALOG_FIELDEXTEND;
item.bottomdesc = "";
- output = bsddialog_form(&conf, text, rows, cols, 1, 1, &item);
+ output = bsddialog_form(conf, text, rows, cols, 1, 1, &item);
print_form_items(output, 1, &item);
return (output);
@@ -1421,7 +1497,7 @@ int passwordform_builder(BUILDER_ARGS)
items[i].bottomdesc = item_bottomdesc_opt ? argv[j++] : "";
}
- output = bsddialog_form(&conf, text, rows, cols, formheight, nitems,
+ output = bsddialog_form(conf, text, rows, cols, formheight, nitems,
items);
print_form_items(output, nitems, items);
free(items);
diff --git a/examples_library/compile b/examples_library/compile
index 3c3961d06baf..6f2c23b8ca75 100755
--- a/examples_library/compile
+++ b/examples_library/compile
@@ -10,7 +10,9 @@
libpath=../lib
examples="menu checklist radiolist mixedlist theme infobox yesno msgbox \
- datebox form formw timebox rangebox pause"
+ datebox form timebox rangebox pause"
+
+rm -f $examples
for e in $examples
do
diff --git a/examples_library/datebox.c b/examples_library/datebox.c
index a3c8946b7f79..7f0138688d53 100644
--- a/examples_library/datebox.c
+++ b/examples_library/datebox.c
@@ -34,9 +34,7 @@ int main()
bsddialog_initconf(&conf);
conf.title = "datebox";
- output = bsddialog_datebox(&conf,
- "TAB / RIGHT / LEFT to move,\nUP / DOWN to select time", 10, 35,
- &yy, &mm, &dd);
+ output = bsddialog_datebox(&conf, "Example", 9, 35, &yy, &mm, &dd);
bsddialog_end();
diff --git a/examples_library/form.c b/examples_library/form.c
index 0256975f2023..56d8a8052a72 100644
--- a/examples_library/form.c
+++ b/examples_library/form.c
@@ -9,6 +9,7 @@
*/
#include <bsddialog.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -21,21 +22,22 @@ int main()
int i, output;
struct bsddialog_conf conf;
struct bsddialog_formitem items[3] = {
- {"Input:", 1, 1, "value", 1, 11, 30, 50, NULL, 0, "desc 1"},
- {"Input:", 2, 1, "read only", 2, 11, 30, 50, NULL, RO, "desc 2"},
- {"Password:", 3, 1, "", 3, 11, 30, 50, NULL, H, "desc 3"}
+ {"Input:", 0, 0, "value", 0, 10, 30, 50, NULL, 0, "desc 1"},
+ {"Input:", 1, 0, "read only", 1, 10, 30, 50, NULL, RO, "desc 2"},
+ {"Password:", 2, 0, "", 2, 10, 30, 50, NULL, H, "desc 3"}
};
+ /* Optional, unless for unicode/multicolum charachters */
+ setlocale(LC_ALL, "");
+
if (bsddialog_init() == BSDDIALOG_ERROR) {
printf("Error: %s\n", bsddialog_geterror());
return (1);
}
-
bsddialog_initconf(&conf);
conf.title = "form";
conf.form.securech = '*';
output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items);
-
bsddialog_end();
if (output == BSDDIALOG_ERROR) {
diff --git a/examples_library/formw.c b/examples_library/formw.c
deleted file mode 100644
index edbeec98f2a3..000000000000
--- a/examples_library/formw.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*-
- * SPDX-License-Identifier: CC0-1.0
- *
- * Written in 2022 by Alfonso Sabato Siciliano.
- * To the extent possible under law, the author has dedicated all copyright
- * and related and neighboring rights to this software to the public domain
- * worldwide. This software is distributed without any warranty, see:
- * <http://creativecommons.org/publicdomain/zero/1.0/>.
- */
-
-#include <bsddialog.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define H BSDDIALOG_FIELDHIDDEN
-#define RO BSDDIALOG_FIELDREADONLY
-
-int main()
-{
- int i, output;
- struct bsddialog_conf conf;
- struct bsddialog_formitem items[3] = {
- {"Input:", 1, 1, "value", 1, 11, 30, 50, NULL, 0, "desc 1"},
- {"Input:", 2, 1, "read only", 2, 11, 30, 50, NULL, RO, "desc 2"},
- {"Password:", 3, 1, "", 3, 11, 30, 50, NULL, H, "desc 3"}
- };
-
- setlocale(LC_ALL, "");
-
- if (bsddialog_init() == BSDDIALOG_ERROR) {
- printf("Error: %s\n", bsddialog_geterror());
- return (1);
- }
-
- bsddialog_initconf(&conf);
- conf.title = "form";
- conf.form.securech = '*';
- conf.form.enable_wchar = true;
- output = bsddialog_form(&conf, "Example", 10, 50, 3, 3, items);
-
- bsddialog_end();
-
- if (output == BSDDIALOG_ERROR) {
- printf("Error: %s", bsddialog_geterror());
- return (1);
- }
-
- if (output == BSDDIALOG_CANCEL) {
- printf("Cancel\n");
- return (0);
- }
-
- for (i = 0; i < 3; i++) {
- printf("%s \"%ls\"\n", items[i].label, (wchar_t*)items[i].value);
- free(items[i].value);
- }
-
- return (output);
-} \ No newline at end of file
diff --git a/examples_library/timebox.c b/examples_library/timebox.c
index 0e27f824af11..f06986423558 100644
--- a/examples_library/timebox.c
+++ b/examples_library/timebox.c
@@ -34,9 +34,7 @@ int main()
bsddialog_initconf(&conf);
conf.title = "timebox";
- output = bsddialog_timebox(&conf,
- "TAB / RIGHT / LEFT to move,\nUP / DOWN to select time", 10, 35,
- &hh, &mm, &ss);
+ output = bsddialog_timebox(&conf, "Example", 9, 35, &hh, &mm, &ss);
bsddialog_end();
diff --git a/examples_utility/form.sh b/examples_utility/form.sh
index bd1bac8a3939..783993d3db30 100755
--- a/examples_utility/form.sh
+++ b/examples_utility/form.sh
@@ -15,11 +15,11 @@
: ${BSDDIALOG_ESC=5}
FORMS=$(./bsddialog --title " form " --form "Hello World!" 12 40 5 \
- Label1: 1 1 Value1 1 9 18 25 \
- Label2: 2 1 Value2 2 9 18 25 \
- Label3: 3 1 Value3 3 9 18 25 \
- Label4: 4 1 Value4 4 9 18 25 \
- Label5: 5 1 Value5 5 9 18 25 \
+ Label1: 0 0 Value1 0 8 18 25 \
+ Label2: 1 0 Value2 1 8 18 25 \
+ Label3: 2 0 Value3 2 8 18 25 \
+ Label4: 3 0 Value4 3 8 18 25 \
+ Label5: 4 0 Value5 4 8 18 25 \
3>&1 1>&2 2>&3 3>&-)
case $? in
diff --git a/examples_utility/mixedform.sh b/examples_utility/mixedform.sh
index 80b7abf93745..8a96fa8d9e72 100755
--- a/examples_utility/mixedform.sh
+++ b/examples_utility/mixedform.sh
@@ -16,9 +16,9 @@
FORMS=$(./bsddialog --insecure --title " mixedform " \
--mixedform "Hello World!" 12 40 3 \
- Label: 1 1 Entry 1 11 18 25 0 \
- Label: 2 1 Read-Only 2 11 18 25 2 \
- Password: 3 1 "" 3 11 18 25 1 \
+ Label: 0 0 Entry 0 10 18 25 0 \
+ Label: 1 0 Read-Only 1 10 18 25 2 \
+ Password: 2 0 "" 2 10 18 25 1 \
3>&1 1>&2 2>&3 3>&-)
case $? in
diff --git a/examples_utility/passwordform.sh b/examples_utility/passwordform.sh
index 19b3a355b6eb..9bfe11a28645 100755
--- a/examples_utility/passwordform.sh
+++ b/examples_utility/passwordform.sh
@@ -16,11 +16,11 @@
FORMS=$(./bsddialog --insecure --title " passwordform " \
--passwordform "Example" 12 40 5 \
- Password1: 1 1 "" 1 12 18 25 \
- Password2: 2 1 "" 2 12 18 25 \
- Password3: 3 1 "" 3 12 18 25 \
- Password4: 4 1 "" 4 12 18 25 \
- Password5: 5 1 "" 5 12 18 25 \
+ Password1: 0 0 "" 0 11 18 25 \
+ Password2: 1 0 "" 1 11 18 25 \
+ Password3: 2 0 "" 2 11 18 25 \
+ Password4: 3 0 "" 3 11 18 25 \
+ Password5: 4 0 "" 4 11 18 25 \
3>&1 1>&2 2>&3 3>&-)
case $? in
diff --git a/lib/GNUMakefile b/lib/GNUMakefile
index 0d724b803be3..1d55d6edd60d 100644
--- a/lib/GNUMakefile
+++ b/lib/GNUMakefile
@@ -3,16 +3,16 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.2
+VERSION = 0.3
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
HEADERS = bsddialog.h bsddialog_theme.h bsddialog_progressview.h
SOURCES = barbox.c formbox.c infobox.c libbsddialog.c lib_util.c menubox.c \
messagebox.c textbox.c theme.c timebox.c
OBJECTS = $(SOURCES:.c=.o)
-CFLAGS = -D_XOPEN_SOURCE_EXTENDED -Wall -Wextra -Wno-implicit-fallthrough \
+CFLAGS = -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE -D_GNU_SOURCE -Wall -Wextra -Wno-implicit-fallthrough \
-Werror -fpic
-LDFLAGS = -lformw -lncursesw -ltinfo
+LDFLAGS = -lncursesw -ltinfo
LIBFLAG = -shared
RM = rm -f
diff --git a/lib/Makefile b/lib/Makefile
index 962b059b3e03..5c535c5483f1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -3,7 +3,7 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.2
+VERSION = 0.3
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
LIBRARY_A = lib${LIBRARY:=.a}
@@ -14,7 +14,7 @@ OBJECTS = ${SOURCES:.c=.o}
CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
-Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
- -L/usr/lib -lformw -lncursesw -ltinfow
+ -L/usr/lib -lncursesw -ltinfow
.if defined(DEBUG)
# `make -DDEBUG`
diff --git a/lib/barbox.c b/lib/barbox.c
index 49aa105c1de3..b6bfe32fc0aa 100644
--- a/lib/barbox.c
+++ b/lib/barbox.c
@@ -70,7 +70,7 @@ draw_bar(WINDOW *win, int y, int x, int barlen, int perc, bool withlabel,
sprintf(labelstr, "%d", label);
else
sprintf(labelstr, "%3d%%", perc);
- stringlen = (int)strlen(labelstr);
+ stringlen = (int)strlen(labelstr); /* number, always 1-byte-ch string */
wmove(win, y, x + barlen/2 - stringlen/2);
for (i = 0; i < stringlen; i++) {
color = (blue_x + 1 <= barlen/2 - stringlen/2 + i ) ?
@@ -109,7 +109,7 @@ bar_checksize(int rows, int cols, struct buttons *bs)
minwidth = 0;
if (bs != NULL) /* gauge has not buttons */
- minwidth = buttons_width(*bs);
+ minwidth = buttons_min_width(*bs);
minwidth = MAX(minwidth, MINBARWIDTH);
minwidth += VBORDERS;
@@ -151,16 +151,14 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
- mainloop = (fd < 0) ? false : true;
-
- if (mainloop) {
+ input = NULL;
+ if (fd >= 0) {
fd2 = dup(fd);
- input = fdopen(fd2, "r");
- if (input == NULL)
+ if ((input = fdopen(fd2, "r")) == NULL)
RETURN_ERROR("Cannot build FILE* from fd");
- } else
- input = NULL;
+ }
+ mainloop = true;
while (mainloop) {
wrefresh(widget);
prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-4,
@@ -168,6 +166,8 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
draw_borders(conf, bar, 3, w-6, RAISED);
draw_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/);
wrefresh(bar);
+ if (input == NULL) /* that is fd < 0 */
+ break;
while (true) {
fscanf(input, "%s", inputbuf);
@@ -193,10 +193,11 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
if (strcmp(inputbuf, sep) == 0)
break;
strcpy(pntext, inputbuf);
- pntext += strlen(inputbuf);
+ pntext += strlen(inputbuf); /* end string, no strlen */
pntext[0] = ' ';
pntext++;
}
+ pntext[0] = '\0';
if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
ntext, NULL, false) != 0)
return (BSDDIALOG_ERROR);
@@ -216,7 +217,7 @@ do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols,
unsigned int mainperc, unsigned int nminibars, const char **minilabels,
int *minipercs, bool color)
{
- int i, output, miniperc, y, x, h, w, ypad, max_minbarlen;
+ int i, retval, miniperc, y, x, h, w, ypad, max_minbarlen;
int htextpad, htext, wtext;
int colorperc, red, green;
WINDOW *widget, *textpad, *bar, *shadow;
@@ -240,7 +241,7 @@ do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols,
max_minbarlen = 0;
for (i = 0; i < (int)nminibars; i++)
- max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i]));
+ max_minbarlen = MAX(max_minbarlen, (int)strcols(minilabels[i]));
max_minbarlen += 3 + 16; /* seps + [...] */
max_minbarlen = MAX(max_minbarlen, MINMGBARWIDTH); /* mainbar */
@@ -267,10 +268,10 @@ do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols,
if (set_widget_position(conf, &y, &x, h, w) != 0)
return (BSDDIALOG_ERROR);
- output = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
+ retval = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
NULL, false);
- if (output == BSDDIALOG_ERROR)
- return (output);
+ if (retval == BSDDIALOG_ERROR)
+ return (retval);
/* mini bars */
for (i = 0; i < (int)nminibars; i++) {
@@ -281,6 +282,7 @@ do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols,
if (color && (miniperc >= 0))
wattron(widget, A_BOLD);
mvwaddstr(widget, i+1, 2, minilabels[i]);
+ if (color && (miniperc >= 0))
wattroff(widget, A_BOLD);
/* perc */
if (miniperc < -11)
@@ -338,12 +340,12 @@ bsddialog_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int mainperc, unsigned int nminibars,
const char **minilabels, int *minipercs)
{
- int output;
+ int retval;
- output = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars,
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars,
minilabels, minipercs, false);
- return (output);
+ return (retval);
}
int
@@ -352,7 +354,7 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
struct bsddialog_fileminibar *minibar)
{
bool update;
- int perc, output, *minipercs;
+ int perc, retval, *minipercs;
unsigned int i, mainperc, totaltodo;
float readforsec;
const char **minilabels;
@@ -371,7 +373,7 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
}
refresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1;
- output = BSDDIALOG_OK;
+ retval = BSDDIALOG_OK;
i = 0;
update = true;
time(&told);
@@ -384,9 +386,9 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
time(&tnew);
if (update || tnew > told + refresh) {
- output = do_mixedgauge(conf, text, rows, cols, mainperc,
+ retval = do_mixedgauge(conf, text, rows, cols, mainperc,
nminibar, minilabels, minipercs, true);
- if (output == BSDDIALOG_ERROR)
+ if (retval == BSDDIALOG_ERROR)
return (BSDDIALOG_ERROR);
move(SCREENLINES - 1, 2);
@@ -421,7 +423,7 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
free(minilabels);
free(minipercs);
- return (output);
+ return (retval);
}
int
@@ -430,7 +432,8 @@ bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
{
bool loop, buttupdate, barupdate;
int y, x, h, w;
- int input, currvalue, output, sizebar, bigchange, positions;
+ int currvalue, retval, sizebar, bigchange, positions;
+ wint_t input;
float perc;
WINDOW *widget, *textpad, *bar, *shadow;
struct buttons bs;
@@ -483,17 +486,18 @@ bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
wrefresh(bar);
}
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
*value = currvalue;
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -587,7 +591,7 @@ bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
@@ -596,7 +600,7 @@ bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
delwin(bar);
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
}
int
@@ -604,7 +608,8 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int sec)
{
bool loop, buttupdate, barupdate;
- int output, y, x, h, w, input, tout, sizebar;
+ int retval, y, x, h, w, tout, sizebar;
+ wint_t input;
float perc;
WINDOW *widget, *textpad, *bar, *shadow;
struct buttons bs;
@@ -650,11 +655,10 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
buttupdate = false;
}
- input = getch();
- if (input < 0) { /* timeout */
+ if (get_wch(&input) == ERR) { /* timeout */
tout--;
if (tout < 0) {
- output = BSDDIALOG_TIMEOUT;
+ retval = BSDDIALOG_TIMEOUT;
break;
}
else {
@@ -665,12 +669,12 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -731,7 +735,7 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
@@ -742,5 +746,5 @@ bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
delwin(bar);
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
} \ No newline at end of file
diff --git a/lib/bsddialog.3 b/lib/bsddialog.3
index 38500b4da6ca..12db1f039d59 100644
--- a/lib/bsddialog.3
+++ b/lib/bsddialog.3
@@ -22,13 +22,14 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 9, 2022
+.Dd August 29, 2022
.Dt BSDDIALOG 3
.Os
.Sh NAME
.Nm bsddialog_backtitle ,
.Nm bsddialog_clearterminal ,
.Nm bsddialog_color ,
+.Nm bsddialog_color_attrs ,
.Nm bsddialog_checklist ,
.Nm bsddialog_datebox ,
.Nm bsddialog_end ,
@@ -36,8 +37,10 @@
.Nm bsddialog_gauge ,
.Nm bsddialog_geterror ,
.Nm bsddialog_get_theme ,
+.Nm bsddialog_hascolors ,
.Nm bsddialog_infobox ,
.Nm bsddialog_init ,
+.Nm bsddialog_init_notheme ,
.Nm bsddialog_initconf ,
.Nm bsddialog_menu ,
.Nm bsddialog_mixedgauge ,
@@ -115,6 +118,8 @@
.Ft int
.Fn bsddialog_init "void"
.Ft int
+.Fn bsddialog_init_notheme "void"
+.Ft int
.Fn bsddialog_initconf "struct bsddialog_conf *conf"
.Ft int
.Fo bsddialog_menu
@@ -218,7 +223,16 @@
.Fa "unsigned int flags"
.Fc
.Ft int
+.Fo bsddialog_color_attrs
+.Fa "int color"
+.Fa "enum bsddialog_color *foreground"
+.Fa "enum bsddialog_color *background"
+.Fa "unsigned int *flags"
+.Fc
+.Ft int
.Fn bsddialog_get_theme "struct bsddialog_theme *theme"
+.Ft bool
+.Fn bsddialog_hascolors "void"
.Ft int
.Fn bsddialog_set_default_theme "enum bsddialog_default_theme theme"
.Ft int
@@ -239,6 +253,12 @@ API.
restores the screen like before
.Fn bsddialog_init ,
then it is not possible to use the library functions.
+.Fn bsddialog_init_notheme
+is equivalent to
+.Fn bsddialog_init
+except it does not set the default graphical theme; see
+.Sx Theme
+subsection to set a theme explicitly.
.Pp
.Fn bsddialog_error
returns a string to describe the last error, it should be called after a
@@ -258,10 +278,9 @@ is described later.
.Pp
Each
.Fa char*
-argument has to be a well terminated string, can be empty
-.Pq Dq
-but not
-.Dv NULL .
+argument has to be a well terminated string, it can be a multibyte character
+string depending on current locale, see
+.Xr setlocale 3 .
.Ss Dialogs
The dialogs have common arguments.
.Fa text
@@ -282,6 +301,8 @@ struct bsddialog_conf {
bool ascii_lines;
unsigned int auto_minheight;
unsigned int auto_minwidth;
+ unsigned int auto_topmargin;
+ unsigned int auto_downmargin;
const char *bottomtitle;
bool clear;
int *get_height;
@@ -298,6 +319,7 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
+ unsigned int cols_per_row;
bool highlight;
unsigned int tablen;
} text;
@@ -309,11 +331,13 @@ struct bsddialog_conf {
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
+ char securech;
+ char *securembch;
+ bool value_wchar;
bool value_without_ok;
} form;
struct {
+ bool always_active;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -343,6 +367,23 @@ minimum width if
.Fa cols
is
.Dv BSDDIALOG_AUTOSIZE .
+.It Fa conf.auto_topmargin
+top margin if
+.Fa rows
+is
+.Dv BSDDIALOG_AUTOSIZE
+or
+.Dv BSDDIALOG_FULLSCREEN ,
+.Fa conf.y
+has to be
+.Dv BSDDIALOG_CENTER .
+.It Fa conf.auto_downmargin
+down margin if
+.Fa rows
+is
+.Dv BSDDIALOG_AUTOSIZE
+or
+.Dv BSDDIALOG_FULLSCREEN .
.It Fa conf.bottomtitle
subtitle at the dialog bottom side.
.It Fa conf.clear
@@ -382,11 +423,16 @@ file to open if F1 is pressed.
message to display if F1 is pressed.
.El
.Pp
-.Fa conf.text.highlight
+.Bl -column -compact
+.It Fa conf.text.cols_per_row
+Try to set the number of columns for a row of
+.Fa text
+with autosizing; default
+.Dv 10 .
+.It Fa conf.text.highlight
enables highlights for
.Fa text ,
properly the following sequences are considered escapes:
-.Bl -column -compact
.It Dq \eZ0
black.
.It Dq \eZ1
@@ -404,7 +450,7 @@ cyan.
.It Dq \eZ7
white.
.It Dq \eZr
-reverse colors between foreground and background.
+reverse foreground and background.
.It Dq \eZR
disable reverse.
.It Dq \eZb
@@ -417,11 +463,22 @@ underline.
disable underline.
.It Dq \eZn
disable each customization.
+.It Fa conf.text.tablen
+tab length for
+.Fa text
+argument and
+.Fn bsddialog_textbox
+function.
.El
-.Fa conf.text.tablen
-tab length.
.Pp
.Bl -column -compact
+.It Fa conf.button.always_active
+buttons always active, avoidind focus switch between buttons and input fields or
+input boxes in
+.Fn bsddialog_form ,
+.Fn bsddialog_datebox
+and
+.Fn bsddialog_timebox .
.It Fa conf.button.without_ok
disable OK button.
.It Fa conf.button.ok_label
@@ -598,8 +655,16 @@ enable shortcut keys on buttons, default on items.
.El
.Pp
.Fn bsddialog_form
-builds a dialog to display a list of items to get strings in input, an item is
-defined like:
+builds a dialog to display an array of
+.Fa items
+of
+.Fa nitems
+elements to get strings in input.
+.Fa formrows
+specifies the graphical height for the box around the items,
+.Dv 0
+for autosizing.
+An item is defined like:
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_formitem {
@@ -621,7 +686,7 @@ struct bsddialog_formitem {
.Ed
.Pp
.Fa label
-describes the request, it is printed at the position
+is a string to describe the request, it is printed at the position
.Fa ylabel
and
.Fa xlabel .
@@ -632,45 +697,43 @@ and
.Fa fieldlen
is its graphical width, while
.Fa maxvalelen
-is the maximum length of the input string,
+is the maximum number of characters of the input string.
.Fa init
-is the default value.
+is the default field value.
If the OK button is pressed
.Fa value
-is the allocated memory with the current field string.
+is the allocated memory with the current field string, its size depends on
+the current locale.
.Fa flags
is an OR value to set the
-.Dv BSDDIALOG_FIELDHIDDEN
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Dv BSDDIALOG_FIELDREADONLY ,
+.Dv BSDDIALOG_FIELDNOCOLOR ,
+.Dv BSDDIALOG_FIELDCURSOREND ,
+.Dv BSDDIALOG_FIELDEXTEND
and
-.Dv BSDDIALOG_FIELDREADONLY
+.Dv BSDDIALOG_FIELDSINGLEBYTE .
flags for the field.
.Fa bottomdesc
is printed on the bottom side of the screen if the item is focused.
-.Fa items
-is an array of items of
-.Fa nitems
-elements,
-.Fa formrows
-specifies the graphical fixed height for the items list;
-.Fa ylabel
-and
-.Fa yfield
-have to be between 1 and
-.Fa formrows .
.Pp
.Fn bsddialog_form
can be customized by:
.Bl -column -compact
-.It Fa conf.form.enable_wchar
-enables characters greater than 127 in the field,
-.Fa value
-is a pointer to allocated memory for a
-.Em wchar_t
-string.
.It Fa conf.form.securech
-charachter to hide the input
-with
+charachter to hide the input with
.Dv BSDDIALOG_FIELDHIDDEN .
+.It Fa conf.form.securembch
+multibyte charachter to hide the input with
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Fa conf.form.securech
+is ignored.
+.It Fa conf.form.value_wchar
+the allocated
+.Fa value
+is a
+.Em wchar_t*
+string.
.It Fa conf.form.value_without_ok
allocate memory and set
.Fa value
@@ -747,8 +810,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -770,20 +833,23 @@ struct bsddialog_theme {
int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int delimcolor;
int f_delimcolor;
int color;
@@ -825,6 +891,8 @@ specifies OR-flags, possible values:
.Dv BSDDIALOG_REVERSE
and
.Dv BSDDIALOG_UNDERLINE .
+.Fn bsddialog_color_attrs
+gets the properties of a color.
.Pp
.Fn bsddialog_set_theme
sets
@@ -840,6 +908,13 @@ and
.Dv BSDDIALOG_THEME_DIALOG ,
they can be set via
.Fn bsddialog_set_default_theme .
+.Pp
+.Fn bsddialog_hascolors
+returns
+.Dv true
+if the terminal provides colors,
+.Dv false
+otherwise.
.Sh RETURN VALUES
The functions return the value
.Dv BSDDIALOG_ERROR
@@ -975,8 +1050,7 @@ for (i = 0; i < 3; i++) {
.Ed
.Sh SEE ALSO
.Xr bsddialog 1 ,
-.Xr curses 3 ,
-.Xr ncurses 3
+.Xr curses 3
.Sh HISTORY
The
.Nm bsddialog
@@ -985,8 +1059,4 @@ library first appeared in
.Sh AUTHORS
.Nm bsddialog
was written by
-.An Alfonso Sabato Siciliano Aq Mt alf.siciliano@gmail.com .
-.Sh BUGS
-.Fn bsddialog_form
-does not resize the dialog after a terminal resize and does not provide
-scrolling for items. \ No newline at end of file
+.An Alfonso Sabato Siciliano Aq Mt asiciliano@FreeBSD.org .
diff --git a/lib/bsddialog.h b/lib/bsddialog.h
index 37f9899141c0..6f13da3fa667 100644
--- a/lib/bsddialog.h
+++ b/lib/bsddialog.h
@@ -30,7 +30,7 @@
#include <stdbool.h>
-#define LIBBSDDIALOG_VERSION "0.2"
+#define LIBBSDDIALOG_VERSION "0.3"
/* Exit status */
#define BSDDIALOG_ERROR -1
@@ -64,13 +64,19 @@
#define BSDDIALOG_MG_PENDING -11
/* Form */
-#define BSDDIALOG_FIELDHIDDEN 1U
-#define BSDDIALOG_FIELDREADONLY 2U
+#define BSDDIALOG_FIELDHIDDEN 1U
+#define BSDDIALOG_FIELDREADONLY 2U
+#define BSDDIALOG_FIELDNOCOLOR 4U
+#define BSDDIALOG_FIELDCURSOREND 8U
+#define BSDDIALOG_FIELDEXTEND 16U
+#define BSDDIALOG_FIELDSINGLEBYTE 32U
struct bsddialog_conf {
bool ascii_lines;
unsigned int auto_minheight;
unsigned int auto_minwidth;
+ unsigned int auto_topmargin;
+ unsigned int auto_downmargin;
const char *bottomtitle;
bool clear;
int *get_height;
@@ -87,6 +93,7 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
+ unsigned int cols_per_row;
bool highlight;
unsigned int tablen;
} text;
@@ -98,11 +105,13 @@ struct bsddialog_conf {
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
+ char securech;
+ char *securembch;
+ bool value_wchar;
bool value_without_ok;
} form;
struct {
+ bool always_active;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -156,6 +165,7 @@ struct bsddialog_formitem {
};
int bsddialog_init(void);
+int bsddialog_init_notheme(void);
int bsddialog_end(void);
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle);
int bsddialog_initconf(struct bsddialog_conf *conf);
diff --git a/lib/bsddialog_theme.h b/lib/bsddialog_theme.h
index 89381cfe28d5..2f20d7b5a79c 100644
--- a/lib/bsddialog_theme.h
+++ b/lib/bsddialog_theme.h
@@ -39,8 +39,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -62,20 +62,23 @@ struct bsddialog_theme {
int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int delimcolor;
int f_delimcolor;
int color;
@@ -106,7 +109,11 @@ enum bsddialog_color {
int
bsddialog_color(enum bsddialog_color foreground,
enum bsddialog_color background, unsigned int flags);
+int
+bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
+ enum bsddialog_color *background, unsigned int *flags);
int bsddialog_get_theme(struct bsddialog_theme *theme);
+bool bsddialog_hascolors(void);
int bsddialog_set_default_theme(enum bsddialog_default_theme theme);
int bsddialog_set_theme(struct bsddialog_theme *theme);
diff --git a/lib/formbox.c b/lib/formbox.c
index 564fa99d69a8..cd29919417be 100644
--- a/lib/formbox.c
+++ b/lib/formbox.c
@@ -27,454 +27,608 @@
#include <sys/param.h>
-#include <ctype.h>
-#include <form.h>
+#include <curses.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define ISFIELDHIDDEN(item) (item.flags & BSDDIALOG_FIELDHIDDEN)
-#define ISFIELDREADONLY(item) (item.flags & BSDDIALOG_FIELDREADONLY)
-#define REDRAWFORM 19860214 /* magic number */
-
-/* field_userptr for private buffer and view options */
-struct myfield {
- int buflen;
- wchar_t *buf;
- int pos;
- int maxpos;
- bool secure;
- int securech;
- const char *bottomdesc;
+struct privateitem {
+ const char *label; /* formitem.label */
+ unsigned int ylabel; /* formitem.ylabel */
+ unsigned int xlabel; /* formitem.xlabel */
+ unsigned int yfield; /* formitem.yfield */
+ unsigned int xfield; /* formitem.xfield */
+ bool secure; /* formitem.flags & BSDDIALOG_FIELDHIDDEN */
+ bool readonly; /* formitem.flags & BSDDIALOG_FIELDREADONLY */
+ bool fieldnocolor; /* formitem.flags & BSDDIALOG_FIELDNOCOLOR */
+ bool extendfield; /* formitem.flags & BSDDIALOG_FIELDEXTEND */
+ bool fieldonebyte; /* formitem.flags & BSDDIALOG_FIELDSINGLEBYTE */
+ bool cursorend; /* formitem.flags & BSDDIALOG_FIELDCURSOREND */
+ bool cursor; /* field cursor visibility */
+ const char *bottomdesc; /* formitem.bottomdesc */
+
+ wchar_t *privwbuf; /* formitem.value */
+ wchar_t *pubwbuf; /* string for drawitem() */
+ unsigned int maxletters; /* formitem.maxvaluelen, [priv|pub]wbuf size */
+ unsigned int nletters; /* letters in privwbuf and pubwbuf */
+ unsigned int pos; /* pos in privwbuf and pubwbuf */
+ unsigned int fieldcols; /* formitem.fieldlen */
+ unsigned int xcursor; /* position in fieldcols [0 - fieldcols-1] */
+ unsigned int xposdraw; /* first pubwbuf index to draw */
};
-#define GETMYFIELD(field) ((struct myfield*)field_userptr(field))
-#define GETMYFIELD2(form) ((struct myfield*)field_userptr(current_field(form)))
-static void insertch(struct myfield *mf, int ch)
+struct privateform {
+ WINDOW *border;
+
+ WINDOW *pad;
+ unsigned int h; /* only to create pad */
+ unsigned int w; /* only to create pad */
+ unsigned int wmin; /* to refresh, w can change for FIELDEXTEND */
+ unsigned int ys; /* to refresh */
+ unsigned int ye; /* to refresh */
+ unsigned int xs; /* to refresh */
+ unsigned int xe; /* to refresh */
+ unsigned int y; /* changes moving focus around items */
+ unsigned int viewrows; /* visible rows, real formheight */
+ unsigned int minviewrows; /* min viewrows, ylabel != yfield */
+
+ wchar_t securewch; /* wide char of conf.form.secure[mb]ch */
+};
+
+enum operation {
+ MOVE_CURSOR_BEGIN,
+ MOVE_CURSOR_END,
+ MOVE_CURSOR_RIGHT,
+ MOVE_CURSOR_LEFT,
+ DEL_LETTER
+};
+
+static bool fieldctl(struct privateitem *item, enum operation op)
{
- int i;
+ bool change;
+ int width, oldwidth, nextwidth, cols;
+ unsigned int i;
+
+ change = false;
+ switch (op){
+ case MOVE_CURSOR_BEGIN:
+ if (item->pos == 0 && item->xcursor == 0)
+ break;
+ /* here the cursor is changed */
+ change = true;
+ item->pos = 0;
+ item->xcursor = 0;
+ item->xposdraw = 0;
+ break;
+ case MOVE_CURSOR_END:
+ while (fieldctl(item, MOVE_CURSOR_RIGHT))
+ change = true;
+ break;
+ case MOVE_CURSOR_LEFT:
+ if (item->pos == 0)
+ break;
+ /* check redundant by item->pos == 0 because of 'while' below */
+ if (item->xcursor == 0 && item->xposdraw == 0)
+ break;
+ /* here some letter to left */
+ change = true;
+ item->pos -= 1;
+ width = wcwidth(item->pubwbuf[item->pos]);
+ if (((int)item->xcursor) - width < 0) {
+ item->xcursor = 0;
+ item->xposdraw -= 1;
+ } else
+ item->xcursor -= width;
+
+ while (true) {
+ if (item->xposdraw == 0)
+ break;
+ if (item->xcursor >= item->fieldcols / 2)
+ break;
+ if (wcwidth(item->pubwbuf[item->xposdraw - 1]) +
+ item->xcursor + width > item->fieldcols)
+ break;
- if (mf->buflen > mf->maxpos)
- return;
+ item->xposdraw -= 1;
+ item->xcursor +=
+ wcwidth(item->pubwbuf[item->xposdraw]);
+ }
+ break;
+ case DEL_LETTER:
+ if (item->nletters == 0)
+ break;
+ if (item->pos == item->nletters)
+ break;
+ /* here a letter under the cursor */
+ change = true;
+ for (i = item->pos; i < item->nletters; i++) {
+ item->privwbuf[i] = item->privwbuf[i+1];
+ item->pubwbuf[i] = item->pubwbuf[i+1];
+ }
+ item->nletters -= 1;
+ item->privwbuf[i] = L'\0';
+ item->pubwbuf[i] = L'\0';
+ break;
+ case MOVE_CURSOR_RIGHT: /* used also by "insert", see handler loop */
+ if (item->pos + 1 == item->maxletters)
+ break;
+ if (item->pos == item->nletters)
+ break;
+ /* here a change to right */
+ change = true;
+ oldwidth = wcwidth(item->pubwbuf[item->pos]);
+ item->pos += 1;
+ if (item->pos == item->nletters) { /* empty column */
+ nextwidth = 1;
+ } else { /* a letter to right */
+ nextwidth = wcwidth(item->pubwbuf[item->pos]);
+ }
+ if (item->xcursor + oldwidth + nextwidth - 1 >= item->fieldcols) {
+ cols = nextwidth;
+ item->xposdraw = item->pos;
+ while (item->xposdraw != 0) {
+ cols += wcwidth(item->pubwbuf[item->xposdraw - 1]);
+ if (cols > (int)item->fieldcols)
+ break;
+ item->xposdraw -= 1;
+ }
+ item->xcursor = 0;
+ for (i = item->xposdraw; i < item->pos ; i++)
+ item->xcursor += wcwidth(item->pubwbuf[i]);
+ }
+ else {
+ item->xcursor += oldwidth;
+ }
- for (i = mf->buflen; i >= mf->pos; i--) {
- mf->buf[i+1] = mf->buf[i];
+ break;
}
- mf->buf[mf->pos] = ch;
- mf->pos += 1;
- if (mf->pos > mf->maxpos)
- mf->pos = mf->maxpos;
- mf->buflen += 1;
- mf->buf[mf->buflen] = '\0';
+ return (change);
}
-static void shiftleft(struct myfield *mf)
+static void
+drawitem(struct privateform *form, struct privateitem *item, bool focus)
{
- int i, last;
+ int color;
+ unsigned int n, cols;
+
+ /* Label */
+ wattron(form->pad, t.dialog.color);
+ mvwaddstr(form->pad, item->ylabel, item->xlabel, item->label);
+ wattroff(form->pad, t.dialog.color);
+
+ /* Field */
+ if (item->readonly)
+ color = t.form.readonlycolor;
+ else if (item->fieldnocolor)
+ color = t.dialog.color;
+ else
+ color = focus ? t.form.f_fieldcolor : t.form.fieldcolor;
+ wattron(form->pad, color);
+ mvwhline(form->pad, item->yfield, item->xfield, ' ', item->fieldcols);
+ n = 0;
+ cols = wcwidth(item->pubwbuf[item->xposdraw]);
+ while (cols <= item->fieldcols && item->xposdraw + n <
+ wcslen(item->pubwbuf)) {
+ n++;
+ cols += wcwidth(item->pubwbuf[item->xposdraw + n]);
- for (i = mf->pos; i < mf->buflen -1; i++) {
- mf->buf[i] = mf->buf[i+1];
}
+ mvwaddnwstr(form->pad, item->yfield, item->xfield,
+ &item->pubwbuf[item->xposdraw], n);
+ wattroff(form->pad, color);
- last = mf->buflen > 0 ? mf->buflen -1 : 0;
- mf->buf[last] = '\0';
- mf->buflen = last;
-}
-
-static void print_bottomdesc(struct myfield *mf)
-{
+ /* Bottom Desc */
move(SCREENLINES - 1, 2);
clrtoeol();
- if (mf->bottomdesc != NULL) {
- addstr(mf->bottomdesc);
+ if (item->bottomdesc != NULL && focus) {
+ attron(t.form.bottomdesccolor);
+ addstr(item->bottomdesc);
+ attroff(t.form.bottomdesccolor);
refresh();
}
+
+ /* Cursor */
+ curs_set((focus && item->cursor) ? 1 : 0);
+ wmove(form->pad, item->yfield, item->xfield + item->xcursor);
+
+ prefresh(form->pad, form->y, 0, form->ys, form->xs, form->ye, form->xe);
}
-static char *w2c(wchar_t *string)
+/*
+ * Trick: draw 2 times an item switching focus.
+ * Problem: curses tries to optimize the rendering but sometimes it misses some
+ * updates or draws old stuff. libformw has a similar problem fixed by the
+ * same trick.
+ * Case 1: KEY_DC and KEY_BACKSPACE, deleted multicolumn letters are drawn
+ * again. It seems fixed by new items pad and prefresh(), previously WINDOW.
+ * Case2: some terminal, tmux and ssh does not show the cursor.
+ */
+#define DRAWITEM_TRICK(form,item,focus) do { \
+ drawitem(form, item, !focus); \
+ drawitem(form, item, focus); \
+} while (0)
+
+static bool
+insertch(struct privateform *form, struct privateitem *item, wchar_t wch)
{
- int i, len;
- char *value;
+ int i;
+
+ if (item->nletters >= item->maxletters)
+ return (false);
- len = wcslen(string);
- if ((value = calloc(len + 1, sizeof(char))) == NULL)
- return NULL;
+ for (i = (int)item->nletters - 1; i >= (int)item->pos; i--) {
+ item->privwbuf[i+1] = item->privwbuf[i];
+ item->pubwbuf[i+1] = item->pubwbuf[i];
+ }
- for (i = 0; i < len; i++)
- value[i] = string[i];
- value[i] = '\0';
+ item->privwbuf[item->pos] = wch;
+ item->pubwbuf[item->pos] = item->secure ? form->securewch : wch;
+ item->nletters += 1;
+ item->privwbuf[item->nletters] = L'\0';
+ item->pubwbuf[item->nletters] = L'\0';
- return value;
+ return (true);
+}
+
+static char* alloc_wstomb(wchar_t *wstr)
+{
+ int len, nbytes, i;
+ char mbch[MB_LEN_MAX], *mbstr;
+
+ nbytes = MB_LEN_MAX; /* to ensure a null terminated string */
+ len = wcslen(wstr);
+ for (i = 0; i < len; i++) {
+ wctomb(mbch, wstr[i]);
+ nbytes += mblen(mbch, MB_LEN_MAX);
+ }
+ if((mbstr = malloc(nbytes)) == NULL)
+ return (NULL);
+
+ wcstombs(mbstr, wstr, nbytes);
+
+ return (mbstr);
}
static int
return_values(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_formitem *items, FORM *form, FIELD **cfield)
+ struct bsddialog_formitem *apiitems, struct privateitem *items)
{
int i;
- struct myfield *mf;
if (output != BSDDIALOG_OK && conf->form.value_without_ok == false)
return (output);
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_FIELD);
for (i = 0; i < nitems; i++) {
- mf = GETMYFIELD(cfield[i]);
- if (conf->form.enable_wchar) {
- items[i].value = (char*)wcsdup(mf->buf);
+ if (conf->form.value_wchar) {
+ apiitems[i].value = (char*)wcsdup(items[i].privwbuf);
} else {
- items[i].value = w2c(mf->buf);
+ apiitems[i].value = alloc_wstomb(items[i].privwbuf);
}
- if (items[i].value == NULL)
+ if (apiitems[i].value == NULL)
RETURN_ERROR("Cannot allocate memory for form value");
}
return (output);
}
-static int
-form_handler(struct bsddialog_conf *conf, WINDOW *widget, struct buttons bs,
- WINDOW *formwin, FORM *form, FIELD **cfield, int nitems,
- struct bsddialog_formitem *items)
+static unsigned int firstitem(unsigned int nitems, struct privateitem *items)
{
- bool loop, buttupdate, informwin;
- int i, chtype, output;
- wint_t input;
- struct myfield *mf;
+ int i;
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- pos_form_cursor(form);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- curs_set(1);
- informwin = true;
+ for (i = 0; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ break;
- bs.curr = -1;
- buttupdate = true;
+ return (i);
+}
- loop = true;
- while (loop) {
- if (buttupdate) {
- draw_buttons(widget, bs, !informwin);
- wrefresh(widget);
- buttupdate = false;
- }
- wrefresh(formwin);
- chtype = get_wch(&input);
- if (chtype != KEY_CODE_YES && input > 127 &&
- conf->form.enable_wchar == false)
- continue;
- switch(input) {
- case KEY_HOME:
- case KEY_PPAGE:
- case KEY_END:
- case KEY_NPAGE:
- /* disabled keys */
- break;
- case KEY_ENTER:
- case 10: /* Enter */
- if (informwin)
- break;
- output = return_values(conf, bs.value[bs.curr], nitems,
- items, form, cfield);
- loop = false;
- break;
- case 27: /* Esc */
- if (conf->key.enable_esc) {
- output = return_values(conf, BSDDIALOG_ESC,
- nitems, items, form, cfield);
- loop = false;
- }
- break;
- case '\t': /* TAB */
- if (informwin) {
- bs.curr = 0;
- informwin = false;
- curs_set(0);
- } else {
- bs.curr++;
- informwin = bs.curr >= (int)bs.nbuttons ?
- true : false;
- if (informwin) {
- curs_set(1);
- pos_form_cursor(form);
- }
- }
- buttupdate = true;
- break;
- case KEY_LEFT:
- if (informwin) {
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->pos > 0)
- mf->pos -= 1;
- } else {
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
- }
- break;
- case KEY_RIGHT:
- if (informwin) {
- mf = GETMYFIELD2(form);
- if (mf->pos >= mf->buflen)
- break;
- mf->pos += 1;
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_CHAR);
- } else {
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
- }
- break;
- case KEY_UP:
- if (nitems < 2)
- break;
- set_field_fore(current_field(form), t.form.fieldcolor);
- set_field_back(current_field(form), t.form.fieldcolor);
- form_driver_w(form, KEY_CODE_YES, REQ_PREV_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- set_field_fore(current_field(form), t.form.f_fieldcolor);
- set_field_back(current_field(form), t.form.f_fieldcolor);
- break;
- case KEY_DOWN:
- if (nitems < 2)
- break;
- set_field_fore(current_field(form), t.form.fieldcolor);
- set_field_back(current_field(form), t.form.fieldcolor);
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_FIELD);
- form_driver_w(form, KEY_CODE_YES, REQ_END_LINE);
- mf = GETMYFIELD2(form);
- print_bottomdesc(mf);
- mf->pos = MIN(mf->buflen, mf->maxpos);
- set_field_fore(current_field(form), t.form.f_fieldcolor);
- set_field_back(current_field(form), t.form.f_fieldcolor);
- break;
- case KEY_BACKSPACE:
- case 127: /* Backspace */
- mf = GETMYFIELD2(form);
- if (mf->pos <= 0)
- break;
- form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
- form_driver_w(form, KEY_CODE_YES, REQ_BEG_LINE);
- mf->pos = mf->pos - 1;
- for (i = 0; i < mf->pos; i++)
- form_driver_w(form, KEY_CODE_YES, REQ_NEXT_CHAR);
- shiftleft(mf);
- break;
- case KEY_DC:
- form_driver_w(form, KEY_CODE_YES, REQ_DEL_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->pos < mf->buflen)
- shiftleft(mf);
- break;
- case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
- break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No Break */
- case KEY_RESIZE:
- output = REDRAWFORM;
- loop = false;
- break;
- default:
- if (informwin) {
- if (chtype == KEY_CODE_YES)
- break;
- mf = GETMYFIELD2(form);
- if (mf->secure)
- form_driver_w(form, chtype, mf->securech);
- else
- form_driver_w(form, chtype, input);
- insertch(mf, input);
- }
- else {
- if (shortcut_buttons(input, &bs)) {
- output = return_values(conf,
- bs.value[bs.curr], nitems, items,
- form, cfield);
- loop = false;
- }
- }
+static unsigned int lastitem(unsigned int nitems, struct privateitem *items)
+{
+ int i;
+
+ for (i = nitems - 1; i >= 0 ; i--)
+ if (items[i].readonly == false)
break;
- }
- }
- curs_set(0);
+ return (i);
+}
- return (output);
+static unsigned int
+previtem(unsigned int nitems, struct privateitem *items, int curritem)
+{
+ int i;
+
+ for (i = curritem - 1; i >= 0; i--)
+ if (items[i].readonly == false)
+ return(i);
+
+ for (i = nitems - 1; i > curritem - 1; i--)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static unsigned int
+nextitem(unsigned int nitems, struct privateitem *items, int curritem)
+{
+ int i;
+
+ for (i = curritem + 1; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ for (i = 0; i < curritem; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static void
+redrawbuttons(WINDOW *window, struct buttons *bs, bool focus, bool shortcut)
+{
+ int selected;
+
+ selected = bs->curr;
+ if (focus == false)
+ bs->curr = -1;
+ draw_buttons(window, *bs, shortcut);
+ wrefresh(window);
+ bs->curr = selected;
}
+static void
+update_formborders(struct bsddialog_conf *conf, struct privateform *form)
+{
+ int h, w;
+
+ getmaxyx(form->border, h, w);
+ draw_borders(conf, form->border, h, w, LOWERED);
+
+ if (form->viewrows < form->h) {
+ wattron(form->border, t.dialog.arrowcolor);
+ if (form->y > 0)
+ mvwhline(form->border, 0, (w / 2) - 2,
+ conf->ascii_lines ? '^' : ACS_UARROW, 5);
+
+ if (form->y + form->viewrows < form->h)
+ mvwhline(form->border, h-1, (w / 2) - 2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 5);
+ wattroff(form->border, t.dialog.arrowcolor);
+ wrefresh(form->border);
+ }
+}
+
+/* use menu autosizing, linelen = form.w, nitems = form.h */
static int
-form_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *formheight, int nitems,
+menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
+ const char *text, int linelen, unsigned int *menurows, int nitems,
struct buttons bs)
{
- int htext, wtext, menusize;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, *formheight + 2,
- linelen + 2, &htext, &wtext) != 0)
+ int htext, wtext, menusize, notext;
+
+ notext = 2;
+ if (*menurows == BSDDIALOG_AUTOSIZE) {
+ /* algo 1): grows vertically */
+ /* notext = 1; */
+ /* algo 2): grows horizontally, better with little screens */
+ notext += nitems;
+ notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
+ } else
+ notext += *menurows;
+
+ /* cols autosize, rows autosize, rows fullscreen, menu particularity */
+ if (cols == BSDDIALOG_AUTOSIZE || rows <= BSDDIALOG_AUTOSIZE) {
+ if (text_size(conf, rows, cols, text, &bs, notext, linelen + 4,
+ &htext, &wtext) != 0)
return (BSDDIALOG_ERROR);
}
if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 2, &bs);
+ *w = widget_min_width(conf, wtext, linelen + 4, &bs);
if (rows == BSDDIALOG_AUTOSIZE) {
- if (*formheight == 0) {
+ if (*menurows == 0) {
menusize = widget_max_height(conf) - HBORDERS -
2 /*buttons*/ - htext;
menusize = MIN(menusize, nitems + 2);
- *formheight = menusize - 2 < 0 ? 0 : menusize - 2;
+ *menurows = menusize - 2 < 0 ? 0 : menusize - 2;
}
- else /* h autosize with fixed formheight */
- menusize = *formheight + 2;
+ else /* h autosize with fixed menurows */
+ menusize = *menurows + 2;
*h = widget_min_height(conf, htext, menusize, true);
+ /*
+ * avoid menurows overflow and
+ * with rows=AUTOSIZE menurows!=0 becomes max-menurows
+ */
+ *menurows = MIN(*h - 6 - htext, (int)*menurows);
} else {
- if (*formheight == 0)
- *formheight = MIN(rows-6-htext, nitems);
+ if (*menurows == 0) {
+ if (*h - 6 - htext <= 0)
+ *menurows = 0; /* form_checksize() will check */
+ else
+ *menurows = MIN(*h-6-htext, nitems);
+ }
}
return (0);
}
static int
-form_checksize(int rows, int cols, const char *text, int formheight, int nitems,
- unsigned int linelen, struct buttons bs)
+form_checksize(int rows, int cols, const char *text, struct privateform *form,
+ int nitems, struct buttons bs)
{
- int mincols, textrow, formrows;
+ int mincols, textrow, menusize;
+ /* cols */
mincols = VBORDERS;
- /* buttons */
- mincols += buttons_width(bs);
- mincols = MAX(mincols, (int)linelen + 4);
+ mincols += buttons_min_width(bs);
+ mincols = MAX(mincols, (int)form->w + 6);
if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "forms (label + field)");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+ RETURN_ERROR("Form width, cols < buttons or xlabels/xfields");
- if (nitems > 0 && formheight == 0)
- RETURN_ERROR("fields > 0 but formheight == 0, probably "
+ /* rows */
+ if (nitems > 0 && form->viewrows == 0)
+ RETURN_ERROR("items > 0 but viewrows == 0, if formheight = 0 "
"terminal too small");
- formrows = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + formrows + textrow)
- RETURN_ERROR("Few lines for this menus");
+ if (form->viewrows < form->minviewrows)
+ RETURN_ERROR("Few formheight rows, if formheight = 0 terminal "
+ "too small");
+
+ textrow = text != NULL && text[0] != '\0' ? 1 : 0;
+ menusize = nitems > 0 ? 3 : 0;
+ if (rows < 2 + 2 + menusize + textrow)
+ RETURN_ERROR("Few lines for this form");
return (0);
}
+static void curriteminview(struct privateform *form, struct privateitem *item)
+{
+ unsigned int yup, ydown;
+
+ yup = MIN(item->ylabel, item->yfield);
+ ydown = MAX(item->ylabel, item->yfield);
+
+ if (form->y > yup && form->y > 0)
+ form->y = yup;
+ if ((int)(form->y + form->viewrows) - 1 < (int)ydown)
+ form->y = ydown - form->viewrows + 1;
+}
+
+/* API */
int
bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items)
+ struct bsddialog_formitem *apiitems)
{
- int i, output, color, y, x, h, w;
- unsigned long j, maxline, mybufsize;
+ bool switchfocus, changeitem, focusinform, insecurecursor, loop;
+ int curritem, mbchsize, next, retval, y, x, h, w, wchtype;
+ unsigned int i, j, itemybeg, itemxbeg, tmp;
+ wchar_t *winit;
+ wint_t input;
+ WINDOW *widget, *textpad, *shadow;
+ struct privateitem *items, *item;
struct buttons bs;
- struct myfield *myfields;
- FIELD **cfield;
- FORM *form;
- WINDOW *widget, *formwin, *textpad, *shadow;
-
- /* disable form scrolling */
- if (formheight < nitems)
- formheight = nitems;
+ struct privateform form;
- for (i = 0; i < (int)nitems; i++) {
- if (items[i].maxvaluelen == 0)
+ for (i = 0; i < nitems; i++) {
+ if (apiitems[i].maxvaluelen == 0)
RETURN_ERROR("maxvaluelen cannot be zero");
- if (items[i].fieldlen == 0)
+ if (apiitems[i].fieldlen == 0)
RETURN_ERROR("fieldlen cannot be zero");
- if (items[i].fieldlen > items[i].maxvaluelen)
- RETURN_ERROR("fieldlen cannot be > maxvaluelen");
}
- maxline = 0;
- myfields = malloc(nitems * sizeof(struct myfield));
- cfield = calloc(nitems + 1, sizeof(FIELD*));
- for (i = 0; i < (int)nitems; i++) {
- cfield[i] = new_field(1, items[i].fieldlen, items[i].yfield-1,
- items[i].xfield-1, 0, 0);
- field_opts_off(cfield[i], O_STATIC);
- set_max_field(cfield[i], items[i].maxvaluelen);
- /* setlocale() should handle set_field_buffer() */
- set_field_buffer(cfield[i], 0, items[i].init);
-
- mybufsize = (items[i].maxvaluelen + 1) * sizeof(wchar_t);
- myfields[i].buf = malloc(mybufsize);
- memset(myfields[i].buf, 0, mybufsize);
- for (j = 0; j < items[i].maxvaluelen && j < strlen(items[i].init);
- j++)
- myfields[i].buf[j] = items[i].init[j];
-
- myfields[i].buflen = wcslen(myfields[i].buf);
-
- myfields[i].maxpos = items[i].maxvaluelen -1;
- myfields[i].pos = MIN(myfields[i].buflen, myfields[i].maxpos);
-
- myfields[i].bottomdesc = items[i].bottomdesc;
- set_field_userptr(cfield[i], &myfields[i]);
-
- field_opts_off(cfield[i], O_AUTOSKIP);
- field_opts_off(cfield[i], O_BLANK);
-
- if (ISFIELDHIDDEN(items[i])) {
- myfields[i].secure = true;
- myfields[i].securech = ' ';
- if (conf->form.securech != '\0')
- myfields[i].securech = conf->form.securech;
- }
+ insecurecursor = false;
+ if (conf->form.securembch != NULL) {
+ mbchsize = mblen(conf->form.securembch, MB_LEN_MAX);
+ if(mbtowc(&form.securewch, conf->form.securembch, mbchsize) < 0)
+ RETURN_ERROR("Cannot convert securembch to wchar_t");
+ insecurecursor = true;
+ } else if (conf->form.securech != '\0') {
+ form.securewch = btowc(conf->form.securech);
+ insecurecursor = true;
+ } else {
+ form.securewch = L' ';
+ }
+
+ if ((items = malloc(nitems * sizeof(struct privateitem))) == NULL)
+ RETURN_ERROR("Cannot allocate internal items");
+ form.h = form.w = form.minviewrows = 0;
+ for (i = 0; i < nitems; i++) {
+ item = &items[i];
+ item->label = apiitems[i].label;
+ item->ylabel = apiitems[i].ylabel;
+ item->xlabel = apiitems[i].xlabel;
+ item->yfield = apiitems[i].yfield;
+ item->xfield = apiitems[i].xfield;
+ item->secure = apiitems[i].flags & BSDDIALOG_FIELDHIDDEN;
+ item->readonly = apiitems[i].flags & BSDDIALOG_FIELDREADONLY;
+ item->fieldnocolor = apiitems[i].flags & BSDDIALOG_FIELDNOCOLOR;
+ item->extendfield = apiitems[i].flags & BSDDIALOG_FIELDEXTEND;
+ item->fieldonebyte = apiitems[i].flags &
+ BSDDIALOG_FIELDSINGLEBYTE;
+ item->cursorend = apiitems[i].flags & BSDDIALOG_FIELDCURSOREND;
+ item->bottomdesc = apiitems[i].bottomdesc;
+ if (item->readonly || (item->secure && !insecurecursor))
+ item->cursor = false;
else
- myfields[i].secure = false;
+ item->cursor = true;
+
+ item->maxletters = apiitems[i].maxvaluelen;
+ item->privwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->privwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->privwbuf, 0, item->maxletters + 1);
+ item->pubwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->pubwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->pubwbuf, 0, item->maxletters + 1);
+
+ if ((winit = alloc_mbstows(apiitems[i].init)) == NULL)
+ RETURN_ERROR("Cannot allocate item.init in wchar_t*");
+ wcsncpy(item->privwbuf, winit, item->maxletters);
+ wcsncpy(item->pubwbuf, winit, item->maxletters);
+ free(winit);
+ item->nletters = wcslen(item->pubwbuf);
+ if (item->secure) {
+ for (j = 0; j < item->nletters; j++)
+ item->pubwbuf[j] = form.securewch;
+ }
- if (ISFIELDREADONLY(items[i])) {
- field_opts_off(cfield[i], O_EDIT);
- field_opts_off(cfield[i], O_ACTIVE);
- color = t.form.readonlycolor;
+ item->fieldcols = apiitems[i].fieldlen;
+ item->xposdraw = 0;
+ item->xcursor = 0;
+ item->pos = 0;
+
+ form.h = MAX(form.h, items[i].ylabel);
+ form.h = MAX(form.h, items[i].yfield);
+ form.w = MAX(form.w, items[i].xlabel + strcols(items[i].label));
+ form.w = MAX(form.w, items[i].xfield + items[i].fieldcols);
+ if (i == 0) {
+ itemybeg = MIN(items[i].ylabel, items[i].yfield);
+ itemxbeg = MIN(items[i].xlabel, items[i].xfield);
} else {
- color = i == 0 ? t.form.f_fieldcolor : t.form.fieldcolor;
+ tmp = MIN(items[i].ylabel, items[i].yfield);
+ itemybeg = MIN(itemybeg, tmp);
+ tmp = MIN(items[i].xlabel, items[i].xfield);
+ itemxbeg = MIN(itemxbeg, tmp);
}
- set_field_fore(cfield[i], color);
- set_field_back(cfield[i], color);
-
- maxline = MAX(maxline, items[i].xlabel + strlen(items[i].label));
- maxline = MAX(maxline, items[i].xfield + items[i].fieldlen - 1);
+ tmp = abs((int)items[i].ylabel - (int)items[i].yfield);
+ form.minviewrows = MAX(form.minviewrows, tmp);
}
- cfield[i] = NULL;
-
- /* disable focus with 1 item (inputbox or passwordbox) */
- if (formheight == 1 && nitems == 1 && strlen(items[0].label) == 0 &&
- items[0].xfield == 1 ) {
- set_field_fore(cfield[0], t.dialog.color);
- set_field_back(cfield[0], t.dialog.color);
+ if (nitems > 0) {
+ form.h = form.h + 1 - itemybeg;
+ form.w -= itemxbeg;
+ form.minviewrows += 1;
+ }
+ form.wmin = form.w;
+ for (i = 0; i < nitems; i++) {
+ items[i].ylabel -= itemybeg;
+ items[i].yfield -= itemybeg;
+ items[i].xlabel -= itemxbeg;
+ items[i].xfield -= itemxbeg;
}
get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
+ form.viewrows = formheight;
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
return (BSDDIALOG_ERROR);
- if (form_autosize(conf, rows, cols, &h, &w, text, maxline, &formheight,
- nitems, bs) != 0)
+ if (menu_autosize(conf, rows, cols, &h, &w, text, form.w,
+ &form.viewrows, form.h, bs) != 0)
return (BSDDIALOG_ERROR);
- if (form_checksize(h, w, text, formheight, nitems, maxline, bs) != 0)
+ if (form_checksize(h, w, text, &form, nitems, bs) != 0)
return (BSDDIALOG_ERROR);
if (set_widget_position(conf, &y, &x, h, w) != 0)
return (BSDDIALOG_ERROR);
@@ -483,55 +637,308 @@ bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
true) != 0)
return (BSDDIALOG_ERROR);
+ doupdate();
+
prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
+ y + h - form.viewrows, x + 1 + w - TEXTHMARGIN);
- formwin = new_boxed_window(conf, y + h - 3 - formheight -2, x +1,
- formheight+2, w-2, LOWERED);
+ form.border = new_boxed_window(conf, y + h - 5 - form.viewrows, x + 2,
+ form.viewrows + 2, w - 4, LOWERED);
- form = new_form(cfield);
- set_form_win(form, formwin);
- /* should be formheight */
- set_form_sub(form, derwin(formwin, nitems, w-4, 1, 1));
- post_form(form);
+ for (i = 0; i < nitems; i++) {
+ if (items[i].extendfield) {
+ form.w = w - 6;
+ items[i].fieldcols = form.w - items[i].xfield;
+ }
+ if (items[i].cursorend)
+ fieldctl(item, MOVE_CURSOR_END);
+ }
- for (i = 0; i < (int)nitems; i++)
- mvwaddstr(formwin, items[i].ylabel, items[i].xlabel,
- items[i].label);
+ form.pad = newpad(form.h, form.w);
+ wbkgd(form.pad, t.dialog.color);
+
+ form.ys = y + h - 5 - form.viewrows + 1;
+ form.ye = y + h - 5 ;
+ if ((int)form.w >= w - 6) { /* left */
+ form.xs = x + 3;
+ form.xe = form.xs + w - 7;
+ } else { /* center */
+ form.xs = x + 3 + (w-6)/2 - form.w/2;
+ form.xe = form.xs + w - 5;
+ }
+
+ curritem = -1;
+ for (i=0 ; i < nitems; i++) {
+ DRAWITEM_TRICK(&form, &items[i], false);
+ if (curritem == -1 && items[i].readonly == false)
+ curritem = i;
+ }
+ if (curritem != -1) {
+ focusinform = true;
+ redrawbuttons(widget, &bs, conf->button.always_active, false);
+ form.y = 0;
+ item = &items[curritem];
+ curriteminview(&form, item);
+ update_formborders(conf, &form);
+ wrefresh(form.border);
+ DRAWITEM_TRICK(&form, item, true);
+ } else {
+ item = NULL;
+ focusinform = false;
+ wrefresh(form.border);
+ }
- wrefresh(formwin);
+ changeitem = switchfocus = false;
+ loop = true;
+ while (loop) {
+ if ((wchtype = get_wch(&input)) == ERR)
+ continue;
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ if (focusinform && conf->button.always_active == false)
+ break;
+ retval = return_values(conf, bs.value[bs.curr],
+ nitems, apiitems, items);
+ loop = false;
+ break;
+ case 27: /* Esc */
+ if (conf->key.enable_esc) {
+ retval = return_values(conf, BSDDIALOG_ESC,
+ nitems, apiitems, items);
+ loop = false;
+ }
+ break;
+ case '\t': /* TAB */
+ if (focusinform) {
+ switchfocus = true;
+ } else {
+ if (bs.curr + 1 < (int)bs.nbuttons) {
+ bs.curr++;
+ } else {
+ bs.curr = 0;
+ if (curritem != -1) {
+ switchfocus = true;
+ }
+ }
+ draw_buttons(widget, bs, true);
+ wrefresh(widget);
+ }
+ break;
+ case KEY_LEFT:
+ if (focusinform) {
+ if(fieldctl(item, MOVE_CURSOR_LEFT))
+ DRAWITEM_TRICK(&form, item, true);
+ } else if (bs.curr > 0) {
+ bs.curr--;
+ draw_buttons(widget, bs, true);
+ wrefresh(widget);
+ } else if (curritem != -1) {
+ switchfocus = true;
+ }
+ break;
+ case KEY_RIGHT:
+ if (focusinform) {
+ if(fieldctl(item, MOVE_CURSOR_RIGHT))
+ DRAWITEM_TRICK(&form, item, true);
+ } else if (bs.curr < (int) bs.nbuttons - 1) {
+ bs.curr++;
+ draw_buttons(widget, bs, true);
+ wrefresh(widget);
+ } else if (curritem != -1) {
+ switchfocus = true;
+ }
+ break;
+ case KEY_UP:
+ if (focusinform) {
+ next = previtem(nitems, items, curritem);
+ changeitem = curritem != next;
+ } else if (curritem != -1) {
+ switchfocus = true;
+ }
+ break;
+ case KEY_DOWN:
+ if (focusinform == false)
+ break;
+ if (nitems == 1) {
+ switchfocus = true;
+ } else {
+ next = nextitem(nitems, items, curritem);
+ changeitem = curritem != next;
+ }
+ break;
+ case KEY_PPAGE:
+ if (focusinform) {
+ next = firstitem(nitems, items);
+ changeitem = curritem != next;
+ }
+ break;
+ case KEY_NPAGE:
+ if (focusinform) {
+ next = lastitem(nitems, items);
+ changeitem = curritem != next;
+ }
+ break;
+ case KEY_BACKSPACE:
+ case 127: /* Backspace */
+ if (focusinform == false)
+ break;
+ if(fieldctl(item, MOVE_CURSOR_LEFT))
+ if(fieldctl(item, DEL_LETTER))
+ DRAWITEM_TRICK(&form, item, true);
+ break;
+ case KEY_DC:
+ if (focusinform == false)
+ break;
+ if(fieldctl(item, DEL_LETTER))
+ DRAWITEM_TRICK(&form, item, true);
+ break;
+ case KEY_HOME:
+ if (focusinform == false)
+ break;
+ if(fieldctl(item, MOVE_CURSOR_BEGIN))
+ DRAWITEM_TRICK(&form, item, true);
+ break;
+ case KEY_END:
+ if (focusinform == false)
+ break;
+ if (fieldctl(item, MOVE_CURSOR_END))
+ DRAWITEM_TRICK(&form, item, true);
+ break;
+ case KEY_F(1):
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
+ break;
+ curs_set(0);
+ if (f1help(conf) != 0) {
+ retval = BSDDIALOG_ERROR;
+ loop = false;
+ }
+ /* No break, screen size can change */
+ case KEY_RESIZE:
+ /* Important for decreasing screen */
+ hide_widget(y, x, h, w, conf->shadow);
+ refresh();
- do {
- output = form_handler(conf, widget, bs, formwin, form, cfield,
- nitems, items);
+ form.viewrows = formheight;
+ form.w = form.wmin;
+ if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (menu_autosize(conf, rows, cols, &h, &w, text, form.w,
+ &form.viewrows, form.h, bs) != 0)
+ return (BSDDIALOG_ERROR);
+ if (form_checksize(h, w, text, &form, nitems, bs) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(conf, &y, &x, h, w) != 0)
+ return (BSDDIALOG_ERROR);
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- text, &bs, true) != 0)
+ if (update_dialog(conf, shadow, widget, y, x, h, w,
+ textpad, text, &bs, true) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
- wrefresh(widget);
+ doupdate();
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
+ prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
+ y + h - form.viewrows, x + 1 + w - TEXTHMARGIN);
- draw_borders(conf, formwin, formheight+2, w-2, LOWERED);
- wrefresh(formwin);
+ wclear(form.border);
+ mvwin(form.border, y + h - 5 - form.viewrows, x + 2);
+ wresize(form.border, form.viewrows + 2, w - 4);
- refresh();
- } while (output == REDRAWFORM);
+ for (i = 0; i < nitems; i++) {
+ fieldctl(&items[i], MOVE_CURSOR_BEGIN);
+ if (items[i].extendfield) {
+ form.w = w - 6;
+ items[i].fieldcols =
+ form.w - items[i].xfield;
+ }
+ if (items[i].cursorend)
+ fieldctl(&items[i], MOVE_CURSOR_END);
+ }
- unpost_form(form);
- free_form(form);
- for (i = 0; i < (int)nitems; i++) {
- free_field(cfield[i]);
- free(myfields[i].buf);
- }
- free(cfield);
- free(myfields);
+ form.ys = y + h - 5 - form.viewrows + 1;
+ form.ye = y + h - 5 ;
+ if ((int)form.w >= w - 6) { /* left */
+ form.xs = x + 3;
+ form.xe = form.xs + w - 7;
+ } else { /* center */
+ form.xs = x + 3 + (w-6)/2 - form.w/2;
+ form.xe = form.xs + w - 5;
+ }
+
+ if (curritem != -1) {
+ redrawbuttons(widget, &bs,
+ conf->button.always_active || !focusinform,
+ !focusinform);
+ curriteminview(&form, item);
+ update_formborders(conf, &form);
+ wrefresh(form.border);
+ /* drawitem just to prefresh() pad */
+ DRAWITEM_TRICK(&form, item, focusinform);
+ } else {
+ wrefresh(form.border);
+ }
+ break;
+ default:
+ if (wchtype == KEY_CODE_YES)
+ break;
+ if (focusinform) {
+ if (item->fieldonebyte && wctob(input) == EOF)
+ break;
+ /*
+ * MOVE_CURSOR_RIGHT manages new positions
+ * because the cursor remains on the new letter,
+ * "if" and "while" update the positions.
+ */
+ if(insertch(&form, item, input)) {
+ fieldctl(item, MOVE_CURSOR_RIGHT);
+ /*
+ * no if(fieldctl), update always
+ * because it fails with maxletters.
+ */
+ DRAWITEM_TRICK(&form, item, true);
+ }
+ } else {
+ if (shortcut_buttons(input, &bs)) {
+ retval = return_values(conf,
+ bs.value[bs.curr], nitems, apiitems,
+ items);
+ loop = false;
+ }
+ }
+ break;
+ } /* end switch handler */
+
+ if (switchfocus) {
+ focusinform = !focusinform;
+ bs.curr = 0;
+ redrawbuttons(widget, &bs,
+ conf->button.always_active || !focusinform,
+ !focusinform);
+ DRAWITEM_TRICK(&form, item, focusinform);
+ switchfocus = false;
+ }
+
+ if (changeitem) {
+ DRAWITEM_TRICK(&form, item, false);
+ curritem = next;
+ item = &items[curritem];
+ curriteminview(&form, item);
+ update_formborders(conf, &form);
+ DRAWITEM_TRICK(&form, item, true);
+ changeitem = false;
+ }
+ } /* end while handler */
+
+ curs_set(0);
- delwin(formwin);
+ delwin(form.pad);
+ delwin(form.border);
+ for (i = 0; i < nitems; i++) {
+ free(items[i].privwbuf);
+ free(items[i].pubwbuf);
+ }
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
}
diff --git a/lib/infobox.c b/lib/infobox.c
index 5a6b7c2fd692..c8a0b6e90c8e 100644
--- a/lib/infobox.c
+++ b/lib/infobox.c
@@ -39,13 +39,13 @@ infobox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
int htext, wtext;
if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
+ if (text_size(conf, rows, cols, text, NULL, 0, 1, &htext,
+ &wtext) != 0)
return (BSDDIALOG_ERROR);
}
if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, NULL);
+ *w = widget_min_width(conf, wtext, TEXTHMARGINS + 1, NULL);
if (rows == BSDDIALOG_AUTOSIZE)
*h = widget_min_height(conf, htext, 0, false);
diff --git a/lib/lib_util.c b/lib/lib_util.c
index 4c2ab76bc592..fcdf4c3d8769 100644
--- a/lib/lib_util.c
+++ b/lib/lib_util.c
@@ -32,13 +32,14 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define TABLEN 4 /* Default tab len */
-#define ERRBUFLEN 1024 /* Error buffer */
+#define ERRBUFLEN 1024 /* Error buffer len */
/* Error */
static char errorbuffer[ERRBUFLEN];
@@ -53,12 +54,101 @@ void set_error_string(const char *str)
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
+/* Unicode */
+wchar_t* alloc_mbstows(const char *mbstring)
+{
+ size_t charlen, nchar;
+ mbstate_t mbs;
+ const char *pmbstring;
+ wchar_t *wstring;
+
+ nchar = 1;
+ pmbstring = mbstring;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ pmbstring += charlen;
+ nchar++;
+ }
+
+ if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL)
+ return (NULL);
+ mbstowcs(wstring, mbstring, nchar);
+
+ return (wstring);
+}
+
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
+{
+ wchar_t ws[2];
+
+ ws[0] = wch;
+ ws[1] = L'\0';
+ mvwaddwstr(w, y, x, ws);
+
+}
+
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
+{
+ bool multicol;
+ int w;
+ unsigned int ncol;
+ size_t charlen, mb_cur_max;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ multicol = false;
+ mb_cur_max = MB_CUR_MAX;
+ ncol = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
+ return (-1);
+ w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ ncol += (w < 0) ? 0 : w;
+ if (w > 1 && wch != L'\t')
+ multicol = true;
+ mbstring += charlen;
+ }
+
+ if (cols != NULL)
+ *cols = ncol;
+ if (has_multi_col != NULL)
+ *has_multi_col = multicol;
+
+ return (0);
+}
+
+unsigned int strcols(const char *mbstring)
+{
+ int w;
+ unsigned int ncol;
+ size_t charlen, mb_cur_max;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ mb_cur_max = MB_CUR_MAX;
+ ncol = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
+ return (0);
+ w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ ncol += (w < 0) ? 0 : w;
+ mbstring += charlen;
+ }
+
+ return (ncol);
+}
+
/* Clear */
int hide_widget(int y, int x, int h, int w, bool withshadow)
{
WINDOW *clear;
- if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL)
+ if ((clear = newwin(h, w, y + t.shadow.y, x + t.shadow.x)) == NULL)
RETURN_ERROR("Cannot hide the widget");
wbkgd(clear, t.screen.color);
@@ -101,7 +191,7 @@ int f1help(struct bsddialog_conf *conf)
/* Buttons */
static void
draw_button(WINDOW *window, int y, int x, int size, const char *text,
- bool selected, bool shortcut)
+ wchar_t first, bool selected, bool shortcut)
{
int i, color_arrows, color_shortkey, color_button;
@@ -126,14 +216,14 @@ draw_button(WINDOW *window, int y, int x, int size, const char *text,
mvwaddch(window, y, x + i, t.button.rightdelim);
wattroff(window, color_arrows);
- x = x + 1 + ((size - 2 - strlen(text))/2);
+ x = x + 1 + ((size - 2 - strcols(text))/2);
wattron(window, color_button);
mvwaddstr(window, y, x, text);
wattroff(window, color_button);
if (shortcut) {
wattron(window, color_shortkey);
- mvwaddch(window, y, x, text[0]);
+ mvwaddwch(window, y, x, first);
wattroff(window, color_shortkey);
}
}
@@ -142,16 +232,28 @@ void
draw_buttons(WINDOW *window, struct buttons bs, bool shortcut)
{
int i, x, startx, y, rows, cols;
+ unsigned int newmargin, margin, wbuttons;
getmaxyx(window, rows, cols);
y = rows - 2;
- startx = cols/2 - buttons_width(bs)/2;
+ newmargin = cols - VBORDERS - (bs.nbuttons * bs.sizebutton);
+ newmargin /= (bs.nbuttons + 1);
+ newmargin = MIN(newmargin, t.button.maxmargin);
+ if (newmargin == 0) {
+ margin = t.button.minmargin;
+ wbuttons = buttons_min_width(bs);
+ } else {
+ margin = newmargin;
+ wbuttons = bs.nbuttons * bs.sizebutton;
+ wbuttons += (bs.nbuttons + 1) * margin;
+ }
+ startx = (cols)/2 - wbuttons/2 + newmargin;
for (i = 0; i < (int)bs.nbuttons; i++) {
- x = i * (bs.sizebutton + t.button.hmargin);
+ x = i * (bs.sizebutton + margin);
draw_button(window, y, startx + x, bs.sizebutton, bs.label[i],
- i == bs.curr, shortcut);
+ bs.first[i], i == bs.curr, shortcut);
}
}
@@ -163,6 +265,7 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
#define SIZEBUTTON 8
#define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL
#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
+ wchar_t first;
bs->nbuttons = 0;
bs->curr = 0;
@@ -216,6 +319,11 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
bs->nbuttons = 1;
}
+ for (i = 0; i < (int)bs->nbuttons; i++) {
+ mbtowc(&first, bs->label[i], MB_CUR_MAX);
+ bs->first[i] = first;
+ }
+
if (conf->button.default_label != NULL) {
for (i = 0; i < (int)bs->nbuttons; i++) {
if (strcmp(conf->button.default_label,
@@ -224,31 +332,31 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
}
}
- bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
+ bs->sizebutton = MAX(SIZEBUTTON - 2, strcols(bs->label[0]));
for (i = 1; i < (int)bs->nbuttons; i++)
- bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
+ bs->sizebutton = MAX(bs->sizebutton, strcols(bs->label[i]));
bs->sizebutton += 2;
}
-int buttons_width(struct buttons bs)
+int buttons_min_width(struct buttons bs)
{
unsigned int width;
width = bs.nbuttons * bs.sizebutton;
if (bs.nbuttons > 0)
- width += (bs.nbuttons - 1) * t.button.hmargin;
+ width += (bs.nbuttons - 1) * t.button.minmargin;
return (width);
}
-bool shortcut_buttons(int key, struct buttons *bs)
+bool shortcut_buttons(wint_t key, struct buttons *bs)
{
bool match;
unsigned int i;
match = false;
for (i = 0; i < bs->nbuttons; i++) {
- if (tolower(key) == tolower(bs->label[i][0])) {
+ if (towlower(key) == towlower(bs->first[i])) {
bs->curr = i;
match = true;
break;
@@ -259,48 +367,51 @@ bool shortcut_buttons(int key, struct buttons *bs)
}
/* Text */
-static bool is_text_attr(const char *text)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- if (strnlen(text, 3) < 3)
+ if (wcsnlen(wtext, 3) < 3)
return (false);
- if (text[0] != '\\' || text[1] != 'Z')
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
return (false);
- return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true);
+ return (wcschr(L"nbBrRuU01234567", wtext[2]) == NULL ? false : true);
}
-static bool check_set_text_attr(WINDOW *win, char *text)
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
{
- if (is_text_attr(text) == false)
+ enum bsddialog_color bg;
+
+ if (is_wtext_attr(wtext) == false)
return (false);
- if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) {
- wattron(win, bsddialog_color(text[2] - '0', COLOR_WHITE, 0));
+ if ((wtext[2] - L'0') >= 0 && (wtext[2] - L'0') < 8) {
+ bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
+ wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
return (true);
}
- switch (text[2]) {
- case 'n':
+ switch (wtext[2]) {
+ case L'n':
wattron(win, t.dialog.color);
wattrset(win, A_NORMAL);
break;
- case 'b':
+ case L'b':
wattron(win, A_BOLD);
break;
- case 'B':
+ case L'B':
wattroff(win, A_BOLD);
break;
- case 'r':
+ case L'r':
wattron(win, A_REVERSE);
break;
- case 'R':
+ case L'R':
wattroff(win, A_REVERSE);
break;
- case 'u':
+ case L'u':
wattron(win, A_UNDERLINE);
break;
- case 'U':
+ case L'U':
wattroff(win, A_UNDERLINE);
break;
}
@@ -308,21 +419,27 @@ static bool check_set_text_attr(WINDOW *win, char *text)
return (true);
}
+/* Word Wrapping */
static void
-print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str,
+print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
bool color)
{
- int i, j, len, reallen;
+ int i, j, len, reallen, wc;
+ wchar_t ws[2];
+
+ ws[1] = L'\0';
- len = reallen = strlen(str);
+ len = wcslen(str);
if (color) {
+ reallen = 0;
i=0;
while (i < len) {
- if (is_text_attr(str+i))
- reallen -= 3;
+ if (is_wtext_attr(str+i) == false)
+ reallen += wcwidth(str[i]);
i++;
}
- }
+ } else
+ reallen = wcswidth(str, len);
i = 0;
while (i < len) {
@@ -336,13 +453,18 @@ print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str,
}
j = *x;
while (j < cols && i < len) {
- if (color && check_set_text_attr(win, str+i)) {
+ if (color && check_set_wtext_attr(win, str+i)) {
i += 3;
+ } else if (j + wcwidth(str[i]) > cols) {
+ break;
} else {
- mvwaddch(win, *y, j, str[i]);
+ /* inline mvwaddwch() for efficiency */
+ ws[0] = str[i];
+ mvwaddwstr(win, *y, j, ws);
+ wc = wcwidth(str[i]);;
+ reallen -= wc;
+ j += wc;
i++;
- reallen--;
- j++;
*x = j;
}
}
@@ -354,35 +476,38 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
{
bool loop;
int i, j, z, rows, cols, x, y, tablen;
- char *string;
+ wchar_t *wtext, *string;
+
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- if ((string = malloc(strlen(text) + 1)) == NULL)
+ if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
RETURN_ERROR("Cannot build (analyze) text");
getmaxyx(pad, rows, cols);
- tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen;
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
i = j = x = y = 0;
loop = true;
while (loop) {
- string[j] = text[i];
+ string[j] = wtext[i];
- if (strchr("\n\t ", string[j]) != NULL || string[j] == '\0') {
- string[j] = '\0';
+ if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
+ string[j] = L'\0';
print_string(pad, &rows, cols, &y, &x, string,
conf->text.highlight);
}
- switch (text[i]) {
- case '\0':
+ switch (wtext[i]) {
+ case L'\0':
loop = false;
break;
- case '\n':
+ case L'\n':
x = 0;
y++;
j = -1;
break;
- case '\t':
+ case L'\t':
for (z = 0; z < tablen; z++) {
if (x >= cols) {
x = 0;
@@ -392,7 +517,7 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
}
j = -1;
break;
- case ' ':
+ case L' ':
x++;
if (x >= cols) {
x = 0;
@@ -410,78 +535,133 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
i++;
}
+ free(wtext);
free(string);
return (0);
}
-/* Autosize */
+/* Text Autosize */
+#define NL -1
+#define WS -2
+#define TB -3
+
+struct textproperties {
+ int nword;
+ int *words;
+ uint8_t *wletters;
+ int maxwordcols;
+ int maxline;
+ bool hasnewline;
+};
+
static int
-text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
- int mincols, bool increasecols, int *h, int *w)
+text_properties(struct bsddialog_conf *conf, const char *text,
+ struct textproperties *tp)
{
- int i, j, z, x, y;
- int tablen, wordlen, maxwordlen, nword, maxwords, line, maxwidth;
- int *words;
-#define NL -1
-#define WS -2
+ int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
+ wchar_t *wtext;
+
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
maxwords = 1024;
- if ((words = calloc(maxwords, sizeof(int))) == NULL)
+ if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
RETURN_ERROR("Cannot alloc memory for text autosize");
- tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen;
- maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS;
-
- nword = 0;
- wordlen = 0;
- maxwordlen = 0;
- i=0;
- while (true) {
- if (conf->text.highlight && is_text_attr(text + i)) {
- i += 3;
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/autosize text in wchar_t*");
+ wtextlen = wcslen(wtext);
+ if ((tp->wletters = calloc(wtextlen, sizeof(uint8_t))) == NULL)
+ RETURN_ERROR("Cannot allocate wletters for text autosizing");
+
+ tp->nword = 0;
+ tp->maxline = 0;
+ tp->maxwordcols = 0;
+ tp->hasnewline = false;
+ currlinecols = 0;
+ wordcols = 0;
+ l = 0;
+ for (i = 0; i < wtextlen; i++) {
+ if (conf->text.highlight && is_wtext_attr(wtext + i)) {
+ i += 2; /* +1 for update statement */
continue;
}
- if (nword + tablen >= maxwords) {
+ if (tp->nword + 1 >= maxwords) {
maxwords += 1024;
- if (realloc(words, maxwords * sizeof(int)) == NULL)
+ tp->words = realloc(tp->words, maxwords * sizeof(int));
+ if (tp->words == NULL)
RETURN_ERROR("Cannot realloc memory for text "
"autosize");
}
- if (text[i] == '\0') {
- words[nword] = wordlen;
- maxwordlen = MAX(wordlen, maxwordlen);
- break;
- }
-
- if (strchr("\t\n ", text[i]) != NULL) {
- maxwordlen = MAX(wordlen, maxwordlen);
+ if (wcschr(L"\t\n ", wtext[i]) != NULL) {
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
- if (wordlen != 0) {
- words[nword] = wordlen;
- nword++;
- wordlen = 0;
+ if (wordcols != 0) {
+ /* line */
+ currlinecols += wordcols;
+ /* word */
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ wordcols = 0;
}
- if (text[i] == '\t') {
- for (j = 0; j < tablen; j++)
- words[nword + j] = 1;
- nword += tablen;
- } else {
- words[nword] = text[i] == '\n' ? NL : WS;
- nword++;
+ switch (wtext[i]) {
+ case L'\t':
+ /* line */
+ currlinecols += tablen;
+ /* word */
+ tp->words[tp->nword] = TB;
+ break;
+ case L'\n':
+ /* line */
+ tp->hasnewline = true;
+ tp->maxline = MAX(tp->maxline, currlinecols);
+ currlinecols = 0;
+ /* word */
+ tp->words[tp->nword] = NL;
+ break;
+ case L' ':
+ /* line */
+ currlinecols += 1;
+ /* word */
+ tp->words[tp->nword] = WS;
+ break;
}
+ tp->nword += 1;
+ } else {
+ tp->wletters[l] = wcwidth(wtext[i]);
+ wordcols += tp->wletters[l];
+ l++;
}
- else
- wordlen++;
-
- i++;
}
+ /* word */
+ if (wordcols != 0) {
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
+ }
+ /* line */
+ tp->maxline = MAX(tp->maxline, currlinecols);
+
+ free(wtext);
+
+ return (0);
+}
+
+
+static int
+text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
+ int maxrows, int mincols, bool increasecols, int *h, int *w)
+{
+ int i, j, x, y, z, l, line, maxwidth, tablen;
+
+ maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS;
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
if (increasecols) {
- mincols = MAX(mincols, maxwordlen);
+ mincols = MAX(mincols, tp->maxwordcols);
mincols = MAX(mincols,
(int)conf->auto_minwidth - HBORDERS - TEXTHMARGINS);
mincols = MIN(mincols, maxwidth);
@@ -491,26 +671,50 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
x = 0;
y = 1;
line=0;
- for (i = 0; i <= nword; i++) {
- if (words[i] == NL) {
+ l = 0;
+ for (i = 0; i < tp->nword; i++) {
+ switch (tp->words[i]) {
+ case TB:
+ for (j = 0; j < tablen; j++) {
+ if (x >= mincols) {
+ x = 0;
+ y++;
+ }
+ x++;
+ }
+ break;
+ case NL:
y++;
x = 0;
- }
- else if (words[i] == WS) {
+ break;
+ case WS:
x++;
if (x >= mincols) {
x = 0;
y++;
}
- }
- else {
- if (words[i] + x <= mincols)
- x += words[i];
- else {
- for (z = words[i]; z > 0; ) {
- y++;
- x = MIN(mincols, z);
- z -= x;
+ break;
+ default:
+ if (tp->words[i] + x <= mincols) {
+ x += tp->words[i];
+ for (z = 0 ; z != tp->words[i]; l++ )
+ z += tp->wletters[l];
+ } else if (tp->words[i] <= mincols) {
+ y++;
+ x = tp->words[i];
+ for (z = 0 ; z != tp->words[i]; l++ )
+ z += tp->wletters[l];
+ } else {
+ for (j = tp->words[i]; j > 0; ) {
+ y = (x == 0) ? y : y + 1;
+ z = 0;
+ while (z != j && z < mincols) {
+ z += tp->wletters[l];
+ l++;
+ }
+ x = z;
+ line = MAX(line, x);
+ j -= z;
}
}
}
@@ -519,16 +723,16 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows,
if (increasecols == false)
break;
- if (y <= maxrows || mincols >= maxwidth)
+ if (mincols >= maxwidth)
+ break;
+ if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
break;
mincols++;
}
- *h = (nword == 0 && words[0] == 0) ? 0 : y;
+ *h = (tp->nword == 0) ? 0 : y;
*w = MIN(mincols, line); /* wtext can be less than mincols */
- free(words);
-
return (0);
}
@@ -536,13 +740,26 @@ int
text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
{
- int wbuttons, maxhtext;
bool changewtext;
+ int wbuttons, maxhtext;
+ struct textproperties tp;
wbuttons = 0;
if (bs != NULL)
- wbuttons = buttons_width(*bs);
+ wbuttons = buttons_min_width(*bs);
+
+ /* Rows */
+ if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
+ maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext;
+ } else { /* fixed */
+ maxhtext = rows - VBORDERS - rowsnotext;
+ }
+ if (bs != NULL)
+ maxhtext -= 2;
+ if (maxhtext <= 0)
+ maxhtext = 1; /* text_autosize() computes always htext */
+ /* Cols */
if (cols == BSDDIALOG_AUTOSIZE) {
startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
changewtext = true;
@@ -554,45 +771,52 @@ text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
changewtext = false;
}
- if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
- maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext;
- if (bs != NULL)
- maxhtext -= 2;
- } else { /* fixed */
- maxhtext = rows - VBORDERS - rowsnotext;
- if (bs != NULL)
- maxhtext -= 2;
- }
-
if (startwtext <= 0 && changewtext)
startwtext = 1;
- if (maxhtext <= 0 || startwtext <= 0) {
- *htext = *wtext = 0;
- return (0);
- }
+ if (startwtext <= 0)
+ RETURN_ERROR("Fullscreen or fixed cols to print text <=0");
- if (text_autosize(conf, text, maxhtext, startwtext, changewtext,
- htext, wtext) != 0)
+ /* Sizing calculation */
+ if (text_properties(conf, text, &tp) != 0)
+ return (BSDDIALOG_ERROR);
+ if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
+ wtext) != 0)
return (BSDDIALOG_ERROR);
+ free(tp.words);
+ free(tp.wletters);
+
return (0);
}
+/* Widget size and position */
int widget_max_height(struct bsddialog_conf *conf)
{
int maxheight;
- maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.h : SCREENLINES;
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
if (maxheight <= 0)
RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
- if (conf->y > 0) {
+ if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
+ RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
+ else if (conf->y == BSDDIALOG_CENTER) {
+ maxheight -= conf->auto_topmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - top "
+ "margins <= 0");
+ } else if (conf->y > 0) {
maxheight -= conf->y;
if (maxheight <= 0)
RETURN_ERROR("Terminal too small, screen lines - "
"shadow - y <= 0");
}
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
+
return (maxheight);
}
@@ -600,7 +824,7 @@ int widget_max_width(struct bsddialog_conf *conf)
{
int maxwidth;
- maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.w : SCREENCOLS;
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
if (maxwidth <= 0)
RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
@@ -647,13 +871,13 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
struct buttons *bs)
{
- int min, delimtitle;
+ int min, delimtitle, wbottomtitle, wtitle;
min = 0;
/* buttons */
if (bs != NULL)
- min += buttons_width(*bs);
+ min += buttons_min_width(*bs);
/* text */
if (wtext > 0)
@@ -665,12 +889,15 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
/* title */
if (conf->title != NULL) {
delimtitle = t.dialog.delimtitle ? 2 : 0;
- min = MAX(min, (int)strlen(conf->title) + 2 + delimtitle);
+ wtitle = strcols(conf->title);
+ min = MAX(min, wtitle + 2 + delimtitle);
}
/* bottom title */
- if (conf->bottomtitle != NULL)
- min = MAX(min, (int)strlen(conf->bottomtitle) + 4);
+ if (conf->bottomtitle != NULL) {
+ wbottomtitle = strcols(conf->bottomtitle);
+ min = MAX(min, wbottomtitle + 4);
+ }
/* dialog borders */
min += VBORDERS;
@@ -721,8 +948,16 @@ 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)
{
- if (conf->y == BSDDIALOG_CENTER)
- *y = SCREENLINES/2 - (h + t.shadow.h)/2;
+ int hshadow = conf->shadow ? (int)t.shadow.y : 0;
+ int wshadow = conf->shadow ? (int)t.shadow.x : 0;
+
+ if (conf->y == BSDDIALOG_CENTER) {
+ *y = SCREENLINES/2 - (h + hshadow)/2;
+ if (*y < (int)conf->auto_topmargin)
+ *y = conf->auto_topmargin;
+ if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin)
+ *y = SCREENLINES - h - hshadow - conf->auto_downmargin;
+ }
else if (conf->y < BSDDIALOG_CENTER)
RETURN_ERROR("Negative begin y (less than -1)");
else if (conf->y >= SCREENLINES)
@@ -730,13 +965,13 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
else
*y = conf->y;
- if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > SCREENLINES)
+ if (*y + h + hshadow > SCREENLINES)
RETURN_ERROR("The lower of the box under the terminal "
"(begin Y + height (+ shadow) > terminal lines)");
if (conf->x == BSDDIALOG_CENTER)
- *x = SCREENCOLS/2 - (w + t.shadow.w)/2;
+ *x = SCREENCOLS/2 - (w + wshadow)/2;
else if (conf->x < BSDDIALOG_CENTER)
RETURN_ERROR("Negative begin x (less than -1)");
else if (conf->x >= SCREENCOLS)
@@ -744,14 +979,14 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
else
*x = conf->x;
- if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > SCREENCOLS)
+ if ((*x + w + wshadow) > SCREENCOLS)
RETURN_ERROR("The right of the box over the terminal "
"(begin X + width (+ shadow) > terminal cols)");
return (0);
}
-/* Widgets builders */
+/* Widgets build, update, destroy */
void
draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
enum elevation elev)
@@ -815,7 +1050,7 @@ static int
draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons)
{
- int h, w, ts, ltee, rtee;
+ int h, w, wtitle, wbottomtitle, ts, ltee, rtee;
ts = conf->ascii_lines ? '-' : ACS_HLINE;
ltee = conf->ascii_lines ? '+' : ACS_LTEE;
@@ -823,19 +1058,21 @@ draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
getmaxyx(widget, h, w);
- if (shadow != NULL)
+ if (conf->shadow)
wnoutrefresh(shadow);
draw_borders(conf, widget, h, w, RAISED);
if (conf->title != NULL) {
+ if ((wtitle = strcols(conf->title)) < 0)
+ return (BSDDIALOG_ERROR);
if (t.dialog.delimtitle && conf->no_lines == false) {
wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, 0, w/2-strlen(conf->title)/2-1, rtee);
+ mvwaddch(widget, 0, w/2 - wtitle/2 -1, rtee);
wattroff(widget, t.dialog.lineraisecolor);
}
wattron(widget, t.dialog.titlecolor);
- mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title);
+ mvwaddstr(widget, 0, w/2 - wtitle/2, conf->title);
wattroff(widget, t.dialog.titlecolor);
if (t.dialog.delimtitle && conf->no_lines == false) {
wattron(widget, t.dialog.lineraisecolor);
@@ -859,8 +1096,10 @@ draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
}
if (conf->bottomtitle != NULL) {
+ if ((wbottomtitle = strcols(conf->bottomtitle)) < 0)
+ return (BSDDIALOG_ERROR);
wattron(widget, t.dialog.bottomtitlecolor);
- wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1);
+ wmove(widget, h - 1, w/2 - wbottomtitle/2 - 1);
waddch(widget, ' ');
waddstr(widget, conf->bottomtitle);
waddch(widget, ' ');
@@ -883,9 +1122,9 @@ update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
{
int error;
- if (shadow != NULL) {
+ if (conf->shadow) {
wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
+ mvwin(shadow, y + t.shadow.y, x + t.shadow.x);
wresize(shadow, h, w);
}
@@ -912,7 +1151,7 @@ new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
int error;
if (conf->shadow) {
- *shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w);
+ *shadow = newwin(h, w, y + t.shadow.y, x + t.shadow.x);
if (*shadow == NULL)
RETURN_ERROR("Cannot build shadow");
wbkgd(*shadow, t.shadow.color);
@@ -962,10 +1201,10 @@ end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
delwin(shadow);
if (conf->clear)
- hide_widget(y, x, h, w, shadow != NULL);
+ hide_widget(y, x, h, w, conf->shadow);
if (conf->get_height != NULL)
*conf->get_height = h;
if (conf->get_width != NULL)
*conf->get_width = w;
-} \ No newline at end of file
+}
diff --git a/lib/lib_util.h b/lib/lib_util.h
index 6ebc73cf1055..238d3fda4675 100644
--- a/lib/lib_util.h
+++ b/lib/lib_util.h
@@ -33,8 +33,9 @@
#define TEXTHMARGIN 1
#define TEXTHMARGINS (TEXTHMARGIN + TEXTHMARGIN)
-/* current theme */
+/* theme utils */
extern struct bsddialog_theme t;
+extern bool hastermcolors;
/* debug */
#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
@@ -42,6 +43,12 @@ extern struct bsddialog_theme t;
refresh(); \
} while (0)
+/* unicode */
+unsigned int strcols(const char *mbstring);
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col);
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch);
+wchar_t* alloc_mbstows(const char *mbstring);
+
/* error buffer */
const char *get_error_string(void);
void set_error_string(const char *string);
@@ -56,6 +63,7 @@ struct buttons {
unsigned int nbuttons;
#define MAXBUTTONS 6 /* ok + extra + cancel + help + 2 generics */
const char *label[MAXBUTTONS];
+ wchar_t first[MAXBUTTONS];
int value[MAXBUTTONS];
int curr;
unsigned int sizebutton; /* including left and right delimiters */
@@ -70,8 +78,8 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
void
draw_buttons(WINDOW *window, struct buttons bs, bool shortcut);
-int buttons_width(struct buttons bs);
-bool shortcut_buttons(int key, struct buttons *bs);
+int buttons_min_width(struct buttons bs);
+bool shortcut_buttons(wint_t key, struct buttons *bs);
/* help window with F1 key */
int f1help(struct bsddialog_conf *conf);
@@ -130,4 +138,4 @@ void
end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
WINDOW *textpad);
-#endif \ No newline at end of file
+#endif
diff --git a/lib/libbsddialog.c b/lib/libbsddialog.c
index 761bdc3efa77..1a8188b0e7d3 100644
--- a/lib/libbsddialog.c
+++ b/lib/libbsddialog.c
@@ -34,10 +34,11 @@
#include "bsddialog_theme.h"
#include "lib_util.h"
-int bsddialog_init(void)
+#define COLSPERROW 10 /* Default conf.text.columns_per_row */
+
+int bsddialog_init_notheme(void)
{
int i, j, c, error;
- enum bsddialog_default_theme theme;
set_error_string("");
@@ -64,7 +65,18 @@ int bsddialog_init(void)
}
}
- if (error == OK && has_colors())
+ hastermcolors = (error == OK && has_colors()) ? true : false;
+
+ return (BSDDIALOG_OK);
+}
+
+int bsddialog_init(void)
+{
+ enum bsddialog_default_theme theme;
+
+ bsddialog_init_notheme();
+
+ if (bsddialog_hascolors())
theme = BSDDIALOG_THEME_FLAT;
else
theme = BSDDIALOG_THEME_BLACKWHITE;
@@ -113,6 +125,7 @@ int bsddialog_initconf(struct bsddialog_conf *conf)
conf->y = BSDDIALOG_CENTER;
conf->x = BSDDIALOG_CENTER;
conf->shadow = true;
+ conf->text.cols_per_row = COLSPERROW;
return (BSDDIALOG_OK);
}
diff --git a/lib/menubox.c b/lib/menubox.c
index 22ed15e6e7a0..28b9c8a0923b 100644
--- a/lib/menubox.c
+++ b/lib/menubox.c
@@ -177,9 +177,10 @@ getfastprev(int menurows, struct privateitem *pritems, int abs)
static int
getnextshortcut(struct bsddialog_conf *conf, int npritems,
- struct privateitem *pritems, int abs, int key)
+ struct privateitem *pritems, int abs, wint_t key)
{
- int i, ch, next;
+ int i, next;
+ wchar_t wch;
next = -1;
for (i = 0; i < npritems; i++) {
@@ -187,11 +188,11 @@ getnextshortcut(struct bsddialog_conf *conf, int npritems,
continue;
if (conf->menu.no_name)
- ch = pritems[i].item->desc[0];
+ mbtowc(&wch, pritems[i].item->desc, MB_CUR_MAX);
else
- ch = pritems[i].item->name[0];
+ mbtowc(&wch, pritems[i].item->name, MB_CUR_MAX);
- if (ch == key) {
+ if (wch == (wchar_t)key) {
if (i > abs)
return (i);
@@ -236,12 +237,12 @@ drawseparators(struct bsddialog_conf *conf, WINDOW *pad, int linelen,
}
name = pritems[i].item->name;
desc = pritems[i].item->desc;
- labellen = strlen(name) + strlen(desc) + 1;
+ labellen = strcols(name) + strcols(desc) + 1;
wmove(pad, i, labellen < linelen ? linelen/2 - labellen/2 : 0);
wattron(pad, t.menu.namesepcolor);
waddstr(pad, name);
wattroff(pad, t.menu.namesepcolor);
- if (strlen(name) > 0 && strlen(desc) > 0)
+ if (strcols(name) > 0 && strcols(desc) > 0)
waddch(pad, ' ');
wattron(pad, t.menu.descsepcolor);
waddstr(pad, desc);
@@ -254,7 +255,7 @@ drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
struct lineposition pos, struct privateitem *pritem, bool focus)
{
int colordesc, colorname, colorshortcut;
- const char *shortcut;
+ wchar_t shortcut;
struct bsddialog_menuitem *item;
item = pritem->item;
@@ -303,24 +304,47 @@ drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
wattron(pad, colorshortcut);
if (conf->menu.no_name)
- shortcut = item->desc;
+ mbtowc(&shortcut, item->desc, MB_CUR_MAX);
else
- shortcut = item->name;
- wmove(pad, y, pos.xname + item->depth * DEPTH);
- if (shortcut != NULL && shortcut[0] != '\0')
- waddch(pad, shortcut[0]);
- wattroff(pad, colorshortcut);
+ mbtowc(&shortcut, item->name, MB_CUR_MAX);
+ mvwaddwch(pad, y, pos.xname + item->depth * DEPTH, shortcut);
+ wattroff(pad, colorshortcut);
}
/* bottom description */
move(SCREENLINES - 1, 2);
clrtoeol();
if (item->bottomdesc != NULL && focus) {
+ attron(t.menu.bottomdesccolor);
addstr(item->bottomdesc);
+ attroff(t.menu.bottomdesccolor);
refresh();
}
}
+/* 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)
+{
+ draw_borders(conf, menuwin, h, w, LOWERED);
+
+ if (totnitems > (int)menurows) {
+ wattron(menuwin, t.dialog.arrowcolor);
+ if (ymenupad > 0)
+ mvwhline(menuwin, 0, 2,
+ conf->ascii_lines ? '^' : ACS_UARROW, 3);
+
+ if ((ymenupad + (int)menurows) < totnitems)
+ mvwhline(menuwin, h-1, 2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, 3);
+
+ mvwprintw(menuwin, h-1, w-6, "%3d%%",
+ 100 * (ymenupad + menurows) / totnitems);
+ wattroff(menuwin, t.dialog.arrowcolor);
+ }
+}
+
static int
menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
const char *text, int linelen, unsigned int *menurows, int nitems,
@@ -365,8 +389,12 @@ menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
*/
*menurows = MIN(*h - 6 - htext, (int)*menurows);
} else {
- if (*menurows == 0)
- *menurows = MIN(*h-6-htext, nitems);
+ if (*menurows == 0) {
+ if (*h - 6 - htext <= 0)
+ *menurows = 0; /* menu_checksize() will check */
+ else
+ *menurows = MIN(*h-6-htext, nitems);
+ }
}
return (0);
@@ -380,8 +408,7 @@ menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
mincols = VBORDERS;
/* buttons */
- mincols += buttons_width(bs);
-
+ mincols += buttons_min_width(bs);
/*
* linelen check, comment to allow some hidden col otherwise portconfig
* could not show big menus like www/apache24
@@ -392,11 +419,11 @@ menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
RETURN_ERROR("Few cols, width < size buttons or "
"name + descripion of the items");
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+ textrow = text != NULL && text[0] != '\0' ? 1 : 0;
if (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, probably terminal "
- "too small");
+ RETURN_ERROR("items > 0 but menurows == 0, if menurows = 0 "
+ "terminal too small");
menusize = nitems > 0 ? 3 : 0;
if (rows < 2 + 2 + menusize + textrow)
@@ -405,37 +432,15 @@ menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
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)
-{
- draw_borders(conf, menuwin, h, w, LOWERED);
-
- if (totnitems > (int)menurows) {
- wattron(menuwin, t.dialog.arrowcolor);
-
- if (ymenupad > 0)
- mvwprintw(menuwin, 0, 2, "^^^");
-
- if ((ymenupad + (int)menurows) < totnitems)
- mvwprintw(menuwin, h-1, 2, "vvv");
-
- wattroff(menuwin, t.dialog.arrowcolor);
-
- mvwprintw(menuwin, h-1, w-10, "%3d%%",
- 100 * (ymenupad + menurows) / totnitems);
- }
-}
-
static int
do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
unsigned int menurows, enum menumode mode, unsigned int ngroups,
struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
{
bool loop, onetrue, movefocus, automenurows, shortcut_butts;
- int i, j, y, x, h, w, output, input;
+ int i, j, y, x, h, w, retval;
int ymenupad, ys, ye, xs, xe, abs, next, totnitems;
+ wint_t input;
WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
struct buttons bs;
struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -458,14 +463,14 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
if (groups[i].type == BSDDIALOG_SEPARATOR) {
pos.maxsepstr = MAX(pos.maxsepstr,
- strlen(item->name) + strlen(item->desc));
+ strcols(item->name) + strcols(item->desc));
continue;
}
- pos.maxprefix = MAX(pos.maxprefix,strlen(item->prefix));
+ pos.maxprefix = MAX(pos.maxprefix,strcols(item->prefix));
pos.maxdepth = MAX(pos.maxdepth, item->depth);
- pos.maxname = MAX(pos.maxname, strlen(item->name));
- pos.maxdesc = MAX(pos.maxdesc, strlen(item->desc));
+ pos.maxname = MAX(pos.maxname, strcols(item->name));
+ pos.maxdesc = MAX(pos.maxdesc, strcols(item->desc));
}
}
pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
@@ -479,7 +484,6 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
pos.xdesc += (pos.maxname != 0 ? 1 : 0);
pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
-
get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
@@ -498,11 +502,11 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
doupdate();
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
+ prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN, y + h - menurows,
+ x + 1 + w - TEXTHMARGIN);
menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
- menurows+2, w-4, LOWERED);
+ menurows + 2, w - 4, LOWERED);
menupad = newpad(totnitems, pos.line);
wbkgd(menupad, t.dialog.color);
@@ -562,22 +566,23 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
movefocus = false;
loop = true;
while (loop) {
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
if (abs >= 0 && pritems[abs].type == MENUMODE)
pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups, pritems);
+ set_on_output(conf, retval, ngroups, groups, pritems);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
if (abs >= 0 && pritems[abs].type == MENUMODE)
pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups,
+ set_on_output(conf, retval, ngroups, groups,
pritems);
loop = false;
}
@@ -714,10 +719,10 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
default:
if (shortcut_butts) {
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
if (pritems[abs].type == MENUMODE)
pritems[abs].on = true;
- set_on_output(conf, output, ngroups,
+ set_on_output(conf, retval, ngroups,
groups, pritems);
loop = false;
}
@@ -728,7 +733,7 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
next = getnextshortcut(conf, totnitems, pritems, abs,
input);
movefocus = next != abs;
- }
+ } /* end switch handler */
if (movefocus) {
drawitem(conf, menupad, abs, pos, &pritems[abs], false);
@@ -744,7 +749,7 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
movefocus = false;
}
- }
+ } /* end while handler */
if (focuslist != NULL)
*focuslist = abs < 0 ? -1 : pritems[abs].group;
@@ -756,7 +761,7 @@ do_mixedlist(struct bsddialog_conf *conf, const char *text, int rows, int cols,
end_dialog(conf, shadow, widget, textpad);
free(pritems);
- return (output);
+ return (retval);
}
/* API */
@@ -765,12 +770,12 @@ bsddialog_mixedlist(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int ngroups,
struct bsddialog_menugroup *groups, int *focuslist, int *focusitem)
{
- int output;
+ int retval;
- output = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
+ retval = do_mixedlist(conf, text, rows, cols, menurows, MIXEDLISTMODE,
ngroups, groups, focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -778,14 +783,14 @@ bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int nitems,
struct bsddialog_menuitem *items, int *focusitem)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
BSDDIALOG_CHECKLIST /* unused */, nitems, items};
- output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
+ retval = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -793,14 +798,14 @@ bsddialog_menu(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int nitems,
struct bsddialog_menuitem *items, int *focusitem)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
BSDDIALOG_CHECKLIST /* unused */, nitems, items};
- output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
+ retval = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
&group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -808,12 +813,12 @@ bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int nitems,
struct bsddialog_menuitem *items, int *focusitem)
{
- int output, focuslist = 0;
+ int retval, focuslist = 0;
struct bsddialog_menugroup group = {
BSDDIALOG_RADIOLIST /* unused */, nitems, items};
- output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
+ retval = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
diff --git a/lib/messagebox.c b/lib/messagebox.c
index 24b34ccbce97..06753be20c3d 100644
--- a/lib/messagebox.c
+++ b/lib/messagebox.c
@@ -31,18 +31,22 @@
#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
static int
message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text, struct buttons bs)
+ int *w, const char *text, bool *hastext, struct buttons bs)
{
int htext, wtext;
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
+ if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE ||
+ hastext != NULL) {
+ if (text_size(conf, rows, cols, text, &bs, 0, 1, &htext,
+ &wtext) != 0)
return (BSDDIALOG_ERROR);
+ if (hastext != NULL)
+ *hastext = htext > 0 ? true : false;
}
if (cols == BSDDIALOG_AUTOSIZE)
@@ -54,34 +58,40 @@ message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
return (0);
}
-static int message_checksize(int rows, int cols, struct buttons bs)
+static int
+message_checksize(int rows, int cols, bool hastext, struct buttons bs)
{
int mincols;
mincols = VBORDERS;
- mincols += buttons_width(bs);
+ mincols += buttons_min_width(bs);
if (cols < mincols)
RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "
"for borders, buttons and spaces between buttons");
- if (rows < HBORDERS + 2 /*buttons*/)
- RETURN_ERROR("Msgbox and Yesno need at least height 4");
+ if (rows < HBORDERS + 2 /* buttons */)
+ RETURN_ERROR("Msgbox and Yesno need at least 4 rows");
+ if (hastext && rows < HBORDERS + 2 /*buttons*/ + 1 /* text row */)
+ RETURN_ERROR("Msgbox and Yesno with text need at least 5 rows");
return (0);
}
static void
-textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad)
+textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad,
+ bool hastext)
{
int y, x, h, w;
getbegyx(widget, y, x);
getmaxyx(widget, h, w);
- if (htextpad > h - 4) {
+ if (hastext && htextpad > h - 4) {
+ wattron(widget, t.dialog.arrowcolor);
mvwprintw(widget, h-3, w-6, "%3d%%",
100 * (ytextpad+h-4)/ htextpad);
+ wattroff(widget, t.dialog.arrowcolor);
wnoutrefresh(widget);
}
@@ -92,15 +102,16 @@ static int
do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
struct buttons bs)
{
- bool loop;
- int y, x, h, w, input, output, ytextpad, htextpad, unused;
+ bool hastext, loop;
+ int y, x, h, w, retval, ytextpad, htextpad, unused;
WINDOW *widget, *textpad, *shadow;
+ wint_t input;
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
+ if (message_autosize(conf, rows, cols, &h, &w, text, &hastext, bs) != 0)
return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
+ if (message_checksize(h, w, hastext, bs) != 0)
return (BSDDIALOG_ERROR);
if (set_widget_position(conf, &y, &x, h, w) != 0)
return (BSDDIALOG_ERROR);
@@ -112,20 +123,21 @@ do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
ytextpad = 0;
getmaxyx(textpad, htextpad, unused);
unused++; /* fix unused error */
- textupdate(widget, textpad, htextpad, ytextpad);
+ textupdate(widget, textpad, htextpad, ytextpad, hastext);
loop = true;
while (loop) {
doupdate();
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch (input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -163,9 +175,9 @@ do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
return (BSDDIALOG_ERROR);
if (message_autosize(conf, rows, cols, &h, &w, text,
- bs) != 0)
+ NULL, bs) != 0)
return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
+ if (message_checksize(h, w, hastext, bs) != 0)
return (BSDDIALOG_ERROR);
if (set_widget_position(conf, &y, &x, h, w) != 0)
return (BSDDIALOG_ERROR);
@@ -175,7 +187,8 @@ do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
return (BSDDIALOG_ERROR);
getmaxyx(textpad, htextpad, unused);
- textupdate(widget, textpad, htextpad, ytextpad);
+ ytextpad = 0;
+ textupdate(widget, textpad, htextpad, ytextpad, hastext);
/* Important to fix grey lines expanding screen */
refresh();
@@ -184,17 +197,17 @@ do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
if (ytextpad == 0)
break;
ytextpad--;
- textupdate(widget, textpad, htextpad, ytextpad);
+ textupdate(widget, textpad, htextpad, ytextpad, hastext);
break;
case KEY_DOWN:
if (ytextpad + h - 4 >= htextpad)
break;
ytextpad++;
- textupdate(widget, textpad, htextpad, ytextpad);
+ textupdate(widget, textpad, htextpad, ytextpad, hastext);
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
@@ -202,7 +215,7 @@ do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
}
/* API */
diff --git a/lib/textbox.c b/lib/textbox.c
index 69eff7c0bc2e..0c6d53a8cad0 100644
--- a/lib/textbox.c
+++ b/lib/textbox.c
@@ -28,18 +28,61 @@
#include <sys/param.h>
#include <curses.h>
+#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
static void
+updateborders(struct bsddialog_conf *conf, WINDOW *widget, int padmargin,
+ int hpad, int wpad, int ypad, int xpad)
+{
+ int h, w;
+ chtype arrowch, borderch;
+
+ getmaxyx(widget, h, w);
+
+ if (conf->no_lines)
+ borderch = ' ';
+ else if (conf->ascii_lines)
+ borderch = '|';
+ else
+ borderch = ACS_VLINE;
+
+ if (xpad > 0) {
+ arrowch = conf->ascii_lines ? '<' : ACS_LARROW;
+ arrowch |= A_ATTRIBUTES & t.dialog.arrowcolor;
+ } else {
+ arrowch = borderch;
+ arrowch |= A_ATTRIBUTES & t.dialog.lineraisecolor;
+ }
+ mvwvline(widget, (h / 2) - 2, 0, arrowch, 4);
+
+ if (xpad + w-2-padmargin < wpad) {
+ arrowch = conf->ascii_lines ? '>' : ACS_RARROW;
+ arrowch |= A_ATTRIBUTES & t.dialog.arrowcolor;
+ } else {
+ arrowch = borderch;
+ arrowch |= A_ATTRIBUTES & t.dialog.linelowercolor;
+ }
+ mvwvline(widget, (h / 2) - 2, w - 1, arrowch, 4);
+
+ if (hpad > h - 4) {
+ wattron(widget, t.dialog.arrowcolor);
+ mvwprintw(widget, h-3, w-6, "%3d%%", 100 * (ypad+h-4)/ hpad);
+ wattroff(widget, t.dialog.arrowcolor);
+ }
+}
+
+static void
textbox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int hpad, int wpad, struct buttons bs)
+ int *w, int hpad, int wpad, int padmargin, struct buttons bs)
{
if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, 0, wpad, &bs);
+ *w = widget_min_width(conf, 0, wpad + padmargin, &bs);
if (rows == BSDDIALOG_AUTOSIZE)
*h = widget_min_height(conf, 0, hpad, true);
@@ -50,7 +93,8 @@ textbox_checksize(int rows, int cols, int hpad, struct buttons bs)
{
int mincols;
- mincols = VBORDERS + bs.sizebutton;
+ mincols = VBORDERS;
+ mincols += buttons_min_width(bs);
if (cols < mincols)
RETURN_ERROR("Few cols for the textbox");
@@ -66,9 +110,11 @@ int
bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
int cols)
{
- bool loop;
- int i, output, input;
- int y, x, h, w, hpad, wpad, ypad, xpad, ys, ye, xs, xe, printrows;
+ bool loop, has_multi_col;
+ int i, retval, y, x, h, w;
+ int hpad, wpad, ypad, xpad, ys, ye, xs, xe, padmargin, printrows;
+ unsigned int defaulttablen, linecols;
+ wint_t input;
char buf[BUFSIZ];
FILE *fp;
struct buttons bs;
@@ -77,14 +123,19 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
if ((fp = fopen(file, "r")) == NULL)
RETURN_ERROR("Cannot open file");
+ defaulttablen = TABSIZE;
+ set_tabsize((conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen);
hpad = 1;
wpad = 1;
pad = newpad(hpad, wpad);
wbkgd(pad, t.dialog.color);
+ padmargin = 0;
i = 0;
while (fgets(buf, BUFSIZ, fp) != NULL) {
- if ((int) strlen(buf) > wpad) {
- wpad = strlen(buf);
+ if (str_props(buf, &linecols, &has_multi_col) != 0)
+ continue;
+ if ((int)linecols > wpad) {
+ wpad = linecols;
wresize(pad, hpad, wpad);
}
if (i > hpad-1) {
@@ -93,20 +144,19 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
}
mvwaddstr(pad, i, 0, buf);
i++;
+ if (has_multi_col)
+ padmargin = 2;
}
fclose(fp);
+ set_tabsize(defaulttablen);
- bs.nbuttons = 1;
- bs.label[0] = "EXIT";
- if (conf->button.ok_label != NULL)
- bs.label[0] = conf->button.ok_label;
- bs.value[0] = BSDDIALOG_OK;
+ get_buttons(conf, &bs, "EXIT", NULL);
bs.curr = 0;
- bs.sizebutton = strlen(bs.label[0]) + 2;
+ bs.nbuttons = 1;
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad, bs);
+ textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad, padmargin, bs);
if (textbox_checksize(h, w, hpad, bs) != 0)
return (BSDDIALOG_ERROR);
if (set_widget_position(conf, &y, &x, h, w) != 0)
@@ -117,26 +167,33 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
return (BSDDIALOG_ERROR);
ys = y + 1;
- xs = x + 1;
+ xs = (padmargin == 0) ? x + 1 : x + 2;
ye = ys + h - 5;
- xe = xs + w - 3;
+ xe = xs + w - 3 - padmargin;
ypad = xpad = 0;
printrows = h-4;
loop = true;
while (loop) {
- wnoutrefresh(widget);
- pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
- doupdate();
- input = getch();
+ updateborders(conf, widget, padmargin, hpad, wpad, ypad, xpad);
+ /*
+ * Overflow multicolumn charchter right border:
+ * wnoutrefresh(widget);
+ * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ * doupdate();
+ */
+ wrefresh(widget);
+ prefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = BSDDIALOG_OK;
+ retval = BSDDIALOG_OK;
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -164,7 +221,7 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
break;
case KEY_RIGHT:
case 'l':
- xpad = (xpad + w-2) < wpad-1 ? xpad + 1 : xpad;
+ xpad = (xpad + w-2-padmargin) < wpad ? xpad + 1 : xpad;
break;
case KEY_UP:
case 'k':
@@ -189,16 +246,16 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
if (set_widget_size(conf, rows, cols, &h, &w) != 0)
return (BSDDIALOG_ERROR);
textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad,
- bs);
+ padmargin, bs);
if (textbox_checksize(h, w, hpad, bs) != 0)
return (BSDDIALOG_ERROR);
if (set_widget_position(conf, &y, &x, h, w) != 0)
return (BSDDIALOG_ERROR);
ys = y + 1;
- xs = x + 1;
+ xs = (padmargin == 0) ? x + 1 : x + 2;
ye = ys + h - 5;
- xe = xs + w - 3;
+ xe = xs + w - 3 - padmargin;
ypad = xpad = 0;
printrows = h - 4;
@@ -211,7 +268,7 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
@@ -219,5 +276,5 @@ bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
end_dialog(conf, shadow, widget, pad);
- return (output);
-} \ No newline at end of file
+ return (retval);
+}
diff --git a/lib/theme.c b/lib/theme.c
index 20b1e35428dd..40310d58cda4 100644
--- a/lib/theme.c
+++ b/lib/theme.c
@@ -34,51 +34,53 @@
#define GET_COLOR(bg, fg) (COLOR_PAIR(bg * 8 + fg +1))
struct bsddialog_theme t;
+bool hastermcolors;
static struct bsddialog_theme bsddialogtheme = {
-#define bgwidget COLOR_WHITE
-#define bgcurr COLOR_YELLOW
.screen.color = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
.shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.color = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.arrowcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
-
- .menu.f_selectorcolor = GET_COLOR(COLOR_BLACK, bgcurr),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, bgcurr),
- .menu.desccolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_namecolor = GET_COLOR(COLOR_BLACK, bgcurr),
- .menu.namecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.namesepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .menu.descsepcolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, bgcurr),
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, bgwidget),
-
- .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
- .form.readonlycolor = GET_COLOR(COLOR_CYAN,COLOR_WHITE),
-
- .bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
-
- .button.hmargin = 3,
- .button.leftdelim = '[',
- .button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .button.delimcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .button.f_color = GET_COLOR(COLOR_BLACK, bgcurr) | A_UNDERLINE,
- .button.color = GET_COLOR(COLOR_BLACK, bgwidget) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(COLOR_RED, bgcurr) | A_UNDERLINE,
- .button.shortcutcolor = GET_COLOR(COLOR_RED, bgwidget) | A_UNDERLINE
+ .dialog.titlecolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
+ .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.arrowcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
+
+ .menu.f_selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
+ .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_YELLOW),
+ .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_namecolor = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
+ .menu.namecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.namesepcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
+ .menu.descsepcolor = GET_COLOR(COLOR_YELLOW, COLOR_WHITE),
+ .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_YELLOW),
+ .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
+
+ .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
+ .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE),
+ .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN),
+
+ .bar.f_color = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
+ .bar.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
+ .button.leftdelim = '[',
+ .button.rightdelim = ']',
+ .button.f_delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .button.delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .button.f_color = GET_COLOR(COLOR_BLACK, COLOR_YELLOW),
+ .button.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .button.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_YELLOW),
+ .button.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE)
};
static struct bsddialog_theme blackwhite = {
@@ -87,8 +89,8 @@ static struct bsddialog_theme blackwhite = {
.screen.color = GET_COLOR(fg, bk),
.shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = true,
.dialog.titlecolor = GET_COLOR(fg, bk),
@@ -108,15 +110,18 @@ static struct bsddialog_theme blackwhite = {
.menu.descsepcolor = GET_COLOR(fg, bk),
.menu.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
.menu.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE,
+ .menu.bottomdesccolor = GET_COLOR(fg, bk),
- .form.f_fieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .form.fieldcolor = GET_COLOR(fg, bk),
- .form.readonlycolor = GET_COLOR(fg, bk),
+ .form.f_fieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
+ .form.fieldcolor = GET_COLOR(fg, bk),
+ .form.readonlycolor = GET_COLOR(fg, bk),
+ .form.bottomdesccolor = GET_COLOR(fg, bk),
.bar.f_color = GET_COLOR(fg, bk) | A_REVERSE,
.bar.color = GET_COLOR(fg, bk),
- .button.hmargin = 3,
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
.button.leftdelim = '[',
.button.rightdelim = ']',
.button.f_delimcolor = GET_COLOR(fg, bk),
@@ -128,11 +133,11 @@ static struct bsddialog_theme blackwhite = {
};
static struct bsddialog_theme dialogtheme = {
- .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
+ .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
.shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = false,
.dialog.titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
@@ -140,27 +145,30 @@ static struct bsddialog_theme dialogtheme = {
.dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
.dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
- .dialog.arrowcolor = GET_COLOR(COLOR_GREEN, COLOR_WHITE),
-
- .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.selectorcolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
- .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
- .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
- .menu.namesepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.descsepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
- .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
- .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
-
- .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
- .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
- .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
+ .dialog.arrowcolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+
+ .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+ .menu.namesepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.descsepcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
+ .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+
+ .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
+ .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
.bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
.bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .button.hmargin = 3,
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
.button.leftdelim = '<',
.button.rightdelim = '>',
.button.f_delimcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
@@ -177,8 +185,8 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->screen.color = src->screen.color;
dst->shadow.color = src->shadow.color;
- dst->shadow.h = src->shadow.h;
- dst->shadow.w = src->shadow.w;
+ dst->shadow.y = src->shadow.y;
+ dst->shadow.x = src->shadow.x;
dst->dialog.delimtitle = src->dialog.delimtitle;
dst->dialog.titlecolor = src->dialog.titlecolor;
@@ -198,15 +206,18 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->menu.descsepcolor = src->menu.descsepcolor;
dst->menu.f_shortcutcolor = src->menu.f_shortcutcolor;
dst->menu.shortcutcolor = src->menu.shortcutcolor;
+ dst->menu.bottomdesccolor = src->menu.bottomdesccolor;
- dst->form.f_fieldcolor = src->form.f_fieldcolor;
- dst->form.fieldcolor = src->form.fieldcolor;
- dst->form.readonlycolor = src->form.readonlycolor;
+ dst->form.f_fieldcolor = src->form.f_fieldcolor;
+ dst->form.fieldcolor = src->form.fieldcolor;
+ dst->form.readonlycolor = src->form.readonlycolor;
+ dst->form.bottomdesccolor = src->form.bottomdesccolor;
dst->bar.f_color = src->bar.f_color;
dst->bar.color = src->bar.color;
- dst->button.hmargin = src->button.hmargin;
+ dst->button.minmargin = src->button.minmargin;
+ dst->button.maxmargin = src->button.maxmargin;
dst->button.leftdelim = src->button.leftdelim;
dst->button.rightdelim = src->button.rightdelim;
dst->button.f_delimcolor = src->button.f_delimcolor;
@@ -230,7 +241,7 @@ int bsddialog_get_theme(struct bsddialog_theme *theme)
set_theme(theme, &t);
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_theme(struct bsddialog_theme *theme)
@@ -242,7 +253,7 @@ int bsddialog_set_theme(struct bsddialog_theme *theme)
set_theme(&t, theme);
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
@@ -254,6 +265,7 @@ int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
t.dialog.delimtitle = true;
t.button.leftdelim = '[';
t.button.rightdelim = ']';
+ t.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE);
}
else if (newtheme == BSDDIALOG_THEME_BSDDIALOG)
bsddialog_set_theme(&bsddialogtheme);
@@ -264,7 +276,7 @@ int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
else
RETURN_ERROR("Unknow default theme");
- return (0);
+ return (BSDDIALOG_OK);
}
int
@@ -282,3 +294,32 @@ bsddialog_color(enum bsddialog_color foreground,
return (GET_COLOR(foreground, background) | cursesflags);
}
+
+int
+bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
+ enum bsddialog_color *background, unsigned int *flags)
+{
+ unsigned int flag;
+ short f, b;
+
+ flag = 0U;
+ flag |= (color & A_BOLD) ? BSDDIALOG_BOLD : 0U;
+ flag |= (color & A_REVERSE) ? BSDDIALOG_REVERSE : 0U;
+ flag |= (color & A_UNDERLINE) ? BSDDIALOG_UNDERLINE : 0U;
+ if (flags != NULL)
+ *flags = flag;
+
+ if (pair_content(PAIR_NUMBER(color), &f, &b) != OK)
+ RETURN_ERROR("Cannot get color attributes");
+ if (foreground != NULL)
+ *foreground = f;
+ if (background != NULL)
+ *background = b;
+
+ return (BSDDIALOG_OK);
+}
+
+bool bsddialog_hascolors(void)
+{
+ return hastermcolors;
+} \ No newline at end of file
diff --git a/lib/timebox.c b/lib/timebox.c
index 7d69666c32b8..529563b49bca 100644
--- a/lib/timebox.c
+++ b/lib/timebox.c
@@ -32,11 +32,42 @@
#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
#define MINWDATE 23 /* 3 windows and their borders */
#define MINWTIME 14 /* 3 windows and their borders */
+static void
+drawquare(struct bsddialog_conf *conf, WINDOW *win, const char *fmt,
+ const void *value, bool focus)
+{
+ int h, l, w;
+
+ getmaxyx(win, h, w);
+ draw_borders(conf, win, h, w, LOWERED);
+ if (focus) {
+ l = 2 + w%2;
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, w/2 - l/2,
+ conf->ascii_lines ? '^' : ACS_UARROW, l);
+ mvwhline(win, h-1, w/2 - l/2,
+ conf->ascii_lines ? 'v' : ACS_DARROW, l);
+ wattroff(win, t.dialog.arrowcolor);
+ }
+
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ if (strchr(fmt, 's') != NULL)
+ mvwprintw(win, 1, 1, fmt, (const char*)value);
+ else
+ mvwprintw(win, 1, 1, fmt, *((const int*)value));
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
+
+ wrefresh(win);
+}
+
static int
datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
int *w, int minw, const char *text, struct buttons bs)
@@ -50,7 +81,7 @@ datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
}
if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, htext,minw, &bs);
+ *w = widget_min_width(conf, wtext, minw, &bs);
if (rows == BSDDIALOG_AUTOSIZE)
*h = widget_min_height(conf, htext, 3 /* windows */, true);
@@ -64,7 +95,7 @@ datetime_checksize(int rows, int cols, int minw, struct buttons bs)
int mincols;
mincols = VBORDERS;
- mincols += buttons_width(bs);
+ mincols += buttons_min_width(bs);
mincols = MAX(minw, mincols);
if (cols < mincols)
@@ -81,7 +112,8 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
{
bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
+ int i, retval, y, x, h, w, sel;
+ wint_t input;
WINDOW *widget, *textpad, *shadow;
struct buttons bs;
struct myclockstruct {
@@ -131,30 +163,26 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
wrefresh(widget);
+ sel = -1;
loop = focusbuttons = true;
while (loop) {
- for (i = 0; i < 3; i++) {
- mvwprintw(c[i].win, 1, 1, "%2d", c[i].value);
- wrefresh(c[i].win);
- }
-
- if (focusbuttons == false) {
- wmove(c[sel].win, 1, 2);
- wrefresh(c[sel].win);
- }
+ for (i = 0; i < 3; i++)
+ drawquare(conf, c[i].win, "%02d", &c[i].value,
+ sel == i);
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
+ if (focusbuttons || conf->button.always_active) {
+ retval = bs.value[bs.curr];
+ loop = false;
+ }
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -165,14 +193,13 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
focusbuttons = bs.curr < (int)bs.nbuttons ?
true : false;
if (focusbuttons == false) {
- curs_set(1);
sel = 0;
+ bs.curr = conf->button.always_active ? 0 : -1;
}
} else {
sel++;
focusbuttons = sel > 2 ? true : false;
if (focusbuttons) {
- curs_set(0);
bs.curr = 0;
}
}
@@ -184,25 +211,28 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
bs.curr--;
focusbuttons = bs.curr < 0 ? false : true;
if (focusbuttons == false) {
- curs_set(1);
sel = 2;
+ bs.curr = conf->button.always_active ? 0 : -1;
}
} else {
sel--;
focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
+ if (focusbuttons)
bs.curr = (int)bs.nbuttons - 1;
- }
}
draw_buttons(widget, bs, true);
wrefresh(widget);
break;
case KEY_UP:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value > 0 ?
+ if (focusbuttons) {
+ sel = 0;
+ focusbuttons = false;
+ bs.curr = conf->button.always_active ? 0 : -1;
+ draw_buttons(widget, bs, true);
+ wrefresh(widget);
+ } else { c[sel].value = c[sel].value > 0 ?
c[sel].value - 1 : c[sel].max;
+ }
break;
case KEY_DOWN:
if (focusbuttons)
@@ -214,10 +244,8 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- curs_set(0);
if (f1help(conf) != 0)
return (BSDDIALOG_ERROR);
- curs_set(1);
/* No break, screen size can change */
case KEY_RESIZE:
/* Important for decreasing screen */
@@ -248,43 +276,33 @@ bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
wclear(c[0].win);
mvwin(c[0].win, y + h - 6, x + w/2 - 7);
- draw_borders(conf, c[0].win, 3, 4, LOWERED);
- wrefresh(c[0].win);
-
wclear(c[1].win);
mvwin(c[1].win, y + h - 6, x + w/2 - 2);
- draw_borders(conf, c[1].win, 3, 4, LOWERED);
- wrefresh(c[1].win);
-
wclear(c[2].win);
mvwin(c[2].win, y + h - 6, x + w/2 + 3);
- draw_borders(conf, c[2].win, 3, 4, LOWERED);
- wrefresh(c[2].win);
/* Important to avoid grey lines expanding screen */
refresh();
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
}
- if (output == BSDDIALOG_OK) {
+ if (retval == BSDDIALOG_OK) {
*hh = c[0].value;
*mm = c[1].value;
*ss = c[2].value;
}
- curs_set(0);
-
for (i = 0; i < 3; i++)
delwin(c[i].win);
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
}
int
@@ -292,7 +310,8 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
{
bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
+ int i, retval, y, x, h, w, sel;
+ wint_t input;
WINDOW *widget, *textpad, *shadow;
struct buttons bs;
struct calendar {
@@ -363,31 +382,27 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
wrefresh(widget);
+ sel = -1;
loop = focusbuttons = true;
while (loop) {
- mvwprintw(c[0].win, 1, 1, "%4d", c[0].value);
- mvwprintw(c[1].win, 1, 1, "%9s", m[c[1].value-1].name);
- mvwprintw(c[2].win, 1, 1, "%2d", c[2].value);
- for (i = 0; i < 3; i++) {
- wrefresh(c[i].win);
- }
- if (focusbuttons == false) {
- wmove(c[sel].win, 1, c[sel].x);
- wrefresh(c[sel].win);
- }
+ drawquare(conf, c[0].win, "%4d", &c[0].value, sel == 0);
+ drawquare(conf, c[1].win, "%9s", m[c[1].value-1].name,
+ sel == 1);
+ drawquare(conf, c[2].win, "%02d", &c[2].value, sel == 2);
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
+ if (focusbuttons || conf->button.always_active) {
+ retval = bs.value[bs.curr];
+ loop = false;
+ }
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
@@ -398,14 +413,13 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
focusbuttons = bs.curr < (int)bs.nbuttons ?
true : false;
if (focusbuttons == false) {
- curs_set(1);
sel = 0;
+ bs.curr = conf->button.always_active ? 0 : -1;
}
} else {
sel++;
focusbuttons = sel > 2 ? true : false;
if (focusbuttons) {
- curs_set(0);
bs.curr = 0;
}
}
@@ -417,33 +431,37 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
bs.curr--;
focusbuttons = bs.curr < 0 ? false : true;
if (focusbuttons == false) {
- curs_set(1);
sel = 2;
+ bs.curr = conf->button.always_active ? 0 : -1;
}
} else {
sel--;
focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
+ if (focusbuttons)
bs.curr = (int)bs.nbuttons - 1;
- }
}
draw_buttons(widget, bs, true);
wrefresh(widget);
break;
case KEY_UP:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value > 1 ?
- c[sel].value - 1 : c[sel].max ;
- /* if mount change */
- c[2].max = m[c[1].value -1].days;
- /* if year change */
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
+ if (focusbuttons) {
+ sel = 0;
+ focusbuttons = false;
+ bs.curr = conf->button.always_active ? 0 : -1;
+ draw_buttons(widget, bs, true);
+ wrefresh(widget);
+ } else {
+ c[sel].value = c[sel].value > 1 ?
+ c[sel].value - 1 : c[sel].max ;
+ /* if mount change */
+ c[2].max = m[c[1].value -1].days;
+ /* if year change */
+ if (c[1].value == 2 && ISLEAF(c[0].value))
+ c[2].max = 29;
+ /* set new day */
+ if (c[2].value > c[2].max)
+ c[2].value = c[2].max;
+ }
break;
case KEY_DOWN:
if (focusbuttons)
@@ -463,10 +481,8 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- curs_set(0);
if (f1help(conf) != 0)
return (BSDDIALOG_ERROR);
- curs_set(1);
/* No break, screen size can change */
case KEY_RESIZE:
/* Important for decreasing screen */
@@ -496,41 +512,31 @@ bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
wclear(c[0].win);
mvwin(c[0].win, y + h - 6, x + w/2 - 11);
- draw_borders(conf, c[0].win, 3, 6, LOWERED);
- wrefresh(c[0].win);
-
wclear(c[1].win);
mvwin(c[1].win, y + h - 6, x + w/2 - 4);
- draw_borders(conf, c[1].win, 3, 11, LOWERED);
- wrefresh(c[1].win);
-
wclear(c[2].win);
mvwin(c[2].win, y + h - 6, x + w/2 + 8);
- draw_borders(conf, c[2].win, 3, 4, LOWERED);
- wrefresh(c[2].win);
/* Important to avoid grey lines expanding screen */
refresh();
break;
default:
if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ retval = bs.value[bs.curr];
loop = false;
}
}
}
- if (output == BSDDIALOG_OK) {
+ if (retval == BSDDIALOG_OK) {
*yy = c[0].value;
*mm = c[1].value;
*dd = c[2].value;
}
- curs_set(0);
-
for (i = 0; i < 3; i++)
delwin(c[i].win);
end_dialog(conf, shadow, widget, textpad);
- return (output);
+ return (retval);
}
diff --git a/util_theme.c b/util_theme.c
new file mode 100644
index 000000000000..e003e2c3d05f
--- /dev/null
+++ b/util_theme.c
@@ -0,0 +1,356 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <bsddialog.h>
+#include <bsddialog_theme.h>
+
+#include "util_theme.h"
+
+static struct bsddialog_theme t;
+static char title[1024];
+
+enum typeprop {
+ BOOL,
+ CHAR,
+ INT,
+ UINT,
+ COLOR
+};
+
+struct property {
+ const char* name;
+ enum typeprop type;
+ void *value;
+};
+
+#define NPROPERTY 38
+static struct property p[NPROPERTY] = {
+ { "theme.screen.color", COLOR, &t.screen.color },
+
+ { "theme.shadow.color", COLOR, &t.shadow.color },
+ { "theme.shadow.y", UINT, &t.shadow.y },
+ { "theme.shadow.x", UINT, &t.shadow.x },
+
+ { "theme.dialog.color", COLOR, &t.dialog.color },
+ { "theme.dialog.delimtitle", BOOL, &t.dialog.delimtitle },
+ { "theme.dialog.titlecolor", COLOR, &t.dialog.titlecolor },
+ { "theme.dialog.lineraisecolor", COLOR, &t.dialog.lineraisecolor },
+ { "theme.dialog.linelowercolor", COLOR, &t.dialog.linelowercolor },
+ { "theme.dialog.bottomtitlecolor", COLOR, &t.dialog.bottomtitlecolor },
+ { "theme.dialog.arrowcolor", COLOR, &t.dialog.arrowcolor },
+
+ { "theme.menu.f_selectorcolor", COLOR, &t.menu.f_selectorcolor},
+ { "theme.menu.selectorcolor", COLOR, &t.menu.selectorcolor},
+ { "theme.menu.f_namecolor", COLOR, &t.menu.f_namecolor},
+ { "theme.menu.namecolor", COLOR, &t.menu.namecolor},
+ { "theme.menu.f_desccolor", COLOR, &t.menu.f_desccolor},
+ { "theme.menu.desccolor", COLOR, &t.menu.desccolor},
+ { "theme.menu.namesepcolor", COLOR, &t.menu.namesepcolor},
+ { "theme.menu.descsepcolor", COLOR, &t.menu.descsepcolor},
+ { "theme.menu.f_shortcutcolor", COLOR, &t.menu.f_shortcutcolor},
+ { "theme.menu.shortcutcolor", COLOR, &t.menu.shortcutcolor},
+ { "theme.menu.bottomdesccolor", COLOR, &t.menu.bottomdesccolor},
+
+ { "theme.form.f_fieldcolor", COLOR, &t.form.f_fieldcolor},
+ { "theme.form.fieldcolor", COLOR, &t.form.fieldcolor},
+ { "theme.form.readonlycolor", COLOR, &t.form.readonlycolor},
+ { "theme.form.bottomdesccolor", COLOR, &t.form.bottomdesccolor},
+
+ { "theme.bar.f_color", COLOR, &t.bar.f_color},
+ { "theme.bar.color", COLOR, &t.bar.color},
+
+ { "theme.button.minmargin", UINT, &t.button.minmargin},
+ { "theme.button.maxmargin", UINT, &t.button.maxmargin},
+ { "theme.button.leftdelim", CHAR, &t.button.leftdelim},
+ { "theme.button.rightdelim", CHAR, &t.button.rightdelim},
+ { "theme.button.delimcolor", COLOR, &t.button.delimcolor},
+ { "theme.button.f_delimcolor", COLOR, &t.button.f_delimcolor},
+ { "theme.button.color", COLOR, &t.button.color},
+ { "theme.button.f_color", COLOR, &t.button.f_color},
+ { "theme.button.shortcutcolor", COLOR, &t.button.shortcutcolor},
+ { "theme.button.f_shortcutcolor", COLOR, &t.button.f_shortcutcolor}
+};
+
+static char *color[8] = {
+ "black",
+ "red",
+ "green",
+ "yellow",
+ "blue",
+ "magenta",
+ "cyan",
+ "white"
+};
+
+int savetheme(const char *file, char *errbuf, const char *version)
+{
+ int i;
+ unsigned int flags;
+ enum bsddialog_color bg, fg;
+ time_t clock;
+ FILE *fp;
+
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK) {
+ sprintf(errbuf, "Cannot save theme: %s", bsddialog_geterror());
+ return (BSDDIALOG_ERROR);
+ }
+
+ if(time(&clock) < 0) {
+ sprintf(errbuf, "Cannot save profile (getting current time)");
+ return (BSDDIALOG_ERROR);
+ }
+
+ if ((fp = fopen(file, "w")) == NULL) {
+ sprintf(errbuf, "Cannot open %s to save profile", file);
+ return (BSDDIALOG_ERROR);
+ }
+
+ fprintf(fp, "### bsddialog theme - %s", ctime(&clock));
+ fputs("# Refer to bsddialog(3) manual for theme.* properties\n", fp);
+ fprintf(fp, "version %s\n", version);
+
+ for (i = 0; i < NPROPERTY; i++) {
+ switch (p[i].type) {
+ case CHAR:
+ fprintf(fp, "%s %c\n", p[i].name, *((char*)p[i].value));
+ break;
+ case INT:
+ fprintf(fp, "%s %d\n", p[i].name, *((int*)p[i].value));
+ break;
+ case UINT:
+ fprintf(fp, "%s %u\n", p[i].name,
+ *((unsigned int*)p[i].value));
+ break;
+ case BOOL:
+ fprintf(fp, "%s %s\n", p[i].name,
+ *((bool*)p[i].value) ? "true" : "false");
+ break;
+ case COLOR:
+ bsddialog_color_attrs(*(int*)p[i].value, &fg, &bg,
+ &flags);
+ fprintf(fp, "%s %s %s%s%s%s\n",
+ p[i].name, color[fg], color[bg],
+ flags & BSDDIALOG_BOLD ? " bold" : "",
+ flags & BSDDIALOG_REVERSE ? " reverse" : "",
+ flags & BSDDIALOG_UNDERLINE ? " underline" : "");
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ return (BSDDIALOG_OK);
+}
+
+int loadtheme(const char *file, char *errbuf)
+{
+ bool boolvalue;
+ char charvalue, *value;
+ char line[BUFSIZ], name[BUFSIZ], c1[BUFSIZ], c2[BUFSIZ];
+ int i, j, intvalue, flags;
+ unsigned int uintvalue;
+ enum bsddialog_color bg, fg;
+ FILE *fp;
+
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK) {
+ sprintf(errbuf, "Cannot get current theme: %s",
+ bsddialog_geterror());
+ return (BSDDIALOG_ERROR);
+ }
+
+ if((fp = fopen(file, "r")) == NULL) {
+ sprintf(errbuf, "Cannot open theme \"%s\"", file);
+ return (BSDDIALOG_ERROR);
+ }
+
+#define RETURN_ERROR(name, error) do { \
+ sprintf(errbuf, "%s for \"%s\"", error, name); \
+ fclose(fp); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+
+ while(fgets(line, BUFSIZ, fp) != NULL) {
+ if(line[0] == '#' || line[0] == '\n')
+ continue; /* superfluous, only for efficiency */
+ sscanf(line, "%s", name);
+ for (i = 0; i < NPROPERTY; i++) {
+ if (strcmp(name, p[i].name) == 0) {
+ value = &line[strlen(name)];
+ break;
+ }
+ }
+ if (i >= NPROPERTY) {
+ if (strcmp(name, "version") == 0)
+ continue;
+ RETURN_ERROR(name, "Unknown theme property name");
+ }
+ switch (p[i].type) {
+ case CHAR:
+ while (value[0] == ' ' || value[0] == '\n' ||
+ value[0] == '\0')
+ value++;
+ if (sscanf(value, "%c", &charvalue) != 1)
+ RETURN_ERROR(p[i].name, "Cannot get a char");
+ *((int*)p[i].value) = charvalue;
+ break;
+ case INT:
+ if (sscanf(value, "%d", &intvalue) != 1)
+ RETURN_ERROR(p[i].name, "Cannot get a int");
+ *((int*)p[i].value) = intvalue;
+ break;
+ case UINT:
+ if (sscanf(value, "%u", &uintvalue) != 1)
+ RETURN_ERROR(p[i].name, "Cannot get a uint");
+ *((unsigned int*)p[i].value) = uintvalue;
+ break;
+ case BOOL:
+ boolvalue = (strstr(value, "true") != NULL) ?
+ true :false;
+ *((bool*)p[i].value) = boolvalue;
+ break;
+ case COLOR:
+ if (sscanf(value, "%s %s", c1, c2) != 2)
+ RETURN_ERROR(p[i].name, "Cannot get 2 colors");
+ /* Foreground */
+ for (j = 0; j < 8 ; j++)
+ if ((strstr(c1, color[j])) != NULL)
+ break;
+ if ((fg = j) > 7)
+ RETURN_ERROR(p[i].name, "Bad foreground");
+ /* Background */
+ for (j = 0; j < 8 ; j++)
+ if ((value = strstr(c2, color[j])) != NULL)
+ break;
+ if ((bg = j) > 7)
+ RETURN_ERROR(p[i].name, "Bad background");
+ /* Flags */
+ flags = 0;
+ if (strstr(value, "bold") != NULL)
+ flags |= BSDDIALOG_BOLD;
+ if (strstr(value, "reverse") != NULL)
+ flags |= BSDDIALOG_REVERSE;
+ if (strstr(value, "underline") != NULL)
+ flags |= BSDDIALOG_UNDERLINE;
+ *((int*)p[i].value) = bsddialog_color(fg, bg, flags);
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ bsddialog_set_theme(&t);
+
+ return (BSDDIALOG_OK);
+}
+
+int bikeshed(struct bsddialog_conf *conf, char *errbuf)
+{
+ int margin, i;
+ int colors[8] = {0, 0, 0, 0 ,0 ,0 , 0, 0};
+ enum bsddialog_color col[6];
+ time_t clock;
+
+ time(&clock);
+ srand(clock);
+
+ /* theme */
+ if (bsddialog_get_theme(&t) != BSDDIALOG_OK)
+ return (BSDDIALOG_ERROR);
+
+ for (i = 0; i < 6; i++) {
+ do {
+ col[i] = rand() % 8;
+ } while (colors[col[i]] == 1);
+ colors[col[i]] = 1;
+ }
+
+ t.screen.color = bsddialog_color(col[4], col[3], 0);
+
+ t.shadow.color = bsddialog_color(col[0], col[0], 0);
+ t.shadow.y = 1,
+ t.shadow.x = 2,
+
+ t.dialog.delimtitle = (rand() % 2 == 0) ? true : false;
+ t.dialog.titlecolor = bsddialog_color(col[3], col[5], 0);
+ t.dialog.lineraisecolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.linelowercolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.color = bsddialog_color(col[0], col[5], 0);
+ t.dialog.bottomtitlecolor = bsddialog_color(col[0], col[5], 0);
+ t.dialog.arrowcolor = bsddialog_color(col[3], col[5], 0);
+
+ t.menu.f_selectorcolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.selectorcolor = bsddialog_color(col[0], col[5], 0);
+ t.menu.f_desccolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.desccolor = bsddialog_color(col[0], col[5], 0);
+ t.menu.f_namecolor = bsddialog_color(col[5], col[3], 0);
+ t.menu.namecolor = bsddialog_color(col[3], col[5], 0);
+ t.menu.namesepcolor = bsddialog_color(col[1], col[5], 0);
+ t.menu.descsepcolor = bsddialog_color(col[1], col[5], 0);
+ t.menu.f_shortcutcolor = bsddialog_color(col[1], col[3], 0);
+ t.menu.shortcutcolor = bsddialog_color(col[1], col[5], 0);
+ t.menu.bottomdesccolor = bsddialog_color(col[4], col[3], 0);
+
+ t.form.f_fieldcolor = bsddialog_color(col[5], col[3], 0);
+ t.form.fieldcolor = bsddialog_color(col[5], col[4], 0);
+ t.form.readonlycolor = bsddialog_color(col[4], col[5], 0);
+ t.form.bottomdesccolor = bsddialog_color(col[4], col[3], 0);
+
+ t.bar.f_color = bsddialog_color(col[5], col[3], 0);
+ t.bar.color = bsddialog_color(col[3], col[5], 0);
+
+ t.button.minmargin = 1,
+ t.button.maxmargin = 5,
+ t.button.leftdelim = '[',
+ t.button.rightdelim = ']',
+ t.button.f_delimcolor = bsddialog_color(col[5], col[3], 0);
+ t.button.delimcolor = bsddialog_color(col[0], col[5], 0);
+ t.button.f_color = bsddialog_color(col[2], col[3], 0);
+ t.button.color = bsddialog_color(col[0], col[5], 0);
+ t.button.f_shortcutcolor = bsddialog_color(col[5], col[3], 0);
+ t.button.shortcutcolor = bsddialog_color(col[1], col[5], 0);
+
+ if (bsddialog_set_theme(&t))
+ return (BSDDIALOG_ERROR);
+
+ /* conf */
+ conf->button.always_active = (rand() % 2 == 0) ? true : false;
+ if (conf->title != NULL) {
+ memset(title, 0, 1024);
+ margin = rand() % 5;
+ memset(title, ' ', margin);
+ strcpy(title + margin, conf->title);
+ memset(title + strlen(title), ' ', margin);
+ conf->title = title;
+ }
+
+ return (BSDDIALOG_OK);
+}
diff --git a/util_theme.h b/util_theme.h
new file mode 100644
index 000000000000..fd9b32db1204
--- /dev/null
+++ b/util_theme.h
@@ -0,0 +1,35 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BSDDIALOG_UTILITY_THEME_H_
+#define _BSDDIALOG_UTILITY_THEME_H_
+
+int savetheme(const char *file, char *errbuf, const char *version);
+int loadtheme(const char *file, char *errbuf);
+int bikeshed(struct bsddialog_conf *conf, char *errbuf);
+
+#endif