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 3 43 #define MINBARWIDTH (15 + BARPADDING * 2) 44 45 bool bsddialog_interruptprogview; 46 bool bsddialog_abortprogview; 47 int bsddialog_total_progview; 48 49 extern struct bsddialog_theme t; 50 51 static void 52 draw_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel, 53 int label) 54 { 55 int i, blue_x, color; 56 char labelstr[128]; 57 58 blue_x = (int)((perc*(size))/100); 59 60 wmove(win, y, x); 61 for (i = 0; i < size; i++) { 62 color = (i <= blue_x) ? t.bar.f_color : t.bar.color; 63 wattron(win, color); 64 waddch(win, ' '); 65 wattroff(win, color); 66 } 67 68 if (withlabel) 69 sprintf(labelstr, "%d", label); 70 else 71 sprintf(labelstr, "%3d%%", perc); 72 wmove(win, y, x + size/2 - 2); 73 for (i = 0; i < (int)strlen(labelstr); i++) { 74 color = (blue_x + 1 <= size/2 - (int)strlen(labelstr)/2 + i ) ? 75 t.bar.color : t.bar.f_color; 76 wattron(win, color); 77 waddch(win, labelstr[i]); 78 wattroff(win, color); 79 } 80 } 81 82 static int 83 bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w, 84 const char *text, struct buttons *bs) 85 { 86 int htext, wtext; 87 88 if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) { 89 if (text_size(conf, rows, cols, text, bs, 3, MINBARWIDTH, 90 &htext, &wtext) != 0) 91 return (BSDDIALOG_ERROR); 92 } 93 94 if (cols == BSDDIALOG_AUTOSIZE) 95 *w = widget_min_width(conf, wtext, MINBARWIDTH, bs); 96 97 if (rows == BSDDIALOG_AUTOSIZE) 98 *h = widget_min_height(conf, htext, 3 /* bar */, bs != NULL); 99 100 return (0); 101 } 102 103 static int 104 bar_checksize(int rows, int cols, struct buttons *bs) 105 { 106 int minheight, minwidth; 107 108 minwidth = 0; 109 if (bs != NULL) { /* gauge has not buttons */ 110 minwidth = bs->nbuttons * bs->sizebutton; 111 if (bs->nbuttons > 0) 112 minwidth += (bs->nbuttons-1) * t.button.space; 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 < 0 ? 0 : perc; 185 perc = perc > 100 ? 100 : perc; 186 pntext = &ntext[0]; 187 ntext[0] = '\0'; 188 while (true) { 189 fscanf(input, "%s", inputbuf); 190 if (strcmp(inputbuf,"EOF") == 0) { 191 mainloop = false; 192 break; 193 } 194 if (strcmp(inputbuf, sep) == 0) 195 break; 196 strcpy(pntext, inputbuf); 197 pntext += strlen(inputbuf); 198 pntext[0] = ' '; 199 pntext++; 200 } 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, output, 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)strlen(minilabels[i])); 245 max_minbarlen += 3 + 16 /* seps + [...] or 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+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->f1_file == NULL && conf->f1_message == NULL) 550 break; 551 if (f1help(conf) != 0) 552 return (BSDDIALOG_ERROR); 553 /* No break, screen size can change */ 554 case KEY_RESIZE: 555 /* Important for decreasing screen */ 556 hide_widget(y, x, h, w, conf->shadow); 557 refresh(); 558 559 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 560 return (BSDDIALOG_ERROR); 561 if (bar_autosize(conf, rows, cols, &h, &w, text, 562 &bs) != 0) 563 return (BSDDIALOG_ERROR); 564 if (bar_checksize(h, w, &bs) != 0) 565 return (BSDDIALOG_ERROR); 566 if (set_widget_position(conf, &y, &x, h, w) != 0) 567 return (BSDDIALOG_ERROR); 568 569 if (update_dialog(conf, shadow, widget,y, x, h, w, 570 textpad, text, &bs, true) != 0) 571 return (BSDDIALOG_ERROR); 572 573 doupdate(); 574 575 sizebar = w - HBORDERS - 2 - BARPADDING * 2; 576 bigchange = MAX(1, sizebar/10); 577 wclear(bar); 578 mvwin(bar, y + h - 6, x + 1 + BARPADDING); 579 wresize(bar, 3, sizebar + 2); 580 draw_borders(conf, bar, 3, sizebar+2, RAISED); 581 582 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, 583 x+w-1-TEXTHMARGIN); 584 585 barupdate = true; 586 break; 587 default: 588 if (shortcut_buttons(input, &bs)) { 589 output = bs.value[bs.curr]; 590 loop = false; 591 } 592 } 593 } 594 595 delwin(bar); 596 end_dialog(conf, shadow, widget, textpad); 597 598 return (output); 599 } 600 601 int 602 bsddialog_pause(struct bsddialog_conf *conf, const char *text, int rows, 603 int cols, unsigned int sec) 604 { 605 bool loop, buttupdate, barupdate; 606 int output, y, x, h, w, input, tout, sizebar; 607 float perc; 608 WINDOW *widget, *textpad, *bar, *shadow; 609 struct buttons bs; 610 611 get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL); 612 613 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 614 return (BSDDIALOG_ERROR); 615 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0) 616 return (BSDDIALOG_ERROR); 617 if (bar_checksize(h, w, &bs) != 0) 618 return (BSDDIALOG_ERROR); 619 if (set_widget_position(conf, &y, &x, h, w) != 0) 620 return (BSDDIALOG_ERROR); 621 622 if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs, 623 true) != 0) 624 return (BSDDIALOG_ERROR); 625 626 doupdate(); 627 628 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, x+w-1-TEXTHMARGIN); 629 630 sizebar = w - HBORDERS - 2 - BARPADDING * 2; 631 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARPADDING, 3, 632 sizebar + 2, RAISED); 633 634 tout = sec; 635 nodelay(stdscr, TRUE); 636 timeout(1000); 637 loop = buttupdate = barupdate = true; 638 while (loop) { 639 if (barupdate) { 640 perc = (float)tout * 100 / sec; 641 draw_bar(bar, 1, 1, sizebar, perc, true, tout); 642 barupdate = false; 643 wrefresh(bar); 644 } 645 646 if (buttupdate) { 647 draw_buttons(widget, bs, true); 648 wrefresh(widget); 649 buttupdate = false; 650 } 651 652 input = getch(); 653 if (input < 0) { /* timeout */ 654 tout--; 655 if (tout < 0) { 656 output = BSDDIALOG_TIMEOUT; 657 break; 658 } 659 else { 660 barupdate = true; 661 continue; 662 } 663 } 664 switch(input) { 665 case KEY_ENTER: 666 case 10: /* Enter */ 667 output = bs.value[bs.curr]; 668 loop = false; 669 break; 670 case 27: /* Esc */ 671 if (conf->key.enable_esc) { 672 output = BSDDIALOG_ESC; 673 loop = false; 674 } 675 break; 676 case '\t': /* TAB */ 677 bs.curr = (bs.curr + 1) % bs.nbuttons; 678 buttupdate = true; 679 break; 680 case KEY_LEFT: 681 if (bs.curr > 0) { 682 bs.curr--; 683 buttupdate = true; 684 } 685 break; 686 case KEY_RIGHT: 687 if (bs.curr < (int) bs.nbuttons - 1) { 688 bs.curr++; 689 buttupdate = true; 690 } 691 break; 692 case KEY_F(1): 693 if (conf->f1_file == NULL && conf->f1_message == NULL) 694 break; 695 if (f1help(conf) != 0) 696 return (BSDDIALOG_ERROR); 697 /* No break, screen size can change */ 698 case KEY_RESIZE: 699 /* Important for decreasing screen */ 700 hide_widget(y, x, h, w, conf->shadow); 701 refresh(); 702 703 if (set_widget_size(conf, rows, cols, &h, &w) != 0) 704 return (BSDDIALOG_ERROR); 705 if (bar_autosize(conf, rows, cols, &h, &w, text, 706 &bs) != 0) 707 return (BSDDIALOG_ERROR); 708 if (bar_checksize(h, w, &bs) != 0) 709 return (BSDDIALOG_ERROR); 710 if (set_widget_position(conf, &y, &x, h, w) != 0) 711 return (BSDDIALOG_ERROR); 712 713 if (update_dialog(conf, shadow, widget,y, x, h, w, 714 textpad, text, &bs, true) != 0) 715 return (BSDDIALOG_ERROR); 716 717 doupdate(); 718 719 sizebar = w - HBORDERS - 2 - BARPADDING * 2; 720 wclear(bar); 721 mvwin(bar, y + h - 6, x + 1 + BARPADDING); 722 wresize(bar, 3, sizebar + 2); 723 draw_borders(conf, bar, 3, sizebar+2, LOWERED); 724 725 prefresh(textpad, 0, 0, y+1, x+1+TEXTHMARGIN, y+h-7, 726 x+w-1-TEXTHMARGIN); 727 728 barupdate = true; 729 break; 730 default: 731 if (shortcut_buttons(input, &bs)) { 732 output = bs.value[bs.curr]; 733 loop = false; 734 } 735 } 736 } 737 738 nodelay(stdscr, FALSE); 739 740 delwin(bar); 741 end_dialog(conf, shadow, widget, textpad); 742 743 return (output); 744 }