aboutsummaryrefslogtreecommitdiff
path: root/contrib/bsddialog/lib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsddialog/lib')
-rw-r--r--contrib/bsddialog/lib/GNUmakefile (renamed from contrib/bsddialog/lib/GNUMakefile)15
-rw-r--r--contrib/bsddialog/lib/Makefile49
-rw-r--r--contrib/bsddialog/lib/barbox.c815
-rw-r--r--contrib/bsddialog/lib/bsddialog.3790
-rw-r--r--contrib/bsddialog/lib/bsddialog.h68
-rw-r--r--contrib/bsddialog/lib/bsddialog_progressview.h8
-rw-r--r--contrib/bsddialog/lib/bsddialog_theme.h45
-rw-r--r--contrib/bsddialog/lib/datebox.c746
-rw-r--r--contrib/bsddialog/lib/formbox.c1195
-rw-r--r--contrib/bsddialog/lib/infobox.c96
-rw-r--r--contrib/bsddialog/lib/lib_util.c1504
-rw-r--r--contrib/bsddialog/lib/lib_util.h169
-rw-r--r--contrib/bsddialog/lib/libbsddialog.c64
-rw-r--r--contrib/bsddialog/lib/menubox.c887
-rw-r--r--contrib/bsddialog/lib/messagebox.c260
-rw-r--r--contrib/bsddialog/lib/textbox.c279
-rw-r--r--contrib/bsddialog/lib/theme.c314
-rw-r--r--contrib/bsddialog/lib/timebox.c534
18 files changed, 4605 insertions, 3233 deletions
diff --git a/contrib/bsddialog/lib/GNUMakefile b/contrib/bsddialog/lib/GNUmakefile
index 0d724b803be3..7c7a9bc25ee4 100644
--- a/contrib/bsddialog/lib/GNUMakefile
+++ b/contrib/bsddialog/lib/GNUmakefile
@@ -3,16 +3,19 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.2
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
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
OBJECTS = $(SOURCES:.c=.o)
-CFLAGS = -D_XOPEN_SOURCE_EXTENDED -Wall -Wextra -Wno-implicit-fallthrough \
- -Werror -fpic
-LDFLAGS = -lformw -lncursesw -ltinfo
+
+ifneq ($(ENABLEDEBUG),)
+CFLAGS += -g
+endif
+CFLAGS += -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE -D_GNU_SOURCE \
+ -Wall -Wextra -Werror -fpic
+LDFLAGS += -lncursesw -ltinfo
LIBFLAG = -shared
RM = rm -f
diff --git a/contrib/bsddialog/lib/Makefile b/contrib/bsddialog/lib/Makefile
index 962b059b3e03..252b33f79848 100644
--- a/contrib/bsddialog/lib/Makefile
+++ b/contrib/bsddialog/lib/Makefile
@@ -3,39 +3,27 @@
#
# Written in 2021 by Alfonso Sabato Siciliano
-VERSION = 0.2
LIBRARY = bsddialog
LIBRARY_SO = lib${LIBRARY:=.so}
LIBRARY_A = lib${LIBRARY:=.a}
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
+SOURCES = barbox.c datebox.c formbox.c libbsddialog.c lib_util.c \
+ menubox.c messagebox.c textbox.c theme.c timebox.c
OBJECTS = ${SOURCES:.c=.o}
-CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
- -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
- -L/usr/lib -lformw -lncursesw -ltinfow
.if defined(DEBUG)
-# `make -DDEBUG`
-CFLAGS = -g -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra
-.else
-CFLAGS += -std=gnu99 -fstack-protector-strong
+CFLAGS += -g
.endif
+CFLAGS += -D_XOPEN_SOURCE_EXTENDED -fPIC -Wall -Wextra -std=gnu99 \
+ -fstack-protector-strong
+LDFLAGS += -fstack-protector-strong -shared -Wl,-x -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel -Wl,-soname,${LIBRARY_SO}.${VERSION} \
+ -L/usr/lib -lncursesw -ltinfow
-LOCALBASE = /usr/local
LN = ln -s -f
RM = rm -f
-CP = cp
-GZIP = gzip -cn
-LDCONFIG = /sbin/ldconfig -m
-MAN = ${OUTPUT}.3
-GZIP = gzip -cn
-MANDIR = ${LOCALBASE}/share/man/man3
-INSTALL = install
-RM = rm -f
-all : man ${LIBRARY}
+all : ${LIBRARY}
${LIBRARY}: ${LIBRARY_SO} ${LIBRARY_A}
@@ -52,24 +40,5 @@ ${LIBRARY_A}: ${OBJECTS}
.c.o:
${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
-man:
- ${GZIP} ${LIBRARY}.3 > ${LIBRARY}.3.gz
-
clean:
${RM} ${LIBRARY_SO}* *.o *~ *.gz ${LIBRARY_A}
-
-
-install:
- ${INSTALL} -m 644 ${HEADERS} ${LOCALBASE}/include
- ${INSTALL} -m 644 -s ${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/
- ${INSTALL} -l rs ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${INSTALL} -m 644 ${LIBRARY_A} ${LOCALBASE}/lib
- ${LDCONFIG} ${LOCALBASE}/lib
- ${INSTALL} -m 644 ${LIBRARY}.3.gz ${MANDIR}
-
-unistall:
- ${RM} ${LOCALBASE}/include/${LIBRARY}*.h
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}
- ${RM} ${LOCALBASE}/lib/${LIBRARY_SO}.${VERSION}
- ${LDCONFIG} ${LOCALBASE}/lib
- ${RM} ${MANDIR}/${LIBRARY}.3.gz
diff --git a/contrib/bsddialog/lib/barbox.c b/contrib/bsddialog/lib/barbox.c
index 49aa105c1de3..4feea20c6441 100644
--- a/contrib/bsddialog/lib/barbox.c
+++ b/contrib/bsddialog/lib/barbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,9 +25,6 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
@@ -39,139 +36,138 @@
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define BARPADDING 2
-#define MINBARLEN 15
-#define MINBARWIDTH (2 + 2 * BARPADDING + MINBARLEN)
-#define MINMGBARLEN 18
-#define MINMGBARWIDTH (2 + 2 * BARPADDING + MINMGBARLEN)
+#define BARPADDING 2 /* Dialog border | BARPADDING | box bar */
+#define BOXBORDERS 2
+#define MIN_WBAR 15
+#define MIN_WBOX (BARPADDING + BOXBORDERS + MIN_WBAR + BARPADDING)
+#define MIN_WMGBAR 18 /* Mixedgauge main bar */
+#define MIN_WMGBOX (BARPADDING + BOXBORDERS + MIN_WMGBAR + BARPADDING)
+#define HBOX 3
+#define WBOX(d) ((d)->w - BORDERS - BARPADDING - BARPADDING)
+#define WBAR(d) (WBOX(d) - BOXBORDERS)
bool bsddialog_interruptprogview;
bool bsddialog_abortprogview;
-int bsddialog_total_progview;
-
-static void
-draw_bar(WINDOW *win, int y, int x, int barlen, int perc, bool withlabel,
- int label)
+long long int bsddialog_total_progview;
+
+static const char states[12][14] = {
+ " Succeeded ", /* -1 */
+ " Failed ", /* -2 */
+ " Passed ", /* -3 */
+ " Completed ", /* -4 */
+ " Checked ", /* -5 */
+ " Done ", /* -6 */
+ " Skipped ", /* -7 */
+ " In Progress ", /* -8 */
+ "(blank) ", /* -9 */
+ " N/A ", /* -10 */
+ " Pending ", /* -11 */
+ " UNKNOWN ", /* < -11, no API */
+};
+
+struct bar {
+ bool toupdate;
+ WINDOW *win;
+ int y; /* bar y in win */
+ int x; /* bar x in win */
+ int w; /* width in win */
+ int perc; /* barlen = (w * perc) / 100 */
+ const char* fmt; /* format for label */
+ int label; /* rangebox and pause perc!=label */
+};
+
+static void draw_bar(struct bar *b)
{
- int i, blue_x, color, stringlen;
- char labelstr[128];
-
- blue_x = perc > 0 ? (perc * barlen) / 100 : -1;
-
- wmove(win, y, x);
- for (i = 0; i < barlen; i++) {
- color = (i <= blue_x) ? t.bar.f_color : t.bar.color;
- wattron(win, color);
- waddch(win, ' ');
- wattroff(win, color);
- }
-
- if (withlabel)
- sprintf(labelstr, "%d", label);
- else
- sprintf(labelstr, "%3d%%", perc);
- stringlen = (int)strlen(labelstr);
- wmove(win, y, x + barlen/2 - stringlen/2);
- for (i = 0; i < stringlen; i++) {
- color = (blue_x + 1 <= barlen/2 - stringlen/2 + i ) ?
- t.bar.color : t.bar.f_color;
- wattron(win, color);
- waddch(win, labelstr[i]);
- wattroff(win, color);
- }
+ int barlen, xlabel;
+ chtype ch;
+ char label[128];
+
+ barlen = b->perc > 0 ? (b->perc * b->w) / 100 : 0;
+
+ ch = ' ' | t.bar.f_color;
+ mvwhline(b->win, b->y, b->x, ch, barlen);
+ ch = ' ' | t.bar.color;
+ mvwhline(b->win, b->y, b->x + barlen, ch, b->w - barlen);
+
+ sprintf(label, b->fmt, b->label);
+ xlabel = b->x + b->w/2 - (int)strlen(label)/2; /* 1-byte-char string */
+ wattron(b->win, t.bar.color); /* x+barlen < xlabel */
+ mvwaddstr(b->win, b->y, xlabel, label);
+ wattroff(b->win, t.bar.color);
+ wattron(b->win, t.bar.f_color); /* x+barlen >= xlabel */
+ mvwaddnstr(b->win, b->y, xlabel, label, MAX((b->x+barlen) - xlabel, 0));
+ wattroff(b->win, t.bar.f_color);
+
+ if (b->toupdate)
+ wnoutrefresh(b->win);
+ b->toupdate = false;
}
-static int
-bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, struct buttons *bs)
+static void update_barbox(struct dialog *d, struct bar *b, bool buttons)
{
- int htext, wtext;
+ int y;
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, bs, 3, MINBARWIDTH,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, MINBARWIDTH, bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* bar */, bs != NULL);
-
- return (0);
-}
-
-static int
-bar_checksize(int rows, int cols, struct buttons *bs)
-{
- int minheight, minwidth;
-
- minwidth = 0;
- if (bs != NULL) /* gauge has not buttons */
- minwidth = buttons_width(*bs);
-
- minwidth = MAX(minwidth, MINBARWIDTH);
- minwidth += VBORDERS;
-
- if (cols < minwidth)
- RETURN_ERROR("Few cols to draw bar and/or buttons");
-
- minheight = HBORDERS + 3;
- if (bs != NULL)
- minheight += 2;
- if (rows < minheight)
- RETURN_ERROR("Few rows to draw bar");
-
- return (0);
+ y = d->y + d->h - BORDER - HBOX;
+ if (buttons)
+ y -= HBUTTONS;
+ update_box(d->conf, b->win, y, d->x + BORDER + BARPADDING, HBOX,
+ WBOX(d), RAISED);
}
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep)
+ int cols, unsigned int perc, int fd, const char *sep, const char *end)
{
bool mainloop;
- int y, x, h, w, fd2;
+ int fd2;
FILE *input;
- WINDOW *widget, *textpad, *bar, *shadow;
char inputbuf[2048], ntext[2048], *pntext;
+ struct bar b;
+ struct dialog d;
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, NULL) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, NULL) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, NULL,
- false) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%3d%%";
- bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
-
- mainloop = (fd < 0) ? false : true;
+ input = NULL;
+ if (fd >= 0) {
+ CHECK_PTR(sep);
+ CHECK_PTR(end);
- if (mainloop) {
fd2 = dup(fd);
- input = fdopen(fd2, "r");
- if (input == NULL)
- RETURN_ERROR("Cannot build FILE* from fd");
- } else
- input = NULL;
+ if ((input = fdopen(fd2, "r")) == NULL)
+ RETURN_FMTERROR("Cannot build FILE* from fd %d", fd);
+ }
+ perc = MIN(perc, 100);
+ mainloop = true;
while (mainloop) {
- wrefresh(widget);
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-4,
- x+w-1-TEXTHMARGIN);
- draw_borders(conf, bar, 3, w-6, RAISED);
- draw_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/);
- wrefresh(bar);
+ if (d.built) {
+ hide_dialog(&d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(&d, HBOX, MIN_WBOX, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d))
+ return (BSDDIALOG_ERROR);
+ if (d.built)
+ refresh(); /* fix grey lines expanding screen */
+ TEXTPAD(&d, HBOX);
+ update_barbox(&d, &b, false);
+ b.w = WBAR(&d);
+ b.perc = b.label = perc;
+ b.toupdate = true;
+ draw_bar(&b);
+ doupdate();
+ if (input == NULL) /* that is fd < 0 */
+ break;
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
@@ -181,154 +177,173 @@ bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
if (mainloop == false)
break;
fscanf(input, "%d", &perc);
- perc = perc > 100 ? 100 : perc;
+ perc = MIN(perc, 100);
pntext = &ntext[0];
ntext[0] = '\0';
while (true) {
fscanf(input, "%s", inputbuf);
- if (strcmp(inputbuf,"EOF") == 0) {
+ if (strcmp(inputbuf, end) == 0) {
mainloop = false;
break;
}
if (strcmp(inputbuf, sep) == 0)
break;
strcpy(pntext, inputbuf);
- pntext += strlen(inputbuf);
+ pntext += strlen(inputbuf); /* end string, no strlen */
pntext[0] = ' ';
pntext++;
}
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- ntext, NULL, false) != 0)
- return (BSDDIALOG_ERROR);
+ pntext[0] = '\0';
+ d.text = ntext;
}
if (input != NULL)
fclose(input);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
/* Mixedgauge */
+static void
+mvwaddcstr(WINDOW *win, int y, int x, const char *mbstring, unsigned int cols)
+{
+ size_t charlen, n, w;
+ mbstate_t mbs;
+ const char *pmbstring;
+ wchar_t wch;
+
+ w = n = 0;
+ pmbstring = mbstring;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ mbtowc(&wch, pmbstring, charlen);
+ w += (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ if (w > cols)
+ break;
+ pmbstring += charlen;
+ n += charlen;
+ }
+ mvwaddnstr(win, y, x, mbstring, n);
+ if(w > cols)
+ mvwaddstr(win, y, (x + cols) - 3, "...");
+}
+
+static int
+mixedgauge_size_position(struct dialog *d, int nminibars,
+ const char **minilabels, int *htext)
+{
+ int i, max_minibarlen;
+
+ max_minibarlen = 0;
+ for (i = 0; i < (int)nminibars; i++)
+ max_minibarlen = MAX(max_minibarlen,
+ (int)strcols(CHECK_STR(minilabels[i])));
+ max_minibarlen += 18; /* ' '<max_minibarlen>' ['13'] ' */
+ max_minibarlen = MAX(max_minibarlen, MIN_WMGBOX); /* mainbar */
+
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, htext, &d->bs, nminibars + HBOX, max_minibarlen) != 0)
+ return (BSDDIALOG_ERROR);
+ if (widget_checksize(d->h, d->w, &d->bs, nminibars + HBOX,
+ MIN_WMGBOX) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
+}
+
static int
do_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 htextpad, htext, wtext;
- int colorperc, red, green;
- WINDOW *widget, *textpad, *bar, *shadow;
- char states[12][14] = {
- " Succeeded ", /* -1 */
- " Failed ", /* -2 */
- " Passed ", /* -3 */
- " Completed ", /* -4 */
- " Checked ", /* -5 */
- " Done ", /* -6 */
- " Skipped ", /* -7 */
- " In Progress ", /* -8 */
- "(blank) ", /* -9 */
- " N/A ", /* -10 */
- " Pending ", /* -11 */
- " UNKNOWN ", /* < -11, no API */
- };
+ int i, miniperc;
+ int ystext, htext;
+ int minicolor, red, green;
+ struct bar b;
+ struct dialog d;
+
+ CHECK_ARRAY(nminibars, minilabels);
+ CHECK_ARRAY(nminibars, minipercs);
red = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_RED, BSDDIALOG_BOLD);
green = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_GREEN,BSDDIALOG_BOLD);
- max_minbarlen = 0;
- for (i = 0; i < (int)nminibars; i++)
- max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i]));
- max_minbarlen += 3 + 16; /* seps + [...] */
- max_minbarlen = MAX(max_minbarlen, MINMGBARWIDTH); /* mainbar */
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
-
- /* mixedgauge autosize */
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, nminibars + 3,
- max_minbarlen, &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
- if (cols == BSDDIALOG_AUTOSIZE)
- w = widget_min_width(conf, wtext, max_minbarlen, NULL);
- if (rows == BSDDIALOG_AUTOSIZE)
- h = widget_min_height(conf, htext, nminibars + 3, false);
-
- /* mixedgauge checksize */
- if (w < max_minbarlen + 2)
- RETURN_ERROR("Few cols for this mixedgauge");
- if (h < 5 + (int)nminibars)
- RETURN_ERROR("Few rows for this mixedgauge");
-
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (mixedgauge_size_position(&d, nminibars, minilabels, &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
return (BSDDIALOG_ERROR);
-
- output = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false);
- if (output == BSDDIALOG_ERROR)
- return (output);
/* mini bars */
+ b.win = d.widget;
+ b.x = 1 + d.w - 2 - 15;
+ b.w = 13;
+ b.fmt = "%3d%%";
+ b.toupdate = false;
for (i = 0; i < (int)nminibars; i++) {
miniperc = minipercs[i];
- if (miniperc == BSDDIALOG_MG_BLANK)
- continue;
/* label */
- if (color && (miniperc >= 0))
- wattron(widget, A_BOLD);
- mvwaddstr(widget, i+1, 2, minilabels[i]);
- wattroff(widget, A_BOLD);
+ if (color && miniperc >= 0)
+ wattron(d.widget, A_BOLD);
+ mvwaddcstr(d.widget, i+1, 2, CHECK_STR(minilabels[i]), d.w-20);
+ if (color && miniperc >= 0)
+ wattroff(d.widget, A_BOLD);
/* perc */
- if (miniperc < -11)
- mvwaddstr(widget, i+1, w-2-15, states[11]);
- else if (miniperc < 0) {
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- colorperc = -1;
+ if (miniperc == BSDDIALOG_MG_BLANK)
+ continue;
+ mvwaddstr(d.widget, i+1, d.w-2-15, "[ ]");
+ if (miniperc >= 0) {
+ b.y = i + 1;
+ b.perc = b.label = MIN(miniperc, 100);
+ draw_bar(&b);
+ } else { /* miniperc < 0 */
+ if (miniperc < BSDDIALOG_MG_PENDING)
+ miniperc = -12; /* UNKNOWN */
+ minicolor = t.dialog.color;
if (color && miniperc == BSDDIALOG_MG_FAILED)
- colorperc = red;
- if (color && miniperc == BSDDIALOG_MG_DONE)
- colorperc = green;
- if (colorperc != -1)
- wattron(widget, colorperc);
+ minicolor = red;
+ else if (color && miniperc == BSDDIALOG_MG_DONE)
+ minicolor = green;
+ wattron(d.widget, minicolor);
miniperc = abs(miniperc + 1);
- mvwaddstr(widget, i+1, 1+w-2-15, states[miniperc]);
- if (colorperc != -1)
- wattroff(widget, colorperc);
- }
- else { /* miniperc >= 0 */
- if (miniperc > 100)
- miniperc = 100;
- mvwaddstr(widget, i+1, w-2-15, "[ ]");
- draw_bar(widget, i+1, 1+w-2-15, 13, miniperc, false,
- -1 /*unused*/);
+ mvwaddstr(d.widget, i+1, 1+d.w-2-15, states[miniperc]);
+ wattroff(d.widget, minicolor);
}
}
+ wnoutrefresh(d.widget);
- wrefresh(widget);
- getmaxyx(textpad, htextpad, i /* unused */);
- ypad = y + h - 4 - htextpad;
- ypad = ypad < y+(int)nminibars ? y+(int)nminibars : ypad;
- prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2);
+ /* text */
+ ystext = MAX(d.h - BORDERS - htext - HBOX, (int)nminibars);
+ rtextpad(&d, 0, 0, ystext, HBOX);
/* main bar */
- bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED);
-
- draw_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/);
-
- wattron(bar, t.bar.color);
- mvwaddstr(bar, 0, 2, "Overall Progress");
- wattroff(bar, t.bar.color);
-
- wrefresh(bar);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ update_barbox(&d, &b, false);
+ wattron(b.win, t.bar.color);
+ mvwaddstr(b.win, 0, 2, "Overall Progress");
+ wattroff(b.win, t.bar.color);
+
+ b.y = b.x = 1;
+ b.w = WBAR(&d);
+ b.fmt = "%3d%%";
+ b.perc = b.label = MIN(mainperc, 100);
+ b.toupdate = true;
+ draw_bar(&b);
- /* getch(); port ncurses shows nothing */
+ doupdate();
+ /* getch(); to test with "alternate mode" */
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ delwin(b.win);
+ end_dialog(&d);
return (BSDDIALOG_OK);
}
@@ -338,12 +353,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 +367,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 +386,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 +399,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);
@@ -412,7 +427,8 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
minipercs[i] = BSDDIALOG_MG_DONE;
update = true;
i++;
- } else if (minibar[i].status == BSDDIALOG_MG_FAILED || perc < 0) {
+ } else if (minibar[i].status == BSDDIALOG_MG_FAILED ||
+ perc < 0) {
minipercs[i] = BSDDIALOG_MG_FAILED;
update = true;
} else /* perc >= 0 */
@@ -421,326 +437,279 @@ bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows,
free(minilabels);
free(minipercs);
- return (output);
+ return (retval);
+}
+
+static int rangebox_redraw(struct dialog *d, struct bar *b, int *bigchange)
+{
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MIN_WBOX, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
+
+ b->w = WBAR(d);
+ *bigchange = MAX(1, b->w / 10);
+ update_barbox(d, b, true);
+ b->toupdate = true;
+
+ return (0);
}
int
bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows,
int cols, int min, int max, int *value)
{
- bool loop, buttupdate, barupdate;
- int y, x, h, w;
- int input, currvalue, output, sizebar, bigchange, positions;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- if (value == NULL)
- RETURN_ERROR("*value cannot be NULL");
+ bool loop;
+ int currvalue, retval, bigchange, positions;
+ wint_t input;
+ struct bar b;
+ struct dialog d;
+ CHECK_PTR(value);
if (min >= max)
- RETURN_ERROR("min >= max");
+ RETURN_FMTERROR("min (%d) >= max (%d)", min, max);
+ if (*value < min)
+ RETURN_FMTERROR("value (%d) < min (%d)", *value, min);
+ if (*value > max)
+ RETURN_FMTERROR("value (%d) > max (%d)", *value, max);
currvalue = *value;
positions = max - min + 1;
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%d";
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
-
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
-
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
+ if (b.toupdate) {
+ b.perc = ((float)(currvalue - min)*100) / (positions-1);
+ b.label = currvalue;
+ draw_bar(&b);
}
- if (barupdate) {
- perc = ((float)(currvalue - min)*100) / (positions-1);
- draw_bar(bar, 1, 1, sizebar, perc, true, currvalue);
- barupdate = false;
- wrefresh(bar);
- }
-
- input = getch();
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
- *value = currvalue;
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
+ case KEY_CTRL('p'):
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_HOME:
currvalue = max;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_END:
currvalue = min;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_NPAGE:
currvalue -= bigchange;
if (currvalue < min)
currvalue = min;
- barupdate = true;
+ b.toupdate = true;
break;
case KEY_PPAGE:
currvalue += bigchange;
if (currvalue > max)
currvalue = max;
- barupdate = true;
+ b.toupdate = true;
break;
+ case '-':
case KEY_UP:
- if (currvalue < max) {
- currvalue++;
- barupdate = true;
+ if (currvalue > min) {
+ currvalue--;
+ b.toupdate = true;
}
break;
+ case '+':
case KEY_DOWN:
- if (currvalue > min) {
- currvalue--;
- barupdate = true;
+ if (currvalue < max) {
+ currvalue++;
+ b.toupdate = true;
}
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget,y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (rangebox_redraw(&d, &b, &bigchange) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bigchange = MAX(1, sizebar/10);
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, RAISED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *value = currvalue;
+
+ delwin(b.win);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
-int
-bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int sec)
+static int pause_redraw(struct dialog *d, struct bar *b)
{
- bool loop, buttupdate, barupdate;
- int output, y, x, h, w, input, tout, sizebar;
- float perc;
- WINDOW *widget, *textpad, *bar, *shadow;
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MIN_WBOX, NULL) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (draw_dialog(d) != 0)
return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
+ b->w = WBAR(d);
+ update_barbox(d, b, true);
+ b->toupdate = true;
- doupdate();
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN);
+ return (0);
+}
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3,
- sizebar + 2, RAISED);
+int
+bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *seconds)
+{
+ bool loop;
+ int retval, tout;
+ wint_t input;
+ struct bar b;
+ struct dialog d;
+
+ CHECK_PTR(seconds);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((b.win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW bar");
+ b.y = b.x = 1;
+ b.fmt = "%d";
+ if (pause_redraw(&d, &b) != 0)
+ return (BSDDIALOG_ERROR);
- tout = sec;
+ tout = *seconds;
nodelay(stdscr, TRUE);
timeout(1000);
- loop = buttupdate = barupdate = true;
+ loop = true;
while (loop) {
- if (barupdate) {
- perc = (float)tout * 100 / sec;
- draw_bar(bar, 1, 1, sizebar, perc, true, tout);
- barupdate = false;
- wrefresh(bar);
- }
-
- if (buttupdate) {
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- buttupdate = false;
+ if (b.toupdate) {
+ b.perc = (float)tout * 100 / *seconds;
+ b.label = tout;
+ draw_bar(&b);
}
-
- input = getch();
- if (input < 0) { /* timeout */
+ doupdate();
+ if (get_wch(&input) == ERR) { /* timeout */
tout--;
if (tout < 0) {
- output = BSDDIALOG_TIMEOUT;
+ retval = BSDDIALOG_TIMEOUT;
break;
}
else {
- barupdate = true;
+ b.toupdate = true;
continue;
}
}
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- buttupdate = true;
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- buttupdate = true;
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- buttupdate = true;
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_autosize(conf, rows, cols, &h, &w, text,
- &bs) != 0)
- return (BSDDIALOG_ERROR);
- if (bar_checksize(h, w, &bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (pause_redraw(&d, &b) != 0)
return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget,y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (pause_redraw(&d, &b) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- sizebar = w - HBORDERS - (2 * BARPADDING) - 2;
- wclear(bar);
- mvwin(bar, y + h - 6, x + 1 + BARPADDING);
- wresize(bar, 3, sizebar + 2);
- draw_borders(conf, bar, 3, sizebar+2, LOWERED);
-
- prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7,
- x+w-1-TEXTHMARGIN);
-
- barupdate = true;
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
-
nodelay(stdscr, FALSE);
- delwin(bar);
- end_dialog(conf, shadow, widget, textpad);
+ *seconds = MAX(tout, 0);
- return (output);
-} \ No newline at end of file
+ delwin(b.win);
+ end_dialog(&d);
+
+ return (retval);
+}
diff --git a/contrib/bsddialog/lib/bsddialog.3 b/contrib/bsddialog/lib/bsddialog.3
index 38500b4da6ca..cbf1653a2aca 100644
--- a/contrib/bsddialog/lib/bsddialog.3
+++ b/contrib/bsddialog/lib/bsddialog.3
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+.\" Copyright (c) 2021-2024 Alfonso Sabato Siciliano
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -22,13 +22,15 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 9, 2022
+.Dd March 16, 2024
.Dt BSDDIALOG 3
.Os
.Sh NAME
.Nm bsddialog_backtitle ,
-.Nm bsddialog_clearterminal ,
+.Nm bsddialog_calendar ,
+.Nm bsddialog_clear ,
.Nm bsddialog_color ,
+.Nm bsddialog_color_attrs ,
.Nm bsddialog_checklist ,
.Nm bsddialog_datebox ,
.Nm bsddialog_end ,
@@ -36,9 +38,12 @@
.Nm bsddialog_gauge ,
.Nm bsddialog_geterror ,
.Nm bsddialog_get_theme ,
+.Nm bsddialog_hascolors ,
.Nm bsddialog_infobox ,
.Nm bsddialog_init ,
+.Nm bsddialog_init_notheme ,
.Nm bsddialog_initconf ,
+.Nm bsddialog_inmode ,
.Nm bsddialog_menu ,
.Nm bsddialog_mixedgauge ,
.Nm bsddialog_mixedlist ,
@@ -46,6 +51,7 @@
.Nm bsddialog_pause ,
.Nm bsddialog_radiolist ,
.Nm bsddialog_rangebox ,
+.Nm bsddialog_refresh ,
.Nm bsddialog_set_theme ,
.Nm bsddialog_set_default_theme ,
.Nm bsddialog_textbox ,
@@ -59,6 +65,16 @@
.Ft int
.Fn bsddialog_backtitle "struct bsddialog_conf *conf" "const char *backtitle"
.Ft int
+.Fo bsddialog_calendar
+.Fa "struct bsddialog_conf *conf"
+.Fa "const char *text"
+.Fa "int rows"
+.Fa "int cols"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
+.Fc
+.Ft int
.Fo bsddialog_checklist
.Fa "struct bsddialog_conf *conf"
.Fa "const char *text"
@@ -69,17 +85,17 @@
.Fa "struct bsddialog_menuitem *items"
.Fa "int *focusitem"
.Fc
+.Ft void
+.Fn bsddialog_clear "unsigned int y"
.Ft int
-.Fn bsddialog_clearterminal "void"
-.Ft int
-.Fo bsddialog_datebox"
+.Fo bsddialog_datebox
.Fa "struct bsddialog_conf *conf"
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int *yy"
-.Fa "unsigned int *mm"
-.Fa "unsigned int *dd"
+.Fa "unsigned int *year"
+.Fa "unsigned int *month"
+.Fa "unsigned int *day"
.Fc
.Ft int
.Fn bsddialog_end "void"
@@ -92,6 +108,7 @@
.Fa "unsigned int formrows"
.Fa "unsigned int nitems"
.Fa "struct bsddialog_formitem *items"
+.Fa "int *focusitem"
.Fc
.Ft int
.Fo bsddialog_gauge
@@ -102,6 +119,7 @@
.Fa "unsigned int perc"
.Fa "int fd"
.Fa "const char *sep"
+.Fa "const char *end"
.Fc
.Ft const char *
.Fn bsddialog_geterror "void"
@@ -115,6 +133,10 @@
.Ft int
.Fn bsddialog_init "void"
.Ft int
+.Fn bsddialog_init_notheme "void"
+.Ft bool
+.Fn bsddialog_inmode "void"
+.Ft int
.Fn bsddialog_initconf "struct bsddialog_conf *conf"
.Ft int
.Fo bsddialog_menu
@@ -163,7 +185,7 @@
.Fa "const char *text"
.Fa "int rows"
.Fa "int cols"
-.Fa "unsigned int seconds"
+.Fa "unsigned int *seconds"
.Fc
.Ft int
.Fo bsddialog_radiolist
@@ -186,6 +208,8 @@
.Fa "int max"
.Fa "int *value"
.Fc
+.Ft void
+.Fn bsddialog_refresh "void"
.Ft int
.Fo bsddialog_textbox
.Fa "struct bsddialog_conf *conf"
@@ -218,7 +242,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
@@ -226,8 +259,7 @@
.Sh DESCRIPTION
The
.Nm bsddialog
-library provides an API to build Text User Interface dialogs and widgets: to
-display messages, to get input and to inform about a computation status.
+library provides an API to build Text User Interface dialogs and widgets.
.Pp
.Fn bsddialog_init
initializes the library, the only functions that can be called before is
@@ -235,53 +267,80 @@ initializes the library, the only functions that can be called before is
described later.
After the initialization the input and output should be handled via the library
API.
+.Pp
+.Fn bsddialog_init_notheme
+is equivalent to
+.Fn bsddialog_init
+except it does not set the default graphical theme; see
+.Sx Theme
+subsection to set a theme explicitly.
+.Pp
.Fn bsddialog_end
restores the screen like before
-.Fn bsddialog_init ,
-then it is not possible to use the library functions.
+.Fn bsddialog_init .
+After the call is not possible to use the library functions.
+.Pp
+.Fn bsddialog_inmode
+returns
+.Dv true
+after
+.Fn bsddialog_init
+or
+.Fn bsddialog_init_notheme
+and before
+.Fn bsddialog_end ,
+.Dv false
+otherwise.
.Pp
-.Fn bsddialog_error
-returns a string to describe the last error, it should be called after a
-.Dv BSDDIALOG_ERROR
-returned value.
-.Fn bsddialog_clearterminal
-clears the screen.
.Fn bsddialog_backtitle
prints
.Fa backtitle
-on the top of the screen, it is possible to set
+on the top of the screen.
+The function handles
.Fa conf.ascii_lines
and
-.Fa conf.no_lines ;
-.Fa conf
-is described later.
+.Fa conf.no_lines
+described later.
.Pp
-Each
-.Fa char*
-argument has to be a well terminated string, can be empty
-.Pq Dq
-but not
-.Dv NULL .
+.Fn bsddialog_error
+returns a string to describe the last error.
+The function should be called after a
+.Dv BSDDIALOG_ERROR
+returned value.
+.Pp
+.Fn bsddialog_clear
+clears the screen from
+.Fa y .
+.Pp
+.Fn bsddialog_refresh
+useful to refresh the screen after a terminal mode change, see
+.Xr terminfo 5 .
.Ss Dialogs
The dialogs have common arguments.
.Fa text
is a string printed inside the dialog.
+Each
+.Fa char*
+parameter can be a multibyte character string depending on current locale, see
+.Xr setlocale 3 .
.Fa rows
and
.Fa cols
-are height and width, their value can be between 2 and the screen size,
+are height and width, their value can be a fixed size,
.Dv BSDDIALOG_AUTOSIZE
or
.Dv BSDDIALOG_FULLSCREEN .
.Fa conf
-is a struct to customize the dialog, it does not set global properties to the
-library.
+is a struct to customize the current dialog, it does not set global properties
+to the library.
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_conf {
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,22 +357,29 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
- bool highlight;
+ unsigned int cols_per_row;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
- bool value_without_ok;
+ char securech;
+ char *securembch;
+ bool value_wchar;
} form;
struct {
+ const char *format;
+ } date;
+ struct {
+ bool always_active;
+ const char *left1_label;
+ const char *left2_label;
+ const char *left3_label;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -323,8 +389,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -343,8 +410,25 @@ 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.
+dialog subtitle.
.It Fa conf.clear
hide the dialog at exit.
.It Fa conf.get_height
@@ -362,31 +446,35 @@ draw shadow.
.It Fa conf.sleep
wait before to return, the value is in seconds.
.It Fa conf.title
-title at the top dialog side.
+dialog title.
.It Fa conf.y
-vertical position, 0 is top screen size, can be
+dialog vertical position, 0 is top screen, can be
.Dv BSDDIALOG_CENTER .
.It Fa conf.x
-horizontal position, 0 is left screen side, can be
+dialog horizontal position, 0 is left screen, can be
.Dv BSDDIALOG_CENTER .
.El
.Pp
.Bl -column -compact
.It Fa conf.key.enable_esc
-enables
+enable
.Dv ESC
key to close the dialog.
.It Fa conf.key.f1_file
-file to open if F1 is pressed.
+open a file in a textbox if F1 is pressed.
.It Fa conf.key.f1_message
-message to display if F1 is pressed.
+build a msgbox with message if F1 is pressed.
.El
.Pp
-.Fa conf.text.highlight
-enables highlights for
-.Fa text ,
-properly the following sequences are considered escapes:
.Bl -column -compact
+.It Fa conf.text.cols_per_row
+Try to set the number of columns for a row of
+.Fa text
+with autosizing, default
+.Dv 10 .
+.It Fa conf.text.escape
+enable escapes in
+.Fa text :
.It Dq \eZ0
black.
.It Dq \eZ1
@@ -403,25 +491,55 @@ magenta.
cyan.
.It Dq \eZ7
white.
-.It Dq \eZr
-reverse colors between foreground and background.
-.It Dq \eZR
-disable reverse.
.It Dq \eZb
bold.
.It Dq \eZB
disable bold.
+.It Dq \eZd
+Half bright.
+.It Dq \eZD
+disable half bright.
+.It Dq \eZk
+Blink.
+.It Dq \eZK
+disable blinking.
+.It Dq \eZr
+reverse foreground and background.
+.It Dq \eZR
+disable reverse.
+.It Dq \eZs
+Highlight.
+.It Dq \eZS
+disable highlighting.
.It Dq \eZu
underline.
.It Dq \eZU
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, avoiding focus switch between buttons and input fields or
+input boxes in
+.Fn bsddialog_form ,
+.Fn bsddialog_datebox ,
+.Fn bsddialog_calendar
+and
+.Fn bsddialog_timebox .
+.It Fa conf.button.left1_label
+add a button with the specified label.
+.It Fa conf.button.left2_label
+add a button with the specified label.
+.It Fa conf.button.left3_label
+add a button with the specified label.
.It Fa conf.button.without_ok
disable OK button.
.It Fa conf.button.ok_label
@@ -440,9 +558,11 @@ on startup focus on the Cancel button.
add Help button.
.It Fa conf.button.help_label
set a label for Help button.
-.It Fa conf.button.generic1_label
+.It Fa conf.button.right1_label
+add a button with the specified label.
+.It Fa conf.button.right2_label
add a button with the specified label.
-.It Fa conf.button.generic2_label
+.It Fa conf.button.right3_label
add a button with the specified label.
.It Fa conf.button.default_label
focus on the button with the specified label.
@@ -458,148 +578,58 @@ to true,
and
.Fa conf.x
to
-.Dv BSDDIALOG_CENTER .
-.Pp
-.Fn bsddialog_infobox
-builds a dialog without buttons and returns instantly.
-.Fn bsddialog_msgbox
-builds a dialog with OK button.
-.Fn bsddialog_yesno
-provides a dialog for a
-.Dq Yes-No Question ,
-the labels on buttons are Yes and No.
-.Pp
-.Fn bsddialog_pause
-builds a dialog waiting until the timeout in
-.Fa seconds
-expires or a button is pressed.
+.Dv BSDDIALOG_CENTER ,
+.Fa conf.text.cols_per_row
+to
+.Dv 10 .
.Pp
-.Fn bsddialog_datebox
-builds a dialog to select a date,
-.Fa yy ,
-.Fa mm ,
+.Fn bsddialog_calendar
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fa dd
+.Fa day
are default values on startup, selected date at exit.
-.Fn bsddialog_timebox
-builds a dialog to choose a time,
-.Fa hh ,
-.Fa mm ,
-and
-.Fa ss
-are default values on startup, selected time at exit.
-.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu
-and
-.Fn bsddialog_radiolist
-build dialogs to select some item from a list via the SPACE key, an item is
-defined like:
-.Pp
-.Bd -literal -offset indent -compact
-struct bsddialog_menuitem {
- const char *prefix;
- bool on;
- unsigned int depth;
- const char *name;
- const char *desc;
- const char *bottomdesc;
-};
-.Ed
-.Pp
-.Fa prefix ,
-.Fa name
-and
-.Fa desc
-are strings to describe the item and are printed on its row,
-.Fa bottomdesc
-is printed on the bottom side of the screen,
-.Fa depth
-is a margin between the
-.Fa prefix
-and
-.Fa name
-useful to implement a
-.Dq treeview,
-.Fa on
-is set to
-.Dv true
-if the item is selected,
-.Dv false
-otherwise.
-.Fa items
-is an array of items of
-.Fa nitem
-elements,
-.Fa menurows
-specifies the graphical fixed height of the list, if
-.Fa cols
-is set to
-.Dv BSDDIALOG_AUTOSIZE
-.Fa menurows
-specifies a maximum value.
-Finally, if not
-.Dv NULL ,
-.Fa focusitem
-specifies the default item on startup and the last focused item at exit, could
-be a negative value if no item is focused.
.Pp
-.Fn bsddialog_mixedlist
-builds a dialog with collections of checklists, radiolists and separators.
-A collection is a set defined like:
+.Fn bsddialog_checklist
+builds dialogs to select some item from a list via the SPACE key, can be
+customized by
+.Fa conf.menu.* .
+See
+.Fn bsddialog_menu .
.Pp
-.Bd -literal -offset indent -compact
-enum bsddialog_grouptype {
- BSDDIALOG_CHECKLIST,
- BSDDIALOG_RADIOLIST,
- BSDDIALOG_SEPARATOR,
-};
-
-struct bsddialog_menugroup {
- enum bsddialog_grouptype type;
- unsigned int nitems;
- struct bsddialog_menuitem *items;
-};
-.Ed
-.Pp
-.Fa groups
-is an array of sets of
-.Fa ngroups
-elements.
-.Fa menurows
-is the graphical height size for the list.
-If not
-.Dv NULL ,
-.Fa focuslist
-and
-.Fa focusitem
-specify the default item on startup and the last focused item at exit, could be
-a negative value if no item is focused.
-.Pp
-.Fn bsddialog_checklist ,
-.Fn bsddialog_menu ,
-.Fn bsddialog_mixedlist
+.Fn bsddialog_datebox
+builds a dialog to select a date.
+.Fa year ,
+.Fa month ,
and
-.Fn bsddialog_radiolist
-can be costomizated by:
+.Fa day
+are default values on startup, selected date at exit.
+The function can be customized by:
.Bl -column -compact
-.It Fa conf.menu.align_left
-aligns items to left, default center.
-.It Fa conf.menu.no_desc
-hide description.
-.It Fa conf.menu.no_name
-hide names.
-.It Fa conf.menu.on_without_ok
-set items
-.Fa on
-also if the OK button is not pressed.
-.It Fa conf.menu.shortcut_buttons
-enable shortcut keys on buttons, default on items.
+.It Fa conf.date.format
+date format user interface, possible values:
+.Dq d/m/y ,
+.Dq m/d/y ,
+.Dq y/m/d .
.El
.Pp
.Fn bsddialog_form
-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 input strings.
+.Fa formrows
+is the graphical height for the items inside the dialog,
+.Dv 0
+for autosizing.
+If not
+.Dv NULL
+.Fa focusitem
+is the default item index on startup and the last focused item at exit, a
+negative value if no item is focused.
+An item is defined like:
.Pp
.Bd -literal -offset indent -compact
struct bsddialog_formitem {
@@ -621,7 +651,7 @@ struct bsddialog_formitem {
.Ed
.Pp
.Fa label
-describes the request, it is printed at the position
+is a string to describe the request at the position
.Fa ylabel
and
.Fa xlabel .
@@ -632,77 +662,142 @@ 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.
-If the OK button is pressed
+is the default field value.
+If no error occurs
.Fa value
-is the allocated memory with the current field string.
+is the allocated memory with the current field string at exit, its size depends
+on the current locale.
.Fa flags
-is an OR value to set the
-.Dv BSDDIALOG_FIELDHIDDEN
-and
-.Dv BSDDIALOG_FIELDREADONLY
-flags for the field.
+is an OR value to set the field:
+.Dv BSDDIALOG_FIELDHIDDEN ,
+.Dv BSDDIALOG_FIELDREADONLY ,
+.Dv BSDDIALOG_FIELDNOCOLOR ,
+.Dv BSDDIALOG_FIELDCURSOREND ,
+.Dv BSDDIALOG_FIELDEXTEND ,
+.Dv BSDDIALOG_FIELDSINGLEBYTE .
.Fa bottomdesc
-is printed 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 .
+is printed at bottom screen if the item is focused.
.Pp
.Fn bsddialog_form
can be customized by:
.Bl -column -compact
-.It Fa conf.form.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.value_without_ok
-allocate memory and set
+.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
-also if the OK button is not pressed.
+is a
+.Em wchar_t*
+string.
.El
.Pp
.Fn bsddialog_gauge
-builds a dialog with a bar to shows
-.Fa perc ,
-if the file descriptor
+builds a dialog with a bar to show
+.Fa perc .
+If the file descriptor
.Fa fd
is greater or equal to 0 the dialog waits to read
-.Fa separator
+.Fa sep
from it, then the first string replaces
.Fa perc
and the following strings replace
.Fa text
until the next
-.Fa separator ,
+.Fa sep ,
the loop ends reading
-.Dv EOF .
+.Fa end .
+.Pp
+.Fn bsddialog_infobox
+builds a dialog without buttons and returns instantly.
+.Pp
+.Fn bsddialog_menu
+builds a dialog to select an item from a list via SPACE and ENTER.
+An item is defined like:
+.Pp
+.Bd -literal -offset indent -compact
+struct bsddialog_menuitem {
+ const char *prefix;
+ bool on;
+ unsigned int depth;
+ const char *name;
+ const char *desc;
+ const char *bottomdesc;
+};
+.Ed
+.Pp
+.Fa prefix ,
+.Fa name
+and
+.Fa desc
+are printed at the item row.
+.Fa bottomdesc
+is printed at bottom screen if the item is focused.
+.Fa depth
+is a margin between
+.Fa prefix
+and
+.Fa name .
+At exit
+.Fa on
+is set to
+.Dv true
+if the item is selected,
+.Dv false
+otherwise.
+.Fa items
+is an array of items of
+.Fa nitem
+elements.
+.Fa menurows
+is the graphical height of the list inside the dialog, if
+.Fa cols
+is
+.Dv BSDDIALOG_AUTOSIZE
+.Fa menurows
+specifies a maximum value.
+if not
+.Dv NULL
+.Fa focusitem
+is the default item index on startup and the last focused item at exit, a
+negative value if no item is focused.
+.Pp
+.Fn bsddialog_checklist ,
+.Fn bsddialog_menu ,
+.Fn bsddialog_mixedlist
+and
+.Fn bsddialog_radiolist
+can be customized by:
+.Bl -column -compact
+.It Fa conf.menu.align_left
+align items to left, default center.
+.It Fa conf.menu.no_desc
+hide items description.
+.It Fa conf.menu.no_name
+hide items name, mutually exclusive with
+.Fa conf.menu.no_desc .
+.It Fa conf.menu.shortcut_buttons
+enable shortcut keys on buttons, default on items.
+.El
.Pp
.Fn bsddialog_mixedgauge
-draws a main bar with the
+builds a dialog with a main bar with the
.Fa mainperc
percentage and
.Fa nminibars
each one with a
.Fa minilabel
and a
+.Fa miniperc .
.Fa miniperc
-with a value between 0 and 100 or
+can be: a positive value to print a bar with a percentace, a negative constant
.Dv BSDDIALOG_MG_SUCCEEDED ,
.Dv BSDDIALOG_MG_FAILED ,
.Dv BSDDIALOG_MG_PASSED ,
@@ -711,11 +806,69 @@ with a value between 0 and 100 or
.Dv BSDDIALOG_MG_DONE ,
.Dv BSDDIALOG_MG_SKIPPED ,
.Dv BSDDIALOG_MG_INPROGRESS ,
-.Dv BSDDIALOG_MG_BLANK ,
-.Dv BSDDIALOG_MG_NA
-or
+.Dv BSDDIALOG_MG_BLANK
+to hide
+.Fa miniperc ,
+.Dv BSDDIALOG_MG_NA ,
.Dv BSDDIALOG_MG_PENDING
-to print a descriptive string.
+to print a descriptive string, otherwise
+.Dq "UNKNOWN"
+is printed.
+.Pp
+.Fn bsddialog_mixedlist
+builds a dialog with collections of checklists, radiolists and separators.
+A collection is a set defined like:
+.Pp
+.Bd -literal -offset indent -compact
+enum bsddialog_menutype {
+ BSDDIALOG_CHECKLIST,
+ BSDDIALOG_RADIOLIST,
+ BSDDIALOG_SEPARATOR,
+};
+
+struct bsddialog_menugroup {
+ enum bsddialog_menutype type;
+ unsigned int nitems;
+ struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
+};
+.Ed
+.Pp
+.Fa groups
+is an array of sets of
+.Fa ngroups
+elements.
+.Fa menurows
+is the graphical height size for the list.
+If not
+.Dv NULL ,
+.Fa focuslist
+and
+.Fa focusitem
+specify the default item on startup and the last focused item at exit, could be
+a negative value if no item is focused.
+The dialog can be customized by
+.Fa conf.menu.* ,
+see
+.Fn bsddialog_menu .
+.Pp
+.Fn bsddialog_msgbox
+builds a dialog with OK button.
+.Pp
+.Fn bsddialog_pause
+builds a dialog waiting until the timeout in
+.Fa seconds
+expires or a button is pressed.
+At exit
+.Fa seconds
+is set like remaining time.
+.Pp
+.Fn bsddialog_radiolist
+builds dialogs to select at most an item from a list via the SPACE key, can be
+customized by
+.Fa conf.menu.* .
+See
+.Fn bsddialog_menu .
.Pp
.Fn bsddialog_rangebox
to select a value between
@@ -724,17 +877,49 @@ and
.Fa max .
.Fa value
is the default value on startup and the selected value at exit.
-The current value is printed inside a bar, the keys UP, DOWN, HOME, END, PAGEUP
-and PAGEDOWN can change it.
+The current value is printed inside a bar.
.Pp
.Fn bsddialog_textbox
opens and prints
-.Fa file
-in a dialog, the UP, DOWN, HOME, END, PAGEUP and PAGEDOWN keys are availble to
-navigate the file.
-OK button is renamed EXIT.
+.Fa file .
+TAB key changes button.
+Extra keys 0, h, l, k, j are available to navigate the text.
+.Dq OK
+button is renamed
+.Dq EXIT .
+.Pp
+.Fn bsddialog_timebox
+builds a dialog to choose a time.
+.Fa hh ,
+.Fa mm ,
+and
+.Fa ss
+are default values on startup, selected time at exit.
+.Pp
+.Fn bsddialog_yesno
+provides a dialog for a
+.Dq Yes-No Question ,
+the labels on buttons are
+.Dq Yes
+and
+.Dq No .
+.Ss Keys
+.Bl -tag -width Ds
+.It Ctrl-l
+Redraw the dialog.
+.It F1
+Refer to
+.Fa conf.key.f1_file
+and
+.Fa conf.key.f1_message .
+.It SPACE
+Select menu item.
+.It UP DOWN LEFT RIGHT - + HOME END PAGEUP PAGEDOWN Ctrl-p Ctrl-n TAB
+Navigate elements and set value, depending on the dialog.
+.El
.Ss Theme
-The graphical properties are global to the library, they are represented by
+The graphical properties are global to the library.
+They are represented by
.Fa struct bsddialog_theme
and can be customized at runtime via the
.In bsddialog_theme.h
@@ -747,8 +932,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -760,56 +945,56 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
- int delimcolor;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
.Ed
.Pp
A member with the
.Dq f_
-prefix refers to an element with focus.
+refers to focus when an element can be in selected or not selected state.
.Pp
-.Fn bsddialog_get_theme
-sets
-.Fa theme
-like the current theme.
-.Pp
-A color can be set by the value returned by
-.Fn bsddialog_color ,
-Possible values for
-.Fa background
-and
-.Fa foreground
-are:
+.Fn bsddialog_color
+generates and returns a color to set a
+.Fa struct bsddialog_theme
+color member.
+An
+.Fa enum bsddialog_color
+can be:
.Dv BSDDIALOG_BLACK ,
.Dv BSDDIALOG_RED ,
.Dv BSDDIALOG_GREEN ,
@@ -817,29 +1002,51 @@ are:
.Dv BSDDIALOG_BLUE ,
.Dv BSDDIALOG_MAGENTA ,
.Dv BSDDIALOG_CYAN ,
-and
-.Dv BSDDIALOG_WHITE ,
+.Dv BSDDIALOG_WHITE .
.Fa flags
-specifies OR-flags, possible values:
+is an OR value:
+.Dv BSDDIALOG_BLINK ,
.Dv BSDDIALOG_BOLD ,
-.Dv BSDDIALOG_REVERSE
-and
+.Dv BSDDIALOG_HALFBRIGHT ,
+.Dv BSDDIALOG_HIGHLIGHT ,
+.Dv BSDDIALOG_REVERSE ,
.Dv BSDDIALOG_UNDERLINE .
.Pp
+.Fn bsddialog_color_attrs
+sets, if not NULL,
+.Fa foreground ,
+.Fa background ,
+.Fa flags ,
+like the properties of
+.Fa color ,
+see
+.Fn bsddialog_color .
+.Pp
+.Fn bsddialog_get_theme
+sets
+.Fa theme
+like the current runtime theme.
+.Pp
+.Fn bsddialog_hascolors
+returns
+.Dv true
+if the terminal provides colors,
+.Dv false
+otherwise.
+.Pp
.Fn bsddialog_set_theme
sets
.Fa theme
-like current theme, the changes takes effect only for dialogs built after the
-call.
+like current runtime theme.
+Changes take effect only for dialogs built after
+the call.
.Pp
-The library provides predefined themes:
+.Fn bsddialog_set_default_theme
+sets a library default theme like current theme, possible values:
.Dv BSDDIALOG_THEME_BLACKWHITE ,
-.Dv BSDDIALOG_THEME_BSDDIALOG ,
-.Dv BSDDIALOG_THEME_FLAT
-and
-.Dv BSDDIALOG_THEME_DIALOG ,
-they can be set via
-.Fn bsddialog_set_default_theme .
+.Dv BSDDIALOG_THEME_FLAT ,
+.Dv BSDDIALOG_THEME_3D .
+Changes take effect only for dialogs built after the call.
.Sh RETURN VALUES
The functions return the value
.Dv BSDDIALOG_ERROR
@@ -850,9 +1057,12 @@ returned:
.Dv BSDDIALOG_CANCEL ,
.Dv BSDDIALOG_HELP ,
.Dv BSDDIALOG_EXTRA ,
-.Dv BSDDIALOG_GENERIC1
-or
-.Dv BSDDIALOG_GENERIC2 .
+.Dv BSDDIALOG_LEFT1 ,
+.Dv BSDDIALOG_LEFT2 ,
+.Dv BSDDIALOG_LEFT3 ,
+.Dv BSDDIALOG_RIGHT1 ,
+.Dv BSDDIALOG_RIGHT2 ,
+.Dv BSDDIALOG_RIGHT3 .
.Dv BSDDIALOG_YES
and
.Dv BSDDIALOG_NO
@@ -894,10 +1104,11 @@ case BSDDIALOG_YES:
printf("Yes\\n");
break;
case BSDDIALOG_NO
- printf("NO\\n");
+ printf("No\\n");
break;
case BSDDIALOG_ERROR:
printf("Error: %s\\n", bsddialog_geterror());
+ break;
}
.Ed
.Pp
@@ -938,7 +1149,7 @@ struct bsddialog_menuitem check[2] = {
struct bsddialog_menuitem sep[1] = {
{ "3", true, 0, "Radiolist", "(desc)", "" }
};
-struct bsddialog_menuitem radio[5] = {
+struct bsddialog_menuitem radio[2] = {
{ "4", true, 0, "Name 1", "Desc 1", "Radio Bottom Desc 1" },
{ "5", false, 0, "Name 2", "Desc 2", "Radio Bottom Desc 2" }
};
@@ -975,8 +1186,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 +1195,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/contrib/bsddialog/lib/bsddialog.h b/contrib/bsddialog/lib/bsddialog.h
index 37f9899141c0..fd0e2bc02580 100644
--- a/contrib/bsddialog/lib/bsddialog.h
+++ b/contrib/bsddialog/lib/bsddialog.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,9 +30,9 @@
#include <stdbool.h>
-#define LIBBSDDIALOG_VERSION "0.2"
+#define LIBBSDDIALOG_VERSION "1.0.4"
-/* Exit status */
+/* Return values */
#define BSDDIALOG_ERROR -1
#define BSDDIALOG_OK 0
#define BSDDIALOG_YES BSDDIALOG_OK
@@ -42,8 +42,12 @@
#define BSDDIALOG_EXTRA 3
#define BSDDIALOG_TIMEOUT 4
#define BSDDIALOG_ESC 5
-#define BSDDIALOG_GENERIC1 6
-#define BSDDIALOG_GENERIC2 7
+#define BSDDIALOG_LEFT1 6
+#define BSDDIALOG_LEFT2 7
+#define BSDDIALOG_LEFT3 8
+#define BSDDIALOG_RIGHT1 9
+#define BSDDIALOG_RIGHT2 10
+#define BSDDIALOG_RIGHT3 11
/* Size and position */
#define BSDDIALOG_FULLSCREEN -1
@@ -64,13 +68,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,22 +97,29 @@ struct bsddialog_conf {
const char *f1_message;
} key;
struct {
- bool highlight;
+ unsigned int cols_per_row;
+ bool escape;
unsigned int tablen;
} text;
struct {
bool align_left;
bool no_desc;
bool no_name;
- bool on_without_ok;
bool shortcut_buttons;
} menu;
struct {
- bool enable_wchar;
- int securech;
- bool value_without_ok;
+ char securech;
+ char *securembch;
+ bool value_wchar;
} form;
struct {
+ const char *format;
+ } date;
+ struct {
+ bool always_active;
+ const char *left1_label;
+ const char *left2_label;
+ const char *left3_label;
bool without_ok;
const char *ok_label;
bool with_extra;
@@ -112,8 +129,9 @@ struct bsddialog_conf {
bool default_cancel;
bool with_help;
const char *help_label;
- const char *generic1_label;
- const char *generic2_label;
+ const char *right1_label;
+ const char *right2_label;
+ const char *right3_label;
const char *default_label;
} button;
};
@@ -127,16 +145,17 @@ struct bsddialog_menuitem {
const char *bottomdesc;
};
-enum bsddialog_grouptype {
+enum bsddialog_menutype {
BSDDIALOG_CHECKLIST,
BSDDIALOG_RADIOLIST,
BSDDIALOG_SEPARATOR,
};
struct bsddialog_menugroup {
- enum bsddialog_grouptype type;
+ enum bsddialog_menutype type;
unsigned int nitems;
struct bsddialog_menuitem *items;
+ unsigned int min_on; /* unused for now */
};
struct bsddialog_formitem {
@@ -156,30 +175,37 @@ struct bsddialog_formitem {
};
int bsddialog_init(void);
+int bsddialog_init_notheme(void);
+bool bsddialog_inmode(void);
int bsddialog_end(void);
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle);
int bsddialog_initconf(struct bsddialog_conf *conf);
-int bsddialog_clearterminal(void);
+void bsddialog_clear(unsigned int y);
+void bsddialog_refresh(void);
const char *bsddialog_geterror(void);
/* Dialogs */
int
+bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
+
+int
bsddialog_checklist(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int menurows, unsigned int nitems,
struct bsddialog_menuitem *items, int *focusitem);
int
bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd);
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day);
int
bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items);
+ struct bsddialog_formitem *items, int *focusitem);
int
bsddialog_gauge(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int perc, int fd, const char *sep);
+ int cols, unsigned int perc, int fd, const char *sep, const char *end);
int
bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
@@ -206,7 +232,7 @@ bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int
bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int seconds);
+ int cols, unsigned int *seconds);
int
bsddialog_radiolist(struct bsddialog_conf *conf, const char *text, int rows,
diff --git a/contrib/bsddialog/lib/bsddialog_progressview.h b/contrib/bsddialog/lib/bsddialog_progressview.h
index 0cd9368a1040..5203b798bb07 100644
--- a/contrib/bsddialog/lib/bsddialog_progressview.h
+++ b/contrib/bsddialog/lib/bsddialog_progressview.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,14 +36,14 @@
extern bool bsddialog_interruptprogview;
extern bool bsddialog_abortprogview;
-extern int bsddialog_total_progview;
+extern long long int bsddialog_total_progview;
struct bsddialog_fileminibar {
const char *path;
const char *label;
int status; /* next if BSDDIALOG_MG_DONE or BSDDIALOG_MG_FAILED */
- long long size;
- long long read;
+ long long int size;
+ long long int read;
};
struct bsddialog_progviewconf {
diff --git a/contrib/bsddialog/lib/bsddialog_theme.h b/contrib/bsddialog/lib/bsddialog_theme.h
index 89381cfe28d5..2071896b61f0 100644
--- a/contrib/bsddialog/lib/bsddialog_theme.h
+++ b/contrib/bsddialog/lib/bsddialog_theme.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,9 +29,12 @@
#define _LIBBSDDIALOG_THEME_H_
/* color flags */
-#define BSDDIALOG_BOLD 1U
-#define BSDDIALOG_REVERSE 2U
-#define BSDDIALOG_UNDERLINE 4U
+#define BSDDIALOG_BLINK 1U
+#define BSDDIALOG_BOLD 2U
+#define BSDDIALOG_HALFBRIGHT 4U
+#define BSDDIALOG_HIGHLIGHT 8U
+#define BSDDIALOG_REVERSE 16U
+#define BSDDIALOG_UNDERLINE 32U
struct bsddialog_theme {
struct {
@@ -39,8 +42,8 @@ struct bsddialog_theme {
} screen;
struct {
int color;
- unsigned int h;
- unsigned int w;
+ unsigned int y;
+ unsigned int x;
} shadow;
struct {
int color;
@@ -52,44 +55,48 @@ struct bsddialog_theme {
int arrowcolor;
} dialog;
struct {
+ int f_prefixcolor;
+ int prefixcolor;
int f_selectorcolor;
int selectorcolor;
int f_namecolor;
int namecolor;
int f_desccolor;
int desccolor;
- int namesepcolor;
- int descsepcolor;
int f_shortcutcolor;
int shortcutcolor;
+ int bottomdesccolor;
+ int sepnamecolor;
+ int sepdesccolor;
} menu;
struct {
int f_fieldcolor;
int fieldcolor;
int readonlycolor;
+ int bottomdesccolor;
} form;
struct {
int f_color;
int color;
} bar;
struct {
- unsigned int hmargin;
- int leftdelim;
- int rightdelim;
- int delimcolor;
+ unsigned int minmargin;
+ unsigned int maxmargin;
+ char leftdelim;
+ char rightdelim;
int f_delimcolor;
- int color;
+ int delimcolor;
int f_color;
- int shortcutcolor;
+ int color;
int f_shortcutcolor;
+ int shortcutcolor;
} button;
};
enum bsddialog_default_theme {
+ BSDDIALOG_THEME_3D,
BSDDIALOG_THEME_BLACKWHITE,
- BSDDIALOG_THEME_BSDDIALOG,
- BSDDIALOG_THEME_FLAT,
- BSDDIALOG_THEME_DIALOG
+ BSDDIALOG_THEME_FLAT
};
enum bsddialog_color {
@@ -106,7 +113,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/contrib/bsddialog/lib/datebox.c b/contrib/bsddialog/lib/datebox.c
new file mode 100644
index 000000000000..ee955471799e
--- /dev/null
+++ b/contrib/bsddialog/lib/datebox.c
@@ -0,0 +1,746 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2024 Alfonso Sabato Siciliano
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <curses.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bsddialog.h"
+#include "bsddialog_theme.h"
+#include "lib_util.h"
+
+/* Calendar */
+#define MIN_YEAR_CAL 0
+#define MAX_YEAR_CAL 999999999
+#define MINHCAL 13
+#define MINWCAL 36 /* 34 calendar, 1 + 1 margins */
+/* Datebox */
+#define MIN_YEAR_DATE 0
+#define MAX_YEAR_DATE 9999
+#define MINWDATE 23 /* 3 windows and their borders */
+
+#define ISLEAP(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+
+static int minyear;
+static int maxyear;
+
+static const char *m[12] = {
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December"
+};
+
+enum operation {
+ UP_DAY,
+ DOWN_DAY,
+ LEFT_DAY,
+ RIGHT_DAY,
+ UP_MONTH,
+ DOWN_MONTH,
+ UP_YEAR,
+ DOWN_YEAR
+};
+
+/* private datebox item */
+struct dateitem {
+ enum operation up;
+ enum operation down;
+ WINDOW *win;
+ int width;
+ const char *fmt;
+ int *value;
+};
+
+static int month_days(int yy, int mm)
+{
+ int days;
+
+ if (mm == 2)
+ days = ISLEAP(yy) ? 29 : 28;
+ else if (mm == 4 || mm == 6 || mm == 9 || mm == 11)
+ days = 30;
+ else
+ days = 31;
+
+ return (days);
+}
+
+static int week_day(int yy, int mm, int dd)
+{
+ int wd;
+
+ dd += mm < 3 ? yy-- : yy - 2;
+ wd = 23*mm/9 + dd + 4 + yy/4 - yy/100 + yy/400;
+ wd %= 7;
+
+ return (wd);
+}
+
+static void
+init_date(unsigned int *year, unsigned int *month, unsigned int *day, int *yy,
+ int *mm, int *dd)
+{
+ *yy = MIN(*year, (unsigned int)maxyear);
+ if (*yy < minyear)
+ *yy = minyear;
+ *mm = MIN(*month, 12);
+ if (*mm == 0)
+ *mm = 1;
+ *dd = (*day == 0) ? 1 : *day;
+ if (*dd > month_days(*yy, *mm))
+ *dd = month_days(*yy, *mm);
+}
+
+static void datectl(enum operation op, int *yy, int *mm, int *dd)
+{
+ int ndays;
+
+ ndays = month_days(*yy, *mm);
+
+ switch (op) {
+ case UP_DAY:
+ if (*dd > 7)
+ *dd -= 7;
+ else {
+ if (*mm == 1) {
+ *yy -= 1;
+ *mm = 12;
+ } else
+ *mm -= 1;
+ ndays = month_days(*yy, *mm);
+ *dd = ndays - abs(7 - *dd);
+ }
+ break;
+ case DOWN_DAY:
+ if (*dd + 7 < ndays)
+ *dd += 7;
+ else {
+ if (*mm == 12) {
+ *yy += 1;
+ *mm = 1;
+ } else
+ *mm += 1;
+ *dd = *dd + 7 - ndays;
+ }
+ break;
+ case LEFT_DAY:
+ if (*dd > 1)
+ *dd -= 1;
+ else {
+ if (*mm == 1) {
+ *yy -= 1;
+ *mm = 12;
+ } else
+ *mm -= 1;
+ *dd = month_days(*yy, *mm);
+ }
+ break;
+ case RIGHT_DAY:
+ if (*dd < ndays)
+ *dd += 1;
+ else {
+ if (*mm == 12) {
+ *yy += 1;
+ *mm = 1;
+ } else
+ *mm += 1;
+ *dd = 1;
+ }
+ break;
+ case UP_MONTH:
+ if (*mm == 1) {
+ *mm = 12;
+ *yy -= 1;
+ } else
+ *mm -= 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case DOWN_MONTH:
+ if (*mm == 12) {
+ *mm = 1;
+ *yy += 1;
+ } else
+ *mm += 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case UP_YEAR:
+ *yy -= 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ case DOWN_YEAR:
+ *yy += 1;
+ ndays = month_days(*yy, *mm);
+ if (*dd > ndays)
+ *dd = ndays;
+ break;
+ }
+
+ if (*yy < minyear) {
+ *yy = minyear;
+ *mm = 1;
+ *dd = 1;
+ }
+ if (*yy > maxyear) {
+ *yy = maxyear;
+ *mm = 12;
+ *dd = 31;
+ }
+}
+
+static void
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev,
+ const char *fmt, int value, bool focus)
+{
+ int h, l, w;
+
+ getmaxyx(win, h, w);
+ draw_borders(conf, win, elev);
+ if (focus) {
+ l = 2 + w%2;
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, w/2 - l/2, UARROW(conf), l);
+ mvwhline(win, h-1, w/2 - l/2, DARROW(conf), l);
+ wattroff(win, t.dialog.arrowcolor);
+ }
+
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ if (strchr(fmt, 's') != NULL)
+ mvwprintw(win, 1, 1, fmt, m[value - 1]);
+ else
+ mvwprintw(win, 1, 1, fmt, value);
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
+
+ wnoutrefresh(win);
+}
+
+static void
+print_calendar(struct bsddialog_conf *conf, WINDOW *win, int yy, int mm, int dd,
+ bool active)
+{
+ int ndays, i, y, x, wd, h, w;
+
+ getmaxyx(win, h, w);
+ wclear(win);
+ draw_borders(conf, win, RAISED);
+ if (active) {
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, 15, UARROW(conf), 4);
+ mvwhline(win, h-1, 15, DARROW(conf), 4);
+ mvwvline(win, 3, 0, LARROW(conf), 3);
+ mvwvline(win, 3, w-1, RARROW(conf), 3);
+ wattroff(win, t.dialog.arrowcolor);
+ }
+
+ mvwaddstr(win, 1, 5, "Sun Mon Tue Wed Thu Fri Sat");
+ ndays = month_days(yy, mm);
+ y = 2;
+ wd = week_day(yy, mm, 1);
+ for (i = 1; i <= ndays; i++) {
+ x = 5 + (4 * wd); /* x has to be 6 with week number */
+ wmove(win, y, x);
+ mvwprintw(win, y, x, "%2d", i);
+ if (i == dd) {
+ wattron(win, t.menu.f_namecolor);
+ mvwprintw(win, y, x, "%2d", i);
+ wattroff(win, t.menu.f_namecolor);
+ }
+ wd++;
+ if (wd > 6) {
+ wd = 0;
+ y++;
+ }
+ }
+
+ wnoutrefresh(win);
+}
+
+static int
+calendar_redraw(struct dialog *d, WINDOW *yy_win, WINDOW *mm_win,
+ WINDOW *dd_win)
+{
+ int ycal, xcal;
+
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, MINHCAL, MINWCAL, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, MINHCAL + HBUTTONS);
+
+ ycal = d->y + d->h - 15;
+ xcal = d->x + d->w/2 - 17;
+ mvwaddstr(d->widget, d->h - 16, d->w/2 - 17, "Month");
+ update_box(d->conf, mm_win, ycal, xcal, 3, 17, RAISED);
+ mvwaddstr(d->widget, d->h - 16, d->w/2, "Year");
+ update_box(d->conf, yy_win, ycal, xcal + 17, 3, 17, RAISED);
+ update_box(d->conf, dd_win, ycal + 3, xcal, 9, 34, RAISED);
+ wnoutrefresh(d->widget);
+
+ return (0);
+}
+
+int
+bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day)
+{
+ bool loop, focusbuttons;
+ int retval, sel, yy, mm, dd;
+ wint_t input;
+ WINDOW *yy_win, *mm_win, *dd_win;
+ struct dialog d;
+
+ CHECK_PTR(year);
+ CHECK_PTR(month);
+ CHECK_PTR(day);
+ minyear = MIN_YEAR_CAL;
+ maxyear = MAX_YEAR_CAL;
+ init_date(year, month, day, &yy, &mm, &dd);
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if ((yy_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for yy");
+ wbkgd(yy_win, t.dialog.color);
+ if ((mm_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for mm");
+ wbkgd(mm_win, t.dialog.color);
+ if ((dd_win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW for dd");
+ wbkgd(dd_win, t.dialog.color);
+ if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+
+ sel = -1;
+ loop = focusbuttons = true;
+ while (loop) {
+ drawsquare(conf, mm_win, RAISED, "%15s", mm, sel == 0);
+ drawsquare(conf, yy_win, RAISED, "%15d", yy, sel == 1);
+ print_calendar(conf, dd_win, yy, mm, dd, sel == 2);
+ doupdate();
+
+ if (get_wch(&input) == ERR)
+ continue;
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ break;
+ case 27: /* Esc */
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
+ break;
+ case '\t': /* TAB */
+ if (focusbuttons) {
+ d.bs.curr++;
+ if (d.bs.curr >= (int)d.bs.nbuttons) {
+ focusbuttons = false;
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel++;
+ if (sel > 2) {
+ focusbuttons = true;
+ sel = -1;
+ d.bs.curr = 0;
+ }
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
+ if (focusbuttons) {
+ d.bs.curr++;
+ if (d.bs.curr >= (int)d.bs.nbuttons) {
+ focusbuttons = false;
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else if (sel == 2) {
+ datectl(RIGHT_DAY, &yy, &mm, &dd);
+ } else { /* Month or Year*/
+ sel++;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('p'):
+ case KEY_LEFT:
+ if (focusbuttons) {
+ d.bs.curr--;
+ if (d.bs.curr < 0) {
+ focusbuttons = false;
+ sel = 2;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else if (sel == 2) {
+ datectl(LEFT_DAY, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ sel = 0;
+ } else { /* sel = 0, Month */
+ focusbuttons = true;
+ sel = -1;
+ d.bs.curr = 0;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_UP:
+ if (focusbuttons) {
+ sel = 2;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
+ } else if (sel == 0) {
+ datectl(UP_MONTH, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ datectl(UP_YEAR, &yy, &mm, &dd);
+ } else { /* sel = 2 */
+ datectl(UP_DAY, &yy, &mm, &dd);
+ }
+ break;
+ case KEY_DOWN:
+ if (focusbuttons) {
+ break;
+ } else if (sel == 0) {
+ datectl(DOWN_MONTH, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ datectl(DOWN_YEAR, &yy, &mm, &dd);
+ } else { /* sel = 2 */
+ datectl(DOWN_DAY, &yy, &mm, &dd);
+ }
+ break;
+ case '-':
+ if (focusbuttons) {
+ break;
+ } else if (sel == 0) {
+ datectl(UP_MONTH, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ datectl(UP_YEAR, &yy, &mm, &dd);
+ } else { /* sel = 2 */
+ datectl(LEFT_DAY, &yy, &mm, &dd);
+ }
+ break;
+ case '+':
+ if (focusbuttons) {
+ break;
+ } else if (sel == 0) {
+ datectl(DOWN_MONTH, &yy, &mm, &dd);
+ } else if (sel == 1) {
+ datectl(DOWN_YEAR, &yy, &mm, &dd);
+ } else { /* sel = 2 */
+ datectl(RIGHT_DAY, &yy, &mm, &dd);
+ }
+ break;
+ case KEY_HOME:
+ datectl(UP_MONTH, &yy, &mm, &dd);
+ break;
+ case KEY_END:
+ datectl(DOWN_MONTH, &yy, &mm, &dd);
+ break;
+ case KEY_PPAGE:
+ datectl(UP_YEAR, &yy, &mm, &dd);
+ break;
+ case KEY_NPAGE:
+ datectl(DOWN_YEAR, &yy, &mm, &dd);
+ break;
+ case KEY_F(1):
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
+ break;
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ default:
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ }
+ }
+
+ *year = yy;
+ *month = mm;
+ *day = dd;
+
+ delwin(yy_win);
+ delwin(mm_win);
+ delwin(dd_win);
+ end_dialog(&d);
+
+ return (retval);
+}
+
+static int datebox_redraw(struct dialog *d, struct dateitem *di)
+{
+ int y, x;
+
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, 3 /*windows*/, MINWDATE, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 3 /*windows*/ + HBUTTONS);
+
+ y = d->y + d->h - 6;
+ x = (d->x + d->w / 2) - 11;
+ update_box(d->conf, di[0].win, y, x, 3, di[0].width, LOWERED);
+ mvwaddch(d->widget, d->h - 5, x - d->x + di[0].width, '/');
+ x += di[0].width + 1;
+ update_box(d->conf, di[1].win, y, x , 3, di[1].width, LOWERED);
+ mvwaddch(d->widget, d->h - 5, x - d->x + di[1].width, '/');
+ x += di[1].width + 1;
+ update_box(d->conf, di[2].win, y, x, 3, di[2].width, LOWERED);
+ wnoutrefresh(d->widget);
+
+ return (0);
+}
+
+static int
+build_dateitem(const char *format, int *yy, int *mm, int *dd,
+ struct dateitem *dt)
+{
+ int i;
+ wchar_t *wformat;
+ struct dateitem init[3] = {
+ {UP_YEAR, DOWN_YEAR, NULL, 6, "%4d", yy},
+ {UP_MONTH, DOWN_MONTH, NULL, 11, "%9s", mm},
+ {LEFT_DAY, RIGHT_DAY, NULL, 4, "%02d", dd},
+ };
+
+ for (i = 0; i < 3; i++) {
+ if ((init[i].win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_FMTERROR("Cannot build WINDOW dateitem[%d]", i);
+ wbkgd(init[i].win, t.dialog.color);
+ }
+
+ if ((wformat = alloc_mbstows(CHECK_STR(format))) == NULL)
+ RETURN_ERROR("Cannot allocate conf.date.format in wchar_t*");
+ if (format == NULL || wcscmp(wformat, L"d/m/y") == 0) {
+ dt[0] = init[2];
+ dt[1] = init[1];
+ dt[2] = init[0];
+ } else if (wcscmp(wformat, L"m/d/y") == 0) {
+ dt[0] = init[1];
+ dt[1] = init[2];
+ dt[2] = init[0];
+ } else if (wcscmp(wformat, L"y/m/d") == 0) {
+ dt[0] = init[0];
+ dt[1] = init[1];
+ dt[2] = init[2];
+ } else
+ RETURN_FMTERROR("Invalid conf.date.format=\"%s\"", format);
+ free(wformat);
+
+ return (0);
+}
+
+int
+bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int *year, unsigned int *month, unsigned int *day)
+{
+ bool loop, focusbuttons;
+ int retval, i, sel, yy, mm, dd;
+ wint_t input;
+ struct dateitem di[3];
+ struct dialog d;
+
+ CHECK_PTR(year);
+ CHECK_PTR(month);
+ CHECK_PTR(day);
+ minyear = MIN_YEAR_DATE;
+ maxyear = MAX_YEAR_DATE;
+ init_date(year, month, day, &yy, &mm, &dd);
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ if (build_dateitem(conf->date.format, &yy, &mm, &dd, di) != 0)
+ return (BSDDIALOG_ERROR);
+ if (datebox_redraw(&d, di) != 0)
+ return (BSDDIALOG_ERROR);
+
+ sel = -1;
+ loop = focusbuttons = true;
+ while (loop) {
+ for (i = 0; i < 3; i++)
+ drawsquare(conf, di[i].win, LOWERED, di[i].fmt,
+ *di[i].value, sel == i);
+ doupdate();
+
+ if (get_wch(&input) == ERR)
+ continue;
+ switch(input) {
+ case KEY_ENTER:
+ case 10: /* Enter */
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ break;
+ case 27: /* Esc */
+ if (conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
+ loop = false;
+ }
+ break;
+ case '\t': /* TAB */
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
+ if (focusbuttons) {
+ d.bs.curr++;
+ focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
+ true : false;
+ if (focusbuttons == false) {
+ sel = 0;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel++;
+ focusbuttons = sel > 2 ? true : false;
+ if (focusbuttons) {
+ d.bs.curr = 0;
+ }
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case KEY_CTRL('p'):
+ case KEY_LEFT:
+ if (focusbuttons) {
+ d.bs.curr--;
+ focusbuttons = d.bs.curr < 0 ? false : true;
+ if (focusbuttons == false) {
+ sel = 2;
+ d.bs.curr = conf->button.always_active ?
+ 0 : -1;
+ }
+ } else {
+ sel--;
+ focusbuttons = sel < 0 ? true : false;
+ if (focusbuttons)
+ d.bs.curr = (int)d.bs.nbuttons - 1;
+ }
+ DRAW_BUTTONS(d);
+ break;
+ case '-':
+ if (focusbuttons == false)
+ datectl(di[sel].up, &yy, &mm, &dd);
+ break;
+ case KEY_UP:
+ if (focusbuttons) {
+ sel = 0;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
+ } else {
+ datectl(di[sel].up, &yy, &mm, &dd);
+ }
+ break;
+ case '+':
+ case KEY_DOWN:
+ if (focusbuttons)
+ break;
+ datectl(di[sel].down, &yy, &mm, &dd);
+ break;
+ case KEY_F(1):
+ if (conf->key.f1_file == NULL &&
+ conf->key.f1_message == NULL)
+ break;
+ if (f1help_dialog(conf) != 0)
+ return (BSDDIALOG_ERROR);
+ if (datebox_redraw(&d, di) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (datebox_redraw(&d, di) != 0)
+ return (BSDDIALOG_ERROR);
+ break;
+ default:
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
+ }
+ }
+
+ *year = yy;
+ *month = mm;
+ *day = dd;
+
+ for (i = 0; i < 3 ; i++)
+ delwin(di[i].win);
+ end_dialog(&d);
+
+ return (retval);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/formbox.c b/contrib/bsddialog/lib/formbox.c
index 564fa99d69a8..ca473356e350 100644
--- a/contrib/bsddialog/lib/formbox.c
+++ b/contrib/bsddialog/lib/formbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,10 +25,8 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
-#include <form.h>
+#include <curses.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -36,502 +34,891 @@
#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;
+enum field_action {
+ MOVE_CURSOR_BEGIN,
+ MOVE_CURSOR_END,
+ MOVE_CURSOR_RIGHT,
+ MOVE_CURSOR_LEFT,
+ DEL_LETTER
+};
+
+struct privateitem {
+ const char *label; /* formitem.label */
+ unsigned int ylabel; /* formitem.ylabel */
+ 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 */
+};
+
+struct privateform {
+ WINDOW *box; /* window to draw borders */
+ WINDOW *pad;
+ unsigned int h; /* only to create pad */
+ unsigned int w; /* only to create pad */
+ unsigned int wmin; /* to refresh, w can change for FIELDEXTEND */
+ unsigned int ys; /* to refresh */
+ unsigned int ye; /* to refresh */
+ unsigned int xs; /* to refresh */
+ unsigned int xe; /* to refresh */
+ unsigned int y; /* changes moving focus around items */
+ unsigned int formheight; /* API formheight */
+ unsigned int viewrows; /* visible rows, real formheight */
+ unsigned int minviewrows; /* min viewrows, ylabel != yfield */
+ wchar_t securewch; /* wide char of conf.form.secure[mb]ch */
+ unsigned int nitems; /* like API nitems */
+ struct privateitem *pritems;
+ int sel; /* selected item in pritem, can be -1 */
+ bool hasbottomdesc; /* some item has bottomdesc */
};
-#define GETMYFIELD(field) ((struct myfield*)field_userptr(field))
-#define GETMYFIELD2(form) ((struct myfield*)field_userptr(current_field(form)))
-static void insertch(struct myfield *mf, int ch)
+static int
+build_privateform(struct bsddialog_conf*conf, unsigned int nitems,
+ struct bsddialog_formitem *items, struct privateform *f)
{
- int i;
+ bool insecurecursor;
+ int mbchsize;
+ unsigned int i, j, itemybeg, itemxbeg, tmp;
+ wchar_t *winit;
+ struct privateitem *item;
+
+ /* checks */
+ CHECK_ARRAY(nitems, items);
+ for (i = 0; i < nitems; i++) {
+ if (items[i].fieldlen == 0)
+ RETURN_FMTERROR("item %u [0-%u] fieldlen = 0",
+ i, nitems);
+ if (items[i].maxvaluelen == 0)
+ RETURN_FMTERROR("item %u [0-%u] maxvaluelen = 0",
+ i, nitems);
+ }
+ f->nitems = nitems;
+
+ /* insecure ch */
+ insecurecursor = false;
+ if (conf->form.securembch != NULL) {
+ mbchsize = mblen(conf->form.securembch, MB_LEN_MAX);
+ if (mbtowc(&f->securewch, conf->form.securembch, mbchsize) < 0)
+ RETURN_ERROR("Cannot convert securembch to wchar_t");
+ insecurecursor = true;
+ } else if (conf->form.securech != '\0') {
+ f->securewch = btowc(conf->form.securech);
+ insecurecursor = true;
+ } else {
+ f->securewch = L' ';
+ }
+
+ /* alloc and set private items */
+ f->pritems = malloc(f->nitems * sizeof(struct privateitem));
+ if (f->pritems == NULL)
+ RETURN_ERROR("Cannot allocate internal form.pritems");
+ f->hasbottomdesc = false;
+ f->h = f->w = f->minviewrows = 0;
+ for (i = 0; i < f->nitems; i++) {
+ item = &f->pritems[i];
+ item->label = CHECK_STR(items[i].label);
+ item->ylabel = items[i].ylabel;
+ item->xlabel = items[i].xlabel;
+ item->yfield = items[i].yfield;
+ item->xfield = items[i].xfield;
+ item->secure = items[i].flags & BSDDIALOG_FIELDHIDDEN;
+ item->readonly = items[i].flags & BSDDIALOG_FIELDREADONLY;
+ item->fieldnocolor = items[i].flags & BSDDIALOG_FIELDNOCOLOR;
+ item->extendfield = items[i].flags & BSDDIALOG_FIELDEXTEND;
+ item->fieldonebyte = items[i].flags &
+ BSDDIALOG_FIELDSINGLEBYTE;
+ item->cursorend = items[i].flags & BSDDIALOG_FIELDCURSOREND;
+ item->bottomdesc = CHECK_STR(items[i].bottomdesc);
+ if (items[i].bottomdesc != NULL)
+ f->hasbottomdesc = true;
+ if (item->readonly || (item->secure && !insecurecursor))
+ item->cursor = false;
+ else
+ item->cursor = true;
+
+ item->maxletters = items[i].maxvaluelen;
+ item->privwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->privwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->privwbuf, 0, item->maxletters + 1);
+ item->pubwbuf = calloc(item->maxletters + 1, sizeof(wchar_t));
+ if (item->pubwbuf == NULL)
+ RETURN_ERROR("Cannot allocate item private buffer");
+ memset(item->pubwbuf, 0, item->maxletters + 1);
+
+ if ((winit = alloc_mbstows(CHECK_STR(items[i].init))) == NULL)
+ RETURN_ERROR("Cannot allocate item.init in wchar_t*");
+ wcsncpy(item->privwbuf, winit, item->maxletters);
+ wcsncpy(item->pubwbuf, winit, item->maxletters);
+ free(winit);
+ item->nletters = wcslen(item->pubwbuf);
+ if (item->secure) {
+ for (j = 0; j < item->nletters; j++)
+ item->pubwbuf[j] = f->securewch;
+ }
+
+ item->fieldcols = items[i].fieldlen;
+ item->xposdraw = 0;
+ item->xcursor = 0;
+ item->pos = 0;
+
+ /* size and position */
+ f->h = MAX(f->h, item->ylabel);
+ f->h = MAX(f->h, item->yfield);
+ f->w = MAX(f->w, item->xlabel + strcols(item->label));
+ f->w = MAX(f->w, item->xfield + item->fieldcols);
+ if (i == 0) {
+ itemybeg = MIN(item->ylabel, item->yfield);
+ itemxbeg = MIN(item->xlabel, item->xfield);
+ } else {
+ tmp = MIN(item->ylabel, item->yfield);
+ itemybeg = MIN(itemybeg, tmp);
+ tmp = MIN(item->xlabel, item->xfield);
+ itemxbeg = MIN(itemxbeg, tmp);
+ }
+ tmp = abs((int)item->ylabel - (int)item->yfield);
+ f->minviewrows = MAX(f->minviewrows, tmp);
+ }
+ if (f->nitems > 0) {
+ f->h = f->h + 1 - itemybeg;
+ f->w -= itemxbeg;
+ f->minviewrows += 1;
+ }
+ f->wmin = f->w;
+ for (i = 0; i < f->nitems; i++) {
+ f->pritems[i].ylabel -= itemybeg;
+ f->pritems[i].yfield -= itemybeg;
+ f->pritems[i].xlabel -= itemxbeg;
+ f->pritems[i].xfield -= itemxbeg;
+ }
+
+ return (0);
+}
+
+static bool fieldctl(struct privateitem *item, enum field_action act)
+{
+ bool change;
+ int width, oldwidth, nextwidth, cols;
+ unsigned int i;
+
+ change = false;
+ switch (act){
+ case MOVE_CURSOR_BEGIN:
+ if (item->pos == 0 && item->xcursor == 0)
+ break;
+ /* here the cursor is changed */
+ change = true;
+ item->pos = 0;
+ item->xcursor = 0;
+ item->xposdraw = 0;
+ break;
+ case MOVE_CURSOR_END:
+ while (fieldctl(item, MOVE_CURSOR_RIGHT))
+ change = true;
+ break;
+ case MOVE_CURSOR_LEFT:
+ if (item->pos == 0)
+ break;
+ /* check redundant by item->pos == 0 because of 'while' below */
+ if (item->xcursor == 0 && item->xposdraw == 0)
+ break;
+ /* here some letter to left */
+ change = true;
+ item->pos -= 1;
+ width = wcwidth(item->pubwbuf[item->pos]);
+ if (((int)item->xcursor) - width < 0) {
+ item->xcursor = 0;
+ item->xposdraw -= 1;
+ } else
+ item->xcursor -= width;
+
+ while (true) {
+ if (item->xposdraw == 0)
+ break;
+ if (item->xcursor >= item->fieldcols / 2)
+ break;
+ if (wcwidth(item->pubwbuf[item->xposdraw - 1]) +
+ item->xcursor + width > item->fieldcols)
+ break;
- 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 bool insertch(struct privateitem *item, wchar_t wch, wchar_t securewch)
{
- int i, last;
+ int i;
+
+ if (item->nletters >= item->maxletters)
+ return (false);
- for (i = mf->pos; i < mf->buflen -1; i++) {
- mf->buf[i] = mf->buf[i+1];
+ 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];
}
- last = mf->buflen > 0 ? mf->buflen -1 : 0;
- mf->buf[last] = '\0';
- mf->buflen = last;
+ item->privwbuf[item->pos] = wch;
+ item->pubwbuf[item->pos] = item->secure ? securewch : wch;
+ item->nletters += 1;
+ item->privwbuf[item->nletters] = L'\0';
+ item->pubwbuf[item->nletters] = L'\0';
+
+ return (true);
}
-static void print_bottomdesc(struct myfield *mf)
+static char* alloc_wstomb(wchar_t *wstr)
{
- move(SCREENLINES - 1, 2);
- clrtoeol();
- if (mf->bottomdesc != NULL) {
- addstr(mf->bottomdesc);
- refresh();
+ 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 char *w2c(wchar_t *string)
+static int
+return_values(struct bsddialog_conf *conf, struct privateform *f,
+ struct bsddialog_formitem *items)
{
- int i, len;
- char *value;
+ unsigned int i;
- len = wcslen(string);
- if ((value = calloc(len + 1, sizeof(char))) == NULL)
- return NULL;
+ for (i = 0; i < f->nitems; i++) {
+ if (conf->form.value_wchar)
+ items[i].value = (char*)wcsdup(f->pritems[i].privwbuf);
+ else
+ items[i].value = alloc_wstomb(f->pritems[i].privwbuf);
- for (i = 0; i < len; i++)
- value[i] = string[i];
- value[i] = '\0';
+ if (items[i].value == NULL)
+ RETURN_FMTERROR(
+ "Cannot allocate memory for item[%d].value", i);
+ }
- return value;
+ return (0);
}
-static int
-return_values(struct bsddialog_conf *conf, int output, int nitems,
- struct bsddialog_formitem *items, FORM *form, FIELD **cfield)
+static void set_first_with_default(struct privateform *f, int *focusitem)
+{
+ unsigned int i;
+
+ f->sel = -1;
+ if (focusitem != NULL && *focusitem >=0 && *focusitem < (int)f->nitems)
+ if (f->pritems[*focusitem].readonly == false) {
+ f->sel = *focusitem;
+ return;
+ }
+ for (i = 0 ; i < f->nitems; i++)
+ if (f->pritems[i].readonly == false) {
+ f->sel = i;
+ break;
+ }
+}
+
+static unsigned int firstitem(unsigned int nitems, struct privateitem *items)
+{
+ int i;
+
+ for (i = 0; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ break;
+
+ return (i);
+}
+
+static unsigned int lastitem(unsigned int nitems, struct privateitem *items)
+{
+ int i;
+
+ for (i = nitems - 1; i >= 0 ; i--)
+ if (items[i].readonly == false)
+ break;
+
+ return (i);
+}
+
+static unsigned int
+previtem(unsigned int nitems, struct privateitem *items, int curritem)
{
int i;
- struct myfield *mf;
- if (output != BSDDIALOG_OK && conf->form.value_without_ok == false)
- return (output);
+ for (i = curritem - 1; i >= 0; i--)
+ if (items[i].readonly == false)
+ return(i);
- 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);
- } else {
- items[i].value = w2c(mf->buf);
+ for (i = nitems - 1; i > curritem - 1; i--)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static unsigned int
+nextitem(unsigned int nitems, struct privateitem *items, int curritem)
+{
+ int i;
+
+ for (i = curritem + 1; i < (int)nitems; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ for (i = 0; i < curritem; i++)
+ if (items[i].readonly == false)
+ return(i);
+
+ return (curritem);
+}
+
+static void redrawbuttons(struct dialog *d, bool focus, bool shortcut)
+{
+ int selected;
+
+ selected = d->bs.curr;
+ if (focus == false)
+ d->bs.curr = -1;
+ d->bs.shortcut = shortcut;
+ draw_buttons(d);
+ d->bs.curr = selected;
+}
+
+static void
+drawitem(struct privateform *f, int idx, bool focus)
+{
+ int color;
+ unsigned int n, cols;
+ struct privateitem *item;
+
+ item = &f->pritems[idx];
+
+ /* Label */
+ wattron(f->pad, t.dialog.color);
+ mvwaddstr(f->pad, item->ylabel, item->xlabel, item->label);
+ wattroff(f->pad, t.dialog.color);
+
+ /* Field */
+ if (item->readonly)
+ color = t.form.readonlycolor;
+ else if (item->fieldnocolor)
+ color = t.dialog.color;
+ else
+ color = focus ? t.form.f_fieldcolor : t.form.fieldcolor;
+ wattron(f->pad, color);
+ mvwhline(f->pad, item->yfield, item->xfield, ' ', item->fieldcols);
+ n = 0;
+ cols = wcwidth(item->pubwbuf[item->xposdraw]);
+ while (cols <= item->fieldcols &&
+ item->xposdraw + n < wcslen(item->pubwbuf)) {
+ n++;
+ cols += wcwidth(item->pubwbuf[item->xposdraw + n]);
+
+ }
+ mvwaddnwstr(f->pad, item->yfield, item->xfield,
+ &item->pubwbuf[item->xposdraw], n);
+ wattroff(f->pad, color);
+
+ /* Bottom Desc */
+ if (f->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (item->bottomdesc != NULL && focus) {
+ attron(t.form.bottomdesccolor);
+ addstr(item->bottomdesc);
+ attroff(t.form.bottomdesccolor);
+ refresh();
}
- if (items[i].value == NULL)
- RETURN_ERROR("Cannot allocate memory for form value");
}
- return (output);
+ /* Cursor */
+ curs_set((focus && item->cursor) ? 1 : 0);
+ wmove(f->pad, item->yfield, item->xfield + item->xcursor);
+}
+
+/*
+ * Trick: draw 2 times an item switching focus.
+ * Problem: curses tries to optimize the rendering but sometimes it misses some
+ * updates or draws old stuff. libformw has a similar problem fixed by the
+ * same trick.
+ * Case 1: KEY_DC and KEY_BACKSPACE, deleted multicolumn letters are drawn
+ * again. It seems fixed by new items pad and prefresh(), previously WINDOW.
+ * Case2: some terminal, tmux and ssh does not show the cursor.
+ */
+#define DRAWITEM_TRICK(f, idx, focus) do { \
+ drawitem(f, idx, !focus); \
+ prefresh((f)->pad, (f)->y, 0, (f)->ys, (f)->xs, (f)->ye, (f)->xe); \
+ drawitem(f, idx, focus); \
+ prefresh((f)->pad, (f)->y, 0, (f)->ys, (f)->xs, (f)->ye, (f)->xe); \
+} while (0)
+
+static void update_formbox(struct bsddialog_conf *conf, struct privateform *f)
+{
+ int h, w;
+
+ getmaxyx(f->box, h, w);
+ draw_borders(conf, f->box, LOWERED);
+
+ if (f->viewrows < f->h) {
+ wattron(f->box, t.dialog.arrowcolor);
+ if (f->y > 0)
+ mvwhline(f->box, 0, (w / 2) - 2, UARROW(conf), 5);
+
+ if (f->y + f->viewrows < f->h)
+ mvwhline(f->box, h-1, (w / 2) - 2, DARROW(conf), 5);
+ wattroff(f->box, t.dialog.arrowcolor);
+ }
+}
+
+static void curriteminview(struct privateform *f, struct privateitem *item)
+{
+ unsigned int yup, ydown;
+
+ yup = MIN(item->ylabel, item->yfield);
+ ydown = MAX(item->ylabel, item->yfield);
+
+ /* selected item in view */
+ if (f->y > yup && f->y > 0)
+ f->y = yup;
+ if ((int)(f->y + f->viewrows) - 1 < (int)ydown)
+ f->y = ydown - f->viewrows + 1;
+ /* lower pad after a terminal expansion */
+ if (f->y > 0 && (f->h - f->y) < f->viewrows)
+ f->y = f->h - f->viewrows;
+}
+
+static int form_size_position(struct dialog *d, struct privateform *f)
+{
+ int htext, hform;
+
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ /* autosize */
+ hform = (int) f->viewrows;
+ if (f->viewrows == BSDDIALOG_AUTOSIZE)
+ hform = MAX(f->h, f->minviewrows);
+ hform += 2; /* formborders */
+
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, &htext, &d->bs, hform, f->w + 4) != 0)
+ return (BSDDIALOG_ERROR);
+ /* formheight: avoid overflow, "at most" and at least minviewrows */
+ if (d->h - BORDERS - htext - HBUTTONS < 2 + (int)f->minviewrows) {
+ f->viewrows = f->minviewrows; /* for widget_checksize() */
+ } else if (f->viewrows == BSDDIALOG_AUTOSIZE) {
+ f->viewrows = MIN(d->h - BORDERS - htext - HBUTTONS, hform) - 2;
+ f->viewrows = MAX(f->viewrows, f->minviewrows);
+ } else {
+ f->viewrows = MIN(d->h - BORDERS - htext - HBUTTONS, hform) - 2;
+ }
+
+ /* checksize */
+ if (f->viewrows < f->minviewrows)
+ RETURN_FMTERROR("formheight, current: %u needed at least %u",
+ f->viewrows, f->minviewrows);
+ if (widget_checksize(d->h, d->w, &d->bs,
+ 2 /* borders */ + f->minviewrows, f->w + 4) != 0)
+ return (BSDDIALOG_ERROR);
+
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
}
static int
-form_handler(struct bsddialog_conf *conf, WINDOW *widget, struct buttons bs,
- WINDOW *formwin, FORM *form, FIELD **cfield, int nitems,
- struct bsddialog_formitem *items)
+form_redraw(struct dialog *d, struct privateform *f, bool focusinform)
{
- bool loop, buttupdate, informwin;
- int i, chtype, output;
+ unsigned int i;
+
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ f->viewrows = f->formheight;
+ f->w = f->wmin;
+ if (form_size_position(d, f) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2 /* box borders */ + f->viewrows + HBUTTONS);
+
+ update_box(d->conf, f->box, d->y + d->h - 5 - f->viewrows, d->x + 2,
+ f->viewrows + 2, d->w - 4, LOWERED);
+
+ for (i = 0; i < f->nitems; i++) {
+ fieldctl(&f->pritems[i], MOVE_CURSOR_BEGIN);
+ if (f->pritems[i].extendfield) {
+ f->w = d->w - 6;
+ f->pritems[i].fieldcols = f->w - f->pritems[i].xfield;
+ }
+ if (f->pritems[i].cursorend)
+ fieldctl(&f->pritems[i], MOVE_CURSOR_END);
+ }
+
+ wresize(f->pad, f->h, f->w);
+ for (i = 0; i < f->nitems; i++)
+ drawitem(f, i, false);
+
+ f->ys = d->y + d->h - 5 - f->viewrows + 1;
+ f->ye = d->y + d->h - 5 ;
+ if ((int)f->w >= d->w - 6) { /* left */
+ f->xs = d->x + 3;
+ f->xe = f->xs + d->w - 7;
+ } else { /* center */
+ f->xs = d->x + 3 + (d->w - 6)/2 - f->w/2;
+ f->xe = f->xs + d->w - 5;
+ }
+
+ if (f->sel != -1) { /* at least 1 writable item */
+ redrawbuttons(d,
+ d->conf->button.always_active || !focusinform,
+ !focusinform);
+ wnoutrefresh(d->widget);
+ curriteminview(f, &f->pritems[f->sel]);
+ update_formbox(d->conf, f);
+ wnoutrefresh(f->box);
+ DRAWITEM_TRICK(f, f->sel, focusinform);
+ } else if (f->sel == -1 && f->nitems > 0) { /* all read only */
+ redrawbuttons(d, true, true);
+ wnoutrefresh(d->widget);
+ update_formbox(d->conf, f);
+ wnoutrefresh(f->box);
+ DRAWITEM_TRICK(f, 0, false); /* to refresh pad*/
+ } else { /* no item */
+ wnoutrefresh(f->box);
+ }
+
+ return (0);
+}
+
+/* API */
+int
+bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, unsigned int formheight, unsigned int nitems,
+ struct bsddialog_formitem *items, int *focusitem)
+{
+ bool switchfocus, changeitem, focusinform, loop;
+ int next, retval, wchtype;
+ unsigned int i;
wint_t input;
- struct myfield *mf;
+ struct privateitem *item;
+ struct privateform form;
+ struct dialog d;
+
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+
+ if (build_privateform(conf, nitems, items, &form) != 0)
+ return (BSDDIALOG_ERROR);
- 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;
+ if ((form.box = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW form box");
+ wbkgd(form.box, t.dialog.color);
+ if ((form.pad = newpad(1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW form pad");
+ wbkgd(form.pad, t.dialog.color);
+
+ set_first_with_default(&form, focusitem);
+ if (form.sel != -1) {
+ focusinform = true;
+ form.y = 0;
+ item = &form.pritems[form.sel];
+ } else {
+ item = NULL;
+ focusinform = false;
+ }
- bs.curr = -1;
- buttupdate = true;
+ form.formheight = formheight;
+ if (form_redraw(&d, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
+ changeitem = switchfocus = false;
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)
+ doupdate();
+ if ((wchtype = get_wch(&input)) == ERR)
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)
+ if (focusinform && conf->button.always_active == false)
break;
- output = return_values(conf, bs.value[bs.curr], nitems,
- items, form, cfield);
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = return_values(conf, BSDDIALOG_ESC,
- nitems, items, form, cfield);
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- if (informwin) {
- bs.curr = 0;
- informwin = false;
- curs_set(0);
+ if (focusinform) {
+ switchfocus = true;
} else {
- bs.curr++;
- informwin = bs.curr >= (int)bs.nbuttons ?
- true : false;
- if (informwin) {
- curs_set(1);
- pos_form_cursor(form);
+ if (d.bs.curr + 1 < (int)d.bs.nbuttons) {
+ d.bs.curr++;
+ } else {
+ d.bs.curr = 0;
+ if (form.sel != -1) {
+ switchfocus = true;
+ }
}
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
}
- buttupdate = true;
break;
case KEY_LEFT:
- if (informwin) {
- form_driver_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;
- }
+ if (focusinform) {
+ if (fieldctl(item, MOVE_CURSOR_LEFT))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ } else if (d.bs.curr > 0) {
+ d.bs.curr--;
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
+ } else if (form.sel != -1) {
+ switchfocus = true;
}
break;
case KEY_RIGHT:
- if (informwin) {
- mf = GETMYFIELD2(form);
- if (mf->pos >= mf->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;
- }
+ if (focusinform) {
+ if (fieldctl(item, MOVE_CURSOR_RIGHT))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ } else if (d.bs.curr < (int) d.bs.nbuttons - 1) {
+ d.bs.curr++;
+ redrawbuttons(&d, true, true);
+ wnoutrefresh(d.widget);
+ } else if (form.sel != -1) {
+ switchfocus = true;
}
break;
+ case KEY_CTRL('p'):
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);
+ if (focusinform) {
+ next = previtem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
+ } else if (form.sel != -1) {
+ switchfocus = true;
+ }
break;
+ case KEY_CTRL('n'):
case KEY_DOWN:
- if (nitems < 2)
+ if (focusinform == false)
break;
- set_field_fore(current_field(form), t.form.fieldcolor);
- set_field_back(current_field(form), t.form.fieldcolor);
- form_driver_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);
+ if (form.nitems == 1) {
+ switchfocus = true;
+ } else {
+ next = nextitem(form.nitems, form.pritems,
+ form.sel);
+ changeitem = form.sel != next;
+ }
+ break;
+ case KEY_PPAGE:
+ if (focusinform) {
+ next = firstitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
+ }
+ break;
+ case KEY_NPAGE:
+ if (focusinform) {
+ next = lastitem(form.nitems, form.pritems);
+ changeitem = form.sel != next;
+ }
break;
case KEY_BACKSPACE:
case 127: /* Backspace */
- mf = GETMYFIELD2(form);
- if (mf->pos <= 0)
+ if (focusinform == false)
break;
- form_driver_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);
+ if (fieldctl(item, MOVE_CURSOR_LEFT))
+ if (fieldctl(item, DEL_LETTER))
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_DC:
- form_driver_w(form, KEY_CODE_YES, REQ_DEL_CHAR);
- mf = GETMYFIELD2(form);
- if (mf->pos < mf->buflen)
- shiftleft(mf);
+ if (focusinform == false)
+ break;
+ if (fieldctl(item, DEL_LETTER))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ break;
+ case KEY_HOME:
+ if (focusinform == false)
+ break;
+ if (fieldctl(item, MOVE_CURSOR_BEGIN))
+ DRAWITEM_TRICK(&form, form.sel, true);
+ break;
+ case KEY_END:
+ if (focusinform == false)
+ break;
+ if (fieldctl(item, MOVE_CURSOR_END))
+ DRAWITEM_TRICK(&form, form.sel, true);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
+ curs_set(0);
+ if (f1help_dialog(conf) != 0) {
+ retval = BSDDIALOG_ERROR;
+ loop = false;
+ }
+ if (form_redraw(&d, &form, focusinform) != 0)
return (BSDDIALOG_ERROR);
- /* No Break */
+ break;
+ case KEY_CTRL('l'):
case KEY_RESIZE:
- output = REDRAWFORM;
- loop = false;
+ if (form_redraw(&d, &form, focusinform) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- if (informwin) {
- if (chtype == KEY_CODE_YES)
+ if (wchtype == KEY_CODE_YES)
+ break;
+ if (focusinform) {
+ if (item->fieldonebyte && wctob(input) == EOF)
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);
+ /*
+ * MOVE_CURSOR_RIGHT manages new positions
+ * because the cursor remains on the new letter,
+ * "if" and "while" update the positions.
+ */
+ if (insertch(item, input, form.securewch)) {
+ fieldctl(item, MOVE_CURSOR_RIGHT);
+ /*
+ * no if (fieldctl), update always
+ * because it fails with maxletters.
+ */
+ DRAWITEM_TRICK(&form, form.sel, true);
+ }
+ } else {
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
break;
+ } /* end switch get_wch() */
+
+ if (switchfocus) {
+ focusinform = !focusinform;
+ d.bs.curr = 0;
+ redrawbuttons(&d,
+ conf->button.always_active || !focusinform,
+ !focusinform);
+ wnoutrefresh(d.widget);
+ DRAWITEM_TRICK(&form, form.sel, focusinform);
+ switchfocus = false;
}
- }
-
- curs_set(0);
- return (output);
-}
-
-static 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,
- 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)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 2, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*formheight == 0) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *formheight = menusize - 2 < 0 ? 0 : menusize - 2;
+ if (changeitem) {
+ DRAWITEM_TRICK(&form, form.sel, false);
+ form.sel = next;
+ item = &form.pritems[form.sel];
+ curriteminview(&form, item);
+ update_formbox(conf, &form);
+ wnoutrefresh(form.box);
+ DRAWITEM_TRICK(&form, form.sel, true);
+ changeitem = false;
}
- else /* h autosize with fixed formheight */
- menusize = *formheight + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- } else {
- if (*formheight == 0)
- *formheight = MIN(rows-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)
-{
- int mincols, textrow, formrows;
+ } /* end while (loop) */
- mincols = VBORDERS;
- /* buttons */
- mincols += buttons_width(bs);
- mincols = MAX(mincols, (int)linelen + 4);
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "forms (label + field)");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
-
- if (nitems > 0 && formheight == 0)
- RETURN_ERROR("fields > 0 but formheight == 0, probably "
- "terminal too small");
-
- formrows = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + formrows + textrow)
- RETURN_ERROR("Few lines for this menus");
-
- return (0);
-}
-
-int
-bsddialog_form(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int formheight, unsigned int nitems,
- struct bsddialog_formitem *items)
-{
- int i, output, color, y, x, h, w;
- unsigned long j, maxline, mybufsize;
- struct buttons bs;
- struct myfield *myfields;
- FIELD **cfield;
- FORM *form;
- WINDOW *widget, *formwin, *textpad, *shadow;
-
- /* disable form scrolling */
- if (formheight < nitems)
- formheight = nitems;
-
- for (i = 0; i < (int)nitems; i++) {
- if (items[i].maxvaluelen == 0)
- RETURN_ERROR("maxvaluelen cannot be zero");
- if (items[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;
- }
- else
- myfields[i].secure = false;
-
- if (ISFIELDREADONLY(items[i])) {
- field_opts_off(cfield[i], O_EDIT);
- field_opts_off(cfield[i], O_ACTIVE);
- color = t.form.readonlycolor;
- } else {
- color = i == 0 ? t.form.f_fieldcolor : t.form.fieldcolor;
- }
- set_field_fore(cfield[i], color);
- set_field_back(cfield[i], color);
-
- maxline = MAX(maxline, items[i].xlabel + strlen(items[i].label));
- maxline = MAX(maxline, items[i].xfield + items[i].fieldlen - 1);
- }
- 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);
- }
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- 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)
- return (BSDDIALOG_ERROR);
- if (form_checksize(h, w, text, formheight, nitems, maxline, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
+ curs_set(0);
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ if (return_values(conf, &form, items) == BSDDIALOG_ERROR)
return (BSDDIALOG_ERROR);
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
-
- formwin = new_boxed_window(conf, y + h - 3 - formheight -2, x +1,
- formheight+2, w-2, LOWERED);
-
- form = new_form(cfield);
- set_form_win(form, formwin);
- /* should be formheight */
- set_form_sub(form, derwin(formwin, nitems, w-4, 1, 1));
- post_form(form);
-
- for (i = 0; i < (int)nitems; i++)
- mvwaddstr(formwin, items[i].ylabel, items[i].xlabel,
- items[i].label);
-
- wrefresh(formwin);
-
- do {
- output = form_handler(conf, widget, bs, formwin, form, cfield,
- nitems, items);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w, textpad,
- text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
+ if (focusitem != NULL)
+ *focusitem = form.sel;
- doupdate();
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - formheight, x + 1 + w - TEXTHMARGIN);
-
- draw_borders(conf, formwin, formheight+2, w-2, LOWERED);
- wrefresh(formwin);
-
- refresh();
- } while (output == REDRAWFORM);
-
- unpost_form(form);
- free_form(form);
- for (i = 0; i < (int)nitems; i++) {
- free_field(cfield[i]);
- free(myfields[i].buf);
+ if (form.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
}
- free(cfield);
- free(myfields);
-
- delwin(formwin);
- end_dialog(conf, shadow, widget, textpad);
+ for (i = 0; i < form.nitems; i++) {
+ free(form.pritems[i].privwbuf);
+ free(form.pritems[i].pubwbuf);
+ }
+ delwin(form.pad);
+ delwin(form.box);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
diff --git a/contrib/bsddialog/lib/infobox.c b/contrib/bsddialog/lib/infobox.c
deleted file mode 100644
index 5a6b7c2fd692..000000000000
--- a/contrib/bsddialog/lib/infobox.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/param.h>
-
-#include <curses.h>
-
-#include "bsddialog.h"
-#include "lib_util.h"
-
-static int
-infobox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text)
-{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, NULL, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
- }
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, NULL);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, false);
-
- return (0);
-}
-
-static int infobox_checksize(int rows, int cols)
-{
- if (cols < HBORDERS)
- RETURN_ERROR("Few cols, infobox needs at least width 2");
-
- if (rows < VBORDERS)
- RETURN_ERROR("Infobox needs at least height 2");
-
- return (0);
-}
-
-/* API */
-int
-bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols)
-{
- int y, x, h, w;
- WINDOW *shadow, *widget, *textpad;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_autosize(conf, rows, cols, &h, &w, text) != 0)
- return (BSDDIALOG_ERROR);
- if (infobox_checksize(h, w) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text,
- NULL, false) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-2,
- x+w-TEXTHMARGIN);
-
- doupdate();
-
- end_dialog(conf, shadow, widget, textpad);
-
- return (BSDDIALOG_OK);
-} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/lib_util.c b/contrib/bsddialog/lib/lib_util.c
index 506003b52c8d..d673a1a74d72 100644
--- a/contrib/bsddialog/lib/lib_util.c
+++ b/contrib/bsddialog/lib/lib_util.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,22 +25,82 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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 */
+/*
+ * -1- Error and diagnostic
+ *
+ * get_error_string();
+ * set_error_string();
+ * set_fmt_error_string();
+ *
+ * ----------------------------------------------------
+ * -2- (Unicode) Multicolumn character strings
+ *
+ * alloc_mbstows();
+ * mvwaddwch();
+ * str_props();
+ * strcols();
+ *
+ * ----------------------------------------------------
+ * -3- Buttons
+ *
+ * [static] buttons_min_width();
+ * [static] draw_button();
+ * draw_buttons();
+ * set_buttons(); (to call 1 time after prepare_dialog()).
+ * shortcut_buttons();
+ *
+ * ----------------------------------------------------
+ * -4- (Auto) Sizing and (Auto) Position
+ *
+ * [static] widget_max_height(conf);
+ * [static] widget_max_width(struct bsddialog_conf *conf)
+ * [static] is_wtext_attr();
+ * [static] text_properties();
+ * [static] text_autosize();
+ * [static] text_size();
+ * [static] widget_min_height(conf, htext, hnotext, bool buttons);
+ * [static] widget_min_width(conf, wtext, minw, buttons);
+ * set_widget_size();
+ * set_widget_autosize(); (not for all dialogs).
+ * widget_checksize(); (not for all dialogs).
+ * set_widget_position();
+ * dialog_size_position(struct dialog); (not for all dialogs).
+ *
+ * ----------------------------------------------------
+ * -5- (Dialog) Widget components and utils
+ *
+ * hide_dialog(struct dialog);
+ * f1help_dialog(conf);
+ * draw_borders(conf, win, elev);
+ * update_box(conf, win, y, x, h, w, elev);
+ * rtextpad(); (helper for pnoutrefresh(textpad)).
+ *
+ * ----------------------------------------------------
+ * -6- Dialog init/build, update/draw, destroy
+ *
+ * end_dialog(struct dialog);
+ * [static] check_set_wtext_attr();
+ * [static] print_string(); (word wrapping).
+ * [static] print_textpad();
+ * draw_dialog(struct dialog);
+ * prepare_dialog(struct dialog);
+ */
+
+/*
+ * -1- Error and diagnostic
+ */
+#define ERRBUFLEN 1024
-/* Error */
static char errorbuffer[ERRBUFLEN];
const char *get_error_string(void)
@@ -53,55 +113,122 @@ void set_error_string(const char *str)
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
-/* Clear */
-int hide_widget(int y, int x, int h, int w, bool withshadow)
+void set_fmt_error_string(const char *fmt, ...)
{
- WINDOW *clear;
+ va_list arg_ptr;
- if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL)
- RETURN_ERROR("Cannot hide the widget");
- wbkgd(clear, t.screen.color);
+ va_start(arg_ptr, fmt);
+ vsnprintf(errorbuffer, ERRBUFLEN-1, fmt, arg_ptr);
+ va_end(arg_ptr);
+}
- if (withshadow)
- wrefresh(clear);
+/*
+ * -2- (Unicode) Multicolumn character strings
+ */
+wchar_t* alloc_mbstows(const char *mbstring)
+{
+ size_t charlen, nchar;
+ mbstate_t mbs;
+ const char *pmbstring;
+ wchar_t *wstring;
+
+ nchar = 1;
+ pmbstring = mbstring;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ pmbstring += charlen;
+ nchar++;
+ }
- mvwin(clear, y, x);
- wrefresh(clear);
+ if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL)
+ return (NULL);
+ mbstowcs(wstring, mbstring, nchar);
- delwin(clear);
+ return (wstring);
+}
+
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
+{
+ wchar_t ws[2];
+
+ 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);
}
-/* F1 help */
-int f1help(struct bsddialog_conf *conf)
+unsigned int strcols(const char *mbstring)
{
- int output;
- struct bsddialog_conf hconf;
+ 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;
+ }
- bsddialog_initconf(&hconf);
- hconf.title = "HELP";
- hconf.button.ok_label = "EXIT";
- hconf.clear = true;
- hconf.ascii_lines = conf->ascii_lines;
- hconf.no_lines = conf->no_lines;
- hconf.shadow = conf->shadow;
- hconf.text.highlight = conf->text.highlight;
+ return (ncol);
+}
- output = BSDDIALOG_OK;
- if (conf->key.f1_message != NULL)
- output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+/*
+ * -3- Buttons
+ */
+static int buttons_min_width(struct buttons *bs)
+{
+ unsigned int width;
- if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
- output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+ width = bs->nbuttons * bs->sizebutton;
+ if (bs->nbuttons > 0)
+ width += (bs->nbuttons - 1) * t.button.minmargin;
- return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+ return (width);
}
-/* Buttons */
static void
draw_button(WINDOW *window, int y, int x, int size, const char *text,
- bool selected, bool shortcut)
+ wchar_t first, bool selected, bool shortcut)
{
int i, color_arrows, color_shortkey, color_button;
@@ -126,129 +253,160 @@ 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);
}
}
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut)
+void draw_buttons(struct dialog *d)
{
- int i, x, startx, y, rows, cols;
+ int i, x, startx, y;
+ unsigned int newmargin, margin, wbuttons;
- getmaxyx(window, rows, cols);
- y = rows - 2;
+ y = d->h - 2;
- startx = cols/2 - buttons_width(bs)/2;
+ newmargin = d->w - BORDERS - (d->bs.nbuttons * d->bs.sizebutton);
+ newmargin /= (d->bs.nbuttons + 1);
+ newmargin = MIN(newmargin, t.button.maxmargin);
+ if (newmargin == 0) {
+ margin = t.button.minmargin;
+ wbuttons = buttons_min_width(&d->bs);
+ } else {
+ margin = newmargin;
+ wbuttons = d->bs.nbuttons * d->bs.sizebutton;
+ wbuttons += (d->bs.nbuttons + 1) * margin;
+ }
- for (i = 0; i < (int)bs.nbuttons; i++) {
- x = i * (bs.sizebutton + t.button.hmargin);
- draw_button(window, y, startx + x, bs.sizebutton, bs.label[i],
- i == bs.curr, shortcut);
+ startx = d->w/2 - wbuttons/2 + newmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ x = i * (d->bs.sizebutton + margin);
+ draw_button(d->widget, y, startx + x, d->bs.sizebutton,
+ d->bs.label[i], d->bs.first[i], i == d->bs.curr,
+ d->bs.shortcut);
}
}
void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel)
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *cancellabel)
{
int i;
#define SIZEBUTTON 8
-#define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL
+#define DEFAULT_BUTTON_LABEL OK_LABEL
#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
+ wchar_t first;
- bs->nbuttons = 0;
- bs->curr = 0;
- bs->sizebutton = 0;
+ d->bs.nbuttons = 0;
+ d->bs.curr = 0;
+ d->bs.sizebutton = 0;
+ d->bs.shortcut = shortcut;
- if (yesoklabel != NULL && conf->button.without_ok == false) {
- bs->label[0] = conf->button.ok_label != NULL ?
- conf->button.ok_label : yesoklabel;
- bs->value[0] = BSDDIALOG_OK;
- bs->nbuttons += 1;
+ if (d->conf->button.left1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT1;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_extra) {
- bs->label[bs->nbuttons] = conf->button.extra_label != NULL ?
- conf->button.extra_label : "Extra";
- bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
- bs->nbuttons += 1;
+ if (d->conf->button.left2_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left2_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT2;
+ d->bs.nbuttons += 1;
}
- if (nocancellabel != NULL && conf->button.without_cancel == false) {
- bs->label[bs->nbuttons] = conf->button.cancel_label ?
- conf->button.cancel_label : nocancellabel;
- bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
- if (conf->button.default_cancel)
- bs->curr = bs->nbuttons;
- bs->nbuttons += 1;
+ if (d->conf->button.left3_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.left3_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT3;
+ d->bs.nbuttons += 1;
}
- if (conf->button.with_help) {
- bs->label[bs->nbuttons] = conf->button.help_label != NULL ?
- conf->button.help_label : "Help";
- bs->value[bs->nbuttons] = BSDDIALOG_HELP;
- bs->nbuttons += 1;
+ if (oklabel != NULL && d->conf->button.without_ok == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.ok_label != NULL ?
+ d->conf->button.ok_label : oklabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_OK;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic1_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic1_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1;
- bs->nbuttons += 1;
+ if (d->conf->button.with_extra) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.extra_label != NULL ?
+ d->conf->button.extra_label : "Extra";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_EXTRA;
+ d->bs.nbuttons += 1;
}
- if (conf->button.generic2_label != NULL) {
- bs->label[bs->nbuttons] = conf->button.generic2_label;
- bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
- bs->nbuttons += 1;
+ if (cancellabel != NULL && d->conf->button.without_cancel == false) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.cancel_label ?
+ d->conf->button.cancel_label : cancellabel;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_CANCEL;
+ if (d->conf->button.default_cancel)
+ d->bs.curr = d->bs.nbuttons;
+ d->bs.nbuttons += 1;
}
- if (bs->nbuttons == 0) {
- bs->label[0] = DEFAULT_BUTTON_LABEL;
- bs->value[0] = DEFAULT_BUTTON_VALUE;
- bs->nbuttons = 1;
+ if (d->conf->button.with_help) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.help_label != NULL ?
+ d->conf->button.help_label : "Help";
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_HELP;
+ d->bs.nbuttons += 1;
}
- if (conf->button.default_label != NULL) {
- for (i = 0; i < (int)bs->nbuttons; i++) {
- if (strcmp(conf->button.default_label,
- bs->label[i]) == 0)
- bs->curr = i;
- }
+ if (d->conf->button.right1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT1;
+ d->bs.nbuttons += 1;
}
- bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
- for (i = 1; i < (int)bs->nbuttons; i++)
- bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
- bs->sizebutton += 2;
-}
+ if (d->conf->button.right2_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right2_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT2;
+ d->bs.nbuttons += 1;
+ }
-int buttons_width(struct buttons bs)
-{
- unsigned int width;
+ if (d->conf->button.right3_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right3_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT3;
+ d->bs.nbuttons += 1;
+ }
+
+ if (d->bs.nbuttons == 0) {
+ d->bs.label[0] = DEFAULT_BUTTON_LABEL;
+ d->bs.value[0] = DEFAULT_BUTTON_VALUE;
+ d->bs.nbuttons = 1;
+ }
- width = bs.nbuttons * bs.sizebutton;
- if (bs.nbuttons > 0)
- width += (bs.nbuttons - 1) * t.button.hmargin;
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
+ d->bs.first[i] = first;
+ }
- return (width);
+ if (d->conf->button.default_label != NULL) {
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ if (strcmp(d->conf->button.default_label,
+ d->bs.label[i]) == 0)
+ d->bs.curr = i;
+ }
+ }
+
+ d->bs.sizebutton = MAX(SIZEBUTTON - 2, strcols(d->bs.label[0]));
+ for (i = 1; i < (int)d->bs.nbuttons; i++)
+ d->bs.sizebutton = MAX(d->bs.sizebutton, strcols(d->bs.label[i]));
+ d->bs.sizebutton += 2;
}
-bool shortcut_buttons(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;
@@ -258,233 +416,192 @@ bool shortcut_buttons(int key, struct buttons *bs)
return (match);
}
-/* Text */
-static bool is_text_attr(const char *text)
+/*
+ * -4- (Auto) Sizing and (Auto) Position
+ */
+static int widget_max_height(struct bsddialog_conf *conf)
{
- if (strnlen(text, 3) < 3)
- return (false);
-
- if (text[0] != '\\' || text[1] != 'Z')
- return (false);
-
- return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true);
-}
+ int maxheight;
-static bool check_set_text_attr(WINDOW *win, char *text)
-{
- if (is_text_attr(text) == false)
- return (false);
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
- if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) {
- wattron(win, bsddialog_color(text[2] - '0', COLOR_WHITE, 0));
- return (true);
+ if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
+ RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
+ else if (conf->y == BSDDIALOG_CENTER) {
+ maxheight -= conf->auto_topmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - top "
+ "margins <= 0");
+ } else if (conf->y > 0) {
+ maxheight -= conf->y;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - "
+ "shadow - y <= 0");
}
- switch (text[2]) {
- case 'n':
- wattron(win, t.dialog.color);
- wattrset(win, A_NORMAL);
- break;
- case 'b':
- wattron(win, A_BOLD);
- break;
- case 'B':
- wattroff(win, A_BOLD);
- break;
- case 'r':
- wattron(win, A_REVERSE);
- break;
- case 'R':
- wattroff(win, A_REVERSE);
- break;
- case 'u':
- wattron(win, A_UNDERLINE);
- break;
- case 'U':
- wattroff(win, A_UNDERLINE);
- break;
- }
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
- return (true);
+ return (maxheight);
}
-static void
-print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str,
- bool color)
+static int widget_max_width(struct bsddialog_conf *conf)
{
- int i, j, len, reallen;
+ int maxwidth;
- len = reallen = strlen(str);
- if (color) {
- i=0;
- while (i < len) {
- if (is_text_attr(str+i))
- reallen -= 3;
- i++;
- }
- }
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
- i = 0;
- while (i < len) {
- if (*x + reallen > cols) {
- *y = (*x != 0 ? *y+1 : *y);
- if (*y >= *rows) {
- *rows = *y + 1;
- wresize(win, *rows, cols);
- }
- *x = 0;
- }
- j = *x;
- while (j < cols && i < len) {
- if (color && check_set_text_attr(win, str+i)) {
- i += 3;
- } else {
- mvwaddch(win, *y, j, str[i]);
- i++;
- reallen--;
- j++;
- *x = j;
- }
- }
+ if (conf->x > 0) {
+ maxwidth -= conf->x;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow "
+ "- x <= 0");
}
+
+ return (maxwidth);
}
-static int
-print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- bool loop;
- int i, j, z, rows, cols, x, y, tablen;
- char *string;
-
- if ((string = malloc(strlen(text) + 1)) == NULL)
- RETURN_ERROR("Cannot build (analyze) text");
-
- getmaxyx(pad, rows, cols);
- tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen;
+ bool att;
- i = j = x = y = 0;
- loop = true;
- while (loop) {
- string[j] = text[i];
-
- if (strchr("\n\t ", string[j]) != NULL || string[j] == '\0') {
- string[j] = '\0';
- print_string(pad, &rows, cols, &y, &x, string,
- conf->text.highlight);
- }
-
- switch (text[i]) {
- case '\0':
- loop = false;
- break;
- case '\n':
- x = 0;
- y++;
- j = -1;
- break;
- case '\t':
- for (z = 0; z < tablen; z++) {
- if (x >= cols) {
- x = 0;
- y++;
- }
- x++;
- }
- j = -1;
- break;
- case ' ':
- x++;
- if (x >= cols) {
- x = 0;
- y++;
- }
- j = -1;
- }
+ if (wcsnlen(wtext, 3) < 3)
+ return (false);
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
+ return (false);
- if (y >= rows) {
- rows = y + 1;
- wresize(pad, rows, cols);
- }
+ att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
- j++;
- i++;
- }
+ return (att);
+}
- free(string);
+#define NL -1
+#define WS -2
+#define TB -3
- return (0);
-}
+struct textproperties {
+ int nword;
+ int *words;
+ uint8_t *wletters;
+ int maxwordcols;
+ int maxline;
+ bool hasnewline;
+};
-/* Autosize */
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.escape && is_wtext_attr(wtext + i)) {
+ i += 2; /* +1 for update statement */
continue;
}
- if (nword + tablen + 1 >= maxwords) {
+ if (tp->nword + 1 >= maxwords) {
maxwords += 1024;
- words = realloc(words, maxwords * sizeof(int));
- if (words == 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) - BORDERS - 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);
+ (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
mincols = MIN(mincols, maxwidth);
}
@@ -492,26 +609,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;
}
}
}
@@ -520,141 +661,111 @@ 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);
}
-int
+static int
text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
{
- int wbuttons, maxhtext;
bool changewtext;
+ int wbuttons, maxhtext;
+ struct textproperties tp;
wbuttons = 0;
- if (bs != NULL)
- wbuttons = buttons_width(*bs);
+ if (bs->nbuttons > 0)
+ wbuttons = buttons_min_width(bs);
+ /* Rows */
+ if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
+ maxhtext = widget_max_height(conf) - BORDERS - rowsnotext;
+ } else { /* fixed */
+ maxhtext = rows - BORDERS - rowsnotext;
+ }
+ if (bs->nbuttons > 0)
+ maxhtext -= 2;
+ if (maxhtext <= 0)
+ maxhtext = 1; /* text_autosize() computes always htext */
+
+ /* Cols */
if (cols == BSDDIALOG_AUTOSIZE) {
startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
changewtext = true;
} else if (cols == BSDDIALOG_FULLSCREEN) {
- startwtext = widget_max_width(conf) - VBORDERS - TEXTHMARGINS;
+ startwtext = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
changewtext = false;
} else { /* fixed */
- startwtext = cols - VBORDERS - TEXTHMARGINS;
+ startwtext = cols - BORDERS - TEXTHMARGINS;
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 (text_autosize(conf, text, maxhtext, startwtext, changewtext,
- htext, wtext) != 0)
+ /* Sizing calculation */
+ if (text_properties(conf, text, &tp) != 0)
+ return (BSDDIALOG_ERROR);
+ if (tp.nword > 0 && startwtext <= 0)
+ RETURN_FMTERROR("(fixed cols or fullscreen) "
+ "needed at least %d cols to draw text",
+ BORDERS + TEXTHMARGINS + 1);
+ if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
+ wtext) != 0)
return (BSDDIALOG_ERROR);
- return (0);
-}
-
-int widget_max_height(struct bsddialog_conf *conf)
-{
- int maxheight;
-
- maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.h : SCREENLINES;
- if (maxheight <= 0)
- RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
-
- if (conf->y > 0) {
- maxheight -= conf->y;
- if (maxheight <= 0)
- RETURN_ERROR("Terminal too small, screen lines - "
- "shadow - y <= 0");
- }
-
- return (maxheight);
-}
-
-int widget_max_width(struct bsddialog_conf *conf)
-{
- int maxwidth;
-
- maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.w : SCREENCOLS;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
+ free(tp.words);
+ free(tp.wletters);
- if (conf->x > 0) {
- maxwidth -= conf->x;
- if (maxwidth <= 0)
- RETURN_ERROR("Terminal too small, screen cols - shadow "
- "- x <= 0");
- }
-
- return (maxwidth);
+ return (0);
}
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
+static int
+widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
bool withbuttons)
{
int min;
- min = 0;
-
- /* buttons */
- if (withbuttons)
- min += 2; /* buttons and border */
+ /* dialog borders */
+ min = BORDERS;
/* text */
min += htext;
- /* specific widget min height */
- min += minwidget;
+ /* specific widget lines without text */
+ min += hnotext;
+
+ /* buttons */
+ if (withbuttons)
+ min += HBUTTONS; /* buttons and their up-border */
- /* dialog borders */
- min += HBORDERS;
/* conf.auto_minheight */
min = MAX(min, (int)conf->auto_minheight);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_height(conf));
return (min);
}
-int
+static int
widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
struct buttons *bs)
{
- int min, delimtitle;
+ int min, delimtitle, wbottomtitle, wtitle;
min = 0;
/* buttons */
- if (bs != NULL)
- min += buttons_width(*bs);
+ if (bs->nbuttons > 0)
+ min += buttons_min_width(bs);
/* text */
if (wtext > 0)
@@ -666,19 +777,20 @@ 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;
+ min += BORDERS;
/* conf.auto_minwidth */
min = MAX(min, (int)conf->auto_minwidth);
- /* avoid terminal overflow */
- min = MIN(min, widget_max_width(conf));
return (min);
}
@@ -695,11 +807,8 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
*h = maxheight;
else if (rows < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) height");
- else if (rows > BSDDIALOG_AUTOSIZE) {
- if ((*h = rows) > maxheight)
- RETURN_ERROR("Height too big (> terminal height - "
- "shadow)");
- }
+ else if (rows > BSDDIALOG_AUTOSIZE) /* fixed rows */
+ *h = MIN(rows, maxheight); /* rows is at most maxheight */
/* rows == AUTOSIZE: each widget has to set its size */
if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
@@ -709,21 +818,78 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
*w = maxwidth;
else if (cols < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) width");
- else if (cols > BSDDIALOG_AUTOSIZE) {
- if ((*w = cols) > maxwidth)
- RETURN_ERROR("Width too big (> terminal width - "
- "shadow)");
- }
+ else if (cols > BSDDIALOG_AUTOSIZE) /* fixed cols */
+ *w = MIN(cols, maxwidth); /* cols is at most maxwidth */
/* cols == AUTOSIZE: each widget has to set its size */
return (0);
}
int
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw)
+{
+ int htext, wtext;
+
+ if (rows == BSDDIALOG_AUTOSIZE || cols == BSDDIALOG_AUTOSIZE ||
+ rowstext != NULL) {
+ if (text_size(conf, rows, cols, text, bs, hnotext, minw,
+ &htext, &wtext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (rowstext != NULL)
+ *rowstext = htext;
+ }
+
+ if (rows == BSDDIALOG_AUTOSIZE) {
+ *h = widget_min_height(conf, htext, hnotext, bs->nbuttons > 0);
+ *h = MIN(*h, widget_max_height(conf));
+ }
+
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = widget_min_width(conf, wtext, minw, bs);
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ return (0);
+}
+
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw)
+{
+ int minheight, minwidth;
+
+ minheight = BORDERS + hnotext;
+ if (bs->nbuttons > 0)
+ minheight += HBUTTONS;
+ if (h < minheight)
+ RETURN_FMTERROR("Current rows: %d, needed at least: %d",
+ h, minheight);
+
+ minwidth = 0;
+ if (bs->nbuttons > 0)
+ minwidth = buttons_min_width(bs);
+ minwidth = MAX(minwidth, minw);
+ minwidth += BORDERS;
+ if (w < minwidth)
+ RETURN_FMTERROR("Current cols: %d, nedeed at least %d",
+ w, minwidth);
+
+ return (0);
+}
+
+int
set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
{
- 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)
@@ -731,13 +897,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)
@@ -745,228 +911,456 @@ 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 */
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev)
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext)
+{
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, htext, &d->bs, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (widget_checksize(d->h, d->w, &d->bs, hnotext, minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
+
+ return (0);
+}
+
+/*
+ * -5- Widget components and utilities
+ */
+int hide_dialog(struct dialog *d)
{
+ WINDOW *clear;
+
+ if ((clear = newwin(d->h, d->w, d->y, d->x)) == NULL)
+ RETURN_ERROR("Cannot hide the widget");
+ wbkgd(clear, t.screen.color);
+ wrefresh(clear);
+
+ if (d->conf->shadow) {
+ mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
+ wrefresh(clear);
+ }
+
+ delwin(clear);
+
+ return (0);
+}
+
+int f1help_dialog(struct bsddialog_conf *conf)
+{
+ int output;
+ struct bsddialog_conf hconf;
+
+ bsddialog_initconf(&hconf);
+ hconf.title = "HELP";
+ hconf.button.ok_label = "EXIT";
+ hconf.clear = true;
+ hconf.ascii_lines = conf->ascii_lines;
+ hconf.no_lines = conf->no_lines;
+ hconf.shadow = conf->shadow;
+ hconf.text.escape = conf->text.escape;
+
+ output = BSDDIALOG_OK;
+ if (conf->key.f1_message != NULL)
+ output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
+
+ if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
+ output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
+
+ return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+}
+
+void draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev)
+{
+ int h, w;
int leftcolor, rightcolor;
- int ls, rs, ts, bs, tl, tr, bl, br, ltee, rtee;
+ cchar_t *ls, *rs, *ts, *bs, *tl, *tr, *bl, *br;
+ cchar_t hline, vline, corner;
if (conf->no_lines)
return;
if (conf->ascii_lines) {
- ls = rs = '|';
- ts = bs = '-';
- tl = tr = bl = br = ltee = rtee = '+';
+ setcchar(&hline, L"|", 0, 0, NULL);
+ ls = rs = &hline;
+ setcchar(&vline, L"-", 0, 0, NULL);
+ ts = bs = &vline;
+ setcchar(&corner, L"+", 0, 0, NULL);
+ tl = tr = bl = br = &corner;
} else {
- ls = rs = ACS_VLINE;
- ts = bs = ACS_HLINE;
- tl = ACS_ULCORNER;
- tr = ACS_URCORNER;
- bl = ACS_LLCORNER;
- br = ACS_LRCORNER;
- ltee = ACS_LTEE;
- rtee = ACS_RTEE;
+ ls = rs = WACS_VLINE;
+ ts = bs = WACS_HLINE;
+ tl = WACS_ULCORNER;
+ tr = WACS_URCORNER;
+ bl = WACS_LLCORNER;
+ br = WACS_LRCORNER;
}
- leftcolor = elev == RAISED ?
+ getmaxyx(win, h, w);
+ leftcolor = (elev == RAISED) ?
t.dialog.lineraisecolor : t.dialog.linelowercolor;
- rightcolor = elev == RAISED ?
+ rightcolor = (elev == RAISED) ?
t.dialog.linelowercolor : t.dialog.lineraisecolor;
+
wattron(win, leftcolor);
- wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
+ wborder_set(win, ls, rs, ts, bs, tl, tr, bl, br);
wattroff(win, leftcolor);
wattron(win, rightcolor);
- mvwaddch(win, 0, cols-1, tr);
- mvwvline(win, 1, cols-1, rs, rows-2);
- mvwaddch(win, rows-1, cols-1, br);
- mvwhline(win, rows-1, 1, bs, cols-2);
+ mvwadd_wch(win, 0, w-1, tr);
+ mvwvline_set(win, 1, w-1, rs, h-2);
+ mvwadd_wch(win, h-1, w-1, br);
+ mvwhline_set(win, h-1, 1, bs, w-2);
wattroff(win, rightcolor);
}
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
enum elevation elev)
{
- WINDOW *win;
+ wclear(win);
+ wresize(win, h, w);
+ mvwin(win, y, x);
+ draw_borders(conf, win, elev);
+}
- if ((win = newwin(rows, cols, y, x)) == NULL) {
- set_error_string("Cannot build boxed window");
- return (NULL);
- }
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext)
+{
+ pnoutrefresh(d->textpad, ytext, xtext,
+ d->y + BORDER + upnotext,
+ d->x + BORDER + TEXTHMARGIN,
+ d->y + d->h - 1 - downnotext - BORDER,
+ d->x + d->w - TEXTHMARGIN - BORDER);
+}
- wbkgd(win, t.dialog.color);
+/*
+ * -6- Dialog init/build, update/draw, destroy
+ */
+void end_dialog(struct dialog *d)
+{
+ if (d->conf->sleep > 0)
+ sleep(d->conf->sleep);
- draw_borders(conf, win, rows, cols, elev);
+ delwin(d->textpad);
+ delwin(d->widget);
+ if (d->conf->shadow)
+ delwin(d->shadow);
- return (win);
+ if (d->conf->clear)
+ hide_dialog(d);
+
+ if (d->conf->get_height != NULL)
+ *d->conf->get_height = d->h;
+ if (d->conf->get_width != NULL)
+ *d->conf->get_width = d->w;
}
-static int
-draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons)
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
{
- int h, w, ts, ltee, rtee;
+ enum bsddialog_color bg;
+
+ if (is_wtext_attr(wtext) == false)
+ return (false);
+
+ if ((wtext[2] >= L'0') && (wtext[2] <= L'7')) {
+ bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
+ wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
+ return (true);
+ }
- ts = conf->ascii_lines ? '-' : ACS_HLINE;
- ltee = conf->ascii_lines ? '+' : ACS_LTEE;
- rtee = conf->ascii_lines ? '+' : ACS_RTEE;
+ switch (wtext[2]) {
+ case L'n':
+ wattron(win, t.dialog.color);
+ wattrset(win, A_NORMAL);
+ break;
+ case L'b':
+ wattron(win, A_BOLD);
+ break;
+ case L'B':
+ wattroff(win, A_BOLD);
+ break;
+ case L'd':
+ wattron(win, A_DIM);
+ break;
+ case L'D':
+ wattroff(win, A_DIM);
+ break;
+ case L'k':
+ wattron(win, A_BLINK);
+ break;
+ case L'K':
+ wattroff(win, A_BLINK);
+ break;
+ case L'r':
+ wattron(win, A_REVERSE);
+ break;
+ case L'R':
+ wattroff(win, A_REVERSE);
+ break;
+ case L's':
+ wattron(win, A_STANDOUT);
+ break;
+ case L'S':
+ wattroff(win, A_STANDOUT);
+ break;
+ case L'u':
+ wattron(win, A_UNDERLINE);
+ break;
+ case L'U':
+ wattroff(win, A_UNDERLINE);
+ break;
+ }
- getmaxyx(widget, h, w);
+ return (true);
+}
- if (conf->shadow)
- wnoutrefresh(shadow);
+static void
+print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
+ bool color)
+{
+ int charwidth, i, j, strlen, strwidth;
+ wchar_t ws[2];
- draw_borders(conf, widget, h, w, RAISED);
+ ws[1] = L'\0';
- if (conf->title != NULL) {
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, 0, w/2-strlen(conf->title)/2-1, rtee);
- wattroff(widget, t.dialog.lineraisecolor);
- }
- wattron(widget, t.dialog.titlecolor);
- mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title);
- wattroff(widget, t.dialog.titlecolor);
- if (t.dialog.delimtitle && conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- waddch(widget, ltee);
- wattroff(widget, t.dialog.lineraisecolor);
+ strlen = wcslen(str);
+ if (color) {
+ strwidth = 0;
+ i=0;
+ while (i < strlen) {
+ if (is_wtext_attr(str+i) == false) {
+ strwidth += wcwidth(str[i]);
+ i++;
+ } else {
+ i += 3;
+ }
}
- }
+ } else
+ strwidth = wcswidth(str, strlen);
- if (bs != NULL) {
- if (conf->no_lines == false) {
- wattron(widget, t.dialog.lineraisecolor);
- mvwaddch(widget, h-3, 0, ltee);
- mvwhline(widget, h-3, 1, ts, w-2);
- wattroff(widget, t.dialog.lineraisecolor);
+ i = 0;
+ while (i < strlen) {
+ if (*x + strwidth > cols) {
+ if (*x != 0)
+ *y = *y + 1;
+ if (*y >= *rows) {
+ *rows = *y + 1;
+ wresize(win, *rows, cols);
+ }
+ *x = 0;
+ }
+ j = *x;
+ while (i < strlen) {
+ if (color && check_set_wtext_attr(win, str+i)) {
+ i += 3;
+ continue;
+ }
- wattron(widget, t.dialog.linelowercolor);
- mvwaddch(widget, h-3, w-1, rtee);
- wattroff(widget, t.dialog.linelowercolor);
+ charwidth = wcwidth(str[i]);
+ if (j + wcwidth(str[i]) > cols)
+ break;
+ /* inline mvwaddwch() for efficiency */
+ ws[0] = str[i];
+ mvwaddwstr(win, *y, j, ws);
+ strwidth -= charwidth;
+ j += charwidth;
+ *x = j;
+ i++;
}
- draw_buttons(widget, *bs, shortcutbuttons);
}
+}
- if (conf->bottomtitle != NULL) {
- wattron(widget, t.dialog.bottomtitlecolor);
- wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1);
- waddch(widget, ' ');
- waddstr(widget, conf->bottomtitle);
- waddch(widget, ' ');
- wattroff(widget, t.dialog.bottomtitlecolor);
- }
+static int
+print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
+{
+ bool loop;
+ int i, j, z, rows, cols, x, y, tablen;
+ wchar_t *wtext, *string;
- wnoutrefresh(widget);
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- if (textpad != NULL && text != NULL) /* textbox */
- if (print_textpad(conf, textpad, text) !=0)
- return (BSDDIALOG_ERROR);
+ if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
+ RETURN_ERROR("Cannot build (analyze) text");
- return (0);
-}
+ getmaxyx(pad, rows, cols);
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
-int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons)
-{
- int error;
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = wtext[i];
- if (conf->shadow) {
- wclear(shadow);
- mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
- wresize(shadow, h, w);
- }
+ if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
+ string[j] = L'\0';
+ print_string(pad, &rows, cols, &y, &x, string,
+ conf->text.escape);
+ }
- wclear(widget);
- mvwin(widget, y, x);
- wresize(widget, h, w);
+ switch (wtext[i]) {
+ case L'\0':
+ loop = false;
+ break;
+ case L'\n':
+ x = 0;
+ y++;
+ j = -1;
+ break;
+ case L'\t':
+ for (z = 0; z < tablen; z++) {
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ x++;
+ }
+ j = -1;
+ break;
+ case L' ':
+ x++;
+ if (x >= cols) {
+ x = 0;
+ y++;
+ }
+ j = -1;
+ }
- if (textpad != NULL) {
- wclear(textpad);
- wresize(textpad, 1, w - HBORDERS - TEXTHMARGINS);
+ if (y >= rows) {
+ rows = y + 1;
+ wresize(pad, rows, cols);
+ }
+
+ j++;
+ i++;
}
- error = draw_dialog(conf, shadow, widget, textpad, text, bs,
- shortcutbuttons);
+ free(wtext);
+ free(string);
- return (error);
+ return (0);
}
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons)
+int draw_dialog(struct dialog *d)
{
- int error;
+ int wtitle, wbottomtitle;
+ cchar_t ts, ltee, rtee;
- if (conf->shadow) {
- *shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w);
- if (*shadow == NULL)
- RETURN_ERROR("Cannot build shadow");
- wbkgd(*shadow, t.shadow.color);
+ if (d->conf->ascii_lines) {
+ setcchar(&ts, L"-", 0, 0, NULL);
+ setcchar(&ltee, L"+", 0, 0,NULL);
+ setcchar(&rtee, L"+", 0, 0, NULL);
+ } else {
+ ts = *WACS_HLINE;
+ ltee = *WACS_LTEE;
+ rtee = *WACS_RTEE;
}
- if ((*widget = new_boxed_window(conf, y, x, h, w, RAISED)) == NULL) {
- if (conf->shadow)
- delwin(*shadow);
- return (BSDDIALOG_ERROR);
+ if (d->conf->shadow) {
+ wclear(d->shadow);
+ wresize(d->shadow, d->h, d->w);
+ mvwin(d->shadow, d->y + t.shadow.y, d->x + t.shadow.x);
+ wnoutrefresh(d->shadow);
}
- if (textpad != NULL && text != NULL) { /* textbox */
- *textpad = newpad(1, w - HBORDERS - TEXTHMARGINS);
- if (*textpad == NULL) {
- delwin(*widget);
- if (conf->shadow)
- delwin(*shadow);
- RETURN_ERROR("Cannot build the pad window for text");
+ wclear(d->widget);
+ wresize(d->widget, d->h, d->w);
+ mvwin(d->widget, d->y, d->x);
+ draw_borders(d->conf, d->widget, RAISED);
+
+ if (d->conf->title != NULL) {
+ if ((wtitle = strcols(d->conf->title)) < 0)
+ return (BSDDIALOG_ERROR);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwadd_wch(d->widget, 0, d->w/2 - wtitle/2 -1, &rtee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+ wattron(d->widget, t.dialog.titlecolor);
+ mvwaddstr(d->widget, 0, d->w/2 - wtitle/2, d->conf->title);
+ wattroff(d->widget, t.dialog.titlecolor);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ wadd_wch(d->widget, &ltee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
}
- wbkgd(*textpad, t.dialog.color);
}
- error = draw_dialog(conf, *shadow, *widget,
- textpad == NULL ? NULL : *textpad, text, bs, shortcutbuttons);
+ if (d->bs.nbuttons > 0) {
+ if (d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwadd_wch(d->widget, d->h-3, 0, &ltee);
+ mvwhline_set(d->widget, d->h-3, 1, &ts, d->w-2);
+ wattroff(d->widget, t.dialog.lineraisecolor);
- return (error);
-}
+ wattron(d->widget, t.dialog.linelowercolor);
+ mvwadd_wch(d->widget, d->h-3, d->w-1, &rtee);
+ wattroff(d->widget, t.dialog.linelowercolor);
+ }
+ draw_buttons(d);
+ }
-void
-end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad)
-{
- int y, x, h, w;
+ if (d->conf->bottomtitle != NULL) {
+ if ((wbottomtitle = strcols(d->conf->bottomtitle)) < 0)
+ return (BSDDIALOG_ERROR);
+ wattron(d->widget, t.dialog.bottomtitlecolor);
+ wmove(d->widget, d->h - 1, d->w/2 - wbottomtitle/2 - 1);
+ waddch(d->widget, ' ');
+ waddstr(d->widget, d->conf->bottomtitle);
+ waddch(d->widget, ' ');
+ wattroff(d->widget, t.dialog.bottomtitlecolor);
+ }
- getbegyx(widget, y, x);
- getmaxyx(widget, h, w);
+ wnoutrefresh(d->widget);
- if (conf->sleep > 0)
- sleep(conf->sleep);
+ wclear(d->textpad);
+ /* `infobox "" 0 2` fails but text is empty and textpad remains 1 1 */
+ wresize(d->textpad, 1, d->w - BORDERS - TEXTHMARGINS);
- if (textpad != NULL)
- delwin(textpad);
+ if (print_textpad(d->conf, d->textpad, d->text) != 0)
+ return (BSDDIALOG_ERROR);
- delwin(widget);
+ d->built = true;
- if (conf->shadow)
- delwin(shadow);
+ return (0);
+}
- if (conf->clear)
- hide_widget(y, x, h, w, conf->shadow);
+int
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d)
+{
+ CHECK_PTR(conf);
+
+ d->built = false;
+ d->conf = conf;
+ d->rows = rows;
+ d->cols = cols;
+ d->text = CHECK_STR(text);
+ d->bs.nbuttons = 0;
+
+ if (d->conf->shadow) {
+ if ((d->shadow = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW shadow");
+ wbkgd(d->shadow, t.shadow.color);
+ }
- if (conf->get_height != NULL)
- *conf->get_height = h;
- if (conf->get_width != NULL)
- *conf->get_width = w;
-}
+ if ((d->widget = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW widget");
+ wbkgd(d->widget, t.dialog.color);
+
+ /* fake for textpad */
+ if ((d->textpad = newpad(1, 1)) == NULL)
+ RETURN_ERROR("Cannot build the pad WINDOW for text");
+ wbkgd(d->textpad, t.dialog.color);
+
+ return (0);
+} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/lib_util.h b/contrib/bsddialog/lib/lib_util.h
index 6ebc73cf1055..526f65b4bfaa 100644
--- a/contrib/bsddialog/lib/lib_util.h
+++ b/contrib/bsddialog/lib/lib_util.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,106 +28,141 @@
#ifndef _LIBBSDDIALOG_UTIL_H_
#define _LIBBSDDIALOG_UTIL_H_
-#define HBORDERS 2
-#define VBORDERS 2
+#define BORDER 1
+#define BORDERS (BORDER + BORDER)
#define TEXTHMARGIN 1
#define TEXTHMARGINS (TEXTHMARGIN + TEXTHMARGIN)
+#define HBUTTONS 2
+#define OK_LABEL "OK"
+#define CANCEL_LABEL "Cancel"
-/* current theme */
+/* theme util */
extern struct bsddialog_theme t;
+extern bool hastermcolors;
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
/* debug */
-#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
- mvprintw(y, x, fmt, __VA_ARGS__); \
- refresh(); \
+#define BSDDIALOG_DEBUG(y,x,fmt, ...) do { \
+ mvprintw(y, x, fmt, __VA_ARGS__); \
+ refresh(); \
} while (0)
-
-/* error buffer */
-const char *get_error_string(void);
-void set_error_string(const char *string);
-
-#define RETURN_ERROR(str) do { \
- set_error_string(str); \
- return (BSDDIALOG_ERROR); \
+/* error and diagnostic */
+#define RETURN_ERROR(str) do { \
+ set_error_string(str); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+#define RETURN_FMTERROR(fmt, ...) do { \
+ set_fmt_error_string(fmt, __VA_ARGS__); \
+ return (BSDDIALOG_ERROR); \
+} while (0)
+/* check ptr */
+#define CHECK_PTR(p) do { \
+ if (p == NULL) \
+ RETURN_ERROR("*" #p " is NULL"); \
+} while (0)
+#define CHECK_ARRAY(nitem, a) do { \
+ if (nitem > 0 && a == NULL) \
+ RETURN_FMTERROR(#nitem " is %d but *" #a " is NULL", nitem); \
+} while (0)
+/* widget utils */
+#define KEY_CTRL(c) (c & 037)
+#define TEXTPAD(d, downnotext) rtextpad(d, 0, 0, 0, downnotext)
+#define SCREENLINES (getmaxy(stdscr))
+#define SCREENCOLS (getmaxx(stdscr))
+#define CHECK_STR(s) (s == NULL ? "" : s)
+#define UARROW(c) (c->ascii_lines ? '^' : ACS_UARROW)
+#define DARROW(c) (c->ascii_lines ? 'v' : ACS_DARROW)
+#define LARROW(c) (c->ascii_lines ? '<' : ACS_LARROW)
+#define RARROW(c) (c->ascii_lines ? '>' : ACS_RARROW)
+#define DRAW_BUTTONS(d) do { \
+ draw_buttons(&d); \
+ wnoutrefresh(d.widget); \
} while (0)
-/* buttons */
+/* internal types */
+enum elevation { RAISED, LOWERED };
+
struct buttons {
unsigned int nbuttons;
-#define MAXBUTTONS 6 /* ok + extra + cancel + help + 2 generics */
+#define MAXBUTTONS 10 /* 3left + ok + extra + cancel + help + 3 right */
const char *label[MAXBUTTONS];
+ bool shortcut;
+ wchar_t first[MAXBUTTONS];
int value[MAXBUTTONS];
int curr;
+#define BUTTONVALUE(bs) bs.value[bs.curr]
unsigned int sizebutton; /* including left and right delimiters */
};
-#define BUTTON_OK_LABEL "OK"
-#define BUTTON_CANCEL_LABEL "Cancel"
-void
-get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
- const char *yesoklabel, const char *nocancellabel);
-
-void
-draw_buttons(WINDOW *window, struct buttons bs, bool shortcut);
-
-int buttons_width(struct buttons bs);
-bool shortcut_buttons(int key, struct buttons *bs);
+struct dialog {
+ bool built; /* true after the first draw_dialog() */
+ struct bsddialog_conf *conf; /* Checked API conf */
+ WINDOW *widget; /* Size and position refer to widget */
+ int y, x; /* Current position, API conf.[y|x]: -1, >=0 */
+ int rows, cols; /* API rows and cols: -1, 0, >0 */
+ int h, w; /* Current height and width */
+ const char *text; /* Checked API text, at least "" */
+ WINDOW *textpad; /* Fake for textbox */
+ struct buttons bs; /* bs.nbuttons = 0 for no buttons */
+ WINDOW *shadow;
+};
-/* help window with F1 key */
-int f1help(struct bsddialog_conf *conf);
+/* error and diagnostic */
+const char *get_error_string(void);
+void set_error_string(const char *string);
+void set_fmt_error_string(const char *fmt, ...);
-/* cleaner */
-int hide_widget(int y, int x, int h, int w, bool withshadow);
+/* multicolumn character string */
+unsigned int strcols(const char *mbstring);
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col);
+void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch);
+wchar_t* alloc_mbstows(const char *mbstring);
-/* (auto) size and (auto) position */
-#define SCREENLINES (getmaxy(stdscr))
-#define SCREENCOLS (getmaxx(stdscr))
+/* buttons */
+void
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *canclabel);
+void draw_buttons(struct dialog *d);
+bool shortcut_buttons(wint_t key, struct buttons *bs);
-int
-text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
- struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext);
+/* widget utils */
+int hide_dialog(struct dialog *d);
+int f1help_dialog(struct bsddialog_conf *conf);
-int widget_max_height(struct bsddialog_conf *conf);
-int widget_max_width(struct bsddialog_conf *conf);
+void
+draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev);
-int
-widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
- bool withbuttons);
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev);
-int
-widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
- struct buttons *bs);
+void
+rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext);
+/* (auto) sizing and (auto) position */
int
set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h,
int *w);
int
-set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
+set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
+ int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
+ int minw);
-/* widget builders */
-enum elevation { RAISED, LOWERED };
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw);
-void
-draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
- enum elevation elev);
+int
+set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w);
-WINDOW *
-new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
- enum elevation elev);
+int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext);
-int
-new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
- int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
- bool shortcutbuttons);
+/* dialog */
+void end_dialog(struct dialog *d);
+int draw_dialog(struct dialog *d);
int
-update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- int y, int x, int h, int w, WINDOW *textpad, const char *text,
- struct buttons *bs, bool shortcutbuttons);
-
-void
-end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
- WINDOW *textpad);
+prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols, struct dialog *d);
-#endif \ No newline at end of file
+#endif
diff --git a/contrib/bsddialog/lib/libbsddialog.c b/contrib/bsddialog/lib/libbsddialog.c
index 761bdc3efa77..555d060ebcbd 100644
--- a/contrib/bsddialog/lib/libbsddialog.c
+++ b/contrib/bsddialog/lib/libbsddialog.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,18 +26,19 @@
*/
#include <curses.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-int bsddialog_init(void)
+#define DEFAULT_COLS_PER_ROW 10 /* Default conf.text.columns_per_row */
+
+static bool in_bsddialog_mode = false;
+
+int bsddialog_init_notheme(void)
{
int i, j, c, error;
- enum bsddialog_default_theme theme;
set_error_string("");
@@ -54,6 +55,7 @@ int bsddialog_init(void)
bsddialog_end();
RETURN_ERROR("Cannot init curses (keypad and cursor)");
}
+ in_bsddialog_mode = true;
c = 1;
error += start_color();
@@ -64,13 +66,25 @@ 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;
if (bsddialog_set_default_theme(theme) != 0) {
bsddialog_end();
+ in_bsddialog_mode = false;
return (BSDDIALOG_ERROR);
}
@@ -81,22 +95,35 @@ int bsddialog_end(void)
{
if (endwin() != OK)
RETURN_ERROR("Cannot end curses (endwin)");
+ in_bsddialog_mode = false;
return (BSDDIALOG_OK);
}
int bsddialog_backtitle(struct bsddialog_conf *conf, const char *backtitle)
{
- mvaddstr(0, 1, backtitle);
- if (conf->no_lines != true)
- mvhline(1, 1, conf->ascii_lines ? '-' : ACS_HLINE,
- SCREENCOLS - 2);
+ CHECK_PTR(conf);
+
+ move(0, 1);
+ clrtoeol();
+ addstr(CHECK_STR(backtitle));
+ if (conf->no_lines != true) {
+ if (conf->ascii_lines)
+ mvhline(1, 1, '-', SCREENCOLS - 2);
+ else
+ mvhline_set(1, 1, WACS_HLINE, SCREENCOLS - 2);
+ }
refresh();
return (BSDDIALOG_OK);
}
+bool bsddialog_inmode(void)
+{
+ return (in_bsddialog_mode);
+}
+
const char *bsddialog_geterror(void)
{
return (get_error_string());
@@ -104,24 +131,25 @@ const char *bsddialog_geterror(void)
int bsddialog_initconf(struct bsddialog_conf *conf)
{
- if (conf == NULL)
- RETURN_ERROR("conf is NULL");
- if (sizeof(*conf) != sizeof(struct bsddialog_conf))
- RETURN_ERROR("Bad conf size");
+ CHECK_PTR(conf);
memset(conf, 0, sizeof(struct bsddialog_conf));
conf->y = BSDDIALOG_CENTER;
conf->x = BSDDIALOG_CENTER;
conf->shadow = true;
+ conf->text.cols_per_row = DEFAULT_COLS_PER_ROW;
return (BSDDIALOG_OK);
}
-int bsddialog_clearterminal(void)
+void bsddialog_refresh(void)
{
- if (clear() != OK)
- RETURN_ERROR("Cannot clear the terminal");
refresh();
+}
- return (BSDDIALOG_OK);
+void bsddialog_clear(unsigned int y)
+{
+ move(y, 0);
+ clrtobot();
+ refresh();
} \ No newline at end of file
diff --git a/contrib/bsddialog/lib/menubox.c b/contrib/bsddialog/lib/menubox.c
index 22ed15e6e7a0..896306b2881d 100644
--- a/contrib/bsddialog/lib/menubox.c
+++ b/contrib/bsddialog/lib/menubox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,20 +25,13 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
#include <stdlib.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-#define DEPTH 2
-#define MIN_HEIGHT VBORDERS + 6 /* 2 buttons 1 text 3 menu */
-
enum menumode {
CHECKLISTMODE,
MENUMODE,
@@ -47,47 +40,155 @@ enum menumode {
SEPARATORMODE
};
-struct lineposition {
- unsigned int maxsepstr;
- unsigned int maxprefix;
- unsigned int xselector;
- unsigned int selectorlen;
- unsigned int maxdepth;
- unsigned int xname;
- unsigned int maxname;
- unsigned int xdesc;
- unsigned int maxdesc;
- unsigned int line;
-};
-
struct privateitem {
- bool on;
- int group;
- int index;
+ const char *prefix;
+ bool on; /* menu changes, not API on */
+ unsigned int depth;
+ const char *name;
+ const char *desc;
+ const char *bottomdesc;
+ int group; /* index menu in menugroup */
+ int index; /* real item index inside its menu */
enum menumode type;
- struct bsddialog_menuitem *item;
+ wchar_t shortcut;
};
-static void
-set_on_output(struct bsddialog_conf *conf, int output, int ngroups,
- struct bsddialog_menugroup *groups, struct privateitem *pritems)
+struct privatemenu {
+ WINDOW *box; /* only for borders */
+ WINDOW *pad; /* pad for the private items */
+ int ypad; /* start pad line */
+ int ys, ye, xs, xe; /* pad pos */
+ unsigned int xselector; /* [] */
+ unsigned int xname; /* real x: xname + item.depth */
+ unsigned int xdesc; /* real x: xdesc + item.depth */
+ unsigned int line; /* wpad: prefix [] depth name desc */
+ unsigned int apimenurows;
+ unsigned int menurows; /* real menurows after menu_size_position() */
+ int nitems; /* total nitems (all groups * all items) */
+ struct privateitem *pritems;
+ int sel; /* current focus item, can be -1 */
+ bool hasbottomdesc;
+};
+
+static enum menumode
+getmode(enum menumode mode, struct bsddialog_menugroup group)
{
+ if (mode == MIXEDLISTMODE) {
+ if (group.type == BSDDIALOG_SEPARATOR)
+ mode = SEPARATORMODE;
+ else if (group.type == BSDDIALOG_RADIOLIST)
+ mode = RADIOLISTMODE;
+ else if (group.type == BSDDIALOG_CHECKLIST)
+ mode = CHECKLISTMODE;
+ }
+
+ return (mode);
+}
+
+static int
+build_privatemenu(struct bsddialog_conf *conf, struct privatemenu *m,
+ enum menumode mode, unsigned int ngroups,
+ struct bsddialog_menugroup *groups)
+{
+ bool onetrue;
int i, j, abs;
+ unsigned int maxsepstr, maxprefix, selectorlen, maxdepth;
+ unsigned int maxname, maxdesc;
+ struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- if (output != BSDDIALOG_OK && !conf->menu.on_without_ok)
- return;
+ /* nitems and fault checks */
+ CHECK_ARRAY(ngroups, groups);
+ m->nitems = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ CHECK_ARRAY(groups[i].nitems, groups[i].items);
+ m->nitems += (int)groups[i].nitems;
+ }
- for(i = abs = 0; i < ngroups; i++) {
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- abs += groups[i].nitems;
- continue;
- }
+ /* alloc and set private items */
+ m->pritems = calloc(m->nitems, sizeof (struct privateitem));
+ if (m->pritems == NULL)
+ RETURN_ERROR("Cannot allocate memory for internal menu items");
+ m->hasbottomdesc = false;
+ abs = 0;
+ for (i = 0; i < (int)ngroups; i++) {
+ onetrue = false;
+ for (j = 0; j < (int)groups[i].nitems; j++) {
+ item = &groups[i].items[j];
+ pritem = &m->pritems[abs];
+
+ if (getmode(mode, groups[i]) == MENUMODE) {
+ m->pritems[abs].on = false;
+ } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
+ m->pritems[abs].on = onetrue ? false : item->on;
+ if (m->pritems[abs].on)
+ onetrue = true;
+ } else { /* CHECKLISTMODE */
+ m->pritems[abs].on = item->on;
+ }
+ pritem->group = i;
+ pritem->index = j;
+ pritem->type = getmode(mode, groups[i]);
+
+ pritem->prefix = CHECK_STR(item->prefix);
+ pritem->depth = item->depth;
+ pritem->name = CHECK_STR(item->name);
+ pritem->desc = CHECK_STR(item->desc);
+ pritem->bottomdesc = CHECK_STR(item->bottomdesc);
+ if (item->bottomdesc != NULL)
+ m->hasbottomdesc = true;
+
+ mbtowc(&pritem->shortcut, conf->menu.no_name ?
+ pritem->desc : pritem->name, MB_CUR_MAX);
- for(j = 0; j < (int)groups[i].nitems; j++) {
- groups[i].items[j].on = pritems[abs].on;
abs++;
}
}
+
+ /* positions */
+ m->xselector = m->xname = m->xdesc = m->line = 0;
+ maxsepstr = maxprefix = selectorlen = maxdepth = maxname = maxdesc = 0;
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == RADIOLISTMODE ||
+ m->pritems[i].type == CHECKLISTMODE)
+ selectorlen = 4;
+
+ if (m->pritems[i].type == SEPARATORMODE) {
+ maxsepstr = MAX(maxsepstr,
+ strcols(m->pritems[i].name) +
+ strcols(m->pritems[i].desc));
+ continue;
+ }
+
+ maxprefix = MAX(maxprefix, strcols(m->pritems[i].prefix));
+ maxdepth = MAX(maxdepth, m->pritems[i].depth);
+ maxname = MAX(maxname, strcols(m->pritems[i].name));
+ maxdesc = MAX(maxdesc, strcols(m->pritems[i].desc));
+ }
+ maxname = conf->menu.no_name ? 0 : maxname;
+ maxdesc = conf->menu.no_desc ? 0 : maxdesc;
+
+ m->xselector = maxprefix + (maxprefix != 0 ? 1 : 0);
+ m->xname = m->xselector + selectorlen;
+ m->xdesc = maxdepth + m->xname + maxname;
+ m->xdesc += (maxname != 0 ? 1 : 0);
+ m->line = MAX(maxsepstr + 3, m->xdesc + maxdesc);
+
+ return (0);
+}
+
+static void
+set_return_on(struct privatemenu *m, struct bsddialog_menugroup *groups)
+{
+ int i;
+ struct privateitem *pritem;
+
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type == SEPARATORMODE)
+ continue;
+ pritem = &m->pritems[i];
+ groups[pritem->group].items[pritem->index].on = pritem->on;
+ }
}
static int getprev(struct privateitem *pritems, int abs)
@@ -176,25 +277,17 @@ getfastprev(int menurows, struct privateitem *pritems, int abs)
}
static int
-getnextshortcut(struct bsddialog_conf *conf, int npritems,
- struct privateitem *pritems, int abs, int key)
+getnextshortcut(int npritems, struct privateitem *pritems, int abs, wint_t key)
{
- int i, ch, next;
+ int i, next;
next = -1;
for (i = 0; i < npritems; i++) {
if (pritems[i].type == SEPARATORMODE)
continue;
-
- if (conf->menu.no_name)
- ch = pritems[i].item->desc[0];
- else
- ch = pritems[i].item->name[0];
-
- if (ch == key) {
+ if (pritems[i].shortcut == (wchar_t)key) {
if (i > abs)
return (i);
-
if (i < abs && next == -1)
next = i;
}
@@ -203,81 +296,66 @@ getnextshortcut(struct bsddialog_conf *conf, int npritems,
return (next != -1 ? next : abs);
}
-static enum menumode
-getmode(enum menumode mode, struct bsddialog_menugroup group)
-{
- if (mode == MIXEDLISTMODE) {
- if (group.type == BSDDIALOG_SEPARATOR)
- mode = SEPARATORMODE;
- else if (group.type == BSDDIALOG_RADIOLIST)
- mode = RADIOLISTMODE;
- else if (group.type == BSDDIALOG_CHECKLIST)
- mode = CHECKLISTMODE;
- }
-
- return (mode);
-}
-
-static void
-drawseparators(struct bsddialog_conf *conf, WINDOW *pad, int linelen,
- int nitems, struct privateitem *pritems)
+static void drawseparators(struct bsddialog_conf *conf, struct privatemenu *m)
{
- int i, linech, labellen;
+ int i, realw, labellen;
const char *desc, *name;
- for (i = 0; i < nitems; i++) {
- if (pritems[i].type != SEPARATORMODE)
+ for (i = 0; i < m->nitems; i++) {
+ if (m->pritems[i].type != SEPARATORMODE)
continue;
if (conf->no_lines == false) {
- wattron(pad, t.menu.desccolor);
- linech = conf->ascii_lines ? '-' : ACS_HLINE;
- mvwhline(pad, i, 0, linech, linelen);
- wattroff(pad, t.menu.desccolor);
+ wattron(m->pad, t.menu.desccolor);
+ if (conf->ascii_lines)
+ mvwhline(m->pad, i, 0, '-', m->line);
+ else
+ mvwhline_set(m->pad, i, 0, WACS_HLINE, m->line);
+ wattroff(m->pad, t.menu.desccolor);
}
- name = pritems[i].item->name;
- desc = pritems[i].item->desc;
- labellen = strlen(name) + strlen(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)
- waddch(pad, ' ');
- wattron(pad, t.menu.descsepcolor);
- waddstr(pad, desc);
- wattroff(pad, t.menu.descsepcolor);
+ name = m->pritems[i].name;
+ desc = m->pritems[i].desc;
+ realw = m->xe - m->xs;
+ labellen = strcols(name) + strcols(desc) + 1;
+ wmove(m->pad, i, (labellen < realw) ? realw/2 - labellen/2 : 0);
+ wattron(m->pad, t.menu.sepnamecolor);
+ waddstr(m->pad, name);
+ wattroff(m->pad, t.menu.sepnamecolor);
+ if (strcols(name) > 0 && strcols(desc) > 0)
+ waddch(m->pad, ' ');
+ wattron(m->pad, t.menu.sepdesccolor);
+ waddstr(m->pad, desc);
+ wattroff(m->pad, t.menu.sepdesccolor);
}
}
static void
-drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
- struct lineposition pos, struct privateitem *pritem, bool focus)
+drawitem(struct bsddialog_conf *conf, struct privatemenu *m, int y, bool focus)
{
int colordesc, colorname, colorshortcut;
- const char *shortcut;
- struct bsddialog_menuitem *item;
+ struct privateitem *pritem;
- item = pritem->item;
+ pritem = &m->pritems[y];
/* prefix */
- if (item->prefix != NULL && item->prefix[0] != '\0')
- mvwaddstr(pad, y, 0, item->prefix);
+ wattron(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
+ mvwaddstr(m->pad, y, 0, pritem->prefix);
+ wattroff(m->pad, focus ? t.menu.f_prefixcolor : t.menu.prefixcolor);
/* selector */
- wmove(pad, y, pos.xselector);
- wattron(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wmove(m->pad, y, m->xselector);
+ wattron(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
if (pritem->type == CHECKLISTMODE)
- wprintw(pad, "[%c]", pritem->on ? 'X' : ' ');
+ wprintw(m->pad, "[%c]", pritem->on ? 'X' : ' ');
if (pritem->type == RADIOLISTMODE)
- wprintw(pad, "(%c)", pritem->on ? '*' : ' ');
- wattroff(pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
+ wprintw(m->pad, "(%c)", pritem->on ? '*' : ' ');
+ wattroff(m->pad, focus ? t.menu.f_selectorcolor : t.menu.selectorcolor);
/* name */
colorname = focus ? t.menu.f_namecolor : t.menu.namecolor;
if (conf->menu.no_name == false) {
- wattron(pad, colorname);
- mvwaddstr(pad, y, pos.xname + item->depth * DEPTH, item->name);
- wattroff(pad, colorname);
+ wattron(m->pad, colorname);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth, pritem->name);
+ wattroff(m->pad, colorname);
}
/* description */
@@ -287,145 +365,137 @@ drawitem(struct bsddialog_conf *conf, WINDOW *pad, int y,
colordesc = focus ? t.menu.f_desccolor : t.menu.desccolor;
if (conf->menu.no_desc == false) {
- wattron(pad, colordesc);
+ wattron(m->pad, colordesc);
if (conf->menu.no_name)
- mvwaddstr(pad, y, pos.xname + item->depth * DEPTH,
- item->desc);
+ mvwaddstr(m->pad, y, m->xname + pritem->depth,
+ pritem->desc);
else
- mvwaddstr(pad, y, pos.xdesc, item->desc);
- wattroff(pad, colordesc);
+ mvwaddstr(m->pad, y, m->xdesc, pritem->desc);
+ wattroff(m->pad, colordesc);
}
/* shortcut */
if (conf->menu.shortcut_buttons == false) {
colorshortcut = focus ?
t.menu.f_shortcutcolor : t.menu.shortcutcolor;
- wattron(pad, colorshortcut);
-
- if (conf->menu.no_name)
- shortcut = item->desc;
- 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);
+ wattron(m->pad, colorshortcut);
+ mvwaddwch(m->pad, y, m->xname + pritem->depth, pritem->shortcut);
+ wattroff(m->pad, colorshortcut);
}
/* bottom description */
- move(SCREENLINES - 1, 2);
- clrtoeol();
- if (item->bottomdesc != NULL && focus) {
- addstr(item->bottomdesc);
- refresh();
+ if (m->hasbottomdesc) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ if (focus) {
+ attron(t.menu.bottomdesccolor);
+ addstr(pritem->bottomdesc);
+ attroff(t.menu.bottomdesccolor);
+ refresh();
+ }
}
}
-static int
-menu_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
- const char *text, int linelen, unsigned int *menurows, int nitems,
- struct buttons bs)
+static void update_menubox(struct bsddialog_conf *conf, struct privatemenu *m)
{
- int htext, wtext, menusize, notext;
-
- notext = 2;
- if (*menurows == BSDDIALOG_AUTOSIZE) {
- /* algo 1): grows vertically */
- /* notext = 1; */
- /* algo 2): grows horizontally, better with little screens */
- notext += nitems;
- notext = MIN(notext, widget_max_height(conf) - HBORDERS - 3);
- } else
- notext += *menurows;
-
- /* 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);
- }
+ int h, w;
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, linelen + 4, &bs);
+ draw_borders(conf, m->box, LOWERED);
+ getmaxyx(m->box, h, w);
- if (rows == BSDDIALOG_AUTOSIZE) {
- if (*menurows == 0) {
- menusize = widget_max_height(conf) - HBORDERS -
- 2 /*buttons*/ - htext;
- menusize = MIN(menusize, nitems + 2);
- *menurows = menusize - 2 < 0 ? 0 : menusize - 2;
- }
- else /* h autosize with fixed menurows */
- menusize = *menurows + 2;
-
- *h = widget_min_height(conf, htext, menusize, true);
- /*
- * avoid menurows overflow and
- * with rows=AUTOSIZE menurows!=0 becomes max-menurows
- */
- *menurows = MIN(*h - 6 - htext, (int)*menurows);
- } else {
- if (*menurows == 0)
- *menurows = MIN(*h-6-htext, nitems);
- }
+ if (m->nitems > (int)m->menurows) {
+ wattron(m->box, t.dialog.arrowcolor);
+ if (m->ypad > 0)
+ mvwhline(m->box, 0, 2, UARROW(conf), 3);
- return (0);
+ if ((m->ypad + (int)m->menurows) < m->nitems)
+ mvwhline(m->box, h-1, 2, DARROW(conf), 3);
+
+ mvwprintw(m->box, h-1, w-6, "%3d%%",
+ 100 * (m->ypad + m->menurows) / m->nitems);
+ wattroff(m->box, t.dialog.arrowcolor);
+ }
}
-static int
-menu_checksize(int rows, int cols, const char *text, int menurows, int nitems,
- struct buttons bs)
+static int menu_size_position(struct dialog *d, struct privatemenu *m)
{
- int mincols, textrow, menusize;
+ int htext, hmenu;
- mincols = VBORDERS;
- /* buttons */
- mincols += buttons_width(bs);
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ hmenu = (int)(m->menurows == BSDDIALOG_AUTOSIZE) ?
+ (int)m->nitems : (int)m->menurows;
+ hmenu += 2; /* menu borders */
/*
- * linelen check, comment to allow some hidden col otherwise portconfig
- * could not show big menus like www/apache24
+ * algo 1: notext = 1 (grows vertically).
+ * algo 2: notext = hmenu (grows horizontally, better for little term).
*/
- /* mincols = MAX(mincols, linelen); */
-
- if (cols < mincols)
- RETURN_ERROR("Few cols, width < size buttons or "
- "name + descripion of the items");
-
- textrow = text != NULL && strlen(text) > 0 ? 1 : 0;
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, &htext, &d->bs, hmenu, m->line + 4) != 0)
+ return (BSDDIALOG_ERROR);
+ /* avoid menurows overflow and menurows becomes "at most menurows" */
+ if (d->h - BORDERS - htext - HBUTTONS <= 2 /* menuborders */)
+ m->menurows = (m->nitems > 0) ? 1 : 0; /* widget_checksize() */
+ else
+ m->menurows = MIN(d->h - BORDERS - htext - HBUTTONS, hmenu) - 2;
- if (nitems > 0 && menurows == 0)
- RETURN_ERROR("items > 0 but menurows == 0, probably terminal "
- "too small");
+ /*
+ * no minw=linelen to avoid big menu fault, then some col can be
+ * hidden (example portconfig www/apache24).
+ */
+ if (widget_checksize(d->h, d->w, &d->bs,
+ 2 /* border box */ + MIN(m->menurows, 1), 0) != 0)
+ return (BSDDIALOG_ERROR);
- menusize = nitems > 0 ? 3 : 0;
- if (rows < 2 + 2 + menusize + textrow)
- RETURN_ERROR("Few lines for this menus");
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
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)
+static int mixedlist_redraw(struct dialog *d, struct privatemenu *m)
{
- 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);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
+ m->menurows = m->apimenurows;
+ if (menu_size_position(d, m) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, 2/*bmenu*/ + m->menurows + HBUTTONS);
+
+ /* selected item in view*/
+ if (m->ypad > m->sel && m->ypad > 0)
+ m->ypad = m->sel;
+ if ((int)(m->ypad + m->menurows) <= m->sel)
+ m->ypad = m->sel - m->menurows + 1;
+ /* lower pad after a terminal expansion */
+ if (m->ypad > 0 && (m->nitems - m->ypad) < (int)m->menurows)
+ m->ypad = m->nitems - m->menurows;
+
+ update_box(d->conf, m->box, d->y + d->h - 5 - m->menurows, d->x + 2,
+ m->menurows+2, d->w-4, LOWERED);
+ update_menubox(d->conf, m);
+ wnoutrefresh(m->box);
+
+ m->ys = d->y + d->h - 5 - m->menurows + 1;
+ m->ye = d->y + d->h - 5 ;
+ if (d->conf->menu.align_left || (int)m->line > d->w - 6) {
+ m->xs = d->x + 3;
+ m->xe = m->xs + d->w - 7;
+ } else { /* center */
+ m->xs = d->x + 3 + (d->w-6)/2 - m->line/2;
+ m->xe = m->xs + d->w - 5;
+ }
+ drawseparators(d->conf, m); /* uses xe - xs */
+ pnoutrefresh(m->pad, m->ypad, 0, m->ys, m->xs, m->ye, m->xe);
+
+ return (0);
}
static int
@@ -433,330 +503,192 @@ 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 ymenupad, ys, ye, xs, xe, abs, next, totnitems;
- WINDOW *shadow, *widget, *textpad, *menuwin, *menupad;
- struct buttons bs;
- struct lineposition pos = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- struct bsddialog_menuitem *item;
- struct privateitem *pritems;
-
- shortcut_butts = conf->menu.shortcut_buttons;
-
- automenurows = (menurows == BSDDIALOG_AUTOSIZE) ? true : false;
-
- totnitems = 0;
- for (i = 0; i < (int)ngroups; i++) {
- if (getmode(mode, groups[i]) == RADIOLISTMODE ||
- getmode(mode, groups[i]) == CHECKLISTMODE)
- pos.selectorlen = 3;
-
- for (j = 0; j < (int)groups[i].nitems; j++) {
- totnitems++;
- item = &groups[i].items[j];
-
- if (groups[i].type == BSDDIALOG_SEPARATOR) {
- pos.maxsepstr = MAX(pos.maxsepstr,
- strlen(item->name) + strlen(item->desc));
- continue;
- }
+ bool loop, changeitem;
+ int i, next, retval;
+ wint_t input;
+ struct privatemenu m;
+ struct dialog d;
- pos.maxprefix = MAX(pos.maxprefix,strlen(item->prefix));
- pos.maxdepth = MAX(pos.maxdepth, item->depth);
- pos.maxname = MAX(pos.maxname, strlen(item->name));
- pos.maxdesc = MAX(pos.maxdesc, strlen(item->desc));
- }
- }
- pos.maxname = conf->menu.no_name ? 0 : pos.maxname;
- pos.maxdesc = conf->menu.no_desc ? 0 : pos.maxdesc;
- pos.maxdepth = DEPTH * pos.maxdepth;
-
- pos.xselector = pos.maxprefix + (pos.maxprefix != 0 ? 1 : 0);
- pos.xname = pos.xselector + pos.selectorlen +
- (pos.selectorlen > 0 ? 1 : 0);
- pos.xdesc = pos.maxdepth + pos.xname + pos.maxname;
- pos.xdesc += (pos.maxname != 0 ? 1 : 0);
- pos.line = MAX(pos.maxsepstr + 3, pos.xdesc + pos.maxdesc);
-
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_autosize(conf, rows, cols, &h, &w, text, pos.line, &menurows,
- totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
+ set_buttons(&d, conf->menu.shortcut_buttons, OK_LABEL, CANCEL_LABEL);
+ if (d.conf->menu.no_name && d.conf->menu.no_desc)
+ RETURN_ERROR("Both conf.menu.no_name and conf.menu.no_desc");
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- shortcut_butts) != 0)
+ if (build_privatemenu(conf, &m, mode, ngroups, groups) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
-
- menuwin = new_boxed_window(conf, y + h - 5 - menurows, x + 2,
- menurows+2, w-4, LOWERED);
-
- menupad = newpad(totnitems, pos.line);
- wbkgd(menupad, t.dialog.color);
-
- if ((pritems = calloc(totnitems, sizeof (struct privateitem))) == NULL)
- RETURN_ERROR("Cannot allocate memory for internal menu items");
-
- abs = 0;
- for (i = 0; i < (int)ngroups; i++) {
- onetrue = false;
- for (j = 0; j < (int)groups[i].nitems; j++) {
- item = &groups[i].items[j];
-
- if (getmode(mode, groups[i]) == MENUMODE) {
- pritems[abs].on = false;
- } else if (getmode(mode, groups[i]) == RADIOLISTMODE) {
- pritems[abs].on = onetrue ? false : item->on;
- if (pritems[abs].on)
- onetrue = true;
- } else {
- pritems[abs].on = item->on;
- }
- pritems[abs].group = i;
- pritems[abs].index = j;
- pritems[abs].type = getmode(mode, groups[i]);
- pritems[abs].item = item;
+ if ((m.box = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_ERROR("Cannot build WINDOW box menu");
+ wbkgd(m.box, t.dialog.color);
+ m.pad = newpad(m.nitems, m.line);
+ wbkgd(m.pad, t.dialog.color);
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs++;
- }
- }
- drawseparators(conf, menupad, MIN((int)pos.line, w-6), totnitems,
- pritems);
- abs = getfirst_with_default(totnitems, pritems, ngroups, groups,
+ for (i = 0; i < m.nitems; i++)
+ drawitem(conf, &m, i, false);
+ m.sel = getfirst_with_default(m.nitems, m.pritems, ngroups, groups,
focuslist, focusitem);
- if (abs >= 0)
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- ymenupad = 0;
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4, totnitems, menurows,
- ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ if (m.sel >= 0)
+ drawitem(d.conf, &m, m.sel, true);
+ m.ypad = 0;
+ m.apimenurows = menurows;
+ if (mixedlist_redraw(&d, &m) != 0)
+ return (BSDDIALOG_ERROR);
- movefocus = false;
+ changeitem = false;
loop = true;
while (loop) {
- input = getch();
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups, pritems);
+ retval = BUTTONVALUE(d.bs);
+ if (m.sel >= 0 && m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
- if (abs >= 0 && pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups, groups,
- pritems);
+ retval = BSDDIALOG_ESC;
+ if (m.sel >= 0 &&
+ m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
- break;
- case KEY_RIGHT:
- if (bs.curr < (int) bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, shortcut_butts);
- wrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- menurows = automenurows ? 0 : menurows;
- if (menu_autosize(conf, rows, cols, &h, &w, text,
- pos.line, &menurows, totnitems, bs) != 0)
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
- if (menu_checksize(h, w, text, menurows, totnitems,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, shortcut_butts) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (mixedlist_redraw(&d, &m) != 0)
return (BSDDIALOG_ERROR);
-
- doupdate();
-
- prefresh(textpad, 0, 0, y + 1, x + 1 + TEXTHMARGIN,
- y + h - menurows, x + 1 + w - TEXTHMARGIN);
-
- wclear(menuwin);
- mvwin(menuwin, y + h - 5 - menurows, x + 2);
- wresize(menuwin,menurows+2, w-4);
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
-
- ys = y + h - 5 - menurows + 1;
- ye = y + h - 5 ;
- if (conf->menu.align_left || (int)pos.line > w - 6) {
- xs = x + 3;
- xe = xs + w - 7;
- } else { /* center */
- xs = x + 3 + (w-6)/2 - pos.line/2;
- xe = xs + w - 5;
- }
-
- drawseparators(conf, menupad, MIN((int)pos.line, w-6),
- totnitems, pritems);
-
- if ((int)(ymenupad + menurows) - 1 < abs)
- ymenupad = abs - menurows + 1;
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
-
- refresh();
-
break;
}
- if (abs < 0)
+ if (m.sel < 0)
continue;
switch(input) {
case KEY_HOME:
- next = getnext(totnitems, pritems, -1);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, -1);
+ changeitem = next != m.sel;
break;
+ case '-':
+ case KEY_CTRL('p'):
case KEY_UP:
- next = getprev(pritems, abs);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_PPAGE:
- next = getfastprev(menurows, pritems, abs);
- movefocus = next != abs;
+ next = getfastprev(m.menurows, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_END:
- next = getprev(pritems, totnitems);
- movefocus = next != abs;
+ next = getprev(m.pritems, m.nitems);
+ changeitem = next != m.sel;
break;
+ case '+':
+ case KEY_CTRL('n'):
case KEY_DOWN:
- next = getnext(totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getnext(m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case KEY_NPAGE:
- next = getfastnext(menurows, totnitems, pritems, abs);
- movefocus = next != abs;
+ next = getfastnext(m.menurows, m.nitems, m.pritems, m.sel);
+ changeitem = next != m.sel;
break;
case ' ': /* Space */
- if (pritems[abs].type == MENUMODE)
- break;
- else if (pritems[abs].type == CHECKLISTMODE)
- pritems[abs].on = !pritems[abs].on;
- else { /* RADIOLISTMODE */
- for (i = abs - pritems[abs].index;
- i < totnitems &&
- pritems[i].group == pritems[abs].group;
+ if (m.pritems[m.sel].type == MENUMODE) {
+ retval = BUTTONVALUE(d.bs);
+ m.pritems[m.sel].on = true;
+ loop = false;
+ } else if (m.pritems[m.sel].type == CHECKLISTMODE) {
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
+ } else { /* RADIOLISTMODE */
+ for (i = m.sel - m.pritems[m.sel].index;
+ i < m.nitems &&
+ m.pritems[i].group == m.pritems[m.sel].group;
i++) {
- if (i != abs && pritems[i].on) {
- pritems[i].on = false;
- drawitem(conf, menupad, i, pos,
- &pritems[i], false);
+ if (i != m.sel && m.pritems[i].on) {
+ m.pritems[i].on = false;
+ drawitem(conf, &m, i, false);
}
}
- pritems[abs].on = !pritems[abs].on;
+ m.pritems[m.sel].on = !m.pritems[m.sel].on;
}
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
+ drawitem(conf, &m, m.sel, true);
+ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
break;
default:
- if (shortcut_butts) {
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
- if (pritems[abs].type == MENUMODE)
- pritems[abs].on = true;
- set_on_output(conf, output, ngroups,
- groups, pritems);
+ if (conf->menu.shortcut_buttons) {
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ if (m.pritems[m.sel].type == MENUMODE)
+ m.pritems[m.sel].on = true;
loop = false;
}
break;
}
/* shourtcut items */
- next = getnextshortcut(conf, totnitems, pritems, abs,
+ next = getnextshortcut(m.nitems, m.pritems, m.sel,
input);
- movefocus = next != abs;
+ changeitem = next != m.sel;
+ } /* end switch get_wch() */
+
+ if (changeitem) {
+ drawitem(conf, &m, m.sel, false);
+ m.sel = next;
+ drawitem(conf, &m, m.sel, true);
+ if (m.ypad > m.sel && m.ypad > 0)
+ m.ypad = m.sel;
+ if ((int)(m.ypad + m.menurows) <= m.sel)
+ m.ypad = m.sel - m.menurows + 1;
+ update_menubox(conf, &m);
+ wnoutrefresh(m.box);
+ pnoutrefresh(m.pad, m.ypad, 0, m.ys, m.xs, m.ye, m.xe);
+ changeitem = false;
}
+ } /* end while (loop) */
- if (movefocus) {
- drawitem(conf, menupad, abs, pos, &pritems[abs], false);
- abs = next;
- drawitem(conf, menupad, abs, pos, &pritems[abs], true);
- if (ymenupad > abs && ymenupad > 0)
- ymenupad = abs;
- if ((int)(ymenupad + menurows) <= abs)
- ymenupad = abs - menurows + 1;
- update_menuwin(conf, menuwin, menurows+2, w-4,
- totnitems, menurows, ymenupad);
- wrefresh(menuwin);
- prefresh(menupad, ymenupad, 0, ys, xs, ye, xe);
- movefocus = false;
- }
- }
+ set_return_on(&m, groups);
if (focuslist != NULL)
- *focuslist = abs < 0 ? -1 : pritems[abs].group;
+ *focuslist = m.sel < 0 ? -1 : m.pritems[m.sel].group;
if (focusitem !=NULL)
- *focusitem = abs < 0 ? -1 : pritems[abs].index;
+ *focusitem = m.sel < 0 ? -1 : m.pritems[m.sel].index;
- delwin(menupad);
- delwin(menuwin);
- end_dialog(conf, shadow, widget, textpad);
- free(pritems);
+ if (m.hasbottomdesc && conf->clear) {
+ move(SCREENLINES - 1, 2);
+ clrtoeol();
+ }
+ delwin(m.pad);
+ delwin(m.box);
+ end_dialog(&d);
+ free(m.pritems);
- return (output);
+ return (retval);
}
/* API */
@@ -765,12 +697,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 +710,15 @@ 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};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, CHECKLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -793,14 +726,15 @@ 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};
+ BSDDIALOG_CHECKLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, MENUMODE, 1,
&group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
int
@@ -808,12 +742,13 @@ 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};
+ BSDDIALOG_RADIOLIST /* unused */, nitems, items, 0};
- output = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
+ CHECK_ARRAY(nitems, items); /* efficiency, avoid do_mixedlist() */
+ retval = do_mixedlist(conf, text, rows, cols, menurows, RADIOLISTMODE,
1, &group, &focuslist, focusitem);
- return (output);
+ return (retval);
}
diff --git a/contrib/bsddialog/lib/messagebox.c b/contrib/bsddialog/lib/messagebox.c
index 24b34ccbce97..5132b1b089b8 100644
--- a/contrib/bsddialog/lib/messagebox.c
+++ b/contrib/bsddialog/lib/messagebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,184 +25,172 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
-static int
-message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, const char *text, struct buttons bs)
-{
- int htext, wtext;
+struct scroll {
+ int ypad; /* y scrollable pad */
+ int htext; /* real h text to draw, to use with htextpad */
+ int htextpad; /* h textpad, draw_dialog() set at least 1 */
+ int printrows; /* h - BORDER - HBUTTONS - BORDER */
+};
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 0, SCREENCOLS/2,
- &htext, &wtext) != 0)
- return (BSDDIALOG_ERROR);
+static void textupdate(struct dialog *d, struct scroll *s)
+{
+ if (s->htext > 0 && s->htextpad > s->printrows) {
+ wattron(d->widget, t.dialog.arrowcolor);
+ mvwprintw(d->widget, d->h - HBUTTONS - BORDER,
+ d->w - 4 - TEXTHMARGIN - BORDER,
+ "%3d%%", 100 * (s->ypad + s->printrows) / s->htextpad);
+ wattroff(d->widget, t.dialog.arrowcolor);
+ wnoutrefresh(d->widget);
}
-
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, wtext, 0, &bs);
-
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 0, true);
-
- return (0);
+ rtextpad(d, s->ypad, 0, 0, HBUTTONS);
}
-static int message_checksize(int rows, int cols, struct buttons bs)
+static int message_size_position(struct dialog *d, int *htext)
{
- int mincols;
+ int minw;
- mincols = VBORDERS;
- mincols += buttons_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 (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, (*htext < 0) ? htext : NULL, &d->bs, 0, 0) != 0)
+ return (BSDDIALOG_ERROR);
+ minw = (*htext > 0) ? 1 + TEXTHMARGINS : 0 ;
+ if (widget_checksize(d->h, d->w, &d->bs, MIN(*htext, 1), minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
return (0);
}
-static void
-textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad)
+static int message_draw(struct dialog *d, struct scroll *s)
{
- int y, x, h, w;
+ int unused;
- getbegyx(widget, y, x);
- getmaxyx(widget, h, w);
-
- if (htextpad > h - 4) {
- mvwprintw(widget, h-3, w-6, "%3d%%",
- 100 * (ytextpad+h-4)/ htextpad);
- wnoutrefresh(widget);
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
}
+ if (message_size_position(d, &s->htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+
+ s->printrows = d->h - BORDER - HBUTTONS - BORDER;
+ s->ypad = 0;
+ getmaxyx(d->textpad, s->htextpad, unused);
+ (void)unused; /* fix unused error */
- pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2);
+ return (0);
}
static int
do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
- struct buttons bs)
+ const char *oklabel, const char *cancellabel)
{
bool loop;
- int y, x, h, w, input, output, ytextpad, htextpad, unused;
- WINDOW *widget, *textpad, *shadow;
+ int retval;
+ wint_t input;
+ struct scroll s;
+ struct dialog d;
- 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 (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, oklabel, cancellabel);
+ s.htext = -1;
+ if (message_draw(&d, &s) != 0)
return (BSDDIALOG_ERROR);
- ytextpad = 0;
- getmaxyx(textpad, htextpad, unused);
- unused++; /* fix unused error */
- textupdate(widget, textpad, htextpad, ytextpad);
loop = true;
while (loop) {
+ textupdate(&d, &s);
doupdate();
- input = getch();
+ if (get_wch(&input) == ERR)
+ continue;
switch (input) {
case KEY_ENTER:
case 10: /* Enter */
- output = bs.value[bs.curr];
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
- if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ if (d.conf->key.enable_esc) {
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
case '\t': /* TAB */
- bs.curr = (bs.curr + 1) % bs.nbuttons;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
+ case KEY_RIGHT:
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
break;
case KEY_LEFT:
- if (bs.curr > 0) {
- bs.curr--;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
- }
+ d.bs.curr--;
+ if (d.bs.curr < 0)
+ d.bs.curr = d.bs.nbuttons - 1;
+ DRAW_BUTTONS(d);
break;
- case KEY_RIGHT:
- if (bs.curr < (int)bs.nbuttons - 1) {
- bs.curr++;
- draw_buttons(widget, bs, true);
- wnoutrefresh(widget);
- }
+ case '-':
+ case KEY_CTRL('p'):
+ case KEY_UP:
+ if (s.ypad > 0)
+ s.ypad--;
+ break;
+ case '+':
+ case KEY_CTRL('n'):
+ case KEY_DOWN:
+ if (s.ypad + s.printrows < s.htextpad)
+ s.ypad++;
+ break;
+ case KEY_HOME:
+ s.ypad = 0;
+ break;
+ case KEY_END:
+ s.ypad = MAX(s.htextpad - s.printrows, 0);
+ break;
+ case KEY_PPAGE:
+ s.ypad = MAX(s.ypad - s.printrows, 0);
+ break;
+ case KEY_NPAGE:
+ s.ypad += s.printrows;
+ if (s.ypad + s.printrows > s.htextpad)
+ s.ypad = s.htextpad - s.printrows;
break;
case KEY_F(1):
- if (conf->key.f1_file == NULL &&
- conf->key.f1_message == NULL)
+ if (d.conf->key.f1_file == NULL &&
+ d.conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (message_autosize(conf, rows, cols, &h, &w, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (message_checksize(h, w, bs) != 0)
+ if (f1help_dialog(d.conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (message_draw(&d, &s) != 0)
return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- getmaxyx(textpad, htextpad, unused);
- textupdate(widget, textpad, htextpad, ytextpad);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
- case KEY_UP:
- if (ytextpad == 0)
- break;
- ytextpad--;
- textupdate(widget, textpad, htextpad, ytextpad);
- break;
- case KEY_DOWN:
- if (ytextpad + h - 4 >= htextpad)
- break;
- ytextpad++;
- textupdate(widget, textpad, htextpad, ytextpad);
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (message_draw(&d, &s) != 0)
+ return (BSDDIALOG_ERROR);
break;
default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
- return (output);
+ return (retval);
}
/* API */
@@ -210,20 +198,34 @@ int
bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL);
-
- return (do_message(conf, text, rows, cols, bs));
+ return (do_message(conf, text, rows, cols, OK_LABEL, NULL));
}
int
bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
int cols)
{
- struct buttons bs;
+ return (do_message(conf, text, rows, cols, "Yes", "No"));
+}
- get_buttons(conf, &bs, "Yes", "No");
+int
+bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows,
+ int cols)
+{
+ int htext;
+ struct dialog d;
- return (do_message(conf, text, rows, cols, bs));
-} \ No newline at end of file
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ htext = -1;
+ if (message_size_position(&d, &htext) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(&d) != 0)
+ return (BSDDIALOG_ERROR);
+ TEXTPAD(&d, 0);
+ doupdate();
+
+ end_dialog(&d);
+
+ return (BSDDIALOG_OK);
+}
diff --git a/contrib/bsddialog/lib/textbox.c b/contrib/bsddialog/lib/textbox.c
index 69eff7c0bc2e..ca3eb69fff52 100644
--- a/contrib/bsddialog/lib/textbox.c
+++ b/contrib/bsddialog/lib/textbox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,199 +25,248 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
#include "bsddialog_theme.h"
#include "lib_util.h"
-static void
-textbox_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int hpad, int wpad, struct buttons bs)
+struct scrolltext {
+ WINDOW *pad;
+ int ypad;
+ int xpad;
+ int ys;
+ int ye;
+ int xs;
+ int xe;
+ int hpad;
+ int wpad;
+ int margin; /* 2 with multicolumn char, 0 otherwise */
+ int printrows; /* d.h - BORDERS - HBUTTONS */
+};
+
+static void updateborders(struct dialog *d, struct scrolltext *st)
{
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, 0, wpad, &bs);
+ chtype arrowch;
+ cchar_t borderch;
+
+ if (d->conf->no_lines)
+ setcchar(&borderch, L" ", 0, 0, NULL);
+ else if (d->conf->ascii_lines)
+ setcchar(&borderch, L"|", 0, 0, NULL);
+ else
+ borderch = *WACS_VLINE;
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, 0, hpad, true);
+ if (st->xpad > 0) {
+ arrowch = LARROW(d->conf) | t.dialog.arrowcolor;
+ mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4);
+ } else {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwvline_set(d->widget, (d->h / 2) - 2, 0, &borderch, 4);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+
+ if (st->xpad + d->w - 2 - st->margin < st->wpad) {
+ arrowch = RARROW(d->conf) | t.dialog.arrowcolor;
+ mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4);
+ } else {
+ wattron(d->widget, t.dialog.linelowercolor);
+ mvwvline_set(d->widget, (d->h / 2) - 2, d->w - 1, &borderch, 4);
+ wattroff(d->widget, t.dialog.linelowercolor);
+ }
+
+ if (st->hpad > d->h - 4) {
+ wattron(d->widget, t.dialog.arrowcolor);
+ mvwprintw(d->widget, d->h - 3, d->w - 6,
+ "%3d%%", 100 * (st->ypad + d->h - 4) / st->hpad);
+ wattroff(d->widget, t.dialog.arrowcolor);
+ }
}
-static int
-textbox_checksize(int rows, int cols, int hpad, struct buttons bs)
+static int textbox_size_position(struct dialog *d, struct scrolltext *st)
{
- int mincols;
+ int minw;
- mincols = VBORDERS + bs.sizebutton;
+ if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
+ d->text, NULL, &d->bs, st->hpad, st->wpad + st->margin) != 0)
+ return (BSDDIALOG_ERROR);
+ minw = (st->wpad > 0) ? 2 /*multicolumn char*/ + st->margin : 0 ;
+ if (widget_checksize(d->h, d->w, &d->bs, MIN(st->hpad, 1), minw) != 0)
+ return (BSDDIALOG_ERROR);
+ if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
+ return (BSDDIALOG_ERROR);
- if (cols < mincols)
- RETURN_ERROR("Few cols for the textbox");
+ return (0);
+}
+
+static int textbox_draw(struct dialog *d, struct scrolltext *st)
+{
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (textbox_size_position(d, st) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
- if (rows < 4 /* HBORDERS + button*/ + (hpad > 0 ? 1 : 0))
- RETURN_ERROR("Few rows for the textbox");
+ st->ys = d->y + 1;
+ st->xs = (st->margin == 0) ? d->x + 1 : d->x + 2;
+ st->ye = st->ys + d->h - 5;
+ st->xe = st->xs + d->w - 3 - st->margin;
+ st->ypad = st->xpad = 0;
+ st->printrows = d->h-4;
return (0);
}
/* API */
int
-bsddialog_textbox(struct bsddialog_conf *conf, const char* file, int rows,
+bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
int cols)
{
- bool loop;
- int i, output, input;
- int y, x, h, w, hpad, wpad, ypad, xpad, ys, ye, xs, xe, printrows;
+ bool loop, has_multicol_ch;
+ int i, retval;
+ unsigned int defaulttablen, linecols;
+ wint_t input;
char buf[BUFSIZ];
FILE *fp;
- struct buttons bs;
- WINDOW *shadow, *widget, *pad;
+ struct scrolltext st;
+ struct dialog d;
+ if (file == NULL)
+ RETURN_ERROR("*file is NULL");
if ((fp = fopen(file, "r")) == NULL)
- RETURN_ERROR("Cannot open file");
+ RETURN_FMTERROR("Cannot open file \"%s\"", file);
+
+ if (prepare_dialog(conf, "" /* fake */, rows, cols, &d) != 0)
+ return (BSDDIALOG_ERROR);
+ set_buttons(&d, true, "EXIT", NULL);
- hpad = 1;
- wpad = 1;
- pad = newpad(hpad, wpad);
- wbkgd(pad, t.dialog.color);
+ defaulttablen = TABSIZE;
+ if (conf->text.tablen > 0)
+ set_tabsize(conf->text.tablen);
+ st.hpad = 1;
+ st.wpad = 1;
+ st.pad = newpad(st.hpad, st.wpad);
+ wbkgd(st.pad, t.dialog.color);
+ st.margin = 0;
i = 0;
while (fgets(buf, BUFSIZ, fp) != NULL) {
- if ((int) strlen(buf) > wpad) {
- wpad = strlen(buf);
- wresize(pad, hpad, wpad);
+ if (str_props(buf, &linecols, &has_multicol_ch) != 0)
+ continue;
+ if ((int)linecols > st.wpad) {
+ st.wpad = linecols;
+ wresize(st.pad, st.hpad, st.wpad);
}
- if (i > hpad-1) {
- hpad++;
- wresize(pad, hpad, wpad);
+ if (i > st.hpad-1) {
+ st.hpad++;
+ wresize(st.pad, st.hpad, st.wpad);
}
- mvwaddstr(pad, i, 0, buf);
+ mvwaddstr(st.pad, i, 0, buf);
i++;
+ if (has_multicol_ch)
+ st.margin = 2;
}
fclose(fp);
+ set_tabsize(defaulttablen); /* reset because it is curses global */
- 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;
- bs.curr = 0;
- bs.sizebutton = strlen(bs.label[0]) + 2;
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad, bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, NULL, NULL, &bs,
- true) != 0)
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h-4;
loop = true;
while (loop) {
- wnoutrefresh(widget);
- pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
- doupdate();
- input = getch();
+ updateborders(&d, &st);
+ /*
+ * Trick, overflow multicolumn charchter right border:
+ * wnoutrefresh(widget);
+ * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
+ * doupdate();
+ */
+ wrefresh(d.widget);
+ prefresh(st.pad, st.ypad, st.xpad, st.ys, st.xs, st.ye, st.xe);
+ if (get_wch(&input) == ERR)
+ continue;
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
+ break; /* loop */
+ }
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- output = BSDDIALOG_OK;
+ retval = BUTTONVALUE(d.bs);
loop = false;
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
+ case '\t': /* TAB */
+ d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
+ DRAW_BUTTONS(d);
+ break;
case KEY_HOME:
- ypad = 0;
+ st.ypad = 0;
break;
case KEY_END:
- ypad = hpad - printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.hpad - st.printrows, 0);
break;
case KEY_PPAGE:
- ypad -= printrows;
- ypad = ypad < 0 ? 0 : ypad;
+ st.ypad = MAX(st.ypad - st.printrows, 0);
break;
case KEY_NPAGE:
- ypad += printrows;
- if (ypad + printrows > hpad)
- ypad = hpad - printrows;
+ st.ypad += st.printrows;
+ if (st.ypad + st.printrows > st.hpad)
+ st.ypad = st.hpad - st.printrows;
break;
case '0':
- xpad = 0;
+ st.xpad = 0;
+ break;
case KEY_LEFT:
case 'h':
- xpad = xpad > 0 ? xpad - 1 : 0;
+ st.xpad = MAX(st.xpad - 1, 0);
break;
case KEY_RIGHT:
case 'l':
- xpad = (xpad + w-2) < wpad-1 ? xpad + 1 : xpad;
+ if (st.xpad + d.w - 2 - st.margin < st.wpad)
+ st.xpad++;
break;
case KEY_UP:
case 'k':
- ypad = ypad > 0 ? ypad - 1 : 0;
+ st.ypad = MAX(st.ypad - 1, 0);
break;
case KEY_DOWN:
case'j':
- ypad = ypad + printrows <= hpad -1 ? ypad + 1 : ypad;
+ if (st.ypad + st.printrows <= st.hpad -1)
+ st.ypad++;
break;
case KEY_F(1):
if (conf->key.f1_file == NULL &&
conf->key.f1_message == NULL)
break;
- if (f1help(conf) != 0)
- return (BSDDIALOG_ERROR);
- /* No break, screen size can change */
- case KEY_RESIZE:
- /* Important for decreasing screen */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- textbox_autosize(conf, rows, cols, &h, &w, hpad, wpad,
- bs);
- if (textbox_checksize(h, w, hpad, bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
-
- ys = y + 1;
- xs = x + 1;
- ye = ys + h - 5;
- xe = xs + w - 3;
- ypad = xpad = 0;
- printrows = h - 4;
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- NULL, NULL, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (textbox_draw(&d, &st) != 0)
return (BSDDIALOG_ERROR);
-
- /* Important to fix grey lines expanding screen */
- refresh();
break;
- default:
- if (shortcut_buttons(input, &bs)) {
- output = bs.value[bs.curr];
- loop = false;
- }
}
}
- end_dialog(conf, shadow, widget, pad);
+ delwin(st.pad);
+ end_dialog(&d);
- return (output);
-} \ No newline at end of file
+ return (retval);
+}
diff --git a/contrib/bsddialog/lib/theme.c b/contrib/bsddialog/lib/theme.c
index 20b1e35428dd..04f85b2455fa 100644
--- a/contrib/bsddialog/lib/theme.c
+++ b/contrib/bsddialog/lib/theme.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2023 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,137 +32,117 @@
#include "lib_util.h"
#define GET_COLOR(bg, fg) (COLOR_PAIR(bg * 8 + fg +1))
+#define WHITE GET_COLOR(COLOR_WHITE, COLOR_BLACK)
+#define BLACK GET_COLOR(COLOR_WHITE, COLOR_BLACK) | A_REVERSE
+#define NFLAGS 6
struct bsddialog_theme t;
+bool hastermcolors;
-static struct bsddialog_theme bsddialogtheme = {
-#define bgwidget COLOR_WHITE
-#define bgcurr COLOR_YELLOW
- .screen.color = GET_COLOR(COLOR_BLACK, COLOR_CYAN),
-
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+struct flag_converter {
+ unsigned int public;
+ unsigned int private;
+};
- .dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(COLOR_YELLOW, bgwidget),
- .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.color = GET_COLOR(COLOR_BLACK, bgwidget),
- .dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, bgwidget),
- .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
+static struct flag_converter flagconv[NFLAGS] = {
+ {BSDDIALOG_BLINK, A_BLINK},
+ {BSDDIALOG_BOLD, A_BOLD},
+ {BSDDIALOG_HALFBRIGHT, A_DIM},
+ {BSDDIALOG_HIGHLIGHT, A_STANDOUT},
+ {BSDDIALOG_REVERSE, A_REVERSE},
+ {BSDDIALOG_UNDERLINE, A_UNDERLINE}
};
static struct bsddialog_theme blackwhite = {
-#define fg COLOR_WHITE
-#define bk COLOR_BLACK
- .screen.color = GET_COLOR(fg, bk),
+ .screen.color = WHITE,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
.dialog.delimtitle = true,
- .dialog.titlecolor = GET_COLOR(fg, bk),
- .dialog.lineraisecolor = GET_COLOR(fg, bk),
- .dialog.linelowercolor = GET_COLOR(fg, bk),
- .dialog.color = GET_COLOR(fg, bk),
- .dialog.bottomtitlecolor = GET_COLOR(fg, bk),
- .dialog.arrowcolor = GET_COLOR(fg, bk),
-
- .menu.f_selectorcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.selectorcolor = GET_COLOR(fg, bk),
- .menu.f_desccolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.desccolor = GET_COLOR(fg, bk),
- .menu.f_namecolor = GET_COLOR(fg, bk) | A_REVERSE,
- .menu.namecolor = GET_COLOR(fg, bk),
- .menu.namesepcolor = GET_COLOR(fg, bk),
- .menu.descsepcolor = GET_COLOR(fg, bk),
- .menu.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .menu.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE,
-
- .form.f_fieldcolor = GET_COLOR(fg, bk) | A_REVERSE,
- .form.fieldcolor = GET_COLOR(fg, bk),
- .form.readonlycolor = GET_COLOR(fg, bk),
-
- .bar.f_color = GET_COLOR(fg, bk) | A_REVERSE,
- .bar.color = GET_COLOR(fg, bk),
-
- .button.hmargin = 3,
+ .dialog.titlecolor = WHITE,
+ .dialog.lineraisecolor = WHITE,
+ .dialog.linelowercolor = WHITE,
+ .dialog.color = WHITE,
+ .dialog.bottomtitlecolor = WHITE,
+ .dialog.arrowcolor = WHITE,
+
+ .menu.f_prefixcolor = WHITE,
+ .menu.prefixcolor = WHITE,
+ .menu.f_selectorcolor = BLACK,
+ .menu.selectorcolor = WHITE,
+ .menu.f_desccolor = BLACK,
+ .menu.desccolor = WHITE,
+ .menu.f_namecolor = BLACK,
+ .menu.namecolor = WHITE,
+ .menu.f_shortcutcolor = BLACK | A_UNDERLINE,
+ .menu.shortcutcolor = WHITE | A_UNDERLINE,
+ .menu.bottomdesccolor = WHITE,
+ .menu.sepnamecolor = WHITE,
+ .menu.sepdesccolor = WHITE,
+
+ .form.f_fieldcolor = BLACK,
+ .form.fieldcolor = WHITE,
+ .form.readonlycolor = WHITE,
+ .form.bottomdesccolor = WHITE,
+
+ .bar.f_color = BLACK,
+ .bar.color = WHITE,
+
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
.button.leftdelim = '[',
.button.rightdelim = ']',
- .button.f_delimcolor = GET_COLOR(fg, bk),
- .button.delimcolor = GET_COLOR(fg, bk),
- .button.f_color = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.color = GET_COLOR(fg, bk) | A_UNDERLINE,
- .button.f_shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE | A_REVERSE,
- .button.shortcutcolor = GET_COLOR(fg, bk) | A_UNDERLINE
+ .button.f_delimcolor = WHITE,
+ .button.delimcolor = WHITE,
+ .button.f_color = BLACK,
+ .button.color = WHITE,
+ .button.f_shortcutcolor = BLACK | A_UNDERLINE | A_BOLD,
+ .button.shortcutcolor = WHITE | A_UNDERLINE | A_BOLD
};
-static struct bsddialog_theme dialogtheme = {
- .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
+static struct bsddialog_theme flat = {
+ .screen.color = GET_COLOR(COLOR_CYAN, COLOR_BLUE) | A_BOLD,
- .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
- .shadow.h = 1,
- .shadow.w = 2,
+ .shadow.color = GET_COLOR(COLOR_BLACK, COLOR_BLACK),
+ .shadow.y = 1,
+ .shadow.x = 2,
- .dialog.delimtitle = false,
+ .dialog.delimtitle = true,
.dialog.titlecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .dialog.lineraisecolor = GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD,
- .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
+ .dialog.lineraisecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .dialog.linelowercolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.color = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.dialog.bottomtitlecolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE) | A_BOLD,
- .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_prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.prefixcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_selectorcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.selectorcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_desccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.desccolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
+ .menu.f_namecolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.namecolor = GET_COLOR(COLOR_BLUE, COLOR_WHITE),
+ .menu.f_shortcutcolor = GET_COLOR(COLOR_RED, COLOR_BLUE),
+ .menu.shortcutcolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
+ .menu.sepnamecolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+ .menu.sepdesccolor = GET_COLOR(COLOR_RED, COLOR_WHITE),
+
+ .form.f_fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
+ .form.fieldcolor = GET_COLOR(COLOR_WHITE, COLOR_CYAN) | A_BOLD,
+ .form.readonlycolor = GET_COLOR(COLOR_CYAN, COLOR_WHITE)| A_BOLD,
+ .form.bottomdesccolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE),
.bar.f_color = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
.bar.color = GET_COLOR(COLOR_BLUE, COLOR_WHITE) | A_BOLD,
- .button.hmargin = 3,
- .button.leftdelim = '<',
- .button.rightdelim = '>',
+ .button.minmargin = 1,
+ .button.maxmargin = 5,
+ .button.leftdelim = '[',
+ .button.rightdelim = ']',
.button.f_delimcolor = GET_COLOR(COLOR_WHITE, COLOR_BLUE) | A_BOLD,
.button.delimcolor = GET_COLOR(COLOR_BLACK, COLOR_WHITE),
.button.f_color = GET_COLOR(COLOR_YELLOW, COLOR_BLUE) | A_BOLD,
@@ -177,8 +157,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;
@@ -188,25 +168,30 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->dialog.bottomtitlecolor = src->dialog.bottomtitlecolor;
dst->dialog.arrowcolor = src->dialog.arrowcolor;
+ dst->menu.f_prefixcolor = src->menu.f_prefixcolor;
+ dst->menu.prefixcolor = src->menu.prefixcolor;
dst->menu.f_selectorcolor = src->menu.f_selectorcolor;
dst->menu.selectorcolor = src->menu.selectorcolor;
dst->menu.f_desccolor = src->menu.f_desccolor;
dst->menu.desccolor = src->menu.desccolor;
dst->menu.f_namecolor = src->menu.f_namecolor;
dst->menu.namecolor = src->menu.namecolor;
- dst->menu.namesepcolor = src->menu.namesepcolor;
- dst->menu.descsepcolor = src->menu.descsepcolor;
dst->menu.f_shortcutcolor = src->menu.f_shortcutcolor;
dst->menu.shortcutcolor = src->menu.shortcutcolor;
+ dst->menu.bottomdesccolor = src->menu.bottomdesccolor;
+ dst->menu.sepnamecolor = src->menu.sepnamecolor;
+ dst->menu.sepdesccolor = src->menu.sepdesccolor;
- dst->form.f_fieldcolor = src->form.f_fieldcolor;
- dst->form.fieldcolor = src->form.fieldcolor;
- 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;
@@ -217,68 +202,87 @@ set_theme(struct bsddialog_theme *dst, struct bsddialog_theme *src)
dst->button.shortcutcolor = src->button.shortcutcolor;
bkgd(dst->screen.color);
- refresh();
}
/* API */
int bsddialog_get_theme(struct bsddialog_theme *theme)
{
- if (theme == NULL)
- RETURN_ERROR("theme is NULL");
- if (sizeof(*theme) != sizeof(struct bsddialog_theme))
- RETURN_ERROR("Bad suze struct bsddialog_theme");
-
+ CHECK_PTR(theme);
set_theme(theme, &t);
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_theme(struct bsddialog_theme *theme)
{
- if (theme == NULL)
- RETURN_ERROR("theme is NULL");
- if (sizeof(*theme) != sizeof(struct bsddialog_theme))
- RETURN_ERROR("Bad size struct bsddialog_theme");
-
+ CHECK_PTR(theme);
set_theme(&t, theme);
+ refresh();
- return (0);
+ return (BSDDIALOG_OK);
}
int bsddialog_set_default_theme(enum bsddialog_default_theme newtheme)
{
-
- if (newtheme == BSDDIALOG_THEME_FLAT) {
- bsddialog_set_theme(&dialogtheme);
- t.dialog.lineraisecolor = t.dialog.linelowercolor;
- t.dialog.delimtitle = true;
- t.button.leftdelim = '[';
- t.button.rightdelim = ']';
+ if (newtheme == BSDDIALOG_THEME_3D) {
+ set_theme(&t, &flat);
+ t.dialog.lineraisecolor =
+ GET_COLOR(COLOR_WHITE, COLOR_WHITE) | A_BOLD;
+ t.dialog.delimtitle = false;
+ t.dialog.bottomtitlecolor = t.dialog.bottomtitlecolor | A_BOLD;
+ } else if (newtheme == BSDDIALOG_THEME_BLACKWHITE) {
+ set_theme(&t, &blackwhite);
+ } else if (newtheme == BSDDIALOG_THEME_FLAT) {
+ set_theme(&t, &flat);
+ } else {
+ RETURN_FMTERROR("Unknown default theme (%d), "
+ "to use enum bsddialog_default_theme",
+ newtheme);
}
- else if (newtheme == BSDDIALOG_THEME_BSDDIALOG)
- bsddialog_set_theme(&bsddialogtheme);
- else if (newtheme == BSDDIALOG_THEME_BLACKWHITE)
- bsddialog_set_theme(&blackwhite);
- else if (newtheme == BSDDIALOG_THEME_DIALOG)
- bsddialog_set_theme(&dialogtheme);
- else
- RETURN_ERROR("Unknow default theme");
-
- return (0);
+ refresh();
+
+ return (BSDDIALOG_OK);
}
int
bsddialog_color(enum bsddialog_color foreground,
enum bsddialog_color background, unsigned int flags)
{
- unsigned int cursesflags = 0;
+ unsigned int i, f;
+
+ f = 0;
+ for (i=0; i < NFLAGS; i++)
+ if (flags & flagconv[i].public)
+ f |= flagconv[i].private;
+
+ return (GET_COLOR(foreground, background) | f);
+}
- if (flags & BSDDIALOG_BOLD)
- cursesflags |= A_BOLD;
- if (flags & BSDDIALOG_REVERSE)
- cursesflags |= A_REVERSE;
- if (flags & BSDDIALOG_UNDERLINE)
- cursesflags |= A_UNDERLINE;
+int
+bsddialog_color_attrs(int color, enum bsddialog_color *foreground,
+ enum bsddialog_color *background, unsigned int *flags)
+{
+ short fg, bg;
+ unsigned int i, f;
+
+ if (flags != NULL) {
+ f = 0;
+ for (i=0; i < NFLAGS; i++)
+ if (color & flagconv[i].private)
+ f |= flagconv[i].public;
+ *flags = f;
+ }
+ if (pair_content(PAIR_NUMBER(color), &fg, &bg) != OK)
+ RETURN_ERROR("Cannot get color attributes");
+ if (foreground != NULL)
+ *foreground = fg;
+ if (background != NULL)
+ *background = bg;
+
+ return (BSDDIALOG_OK);
+}
- return (GET_COLOR(foreground, background) | cursesflags);
+bool bsddialog_hascolors(void)
+{
+ return (hastermcolors);
}
diff --git a/contrib/bsddialog/lib/timebox.c b/contrib/bsddialog/lib/timebox.c
index 7d69666c32b8..1421cd7d2b81 100644
--- a/contrib/bsddialog/lib/timebox.c
+++ b/contrib/bsddialog/lib/timebox.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
+ * Copyright (c) 2021-2024 Alfonso Sabato Siciliano
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,512 +25,216 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
-#include <ctype.h>
#include <curses.h>
-#include <string.h>
#include "bsddialog.h"
+#include "bsddialog_theme.h"
#include "lib_util.h"
-#define MINWDATE 23 /* 3 windows and their borders */
#define MINWTIME 14 /* 3 windows and their borders */
-
-static int
-datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
- int *w, int minw, const char *text, struct buttons bs)
+#define HBOX 3
+#define WBOX 4
+
+struct clock {
+ unsigned int max;
+ unsigned int value;
+ WINDOW *win;
+};
+
+static void
+drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value,
+ bool focus)
{
- int htext, wtext;
-
- if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
- if (text_size(conf, rows, cols, text, &bs, 3, minw, &htext,
- &wtext) != 0)
- return (BSDDIALOG_ERROR);
+ draw_borders(conf, win, LOWERED);
+ if (focus) {
+ wattron(win, t.dialog.arrowcolor);
+ mvwhline(win, 0, 1, UARROW(conf), 2);
+ mvwhline(win, 2, 1, DARROW(conf), 2);
+ wattroff(win, t.dialog.arrowcolor);
}
- if (cols == BSDDIALOG_AUTOSIZE)
- *w = widget_min_width(conf, htext,minw, &bs);
+ if (focus)
+ wattron(win, t.menu.f_namecolor);
+ mvwprintw(win, 1, 1, "%02u", value);
+ if (focus)
+ wattroff(win, t.menu.f_namecolor);
- if (rows == BSDDIALOG_AUTOSIZE)
- *h = widget_min_height(conf, htext, 3 /* windows */, true);
-
- return (0);
+ wnoutrefresh(win);
}
-static int
-datetime_checksize(int rows, int cols, int minw, struct buttons bs)
+static int timebox_redraw(struct dialog *d, struct clock *c)
{
- int mincols;
-
- mincols = VBORDERS;
- mincols += buttons_width(bs);
- mincols = MAX(minw, mincols);
+ int y, x;
- if (cols < mincols)
- RETURN_ERROR("Few cols for this timebox/datebox");
-
- if (rows < 7) /* 2 button + 2 borders + 3 windows */
- RETURN_ERROR("Few rows for this timebox/datebox, at least 7");
+ if (d->built) {
+ hide_dialog(d);
+ refresh(); /* Important for decreasing screen */
+ }
+ if (dialog_size_position(d, HBOX, MINWTIME, NULL) != 0)
+ return (BSDDIALOG_ERROR);
+ if (draw_dialog(d) != 0)
+ return (BSDDIALOG_ERROR);
+ if (d->built)
+ refresh(); /* Important to fix grey lines expanding screen */
+ TEXTPAD(d, HBOX + HBUTTONS);
+
+ y = d->y + d->h - BORDER - HBUTTONS - HBOX;
+ x = d->x + d->w/2 - 7;
+ update_box(d->conf, c[0].win, y, x, HBOX, WBOX, LOWERED);
+ mvwaddch(d->widget, d->h - 5, d->w/2 - 3, ':');
+ update_box(d->conf, c[1].win, y, x += 5, HBOX, WBOX, LOWERED);
+ mvwaddch(d->widget, d->h - 5, d->w/2 + 2, ':');
+ update_box(d->conf, c[2].win, y, x + 5, HBOX, WBOX, LOWERED);
+ wnoutrefresh(d->widget); /* for mvwaddch(':') */
return (0);
}
+/* API */
int
bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
{
bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct myclockstruct {
- unsigned int max;
- unsigned int value;
- WINDOW *win;
- };
-
- if (hh == NULL || mm == NULL || ss == NULL)
- RETURN_ERROR("hh / mm / ss cannot be NULL");
-
- struct myclockstruct c[3] = {
+ int i, retval, sel;
+ wint_t input;
+ struct dialog d;
+ struct clock c[3] = {
{23, *hh, NULL},
{59, *mm, NULL},
{59, *ss, NULL}
};
- for (i = 0 ; i < 3; i++) {
- if (c[i].value > c[i].max)
- c[i].value = c[i].max;
- }
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
+ CHECK_PTR(hh);
+ CHECK_PTR(mm);
+ CHECK_PTR(ss);
+ if (prepare_dialog(conf, text, rows, cols, &d) != 0)
return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
+ set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
+ for (i=0; i<3; i++) {
+ if ((c[i].win = newwin(1, 1, 1, 1)) == NULL)
+ RETURN_FMTERROR("Cannot build WINDOW for time[%d]", i);
+ wbkgd(c[i].win, t.dialog.color);
+ c[i].value = MIN(c[i].value, c[i].max);
+ }
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 7, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 2, 3, 4, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 3, 3, 4, LOWERED);
-
- wrefresh(widget);
-
+ sel = -1;
loop = focusbuttons = true;
while (loop) {
- for (i = 0; i < 3; i++) {
- 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);
- }
-
- input = getch();
+ for (i = 0; i < 3; i++)
+ drawsquare(conf, c[i].win, c[i].value, sel == i);
+ doupdate();
+ if (get_wch(&input) == ERR)
+ continue;
switch(input) {
case KEY_ENTER:
case 10: /* Enter */
- if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
+ if (focusbuttons || conf->button.always_active) {
+ retval = BUTTONVALUE(d.bs);
+ loop = false;
+ }
break;
case 27: /* Esc */
if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
+ retval = BSDDIALOG_ESC;
loop = false;
}
break;
- case KEY_RIGHT:
case '\t': /* TAB */
+ case KEY_CTRL('n'):
+ case KEY_RIGHT:
if (focusbuttons) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
+ d.bs.curr++;
+ focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
true : false;
if (focusbuttons == false) {
- curs_set(1);
sel = 0;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel++;
focusbuttons = sel > 2 ? true : false;
if (focusbuttons) {
- curs_set(0);
- bs.curr = 0;
+ d.bs.curr = 0;
}
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ DRAW_BUTTONS(d);
break;
+ case KEY_CTRL('p'):
case KEY_LEFT:
if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
+ d.bs.curr--;
+ focusbuttons = d.bs.curr < 0 ? false : true;
if (focusbuttons == false) {
- curs_set(1);
sel = 2;
+ d.bs.curr =
+ conf->button.always_active ? 0 : -1;
}
} else {
sel--;
focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = (int)bs.nbuttons - 1;
- }
+ if (focusbuttons)
+ d.bs.curr = (int)d.bs.nbuttons - 1;
}
- draw_buttons(widget, bs, true);
- wrefresh(widget);
- break;
- case KEY_UP:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value > 0 ?
- c[sel].value - 1 : c[sel].max;
- break;
- case KEY_DOWN:
- if (focusbuttons)
- break;
- c[sel].value = c[sel].value < c[sel].max ?
- c[sel].value + 1 : 0;
+ DRAW_BUTTONS(d);
break;
- case KEY_F(1):
- 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 */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWTIME, text, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWTIME, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
- return (BSDDIALOG_ERROR);
-
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 3, ':');
- mvwaddch(widget, h - 5, w/2 + 2, ':');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 7);
- 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];
- loop = false;
- }
- }
- }
-
- if (output == 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);
-}
-
-int
-bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
- int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
-{
- bool loop, focusbuttons;
- int i, input, output, y, x, h, w, sel;
- WINDOW *widget, *textpad, *shadow;
- struct buttons bs;
- struct calendar {
- int max;
- int value;
- WINDOW *win;
- unsigned int x;
- };
- struct month {
- const char *name;
- unsigned int days;
- };
-
- if (yy == NULL || mm == NULL || dd == NULL)
- RETURN_ERROR("yy / mm / dd cannot be NULL");
-
- struct calendar c[3] = {
- {9999, *yy, NULL, 4 },
- {12, *mm, NULL, 9 },
- {31, *dd, NULL, 2 }
- };
-
- struct month m[12] = {
- { "January", 31 }, { "February", 28 }, { "March", 31 },
- { "April", 30 }, { "May", 31 }, { "June", 30 },
- { "July", 31 }, { "August", 31 }, { "September", 30 },
- { "October", 31 }, { "November", 30 }, { "December", 31 }
- };
-
-#define ISLEAF(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
-
- for (i = 0 ; i < 3; i++) {
- if (c[i].value > c[i].max)
- c[i].value = c[i].max;
- if (c[i].value < 1)
- c[i].value = 1;
- }
- c[2].max = m[c[1].value -1].days;
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
-
- get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text,
- bs) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
- return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
- true) != 0)
- return (BSDDIALOG_ERROR);
-
- pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
- doupdate();
-
- c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 11, 3, 6, LOWERED);
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 4, 3, 11, LOWERED);
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 8, 3, 4, LOWERED);
-
- wrefresh(widget);
-
- 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);
- }
-
- input = getch();
- switch(input) {
- case KEY_ENTER:
- case 10: /* Enter */
+ case '-':
if (focusbuttons == false)
- break;
- output = bs.value[bs.curr];
- loop = false;
- break;
- case 27: /* Esc */
- if (conf->key.enable_esc) {
- output = BSDDIALOG_ESC;
- loop = false;
- }
- break;
- case KEY_RIGHT:
- case '\t': /* TAB */
- if (focusbuttons) {
- bs.curr++;
- focusbuttons = bs.curr < (int)bs.nbuttons ?
- true : false;
- if (focusbuttons == false) {
- curs_set(1);
- sel = 0;
- }
- } else {
- sel++;
- focusbuttons = sel > 2 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = 0;
- }
- }
- draw_buttons(widget, bs, true);
- wrefresh(widget);
+ c[sel].value = c[sel].value > 0 ?
+ c[sel].value - 1 : c[sel].max;
break;
- case KEY_LEFT:
+ case KEY_UP:
if (focusbuttons) {
- bs.curr--;
- focusbuttons = bs.curr < 0 ? false : true;
- if (focusbuttons == false) {
- curs_set(1);
- sel = 2;
- }
+ sel = 0;
+ focusbuttons = false;
+ d.bs.curr = conf->button.always_active ? 0 : -1;
+ DRAW_BUTTONS(d);
} else {
- sel--;
- focusbuttons = sel < 0 ? true : false;
- if (focusbuttons) {
- curs_set(0);
- bs.curr = (int)bs.nbuttons - 1;
- }
+ c[sel].value = c[sel].value > 0 ?
+ c[sel].value - 1 : c[sel].max;
}
- 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;
break;
+ case '+':
case KEY_DOWN:
if (focusbuttons)
break;
c[sel].value = c[sel].value < c[sel].max ?
- c[sel].value + 1 : 1;
- /* if mount change */
- c[2].max = m[c[1].value -1].days;
- /* if year change */
- if (c[1].value == 2 && ISLEAF(c[0].value))
- c[2].max = 29;
- /* set new day */
- if (c[2].value > c[2].max)
- c[2].value = c[2].max;
+ c[sel].value + 1 : 0;
break;
case KEY_F(1):
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 */
- hide_widget(y, x, h, w, conf->shadow);
- refresh();
-
- if (set_widget_size(conf, rows, cols, &h, &w) != 0)
- return (BSDDIALOG_ERROR);
- if (datetime_autosize(conf, rows, cols, &h, &w,
- MINWDATE, text, bs) != 0)
+ if (f1help_dialog(conf) != 0)
return (BSDDIALOG_ERROR);
- if (datetime_checksize(h, w, MINWDATE, bs) != 0)
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- if (set_widget_position(conf, &y, &x, h, w) != 0)
- return (BSDDIALOG_ERROR);
-
- if (update_dialog(conf, shadow, widget, y, x, h, w,
- textpad, text, &bs, true) != 0)
+ break;
+ case KEY_CTRL('l'):
+ case KEY_RESIZE:
+ if (timebox_redraw(&d, c) != 0)
return (BSDDIALOG_ERROR);
- doupdate();
-
- mvwaddch(widget, h - 5, w/2 - 5, '/');
- mvwaddch(widget, h - 5, w/2 + 7, '/');
- wrefresh(widget);
-
- prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
-
- wclear(c[0].win);
- mvwin(c[0].win, y + h - 6, x + w/2 - 11);
- 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];
+ if (shortcut_buttons(input, &d.bs)) {
+ DRAW_BUTTONS(d);
+ doupdate();
+ retval = BUTTONVALUE(d.bs);
loop = false;
}
}
}
- if (output == BSDDIALOG_OK) {
- *yy = c[0].value;
- *mm = c[1].value;
- *dd = c[2].value;
- }
-
- curs_set(0);
+ *hh = c[0].value;
+ *mm = c[1].value;
+ *ss = c[2].value;
for (i = 0; i < 3; i++)
delwin(c[i].win);
- end_dialog(conf, shadow, widget, textpad);
+ end_dialog(&d);
- return (output);
+ return (retval);
}