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