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