2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/param.h>
38 #include "bsddialog.h"
39 #include "bsddialog_theme.h"
42 #define ERRBUFLEN 1024 /* Error buffer len */
45 static char errorbuffer[ERRBUFLEN];
47 const char *get_error_string(void)
52 void set_error_string(const char *str)
54 strncpy(errorbuffer, str, ERRBUFLEN-1);
58 wchar_t* alloc_mbstows(const char *mbstring)
60 size_t charlen, nchar;
62 const char *pmbstring;
67 memset(&mbs, 0, sizeof(mbs));
68 while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
69 charlen != (size_t)-1 && charlen != (size_t)-2) {
74 if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL)
76 mbstowcs(wstring, mbstring, nchar);
81 void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
87 mvwaddwstr(w, y, x, ws);
91 int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
96 size_t charlen, mb_cur_max;
101 mb_cur_max = MB_CUR_MAX;
103 memset(&mbs, 0, sizeof(mbs));
104 while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
105 charlen != (size_t)-1 && charlen != (size_t)-2) {
106 if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
108 w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
109 ncol += (w < 0) ? 0 : w;
110 if (w > 1 && wch != L'\t')
117 if (has_multi_col != NULL)
118 *has_multi_col = multicol;
123 unsigned int strcols(const char *mbstring)
127 size_t charlen, mb_cur_max;
131 mb_cur_max = MB_CUR_MAX;
133 memset(&mbs, 0, sizeof(mbs));
134 while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
135 charlen != (size_t)-1 && charlen != (size_t)-2) {
136 if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
138 w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
139 ncol += (w < 0) ? 0 : w;
147 int hide_widget(int y, int x, int h, int w, bool withshadow)
151 if ((clear = newwin(h, w, y + t.shadow.y, x + t.shadow.x)) == NULL)
152 RETURN_ERROR("Cannot hide the widget");
153 wbkgd(clear, t.screen.color);
167 int f1help(struct bsddialog_conf *conf)
170 struct bsddialog_conf hconf;
172 bsddialog_initconf(&hconf);
173 hconf.title = "HELP";
174 hconf.button.ok_label = "EXIT";
176 hconf.ascii_lines = conf->ascii_lines;
177 hconf.no_lines = conf->no_lines;
178 hconf.shadow = conf->shadow;
179 hconf.text.highlight = conf->text.highlight;
181 output = BSDDIALOG_OK;
182 if (conf->key.f1_message != NULL)
183 output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
185 if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
186 output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
188 return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
193 draw_button(WINDOW *window, int y, int x, int size, const char *text,
194 wchar_t first, bool selected, bool shortcut)
196 int i, color_arrows, color_shortkey, color_button;
199 color_arrows = t.button.f_delimcolor;
200 color_shortkey = t.button.f_shortcutcolor;
201 color_button = t.button.f_color;
203 color_arrows = t.button.delimcolor;
204 color_shortkey = t.button.shortcutcolor;
205 color_button = t.button.color;
208 wattron(window, color_arrows);
209 mvwaddch(window, y, x, t.button.leftdelim);
210 wattroff(window, color_arrows);
211 wattron(window, color_button);
212 for (i = 1; i < size - 1; i++)
214 wattroff(window, color_button);
215 wattron(window, color_arrows);
216 mvwaddch(window, y, x + i, t.button.rightdelim);
217 wattroff(window, color_arrows);
219 x = x + 1 + ((size - 2 - strcols(text))/2);
220 wattron(window, color_button);
221 mvwaddstr(window, y, x, text);
222 wattroff(window, color_button);
225 wattron(window, color_shortkey);
226 mvwaddwch(window, y, x, first);
227 wattroff(window, color_shortkey);
232 draw_buttons(WINDOW *window, struct buttons bs, bool shortcut)
234 int i, x, startx, y, rows, cols;
235 unsigned int newmargin, margin, wbuttons;
237 getmaxyx(window, rows, cols);
240 newmargin = cols - VBORDERS - (bs.nbuttons * bs.sizebutton);
241 newmargin /= (bs.nbuttons + 1);
242 newmargin = MIN(newmargin, t.button.maxmargin);
243 if (newmargin == 0) {
244 margin = t.button.minmargin;
245 wbuttons = buttons_min_width(bs);
248 wbuttons = bs.nbuttons * bs.sizebutton;
249 wbuttons += (bs.nbuttons + 1) * margin;
252 startx = (cols)/2 - wbuttons/2 + newmargin;
253 for (i = 0; i < (int)bs.nbuttons; i++) {
254 x = i * (bs.sizebutton + margin);
255 draw_button(window, y, startx + x, bs.sizebutton, bs.label[i],
256 bs.first[i], i == bs.curr, shortcut);
261 get_buttons(struct bsddialog_conf *conf, struct buttons *bs,
262 const char *yesoklabel, const char *nocancellabel)
266 #define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL
267 #define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
274 if (yesoklabel != NULL && conf->button.without_ok == false) {
275 bs->label[0] = conf->button.ok_label != NULL ?
276 conf->button.ok_label : yesoklabel;
277 bs->value[0] = BSDDIALOG_OK;
281 if (conf->button.with_extra) {
282 bs->label[bs->nbuttons] = conf->button.extra_label != NULL ?
283 conf->button.extra_label : "Extra";
284 bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
288 if (nocancellabel != NULL && conf->button.without_cancel == false) {
289 bs->label[bs->nbuttons] = conf->button.cancel_label ?
290 conf->button.cancel_label : nocancellabel;
291 bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
292 if (conf->button.default_cancel)
293 bs->curr = bs->nbuttons;
297 if (conf->button.with_help) {
298 bs->label[bs->nbuttons] = conf->button.help_label != NULL ?
299 conf->button.help_label : "Help";
300 bs->value[bs->nbuttons] = BSDDIALOG_HELP;
304 if (conf->button.generic1_label != NULL) {
305 bs->label[bs->nbuttons] = conf->button.generic1_label;
306 bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1;
310 if (conf->button.generic2_label != NULL) {
311 bs->label[bs->nbuttons] = conf->button.generic2_label;
312 bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
316 if (bs->nbuttons == 0) {
317 bs->label[0] = DEFAULT_BUTTON_LABEL;
318 bs->value[0] = DEFAULT_BUTTON_VALUE;
322 for (i = 0; i < (int)bs->nbuttons; i++) {
323 mbtowc(&first, bs->label[i], MB_CUR_MAX);
324 bs->first[i] = first;
327 if (conf->button.default_label != NULL) {
328 for (i = 0; i < (int)bs->nbuttons; i++) {
329 if (strcmp(conf->button.default_label,
335 bs->sizebutton = MAX(SIZEBUTTON - 2, strcols(bs->label[0]));
336 for (i = 1; i < (int)bs->nbuttons; i++)
337 bs->sizebutton = MAX(bs->sizebutton, strcols(bs->label[i]));
341 int buttons_min_width(struct buttons bs)
345 width = bs.nbuttons * bs.sizebutton;
347 width += (bs.nbuttons - 1) * t.button.minmargin;
352 bool shortcut_buttons(wint_t key, struct buttons *bs)
358 for (i = 0; i < bs->nbuttons; i++) {
359 if (towlower(key) == towlower(bs->first[i])) {
370 static bool is_wtext_attr(const wchar_t *wtext)
372 if (wcsnlen(wtext, 3) < 3)
375 if (wtext[0] != L'\\' || wtext[1] != L'Z')
378 return (wcschr(L"nbBrRuU01234567", wtext[2]) == NULL ? false : true);
381 static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
383 enum bsddialog_color bg;
385 if (is_wtext_attr(wtext) == false)
388 if ((wtext[2] - L'0') >= 0 && (wtext[2] - L'0') < 8) {
389 bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
390 wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
396 wattron(win, t.dialog.color);
397 wattrset(win, A_NORMAL);
400 wattron(win, A_BOLD);
403 wattroff(win, A_BOLD);
406 wattron(win, A_REVERSE);
409 wattroff(win, A_REVERSE);
412 wattron(win, A_UNDERLINE);
415 wattroff(win, A_UNDERLINE);
424 print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
427 int i, j, len, reallen, wc;
437 if (is_wtext_attr(str+i) == false)
438 reallen += wcwidth(str[i]);
442 reallen = wcswidth(str, len);
446 if (*x + reallen > cols) {
447 *y = (*x != 0 ? *y+1 : *y);
450 wresize(win, *rows, cols);
455 while (j < cols && i < len) {
456 if (color && check_set_wtext_attr(win, str+i)) {
458 } else if (j + wcwidth(str[i]) > cols) {
461 /* inline mvwaddwch() for efficiency */
463 mvwaddwstr(win, *y, j, ws);
464 wc = wcwidth(str[i]);;
475 print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
478 int i, j, z, rows, cols, x, y, tablen;
479 wchar_t *wtext, *string;
481 if ((wtext = alloc_mbstows(text)) == NULL)
482 RETURN_ERROR("Cannot allocate/print text in wchar_t*");
484 if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
485 RETURN_ERROR("Cannot build (analyze) text");
487 getmaxyx(pad, rows, cols);
488 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
493 string[j] = wtext[i];
495 if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
497 print_string(pad, &rows, cols, &y, &x, string,
498 conf->text.highlight);
511 for (z = 0; z < tablen; z++) {
531 wresize(pad, rows, cols);
549 struct textproperties {
559 text_properties(struct bsddialog_conf *conf, const char *text,
560 struct textproperties *tp)
562 int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
565 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
568 if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
569 RETURN_ERROR("Cannot alloc memory for text autosize");
571 if ((wtext = alloc_mbstows(text)) == NULL)
572 RETURN_ERROR("Cannot allocate/autosize text in wchar_t*");
573 wtextlen = wcslen(wtext);
574 if ((tp->wletters = calloc(wtextlen, sizeof(uint8_t))) == NULL)
575 RETURN_ERROR("Cannot allocate wletters for text autosizing");
580 tp->hasnewline = false;
584 for (i = 0; i < wtextlen; i++) {
585 if (conf->text.highlight && is_wtext_attr(wtext + i)) {
586 i += 2; /* +1 for update statement */
590 if (tp->nword + 1 >= maxwords) {
592 tp->words = realloc(tp->words, maxwords * sizeof(int));
593 if (tp->words == NULL)
594 RETURN_ERROR("Cannot realloc memory for text "
598 if (wcschr(L"\t\n ", wtext[i]) != NULL) {
599 tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
603 currlinecols += wordcols;
605 tp->words[tp->nword] = wordcols;
613 currlinecols += tablen;
615 tp->words[tp->nword] = TB;
619 tp->hasnewline = true;
620 tp->maxline = MAX(tp->maxline, currlinecols);
623 tp->words[tp->nword] = NL;
629 tp->words[tp->nword] = WS;
634 tp->wletters[l] = wcwidth(wtext[i]);
635 wordcols += tp->wletters[l];
641 tp->words[tp->nword] = wordcols;
643 tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
646 tp->maxline = MAX(tp->maxline, currlinecols);
655 text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
656 int maxrows, int mincols, bool increasecols, int *h, int *w)
658 int i, j, x, y, z, l, line, maxwidth, tablen;
660 maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS;
661 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
664 mincols = MAX(mincols, tp->maxwordcols);
665 mincols = MAX(mincols,
666 (int)conf->auto_minwidth - HBORDERS - TEXTHMARGINS);
667 mincols = MIN(mincols, maxwidth);
675 for (i = 0; i < tp->nword; i++) {
676 switch (tp->words[i]) {
678 for (j = 0; j < tablen; j++) {
698 if (tp->words[i] + x <= mincols) {
700 for (z = 0 ; z != tp->words[i]; l++ )
701 z += tp->wletters[l];
702 } else if (tp->words[i] <= mincols) {
705 for (z = 0 ; z != tp->words[i]; l++ )
706 z += tp->wletters[l];
708 for (j = tp->words[i]; j > 0; ) {
709 y = (x == 0) ? y : y + 1;
711 while (z != j && z < mincols) {
712 z += tp->wletters[l];
724 if (increasecols == false)
726 if (mincols >= maxwidth)
728 if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
733 *h = (tp->nword == 0) ? 0 : y;
734 *w = MIN(mincols, line); /* wtext can be less than mincols */
740 text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
741 struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
744 int wbuttons, maxhtext;
745 struct textproperties tp;
749 wbuttons = buttons_min_width(*bs);
752 if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
753 maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext;
755 maxhtext = rows - VBORDERS - rowsnotext;
760 maxhtext = 1; /* text_autosize() computes always htext */
763 if (cols == BSDDIALOG_AUTOSIZE) {
764 startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
766 } else if (cols == BSDDIALOG_FULLSCREEN) {
767 startwtext = widget_max_width(conf) - VBORDERS - TEXTHMARGINS;
770 startwtext = cols - VBORDERS - TEXTHMARGINS;
774 if (startwtext <= 0 && changewtext)
777 RETURN_ERROR("Fullscreen or fixed cols to print text <=0");
779 /* Sizing calculation */
780 if (text_properties(conf, text, &tp) != 0)
781 return (BSDDIALOG_ERROR);
782 if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
784 return (BSDDIALOG_ERROR);
792 /* Widget size and position */
793 int widget_max_height(struct bsddialog_conf *conf)
797 maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
799 RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
801 if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
802 RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
803 else if (conf->y == BSDDIALOG_CENTER) {
804 maxheight -= conf->auto_topmargin;
806 RETURN_ERROR("Terminal too small, screen lines - top "
808 } else if (conf->y > 0) {
809 maxheight -= conf->y;
811 RETURN_ERROR("Terminal too small, screen lines - "
815 maxheight -= conf->auto_downmargin;
817 RETURN_ERROR("Terminal too small, screen lines - Down margins "
823 int widget_max_width(struct bsddialog_conf *conf)
827 maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
829 RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
834 RETURN_ERROR("Terminal too small, screen cols - shadow "
842 widget_min_height(struct bsddialog_conf *conf, int htext, int minwidget,
851 min += 2; /* buttons and border */
856 /* specific widget min height */
861 /* conf.auto_minheight */
862 min = MAX(min, (int)conf->auto_minheight);
863 /* avoid terminal overflow */
864 min = MIN(min, widget_max_height(conf));
870 widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
874 int min, delimtitle, wbottomtitle, wtitle;
880 min += buttons_min_width(*bs);
884 min = MAX(min, wtext + TEXTHMARGINS);
886 /* specific widget min width */
887 min = MAX(min, minwidget);
890 if (conf->title != NULL) {
891 delimtitle = t.dialog.delimtitle ? 2 : 0;
892 wtitle = strcols(conf->title);
893 min = MAX(min, wtitle + 2 + delimtitle);
897 if (conf->bottomtitle != NULL) {
898 wbottomtitle = strcols(conf->bottomtitle);
899 min = MAX(min, wbottomtitle + 4);
904 /* conf.auto_minwidth */
905 min = MAX(min, (int)conf->auto_minwidth);
906 /* avoid terminal overflow */
907 min = MIN(min, widget_max_width(conf));
913 set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
915 int maxheight, maxwidth;
917 if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
918 return (BSDDIALOG_ERROR);
920 if (rows == BSDDIALOG_FULLSCREEN)
922 else if (rows < BSDDIALOG_FULLSCREEN)
923 RETURN_ERROR("Negative (less than -1) height");
924 else if (rows > BSDDIALOG_AUTOSIZE) /* fixed rows */
925 *h = MIN(rows, maxheight); /* rows is at most maxheight */
926 /* rows == AUTOSIZE: each widget has to set its size */
928 if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
929 return (BSDDIALOG_ERROR);
931 if (cols == BSDDIALOG_FULLSCREEN)
933 else if (cols < BSDDIALOG_FULLSCREEN)
934 RETURN_ERROR("Negative (less than -1) width");
935 else if (cols > BSDDIALOG_AUTOSIZE) /* fixed cols */
936 *w = MIN(cols, maxwidth); /* cols is at most maxwidth */
937 /* cols == AUTOSIZE: each widget has to set its size */
943 set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
945 int hshadow = conf->shadow ? (int)t.shadow.y : 0;
946 int wshadow = conf->shadow ? (int)t.shadow.x : 0;
948 if (conf->y == BSDDIALOG_CENTER) {
949 *y = SCREENLINES/2 - (h + hshadow)/2;
950 if (*y < (int)conf->auto_topmargin)
951 *y = conf->auto_topmargin;
952 if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin)
953 *y = SCREENLINES - h - hshadow - conf->auto_downmargin;
955 else if (conf->y < BSDDIALOG_CENTER)
956 RETURN_ERROR("Negative begin y (less than -1)");
957 else if (conf->y >= SCREENLINES)
958 RETURN_ERROR("Begin Y under the terminal");
962 if (*y + h + hshadow > SCREENLINES)
963 RETURN_ERROR("The lower of the box under the terminal "
964 "(begin Y + height (+ shadow) > terminal lines)");
967 if (conf->x == BSDDIALOG_CENTER)
968 *x = SCREENCOLS/2 - (w + wshadow)/2;
969 else if (conf->x < BSDDIALOG_CENTER)
970 RETURN_ERROR("Negative begin x (less than -1)");
971 else if (conf->x >= SCREENCOLS)
972 RETURN_ERROR("Begin X over the right of the terminal");
976 if ((*x + w + wshadow) > SCREENCOLS)
977 RETURN_ERROR("The right of the box over the terminal "
978 "(begin X + width (+ shadow) > terminal cols)");
983 /* Widgets build, update, destroy */
985 draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
988 int leftcolor, rightcolor;
989 int ls, rs, ts, bs, tl, tr, bl, br, ltee, rtee;
994 if (conf->ascii_lines) {
997 tl = tr = bl = br = ltee = rtee = '+';
1000 ts = bs = ACS_HLINE;
1009 leftcolor = elev == RAISED ?
1010 t.dialog.lineraisecolor : t.dialog.linelowercolor;
1011 rightcolor = elev == RAISED ?
1012 t.dialog.linelowercolor : t.dialog.lineraisecolor;
1013 wattron(win, leftcolor);
1014 wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
1015 wattroff(win, leftcolor);
1017 wattron(win, rightcolor);
1018 mvwaddch(win, 0, cols-1, tr);
1019 mvwvline(win, 1, cols-1, rs, rows-2);
1020 mvwaddch(win, rows-1, cols-1, br);
1021 mvwhline(win, rows-1, 1, bs, cols-2);
1022 wattroff(win, rightcolor);
1026 new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
1027 enum elevation elev)
1031 if ((win = newwin(rows, cols, y, x)) == NULL) {
1032 set_error_string("Cannot build boxed window");
1036 wbkgd(win, t.dialog.color);
1038 draw_borders(conf, win, rows, cols, elev);
1044 draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
1045 WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons)
1047 int h, w, wtitle, wbottomtitle, ts, ltee, rtee;
1049 ts = conf->ascii_lines ? '-' : ACS_HLINE;
1050 ltee = conf->ascii_lines ? '+' : ACS_LTEE;
1051 rtee = conf->ascii_lines ? '+' : ACS_RTEE;
1053 getmaxyx(widget, h, w);
1056 wnoutrefresh(shadow);
1058 draw_borders(conf, widget, h, w, RAISED);
1060 if (conf->title != NULL) {
1061 if ((wtitle = strcols(conf->title)) < 0)
1062 return (BSDDIALOG_ERROR);
1063 if (t.dialog.delimtitle && conf->no_lines == false) {
1064 wattron(widget, t.dialog.lineraisecolor);
1065 mvwaddch(widget, 0, w/2 - wtitle/2 -1, rtee);
1066 wattroff(widget, t.dialog.lineraisecolor);
1068 wattron(widget, t.dialog.titlecolor);
1069 mvwaddstr(widget, 0, w/2 - wtitle/2, conf->title);
1070 wattroff(widget, t.dialog.titlecolor);
1071 if (t.dialog.delimtitle && conf->no_lines == false) {
1072 wattron(widget, t.dialog.lineraisecolor);
1073 waddch(widget, ltee);
1074 wattroff(widget, t.dialog.lineraisecolor);
1079 if (conf->no_lines == false) {
1080 wattron(widget, t.dialog.lineraisecolor);
1081 mvwaddch(widget, h-3, 0, ltee);
1082 mvwhline(widget, h-3, 1, ts, w-2);
1083 wattroff(widget, t.dialog.lineraisecolor);
1085 wattron(widget, t.dialog.linelowercolor);
1086 mvwaddch(widget, h-3, w-1, rtee);
1087 wattroff(widget, t.dialog.linelowercolor);
1089 draw_buttons(widget, *bs, shortcutbuttons);
1092 if (conf->bottomtitle != NULL) {
1093 if ((wbottomtitle = strcols(conf->bottomtitle)) < 0)
1094 return (BSDDIALOG_ERROR);
1095 wattron(widget, t.dialog.bottomtitlecolor);
1096 wmove(widget, h - 1, w/2 - wbottomtitle/2 - 1);
1097 waddch(widget, ' ');
1098 waddstr(widget, conf->bottomtitle);
1099 waddch(widget, ' ');
1100 wattroff(widget, t.dialog.bottomtitlecolor);
1103 wnoutrefresh(widget);
1105 if (textpad != NULL && text != NULL) /* textbox */
1106 if (print_textpad(conf, textpad, text) !=0)
1107 return (BSDDIALOG_ERROR);
1113 update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
1114 int y, int x, int h, int w, WINDOW *textpad, const char *text,
1115 struct buttons *bs, bool shortcutbuttons)
1121 mvwin(shadow, y + t.shadow.y, x + t.shadow.x);
1122 wresize(shadow, h, w);
1126 mvwin(widget, y, x);
1127 wresize(widget, h, w);
1129 if (textpad != NULL) {
1131 wresize(textpad, 1, w - HBORDERS - TEXTHMARGINS);
1134 error = draw_dialog(conf, shadow, widget, textpad, text, bs,
1141 new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y,
1142 int x, int h, int w, WINDOW **textpad, const char *text, struct buttons *bs,
1143 bool shortcutbuttons)
1148 *shadow = newwin(h, w, y + t.shadow.y, x + t.shadow.x);
1149 if (*shadow == NULL)
1150 RETURN_ERROR("Cannot build shadow");
1151 wbkgd(*shadow, t.shadow.color);
1154 if ((*widget = new_boxed_window(conf, y, x, h, w, RAISED)) == NULL) {
1157 return (BSDDIALOG_ERROR);
1160 if (textpad != NULL && text != NULL) { /* textbox */
1161 *textpad = newpad(1, w - HBORDERS - TEXTHMARGINS);
1162 if (*textpad == NULL) {
1166 RETURN_ERROR("Cannot build the pad window for text");
1168 wbkgd(*textpad, t.dialog.color);
1171 error = draw_dialog(conf, *shadow, *widget,
1172 textpad == NULL ? NULL : *textpad, text, bs, shortcutbuttons);
1178 end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget,
1183 getbegyx(widget, y, x);
1184 getmaxyx(widget, h, w);
1186 if (conf->sleep > 0)
1189 if (textpad != NULL)
1198 hide_widget(y, x, h, w, conf->shadow);
1200 if (conf->get_height != NULL)
1201 *conf->get_height = h;
1202 if (conf->get_width != NULL)
1203 *conf->get_width = w;