11590Srgrimes/*- 21590Srgrimes * SPDX-License-Identifier: BSD-2-Clause 31590Srgrimes * 41590Srgrimes * Copyright (c) 2021-2023 Alfonso Sabato Siciliano 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions and the following disclaimer. 111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer in the 131590Srgrimes * documentation and/or other materials provided with the distribution. 141590Srgrimes * 151590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 161590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 191590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251590Srgrimes * SUCH DAMAGE. 261590Srgrimes */ 271590Srgrimes 281590Srgrimes#include <curses.h> 291590Srgrimes#include <stdlib.h> 301590Srgrimes#include <string.h> 311590Srgrimes#include <unistd.h> 321590Srgrimes#include <wctype.h> 332537Spst 342537Spst#include "bsddialog.h" 352537Spst#include "bsddialog_theme.h" 362537Spst#include "lib_util.h" 372537Spst 382537Spst/* 392537Spst * -1- Error and diagnostic 402537Spst * 412537Spst * get_error_string(); 422537Spst * set_error_string(); 431590Srgrimes * set_fmt_error_string(); 4467467Sru * 451590Srgrimes * ---------------------------------------------------- 461590Srgrimes * -2- (Unicode) Multicolumn character strings 471590Srgrimes * 481590Srgrimes * alloc_mbstows(); 4987628Sdwmalone * mvwaddwch(); 501590Srgrimes * str_props(); 5187628Sdwmalone * strcols(); 5272109Scharnier * 5387628Sdwmalone * ---------------------------------------------------- 541590Srgrimes * -3- Buttons 5587628Sdwmalone * 5687628Sdwmalone * [static] buttons_min_width(); 5787628Sdwmalone * [static] draw_button(); 581590Srgrimes * draw_buttons(); 591590Srgrimes * set_buttons(); (to call 1 time after prepare_dialog()). 601590Srgrimes * shortcut_buttons(); 611590Srgrimes * 621590Srgrimes * ---------------------------------------------------- 631590Srgrimes * -4- (Auto) Sizing and (Auto) Position 641590Srgrimes * 651590Srgrimes * [static] widget_max_height(conf); 662537Spst * [static] widget_max_width(struct bsddialog_conf *conf) 672537Spst * [static] is_wtext_attr(); 682537Spst * [static] text_properties(); 692537Spst * [static] text_autosize(); 701590Srgrimes * [static] text_size(); 711590Srgrimes * [static] widget_min_height(conf, htext, hnotext, bool buttons); 72100521Sume * [static] widget_min_width(conf, wtext, minw, buttons); 73100521Sume * set_widget_size(); 7423693Speter * set_widget_autosize(); (not for all dialogs). 7523693Speter * widget_checksize(); (not for all dialogs). 761590Srgrimes * set_widget_position(); 771590Srgrimes * dialog_size_position(struct dialog); (not for all dialogs). 781590Srgrimes * 791590Srgrimes * ---------------------------------------------------- 8023693Speter * -5- (Dialog) Widget components and utils 8123693Speter * 82202191Sed * hide_dialog(struct dialog); 8311759Sache * f1help_dialog(conf); 8423693Speter * draw_borders(conf, win, elev); 851590Srgrimes * update_box(conf, win, y, x, h, w, elev); 8664775Sbrian * rtextpad(); (helper for pnoutrefresh(textpad)). 871590Srgrimes * 881590Srgrimes * ---------------------------------------------------- 891590Srgrimes * -6- Dialog init/build, update/draw, destroy 90168632Sdes * 91106250Ssobomax * end_dialog(struct dialog); 9274586Sache * [static] check_set_wtext_attr(); 931590Srgrimes * [static] print_string(); (word wrapping). 94150316Sdds * [static] print_textpad(); 951590Srgrimes * draw_dialog(struct dialog); 9692920Simp * prepare_dialog(struct dialog); 9792920Simp */ 9892920Simp 9992920Simp/* 1001590Srgrimes * -1- Error and diagnostic 10187229Smarkm */ 102102944Sdwmalone#define ERRBUFLEN 1024 1031590Srgrimes 1041590Srgrimesstatic char errorbuffer[ERRBUFLEN]; 1051590Srgrimes 1062589Spstconst char *get_error_string(void) 1072537Spst{ 108168635Sdes return (errorbuffer); 1091590Srgrimes} 110100521Sume 111100521Sumevoid set_error_string(const char *str) 112100521Sume{ 113100521Sume strncpy(errorbuffer, str, ERRBUFLEN-1); 114100521Sume} 115100521Sume 11699249Sminivoid set_fmt_error_string(const char *fmt, ...) 11799249Smini{ 11899249Smini va_list arg_ptr; 119117010Sjmallett 120117010Sjmallett va_start(arg_ptr, fmt); 121117010Sjmallett vsnprintf(errorbuffer, ERRBUFLEN-1, fmt, arg_ptr); 1221590Srgrimes va_end(arg_ptr); 1231590Srgrimes} 1241590Srgrimes 1251590Srgrimes/* 1261590Srgrimes * -2- (Unicode) Multicolumn character strings 1271590Srgrimes */ 1281590Srgrimeswchar_t* alloc_mbstows(const char *mbstring) 1291590Srgrimes{ 1301590Srgrimes size_t charlen, nchar; 1311590Srgrimes mbstate_t mbs; 1321590Srgrimes const char *pmbstring; 1331590Srgrimes wchar_t *wstring; 1342537Spst 1352537Spst nchar = 1; 1362537Spst pmbstring = mbstring; 1372537Spst memset(&mbs, 0, sizeof(mbs)); 1382537Spst while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 && 1392537Spst charlen != (size_t)-1 && charlen != (size_t)-2) { 1401590Srgrimes pmbstring += charlen; 1411590Srgrimes nchar++; 14227169Scharnier } 1431590Srgrimes 1441590Srgrimes if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL) 1452589Spst return (NULL); 1462589Spst mbstowcs(wstring, mbstring, nchar); 1472589Spst 14827169Scharnier return (wstring); 149102944Sdwmalone} 15027169Scharnier 151146466Sruvoid mvwaddwch(WINDOW *w, int y, int x, wchar_t wch) 152168635Sdes{ 15327169Scharnier wchar_t ws[2]; 15427169Scharnier 15527169Scharnier ws[0] = wch; 15627169Scharnier ws[1] = L'\0'; 157102944Sdwmalone mvwaddwstr(w, y, x, ws); 1582589Spst} 15927169Scharnier 1602589Spstint str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col) 16146662Sobrien{ 16287229Smarkm bool multicol; 1632589Spst int w; 16446662Sobrien unsigned int ncol; 165150316Sdds size_t charlen, mb_cur_max; 16646662Sobrien wchar_t wch; 167220971Ssimon mbstate_t mbs; 168220971Ssimon 169220971Ssimon multicol = false; 170220971Ssimon mb_cur_max = MB_CUR_MAX; 17146662Sobrien ncol = 0; 172220971Ssimon memset(&mbs, 0, sizeof(mbs)); 173220971Ssimon while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 && 174220971Ssimon charlen != (size_t)-1 && charlen != (size_t)-2) { 175220971Ssimon if (mbtowc(&wch, mbstring, mb_cur_max) < 0) 17646662Sobrien return (-1); 17746662Sobrien w = (wch == L'\t') ? TABSIZE : wcwidth(wch); 17846662Sobrien ncol += (w < 0) ? 0 : w; 17911811Sache if (w > 1 && wch != L'\t') 18011759Sache multicol = true; 1812589Spst mbstring += charlen; 1822589Spst } 1832589Spst 1842589Spst if (cols != NULL) 1852589Spst *cols = ncol; 1862589Spst if (has_multi_col != NULL) 1872589Spst *has_multi_col = multicol; 1882589Spst 18987229Smarkm return (0); 1902589Spst} 1912589Spst 1922589Spstunsigned int strcols(const char *mbstring) 1932589Spst{ 1942589Spst int w; 1952589Spst unsigned int ncol; 1962589Spst size_t charlen, mb_cur_max; 1972589Spst wchar_t wch; 1981590Srgrimes mbstate_t mbs; 1991590Srgrimes 2001590Srgrimes mb_cur_max = MB_CUR_MAX; 2011590Srgrimes ncol = 0; 2021590Srgrimes memset(&mbs, 0, sizeof(mbs)); 2031590Srgrimes while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 && 2041590Srgrimes charlen != (size_t)-1 && charlen != (size_t)-2) { 2051590Srgrimes if (mbtowc(&wch, mbstring, mb_cur_max) < 0) 2061590Srgrimes return (0); 2071590Srgrimes w = (wch == L'\t') ? TABSIZE : wcwidth(wch); 2081590Srgrimes ncol += (w < 0) ? 0 : w; 2091590Srgrimes mbstring += charlen; 2101590Srgrimes } 2111590Srgrimes 2121590Srgrimes return (ncol); 2131590Srgrimes} 2141590Srgrimes 2151590Srgrimes/* 2161590Srgrimes * -3- Buttons 2171590Srgrimes */ 2181590Srgrimesstatic int buttons_min_width(struct buttons *bs) 2191590Srgrimes{ 2201590Srgrimes unsigned int width; 22148566Sbillf 2221590Srgrimes width = bs->nbuttons * bs->sizebutton; 2231590Srgrimes if (bs->nbuttons > 0) 2241590Srgrimes width += (bs->nbuttons - 1) * t.button.minmargin; 2251590Srgrimes 22648566Sbillf return (width); 22723693Speter} 2281590Srgrimes 2291590Srgrimesstatic void 2301590Srgrimesdraw_button(WINDOW *window, int y, int x, int size, const char *text, 231102944Sdwmalone wchar_t first, bool selected, bool shortcut) 2321590Srgrimes{ 23387229Smarkm int i, color_arrows, color_shortkey, color_button; 2341590Srgrimes 2351590Srgrimes if (selected) { 236201140Sed color_arrows = t.button.f_delimcolor; 23787229Smarkm color_shortkey = t.button.f_shortcutcolor; 2381590Srgrimes color_button = t.button.f_color; 239117010Sjmallett } else { 240117010Sjmallett color_arrows = t.button.delimcolor; 241117010Sjmallett color_shortkey = t.button.shortcutcolor; 242201140Sed color_button = t.button.color; 243201140Sed } 244201140Sed 2451590Srgrimes wattron(window, color_arrows); 246201140Sed mvwaddch(window, y, x, t.button.leftdelim); 247201140Sed wattroff(window, color_arrows); 2481590Srgrimes wattron(window, color_button); 2495369Sjkh for (i = 1; i < size - 1; i++) 2505369Sjkh waddch(window, ' '); 2511590Srgrimes wattroff(window, color_button); 2521590Srgrimes wattron(window, color_arrows); 253201140Sed mvwaddch(window, y, x + i, t.button.rightdelim); 2541590Srgrimes wattroff(window, color_arrows); 255201140Sed 2561590Srgrimes x = x + 1 + ((size - 2 - strcols(text))/2); 25787229Smarkm wattron(window, color_button); 25823693Speter mvwaddstr(window, y, x, text); 25923693Speter wattroff(window, color_button); 26087229Smarkm 2611590Srgrimes if (shortcut) { 26223693Speter wattron(window, color_shortkey); 2631590Srgrimes mvwaddwch(window, y, x, first); 2641590Srgrimes wattroff(window, color_shortkey); 26523693Speter } 26623693Speter} 2671590Srgrimes 2681590Srgrimesvoid draw_buttons(struct dialog *d) 2691590Srgrimes{ 2701590Srgrimes int i, x, startx, y; 271102944Sdwmalone unsigned int newmargin, margin, wbuttons; 2721590Srgrimes 27387229Smarkm y = d->h - 2; 2741590Srgrimes 275201140Sed newmargin = d->w - BORDERS - (d->bs.nbuttons * d->bs.sizebutton); 2761590Srgrimes newmargin /= (d->bs.nbuttons + 1); 27787229Smarkm newmargin = MIN(newmargin, t.button.maxmargin); 2781590Srgrimes if (newmargin == 0) { 27964775Sbrian margin = t.button.minmargin; 28064775Sbrian wbuttons = buttons_min_width(&d->bs); 28164775Sbrian } else { 28264775Sbrian margin = newmargin; 2831590Srgrimes wbuttons = d->bs.nbuttons * d->bs.sizebutton; 2841590Srgrimes wbuttons += (d->bs.nbuttons + 1) * margin; 2851590Srgrimes } 28623693Speter 2871590Srgrimes startx = d->w/2 - wbuttons/2 + newmargin; 2881590Srgrimes for (i = 0; i < (int)d->bs.nbuttons; i++) { 2891590Srgrimes x = i * (d->bs.sizebutton + margin); 290229403Sed draw_button(d->widget, y, startx + x, d->bs.sizebutton, 2911590Srgrimes d->bs.label[i], d->bs.first[i], i == d->bs.curr, 2921590Srgrimes d->bs.shortcut); 2931590Srgrimes } 2941590Srgrimes} 2951590Srgrimes 2961590Srgrimesvoid 2971590Srgrimesset_buttons(struct dialog *d, bool shortcut, const char *oklabel, 2981590Srgrimes const char *cancellabel) 2991590Srgrimes{ 3001590Srgrimes int i; 3011590Srgrimes#define SIZEBUTTON 8 302228992Suqs#define DEFAULT_BUTTON_LABEL OK_LABEL 303228992Suqs#define DEFAULT_BUTTON_VALUE BSDDIALOG_OK 30466563Sbrian wchar_t first; 30566563Sbrian 30666563Sbrian d->bs.nbuttons = 0; 30766563Sbrian d->bs.curr = 0; 30866563Sbrian d->bs.sizebutton = 0; 30966563Sbrian d->bs.shortcut = shortcut; 31066563Sbrian 31166563Sbrian if (d->conf->button.left1_label != NULL) { 31264775Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.left1_label; 31364775Sbrian d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT1; 31464775Sbrian d->bs.nbuttons += 1; 31564775Sbrian } 31664775Sbrian 31764775Sbrian if (d->conf->button.left2_label != NULL) { 31864775Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.left2_label; 31964775Sbrian d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT2; 32064775Sbrian d->bs.nbuttons += 1; 32164775Sbrian } 32264775Sbrian 32364775Sbrian if (d->conf->button.left3_label != NULL) { 32464775Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.left3_label; 325126960Sbde d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT3; 32664775Sbrian d->bs.nbuttons += 1; 32764775Sbrian } 32864775Sbrian 32964775Sbrian if (oklabel != NULL && d->conf->button.without_ok == false) { 33064775Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.ok_label != NULL ? 33164775Sbrian d->conf->button.ok_label : oklabel; 33264775Sbrian d->bs.value[d->bs.nbuttons] = BSDDIALOG_OK; 33364775Sbrian d->bs.nbuttons += 1; 33464775Sbrian } 33564775Sbrian 3361590Srgrimes if (d->conf->button.with_extra) { 33765064Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.extra_label != NULL ? 33865064Sbrian d->conf->button.extra_label : "Extra"; 33965064Sbrian d->bs.value[d->bs.nbuttons] = BSDDIALOG_EXTRA; 3401590Srgrimes d->bs.nbuttons += 1; 3411590Srgrimes } 34266675Sru 34366675Sru if (cancellabel != NULL && d->conf->button.without_cancel == false) { 34465064Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.cancel_label ? 34565064Sbrian d->conf->button.cancel_label : cancellabel; 34666675Sru d->bs.value[d->bs.nbuttons] = BSDDIALOG_CANCEL; 34765064Sbrian if (d->conf->button.default_cancel) 34865064Sbrian d->bs.curr = d->bs.nbuttons; 34965064Sbrian d->bs.nbuttons += 1; 3501590Srgrimes } 35165787Sbrian 3521590Srgrimes if (d->conf->button.with_help) { 35365064Sbrian d->bs.label[d->bs.nbuttons] = d->conf->button.help_label != NULL ? 35465787Sbrian d->conf->button.help_label : "Help"; 35565064Sbrian d->bs.value[d->bs.nbuttons] = BSDDIALOG_HELP; 35665787Sbrian d->bs.nbuttons += 1; 3571590Srgrimes } 3581590Srgrimes 3591590Srgrimes if (d->conf->button.right1_label != NULL) { 3605369Sjkh d->bs.label[d->bs.nbuttons] = d->conf->button.right1_label; 3611590Srgrimes d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT1; 3621590Srgrimes d->bs.nbuttons += 1; 36327169Scharnier } 3641590Srgrimes 3651590Srgrimes if (d->conf->button.right2_label != NULL) { 3661590Srgrimes d->bs.label[d->bs.nbuttons] = d->conf->button.right2_label; 3674991Spst d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT2; 3681590Srgrimes d->bs.nbuttons += 1; 3694991Spst } 3704991Spst 3714991Spst if (d->conf->button.right3_label != NULL) { 3721590Srgrimes d->bs.label[d->bs.nbuttons] = d->conf->button.right3_label; 373200793Sdelphij d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT3; 3741590Srgrimes d->bs.nbuttons += 1; 3751590Srgrimes } 3761590Srgrimes 377117010Sjmallett if (d->bs.nbuttons == 0) { 378117010Sjmallett d->bs.label[0] = DEFAULT_BUTTON_LABEL; 379117010Sjmallett d->bs.value[0] = DEFAULT_BUTTON_VALUE; 3801590Srgrimes d->bs.nbuttons = 1; 3811590Srgrimes } 3821590Srgrimes 3831590Srgrimes for (i = 0; i < (int)d->bs.nbuttons; i++) { 384201140Sed mbtowc(&first, d->bs.label[i], MB_CUR_MAX); 385201140Sed d->bs.first[i] = first; 386201140Sed } 3871590Srgrimes 388201140Sed if (d->conf->button.default_label != NULL) { 3891590Srgrimes for (i = 0; i < (int)d->bs.nbuttons; i++) { 390201140Sed if (strcmp(d->conf->button.default_label, 3911590Srgrimes d->bs.label[i]) == 0) 392201140Sed d->bs.curr = i; 3931590Srgrimes } 39487229Smarkm } 39523693Speter 39623693Speter d->bs.sizebutton = MAX(SIZEBUTTON - 2, strcols(d->bs.label[0])); 39787229Smarkm for (i = 1; i < (int)d->bs.nbuttons; i++) 3981590Srgrimes d->bs.sizebutton = MAX(d->bs.sizebutton, strcols(d->bs.label[i])); 39923693Speter d->bs.sizebutton += 2; 4001590Srgrimes} 4011590Srgrimes 40223693Speterbool shortcut_buttons(wint_t key, struct buttons *bs) 40323693Speter{ 4041590Srgrimes bool match; 4051590Srgrimes unsigned int i; 406 407 match = false; 408 for (i = 0; i < bs->nbuttons; i++) { 409 if (towlower(key) == towlower(bs->first[i])) { 410 bs->curr = i; 411 match = true; 412 break; 413 } 414 } 415 416 return (match); 417} 418 419/* 420 * -4- (Auto) Sizing and (Auto) Position 421 */ 422static int widget_max_height(struct bsddialog_conf *conf) 423{ 424 int maxheight; 425 426 maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES; 427 if (maxheight <= 0) 428 RETURN_ERROR("Terminal too small, screen lines - shadow <= 0"); 429 430 if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0) 431 RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0"); 432 else if (conf->y == BSDDIALOG_CENTER) { 433 maxheight -= conf->auto_topmargin; 434 if (maxheight <= 0) 435 RETURN_ERROR("Terminal too small, screen lines - top " 436 "margins <= 0"); 437 } else if (conf->y > 0) { 438 maxheight -= conf->y; 439 if (maxheight <= 0) 440 RETURN_ERROR("Terminal too small, screen lines - " 441 "shadow - y <= 0"); 442 } 443 444 maxheight -= conf->auto_downmargin; 445 if (maxheight <= 0) 446 RETURN_ERROR("Terminal too small, screen lines - Down margins " 447 "<= 0"); 448 449 return (maxheight); 450} 451 452static int widget_max_width(struct bsddialog_conf *conf) 453{ 454 int maxwidth; 455 456 maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS; 457 if (maxwidth <= 0) 458 RETURN_ERROR("Terminal too small, screen cols - shadow <= 0"); 459 460 if (conf->x > 0) { 461 maxwidth -= conf->x; 462 if (maxwidth <= 0) 463 RETURN_ERROR("Terminal too small, screen cols - shadow " 464 "- x <= 0"); 465 } 466 467 return (maxwidth); 468} 469 470static bool is_wtext_attr(const wchar_t *wtext) 471{ 472 bool att; 473 474 if (wcsnlen(wtext, 3) < 3) 475 return (false); 476 if (wtext[0] != L'\\' || wtext[1] != L'Z') 477 return (false); 478 479 att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true; 480 481 return (att); 482} 483 484#define NL -1 485#define WS -2 486#define TB -3 487 488struct textproperties { 489 int nword; 490 int *words; 491 uint8_t *wletters; 492 int maxwordcols; 493 int maxline; 494 bool hasnewline; 495}; 496 497static int 498text_properties(struct bsddialog_conf *conf, const char *text, 499 struct textproperties *tp) 500{ 501 int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols; 502 wchar_t *wtext; 503 504 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; 505 506 maxwords = 1024; 507 if ((tp->words = calloc(maxwords, sizeof(int))) == NULL) 508 RETURN_ERROR("Cannot alloc memory for text autosize"); 509 510 if ((wtext = alloc_mbstows(text)) == NULL) 511 RETURN_ERROR("Cannot allocate/autosize text in wchar_t*"); 512 wtextlen = wcslen(wtext); 513 if ((tp->wletters = calloc(wtextlen, sizeof(uint8_t))) == NULL) 514 RETURN_ERROR("Cannot allocate wletters for text autosizing"); 515 516 tp->nword = 0; 517 tp->maxline = 0; 518 tp->maxwordcols = 0; 519 tp->hasnewline = false; 520 currlinecols = 0; 521 wordcols = 0; 522 l = 0; 523 for (i = 0; i < wtextlen; i++) { 524 if (conf->text.escape && is_wtext_attr(wtext + i)) { 525 i += 2; /* +1 for update statement */ 526 continue; 527 } 528 529 if (tp->nword + 1 >= maxwords) { 530 maxwords += 1024; 531 tp->words = realloc(tp->words, maxwords * sizeof(int)); 532 if (tp->words == NULL) 533 RETURN_ERROR("Cannot realloc memory for text " 534 "autosize"); 535 } 536 537 if (wcschr(L"\t\n ", wtext[i]) != NULL) { 538 tp->maxwordcols = MAX(wordcols, tp->maxwordcols); 539 540 if (wordcols != 0) { 541 /* line */ 542 currlinecols += wordcols; 543 /* word */ 544 tp->words[tp->nword] = wordcols; 545 tp->nword += 1; 546 wordcols = 0; 547 } 548 549 switch (wtext[i]) { 550 case L'\t': 551 /* line */ 552 currlinecols += tablen; 553 /* word */ 554 tp->words[tp->nword] = TB; 555 break; 556 case L'\n': 557 /* line */ 558 tp->hasnewline = true; 559 tp->maxline = MAX(tp->maxline, currlinecols); 560 currlinecols = 0; 561 /* word */ 562 tp->words[tp->nword] = NL; 563 break; 564 case L' ': 565 /* line */ 566 currlinecols += 1; 567 /* word */ 568 tp->words[tp->nword] = WS; 569 break; 570 } 571 tp->nword += 1; 572 } else { 573 tp->wletters[l] = wcwidth(wtext[i]); 574 wordcols += tp->wletters[l]; 575 l++; 576 } 577 } 578 /* word */ 579 if (wordcols != 0) { 580 tp->words[tp->nword] = wordcols; 581 tp->nword += 1; 582 tp->maxwordcols = MAX(wordcols, tp->maxwordcols); 583 } 584 /* line */ 585 tp->maxline = MAX(tp->maxline, currlinecols); 586 587 free(wtext); 588 589 return (0); 590} 591 592static int 593text_autosize(struct bsddialog_conf *conf, struct textproperties *tp, 594 int maxrows, int mincols, bool increasecols, int *h, int *w) 595{ 596 int i, j, x, y, z, l, line, maxwidth, tablen; 597 598 maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS; 599 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; 600 601 if (increasecols) { 602 mincols = MAX(mincols, tp->maxwordcols); 603 mincols = MAX(mincols, 604 (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS); 605 mincols = MIN(mincols, maxwidth); 606 } 607 608 while (true) { 609 x = 0; 610 y = 1; 611 line=0; 612 l = 0; 613 for (i = 0; i < tp->nword; i++) { 614 switch (tp->words[i]) { 615 case TB: 616 for (j = 0; j < tablen; j++) { 617 if (x >= mincols) { 618 x = 0; 619 y++; 620 } 621 x++; 622 } 623 break; 624 case NL: 625 y++; 626 x = 0; 627 break; 628 case WS: 629 x++; 630 if (x >= mincols) { 631 x = 0; 632 y++; 633 } 634 break; 635 default: 636 if (tp->words[i] + x <= mincols) { 637 x += tp->words[i]; 638 for (z = 0 ; z != tp->words[i]; l++ ) 639 z += tp->wletters[l]; 640 } else if (tp->words[i] <= mincols) { 641 y++; 642 x = tp->words[i]; 643 for (z = 0 ; z != tp->words[i]; l++ ) 644 z += tp->wletters[l]; 645 } else { 646 for (j = tp->words[i]; j > 0; ) { 647 y = (x == 0) ? y : y + 1; 648 z = 0; 649 while (z != j && z < mincols) { 650 z += tp->wletters[l]; 651 l++; 652 } 653 x = z; 654 line = MAX(line, x); 655 j -= z; 656 } 657 } 658 } 659 line = MAX(line, x); 660 } 661 662 if (increasecols == false) 663 break; 664 if (mincols >= maxwidth) 665 break; 666 if (line >= y * (int)conf->text.cols_per_row && y <= maxrows) 667 break; 668 mincols++; 669 } 670 671 *h = (tp->nword == 0) ? 0 : y; 672 *w = MIN(mincols, line); /* wtext can be less than mincols */ 673 674 return (0); 675} 676 677static int 678text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text, 679 struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext) 680{ 681 bool changewtext; 682 int wbuttons, maxhtext; 683 struct textproperties tp; 684 685 wbuttons = 0; 686 if (bs->nbuttons > 0) 687 wbuttons = buttons_min_width(bs); 688 689 /* Rows */ 690 if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) { 691 maxhtext = widget_max_height(conf) - BORDERS - rowsnotext; 692 } else { /* fixed */ 693 maxhtext = rows - BORDERS - rowsnotext; 694 } 695 if (bs->nbuttons > 0) 696 maxhtext -= 2; 697 if (maxhtext <= 0) 698 maxhtext = 1; /* text_autosize() computes always htext */ 699 700 /* Cols */ 701 if (cols == BSDDIALOG_AUTOSIZE) { 702 startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS); 703 changewtext = true; 704 } else if (cols == BSDDIALOG_FULLSCREEN) { 705 startwtext = widget_max_width(conf) - BORDERS - TEXTHMARGINS; 706 changewtext = false; 707 } else { /* fixed */ 708 startwtext = cols - BORDERS - TEXTHMARGINS; 709 changewtext = false; 710 } 711 712 if (startwtext <= 0 && changewtext) 713 startwtext = 1; 714 715 /* Sizing calculation */ 716 if (text_properties(conf, text, &tp) != 0) 717 return (BSDDIALOG_ERROR); 718 if (tp.nword > 0 && startwtext <= 0) 719 RETURN_FMTERROR("(fixed cols or fullscreen) " 720 "needed at least %d cols to draw text", 721 BORDERS + TEXTHMARGINS + 1); 722 if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext, 723 wtext) != 0) 724 return (BSDDIALOG_ERROR); 725 726 free(tp.words); 727 free(tp.wletters); 728 729 return (0); 730} 731 732static int 733widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext, 734 bool withbuttons) 735{ 736 int min; 737 738 /* dialog borders */ 739 min = BORDERS; 740 741 /* text */ 742 min += htext; 743 744 /* specific widget lines without text */ 745 min += hnotext; 746 747 /* buttons */ 748 if (withbuttons) 749 min += HBUTTONS; /* buttons and their up-border */ 750 751 /* conf.auto_minheight */ 752 min = MAX(min, (int)conf->auto_minheight); 753 754 return (min); 755} 756 757static int 758widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget, 759 struct buttons *bs) 760 761{ 762 int min, delimtitle, wbottomtitle, wtitle; 763 764 min = 0; 765 766 /* buttons */ 767 if (bs->nbuttons > 0) 768 min += buttons_min_width(bs); 769 770 /* text */ 771 if (wtext > 0) 772 min = MAX(min, wtext + TEXTHMARGINS); 773 774 /* specific widget min width */ 775 min = MAX(min, minwidget); 776 777 /* title */ 778 if (conf->title != NULL) { 779 delimtitle = t.dialog.delimtitle ? 2 : 0; 780 wtitle = strcols(conf->title); 781 min = MAX(min, wtitle + 2 + delimtitle); 782 } 783 784 /* bottom title */ 785 if (conf->bottomtitle != NULL) { 786 wbottomtitle = strcols(conf->bottomtitle); 787 min = MAX(min, wbottomtitle + 4); 788 } 789 790 /* dialog borders */ 791 min += BORDERS; 792 /* conf.auto_minwidth */ 793 min = MAX(min, (int)conf->auto_minwidth); 794 795 return (min); 796} 797 798int 799set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w) 800{ 801 int maxheight, maxwidth; 802 803 if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR) 804 return (BSDDIALOG_ERROR); 805 806 if (rows == BSDDIALOG_FULLSCREEN) 807 *h = maxheight; 808 else if (rows < BSDDIALOG_FULLSCREEN) 809 RETURN_ERROR("Negative (less than -1) height"); 810 else if (rows > BSDDIALOG_AUTOSIZE) /* fixed rows */ 811 *h = MIN(rows, maxheight); /* rows is at most maxheight */ 812 /* rows == AUTOSIZE: each widget has to set its size */ 813 814 if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR) 815 return (BSDDIALOG_ERROR); 816 817 if (cols == BSDDIALOG_FULLSCREEN) 818 *w = maxwidth; 819 else if (cols < BSDDIALOG_FULLSCREEN) 820 RETURN_ERROR("Negative (less than -1) width"); 821 else if (cols > BSDDIALOG_AUTOSIZE) /* fixed cols */ 822 *w = MIN(cols, maxwidth); /* cols is at most maxwidth */ 823 /* cols == AUTOSIZE: each widget has to set its size */ 824 825 return (0); 826} 827 828int 829set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, 830 int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext, 831 int minw) 832{ 833 int htext, wtext; 834 835 if (rows == BSDDIALOG_AUTOSIZE || cols == BSDDIALOG_AUTOSIZE || 836 rowstext != NULL) { 837 if (text_size(conf, rows, cols, text, bs, hnotext, minw, 838 &htext, &wtext) != 0) 839 return (BSDDIALOG_ERROR); 840 if (rowstext != NULL) 841 *rowstext = htext; 842 } 843 844 if (rows == BSDDIALOG_AUTOSIZE) { 845 *h = widget_min_height(conf, htext, hnotext, bs->nbuttons > 0); 846 *h = MIN(*h, widget_max_height(conf)); 847 } 848 849 if (cols == BSDDIALOG_AUTOSIZE) { 850 *w = widget_min_width(conf, wtext, minw, bs); 851 *w = MIN(*w, widget_max_width(conf)); 852 } 853 854 return (0); 855} 856 857int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw) 858{ 859 int minheight, minwidth; 860 861 minheight = BORDERS + hnotext; 862 if (bs->nbuttons > 0) 863 minheight += HBUTTONS; 864 if (h < minheight) 865 RETURN_FMTERROR("Current rows: %d, needed at least: %d", 866 h, minheight); 867 868 minwidth = 0; 869 if (bs->nbuttons > 0) 870 minwidth = buttons_min_width(bs); 871 minwidth = MAX(minwidth, minw); 872 minwidth += BORDERS; 873 if (w < minwidth) 874 RETURN_FMTERROR("Current cols: %d, nedeed at least %d", 875 w, minwidth); 876 877 return (0); 878} 879 880int 881set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w) 882{ 883 int hshadow = conf->shadow ? (int)t.shadow.y : 0; 884 int wshadow = conf->shadow ? (int)t.shadow.x : 0; 885 886 if (conf->y == BSDDIALOG_CENTER) { 887 *y = SCREENLINES/2 - (h + hshadow)/2; 888 if (*y < (int)conf->auto_topmargin) 889 *y = conf->auto_topmargin; 890 if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin) 891 *y = SCREENLINES - h - hshadow - conf->auto_downmargin; 892 } 893 else if (conf->y < BSDDIALOG_CENTER) 894 RETURN_ERROR("Negative begin y (less than -1)"); 895 else if (conf->y >= SCREENLINES) 896 RETURN_ERROR("Begin Y under the terminal"); 897 else 898 *y = conf->y; 899 900 if (*y + h + hshadow > SCREENLINES) 901 RETURN_ERROR("The lower of the box under the terminal " 902 "(begin Y + height (+ shadow) > terminal lines)"); 903 904 905 if (conf->x == BSDDIALOG_CENTER) 906 *x = SCREENCOLS/2 - (w + wshadow)/2; 907 else if (conf->x < BSDDIALOG_CENTER) 908 RETURN_ERROR("Negative begin x (less than -1)"); 909 else if (conf->x >= SCREENCOLS) 910 RETURN_ERROR("Begin X over the right of the terminal"); 911 else 912 *x = conf->x; 913 914 if ((*x + w + wshadow) > SCREENCOLS) 915 RETURN_ERROR("The right of the box over the terminal " 916 "(begin X + width (+ shadow) > terminal cols)"); 917 918 return (0); 919} 920 921int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext) 922{ 923 if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0) 924 return (BSDDIALOG_ERROR); 925 if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w, 926 d->text, htext, &d->bs, hnotext, minw) != 0) 927 return (BSDDIALOG_ERROR); 928 if (widget_checksize(d->h, d->w, &d->bs, hnotext, minw) != 0) 929 return (BSDDIALOG_ERROR); 930 if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0) 931 return (BSDDIALOG_ERROR); 932 933 return (0); 934} 935 936/* 937 * -5- Widget components and utilities 938 */ 939int hide_dialog(struct dialog *d) 940{ 941 WINDOW *clear; 942 943 if ((clear = newwin(d->h, d->w, d->y, d->x)) == NULL) 944 RETURN_ERROR("Cannot hide the widget"); 945 wbkgd(clear, t.screen.color); 946 wrefresh(clear); 947 948 if (d->conf->shadow) { 949 mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x); 950 wrefresh(clear); 951 } 952 953 delwin(clear); 954 955 return (0); 956} 957 958int f1help_dialog(struct bsddialog_conf *conf) 959{ 960 int output; 961 struct bsddialog_conf hconf; 962 963 bsddialog_initconf(&hconf); 964 hconf.title = "HELP"; 965 hconf.button.ok_label = "EXIT"; 966 hconf.clear = true; 967 hconf.ascii_lines = conf->ascii_lines; 968 hconf.no_lines = conf->no_lines; 969 hconf.shadow = conf->shadow; 970 hconf.text.escape = conf->text.escape; 971 972 output = BSDDIALOG_OK; 973 if (conf->key.f1_message != NULL) 974 output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0); 975 976 if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL) 977 output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0); 978 979 return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0); 980} 981 982void draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev) 983{ 984 int h, w; 985 int leftcolor, rightcolor; 986 cchar_t *ls, *rs, *ts, *bs, *tl, *tr, *bl, *br; 987 cchar_t hline, vline, corner; 988 989 if (conf->no_lines) 990 return; 991 992 if (conf->ascii_lines) { 993 setcchar(&hline, L"|", 0, 0, NULL); 994 ls = rs = &hline; 995 setcchar(&vline, L"-", 0, 0, NULL); 996 ts = bs = &vline; 997 setcchar(&corner, L"+", 0, 0, NULL); 998 tl = tr = bl = br = &corner; 999 } else { 1000 ls = rs = WACS_VLINE; 1001 ts = bs = WACS_HLINE; 1002 tl = WACS_ULCORNER; 1003 tr = WACS_URCORNER; 1004 bl = WACS_LLCORNER; 1005 br = WACS_LRCORNER; 1006 } 1007 1008 getmaxyx(win, h, w); 1009 leftcolor = (elev == RAISED) ? 1010 t.dialog.lineraisecolor : t.dialog.linelowercolor; 1011 rightcolor = (elev == RAISED) ? 1012 t.dialog.linelowercolor : t.dialog.lineraisecolor; 1013 1014 wattron(win, leftcolor); 1015 wborder_set(win, ls, rs, ts, bs, tl, tr, bl, br); 1016 wattroff(win, leftcolor); 1017 1018 wattron(win, rightcolor); 1019 mvwadd_wch(win, 0, w-1, tr); 1020 mvwvline_set(win, 1, w-1, rs, h-2); 1021 mvwadd_wch(win, h-1, w-1, br); 1022 mvwhline_set(win, h-1, 1, bs, w-2); 1023 wattroff(win, rightcolor); 1024} 1025 1026void 1027update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w, 1028 enum elevation elev) 1029{ 1030 wclear(win); 1031 wresize(win, h, w); 1032 mvwin(win, y, x); 1033 draw_borders(conf, win, elev); 1034} 1035 1036void 1037rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext) 1038{ 1039 pnoutrefresh(d->textpad, ytext, xtext, 1040 d->y + BORDER + upnotext, 1041 d->x + BORDER + TEXTHMARGIN, 1042 d->y + d->h - 1 - downnotext - BORDER, 1043 d->x + d->w - TEXTHMARGIN - BORDER); 1044} 1045 1046/* 1047 * -6- Dialog init/build, update/draw, destroy 1048 */ 1049void end_dialog(struct dialog *d) 1050{ 1051 if (d->conf->sleep > 0) 1052 sleep(d->conf->sleep); 1053 1054 delwin(d->textpad); 1055 delwin(d->widget); 1056 if (d->conf->shadow) 1057 delwin(d->shadow); 1058 1059 if (d->conf->clear) 1060 hide_dialog(d); 1061 1062 if (d->conf->get_height != NULL) 1063 *d->conf->get_height = d->h; 1064 if (d->conf->get_width != NULL) 1065 *d->conf->get_width = d->w; 1066} 1067 1068static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext) 1069{ 1070 enum bsddialog_color bg; 1071 1072 if (is_wtext_attr(wtext) == false) 1073 return (false); 1074 1075 if ((wtext[2] >= L'0') && (wtext[2] <= L'7')) { 1076 bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL); 1077 wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0)); 1078 return (true); 1079 } 1080 1081 switch (wtext[2]) { 1082 case L'n': 1083 wattron(win, t.dialog.color); 1084 wattrset(win, A_NORMAL); 1085 break; 1086 case L'b': 1087 wattron(win, A_BOLD); 1088 break; 1089 case L'B': 1090 wattroff(win, A_BOLD); 1091 break; 1092 case L'd': 1093 wattron(win, A_DIM); 1094 break; 1095 case L'D': 1096 wattroff(win, A_DIM); 1097 break; 1098 case L'k': 1099 wattron(win, A_BLINK); 1100 break; 1101 case L'K': 1102 wattroff(win, A_BLINK); 1103 break; 1104 case L'r': 1105 wattron(win, A_REVERSE); 1106 break; 1107 case L'R': 1108 wattroff(win, A_REVERSE); 1109 break; 1110 case L's': 1111 wattron(win, A_STANDOUT); 1112 break; 1113 case L'S': 1114 wattroff(win, A_STANDOUT); 1115 break; 1116 case L'u': 1117 wattron(win, A_UNDERLINE); 1118 break; 1119 case L'U': 1120 wattroff(win, A_UNDERLINE); 1121 break; 1122 } 1123 1124 return (true); 1125} 1126 1127static void 1128print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str, 1129 bool color) 1130{ 1131 int charwidth, i, j, strlen, strwidth; 1132 wchar_t ws[2]; 1133 1134 ws[1] = L'\0'; 1135 1136 strlen = wcslen(str); 1137 if (color) { 1138 strwidth = 0; 1139 i=0; 1140 while (i < strlen) { 1141 if (is_wtext_attr(str+i) == false) { 1142 strwidth += wcwidth(str[i]); 1143 i++; 1144 } else { 1145 i += 3; 1146 } 1147 } 1148 } else 1149 strwidth = wcswidth(str, strlen); 1150 1151 i = 0; 1152 while (i < strlen) { 1153 if (*x + strwidth > cols) { 1154 if (*x != 0) 1155 *y = *y + 1; 1156 if (*y >= *rows) { 1157 *rows = *y + 1; 1158 wresize(win, *rows, cols); 1159 } 1160 *x = 0; 1161 } 1162 j = *x; 1163 while (i < strlen) { 1164 if (color && check_set_wtext_attr(win, str+i)) { 1165 i += 3; 1166 continue; 1167 } 1168 1169 charwidth = wcwidth(str[i]); 1170 if (j + wcwidth(str[i]) > cols) 1171 break; 1172 /* inline mvwaddwch() for efficiency */ 1173 ws[0] = str[i]; 1174 mvwaddwstr(win, *y, j, ws); 1175 strwidth -= charwidth; 1176 j += charwidth; 1177 *x = j; 1178 i++; 1179 } 1180 } 1181} 1182 1183static int 1184print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text) 1185{ 1186 bool loop; 1187 int i, j, z, rows, cols, x, y, tablen; 1188 wchar_t *wtext, *string; 1189 1190 if ((wtext = alloc_mbstows(text)) == NULL) 1191 RETURN_ERROR("Cannot allocate/print text in wchar_t*"); 1192 1193 if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL) 1194 RETURN_ERROR("Cannot build (analyze) text"); 1195 1196 getmaxyx(pad, rows, cols); 1197 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen; 1198 1199 i = j = x = y = 0; 1200 loop = true; 1201 while (loop) { 1202 string[j] = wtext[i]; 1203 1204 if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') { 1205 string[j] = L'\0'; 1206 print_string(pad, &rows, cols, &y, &x, string, 1207 conf->text.escape); 1208 } 1209 1210 switch (wtext[i]) { 1211 case L'\0': 1212 loop = false; 1213 break; 1214 case L'\n': 1215 x = 0; 1216 y++; 1217 j = -1; 1218 break; 1219 case L'\t': 1220 for (z = 0; z < tablen; z++) { 1221 if (x >= cols) { 1222 x = 0; 1223 y++; 1224 } 1225 x++; 1226 } 1227 j = -1; 1228 break; 1229 case L' ': 1230 x++; 1231 if (x >= cols) { 1232 x = 0; 1233 y++; 1234 } 1235 j = -1; 1236 } 1237 1238 if (y >= rows) { 1239 rows = y + 1; 1240 wresize(pad, rows, cols); 1241 } 1242 1243 j++; 1244 i++; 1245 } 1246 1247 free(wtext); 1248 free(string); 1249 1250 return (0); 1251} 1252 1253int draw_dialog(struct dialog *d) 1254{ 1255 int wtitle, wbottomtitle; 1256 cchar_t ts, ltee, rtee; 1257 1258 if (d->conf->ascii_lines) { 1259 setcchar(&ts, L"-", 0, 0, NULL); 1260 setcchar(<ee, L"+", 0, 0,NULL); 1261 setcchar(&rtee, L"+", 0, 0, NULL); 1262 } else { 1263 ts = *WACS_HLINE; 1264 ltee = *WACS_LTEE; 1265 rtee = *WACS_RTEE; 1266 } 1267 1268 if (d->conf->shadow) { 1269 wclear(d->shadow); 1270 wresize(d->shadow, d->h, d->w); 1271 mvwin(d->shadow, d->y + t.shadow.y, d->x + t.shadow.x); 1272 wnoutrefresh(d->shadow); 1273 } 1274 1275 wclear(d->widget); 1276 wresize(d->widget, d->h, d->w); 1277 mvwin(d->widget, d->y, d->x); 1278 draw_borders(d->conf, d->widget, RAISED); 1279 1280 if (d->conf->title != NULL) { 1281 if ((wtitle = strcols(d->conf->title)) < 0) 1282 return (BSDDIALOG_ERROR); 1283 if (t.dialog.delimtitle && d->conf->no_lines == false) { 1284 wattron(d->widget, t.dialog.lineraisecolor); 1285 mvwadd_wch(d->widget, 0, d->w/2 - wtitle/2 -1, &rtee); 1286 wattroff(d->widget, t.dialog.lineraisecolor); 1287 } 1288 wattron(d->widget, t.dialog.titlecolor); 1289 mvwaddstr(d->widget, 0, d->w/2 - wtitle/2, d->conf->title); 1290 wattroff(d->widget, t.dialog.titlecolor); 1291 if (t.dialog.delimtitle && d->conf->no_lines == false) { 1292 wattron(d->widget, t.dialog.lineraisecolor); 1293 wadd_wch(d->widget, <ee); 1294 wattroff(d->widget, t.dialog.lineraisecolor); 1295 } 1296 } 1297 1298 if (d->bs.nbuttons > 0) { 1299 if (d->conf->no_lines == false) { 1300 wattron(d->widget, t.dialog.lineraisecolor); 1301 mvwadd_wch(d->widget, d->h-3, 0, <ee); 1302 mvwhline_set(d->widget, d->h-3, 1, &ts, d->w-2); 1303 wattroff(d->widget, t.dialog.lineraisecolor); 1304 1305 wattron(d->widget, t.dialog.linelowercolor); 1306 mvwadd_wch(d->widget, d->h-3, d->w-1, &rtee); 1307 wattroff(d->widget, t.dialog.linelowercolor); 1308 } 1309 draw_buttons(d); 1310 } 1311 1312 if (d->conf->bottomtitle != NULL) { 1313 if ((wbottomtitle = strcols(d->conf->bottomtitle)) < 0) 1314 return (BSDDIALOG_ERROR); 1315 wattron(d->widget, t.dialog.bottomtitlecolor); 1316 wmove(d->widget, d->h - 1, d->w/2 - wbottomtitle/2 - 1); 1317 waddch(d->widget, ' '); 1318 waddstr(d->widget, d->conf->bottomtitle); 1319 waddch(d->widget, ' '); 1320 wattroff(d->widget, t.dialog.bottomtitlecolor); 1321 } 1322 1323 wnoutrefresh(d->widget); 1324 1325 wclear(d->textpad); 1326 /* `infobox "" 0 2` fails but text is empty and textpad remains 1 1 */ 1327 wresize(d->textpad, 1, d->w - BORDERS - TEXTHMARGINS); 1328 1329 if (print_textpad(d->conf, d->textpad, d->text) != 0) 1330 return (BSDDIALOG_ERROR); 1331 1332 d->built = true; 1333 1334 return (0); 1335} 1336 1337int 1338prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows, 1339 int cols, struct dialog *d) 1340{ 1341 CHECK_PTR(conf); 1342 1343 d->built = false; 1344 d->conf = conf; 1345 d->rows = rows; 1346 d->cols = cols; 1347 d->text = CHECK_STR(text); 1348 d->bs.nbuttons = 0; 1349 1350 if (d->conf->shadow) { 1351 if ((d->shadow = newwin(1, 1, 1, 1)) == NULL) 1352 RETURN_ERROR("Cannot build WINDOW shadow"); 1353 wbkgd(d->shadow, t.shadow.color); 1354 } 1355 1356 if ((d->widget = newwin(1, 1, 1, 1)) == NULL) 1357 RETURN_ERROR("Cannot build WINDOW widget"); 1358 wbkgd(d->widget, t.dialog.color); 1359 1360 /* fake for textpad */ 1361 if ((d->textpad = newpad(1, 1)) == NULL) 1362 RETURN_ERROR("Cannot build the pad WINDOW for text"); 1363 wbkgd(d->textpad, t.dialog.color); 1364 1365 return (0); 1366}