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/curses.h> 36 #else 37 #include <curses.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.shadowrows, x + t.shadowcols)) == NULL) 69 RETURN_ERROR("Cannot hide the widget"); 70 wbkgd(clear, t.backgroundcolor); 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 char *file = conf.hfile; 87 char *title = conf.title; 88 int output; 89 90 conf.hfile = NULL; 91 conf.clear = true; 92 conf.y = BSDDIALOG_CENTER; 93 conf.x = BSDDIALOG_CENTER; 94 conf.title = "HELP"; 95 conf.sleep = 0; 96 97 output = bsddialog_textbox(conf, file, BSDDIALOG_AUTOSIZE, 98 BSDDIALOG_AUTOSIZE); 99 conf.hfile = file; 100 conf.title = title; 101 102 return output; 103 } 104 105 /* Buttons */ 106 void 107 draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected, 108 bool shortkey) 109 { 110 int i, color_arrows, color_shortkey, color_button; 111 112 if (selected) { 113 color_arrows = t.currbuttdelimcolor; 114 color_shortkey = t.currshortkeycolor; 115 color_button = t.currbuttoncolor; 116 } else { 117 color_arrows = t.buttdelimcolor; 118 color_shortkey = t.shortkeycolor; 119 color_button = t.buttoncolor; 120 } 121 122 wattron(window, color_arrows); 123 mvwaddch(window, y, x, t.buttleftch); 124 wattroff(window, color_arrows); 125 wattron(window, color_button); 126 for(i = 1; i < size - 1; i++) 127 waddch(window, ' '); 128 wattroff(window, color_button); 129 wattron(window, color_arrows); 130 mvwaddch(window, y, x + i, t.buttrightchar); 131 wattroff(window, color_arrows); 132 133 x = x + 1 + ((size - 2 - strlen(text))/2); 134 wattron(window, color_button); 135 mvwaddstr(window, y, x, text); 136 wattroff(window, color_button); 137 138 if (shortkey) { 139 wattron(window, color_shortkey); 140 mvwaddch(window, y, x, text[0]); 141 wattroff(window, color_shortkey); 142 } 143 } 144 145 void 146 draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey) 147 { 148 int i, x, start_x; 149 150 start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.buttonspace; 151 start_x = cols/2 - start_x/2; 152 153 for (i = 0; i < (int) bs.nbuttons; i++) { 154 x = i * (bs.sizebutton + t.buttonspace); 155 draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i], 156 i == bs.curr, shortkey); 157 } 158 } 159 160 void 161 get_buttons(struct bsddialog_conf conf, struct buttons *bs, char *yesoklabel, 162 char *extralabel, char *nocancellabel, char *helplabel) 163 { 164 int i; 165 #define SIZEBUTTON 8 166 #define DEFAULT_BUTTON_LABEL LABEL_ok_label 167 #define DEFAULT_BUTTON_VALUE BSDDIALOG_YESOK 168 169 170 bs->nbuttons = 0; 171 bs->curr = 0; 172 bs->sizebutton = 0; 173 174 if (yesoklabel != NULL && conf.button.no_ok == false) { 175 bs->label[0] = yesoklabel; 176 bs->value[0] = BSDDIALOG_YESOK; 177 bs->nbuttons += 1; 178 } 179 180 if (extralabel != NULL && conf.button.extra_button) { 181 bs->label[bs->nbuttons] = extralabel; 182 bs->value[bs->nbuttons] = BSDDIALOG_EXTRA; 183 bs->nbuttons += 1; 184 } 185 186 if (nocancellabel != NULL && conf.button.no_cancel == false) { 187 bs->label[bs->nbuttons] = nocancellabel; 188 bs->value[bs->nbuttons] = BSDDIALOG_NOCANCEL; 189 if (conf.button.defaultno) 190 bs->curr = bs->nbuttons; 191 bs->nbuttons += 1; 192 } 193 194 if (helplabel != NULL && conf.button.help_button) { 195 bs->label[bs->nbuttons] = helplabel; 196 bs->value[bs->nbuttons] = BSDDIALOG_HELP; 197 bs->nbuttons += 1; 198 } 199 200 if (bs->nbuttons == 0) { 201 bs->label[0] = DEFAULT_BUTTON_LABEL; 202 bs->value[0] = DEFAULT_BUTTON_VALUE; 203 bs->nbuttons = 1; 204 } 205 206 if (conf.button.default_label != NULL) { 207 for (i=0; i<(int)bs->nbuttons; i++) { 208 if (strcmp(conf.button.default_label, bs->label[i]) == 0) 209 bs->curr = i; 210 } 211 } 212 213 bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0])); 214 for (i=1; i < (int) bs->nbuttons; i++) 215 bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i])); 216 bs->sizebutton += 2; 217 } 218 219 /* Text */ 220 221 // old text, to delete in the future 222 enum token { TEXT, WS, END }; 223 224 static bool check_set_ncurses_attr(WINDOW *win, char *text) 225 { 226 bool isattr; 227 int colors[8] = { 228 COLOR_BLACK, 229 COLOR_RED, 230 COLOR_GREEN, 231 COLOR_YELLOW, 232 COLOR_BLUE, 233 COLOR_MAGENTA, 234 COLOR_CYAN, 235 COLOR_WHITE 236 }; 237 238 if (text[0] == '\0' || text[0] != '\\') 239 return false; 240 if (text[1] == '\0' || text[1] != 'Z') 241 return false; 242 if (text[2] == '\0') 243 return false; 244 245 if ((text[2] - 48) >= 0 && (text[2] - 48) < 8) { 246 // tocheck: import BSD_COLOR 247 // tofix color background 248 wattron(win, COLOR_PAIR(colors[text[2] - 48] * 8 + COLOR_WHITE + 1)); 249 return true; 250 } 251 252 isattr = true; 253 switch (text[2]) { 254 case 'n': 255 wattrset(win, A_NORMAL); 256 break; 257 case 'b': 258 wattron(win, A_BOLD); 259 break; 260 case 'B': 261 wattroff(win, A_BOLD); 262 break; 263 case 'r': 264 wattron(win, A_REVERSE); 265 break; 266 case 'R': 267 wattroff(win, A_REVERSE); 268 break; 269 case 'u': 270 wattron(win, A_UNDERLINE); 271 break; 272 case 'U': 273 wattroff(win, A_UNDERLINE); 274 break; 275 default: 276 isattr = false; 277 } 278 279 return isattr; 280 } 281 282 static bool isws(int ch) 283 { 284 285 return (ch == ' ' || ch == '\t' || ch == '\n'); 286 } 287 288 static int 289 next_token(char *text, char *valuestr) 290 { 291 int i, j; 292 enum token tok; 293 294 i = j = 0; 295 296 if (text[0] == '\0') 297 return END; 298 299 while (text[i] != '\0') { 300 if (isws(text[i])) { 301 if (i == 0) { 302 valuestr[0] = text[i]; 303 valuestr[1] = '\0'; 304 tok = WS; 305 } 306 break; 307 } 308 309 valuestr[j] = text[i]; 310 j++; 311 valuestr[j] = '\0'; 312 i++; 313 tok = TEXT; 314 } 315 316 return tok; 317 } 318 319 static void 320 print_string(WINDOW *win, int *y, int *x, int minx, int maxx, char *str, bool color) 321 { 322 int i, j, len, reallen; 323 324 if(strlen(str) == 0) 325 return; 326 327 len = reallen = strlen(str); 328 if (color) { 329 i=0; 330 while (i < len) { 331 if (check_set_ncurses_attr(win, str+i)) 332 reallen -= 3; 333 i++; 334 } 335 } 336 337 i = 0; 338 while (i < len) { 339 if (*x + reallen > maxx) { 340 *y = (*x != minx ? *y+1 : *y); 341 *x = minx; 342 } 343 j = *x; 344 while (j < maxx && i < len) { 345 if (color && check_set_ncurses_attr(win, str+i)) { 346 i += 3; 347 } else { 348 mvwaddch(win, *y, j, str[i]); 349 i++; 350 reallen--; 351 j++; 352 *x = j; 353 } 354 } 355 } 356 } 357 358 void 359 print_text(struct bsddialog_conf conf, WINDOW *pad, int starty, int minx, int maxx, 360 char *text) 361 { 362 char *valuestr; 363 int x, y; 364 bool loop; 365 enum token tok; 366 367 valuestr = malloc(strlen(text) + 1); 368 369 x = minx; 370 y = starty; 371 loop = true; 372 while (loop) { 373 tok = next_token(text, valuestr); 374 switch (tok) { 375 case END: 376 loop = false; 377 break; 378 case WS: 379 text += strlen(valuestr); 380 print_string(pad, &y, &x, minx, maxx, valuestr, false /*useless*/); 381 break; 382 case TEXT: 383 text += strlen(valuestr); 384 print_string(pad, &y, &x, minx, maxx, valuestr, conf.text.colors); 385 break; 386 } 387 } 388 389 free(valuestr); 390 } 391 392 // new text funcs 393 394 static bool is_ncurses_attr(char *text) 395 { 396 bool isattr; 397 398 if (strnlen(text, 3) < 3) 399 return false; 400 401 if (text[0] != '\\' || text[1] != 'Z') 402 return false; 403 404 if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) 405 return true; 406 407 isattr = text[2] == 'n' || text[2] == 'b' || text[2] == 'B' || 408 text[2] == 'r' || text[2] == 'R' || text[2] == 'u' || 409 text[2] == 'U'; 410 411 return isattr; 412 } 413 414 static void 415 print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color) 416 { 417 int i, j, len, reallen; 418 419 if(strlen(str) == 0) 420 return; 421 422 len = reallen = strlen(str); 423 if (color) { 424 i=0; 425 while (i < len) { 426 if (is_ncurses_attr(str+i)) 427 reallen -= 3; 428 i++; 429 } 430 } 431 432 i = 0; 433 while (i < len) { 434 if (*x + reallen > cols) { 435 *y = (*x != 0 ? *y+1 : *y); 436 if (*y >= *rows) { 437 *rows = *y + 1; 438 wresize(win, *rows, cols); 439 } 440 *x = 0; 441 } 442 j = *x; 443 while (j < cols && i < len) { 444 if (color && check_set_ncurses_attr(win, str+i)) { 445 i += 3; 446 } else { 447 mvwaddch(win, *y, j, str[i]); 448 i++; 449 reallen--; 450 j++; 451 *x = j; 452 } 453 } 454 } 455 } 456 457 static void prepare_text(struct bsddialog_conf conf, char *text, char *buf) 458 { 459 int i, j; 460 461 i = j = 0; 462 while (text[i] != '\0') { 463 switch (text[i]) { 464 case '\\': 465 buf[j] = '\\'; 466 switch (text[i+1]) { 467 case '\\': 468 i++; 469 break; 470 case 'n': 471 if (conf.text.no_nl_expand) { 472 j++; 473 buf[j] = 'n'; 474 } else 475 buf[j] = '\n'; 476 i++; 477 break; 478 case 't': 479 if (conf.text.no_collapse) { 480 j++; 481 buf[j] = 't'; 482 } else 483 buf[j] = '\t'; 484 i++; 485 break; 486 } 487 break; 488 case '\n': 489 buf[j] = conf.text.cr_wrap ? ' ' : '\n'; 490 break; 491 case '\t': 492 buf[j] = conf.text.no_collapse ? '\t' : ' '; 493 break; 494 default: 495 buf[j] = text[i]; 496 } 497 i++; 498 j += (buf[j] == ' ' && conf.text.trim && j > 0 && buf[j-1] == ' ') ? 499 0 : 1; 500 } 501 buf[j] = '\0'; 502 } 503 504 int 505 get_text_properties(struct bsddialog_conf conf, char *text, int *maxword, 506 int *maxline, int *nlines) 507 { 508 char *buf; 509 int i, buflen, wordlen, linelen; 510 511 if ((buf = malloc(strlen(text) + 1)) == NULL) 512 RETURN_ERROR("Cannot building a buffer to find the properties "\ 513 "of the text properties"); 514 515 prepare_text(conf, text, buf); 516 517 buflen = strlen(buf) + 1; 518 *maxword = 0; 519 wordlen = 0; 520 for (i=0; i < buflen; i++) { 521 if (buf[i] == '\t' || buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\0') 522 if (wordlen != 0) { 523 *maxword = MAX(*maxword, wordlen); 524 wordlen = 0; 525 continue; 526 } 527 if (conf.text.colors && is_ncurses_attr(buf + i)) 528 i += 3; 529 else 530 wordlen++; 531 } 532 533 *maxline = linelen = 0; 534 *nlines = 1; 535 for (i=0; i < buflen; i++) { 536 switch (buf[i]) { 537 case '\n': 538 *nlines = *nlines + 1; 539 case '\0': 540 *maxline = MAX(*maxline, linelen); 541 linelen = 0; 542 break; 543 default: 544 if (conf.text.colors && is_ncurses_attr(buf + i)) 545 i += 3; 546 else 547 linelen++; 548 } 549 } 550 if (*nlines == 1 && *maxline == 0) 551 *nlines = 0; 552 553 free(buf); 554 555 return 0; 556 } 557 558 static int 559 print_textpad(struct bsddialog_conf conf, WINDOW *pad, int *rows, int cols, char *text) 560 { 561 char *buf, *string; 562 int i, j, x, y; 563 bool loop; 564 565 if ((buf = malloc(strlen(text) + 1)) == NULL) 566 RETURN_ERROR("Cannot build (analyze) text"); 567 568 prepare_text(conf, text, buf); 569 570 if ((string = malloc(strlen(text) + 1)) == NULL) { 571 free(buf); 572 RETURN_ERROR("Cannot build (analyze) text"); 573 } 574 i = j = x = y = 0; 575 loop = true; 576 while (loop) { 577 string[j] = buf[i]; 578 579 if (string[j] == '\0' || string[j] == '\n' || 580 string[j] == '\t' || string[j] == ' ') { 581 if (j != 0) { 582 string[j] = '\0'; 583 print_str(pad, rows, &y, &x, cols, string, conf.text.colors); 584 } 585 } 586 587 switch (buf[i]) { 588 case '\0': 589 loop = false; 590 break; 591 case '\n': 592 j = -1; 593 x = 0; 594 y++; 595 break; 596 case '\t': 597 for (j=0; j<4 /*tablen*/; j++) { 598 x++; 599 if (x >= cols) { 600 x = 0; 601 y++; 602 } 603 } 604 j = -1; 605 break; 606 case ' ': 607 x++; 608 if (x >= cols) { 609 x = 0; 610 y++; 611 } 612 j = -1; 613 } 614 615 if (y >= *rows) { /* check for whitespaces */ 616 *rows = y + 1; 617 wresize(pad, *rows, cols); 618 } 619 620 j++; 621 i++; 622 } 623 624 free(string); 625 free(buf); 626 627 return 0; 628 } 629 630 /* autosize */ 631 632 /* 633 * max y, that is from 0 to LINES - 1 - t.shadowrows, 634 * could not be max height but avoids problems with checksize 635 */ 636 int widget_max_height(struct bsddialog_conf conf) 637 { 638 int maxheight; 639 640 if ((maxheight = conf.shadow ? LINES - 1 - t.shadowrows : LINES - 1) <= 0) 641 RETURN_ERROR("Terminal too small, LINES - shadow <= 0"); 642 643 if (conf.y > 0) 644 if ((maxheight -= conf.y) <=0) 645 RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0"); 646 647 return maxheight; 648 } 649 650 /* 651 * max x, that is from 0 to COLS - 1 - t.shadowcols, 652 * * could not be max height but avoids problems with checksize 653 */ 654 int widget_max_width(struct bsddialog_conf conf) 655 { 656 int maxwidth; 657 658 if ((maxwidth = conf.shadow ? COLS - 1 - t.shadowcols : COLS - 1) <= 0) 659 RETURN_ERROR("Terminal too small, COLS - shadow <= 0"); 660 if (conf.x > 0) 661 if ((maxwidth -= conf.x) <=0) 662 RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0"); 663 664 return maxwidth; 665 } 666 667 int 668 set_widget_size(struct bsddialog_conf conf, int rows, int cols, int *h, int *w) 669 { 670 int maxheight, maxwidth; 671 672 if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR) 673 return BSDDIALOG_ERROR; 674 675 if (rows == BSDDIALOG_FULLSCREEN) 676 *h = maxheight; 677 else if (rows < BSDDIALOG_FULLSCREEN) 678 RETURN_ERROR("Negative (less than -1) height"); 679 else if (rows > BSDDIALOG_AUTOSIZE) { 680 if ((*h = rows) > maxheight) 681 RETURN_ERROR("Height too big (> terminal height - "\ 682 "shadow"); 683 } 684 /* rows == AUTOSIZE: each widget has to set its size */ 685 686 if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR) 687 return BSDDIALOG_ERROR; 688 689 if (cols == BSDDIALOG_FULLSCREEN) 690 *w = maxwidth; 691 else if (cols < BSDDIALOG_FULLSCREEN) 692 RETURN_ERROR("Negative (less than -1) width"); 693 else if (cols > BSDDIALOG_AUTOSIZE) { 694 if ((*w = cols) > maxwidth) 695 RETURN_ERROR("Width too big (> terminal width - shadow)"); 696 } 697 /* cols == AUTOSIZE: each widget has to set its size */ 698 699 return 0; 700 } 701 702 int 703 set_widget_position(struct bsddialog_conf conf, int *y, int *x, int h, int w) 704 { 705 706 if (conf.y == BSDDIALOG_CENTER) 707 *y = LINES/2 - h/2; 708 else if (conf.y < BSDDIALOG_CENTER) 709 RETURN_ERROR("Negative begin y (less than -1)"); 710 else if (conf.y >= LINES) 711 RETURN_ERROR("Begin Y under the terminal"); 712 else 713 *y = conf.y; 714 715 if ((*y + h + (conf.shadow ? (int) t.shadowrows : 0)) > LINES) 716 RETURN_ERROR("The lower of the box under the terminal "\ 717 "(begin Y + height (+ shadow) > terminal lines)"); 718 719 720 if (conf.x == BSDDIALOG_CENTER) 721 *x = COLS/2 - w/2; 722 else if (conf.x < BSDDIALOG_CENTER) 723 RETURN_ERROR("Negative begin x (less than -1)"); 724 else if (conf.x >= COLS) 725 RETURN_ERROR("Begin X over the right of the terminal"); 726 else 727 *x = conf.x; 728 729 if ((*x + w + (conf.shadow ? (int) t.shadowcols : 0)) > COLS) 730 RETURN_ERROR("The right of the box over the terminal "\ 731 "(begin X + width (+ shadow) > terminal cols)"); 732 733 return 0; 734 } 735 736 /* Widgets builders */ 737 void 738 draw_borders(struct bsddialog_conf conf, WINDOW *win, int rows, int cols, 739 enum elevation elev) 740 { 741 int leftcolor, rightcolor; 742 int ls, rs, ts, bs, tl, tr, bl, br; 743 int ltee, rtee; 744 745 ls = rs = ACS_VLINE; 746 ts = bs = ACS_HLINE; 747 tl = ACS_ULCORNER; 748 tr = ACS_URCORNER; 749 bl = ACS_LLCORNER; 750 br = ACS_LRCORNER; 751 ltee = ACS_LTEE; 752 rtee = ACS_RTEE; 753 754 if (conf.no_lines == false) { 755 if (conf.ascii_lines) { 756 ls = rs = '|'; 757 ts = bs = '-'; 758 tl = tr = bl = br = ltee = rtee = '+'; 759 } 760 leftcolor = elev == RAISED ? t.lineraisecolor : t.linelowercolor; 761 rightcolor = elev == RAISED ? t.linelowercolor : t.lineraisecolor; 762 wattron(win, leftcolor); 763 wborder(win, ls, rs, ts, bs, tl, tr, bl, br); 764 wattroff(win, leftcolor); 765 766 wattron(win, rightcolor); 767 mvwaddch(win, 0, cols-1, tr); 768 mvwvline(win, 1, cols-1, rs, rows-2); 769 mvwaddch(win, rows-1, cols-1, br); 770 mvwhline(win, rows-1, 1, bs, cols-2); 771 wattroff(win, rightcolor); 772 } 773 } 774 775 WINDOW * 776 new_boxed_window(struct bsddialog_conf conf, int y, int x, int rows, int cols, 777 enum elevation elev) 778 { 779 WINDOW *win; 780 781 if ((win = newwin(rows, cols, y, x)) == NULL) { 782 set_error_string("Cannot build boxed window"); 783 return NULL; 784 } 785 786 wbkgd(win, t.widgetcolor); 787 788 draw_borders(conf, win, rows, cols, elev); 789 790 return win; 791 } 792 793 /* 794 * `enum elevation elev` could be useless because it should be always RAISED, 795 * to check at the end. 796 */ 797 static int 798 draw_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow, 799 WINDOW *widget, int h, int w, enum elevation elev, 800 WINDOW *textpad, int *htextpad, char *text, bool buttons) 801 { 802 int ts, ltee, rtee; 803 int colorsurroundtitle; 804 805 ts = conf.ascii_lines ? '-' : ACS_HLINE; 806 ltee = conf.ascii_lines ? '+' : ACS_LTEE; 807 rtee = conf.ascii_lines ? '+' : ACS_RTEE; 808 colorsurroundtitle = elev == RAISED ? t.lineraisecolor : t.linelowercolor; 809 810 if (shadow != NULL) 811 wnoutrefresh(shadow); 812 813 // move / resize now or the caller? 814 draw_borders(conf, widget, h, w, elev); 815 816 if (conf.title != NULL) { 817 if (t.surroundtitle && conf.no_lines == false) { 818 wattron(widget, colorsurroundtitle); 819 mvwaddch(widget, 0, w/2 - strlen(conf.title)/2 - 1, rtee); 820 wattroff(widget, colorsurroundtitle); 821 } 822 wattron(widget, t.titlecolor); 823 mvwaddstr(widget, 0, w/2 - strlen(conf.title)/2, conf.title); 824 wattroff(widget, t.titlecolor); 825 if (t.surroundtitle && conf.no_lines == false) { 826 wattron(widget, colorsurroundtitle); 827 waddch(widget, ltee); 828 wattroff(widget, colorsurroundtitle); 829 } 830 } 831 832 if (conf.hline != NULL) { 833 wattron(widget, t.bottomtitlecolor); 834 wmove(widget, h - 1, w/2 - strlen(conf.hline)/2 - 1); 835 waddch(widget, '['); 836 waddstr(widget, conf.hline); 837 waddch(widget, ']'); 838 wattroff(widget, t.bottomtitlecolor); 839 } 840 841 if (textpad == NULL && text != NULL) /* no pad, text null for textbox */ 842 print_text(conf, widget, 1, 2, w-3, text); 843 844 if (buttons && conf.no_lines == false) { 845 wattron(widget, t.lineraisecolor); 846 mvwaddch(widget, h-3, 0, ltee); 847 mvwhline(widget, h-3, 1, ts, w-2); 848 wattroff(widget, t.lineraisecolor); 849 850 wattron(widget, t.linelowercolor); 851 mvwaddch(widget, h-3, w-1, rtee); 852 wattroff(widget, t.linelowercolor); 853 } 854 855 wnoutrefresh(widget); 856 857 if (textpad == NULL) 858 return 0; /* widget_init() ends */ 859 860 if (text != NULL) /* programbox etc */ 861 if (print_textpad(conf, textpad, htextpad, 862 w - HBORDERS - t.texthmargin * 2, text) !=0) 863 return BSDDIALOG_ERROR; 864 865 return 0; 866 } 867 868 /* 869 * `enum elevation elev` could be useless because it should be always RAISED, 870 * to check at the end. 871 */ 872 int 873 update_widget_withtextpad(struct bsddialog_conf conf, WINDOW *shadow, 874 WINDOW *widget, int h, int w, enum elevation elev, 875 WINDOW *textpad, int *htextpad, char *text, bool buttons) 876 { 877 int error; 878 879 /* nothing for now */ 880 881 error = draw_widget_withtextpad(conf, shadow, widget, h, w, 882 elev, textpad, htextpad, text, buttons); 883 884 return error; 885 } 886 887 /* 888 * `enum elevation elev` could be useless because it should be always RAISED, 889 * to check at the end. 890 */ 891 int 892 new_widget_withtextpad(struct bsddialog_conf conf, WINDOW **shadow, 893 WINDOW **widget, int y, int x, int h, int w, enum elevation elev, 894 WINDOW **textpad, int *htextpad, char *text, bool buttons) 895 { 896 int error; 897 898 if (conf.shadow) { 899 *shadow = newwin(h, w, y + t.shadowrows, x + t.shadowcols); 900 if (*shadow == NULL) 901 RETURN_ERROR("Cannot build shadow"); 902 wbkgd(*shadow, t.shadowcolor); 903 } 904 905 if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == NULL) { 906 if (conf.shadow) 907 delwin(*shadow); 908 return BSDDIALOG_ERROR; 909 } 910 911 if (textpad == NULL) { /* widget_init() */ 912 error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, 913 elev, NULL, NULL, text, buttons); 914 return error; 915 } 916 917 if (text != NULL) { /* programbox etc */ 918 *htextpad = 1; 919 *textpad = newpad(*htextpad, w - HBORDERS - t.texthmargin * 2); 920 if (*textpad == NULL) { 921 delwin(*textpad); 922 if (conf.shadow) 923 delwin(*shadow); 924 RETURN_ERROR("Cannot build the pad window for text"); 925 } 926 wbkgd(*textpad, t.widgetcolor); 927 } 928 929 error = draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev, 930 *textpad, htextpad, text, buttons); 931 932 return error; 933 } 934 935 int 936 new_widget(struct bsddialog_conf conf, WINDOW **widget, int *y, int *x, 937 char *text, int *h, int *w, WINDOW **shadow, bool buttons) 938 { 939 940 // to delete (each widget has to check its x,y,h,w) 941 if (*h <= 0) 942 ; /* todo */ 943 944 if (*w <= 0) 945 ; /* todo */ 946 947 *y = (conf.y < 0) ? (LINES/2 - *h/2) : conf.y; 948 *x = (conf.x < 0) ? (COLS/2 - *w/2) : conf.x; 949 950 if (new_widget_withtextpad(conf, shadow, widget, *y, *x, *h, *w, RAISED, 951 NULL, NULL, text, buttons) != 0) 952 return BSDDIALOG_ERROR; 953 954 if (conf.shadow) 955 wrefresh(*shadow); 956 957 wrefresh(*widget); 958 959 return 0; 960 } 961 962 void 963 end_widget_withtextpad(struct bsddialog_conf conf, WINDOW *window, int h, int w, 964 WINDOW *textpad, WINDOW *shadow) 965 { 966 int y, x; 967 968 getbegyx(window, y, x); /* for clear, add y & x to args? */ 969 970 if (conf.sleep > 0) 971 sleep(conf.sleep); 972 973 if (textpad != NULL) 974 delwin(textpad); 975 976 delwin(window); 977 978 if (conf.shadow) 979 delwin(shadow); 980 981 if (conf.clear) 982 hide_widget(y, x, h, w, shadow != NULL); 983 984 if (conf.get_height != NULL) 985 *conf.get_height = h; 986 if (conf.get_width != NULL) 987 *conf.get_width = w; 988 } 989 990 void 991 end_widget(struct bsddialog_conf conf, WINDOW *window, int h, int w, 992 WINDOW *shadow) 993 { 994 995 end_widget_withtextpad(conf, window, h, w, NULL, shadow); 996 } 997