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); 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_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 mainloop = (fd < 0) ? false : true; 155 156 if (mainloop) { 157 fd2 = dup(fd); 158 input = fdopen(fd2, "r"); 159 if (input == NULL) 160 RETURN_ERROR("Cannot build FILE* from fd"); 161 } else 162 input = NULL; 163 164 while (mainloop) { 165 wrefresh(widget); 166 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-4, 167 x+w-1-TEXTHMARGIN); 168 draw_borders(conf, bar, 3, w-6, RAISED); 169 draw_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/); 170 wrefresh(bar); 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); 197 pntext[0] = ' '; 198 pntext++; 199 } 200 if (update_dialog(conf, shadow, widget, y, x, h, w, textpad, 201 ntext, NULL, false) != 0) 202 return (BSDDIALOG_ERROR); 203 } 204 205 if (input != NULL) 206 fclose(input); 207 delwin(bar); 208 end_dialog(conf, shadow, widget, textpad); 209 210 return (BSDDIALOG_OK); 211 } 212 213 /* Mixedgauge */ 214 static int 215 do_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, int cols, 216 unsigned int mainperc, unsigned int nminibars, const char **minilabels, 217 int *minipercs, bool color) 218 { 219 int i, output, miniperc, y, x, h, w, ypad, max_minbarlen; 220 int htextpad, htext, wtext; 221 int colorperc, red, green; 222 WINDOW *widget, *textpad, *bar, *shadow; 223 char states[12][14] = { 224 " Succeeded ", /* -1 */ 225 " Failed ", /* -2 */ 226 " Passed ", /* -3 */ 227 " Completed ", /* -4 */ 228 " Checked ", /* -5 */ 229 " Done ", /* -6 */ 230 " Skipped ", /* -7 */ 231 " In Progress ", /* -8 */ 232 "(blank) ", /* -9 */ 233 " N/A ", /* -10 */ 234 " Pending ", /* -11 */ 235 " UNKNOWN ", /* < -11, no API */ 236 }; 237 238 red = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_RED, BSDDIALOG_BOLD); 239 green = bsddialog_color(BSDDIALOG_WHITE,BSDDIALOG_GREEN,BSDDIALOG_BOLD); 240 241 max_minbarlen = 0; 242 for (i = 0; i < (int)nminibars; i++) 243 max_minbarlen = MAX(max_minbarlen, (int)strlen(minilabels[i])); 244 max_minbarlen += 3 + 16; /* seps + [...] */ 245 max_minbarlen = MAX(max_minbarlen, MINMGBARWIDTH); /* mainbar */ 246 247 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 248 return (BSDDIALOG_ERROR); 249 250 /* mixedgauge autosize */ 251 if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) { 252 if (text_size(conf, rows, cols, text, NULL, nminibars + 3, 253 max_minbarlen, &htext, &wtext) != 0) 254 return (BSDDIALOG_ERROR); 255 } 256 if (cols == BSDDIALOG_AUTOSIZE) 257 w = widget_min_width(conf, wtext, max_minbarlen, NULL); 258 if (rows == BSDDIALOG_AUTOSIZE) 259 h = widget_min_height(conf, htext, nminibars + 3, false); 260 261 /* mixedgauge checksize */ 262 if (w < max_minbarlen + 2) 263 RETURN_ERROR("Few cols for this mixedgauge"); 264 if (h < 5 + (int)nminibars) 265 RETURN_ERROR("Few rows for this mixedgauge"); 266 267 if (set_widget_position(conf, &y, &x, h, w) != 0) 268 return (BSDDIALOG_ERROR); 269 270 output = new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, 271 NULL, false); 272 if (output == BSDDIALOG_ERROR) 273 return (output); 274 275 /* mini bars */ 276 for (i = 0; i < (int)nminibars; i++) { 277 miniperc = minipercs[i]; 278 if (miniperc == BSDDIALOG_MG_BLANK) 279 continue; 280 /* label */ 281 if (color && (miniperc >= 0)) 282 wattron(widget, A_BOLD); 283 mvwaddstr(widget, i+1, 2, minilabels[i]); 284 wattroff(widget, A_BOLD); 285 /* perc */ 286 if (miniperc < -11) 287 mvwaddstr(widget, i+1, w-2-15, states[11]); 288 else if (miniperc < 0) { 289 mvwaddstr(widget, i+1, w-2-15, "[ ]"); 290 colorperc = -1; 291 if (color && miniperc == BSDDIALOG_MG_FAILED) 292 colorperc = red; 293 if (color && miniperc == BSDDIALOG_MG_DONE) 294 colorperc = green; 295 if (colorperc != -1) 296 wattron(widget, colorperc); 297 miniperc = abs(miniperc + 1); 298 mvwaddstr(widget, i+1, 1+w-2-15, states[miniperc]); 299 if (colorperc != -1) 300 wattroff(widget, colorperc); 301 } 302 else { /* miniperc >= 0 */ 303 if (miniperc > 100) 304 miniperc = 100; 305 mvwaddstr(widget, i+1, w-2-15, "[ ]"); 306 draw_bar(widget, i+1, 1+w-2-15, 13, miniperc, false, 307 -1 /*unused*/); 308 } 309 } 310 311 wrefresh(widget); 312 getmaxyx(textpad, htextpad, i /* unused */); 313 ypad = y + h - 4 - htextpad; 314 ypad = ypad < y+(int)nminibars ? y+(int)nminibars : ypad; 315 prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2); 316 317 /* main bar */ 318 bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED); 319 320 draw_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/); 321 322 wattron(bar, t.bar.color); 323 mvwaddstr(bar, 0, 2, "Overall Progress"); 324 wattroff(bar, t.bar.color); 325 326 wrefresh(bar); 327 328 /* getch(); port ncurses shows nothing */ 329 330 delwin(bar); 331 end_dialog(conf, shadow, widget, textpad); 332 333 return (BSDDIALOG_OK); 334 } 335 336 int 337 bsddialog_mixedgauge(struct bsddialog_conf *conf, const char *text, int rows, 338 int cols, unsigned int mainperc, unsigned int nminibars, 339 const char **minilabels, int *minipercs) 340 { 341 int output; 342 343 output = do_mixedgauge(conf, text, rows, cols, mainperc, nminibars, 344 minilabels, minipercs, false); 345 346 return (output); 347 } 348 349 int 350 bsddialog_progressview (struct bsddialog_conf *conf, const char *text, int rows, 351 int cols, struct bsddialog_progviewconf *pvconf, unsigned int nminibar, 352 struct bsddialog_fileminibar *minibar) 353 { 354 bool update; 355 int perc, output, *minipercs; 356 unsigned int i, mainperc, totaltodo; 357 float readforsec; 358 const char **minilabels; 359 time_t tstart, told, tnew, refresh; 360 361 if ((minilabels = calloc(nminibar, sizeof(char*))) == NULL) 362 RETURN_ERROR("Cannot allocate memory for minilabels"); 363 if ((minipercs = calloc(nminibar, sizeof(int))) == NULL) 364 RETURN_ERROR("Cannot allocate memory for minipercs"); 365 366 totaltodo = 0; 367 for (i = 0; i < nminibar; i++) { 368 totaltodo += minibar[i].size; 369 minilabels[i] = minibar[i].label; 370 minipercs[i] = minibar[i].status; 371 } 372 373 refresh = pvconf->refresh == 0 ? 0 : pvconf->refresh - 1; 374 output = BSDDIALOG_OK; 375 i = 0; 376 update = true; 377 time(&told); 378 tstart = told; 379 while (!(bsddialog_interruptprogview || bsddialog_abortprogview)) { 380 if (bsddialog_total_progview == 0 || totaltodo == 0) 381 mainperc = 0; 382 else 383 mainperc = (bsddialog_total_progview * 100) / totaltodo; 384 385 time(&tnew); 386 if (update || tnew > told + refresh) { 387 output = do_mixedgauge(conf, text, rows, cols, mainperc, 388 nminibar, minilabels, minipercs, true); 389 if (output == BSDDIALOG_ERROR) 390 return (BSDDIALOG_ERROR); 391 392 move(SCREENLINES - 1, 2); 393 clrtoeol(); 394 readforsec = ((tnew - tstart) == 0) ? 0 : 395 bsddialog_total_progview / (float)(tnew - tstart); 396 printw(pvconf->fmtbottomstr, bsddialog_total_progview, 397 readforsec); 398 refresh(); 399 400 time(&told); 401 update = false; 402 } 403 404 if (i >= nminibar) 405 break; 406 if (minibar[i].status == BSDDIALOG_MG_FAILED) 407 break; 408 409 perc = pvconf->callback(&minibar[i]); 410 411 if (minibar[i].status == BSDDIALOG_MG_DONE) { /*||perc >= 100)*/ 412 minipercs[i] = BSDDIALOG_MG_DONE; 413 update = true; 414 i++; 415 } else if (minibar[i].status == BSDDIALOG_MG_FAILED || perc < 0) { 416 minipercs[i] = BSDDIALOG_MG_FAILED; 417 update = true; 418 } else /* perc >= 0 */ 419 minipercs[i] = perc; 420 } 421 422 free(minilabels); 423 free(minipercs); 424 return (output); 425 } 426 427 int 428 bsddialog_rangebox(struct bsddialog_conf *conf, const char *text, int rows, 429 int cols, int min, int max, int *value) 430 { 431 bool loop, buttupdate, barupdate; 432 int y, x, h, w; 433 int input, currvalue, output, sizebar, bigchange, positions; 434 float perc; 435 WINDOW *widget, *textpad, *bar, *shadow; 436 struct buttons bs; 437 438 if (value == NULL) 439 RETURN_ERROR("*value cannot be NULL"); 440 441 if (min >= max) 442 RETURN_ERROR("min >= max"); 443 444 currvalue = *value; 445 positions = max - min + 1; 446 447 get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL); 448 449 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 450 return (BSDDIALOG_ERROR); 451 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 452 return (BSDDIALOG_ERROR); 453 if (bar_checksize(h, w, &bs) != 0) 454 return (BSDDIALOG_ERROR); 455 if (set_widget_position(conf, &y, &x, h, w) != 0) 456 return (BSDDIALOG_ERROR); 457 458 if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs, 459 true) != 0) 460 return (BSDDIALOG_ERROR); 461 462 doupdate(); 463 464 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN); 465 466 sizebar = w - HBORDERS - (2 * BARPADDING) - 2; 467 bigchange = MAX(1, sizebar/10); 468 469 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3, 470 sizebar + 2, RAISED); 471 472 loop = buttupdate = barupdate = true; 473 while (loop) { 474 if (buttupdate) { 475 draw_buttons(widget, bs, true); 476 wrefresh(widget); 477 buttupdate = false; 478 } 479 if (barupdate) { 480 perc = ((float)(currvalue - min)*100) / (positions-1); 481 draw_bar(bar, 1, 1, sizebar, perc, true, currvalue); 482 barupdate = false; 483 wrefresh(bar); 484 } 485 486 input = getch(); 487 switch(input) { 488 case KEY_ENTER: 489 case 10: /* Enter */ 490 output = bs.value[bs.curr]; 491 *value = currvalue; 492 loop = false; 493 break; 494 case 27: /* Esc */ 495 if (conf->key.enable_esc) { 496 output = BSDDIALOG_ESC; 497 loop = false; 498 } 499 break; 500 case '\t': /* TAB */ 501 bs.curr = (bs.curr + 1) % bs.nbuttons; 502 buttupdate = true; 503 break; 504 case KEY_LEFT: 505 if (bs.curr > 0) { 506 bs.curr--; 507 buttupdate = true; 508 } 509 break; 510 case KEY_RIGHT: 511 if (bs.curr < (int) bs.nbuttons - 1) { 512 bs.curr++; 513 buttupdate = true; 514 } 515 break; 516 case KEY_HOME: 517 currvalue = max; 518 barupdate = true; 519 break; 520 case KEY_END: 521 currvalue = min; 522 barupdate = true; 523 break; 524 case KEY_NPAGE: 525 currvalue -= bigchange; 526 if (currvalue < min) 527 currvalue = min; 528 barupdate = true; 529 break; 530 case KEY_PPAGE: 531 currvalue += bigchange; 532 if (currvalue > max) 533 currvalue = max; 534 barupdate = true; 535 break; 536 case KEY_UP: 537 if (currvalue < max) { 538 currvalue++; 539 barupdate = true; 540 } 541 break; 542 case KEY_DOWN: 543 if (currvalue > min) { 544 currvalue--; 545 barupdate = true; 546 } 547 break; 548 case KEY_F(1): 549 if (conf->key.f1_file == NULL && 550 conf->key.f1_message == NULL) 551 break; 552 if (f1help(conf) != 0) 553 return (BSDDIALOG_ERROR); 554 /* No break, screen size can change */ 555 case KEY_RESIZE: 556 /* Important for decreasing screen */ 557 hide_widget(y, x, h, w, conf->shadow); 558 refresh(); 559 560 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 561 return (BSDDIALOG_ERROR); 562 if (bar_autosize(conf, rows, cols, &h, &w, text, 563 &bs) != 0) 564 return (BSDDIALOG_ERROR); 565 if (bar_checksize(h, w, &bs) != 0) 566 return (BSDDIALOG_ERROR); 567 if (set_widget_position(conf, &y, &x, h, w) != 0) 568 return (BSDDIALOG_ERROR); 569 570 if (update_dialog(conf, shadow, widget,y, x, h, w, 571 textpad, text, &bs, true) != 0) 572 return (BSDDIALOG_ERROR); 573 574 doupdate(); 575 576 sizebar = w - HBORDERS - (2 * BARPADDING) - 2; 577 bigchange = MAX(1, sizebar/10); 578 wclear(bar); 579 mvwin(bar, y + h - 6, x + 1 + BARPADDING); 580 wresize(bar, 3, sizebar + 2); 581 draw_borders(conf, bar, 3, sizebar+2, RAISED); 582 583 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, 584 x+w-1-TEXTHMARGIN); 585 586 barupdate = true; 587 break; 588 default: 589 if (shortcut_buttons(input, &bs)) { 590 output = bs.value[bs.curr]; 591 loop = false; 592 } 593 } 594 } 595 596 delwin(bar); 597 end_dialog(conf, shadow, widget, textpad); 598 599 return (output); 600 } 601 602 int 603 bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows, 604 int cols, unsigned int sec) 605 { 606 bool loop, buttupdate, barupdate; 607 int output, y, x, h, w, input, tout, sizebar; 608 float perc; 609 WINDOW *widget, *textpad, *bar, *shadow; 610 struct buttons bs; 611 612 get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL); 613 614 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 615 return (BSDDIALOG_ERROR); 616 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 617 return (BSDDIALOG_ERROR); 618 if (bar_checksize(h, w, &bs) != 0) 619 return (BSDDIALOG_ERROR); 620 if (set_widget_position(conf, &y, &x, h, w) != 0) 621 return (BSDDIALOG_ERROR); 622 623 if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs, 624 true) != 0) 625 return (BSDDIALOG_ERROR); 626 627 doupdate(); 628 629 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN); 630 631 sizebar = w - HBORDERS - (2 * BARPADDING) - 2; 632 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3, 633 sizebar + 2, RAISED); 634 635 tout = sec; 636 nodelay(stdscr, TRUE); 637 timeout(1000); 638 loop = buttupdate = barupdate = true; 639 while (loop) { 640 if (barupdate) { 641 perc = (float)tout * 100 / sec; 642 draw_bar(bar, 1, 1, sizebar, perc, true, tout); 643 barupdate = false; 644 wrefresh(bar); 645 } 646 647 if (buttupdate) { 648 draw_buttons(widget, bs, true); 649 wrefresh(widget); 650 buttupdate = false; 651 } 652 653 input = getch(); 654 if (input < 0) { /* timeout */ 655 tout--; 656 if (tout < 0) { 657 output = BSDDIALOG_TIMEOUT; 658 break; 659 } 660 else { 661 barupdate = true; 662 continue; 663 } 664 } 665 switch(input) { 666 case KEY_ENTER: 667 case 10: /* Enter */ 668 output = bs.value[bs.curr]; 669 loop = false; 670 break; 671 case 27: /* Esc */ 672 if (conf->key.enable_esc) { 673 output = BSDDIALOG_ESC; 674 loop = false; 675 } 676 break; 677 case '\t': /* TAB */ 678 bs.curr = (bs.curr + 1) % bs.nbuttons; 679 buttupdate = true; 680 break; 681 case KEY_LEFT: 682 if (bs.curr > 0) { 683 bs.curr--; 684 buttupdate = true; 685 } 686 break; 687 case KEY_RIGHT: 688 if (bs.curr < (int) bs.nbuttons - 1) { 689 bs.curr++; 690 buttupdate = true; 691 } 692 break; 693 case KEY_F(1): 694 if (conf->key.f1_file == NULL && 695 conf->key.f1_message == NULL) 696 break; 697 if (f1help(conf) != 0) 698 return (BSDDIALOG_ERROR); 699 /* No break, screen size can change */ 700 case KEY_RESIZE: 701 /* Important for decreasing screen */ 702 hide_widget(y, x, h, w, conf->shadow); 703 refresh(); 704 705 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 706 return (BSDDIALOG_ERROR); 707 if (bar_autosize(conf, rows, cols, &h, &w, text, 708 &bs) != 0) 709 return (BSDDIALOG_ERROR); 710 if (bar_checksize(h, w, &bs) != 0) 711 return (BSDDIALOG_ERROR); 712 if (set_widget_position(conf, &y, &x, h, w) != 0) 713 return (BSDDIALOG_ERROR); 714 715 if (update_dialog(conf, shadow, widget,y, x, h, w, 716 textpad, text, &bs, true) != 0) 717 return (BSDDIALOG_ERROR); 718 719 doupdate(); 720 721 sizebar = w - HBORDERS - (2 * BARPADDING) - 2; 722 wclear(bar); 723 mvwin(bar, y + h - 6, x + 1 + BARPADDING); 724 wresize(bar, 3, sizebar + 2); 725 draw_borders(conf, bar, 3, sizebar+2, LOWERED); 726 727 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, 728 x+w-1-TEXTHMARGIN); 729 730 barupdate = true; 731 break; 732 default: 733 if (shortcut_buttons(input, &bs)) { 734 output = bs.value[bs.curr]; 735 loop = false; 736 } 737 } 738 } 739 740 nodelay(stdscr, FALSE); 741 742 delwin(bar); 743 end_dialog(conf, shadow, widget, textpad); 744 745 return (output); 746 }