aboutsummaryrefslogtreecommitdiff
path: root/contrib/bsddialog/lib/lib_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsddialog/lib/lib_util.c')
-rw-r--r--contrib/bsddialog/lib/lib_util.c1763
1 files changed, 1061 insertions, 702 deletions
diff --git a/contrib/bsddialog/lib/lib_util.c b/contrib/bsddialog/lib/lib_util.c
index a1cdac1169c4..9cfdd6f1a075 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 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,972 +25,1331 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
-
+#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#ifdef PORTNCURSES
-#include <ncurses/curses.h>
-#else
-#include <curses.h>
-#endif
+#include <wctype.h>
#include "bsddialog.h"
-#include "lib_util.h"
#include "bsddialog_theme.h"
+#include "lib_util.h"
-extern struct bsddialog_theme t;
+/*
+ * -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);
+ */
-/* Error buffer */
+/*
+ * -1- Error and diagnostic
+ */
+#define ERRBUFLEN 1024
-#define ERRBUFLEN 1024
static char errorbuffer[ERRBUFLEN];
const char *get_error_string(void)
{
- return errorbuffer;
+ return (errorbuffer);
}
-void set_error_string(char *str)
+void set_error_string(const char *str)
{
-
strncpy(errorbuffer, str, ERRBUFLEN-1);
}
-/* cleaner */
-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;
- /* no check: y, x, h and w are checked by the builders */
- if ((clear = newwin(h, w, y + t.shadowrows, x + t.shadowcols)) == NULL)
- RETURN_ERROR("Cannot hide the widget");
- wbkgd(clear, t.backgroundcolor);
+ 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);
+}
- return 0;
+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);
}
-/* F1 help */
-int f1help(struct bsddialog_conf conf)
+int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
{
- char *file = conf.hfile;
- char *title = conf.title;
- int output;
+ 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);
+}
- conf.hfile = NULL;
- conf.clear = true;
- conf.y = BSDDIALOG_CENTER;
- conf.x = BSDDIALOG_CENTER;
- conf.title = "HELP";
- conf.sleep = 0;
+unsigned int strcols(const char *mbstring)
+{
+ int w;
+ unsigned int ncol;
+ size_t charlen, mb_cur_max;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ mb_cur_max = MB_CUR_MAX;
+ ncol = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
+ charlen != (size_t)-1 && charlen != (size_t)-2) {
+ if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
+ return (0);
+ w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
+ ncol += (w < 0) ? 0 : w;
+ mbstring += charlen;
+ }
- output = bsddialog_textbox(conf, file, BSDDIALOG_AUTOSIZE,
- BSDDIALOG_AUTOSIZE);
- conf.hfile = file;
- conf.title = title;
+ return (ncol);
+}
- return output;
+/*
+ * -3- Buttons
+ */
+static int buttons_min_width(struct buttons *bs)
+{
+ unsigned int width;
+
+ width = bs->nbuttons * bs->sizebutton;
+ if (bs->nbuttons > 0)
+ width += (bs->nbuttons - 1) * t.button.minmargin;
+
+ return (width);
}
-/* Buttons */
-void
-draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
- bool shortkey)
+static void
+draw_button(WINDOW *window, int y, int x, int size, const char *text,
+ wchar_t first, bool selected, bool shortcut)
{
int i, color_arrows, color_shortkey, color_button;
if (selected) {
- color_arrows = t.currbuttdelimcolor;
- color_shortkey = t.currshortkeycolor;
- color_button = t.currbuttoncolor;
+ color_arrows = t.button.f_delimcolor;
+ color_shortkey = t.button.f_shortcutcolor;
+ color_button = t.button.f_color;
} else {
- color_arrows = t.buttdelimcolor;
- color_shortkey = t.shortkeycolor;
- color_button = t.buttoncolor;
+ color_arrows = t.button.delimcolor;
+ color_shortkey = t.button.shortcutcolor;
+ color_button = t.button.color;
}
wattron(window, color_arrows);
- mvwaddch(window, y, x, t.buttleftch);
+ mvwaddch(window, y, x, t.button.leftdelim);
wattroff(window, color_arrows);
wattron(window, color_button);
- for(i = 1; i < size - 1; i++)
+ for (i = 1; i < size - 1; i++)
waddch(window, ' ');
wattroff(window, color_button);
wattron(window, color_arrows);
- mvwaddch(window, y, x + i, t.buttrightchar);
+ 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 (shortkey) {
+ 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, int y, int cols, struct buttons bs, bool shortkey)
+void draw_buttons(struct dialog *d)
{
- int i, x, start_x;
+ int i, x, startx, y;
+ unsigned int newmargin, margin, wbuttons;
- start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.buttonspace;
- start_x = cols/2 - start_x/2;
+ y = d->h - 2;
- for (i = 0; i < (int) bs.nbuttons; i++) {
- x = i * (bs.sizebutton + t.buttonspace);
- draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i],
- i == bs.curr, shortkey);
+ 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;
+ }
+
+ 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, char *yesoklabel,
- char *extralabel, char *nocancellabel, char *helplabel)
+set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
+ const char *cancellabel)
{
int i;
-#define SIZEBUTTON 8
-#define DEFAULT_BUTTON_LABEL LABEL_ok_label
-#define DEFAULT_BUTTON_VALUE BSDDIALOG_YESOK
-
-
- bs->nbuttons = 0;
- bs->curr = 0;
- bs->sizebutton = 0;
-
- if (yesoklabel != NULL && conf.button.no_ok == false) {
- bs->label[0] = yesoklabel;
- bs->value[0] = BSDDIALOG_YESOK;
- bs->nbuttons += 1;
+#define SIZEBUTTON 8
+#define DEFAULT_BUTTON_LABEL OK_LABEL
+#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
+ wchar_t first;
+
+ d->bs.nbuttons = 0;
+ d->bs.curr = 0;
+ d->bs.sizebutton = 0;
+ d->bs.shortcut = shortcut;
+
+ 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 (extralabel != NULL && conf.button.extra_button) {
- bs->label[bs->nbuttons] = extralabel;
- 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.no_cancel == false) {
- bs->label[bs->nbuttons] = nocancellabel;
- bs->value[bs->nbuttons] = BSDDIALOG_NOCANCEL;
- if (conf.button.defaultno)
- bs->curr = bs->nbuttons;
- bs->nbuttons += 1;
+ if (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 (helplabel != NULL && conf.button.help_button) {
- bs->label[bs->nbuttons] = helplabel;
- 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 (bs->nbuttons == 0) {
- bs->label[0] = DEFAULT_BUTTON_LABEL;
- bs->value[0] = DEFAULT_BUTTON_VALUE;
- 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.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 (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;
}
- bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
- for (i=1; i < (int) bs->nbuttons; i++)
- bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
- bs->sizebutton += 2;
-}
-
-/* Text */
-
-// old text, to delete in the future
-enum token { TEXT, WS, END };
+ 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;
+ }
-static bool check_set_ncurses_attr(WINDOW *win, char *text)
-{
- bool isattr;
- int colors[8] = {
- COLOR_BLACK,
- COLOR_RED,
- COLOR_GREEN,
- COLOR_YELLOW,
- COLOR_BLUE,
- COLOR_MAGENTA,
- COLOR_CYAN,
- COLOR_WHITE
- };
+ if (d->conf->button.right1_label != NULL) {
+ d->bs.label[d->bs.nbuttons] = d->conf->button.right1_label;
+ d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT1;
+ d->bs.nbuttons += 1;
+ }
- if (text[0] == '\0' || text[0] != '\\')
- return false;
- if (text[1] == '\0' || text[1] != 'Z')
- return false;
- if (text[2] == '\0')
- return false;
+ 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;
+ }
- if ((text[2] - 48) >= 0 && (text[2] - 48) < 8) {
- // tocheck: import BSD_COLOR
- // tofix color background
- wattron(win, COLOR_PAIR(colors[text[2] - 48] * 8 + COLOR_WHITE + 1));
- return true;
+ 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;
}
- isattr = true;
- switch (text[2]) {
- case 'n':
- wattrset(win, A_NORMAL);
- break;
- case 'b':
- wattron(win, A_BOLD);
- break;
- case 'B':
- wattroff(win, A_BOLD);
- break;
- case 'r':
- wattron(win, A_REVERSE);
- break;
- case 'R':
- wattroff(win, A_REVERSE);
- break;
- case 'u':
- wattron(win, A_UNDERLINE);
- break;
- case 'U':
- wattroff(win, A_UNDERLINE);
- break;
- default:
- isattr = false;
+ if (d->bs.nbuttons == 0) {
+ d->bs.label[0] = DEFAULT_BUTTON_LABEL;
+ d->bs.value[0] = DEFAULT_BUTTON_VALUE;
+ d->bs.nbuttons = 1;
}
- return isattr;
-}
+ for (i = 0; i < (int)d->bs.nbuttons; i++) {
+ mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
+ d->bs.first[i] = first;
+ }
-static bool isws(int ch)
-{
+ 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;
+ }
+ }
- return (ch == ' ' || ch == '\t' || ch == '\n');
+ 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;
}
-static int
-next_token(char *text, char *valuestr)
+bool shortcut_buttons(wint_t key, struct buttons *bs)
{
- int i, j;
- enum token tok;
-
- i = j = 0;
-
- if (text[0] == '\0')
- return END;
-
- while (text[i] != '\0') {
- if (isws(text[i])) {
- if (i == 0) {
- valuestr[0] = text[i];
- valuestr[1] = '\0';
- tok = WS;
- }
+ bool match;
+ unsigned int i;
+
+ match = false;
+ for (i = 0; i < bs->nbuttons; i++) {
+ if (towlower(key) == towlower(bs->first[i])) {
+ bs->curr = i;
+ match = true;
break;
}
-
- valuestr[j] = text[i];
- j++;
- valuestr[j] = '\0';
- i++;
- tok = TEXT;
}
- return tok;
+ return (match);
}
-static void
-print_string(WINDOW *win, int *y, int *x, int minx, int maxx, char *str, bool color)
+/*
+ * -4- (Auto) Sizing and (Auto) Position
+ */
+static int widget_max_height(struct bsddialog_conf *conf)
{
- int i, j, len, reallen;
-
- if(strlen(str) == 0)
- return;
+ int maxheight;
- len = reallen = strlen(str);
- if (color) {
- i=0;
- while (i < len) {
- if (check_set_ncurses_attr(win, str+i))
- reallen -= 3;
- i++;
- }
+ maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
+
+ if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
+ RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
+ else if (conf->y == BSDDIALOG_CENTER) {
+ maxheight -= conf->auto_topmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - top "
+ "margins <= 0");
+ } else if (conf->y > 0) {
+ maxheight -= conf->y;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - "
+ "shadow - y <= 0");
}
- i = 0;
- while (i < len) {
- if (*x + reallen > maxx) {
- *y = (*x != minx ? *y+1 : *y);
- *x = minx;
- }
- j = *x;
- while (j < maxx && i < len) {
- if (color && check_set_ncurses_attr(win, str+i)) {
- i += 3;
- } else {
- mvwaddch(win, *y, j, str[i]);
- i++;
- reallen--;
- j++;
- *x = j;
- }
- }
- }
+ maxheight -= conf->auto_downmargin;
+ if (maxheight <= 0)
+ RETURN_ERROR("Terminal too small, screen lines - Down margins "
+ "<= 0");
+
+ return (maxheight);
}
-void
-print_text(struct bsddialog_conf conf, WINDOW *pad, int starty, int minx, int maxx,
- char *text)
+static int widget_max_width(struct bsddialog_conf *conf)
{
- char *valuestr;
- int x, y;
- bool loop;
- enum token tok;
+ int maxwidth;
- valuestr = malloc(strlen(text) + 1);
+ maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
- x = minx;
- y = starty;
- loop = true;
- while (loop) {
- tok = next_token(text, valuestr);
- switch (tok) {
- case END:
- loop = false;
- break;
- case WS:
- text += strlen(valuestr);
- print_string(pad, &y, &x, minx, maxx, valuestr, false /*useless*/);
- break;
- case TEXT:
- text += strlen(valuestr);
- print_string(pad, &y, &x, minx, maxx, valuestr, conf.text.colors);
- break;
- }
+ if (conf->x > 0) {
+ maxwidth -= conf->x;
+ if (maxwidth <= 0)
+ RETURN_ERROR("Terminal too small, screen cols - shadow "
+ "- x <= 0");
}
- free(valuestr);
+ return (maxwidth);
}
-// new text funcs
-
-static bool is_ncurses_attr(char *text)
+static bool is_wtext_attr(const wchar_t *wtext)
{
- bool isattr;
-
- if (strnlen(text, 3) < 3)
- return false;
+ bool att;
- if (text[0] != '\\' || text[1] != 'Z')
- return false;
+ if (wcsnlen(wtext, 3) < 3)
+ return (false);
+ if (wtext[0] != L'\\' || wtext[1] != L'Z')
+ return (false);
- if ((text[2] - '0') >= 0 && (text[2] - '0') < 8)
- return true;
+ att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
- isattr = text[2] == 'n' || text[2] == 'b' || text[2] == 'B' ||
- text[2] == 'r' || text[2] == 'R' || text[2] == 'u' ||
- text[2] == 'U';
-
- return isattr;
+ return (att);
}
-static void
-print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color)
-{
- int i, j, len, reallen;
+#define NL -1
+#define WS -2
+#define TB -3
- if(strlen(str) == 0)
- return;
+struct textproperties {
+ int nword;
+ int *words;
+ uint8_t *wletters;
+ int maxwordcols;
+ int maxline;
+ bool hasnewline;
+};
- len = reallen = strlen(str);
- if (color) {
- i=0;
- while (i < len) {
- if (is_ncurses_attr(str+i))
- reallen -= 3;
- i++;
+static int
+text_properties(struct bsddialog_conf *conf, const char *text,
+ struct textproperties *tp)
+{
+ int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
+ wchar_t *wtext;
+
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
+
+ maxwords = 1024;
+ if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
+ RETURN_ERROR("Cannot alloc memory for text autosize");
+
+ 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;
}
- }
- i = 0;
- while (i < len) {
- if (*x + reallen > cols) {
- *y = (*x != 0 ? *y+1 : *y);
- if (*y >= *rows) {
- *rows = *y + 1;
- wresize(win, *rows, cols);
- }
- *x = 0;
- }
- j = *x;
- while (j < cols && i < len) {
- if (color && check_set_ncurses_attr(win, str+i)) {
- i += 3;
- } else {
- mvwaddch(win, *y, j, str[i]);
- i++;
- reallen--;
- j++;
- *x = j;
- }
+ if (tp->nword + 1 >= maxwords) {
+ maxwords += 1024;
+ tp->words = realloc(tp->words, maxwords * sizeof(int));
+ if (tp->words == NULL)
+ RETURN_ERROR("Cannot realloc memory for text "
+ "autosize");
}
- }
-}
-static void prepare_text(struct bsddialog_conf conf, char *text, char *buf)
-{
- int i, j;
+ if (wcschr(L"\t\n ", wtext[i]) != NULL) {
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
- i = j = 0;
- while (text[i] != '\0') {
- switch (text[i]) {
- case '\\':
- buf[j] = '\\';
- switch (text[i+1]) {
- case '\\':
- i++;
+ if (wordcols != 0) {
+ /* line */
+ currlinecols += wordcols;
+ /* word */
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ wordcols = 0;
+ }
+
+ switch (wtext[i]) {
+ case L'\t':
+ /* line */
+ currlinecols += tablen;
+ /* word */
+ tp->words[tp->nword] = TB;
break;
- case 'n':
- if (conf.text.no_nl_expand) {
- j++;
- buf[j] = 'n';
- } else
- buf[j] = '\n';
- i++;
+ case L'\n':
+ /* line */
+ tp->hasnewline = true;
+ tp->maxline = MAX(tp->maxline, currlinecols);
+ currlinecols = 0;
+ /* word */
+ tp->words[tp->nword] = NL;
break;
- case 't':
- if (conf.text.no_collapse) {
- j++;
- buf[j] = 't';
- } else
- buf[j] = '\t';
- i++;
+ case L' ':
+ /* line */
+ currlinecols += 1;
+ /* word */
+ tp->words[tp->nword] = WS;
break;
}
- break;
- case '\n':
- buf[j] = conf.text.cr_wrap ? ' ' : '\n';
- break;
- case '\t':
- buf[j] = conf.text.no_collapse ? '\t' : ' ';
- break;
- default:
- buf[j] = text[i];
+ tp->nword += 1;
+ } else {
+ tp->wletters[l] = wcwidth(wtext[i]);
+ wordcols += tp->wletters[l];
+ l++;
}
- i++;
- j += (buf[j] == ' ' && conf.text.trim && j > 0 && buf[j-1] == ' ') ?
- 0 : 1;
}
- buf[j] = '\0';
-}
-
-int
-get_text_properties(struct bsddialog_conf conf, char *text, int *maxword,
- int *maxline, int *nlines)
-{
- char *buf;
- int i, buflen, wordlen, linelen;
-
- if ((buf = malloc(strlen(text) + 1)) == NULL)
- RETURN_ERROR("Cannot building a buffer to find the properties "\
- "of the text properties");
-
- prepare_text(conf, text, buf);
-
- buflen = strlen(buf) + 1;
- *maxword = 0;
- wordlen = 0;
- for (i=0; i < buflen; i++) {
- if (buf[i] == '\t' || buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\0')
- if (wordlen != 0) {
- *maxword = MAX(*maxword, wordlen);
- wordlen = 0;
- continue;
- }
- if (conf.text.colors && is_ncurses_attr(buf + i))
- i += 3;
- else
- wordlen++;
- }
-
- *maxline = linelen = 0;
- *nlines = 1;
- for (i=0; i < buflen; i++) {
- switch (buf[i]) {
- case '\n':
- *nlines = *nlines + 1;
- case '\0':
- *maxline = MAX(*maxline, linelen);
- linelen = 0;
- break;
- default:
- if (conf.text.colors && is_ncurses_attr(buf + i))
- i += 3;
- else
- linelen++;
- }
+ /* word */
+ if (wordcols != 0) {
+ tp->words[tp->nword] = wordcols;
+ tp->nword += 1;
+ tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
}
- if (*nlines == 1 && *maxline == 0)
- *nlines = 0;
+ /* line */
+ tp->maxline = MAX(tp->maxline, currlinecols);
- free(buf);
+ free(wtext);
- return 0;
+ return (0);
}
static int
-print_textpad(struct bsddialog_conf conf, WINDOW *pad, int *rows, int cols, char *text)
+text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
+ int maxrows, int mincols, bool increasecols, int *h, int *w)
{
- char *buf, *string;
- int i, j, x, y;
- bool loop;
+ int i, j, x, y, z, l, line, maxwidth, tablen;
- if ((buf = malloc(strlen(text) + 1)) == NULL)
- RETURN_ERROR("Cannot build (analyze) text");
+ maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
- prepare_text(conf, text, buf);
-
- if ((string = malloc(strlen(text) + 1)) == NULL) {
- free(buf);
- RETURN_ERROR("Cannot build (analyze) text");
+ if (increasecols) {
+ mincols = MAX(mincols, tp->maxwordcols);
+ mincols = MAX(mincols,
+ (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
+ mincols = MIN(mincols, maxwidth);
}
- i = j = x = y = 0;
- loop = true;
- while (loop) {
- string[j] = buf[i];
- if (string[j] == '\0' || string[j] == '\n' ||
- string[j] == '\t' || string[j] == ' ') {
- if (j != 0) {
- string[j] = '\0';
- print_str(pad, rows, &y, &x, cols, string, conf.text.colors);
- }
- }
-
- switch (buf[i]) {
- case '\0':
- loop = false;
- break;
- case '\n':
- j = -1;
- x = 0;
- y++;
- break;
- case '\t':
- for (j=0; j<4 /*tablen*/; j++) {
+ while (true) {
+ x = 0;
+ y = 1;
+ line=0;
+ 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++;
- if (x >= cols) {
+ }
+ break;
+ case NL:
+ y++;
+ x = 0;
+ break;
+ case WS:
+ x++;
+ if (x >= mincols) {
x = 0;
y++;
}
+ 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;
+ }
+ }
}
- j = -1;
- break;
- case ' ':
- x++;
- if (x >= cols) {
- x = 0;
- y++;
- }
- j = -1;
- }
-
- if (y >= *rows) { /* check for whitespaces */
- *rows = y + 1;
- wresize(pad, *rows, cols);
+ line = MAX(line, x);
}
- j++;
- i++;
+ if (increasecols == false)
+ break;
+ if (mincols >= maxwidth)
+ break;
+ if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
+ break;
+ mincols++;
}
- free(string);
- free(buf);
+ *h = (tp->nword == 0) ? 0 : y;
+ *w = MIN(mincols, line); /* wtext can be less than mincols */
- return 0;
+ return (0);
}
-/* autosize */
+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)
+{
+ bool changewtext;
+ int wbuttons, maxhtext;
+ struct textproperties tp;
+
+ wbuttons = 0;
+ 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) - BORDERS - TEXTHMARGINS;
+ changewtext = false;
+ } else { /* fixed */
+ startwtext = cols - BORDERS - TEXTHMARGINS;
+ changewtext = false;
+ }
+
+ if (startwtext <= 0 && changewtext)
+ startwtext = 1;
-/*
- * max y, that is from 0 to LINES - 1 - t.shadowrows,
- * could not be max height but avoids problems with checksize
- */
-int widget_max_height(struct bsddialog_conf conf)
+ /* 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);
+
+ free(tp.words);
+ free(tp.wletters);
+
+ return (0);
+}
+
+static int
+widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
+ bool withbuttons)
{
- int maxheight;
+ int min;
+
+ /* dialog borders */
+ min = BORDERS;
- if ((maxheight = conf.shadow ? LINES - 1 - t.shadowrows : LINES - 1) <= 0)
- RETURN_ERROR("Terminal too small, LINES - shadow <= 0");
+ /* text */
+ min += htext;
- if (conf.y > 0)
- if ((maxheight -= conf.y) <=0)
- RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0");
+ /* specific widget lines without text */
+ min += hnotext;
- return maxheight;
+ /* buttons */
+ if (withbuttons)
+ min += HBUTTONS; /* buttons and their up-border */
+
+ /* conf.auto_minheight */
+ min = MAX(min, (int)conf->auto_minheight);
+
+ return (min);
}
-/*
- * max x, that is from 0 to COLS - 1 - t.shadowcols,
- * * could not be max height but avoids problems with checksize
- */
-int widget_max_width(struct bsddialog_conf conf)
+static int
+widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
+ struct buttons *bs)
+
{
- int maxwidth;
+ int min, delimtitle, wbottomtitle, wtitle;
+
+ min = 0;
+
+ /* buttons */
+ if (bs->nbuttons > 0)
+ min += buttons_min_width(bs);
+
+ /* text */
+ if (wtext > 0)
+ min = MAX(min, wtext + TEXTHMARGINS);
- if ((maxwidth = conf.shadow ? COLS - 1 - t.shadowcols : COLS - 1) <= 0)
- RETURN_ERROR("Terminal too small, COLS - shadow <= 0");
- if (conf.x > 0)
- if ((maxwidth -= conf.x) <=0)
- RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0");
+ /* specific widget min width */
+ min = MAX(min, minwidget);
- return maxwidth;
+ /* title */
+ if (conf->title != NULL) {
+ delimtitle = t.dialog.delimtitle ? 2 : 0;
+ wtitle = strcols(conf->title);
+ min = MAX(min, wtitle + 2 + delimtitle);
+ }
+
+ /* bottom title */
+ if (conf->bottomtitle != NULL) {
+ wbottomtitle = strcols(conf->bottomtitle);
+ min = MAX(min, wbottomtitle + 4);
+ }
+
+ /* dialog borders */
+ min += BORDERS;
+ /* conf.auto_minwidth */
+ min = MAX(min, (int)conf->auto_minwidth);
+
+ return (min);
}
int
-set_widget_size(struct bsddialog_conf conf, int rows, int cols, int *h, int *w)
+set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
{
int maxheight, maxwidth;
if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
- return BSDDIALOG_ERROR;
+ return (BSDDIALOG_ERROR);
if (rows == BSDDIALOG_FULLSCREEN)
*h = maxheight;
else if (rows < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) height");
- else if (rows > BSDDIALOG_AUTOSIZE) {
- if ((*h = rows) > maxheight)
- RETURN_ERROR("Height too big (> terminal height - "\
- "shadow");
- }
+ 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)
- return BSDDIALOG_ERROR;
+ return (BSDDIALOG_ERROR);
if (cols == BSDDIALOG_FULLSCREEN)
*w = maxwidth;
else if (cols < BSDDIALOG_FULLSCREEN)
RETURN_ERROR("Negative (less than -1) width");
- else if (cols > BSDDIALOG_AUTOSIZE) {
- if ((*w = cols) > maxwidth)
- RETURN_ERROR("Width too big (> terminal width - shadow)");
- }
+ 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;
+ return (0);
}
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)
{
+ 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 (conf.y == BSDDIALOG_CENTER)
- *y = LINES/2 - h/2;
- else if (conf.y < BSDDIALOG_CENTER)
+ if (cols == BSDDIALOG_AUTOSIZE) {
+ *w = widget_min_width(conf, wtext, minw, bs);
+ *w = MIN(*w, widget_max_width(conf));
+ }
+
+ return (0);
+}
+
+int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw)
+{
+ int minheight, minwidth;
+
+ minheight = BORDERS + hnotext;
+ if (bs->nbuttons > 0)
+ minheight += HBUTTONS;
+ if (h < minheight)
+ RETURN_FMTERROR("Current rows: %d, needed at least: %d",
+ h, minheight);
+
+ minwidth = 0;
+ if (bs->nbuttons > 0)
+ minwidth = buttons_min_width(bs);
+ minwidth = MAX(minwidth, minw);
+ minwidth += BORDERS;
+ if (w < minwidth)
+ RETURN_FMTERROR("Current cols: %d, nedeed at least %d",
+ w, minwidth);
+
+ return (0);
+}
+
+int
+set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
+{
+ int hshadow = conf->shadow ? (int)t.shadow.y : 0;
+ 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 >= LINES)
+ else if (conf->y >= SCREENLINES)
RETURN_ERROR("Begin Y under the terminal");
else
- *y = conf.y;
+ *y = conf->y;
- if ((*y + h + (conf.shadow ? (int) t.shadowrows : 0)) > LINES)
- RETURN_ERROR("The lower of the box under the terminal "\
+ 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 = COLS/2 - w/2;
- else if (conf.x < BSDDIALOG_CENTER)
+ if (conf->x == BSDDIALOG_CENTER)
+ *x = SCREENCOLS/2 - (w + wshadow)/2;
+ else if (conf->x < BSDDIALOG_CENTER)
RETURN_ERROR("Negative begin x (less than -1)");
- else if (conf.x >= COLS)
+ else if (conf->x >= SCREENCOLS)
RETURN_ERROR("Begin X over the right of the terminal");
else
- *x = conf.x;
+ *x = conf->x;
- if ((*x + w + (conf.shadow ? (int) t.shadowcols : 0)) > COLS)
- RETURN_ERROR("The right of the box over the terminal "\
+ if ((*x + w + wshadow) > SCREENCOLS)
+ RETURN_ERROR("The right of the box over the terminal "
"(begin X + width (+ shadow) > terminal cols)");
- return 0;
+ 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)
{
- int leftcolor, rightcolor;
- int ls, rs, ts, bs, tl, tr, bl, br;
- int ltee, rtee;
-
- ls = rs = ACS_VLINE;
- ts = bs = ACS_HLINE;
- tl = ACS_ULCORNER;
- tr = ACS_URCORNER;
- bl = ACS_LLCORNER;
- br = ACS_LRCORNER;
- ltee = ACS_LTEE;
- rtee = ACS_RTEE;
-
- if (conf.no_lines == false) {
- if (conf.ascii_lines) {
- ls = rs = '|';
- ts = bs = '-';
- tl = tr = bl = br = ltee = rtee = '+';
- }
- leftcolor = elev == RAISED ? t.lineraisecolor : t.linelowercolor;
- rightcolor = elev == RAISED ? t.linelowercolor : t.lineraisecolor;
- wattron(win, leftcolor);
- wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
- wattroff(win, leftcolor);
-
- wattron(win, rightcolor);
- mvwaddch(win, 0, cols-1, tr);
- mvwvline(win, 1, cols-1, rs, rows-2);
- mvwaddch(win, rows-1, cols-1, br);
- mvwhline(win, rows-1, 1, bs, cols-2);
- wattroff(win, rightcolor);
- }
+ 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);
}
-WINDOW *
-new_boxed_window(struct bsddialog_conf conf, int y, int x, int rows, int cols,
- enum elevation elev)
+/*
+ * -5- Widget components and utilities
+ */
+int hide_dialog(struct dialog *d)
{
- WINDOW *win;
+ WINDOW *clear;
- if ((win = newwin(rows, cols, y, x)) == NULL) {
- set_error_string("Cannot build boxed window");
- return NULL;
- }
+ 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);
- wbkgd(win, t.widgetcolor);
+ if (d->conf->shadow) {
+ mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
+ wrefresh(clear);
+ }
- draw_borders(conf, win, rows, cols, elev);
+ delwin(clear);
- return win;
+ return (0);
}
-/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
- */
-static int
-draw_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow,
- WINDOW *widget, int h, int w, enum elevation elev,
- WINDOW *textpad, int *htextpad, char *text, bool buttons)
+int f1help_dialog(struct bsddialog_conf *conf)
{
- int ts, ltee, rtee;
- int colorsurroundtitle;
-
- ts = conf.ascii_lines ? '-' : ACS_HLINE;
- ltee = conf.ascii_lines ? '+' : ACS_LTEE;
- rtee = conf.ascii_lines ? '+' : ACS_RTEE;
- colorsurroundtitle = elev == RAISED ? t.lineraisecolor : t.linelowercolor;
+ int output;
+ struct bsddialog_conf hconf;
- if (shadow != NULL)
- wnoutrefresh(shadow);
+ 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;
- // move / resize now or the caller?
- draw_borders(conf, widget, h, w, elev);
+ output = BSDDIALOG_OK;
+ if (conf->key.f1_message != NULL)
+ output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
- if (conf.title != NULL) {
- if (t.surroundtitle && conf.no_lines == false) {
- wattron(widget, colorsurroundtitle);
- mvwaddch(widget, 0, w/2 - strlen(conf.title)/2 - 1, rtee);
- wattroff(widget, colorsurroundtitle);
- }
- wattron(widget, t.titlecolor);
- mvwaddstr(widget, 0, w/2 - strlen(conf.title)/2, conf.title);
- wattroff(widget, t.titlecolor);
- if (t.surroundtitle && conf.no_lines == false) {
- wattron(widget, colorsurroundtitle);
- waddch(widget, ltee);
- wattroff(widget, colorsurroundtitle);
- }
- }
+ if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
+ output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
- if (conf.hline != NULL) {
- wattron(widget, t.bottomtitlecolor);
- wmove(widget, h - 1, w/2 - strlen(conf.hline)/2 - 1);
- waddch(widget, '[');
- waddstr(widget, conf.hline);
- waddch(widget, ']');
- wattroff(widget, t.bottomtitlecolor);
- }
+ return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
+}
- if (textpad == NULL && text != NULL) /* no pad, text null for textbox */
- print_text(conf, widget, 1, 2, w-3, text);
+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;
- if (buttons && conf.no_lines == false) {
- wattron(widget, t.lineraisecolor);
- mvwaddch(widget, h-3, 0, ltee);
- mvwhline(widget, h-3, 1, ts, w-2);
- wattroff(widget, t.lineraisecolor);
+ if (conf->no_lines)
+ return;
- wattron(widget, t.linelowercolor);
- mvwaddch(widget, h-3, w-1, rtee);
- wattroff(widget, t.linelowercolor);
+ if (conf->ascii_lines) {
+ ls = rs = '|';
+ ts = bs = '-';
+ tl = tr = bl = br = ltee = rtee = '+';
+ } 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;
}
- wnoutrefresh(widget);
-
- if (textpad == NULL)
- return 0; /* widget_init() ends */
+ getmaxyx(win, h, w);
+ leftcolor = elev == RAISED ?
+ t.dialog.lineraisecolor : t.dialog.linelowercolor;
+ rightcolor = elev == RAISED ?
+ t.dialog.linelowercolor : t.dialog.lineraisecolor;
+
+ wattron(win, leftcolor);
+ wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
+ wattroff(win, leftcolor);
+
+ wattron(win, rightcolor);
+ mvwaddch(win, 0, w-1, tr);
+ mvwvline(win, 1, w-1, rs, h-2);
+ mvwaddch(win, h-1, w-1, br);
+ mvwhline(win, h-1, 1, bs, w-2);
+ wattroff(win, rightcolor);
+}
- if (text != NULL) /* programbox etc */
- if (print_textpad(conf, textpad, htextpad,
- w - HBORDERS - t.texthmargin * 2, text) !=0)
- return BSDDIALOG_ERROR;
+void
+update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
+ enum elevation elev)
+{
+ wclear(win);
+ wresize(win, h, w);
+ mvwin(win, y, x);
+ draw_borders(conf, win, elev);
+}
- return 0;
+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);
}
/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
+ * -6- Dialog init/build, update/draw, destroy
*/
-int
-update_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow,
- WINDOW *widget, int h, int w, enum elevation elev,
- WINDOW *textpad, int *htextpad, char *text, bool buttons)
+void end_dialog(struct dialog *d)
{
- int error;
+ if (d->conf->sleep > 0)
+ sleep(d->conf->sleep);
- /* nothing for now */
+ delwin(d->textpad);
+ delwin(d->widget);
+ if (d->conf->shadow)
+ delwin(d->shadow);
- error = draw_widget_withtextpad(conf, shadow, widget, h, w,
- elev, textpad, htextpad, text, buttons);
+ if (d->conf->clear)
+ hide_dialog(d);
- return error;
+ if (d->conf->get_height != NULL)
+ *d->conf->get_height = d->h;
+ if (d->conf->get_width != NULL)
+ *d->conf->get_width = d->w;
}
-/*
- * `enum elevation elev` could be useless because it should be always RAISED,
- * to check at the end.
- */
-int
-new_widget_withtextpad(struct bsddialog_conf conf, WINDOW **shadow,
- WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
- WINDOW **textpad, int *htextpad, char *text, bool buttons)
+static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
{
- int error;
+ enum bsddialog_color bg;
- if (conf.shadow) {
- *shadow = newwin(h, w, y + t.shadowrows, x + t.shadowcols);
- if (*shadow == NULL)
- RETURN_ERROR("Cannot build shadow");
- wbkgd(*shadow, t.shadowcolor);
- }
+ if (is_wtext_attr(wtext) == false)
+ return (false);
- if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == NULL) {
- if (conf.shadow)
- delwin(*shadow);
- return BSDDIALOG_ERROR;
+ 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);
}
- if (textpad == NULL) { /* widget_init() */
- error = draw_widget_withtextpad(conf, *shadow, *widget, h, w,
- elev, NULL, NULL, text, buttons);
- return error;
+ 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;
}
- if (text != NULL) { /* programbox etc */
- *htextpad = 1;
- *textpad = newpad(*htextpad, w - HBORDERS - t.texthmargin * 2);
- if (*textpad == NULL) {
- delwin(*textpad);
- if (conf.shadow)
- delwin(*shadow);
- RETURN_ERROR("Cannot build the pad window for text");
- }
- wbkgd(*textpad, t.widgetcolor);
- }
+ return (true);
+}
- error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev,
- *textpad, htextpad, text, buttons);
+static void
+print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
+ bool color)
+{
+ int i, j, len, reallen, wc;
+ wchar_t ws[2];
+
+ ws[1] = L'\0';
- return error;
+ len = wcslen(str);
+ if (color) {
+ reallen = 0;
+ i=0;
+ while (i < len) {
+ if (is_wtext_attr(str+i) == false) {
+ reallen += wcwidth(str[i]);
+ i++;
+ } else {
+ i +=3 ;
+ }
+ }
+ } else
+ reallen = wcswidth(str, len);
+
+ i = 0;
+ while (i < len) {
+ if (*x + reallen > cols) {
+ *y = (*x != 0 ? *y+1 : *y);
+ if (*y >= *rows) {
+ *rows = *y + 1;
+ wresize(win, *rows, cols);
+ }
+ *x = 0;
+ }
+ j = *x;
+ while (j < cols && i < len) {
+ if (color && check_set_wtext_attr(win, str+i)) {
+ i += 3;
+ } else if (j + wcwidth(str[i]) > cols) {
+ break;
+ } else {
+ /* inline mvwaddwch() for efficiency */
+ ws[0] = str[i];
+ mvwaddwstr(win, *y, j, ws);
+ wc = wcwidth(str[i]);;
+ reallen -= wc;
+ j += wc;
+ i++;
+ *x = j;
+ }
+ }
+ }
}
-int
-new_widget(struct bsddialog_conf conf, WINDOW **widget, int *y, int *x,
- char *text, int *h, int *w, WINDOW **shadow, bool buttons)
+static int
+print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
{
+ bool loop;
+ int i, j, z, rows, cols, x, y, tablen;
+ wchar_t *wtext, *string;
+
+ if ((wtext = alloc_mbstows(text)) == NULL)
+ RETURN_ERROR("Cannot allocate/print text in wchar_t*");
- // to delete (each widget has to check its x,y,h,w)
- if (*h <= 0)
- ; /* todo */
+ if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
+ RETURN_ERROR("Cannot build (analyze) text");
- if (*w <= 0)
- ; /* todo */
+ getmaxyx(pad, rows, cols);
+ tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
- *y = (conf.y < 0) ? (LINES/2 - *h/2) : conf.y;
- *x = (conf.x < 0) ? (COLS/2 - *w/2) : conf.x;
+ i = j = x = y = 0;
+ loop = true;
+ while (loop) {
+ string[j] = wtext[i];
- if (new_widget_withtextpad(conf, shadow, widget, *y, *x, *h, *w, RAISED,
- NULL, NULL, text, buttons) != 0)
- return BSDDIALOG_ERROR;
+ if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
+ string[j] = L'\0';
+ print_string(pad, &rows, cols, &y, &x, string,
+ conf->text.escape);
+ }
- if (conf.shadow)
- wrefresh(*shadow);
+ 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;
+ }
- wrefresh(*widget);
+ if (y >= rows) {
+ rows = y + 1;
+ wresize(pad, rows, cols);
+ }
+
+ j++;
+ i++;
+ }
+
+ free(wtext);
+ free(string);
- return 0;
+ return (0);
}
-void
-end_widget_withtextpad(struct bsddialog_conf conf, WINDOW *window, int h, int w,
- WINDOW *textpad, WINDOW *shadow)
+int draw_dialog(struct dialog *d)
{
- int y, x;
+ int wtitle, wbottomtitle, ts, ltee, rtee;
- getbegyx(window, y, x); /* for clear, add y & x to args? */
+ ts = d->conf->ascii_lines ? '-' : ACS_HLINE;
+ ltee = d->conf->ascii_lines ? '+' : ACS_LTEE;
+ rtee = d->conf->ascii_lines ? '+' : ACS_RTEE;
- if (conf.sleep > 0)
- sleep(conf.sleep);
+ 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)
- delwin(textpad);
+ wclear(d->widget);
+ wresize(d->widget, d->h, d->w);
+ mvwin(d->widget, d->y, d->x);
+ draw_borders(d->conf, d->widget, RAISED);
+
+ if (d->conf->title != NULL) {
+ if ((wtitle = strcols(d->conf->title)) < 0)
+ return (BSDDIALOG_ERROR);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwaddch(d->widget, 0, d->w/2 - wtitle/2 -1, rtee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+ wattron(d->widget, t.dialog.titlecolor);
+ mvwaddstr(d->widget, 0, d->w/2 - wtitle/2, d->conf->title);
+ wattroff(d->widget, t.dialog.titlecolor);
+ if (t.dialog.delimtitle && d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ waddch(d->widget, ltee);
+ wattroff(d->widget, t.dialog.lineraisecolor);
+ }
+ }
- delwin(window);
+ if (d->bs.nbuttons > 0) {
+ if (d->conf->no_lines == false) {
+ wattron(d->widget, t.dialog.lineraisecolor);
+ mvwaddch(d->widget, d->h-3, 0, ltee);
+ mvwhline(d->widget, d->h-3, 1, ts, d->w-2);
+ wattroff(d->widget, t.dialog.lineraisecolor);
- if (conf.shadow)
- delwin(shadow);
+ wattron(d->widget, t.dialog.linelowercolor);
+ mvwaddch(d->widget, d->h-3, d->w-1, rtee);
+ wattroff(d->widget, t.dialog.linelowercolor);
+ }
+ draw_buttons(d);
+ }
+
+ 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);
+ }
+
+ wnoutrefresh(d->widget);
+
+ 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 (print_textpad(d->conf, d->textpad, d->text) != 0)
+ return (BSDDIALOG_ERROR);
- if (conf.clear)
- hide_widget(y, x, h, w, shadow != NULL);
+ d->built = true;
- if (conf.get_height != NULL)
- *conf.get_height = h;
- if (conf.get_width != NULL)
- *conf.get_width = w;
+ return (0);
}
-void
-end_widget(struct bsddialog_conf conf, WINDOW *window, int h, int w,
- WINDOW *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);
+ }
- end_widget_withtextpad(conf, window, h, w, NULL, shadow);
-}
+ 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