diff options
Diffstat (limited to 'lib/lib_util.c')
| -rw-r--r-- | lib/lib_util.c | 549 |
1 files changed, 394 insertions, 155 deletions
diff --git a/lib/lib_util.c b/lib/lib_util.c index 4c2ab76bc592..fcdf4c3d8769 100644 --- a/lib/lib_util.c +++ b/lib/lib_util.c @@ -32,13 +32,14 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <wchar.h> +#include <wctype.h> #include "bsddialog.h" #include "bsddialog_theme.h" #include "lib_util.h" -#define TABLEN 4 /* Default tab len */ -#define ERRBUFLEN 1024 /* Error buffer */ +#define ERRBUFLEN 1024 /* Error buffer len */ /* Error */ static char errorbuffer[ERRBUFLEN]; @@ -53,12 +54,101 @@ void set_error_string(const char *str) strncpy(errorbuffer, str, ERRBUFLEN-1); } +/* Unicode */ +wchar_t* alloc_mbstows(const char *mbstring) +{ + size_t charlen, nchar; + mbstate_t mbs; + const char *pmbstring; + wchar_t *wstring; + + nchar = 1; + pmbstring = mbstring; + memset(&mbs, 0, sizeof(mbs)); + while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 && + charlen != (size_t)-1 && charlen != (size_t)-2) { + pmbstring += charlen; + nchar++; + } + + if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL) + return (NULL); + mbstowcs(wstring, mbstring, nchar); + + return (wstring); +} + +void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch) +{ + wchar_t ws[2]; + + ws[0] = wch; + ws[1] = L'\0'; + mvwaddwstr(w, y, x, ws); + +} + +int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col) +{ + bool multicol; + int w; + unsigned int ncol; + size_t charlen, mb_cur_max; + wchar_t wch; + mbstate_t mbs; + + multicol = false; + mb_cur_max = MB_CUR_MAX; + ncol = 0; + memset(&mbs, 0, sizeof(mbs)); + while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 && + charlen != (size_t)-1 && charlen != (size_t)-2) { + if (mbtowc(&wch, mbstring, mb_cur_max) < 0) + return (-1); + w = (wch == L'\t') ? TABSIZE : wcwidth(wch); + ncol += (w < 0) ? 0 : w; + if (w > 1 && wch != L'\t') + multicol = true; + mbstring += charlen; + } + + if (cols != NULL) + *cols = ncol; + if (has_multi_col != NULL) + *has_multi_col = multicol; + + return (0); +} + +unsigned int strcols(const char *mbstring) +{ + int w; + unsigned int ncol; + size_t charlen, mb_cur_max; + wchar_t wch; + mbstate_t mbs; + + mb_cur_max = MB_CUR_MAX; + ncol = 0; + memset(&mbs, 0, sizeof(mbs)); + while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 && + charlen != (size_t)-1 && charlen != (size_t)-2) { + if (mbtowc(&wch, mbstring, mb_cur_max) < 0) + return (0); + w = (wch == L'\t') ? TABSIZE : wcwidth(wch); + ncol += (w < 0) ? 0 : w; + mbstring += charlen; + } + + return (ncol); +} + /* Clear */ int hide_widget(int y, int x, int h, int w, bool withshadow) { WINDOW *clear; - if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL) + if ((clear = newwin(h, w, y + t.shadow.y, x + t.shadow.x)) == NULL) RETURN_ERROR("Cannot hide the widget"); wbkgd(clear, t.screen.color); @@ -101,7 +191,7 @@ int f1help(struct bsddialog_conf *conf) /* Buttons */ static void draw_button(WINDOW *window, int y, int x, int size, const char *text, - bool selected, bool shortcut) + wchar_t first, bool selected, bool shortcut) { int i, color_arrows, color_shortkey, color_button; @@ -126,14 +216,14 @@ draw_button(WINDOW *window, int y, int x, int size, const char *text, mvwaddch(window, y, x + i, t.button.rightdelim); wattroff(window, color_arrows); - x = x + 1 + ((size - 2 - strlen(text))/2); + x = x + 1 + ((size - 2 - strcols(text))/2); wattron(window, color_button); mvwaddstr(window, y, x, text); wattroff(window, color_button); if (shortcut) { wattron(window, color_shortkey); - mvwaddch(window, y, x, text[0]); + mvwaddwch(window, y, x, first); wattroff(window, color_shortkey); } } @@ -142,16 +232,28 @@ void draw_buttons(WINDOW *window, struct buttons bs, bool shortcut) { int i, x, startx, y, rows, cols; + unsigned int newmargin, margin, wbuttons; getmaxyx(window, rows, cols); y = rows - 2; - startx = cols/2 - buttons_width(bs)/2; + newmargin = cols - VBORDERS - (bs.nbuttons * bs.sizebutton); + newmargin /= (bs.nbuttons + 1); + newmargin = MIN(newmargin, t.button.maxmargin); + if (newmargin == 0) { + margin = t.button.minmargin; + wbuttons = buttons_min_width(bs); + } else { + margin = newmargin; + wbuttons = bs.nbuttons * bs.sizebutton; + wbuttons += (bs.nbuttons + 1) * margin; + } + startx = (cols)/2 - wbuttons/2 + newmargin; for (i = 0; i < (int)bs.nbuttons; i++) { - x = i * (bs.sizebutton + t.button.hmargin); + x = i * (bs.sizebutton + margin); draw_button(window, y, startx + x, bs.sizebutton, bs.label[i], - i == bs.curr, shortcut); + bs.first[i], i == bs.curr, shortcut); } } @@ -163,6 +265,7 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs, #define SIZEBUTTON 8 #define DEFAULT_BUTTON_LABEL BUTTON_OK_LABEL #define DEFAULT_BUTTON_VALUE BSDDIALOG_OK + wchar_t first; bs->nbuttons = 0; bs->curr = 0; @@ -216,6 +319,11 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs, bs->nbuttons = 1; } + for (i = 0; i < (int)bs->nbuttons; i++) { + mbtowc(&first, bs->label[i], MB_CUR_MAX); + bs->first[i] = first; + } + if (conf->button.default_label != NULL) { for (i = 0; i < (int)bs->nbuttons; i++) { if (strcmp(conf->button.default_label, @@ -224,31 +332,31 @@ get_buttons(struct bsddialog_conf *conf, struct buttons *bs, } } - bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0])); + bs->sizebutton = MAX(SIZEBUTTON - 2, strcols(bs->label[0])); for (i = 1; i < (int)bs->nbuttons; i++) - bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i])); + bs->sizebutton = MAX(bs->sizebutton, strcols(bs->label[i])); bs->sizebutton += 2; } -int buttons_width(struct buttons bs) +int buttons_min_width(struct buttons bs) { unsigned int width; width = bs.nbuttons * bs.sizebutton; if (bs.nbuttons > 0) - width += (bs.nbuttons - 1) * t.button.hmargin; + width += (bs.nbuttons - 1) * t.button.minmargin; return (width); } -bool shortcut_buttons(int key, struct buttons *bs) +bool shortcut_buttons(wint_t key, struct buttons *bs) { bool match; unsigned int i; match = false; for (i = 0; i < bs->nbuttons; i++) { - if (tolower(key) == tolower(bs->label[i][0])) { + if (towlower(key) == towlower(bs->first[i])) { bs->curr = i; match = true; break; @@ -259,48 +367,51 @@ bool shortcut_buttons(int key, struct buttons *bs) } /* Text */ -static bool is_text_attr(const char *text) +static bool is_wtext_attr(const wchar_t *wtext) { - if (strnlen(text, 3) < 3) + if (wcsnlen(wtext, 3) < 3) return (false); - if (text[0] != '\\' || text[1] != 'Z') + if (wtext[0] != L'\\' || wtext[1] != L'Z') return (false); - return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true); + return (wcschr(L"nbBrRuU01234567", wtext[2]) == NULL ? false : true); } -static bool check_set_text_attr(WINDOW *win, char *text) +static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext) { - if (is_text_attr(text) == false) + enum bsddialog_color bg; + + if (is_wtext_attr(wtext) == false) return (false); - if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) { - wattron(win, bsddialog_color(text[2] - '0', COLOR_WHITE, 0)); + if ((wtext[2] - L'0') >= 0 && (wtext[2] - L'0') < 8) { + bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL); + wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0)); return (true); } - switch (text[2]) { - case 'n': + switch (wtext[2]) { + case L'n': wattron(win, t.dialog.color); wattrset(win, A_NORMAL); break; - case 'b': + case L'b': wattron(win, A_BOLD); break; - case 'B': + case L'B': wattroff(win, A_BOLD); break; - case 'r': + case L'r': wattron(win, A_REVERSE); break; - case 'R': + case L'R': wattroff(win, A_REVERSE); break; - case 'u': + case L'u': wattron(win, A_UNDERLINE); break; - case 'U': + case L'U': wattroff(win, A_UNDERLINE); break; } @@ -308,21 +419,27 @@ static bool check_set_text_attr(WINDOW *win, char *text) return (true); } +/* Word Wrapping */ static void -print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str, +print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str, bool color) { - int i, j, len, reallen; + int i, j, len, reallen, wc; + wchar_t ws[2]; - len = reallen = strlen(str); + ws[1] = L'\0'; + + len = wcslen(str); if (color) { + reallen = 0; i=0; while (i < len) { - if (is_text_attr(str+i)) - reallen -= 3; + if (is_wtext_attr(str+i) == false) + reallen += wcwidth(str[i]); i++; } - } + } else + reallen = wcswidth(str, len); i = 0; while (i < len) { @@ -336,13 +453,18 @@ print_string(WINDOW *win, int *rows, int cols, int *y, int *x, char *str, } j = *x; while (j < cols && i < len) { - if (color && check_set_text_attr(win, str+i)) { + if (color && check_set_wtext_attr(win, str+i)) { i += 3; + } else if (j + wcwidth(str[i]) > cols) { + break; } else { - mvwaddch(win, *y, j, str[i]); + /* inline mvwaddwch() for efficiency */ + ws[0] = str[i]; + mvwaddwstr(win, *y, j, ws); + wc = wcwidth(str[i]);; + reallen -= wc; + j += wc; i++; - reallen--; - j++; *x = j; } } @@ -354,35 +476,38 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text) { bool loop; int i, j, z, rows, cols, x, y, tablen; - char *string; + wchar_t *wtext, *string; + + if ((wtext = alloc_mbstows(text)) == NULL) + RETURN_ERROR("Cannot allocate/print text in wchar_t*"); - if ((string = malloc(strlen(text) + 1)) == NULL) + if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL) RETURN_ERROR("Cannot build (analyze) text"); getmaxyx(pad, rows, cols); - tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen; + tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; i = j = x = y = 0; loop = true; while (loop) { - string[j] = text[i]; + string[j] = wtext[i]; - if (strchr("\n\t ", string[j]) != NULL || string[j] == '\0') { - string[j] = '\0'; + if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') { + string[j] = L'\0'; print_string(pad, &rows, cols, &y, &x, string, conf->text.highlight); } - switch (text[i]) { - case '\0': + switch (wtext[i]) { + case L'\0': loop = false; break; - case '\n': + case L'\n': x = 0; y++; j = -1; break; - case '\t': + case L'\t': for (z = 0; z < tablen; z++) { if (x >= cols) { x = 0; @@ -392,7 +517,7 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text) } j = -1; break; - case ' ': + case L' ': x++; if (x >= cols) { x = 0; @@ -410,78 +535,133 @@ print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text) i++; } + free(wtext); free(string); return (0); } -/* Autosize */ +/* Text Autosize */ +#define NL -1 +#define WS -2 +#define TB -3 + +struct textproperties { + int nword; + int *words; + uint8_t *wletters; + int maxwordcols; + int maxline; + bool hasnewline; +}; + static int -text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows, - int mincols, bool increasecols, int *h, int *w) +text_properties(struct bsddialog_conf *conf, const char *text, + struct textproperties *tp) { - int i, j, z, x, y; - int tablen, wordlen, maxwordlen, nword, maxwords, line, maxwidth; - int *words; -#define NL -1 -#define WS -2 + int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols; + wchar_t *wtext; + + tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; maxwords = 1024; - if ((words = calloc(maxwords, sizeof(int))) == NULL) + if ((tp->words = calloc(maxwords, sizeof(int))) == NULL) RETURN_ERROR("Cannot alloc memory for text autosize"); - tablen = (conf->text.tablen == 0) ? TABLEN : (int)conf->text.tablen; - maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS; + 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"); - nword = 0; - wordlen = 0; - maxwordlen = 0; - i=0; - while (true) { - if (conf->text.highlight && is_text_attr(text + i)) { - i += 3; + tp->nword = 0; + tp->maxline = 0; + tp->maxwordcols = 0; + tp->hasnewline = false; + currlinecols = 0; + wordcols = 0; + l = 0; + for (i = 0; i < wtextlen; i++) { + if (conf->text.highlight && is_wtext_attr(wtext + i)) { + i += 2; /* +1 for update statement */ continue; } - if (nword + tablen >= maxwords) { + if (tp->nword + 1 >= maxwords) { maxwords += 1024; - if (realloc(words, maxwords * sizeof(int)) == NULL) + tp->words = realloc(tp->words, maxwords * sizeof(int)); + if (tp->words == NULL) RETURN_ERROR("Cannot realloc memory for text " "autosize"); } - if (text[i] == '\0') { - words[nword] = wordlen; - maxwordlen = MAX(wordlen, maxwordlen); - break; - } - - if (strchr("\t\n ", text[i]) != NULL) { - maxwordlen = MAX(wordlen, maxwordlen); + if (wcschr(L"\t\n ", wtext[i]) != NULL) { + tp->maxwordcols = MAX(wordcols, tp->maxwordcols); - if (wordlen != 0) { - words[nword] = wordlen; - nword++; - wordlen = 0; + if (wordcols != 0) { + /* line */ + currlinecols += wordcols; + /* word */ + tp->words[tp->nword] = wordcols; + tp->nword += 1; + wordcols = 0; } - if (text[i] == '\t') { - for (j = 0; j < tablen; j++) - words[nword + j] = 1; - nword += tablen; - } else { - words[nword] = text[i] == '\n' ? NL : WS; - nword++; + switch (wtext[i]) { + case L'\t': + /* line */ + currlinecols += tablen; + /* word */ + tp->words[tp->nword] = TB; + break; + case L'\n': + /* line */ + tp->hasnewline = true; + tp->maxline = MAX(tp->maxline, currlinecols); + currlinecols = 0; + /* word */ + tp->words[tp->nword] = NL; + break; + case L' ': + /* line */ + currlinecols += 1; + /* word */ + tp->words[tp->nword] = WS; + break; } + tp->nword += 1; + } else { + tp->wletters[l] = wcwidth(wtext[i]); + wordcols += tp->wletters[l]; + l++; } - else - wordlen++; - - i++; } + /* word */ + if (wordcols != 0) { + tp->words[tp->nword] = wordcols; + tp->nword += 1; + tp->maxwordcols = MAX(wordcols, tp->maxwordcols); + } + /* line */ + tp->maxline = MAX(tp->maxline, currlinecols); + + free(wtext); + + return (0); +} + + +static int +text_autosize(struct bsddialog_conf *conf, struct textproperties *tp, + int maxrows, int mincols, bool increasecols, int *h, int *w) +{ + int i, j, x, y, z, l, line, maxwidth, tablen; + + maxwidth = widget_max_width(conf) - HBORDERS - TEXTHMARGINS; + tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; if (increasecols) { - mincols = MAX(mincols, maxwordlen); + mincols = MAX(mincols, tp->maxwordcols); mincols = MAX(mincols, (int)conf->auto_minwidth - HBORDERS - TEXTHMARGINS); mincols = MIN(mincols, maxwidth); @@ -491,26 +671,50 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows, x = 0; y = 1; line=0; - for (i = 0; i <= nword; i++) { - if (words[i] == NL) { + l = 0; + for (i = 0; i < tp->nword; i++) { + switch (tp->words[i]) { + case TB: + for (j = 0; j < tablen; j++) { + if (x >= mincols) { + x = 0; + y++; + } + x++; + } + break; + case NL: y++; x = 0; - } - else if (words[i] == WS) { + break; + case WS: x++; if (x >= mincols) { x = 0; y++; } - } - else { - if (words[i] + x <= mincols) - x += words[i]; - else { - for (z = words[i]; z > 0; ) { - y++; - x = MIN(mincols, z); - z -= x; + break; + default: + if (tp->words[i] + x <= mincols) { + x += tp->words[i]; + for (z = 0 ; z != tp->words[i]; l++ ) + z += tp->wletters[l]; + } else if (tp->words[i] <= mincols) { + y++; + x = tp->words[i]; + for (z = 0 ; z != tp->words[i]; l++ ) + z += tp->wletters[l]; + } else { + for (j = tp->words[i]; j > 0; ) { + y = (x == 0) ? y : y + 1; + z = 0; + while (z != j && z < mincols) { + z += tp->wletters[l]; + l++; + } + x = z; + line = MAX(line, x); + j -= z; } } } @@ -519,16 +723,16 @@ text_autosize(struct bsddialog_conf *conf, const char *text, int maxrows, if (increasecols == false) break; - if (y <= maxrows || mincols >= maxwidth) + if (mincols >= maxwidth) + break; + if (line >= y * (int)conf->text.cols_per_row && y <= maxrows) break; mincols++; } - *h = (nword == 0 && words[0] == 0) ? 0 : y; + *h = (tp->nword == 0) ? 0 : y; *w = MIN(mincols, line); /* wtext can be less than mincols */ - free(words); - return (0); } @@ -536,13 +740,26 @@ int text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text, struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext) { - int wbuttons, maxhtext; bool changewtext; + int wbuttons, maxhtext; + struct textproperties tp; wbuttons = 0; if (bs != NULL) - wbuttons = buttons_width(*bs); + wbuttons = buttons_min_width(*bs); + /* Rows */ + if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) { + maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext; + } else { /* fixed */ + maxhtext = rows - VBORDERS - rowsnotext; + } + if (bs != NULL) + maxhtext -= 2; + if (maxhtext <= 0) + maxhtext = 1; /* text_autosize() computes always htext */ + + /* Cols */ if (cols == BSDDIALOG_AUTOSIZE) { startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS); changewtext = true; @@ -554,45 +771,52 @@ text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text, changewtext = false; } - if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) { - maxhtext = widget_max_height(conf) - VBORDERS - rowsnotext; - if (bs != NULL) - maxhtext -= 2; - } else { /* fixed */ - maxhtext = rows - VBORDERS - rowsnotext; - if (bs != NULL) - maxhtext -= 2; - } - if (startwtext <= 0 && changewtext) startwtext = 1; - if (maxhtext <= 0 || startwtext <= 0) { - *htext = *wtext = 0; - return (0); - } + if (startwtext <= 0) + RETURN_ERROR("Fullscreen or fixed cols to print text <=0"); - if (text_autosize(conf, text, maxhtext, startwtext, changewtext, - htext, wtext) != 0) + /* Sizing calculation */ + if (text_properties(conf, text, &tp) != 0) + return (BSDDIALOG_ERROR); + if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext, + wtext) != 0) return (BSDDIALOG_ERROR); + free(tp.words); + free(tp.wletters); + return (0); } +/* Widget size and position */ int widget_max_height(struct bsddialog_conf *conf) { int maxheight; - maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.h : SCREENLINES; + maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES; if (maxheight <= 0) RETURN_ERROR("Terminal too small, screen lines - shadow <= 0"); - if (conf->y > 0) { + if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0) + RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0"); + else if (conf->y == BSDDIALOG_CENTER) { + maxheight -= conf->auto_topmargin; + if (maxheight <= 0) + RETURN_ERROR("Terminal too small, screen lines - top " + "margins <= 0"); + } else if (conf->y > 0) { maxheight -= conf->y; if (maxheight <= 0) RETURN_ERROR("Terminal too small, screen lines - " "shadow - y <= 0"); } + maxheight -= conf->auto_downmargin; + if (maxheight <= 0) + RETURN_ERROR("Terminal too small, screen lines - Down margins " + "<= 0"); + return (maxheight); } @@ -600,7 +824,7 @@ int widget_max_width(struct bsddialog_conf *conf) { int maxwidth; - maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.w : SCREENCOLS; + maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS; if (maxwidth <= 0) RETURN_ERROR("Terminal too small, screen cols - shadow <= 0"); @@ -647,13 +871,13 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget, struct buttons *bs) { - int min, delimtitle; + int min, delimtitle, wbottomtitle, wtitle; min = 0; /* buttons */ if (bs != NULL) - min += buttons_width(*bs); + min += buttons_min_width(*bs); /* text */ if (wtext > 0) @@ -665,12 +889,15 @@ widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget, /* title */ if (conf->title != NULL) { delimtitle = t.dialog.delimtitle ? 2 : 0; - min = MAX(min, (int)strlen(conf->title) + 2 + delimtitle); + wtitle = strcols(conf->title); + min = MAX(min, wtitle + 2 + delimtitle); } /* bottom title */ - if (conf->bottomtitle != NULL) - min = MAX(min, (int)strlen(conf->bottomtitle) + 4); + if (conf->bottomtitle != NULL) { + wbottomtitle = strcols(conf->bottomtitle); + min = MAX(min, wbottomtitle + 4); + } /* dialog borders */ min += VBORDERS; @@ -721,8 +948,16 @@ set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w) int set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w) { - if (conf->y == BSDDIALOG_CENTER) - *y = SCREENLINES/2 - (h + t.shadow.h)/2; + int hshadow = conf->shadow ? (int)t.shadow.y : 0; + int wshadow = conf->shadow ? (int)t.shadow.x : 0; + + if (conf->y == BSDDIALOG_CENTER) { + *y = SCREENLINES/2 - (h + hshadow)/2; + if (*y < (int)conf->auto_topmargin) + *y = conf->auto_topmargin; + if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin) + *y = SCREENLINES - h - hshadow - conf->auto_downmargin; + } else if (conf->y < BSDDIALOG_CENTER) RETURN_ERROR("Negative begin y (less than -1)"); else if (conf->y >= SCREENLINES) @@ -730,13 +965,13 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w) else *y = conf->y; - if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > SCREENLINES) + if (*y + h + hshadow > SCREENLINES) RETURN_ERROR("The lower of the box under the terminal " "(begin Y + height (+ shadow) > terminal lines)"); if (conf->x == BSDDIALOG_CENTER) - *x = SCREENCOLS/2 - (w + t.shadow.w)/2; + *x = SCREENCOLS/2 - (w + wshadow)/2; else if (conf->x < BSDDIALOG_CENTER) RETURN_ERROR("Negative begin x (less than -1)"); else if (conf->x >= SCREENCOLS) @@ -744,14 +979,14 @@ set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w) else *x = conf->x; - if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > SCREENCOLS) + if ((*x + w + wshadow) > SCREENCOLS) RETURN_ERROR("The right of the box over the terminal " "(begin X + width (+ shadow) > terminal cols)"); return (0); } -/* Widgets builders */ +/* Widgets build, update, destroy */ void draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols, enum elevation elev) @@ -815,7 +1050,7 @@ static int draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget, WINDOW *textpad, const char *text, struct buttons *bs, bool shortcutbuttons) { - int h, w, ts, ltee, rtee; + int h, w, wtitle, wbottomtitle, ts, ltee, rtee; ts = conf->ascii_lines ? '-' : ACS_HLINE; ltee = conf->ascii_lines ? '+' : ACS_LTEE; @@ -823,19 +1058,21 @@ draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget, getmaxyx(widget, h, w); - if (shadow != NULL) + if (conf->shadow) wnoutrefresh(shadow); draw_borders(conf, widget, h, w, RAISED); if (conf->title != NULL) { + if ((wtitle = strcols(conf->title)) < 0) + return (BSDDIALOG_ERROR); if (t.dialog.delimtitle && conf->no_lines == false) { wattron(widget, t.dialog.lineraisecolor); - mvwaddch(widget, 0, w/2-strlen(conf->title)/2-1, rtee); + mvwaddch(widget, 0, w/2 - wtitle/2 -1, rtee); wattroff(widget, t.dialog.lineraisecolor); } wattron(widget, t.dialog.titlecolor); - mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title); + mvwaddstr(widget, 0, w/2 - wtitle/2, conf->title); wattroff(widget, t.dialog.titlecolor); if (t.dialog.delimtitle && conf->no_lines == false) { wattron(widget, t.dialog.lineraisecolor); @@ -859,8 +1096,10 @@ draw_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget, } if (conf->bottomtitle != NULL) { + if ((wbottomtitle = strcols(conf->bottomtitle)) < 0) + return (BSDDIALOG_ERROR); wattron(widget, t.dialog.bottomtitlecolor); - wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1); + wmove(widget, h - 1, w/2 - wbottomtitle/2 - 1); waddch(widget, ' '); waddstr(widget, conf->bottomtitle); waddch(widget, ' '); @@ -883,9 +1122,9 @@ update_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget, { int error; - if (shadow != NULL) { + if (conf->shadow) { wclear(shadow); - mvwin(shadow, y + t.shadow.h, x + t.shadow.w); + mvwin(shadow, y + t.shadow.y, x + t.shadow.x); wresize(shadow, h, w); } @@ -912,7 +1151,7 @@ new_dialog(struct bsddialog_conf *conf, WINDOW **shadow, WINDOW **widget, int y, int error; if (conf->shadow) { - *shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w); + *shadow = newwin(h, w, y + t.shadow.y, x + t.shadow.x); if (*shadow == NULL) RETURN_ERROR("Cannot build shadow"); wbkgd(*shadow, t.shadow.color); @@ -962,10 +1201,10 @@ end_dialog(struct bsddialog_conf *conf, WINDOW *shadow, WINDOW *widget, delwin(shadow); if (conf->clear) - hide_widget(y, x, h, w, shadow != NULL); + hide_widget(y, x, h, w, conf->shadow); if (conf->get_height != NULL) *conf->get_height = h; if (conf->get_width != NULL) *conf->get_width = w; -}
\ No newline at end of file +} |
