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 <ctype.h> 31 #ifdef PORTNCURSES 32 #include <ncurses/ncurses.h> 33 #else 34 #include <ncurses.h> 35 #endif 36 #include <stdlib.h> 37 #include <string.h> 38 #include <time.h> 39 40 #include "bsddialog.h" 41 #include "bsddialog_progressview.h" 42 #include "lib_util.h" 43 #include "bsddialog_theme.h" 44 45 #define BARMARGIN 3 46 #define MINBARWIDTH 10 47 #define MINWIDTH (VBORDERS + MINBARWIDTH + BARMARGIN * 2) 48 #define MINHEIGHT 7 /* without text */ 49 50 /* "Bar": gauge - mixedgauge - rangebox - pause - progressview */ 51 52 bool bsddialog_interruptprogview; 53 bool bsddialog_abortprogview; 54 int bsddialog_total_progview; 55 56 extern struct bsddialog_theme t; 57 58 static void 59 draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel, 60 int label) 61 { 62 char labelstr[128]; 63 int i, blue_x, color; 64 65 blue_x = (int)((perc*(size))/100); 66 67 wmove(win, y, x); 68 for (i = 0; i < size; i++) { 69 color = (i <= blue_x) ? t.bar.f_color : t.bar.color; 70 wattron(win, color); 71 waddch(win, ' '); 72 wattroff(win, color); 73 } 74 75 if (withlabel) 76 sprintf(labelstr, "%d", label); 77 else 78 sprintf(labelstr, "%3d%%", perc); 79 wmove(win, y, x + size/2 - 2); 80 for (i=0; i < (int) strlen(labelstr); i++) { 81 color = (blue_x + 1 <= size/2 - (int)strlen(labelstr)/2 + i ) ? 82 t.bar.color : t.bar.f_color; 83 wattron(win, color); 84 waddch(win, labelstr[i]); 85 wattroff(win, color); 86 } 87 } 88 89 static int 90 bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w, 91 char *text, struct buttons *bs) 92 { 93 int maxword, maxline, nlines, buttonswidth; 94 95 if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0) 96 return BSDDIALOG_ERROR; 97 98 buttonswidth = 0; 99 if (bs != NULL) { /* gauge has not buttons */ 100 buttonswidth= bs->nbuttons * bs->sizebutton; 101 if (bs->nbuttons > 0) 102 buttonswidth += (bs->nbuttons-1) * t.button.space; 103 } 104 105 if (cols == BSDDIALOG_AUTOSIZE) { 106 *w = VBORDERS; 107 /* buttons size */ 108 *w += buttonswidth; 109 /* bar size */ 110 *w = MAX(*w, MINWIDTH); 111 /* text size*/ 112 *w = MAX((int)(maxline + VBORDERS + t.text.hmargin * 2), *w); 113 /* conf.auto_minwidth */ 114 *w = MAX(*w, (int)conf->auto_minwidth); 115 /* avoid terminal overflow */ 116 *w = MIN(*w, widget_max_width(conf)); 117 } 118 119 if (rows == BSDDIALOG_AUTOSIZE) { 120 *h = MINHEIGHT; 121 if (maxword > 0) 122 *h += 1; 123 /* conf.auto_minheight */ 124 *h = MAX(*h, (int)conf->auto_minheight); 125 /* avoid terminal overflow */ 126 *h = MIN(*h, widget_max_height(conf)); 127 } 128 129 return (0); 130 } 131 132 static int 133 bar_checksize(char *text, int rows, int cols, struct buttons *bs) 134 { 135 int minheight, minwidth; 136 137 minwidth = 0; 138 if (bs != NULL) { /* gauge has not buttons */ 139 minwidth = bs->nbuttons * bs->sizebutton; 140 if (bs->nbuttons > 0) 141 minwidth += (bs->nbuttons-1) * t.button.space; 142 } 143 minwidth = MAX(minwidth + VBORDERS, MINBARWIDTH); 144 145 if (cols< minwidth) 146 RETURN_ERROR("Few cols for this widget"); 147 148 minheight = MINHEIGHT + ((text != NULL && strlen(text) > 0) ? 1 : 0); 149 if (rows < minheight) 150 RETURN_ERROR("Few rows for this mixedgauge"); 151 152 return 0; 153 } 154 155 int 156 bsddialog_gauge(struct bsddialog_conf *conf, char* text, int rows, int cols, 157 unsigned int perc) 158 { 159 WINDOW *widget, *textpad, *bar, *shadow; 160 char input[2048], ntext[2048], *pntext; 161 int y, x, h, w, htextpad; 162 bool mainloop; 163 164 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 165 return BSDDIALOG_ERROR; 166 if (bar_autosize(conf, rows, cols, &h, &w, text, NULL) != 0) 167 return BSDDIALOG_ERROR; 168 if (bar_checksize(text, h, w, NULL) != 0) 169 return BSDDIALOG_ERROR; 170 if (set_widget_position(conf, &y, &x, h, w) != 0) 171 return BSDDIALOG_ERROR; 172 173 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED, 174 &textpad, &htextpad, text, false) != 0) 175 return BSDDIALOG_ERROR; 176 177 bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED); 178 179 mainloop = true; 180 while (mainloop) { 181 wrefresh(widget); 182 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-4, 183 x+w-1-t.text.hmargin); 184 draw_perc_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/); 185 wrefresh(bar); 186 187 while (true) { 188 scanf("%s", input); 189 if (strcmp(input,"EOF") == 0) { 190 mainloop = false; 191 break; 192 } 193 if (strcmp(input,"XXX") == 0) 194 break; 195 } 196 scanf("%d", &perc); 197 perc = perc < 0 ? 0 : perc; 198 perc = perc > 100 ? 100 : perc; 199 htextpad = 1; 200 wclear(textpad); 201 pntext = &ntext[0]; 202 ntext[0] = '\0'; 203 while (true) { 204 scanf("%s", input); 205 if (strcmp(input,"EOF") == 0) { 206 mainloop = false; 207 break; 208 } 209 if (strcmp(input,"XXX") == 0) 210 break; 211 pntext[0] = ' '; 212 pntext++; 213 strcpy(pntext, input); 214 pntext += strlen(input); 215 } 216 print_textpad(conf, textpad, &htextpad, w-2-t.text.hmargin*2, 217 ntext); 218 } 219 220 delwin(bar); 221 end_widget_withtextpad(conf, widget, h, w, textpad, shadow); 222 223 return BSDDIALOG_OK; 224 } 225 226 227 /* Mixedgauge */ 228 static int 229 mixedgauge(struct bsddialog_conf *conf, char* text, int rows, int cols, 230 unsigned int mainperc, unsigned int nminibars, char **minilabels, 231 int *minipercs, bool color) 232 { 233 WINDOW *widget, *textpad, *bar, *shadow; 234 int i, output, miniperc, y, x, h, w, max_minbarlen; 235 int maxword, maxline, nlines, htextpad, ypad; 236 int colorperc, red, green; 237 char states[12][14] = { 238 " Succeeded ", /* 0 */ 239 " Failed ", /* 1 */ 240 " Passed ", /* 2 */ 241 " Completed ", /* 3 */ 242 " Checked ", /* 4 */ 243 " Done ", /* 5 */ 244 " Skipped ", /* 6 */ 245 " In Progress ", /* 7 */ 246 "(blank) ", /* 8 */ 247 " N/A ", /* 9 */ 248 " Pending ", /* 10 */ 249 " UNKNOWN ", /* 10+ */ 250 }; 251 252 red = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_RED, BSDDIALOG_BOLD); 253 green = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_GREEN,BSDDIALOG_BOLD); 254 255 max_minbarlen = 0; 256 for (i=0; i < (int)nminibars; i++) 257 max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i])); 258 max_minbarlen += 3 + 16 /* seps + [...] or mainbar */; 259 260 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 261 return BSDDIALOG_ERROR; 262 263 /* mixedgauge autosize */ 264 if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0) 265 return BSDDIALOG_ERROR; 266 267 if (cols == BSDDIALOG_AUTOSIZE) { 268 w = max_minbarlen + HBORDERS; 269 w = MAX(w, maxline + 4); 270 w = MAX(w, (int)conf->auto_minwidth); 271 w = MIN(w, widget_max_width(conf) - 1); 272 } 273 if (rows == BSDDIALOG_AUTOSIZE) { 274 h = 5; /* borders + mainbar */ 275 h += nminibars; 276 h += (strlen(text) > 0 ? 3 : 0); 277 h = MAX(h, (int)conf->auto_minheight); 278 h = MIN(h, widget_max_height(conf) -1); 279 } 280 281 /* mixedgauge checksize */ 282 if (w < max_minbarlen + 2) 283 RETURN_ERROR("Few cols for this mixedgauge"); 284 if (h < 5 + (int)nminibars + (strlen(text) > 0 ? 1 : 0)) 285 RETURN_ERROR("Few rows for this mixedgauge"); 286 287 if (set_widget_position(conf, &y, &x, h, w) != 0) 288 return BSDDIALOG_ERROR; 289 290 output = new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, 291 RAISED, &textpad, &htextpad, text, false); 292 if (output == BSDDIALOG_ERROR) 293 return output; 294 295 /* mini bars */ 296 for (i=0; i < (int)nminibars; i++) { 297 miniperc = minipercs[i]; 298 if (miniperc == 8) 299 continue; 300 /* label */ 301 if (color && (miniperc == 7 || miniperc < 0)) 302 wattron(widget, A_BOLD); 303 mvwaddstr(widget, i+1, 2, minilabels[i]); 304 wattroff(widget, A_BOLD); 305 /* perc */ 306 if (miniperc > 10) 307 mvwaddstr(widget, i+1, w-2-15, states[11]); 308 else if (miniperc >= 0 && miniperc <= 10) { 309 mvwaddstr(widget, i+1, w-2-15, "[ ]"); 310 if (color && miniperc == 1) /* Failed */ 311 colorperc = red; 312 if (color && miniperc == 5) /* Done */ 313 colorperc = green; 314 if (color && (miniperc == 1 || miniperc == 5)) 315 wattron(widget, colorperc); 316 mvwaddstr(widget, i+1, 1+w-2-15, states[miniperc]); 317 if (color && (miniperc == 1 || miniperc == 5)) 318 wattroff(widget, colorperc); 319 } 320 else { /* miniperc < 0 */ 321 miniperc = abs(miniperc); 322 mvwaddstr(widget, i+1, w-2-15, "[ ]"); 323 draw_perc_bar(widget, i+1, 1+w-2-15, 13, miniperc, 324 false, -1 /*unused*/); 325 } 326 } 327 328 wrefresh(widget); 329 ypad = y + h - 5 - htextpad; 330 ypad = ypad < y+(int)nminibars ? y+nminibars : ypad; 331 prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2); 332 333 /* main bar */ 334 bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED); 335 336 draw_perc_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/); 337 338 wattron(bar, t.bar.color); 339 mvwaddstr(bar, 0, 2, "Overall Progress"); 340 wattroff(bar, t.bar.color); 341 342 wrefresh(bar); 343 344 /* getch(); port ncurses shows nothing */ 345 346 delwin(bar); 347 end_widget_withtextpad(conf, widget, h, w, textpad, shadow); 348 349 return BSDDIALOG_OK; 350 } 351 352 int 353 bsddialog_mixedgauge(struct bsddialog_conf *conf, char* text, int rows, 354 int cols, unsigned int mainperc, unsigned int nminibars, char **minilabels, 355 int *minipercs) 356 { 357 int output; 358 359 output = mixedgauge(conf, text, rows, cols, mainperc, nminibars, 360 minilabels, minipercs, false); 361 362 return (output); 363 } 364 365 int 366 bsddialog_progressview (struct bsddialog_conf *conf, char * text, int rows, 367 int cols, struct bsddialog_progviewconf *pvconf, unsigned int nminibar, 368 struct bsddialog_fileminibar *minibar) 369 { 370 int perc, output; 371 int *minipercs; 372 unsigned int i; 373 char **minilabels; 374 unsigned int mainperc, totaltodo; 375 time_t tstart, told, tnew, refresh; 376 bool update; 377 float readforsec; 378 379 if ((minilabels = calloc(nminibar, sizeof(char*))) == NULL) 380 RETURN_ERROR("Cannot allocate memory for minilabels\n"); 381 if ((minipercs = calloc(nminibar, sizeof(int))) == NULL) 382 RETURN_ERROR("Cannot allocate memory for minipercs\n"); 383 384 totaltodo = 0; 385 for(i=0; i<nminibar; i++) { 386 totaltodo += minibar[i].size; 387 minilabels[i] = minibar[i].label; 388 minipercs[i] = 10; /*Pending*/ 389 } 390 391 refresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1; 392 output = BSDDIALOG_OK; 393 i = 0; 394 update = true; 395 time(&told); 396 tstart = told; 397 while (!(bsddialog_interruptprogview || bsddialog_abortprogview)) { 398 if (bsddialog_total_progview == 0 || totaltodo == 0) 399 mainperc = 0; 400 else 401 mainperc = (bsddialog_total_progview * 100) / totaltodo; 402 403 time(&tnew); 404 if (update || tnew > told + refresh) { 405 output = mixedgauge(conf, text, rows, cols, mainperc, 406 nminibar, minilabels, minipercs, true); 407 if (output == BSDDIALOG_ERROR) 408 return BSDDIALOG_ERROR; 409 410 move(LINES-1, 2); 411 clrtoeol(); 412 readforsec = ((tnew - tstart) == 0) ? 413 0 : bsddialog_total_progview / (float)(tnew - tstart); 414 printw(pvconf->fmtbottomstr, bsddialog_total_progview, 415 readforsec); 416 refresh(); 417 418 time(&told); 419 update = false; 420 } 421 422 if (i >= nminibar) 423 break; 424 if (minibar[i].status == 1) /* Failed*/ 425 break; 426 427 perc = pvconf->callback(&minibar[i]); 428 429 if (minibar[i].status == 5) {/* ||prec >= 100) Done */ 430 minipercs[i] = 5; 431 update = true; 432 i++; 433 } else if (minibar[i].status == 1 || perc < 0) { /* Failed */ 434 minipercs[i] = 1; 435 update = true; 436 } else if (perc == 0) 437 minipercs[i] = 7; /* In progress */ 438 else /* perc > 0 */ 439 minipercs[i] = -(perc); 440 } 441 442 free(minilabels); 443 free(minipercs); 444 return (output); 445 } 446 447 int 448 bsddialog_rangebox(struct bsddialog_conf *conf, char* text, int rows, int cols, 449 int min, int max, int *value) 450 { 451 WINDOW *widget, *textpad, *bar, *shadow; 452 int i, y, x, h, w, htextpad; 453 bool loop, buttupdate, barupdate; 454 int input, currvalue, output, sizebar, bigchange, positions; 455 float perc; 456 struct buttons bs; 457 458 if (value == NULL) 459 RETURN_ERROR("*value cannot be NULL"); 460 461 if (min >= max) 462 RETURN_ERROR("min >= max"); 463 464 currvalue = *value; 465 positions = max - min + 1; 466 467 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label), 468 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label)); 469 470 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 471 return BSDDIALOG_ERROR; 472 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 473 return BSDDIALOG_ERROR; 474 if (bar_checksize(text, h, w, &bs) != 0) 475 return BSDDIALOG_ERROR; 476 if (set_widget_position(conf, &y, &x, h, w) != 0) 477 return BSDDIALOG_ERROR; 478 479 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED, 480 &textpad, &htextpad, text, true) != 0) 481 return BSDDIALOG_ERROR; 482 483 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7, 484 x+w-1-t.text.hmargin); 485 486 sizebar = w - HBORDERS - 2 - BARMARGIN * 2; 487 bigchange = MAX(1, sizebar/10); 488 489 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3, 490 sizebar + 2, RAISED); 491 492 loop = buttupdate = barupdate = true; 493 while(loop) { 494 if (buttupdate) { 495 draw_buttons(widget, h-2, w, bs, true); 496 wrefresh(widget); 497 buttupdate = false; 498 } 499 if (barupdate) { 500 perc = ((float)(currvalue - min)*100) / (positions-1); 501 draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue); 502 barupdate = false; 503 wrefresh(bar); 504 } 505 506 input = getch(); 507 switch(input) { 508 case KEY_ENTER: 509 case 10: /* Enter */ 510 output = bs.value[bs.curr]; 511 *value = currvalue; 512 loop = false; 513 break; 514 case 27: /* Esc */ 515 output = BSDDIALOG_ESC; 516 loop = false; 517 break; 518 case '\t': /* TAB */ 519 bs.curr = (bs.curr + 1) % bs.nbuttons; 520 buttupdate = true; 521 break; 522 case KEY_LEFT: 523 if (bs.curr > 0) { 524 bs.curr--; 525 buttupdate = true; 526 } 527 break; 528 case KEY_RIGHT: 529 if (bs.curr < (int) bs.nbuttons - 1) { 530 bs.curr++; 531 buttupdate = true; 532 } 533 break; 534 case KEY_HOME: 535 currvalue = max; 536 barupdate = true; 537 break; 538 case KEY_END: 539 currvalue = min; 540 barupdate = true; 541 break; 542 case KEY_NPAGE: 543 currvalue -= bigchange; 544 if (currvalue < min) 545 currvalue = min; 546 barupdate = true; 547 break; 548 case KEY_PPAGE: 549 currvalue += bigchange; 550 if (currvalue > max) 551 currvalue = max; 552 barupdate = true; 553 break; 554 case KEY_UP: 555 if (currvalue < max) { 556 currvalue++; 557 barupdate = true; 558 } 559 break; 560 case KEY_DOWN: 561 if (currvalue > min) { 562 currvalue--; 563 barupdate = true; 564 } 565 break; 566 case KEY_F(1): 567 if (conf->f1_file == NULL && conf->f1_message == NULL) 568 break; 569 if (f1help(conf) != 0) 570 return BSDDIALOG_ERROR; 571 /* No break! the terminal size can change */ 572 case KEY_RESIZE: 573 hide_widget(y, x, h, w,conf->shadow); 574 575 /* 576 * Unnecessary, but, when the columns decrease the 577 * following "refresh" seem not work 578 */ 579 refresh(); 580 581 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 582 return BSDDIALOG_ERROR; 583 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 584 return BSDDIALOG_ERROR; 585 if (bar_checksize(text, h, w, &bs) != 0) 586 return BSDDIALOG_ERROR; 587 if (set_widget_position(conf, &y, &x, h, w) != 0) 588 return BSDDIALOG_ERROR; 589 590 wclear(shadow); 591 mvwin(shadow, y + t.shadow.h, x + t.shadow.w); 592 wresize(shadow, h, w); 593 594 wclear(widget); 595 mvwin(widget, y, x); 596 wresize(widget, h, w); 597 598 htextpad = 1; 599 wclear(textpad); 600 wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2); 601 602 sizebar = w - HBORDERS - 2 - BARMARGIN * 2; 603 bigchange = MAX(1, sizebar/10); 604 wclear(bar); 605 mvwin(bar, y + h - 6, x + 1 + BARMARGIN); 606 wresize(bar, 3, sizebar + 2); 607 608 if(update_widget_withtextpad(conf, shadow, widget, h, w, 609 RAISED, textpad, &htextpad, text, true) != 0) 610 return BSDDIALOG_ERROR; 611 612 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7, 613 x+w-1-t.text.hmargin); 614 615 draw_borders(conf, bar, 3, sizebar + 2, RAISED); 616 617 barupdate = true; 618 buttupdate = true; 619 break; 620 default: 621 for (i = 0; i < (int) bs.nbuttons; i++) 622 if (tolower(input) == tolower((bs.label[i])[0])) { 623 output = bs.value[i]; 624 loop = false; 625 } 626 } 627 } 628 629 delwin(bar); 630 end_widget_withtextpad(conf, widget, h, w, textpad, shadow); 631 632 return output; 633 } 634 635 int 636 bsddialog_pause(struct bsddialog_conf *conf, char* text, int rows, int cols, 637 unsigned int sec) 638 { 639 WINDOW *widget, *textpad, *bar, *shadow; 640 int i, output, y, x, h, w, htextpad; 641 bool loop, buttupdate, barupdate; 642 int input, tout, sizebar; 643 float perc; 644 struct buttons bs; 645 646 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label), 647 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label)); 648 649 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 650 return BSDDIALOG_ERROR; 651 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 652 return BSDDIALOG_ERROR; 653 if (bar_checksize(text, h, w, &bs) != 0) 654 return BSDDIALOG_ERROR; 655 if (set_widget_position(conf, &y, &x, h, w) != 0) 656 return BSDDIALOG_ERROR; 657 658 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED, 659 &textpad, &htextpad, text, true) != 0) 660 return BSDDIALOG_ERROR; 661 662 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7, 663 x+w-1-t.text.hmargin); 664 665 sizebar = w - HBORDERS - 2 - BARMARGIN * 2; 666 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3, 667 sizebar + 2, RAISED); 668 669 tout = sec; 670 nodelay(stdscr, TRUE); 671 timeout(1000); 672 loop = buttupdate = barupdate = true; 673 while(loop) { 674 if (barupdate) { 675 perc = (float)tout * 100 / sec; 676 draw_perc_bar(bar, 1, 1, sizebar, perc, true, tout); 677 barupdate = false; 678 wrefresh(bar); 679 } 680 681 if (buttupdate) { 682 draw_buttons(widget, h-2, w, bs, true); 683 wrefresh(widget); 684 buttupdate = false; 685 } 686 687 input = getch(); 688 if(input < 0) { /* timeout */ 689 tout--; 690 if (tout < 0) { 691 output = BSDDIALOG_TIMEOUT; 692 break; 693 } 694 else { 695 barupdate = true; 696 continue; 697 } 698 } 699 switch(input) { 700 case KEY_ENTER: 701 case 10: /* Enter */ 702 output = bs.value[bs.curr]; 703 loop = false; 704 break; 705 case 27: /* Esc */ 706 output = BSDDIALOG_ESC; 707 loop = false; 708 break; 709 case '\t': /* TAB */ 710 bs.curr = (bs.curr + 1) % bs.nbuttons; 711 buttupdate = true; 712 break; 713 case KEY_LEFT: 714 if (bs.curr > 0) { 715 bs.curr--; 716 buttupdate = true; 717 } 718 break; 719 case KEY_RIGHT: 720 if (bs.curr < (int) bs.nbuttons - 1) { 721 bs.curr++; 722 buttupdate = true; 723 } 724 break; 725 case KEY_F(1): 726 if (conf->f1_file == NULL && conf->f1_message == NULL) 727 break; 728 if (f1help(conf) != 0) 729 return BSDDIALOG_ERROR; 730 /* No break! the terminal size can change */ 731 case KEY_RESIZE: 732 hide_widget(y, x, h, w,conf->shadow); 733 734 /* 735 * Unnecessary, but, when the columns decrease the 736 * following "refresh" seem not work 737 */ 738 refresh(); 739 740 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 741 return BSDDIALOG_ERROR; 742 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 743 return BSDDIALOG_ERROR; 744 if (bar_checksize(text, h, w, &bs) != 0) 745 return BSDDIALOG_ERROR; 746 if (set_widget_position(conf, &y, &x, h, w) != 0) 747 return BSDDIALOG_ERROR; 748 749 wclear(shadow); 750 mvwin(shadow, y + t.shadow.h, x + t.shadow.w); 751 wresize(shadow, h, w); 752 753 wclear(widget); 754 mvwin(widget, y, x); 755 wresize(widget, h, w); 756 757 htextpad = 1; 758 wclear(textpad); 759 wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2); 760 761 sizebar = w - HBORDERS - 2 - BARMARGIN * 2; 762 wclear(bar); 763 mvwin(bar, y + h - 6, x + 1 + BARMARGIN); 764 wresize(bar, 3, sizebar + 2); 765 766 if(update_widget_withtextpad(conf, shadow, widget, h, w, 767 RAISED, textpad, &htextpad, text, true) != 0) 768 return BSDDIALOG_ERROR; 769 770 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7, 771 x+w-1-t.text.hmargin); 772 773 draw_borders(conf, bar, 3, sizebar + 2, RAISED); 774 775 barupdate = true; 776 buttupdate = true; 777 break; 778 default: 779 for (i = 0; i < (int) bs.nbuttons; i++) 780 if (tolower(input) == tolower((bs.label[i])[0])) { 781 output = bs.value[i]; 782 loop = false; 783 } 784 } 785 } 786 787 nodelay(stdscr, FALSE); 788 789 delwin(bar); 790 end_widget_withtextpad(conf, widget, h, w, textpad, shadow); 791 792 return output; 793 } 794