1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Alfonso Sabato Siciliano 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #ifdef PORTNCURSES 35 #include <ncurses/ncurses.h> 36 #else 37 #include <ncurses.h> 38 #endif 39 40 #include "bsddialog.h" 41 #include "lib_util.h" 42 #include "bsddialog_theme.h" 43 44 extern struct bsddialog_theme t; 45 46 /* Error buffer */ 47 48 #define ERRBUFLEN 1024 49 static char errorbuffer[ERRBUFLEN]; 50 51 const char *get_error_string(void) 52 { 53 return errorbuffer; 54 } 55 56 void set_error_string(char *str) 57 { 58 59 strncpy(errorbuffer, str, ERRBUFLEN-1); 60 } 61 62 /* cleaner */ 63 int hide_widget(int y, int x, int h, int w, bool withshadow) 64 { 65 WINDOW *clear; 66 67 /* no check: y, x, h and w are checked by the builders */ 68 if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL) 69 RETURN_ERROR("Cannot hide the widget"); 70 wbkgd(clear, t.terminal.color); 71 72 if (withshadow) 73 wrefresh(clear); 74 75 mvwin(clear, y, x); 76 wrefresh(clear); 77 78 delwin(clear); 79 80 return 0; 81 } 82 83 /* F1 help */ 84 int f1help(struct bsddialog_conf *conf) 85 { 86 int output; 87 struct bsddialog_conf hconf; 88 89 //memcpy(&hconf, conf, sizeof(struct bsddialog_conf)); 90 bsddialog_initconf(&hconf); 91 hconf.title = "HELP"; 92 hconf.button.ok_label = "EXIT"; 93 hconf.clear = true; 94 hconf.ascii_lines = conf->ascii_lines; 95 hconf.no_lines = conf->no_lines; 96 hconf.shadow = conf->shadow; 97 hconf.text.colors = conf->text.colors; 98 99 output = BSDDIALOG_OK; 100 if (conf->f1_message != NULL) 101 output = bsddialog_msgbox(&hconf, conf->f1_message, 0, 0); 102 103 if (output != BSDDIALOG_ERROR && conf->f1_file != NULL) 104 output = bsddialog_textbox(&hconf, conf->f1_file, 0, 0); 105 106 return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0); 107 } 108 109 /* Buttons */ 110 void 111 draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected, 112 bool shortkey) 113 { 114 int i, color_arrows, color_shortkey, color_button; 115 116 if (selected) { 117 color_arrows = t.button.f_delimcolor; 118 color_shortkey = t.button.f_shortcutcolor; 119 color_button = t.button.f_color; 120 } else { 121 color_arrows = t.button.delimcolor; 122 color_shortkey = t.button.shortcutcolor; 123 color_button = t.button.color; 124 } 125 126 wattron(window, color_arrows); 127 mvwaddch(window, y, x, t.button.leftch); 128 wattroff(window, color_arrows); 129 wattron(window, color_button); 130 for(i = 1; i < size - 1; i++) 131 waddch(window, ' '); 132 wattroff(window, color_button); 133 wattron(window, color_arrows); 134 mvwaddch(window, y, x + i, t.button.rightch); 135 wattroff(window, color_arrows); 136 137 x = x + 1 + ((size - 2 - strlen(text))/2); 138 wattron(window, color_button); 139 mvwaddstr(window, y, x, text); 140 wattroff(window, color_button); 141 142 if (shortkey) { 143 wattron(window, color_shortkey); 144 mvwaddch(window, y, x, text[0]); 145 wattroff(window, color_shortkey); 146 } 147 } 148 149 void 150 draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey) 151 { 152 int i, x, start_x; 153 154 start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.button.space; 155 start_x = cols/2 - start_x/2; 156 157 for (i = 0; i < (int) bs.nbuttons; i++) { 158 x = i * (bs.sizebutton + t.button.space); 159 draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i], 160 i == bs.curr, shortkey); 161 } 162 } 163 164 void 165 get_buttons(struct bsddialog_conf *conf, struct buttons *bs, char *yesoklabel, 166 char *extralabel, char *nocancellabel, char *helplabel) 167 { 168 int i; 169 #define SIZEBUTTON 8 170 #define DEFAULT_BUTTON_LABEL LABEL_ok_label 171 #define DEFAULT_BUTTON_VALUE BSDDIALOG_OK 172 173 174 bs->nbuttons = 0; 175 bs->curr = 0; 176 bs->sizebutton = 0; 177 178 if (yesoklabel != NULL && conf->button.without_ok == false) { 179 bs->label[0] = yesoklabel; 180 bs->value[0] = BSDDIALOG_OK; 181 bs->nbuttons += 1; 182 } 183 184 if (extralabel != NULL && conf->button.with_extra) { 185 bs->label[bs->nbuttons] = extralabel; 186 bs->value[bs->nbuttons] = BSDDIALOG_EXTRA; 187 bs->nbuttons += 1; 188 } 189 190 if (nocancellabel != NULL && conf->button.without_cancel == false) { 191 bs->label[bs->nbuttons] = nocancellabel; 192 bs->value[bs->nbuttons] = BSDDIALOG_CANCEL; 193 if (conf->button.default_cancel) 194 bs->curr = bs->nbuttons; 195 bs->nbuttons += 1; 196 } 197 198 if (helplabel != NULL && conf->button.with_help) { 199 bs->label[bs->nbuttons] = helplabel; 200 bs->value[bs->nbuttons] = BSDDIALOG_HELP; 201 bs->nbuttons += 1; 202 } 203 204 if (conf->button.generic1_label != NULL) { 205 bs->label[bs->nbuttons] = conf->button.generic1_label; 206 bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1; 207 bs->nbuttons += 1; 208 } 209 210 if (conf->button.generic2_label != NULL) { 211 bs->label[bs->nbuttons] = conf->button.generic2_label; 212 bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2; 213 bs->nbuttons += 1; 214 } 215 216 if (bs->nbuttons == 0) { 217 bs->label[0] = DEFAULT_BUTTON_LABEL; 218 bs->value[0] = DEFAULT_BUTTON_VALUE; 219 bs->nbuttons = 1; 220 } 221 222 if (conf->button.default_label != NULL) { 223 for (i=0; i<(int)bs->nbuttons; i++) { 224 if (strcmp(conf->button.default_label, bs->label[i]) == 0) 225 bs->curr = i; 226 } 227 } 228 229 bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0])); 230 for (i=1; i < (int) bs->nbuttons; i++) 231 bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i])); 232 bs->sizebutton += 2; 233 } 234 235 /* Text */ 236 static bool is_ncurses_attr(char *text) 237 { 238 239 if (strnlen(text, 3) < 3) 240 return false; 241 242 if (text[0] != '\\' || text[1] != 'Z') 243 return false; 244 245 return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true); 246 } 247 248 static bool check_set_ncurses_attr(WINDOW *win, char *text) 249 { 250 251 if (is_ncurses_attr(text) == false) 252 return false; 253 254 if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) { 255 wattron(win, bsddialog_color( text[2] - '0', COLOR_WHITE, 0)); 256 return true; 257 } 258 259 switch (text[2]) { 260 case 'n': 261 wattrset(win, A_NORMAL); 262 break; 263 case 'b': 264 wattron(win, A_BOLD); 265 break; 266 case 'B': 267 wattroff(win, A_BOLD); 268 break; 269 case 'r': 270 wattron(win, A_REVERSE); 271 break; 272 case 'R': 273 wattroff(win, A_REVERSE); 274 break; 275 case 'u': 276 wattron(win, A_UNDERLINE); 277 break; 278 case 'U': 279 wattroff(win, A_UNDERLINE); 280 break; 281 } 282 283 return true; 284 } 285 286 static void 287 print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color) 288 { 289 int i, j, len, reallen; 290 291 if(strlen(str) == 0) 292 return; 293 294 len = reallen = strlen(str); 295 if (color) { 296 i=0; 297 while (i < len) { 298 if (is_ncurses_attr(str+i)) 299 reallen -= 3; 300 i++; 301 } 302 } 303 304 i = 0; 305 while (i < len) { 306 if (*x + reallen > cols) { 307 *y = (*x != 0 ? *y+1 : *y); 308 if (*y >= *rows) { 309 *rows = *y + 1; 310 wresize(win, *rows, cols); 311 } 312 *x = 0; 313 } 314 j = *x; 315 while (j < cols && i < len) { 316 if (color && check_set_ncurses_attr(win, str+i)) { 317 i += 3; 318 } else { 319 mvwaddch(win, *y, j, str[i]); 320 i++; 321 reallen--; 322 j++; 323 *x = j; 324 } 325 } 326 } 327 } 328 329 int 330 get_text_properties(struct bsddialog_conf *conf, char *text, int *maxword, 331 int *maxline, int *nlines) 332 { 333 int i, buflen, wordlen, linelen; 334 335 336 buflen = strlen(text) + 1; 337 *maxword = 0; 338 wordlen = 0; 339 for (i=0; i < buflen; i++) { 340 if (text[i] == '\t' || text[i] == '\n' || text[i] == ' ' || text[i] == '\0') 341 if (wordlen != 0) { 342 *maxword = MAX(*maxword, wordlen); 343 wordlen = 0; 344 continue; 345 } 346 if (conf->text.colors && is_ncurses_attr(text + i)) 347 i += 3; 348 else 349 wordlen++; 350 } 351 352 *maxline = linelen = 0; 353 *nlines = 1; 354 for (i=0; i < buflen; i++) { 355 switch (text[i]) { 356 case '\n': 357 *nlines = *nlines + 1; 358 case '\0': 359 *maxline = MAX(*maxline, linelen); 360 linelen = 0; 361 break; 362 default: 363 if (conf->text.colors && is_ncurses_attr(text + i)) 364 i += 3; 365 else 366 linelen++; 367 } 368 } 369 if (*nlines == 1 && *maxline == 0) 370 *nlines = 0; 371 372 //free(buf); 373 374 return 0; 375 } 376 377 int 378 print_textpad(struct bsddialog_conf *conf, WINDOW *pad, int *rows, int cols, 379 char *text) 380 { 381 char *string; 382 int i, j, x, y; 383 bool loop; 384 385 if ((string = malloc(strlen(text) + 1)) == NULL) 386 RETURN_ERROR("Cannot build (analyze) text"); 387 388 i = j = x = y = 0; 389 loop = true; 390 while (loop) { 391 string[j] = text[i]; 392 393 if (string[j] == '\0' || string[j] == '\n' || 394 string[j] == '\t' || string[j] == ' ') { 395 if (j != 0) { 396 string[j] = '\0'; 397 print_str(pad, rows, &y, &x, cols, string, 398 conf->text.colors); 399 } 400 } 401 402 switch (text[i]) { 403 case '\0': 404 loop = false; 405 break; 406 case '\n': 407 j = -1; 408 x = 0; 409 y++; 410 break; 411 case '\t': 412 for (j=0; j<4 /*tablen*/; j++) { 413 x++; 414 if (x >= cols) { 415 x = 0; 416 y++; 417 } 418 } 419 j = -1; 420 break; 421 case ' ': 422 x++; 423 if (x >= cols) { 424 x = 0; 425 y++; 426 } 427 j = -1; 428 } 429 430 if (y >= *rows) { /* check for whitespaces */ 431 *rows = y + 1; 432 wresize(pad, *rows, cols); 433 } 434 435 j++; 436 i++; 437 } 438 439 free(string); 440 441 return 0; 442 } 443 444 /* autosize */ 445 446 /* 447 * max y, that is from 0 to LINES - 1 - t.shadowrows, 448 * could not be max height but avoids problems with checksize 449 */ 450 int widget_max_height(struct bsddialog_conf *conf) 451 { 452 int maxheight; 453 454 if ((maxheight = conf->shadow ? LINES - 1 - t.shadow.h : LINES - 1) <= 0) 455 RETURN_ERROR("Terminal too small, LINES - shadow <= 0"); 456 457 if (conf->y > 0) 458 if ((maxheight -= conf->y) <=0) 459 RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0"); 460 461 return maxheight; 462 } 463 464 /* 465 * max x, that is from 0 to COLS - 1 - t.shadowcols, 466 * * could not be max height but avoids problems with checksize 467 */ 468 int widget_max_width(struct bsddialog_conf *conf) 469 { 470 int maxwidth; 471 472 if ((maxwidth = conf->shadow ? COLS - 1 - t.shadow.w : COLS - 1) <= 0) 473 RETURN_ERROR("Terminal too small, COLS - shadow <= 0"); 474 if (conf->x > 0) 475 if ((maxwidth -= conf->x) <=0) 476 RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0"); 477 478 return maxwidth; 479 } 480 481 int 482 set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w) 483 { 484 int maxheight, maxwidth; 485 486 if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR) 487 return BSDDIALOG_ERROR; 488 489 if (rows == BSDDIALOG_FULLSCREEN) 490 *h = maxheight; 491 else if (rows < BSDDIALOG_FULLSCREEN) 492 RETURN_ERROR("Negative (less than -1) height"); 493 else if (rows > BSDDIALOG_AUTOSIZE) { 494 if ((*h = rows) > maxheight) 495 RETURN_ERROR("Height too big (> terminal height - "\ 496 "shadow"); 497 } 498 /* rows == AUTOSIZE: each widget has to set its size */ 499 500 if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR) 501 return BSDDIALOG_ERROR; 502 503 if (cols == BSDDIALOG_FULLSCREEN) 504 *w = maxwidth; 505 else if (cols < BSDDIALOG_FULLSCREEN) 506 RETURN_ERROR("Negative (less than -1) width"); 507 else if (cols > BSDDIALOG_AUTOSIZE) { 508 if ((*w = cols) > maxwidth) 509 RETURN_ERROR("Width too big (> terminal width - shadow)"); 510 } 511 /* cols == AUTOSIZE: each widget has to set its size */ 512 513 return 0; 514 } 515 516 int 517 set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w) 518 { 519 520 if (conf->y == BSDDIALOG_CENTER) 521 *y = LINES/2 - h/2; 522 else if (conf->y < BSDDIALOG_CENTER) 523 RETURN_ERROR("Negative begin y (less than -1)"); 524 else if (conf->y >= LINES) 525 RETURN_ERROR("Begin Y under the terminal"); 526 else 527 *y = conf->y; 528 529 if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > LINES) 530 RETURN_ERROR("The lower of the box under the terminal "\ 531 "(begin Y + height (+ shadow) > terminal lines)"); 532 533 534 if (conf->x == BSDDIALOG_CENTER) 535 *x = COLS/2 - w/2; 536 else if (conf->x < BSDDIALOG_CENTER) 537 RETURN_ERROR("Negative begin x (less than -1)"); 538 else if (conf->x >= COLS) 539 RETURN_ERROR("Begin X over the right of the terminal"); 540 else 541 *x = conf->x; 542 543 if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > COLS) 544 RETURN_ERROR("The right of the box over the terminal "\ 545 "(begin X + width (+ shadow) > terminal cols)"); 546 547 return 0; 548 } 549 550 /* Widgets builders */ 551 void 552 draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols, 553 enum elevation elev) 554 { 555 int leftcolor, rightcolor; 556 int ls, rs, ts, bs, tl, tr, bl, br; 557 int ltee, rtee; 558 559 ls = rs = ACS_VLINE; 560 ts = bs = ACS_HLINE; 561 tl = ACS_ULCORNER; 562 tr = ACS_URCORNER; 563 bl = ACS_LLCORNER; 564 br = ACS_LRCORNER; 565 ltee = ACS_LTEE; 566 rtee = ACS_RTEE; 567 568 if (conf->no_lines == false) { 569 if (conf->ascii_lines) { 570 ls = rs = '|'; 571 ts = bs = '-'; 572 tl = tr = bl = br = ltee = rtee = '+'; 573 } 574 leftcolor = elev == RAISED ? 575 t.dialog.lineraisecolor : t.dialog.linelowercolor; 576 rightcolor = elev == RAISED ? 577 t.dialog.linelowercolor : t.dialog.lineraisecolor; 578 wattron(win, leftcolor); 579 wborder(win, ls, rs, ts, bs, tl, tr, bl, br); 580 wattroff(win, leftcolor); 581 582 wattron(win, rightcolor); 583 mvwaddch(win, 0, cols-1, tr); 584 mvwvline(win, 1, cols-1, rs, rows-2); 585 mvwaddch(win, rows-1, cols-1, br); 586 mvwhline(win, rows-1, 1, bs, cols-2); 587 wattroff(win, rightcolor); 588 } 589 } 590 591 WINDOW * 592 new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols, 593 enum elevation elev) 594 { 595 WINDOW *win; 596 597 if ((win = newwin(rows, cols, y, x)) == NULL) { 598 set_error_string("Cannot build boxed window"); 599 return NULL; 600 } 601 602 wbkgd(win, t.dialog.color); 603 604 draw_borders(conf, win, rows, cols, elev); 605 606 return win; 607 } 608 609 /* 610 * `enum elevation elev` could be useless because it should be always RAISED, 611 * to check at the end. 612 */ 613 static int 614 draw_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow, 615 WINDOW *widget, int h, int w, enum elevation elev, 616 WINDOW *textpad, int *htextpad, char *text, bool buttons) 617 { 618 int ts, ltee, rtee; 619 int colordelimtitle; 620 621 ts = conf->ascii_lines ? '-' : ACS_HLINE; 622 ltee = conf->ascii_lines ? '+' : ACS_LTEE; 623 rtee = conf->ascii_lines ? '+' : ACS_RTEE; 624 colordelimtitle = elev == RAISED ? 625 t.dialog.lineraisecolor : t.dialog.linelowercolor; 626 627 if (shadow != NULL) 628 wnoutrefresh(shadow); 629 630 // move / resize now or the caller? 631 draw_borders(conf, widget, h, w, elev); 632 633 if (conf->title != NULL) { 634 if (t.dialog.delimtitle && conf->no_lines == false) { 635 wattron(widget, colordelimtitle); 636 mvwaddch(widget, 0, w/2 - strlen(conf->title)/2 - 1, rtee); 637 wattroff(widget, colordelimtitle); 638 } 639 wattron(widget, t.dialog.titlecolor); 640 mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title); 641 wattroff(widget, t.dialog.titlecolor); 642 if (t.dialog.delimtitle && conf->no_lines == false) { 643 wattron(widget, colordelimtitle); 644 waddch(widget, ltee); 645 wattroff(widget, colordelimtitle); 646 } 647 } 648 649 if (conf->bottomtitle != NULL) { 650 wattron(widget, t.dialog.bottomtitlecolor); 651 wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1); 652 waddch(widget, '['); 653 waddstr(widget, conf->bottomtitle); 654 waddch(widget, ']'); 655 wattroff(widget, t.dialog.bottomtitlecolor); 656 } 657 658 //if (textpad == NULL && text != NULL) /* no pad, text null for textbox */ 659 // print_text(conf, widget, 1, 2, w-3, text); 660 661 if (buttons && conf->no_lines == false) { 662 wattron(widget, t.dialog.lineraisecolor); 663 mvwaddch(widget, h-3, 0, ltee); 664 mvwhline(widget, h-3, 1, ts, w-2); 665 wattroff(widget, t.dialog.lineraisecolor); 666 667 wattron(widget, t.dialog.linelowercolor); 668 mvwaddch(widget, h-3, w-1, rtee); 669 wattroff(widget, t.dialog.linelowercolor); 670 } 671 672 wnoutrefresh(widget); 673 674 if (textpad == NULL) 675 return 0; /* widget_init() ends */ 676 677 if (text != NULL) /* programbox etc */ 678 if (print_textpad(conf, textpad, htextpad, 679 w - HBORDERS - t.text.hmargin * 2, text) !=0) 680 return BSDDIALOG_ERROR; 681 682 return 0; 683 } 684 685 /* 686 * `enum elevation elev` could be useless because it should be always RAISED, 687 * to check at the end. 688 */ 689 int 690 update_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow, 691 WINDOW *widget, int h, int w, enum elevation elev, 692 WINDOW *textpad, int *htextpad, char *text, bool buttons) 693 { 694 int error; 695 696 /* nothing for now */ 697 698 error = draw_widget_withtextpad(conf, shadow, widget, h, w, 699 elev, textpad, htextpad, text, buttons); 700 701 return error; 702 } 703 704 /* 705 * `enum elevation elev` could be useless because it should be always RAISED, 706 * to check at the end. 707 */ 708 int 709 new_widget_withtextpad(struct bsddialog_conf *conf, WINDOW **shadow, 710 WINDOW **widget, int y, int x, int h, int w, enum elevation elev, 711 WINDOW **textpad, int *htextpad, char *text, bool buttons) 712 { 713 int error; 714 715 if (conf->shadow) { 716 *shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w); 717 if (*shadow == NULL) 718 RETURN_ERROR("Cannot build shadow"); 719 wbkgd(*shadow, t.shadow.color); 720 } 721 722 if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == NULL) { 723 if (conf->shadow) 724 delwin(*shadow); 725 return BSDDIALOG_ERROR; 726 } 727 728 if (textpad == NULL) { /* widget_init() */ 729 error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, 730 elev, NULL, NULL, text, buttons); 731 return error; 732 } 733 734 if (text != NULL) { /* programbox etc */ 735 *htextpad = 1; 736 *textpad = newpad(*htextpad, w - HBORDERS - t.text.hmargin * 2); 737 if (*textpad == NULL) { 738 delwin(*textpad); 739 if (conf->shadow) 740 delwin(*shadow); 741 RETURN_ERROR("Cannot build the pad window for text"); 742 } 743 wbkgd(*textpad, t.dialog.color); 744 } 745 746 error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev, 747 *textpad, htextpad, text, buttons); 748 749 return error; 750 } 751 752 void 753 end_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *window, int h, int w, 754 WINDOW *textpad, WINDOW *shadow) 755 { 756 int y, x; 757 758 getbegyx(window, y, x); /* for clear, add y & x to args? */ 759 760 if (conf->sleep > 0) 761 sleep(conf->sleep); 762 763 if (textpad != NULL) 764 delwin(textpad); 765 766 delwin(window); 767 768 if (conf->shadow) 769 delwin(shadow); 770 771 if (conf->clear) 772 hide_widget(y, x, h, w, shadow != NULL); 773 774 if (conf->get_height != NULL) 775 *conf->get_height = h; 776 if (conf->get_width != NULL) 777 *conf->get_width = w; 778 } 779