1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022-2024 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 <curses.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "bsddialog.h" 33 #include "bsddialog_theme.h" 34 #include "lib_util.h" 35 36 /* Calendar */ 37 #define MIN_YEAR_CAL 0 38 #define MAX_YEAR_CAL 999999999 39 #define MINHCAL 13 40 #define MINWCAL 36 /* 34 calendar, 1 + 1 margins */ 41 /* Datebox */ 42 #define MIN_YEAR_DATE 0 43 #define MAX_YEAR_DATE 9999 44 #define MINWDATE 23 /* 3 windows and their borders */ 45 46 #define ISLEAP(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) 47 48 static int minyear; 49 static int maxyear; 50 51 static const char *m[12] = { 52 "January", 53 "February", 54 "March", 55 "April", 56 "May", 57 "June", 58 "July", 59 "August", 60 "September", 61 "October", 62 "November", 63 "December" 64 }; 65 66 enum operation { 67 UP_DAY, 68 DOWN_DAY, 69 LEFT_DAY, 70 RIGHT_DAY, 71 UP_MONTH, 72 DOWN_MONTH, 73 UP_YEAR, 74 DOWN_YEAR 75 }; 76 77 /* private datebox item */ 78 struct dateitem { 79 enum operation up; 80 enum operation down; 81 WINDOW *win; 82 int width; 83 const char *fmt; 84 int *value; 85 }; 86 87 static int month_days(int yy, int mm) 88 { 89 int days; 90 91 if (mm == 2) 92 days = ISLEAP(yy) ? 29 : 28; 93 else if (mm == 4 || mm == 6 || mm == 9 || mm == 11) 94 days = 30; 95 else 96 days = 31; 97 98 return (days); 99 } 100 101 static int week_day(int yy, int mm, int dd) 102 { 103 int wd; 104 105 dd += mm < 3 ? yy-- : yy - 2; 106 wd = 23*mm/9 + dd + 4 + yy/4 - yy/100 + yy/400; 107 wd %= 7; 108 109 return (wd); 110 } 111 112 static void 113 init_date(unsigned int *year, unsigned int *month, unsigned int *day, int *yy, 114 int *mm, int *dd) 115 { 116 *yy = MIN(*year, (unsigned int)maxyear); 117 if (*yy < minyear) 118 *yy = minyear; 119 *mm = MIN(*month, 12); 120 if (*mm == 0) 121 *mm = 1; 122 *dd = (*day == 0) ? 1 : *day; 123 if (*dd > month_days(*yy, *mm)) 124 *dd = month_days(*yy, *mm); 125 } 126 127 static void datectl(enum operation op, int *yy, int *mm, int *dd) 128 { 129 int ndays; 130 131 ndays = month_days(*yy, *mm); 132 133 switch (op) { 134 case UP_DAY: 135 if (*dd > 7) 136 *dd -= 7; 137 else { 138 if (*mm == 1) { 139 *yy -= 1; 140 *mm = 12; 141 } else 142 *mm -= 1; 143 ndays = month_days(*yy, *mm); 144 *dd = ndays - abs(7 - *dd); 145 } 146 break; 147 case DOWN_DAY: 148 if (*dd + 7 < ndays) 149 *dd += 7; 150 else { 151 if (*mm == 12) { 152 *yy += 1; 153 *mm = 1; 154 } else 155 *mm += 1; 156 *dd = *dd + 7 - ndays; 157 } 158 break; 159 case LEFT_DAY: 160 if (*dd > 1) 161 *dd -= 1; 162 else { 163 if (*mm == 1) { 164 *yy -= 1; 165 *mm = 12; 166 } else 167 *mm -= 1; 168 *dd = month_days(*yy, *mm); 169 } 170 break; 171 case RIGHT_DAY: 172 if (*dd < ndays) 173 *dd += 1; 174 else { 175 if (*mm == 12) { 176 *yy += 1; 177 *mm = 1; 178 } else 179 *mm += 1; 180 *dd = 1; 181 } 182 break; 183 case UP_MONTH: 184 if (*mm == 1) { 185 *mm = 12; 186 *yy -= 1; 187 } else 188 *mm -= 1; 189 ndays = month_days(*yy, *mm); 190 if (*dd > ndays) 191 *dd = ndays; 192 break; 193 case DOWN_MONTH: 194 if (*mm == 12) { 195 *mm = 1; 196 *yy += 1; 197 } else 198 *mm += 1; 199 ndays = month_days(*yy, *mm); 200 if (*dd > ndays) 201 *dd = ndays; 202 break; 203 case UP_YEAR: 204 *yy -= 1; 205 ndays = month_days(*yy, *mm); 206 if (*dd > ndays) 207 *dd = ndays; 208 break; 209 case DOWN_YEAR: 210 *yy += 1; 211 ndays = month_days(*yy, *mm); 212 if (*dd > ndays) 213 *dd = ndays; 214 break; 215 } 216 217 if (*yy < minyear) { 218 *yy = minyear; 219 *mm = 1; 220 *dd = 1; 221 } 222 if (*yy > maxyear) { 223 *yy = maxyear; 224 *mm = 12; 225 *dd = 31; 226 } 227 } 228 229 static void 230 drawsquare(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev, 231 const char *fmt, int value, bool focus) 232 { 233 int h, l, w; 234 235 getmaxyx(win, h, w); 236 draw_borders(conf, win, elev); 237 if (focus) { 238 l = 2 + w%2; 239 wattron(win, t.dialog.arrowcolor); 240 mvwhline(win, 0, w/2 - l/2, UARROW(conf), l); 241 mvwhline(win, h-1, w/2 - l/2, DARROW(conf), l); 242 wattroff(win, t.dialog.arrowcolor); 243 } 244 245 if (focus) 246 wattron(win, t.menu.f_namecolor); 247 if (strchr(fmt, 's') != NULL) 248 mvwprintw(win, 1, 1, fmt, m[value - 1]); 249 else 250 mvwprintw(win, 1, 1, fmt, value); 251 if (focus) 252 wattroff(win, t.menu.f_namecolor); 253 254 wnoutrefresh(win); 255 } 256 257 static void 258 print_calendar(struct bsddialog_conf *conf, WINDOW *win, int yy, int mm, int dd, 259 bool active) 260 { 261 int ndays, i, y, x, wd, h, w; 262 263 getmaxyx(win, h, w); 264 wclear(win); 265 draw_borders(conf, win, RAISED); 266 if (active) { 267 wattron(win, t.dialog.arrowcolor); 268 mvwhline(win, 0, 15, UARROW(conf), 4); 269 mvwhline(win, h-1, 15, DARROW(conf), 4); 270 mvwvline(win, 3, 0, LARROW(conf), 3); 271 mvwvline(win, 3, w-1, RARROW(conf), 3); 272 wattroff(win, t.dialog.arrowcolor); 273 } 274 275 mvwaddstr(win, 1, 5, "Sun Mon Tue Wed Thu Fri Sat"); 276 ndays = month_days(yy, mm); 277 y = 2; 278 wd = week_day(yy, mm, 1); 279 for (i = 1; i <= ndays; i++) { 280 x = 5 + (4 * wd); /* x has to be 6 with week number */ 281 wmove(win, y, x); 282 mvwprintw(win, y, x, "%2d", i); 283 if (i == dd) { 284 wattron(win, t.menu.f_namecolor); 285 mvwprintw(win, y, x, "%2d", i); 286 wattroff(win, t.menu.f_namecolor); 287 } 288 wd++; 289 if (wd > 6) { 290 wd = 0; 291 y++; 292 } 293 } 294 295 wnoutrefresh(win); 296 } 297 298 static int 299 calendar_redraw(struct dialog *d, WINDOW *yy_win, WINDOW *mm_win, 300 WINDOW *dd_win) 301 { 302 int ycal, xcal; 303 304 if (d->built) { 305 hide_dialog(d); 306 refresh(); /* Important for decreasing screen */ 307 } 308 if (dialog_size_position(d, MINHCAL, MINWCAL, NULL) != 0) 309 return (BSDDIALOG_ERROR); 310 if (draw_dialog(d) != 0) 311 return (BSDDIALOG_ERROR); 312 if (d->built) 313 refresh(); /* Important to fix grey lines expanding screen */ 314 TEXTPAD(d, MINHCAL + HBUTTONS); 315 316 ycal = d->y + d->h - 15; 317 xcal = d->x + d->w/2 - 17; 318 mvwaddstr(d->widget, d->h - 16, d->w/2 - 17, "Month"); 319 update_box(d->conf, mm_win, ycal, xcal, 3, 17, RAISED); 320 mvwaddstr(d->widget, d->h - 16, d->w/2, "Year"); 321 update_box(d->conf, yy_win, ycal, xcal + 17, 3, 17, RAISED); 322 update_box(d->conf, dd_win, ycal + 3, xcal, 9, 34, RAISED); 323 wnoutrefresh(d->widget); 324 325 return (0); 326 } 327 328 int 329 bsddialog_calendar(struct bsddialog_conf *conf, const char *text, int rows, 330 int cols, unsigned int *year, unsigned int *month, unsigned int *day) 331 { 332 bool loop, focusbuttons; 333 int retval, sel, yy, mm, dd; 334 wint_t input; 335 WINDOW *yy_win, *mm_win, *dd_win; 336 struct dialog d; 337 338 CHECK_PTR(year); 339 CHECK_PTR(month); 340 CHECK_PTR(day); 341 minyear = MIN_YEAR_CAL; 342 maxyear = MAX_YEAR_CAL; 343 init_date(year, month, day, &yy, &mm, &dd); 344 345 if (prepare_dialog(conf, text, rows, cols, &d) != 0) 346 return (BSDDIALOG_ERROR); 347 set_buttons(&d, true, OK_LABEL, CANCEL_LABEL); 348 if ((yy_win = newwin(1, 1, 1, 1)) == NULL) 349 RETURN_ERROR("Cannot build WINDOW for yy"); 350 wbkgd(yy_win, t.dialog.color); 351 if ((mm_win = newwin(1, 1, 1, 1)) == NULL) 352 RETURN_ERROR("Cannot build WINDOW for mm"); 353 wbkgd(mm_win, t.dialog.color); 354 if ((dd_win = newwin(1, 1, 1, 1)) == NULL) 355 RETURN_ERROR("Cannot build WINDOW for dd"); 356 wbkgd(dd_win, t.dialog.color); 357 if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0) 358 return (BSDDIALOG_ERROR); 359 360 sel = -1; 361 loop = focusbuttons = true; 362 while (loop) { 363 drawsquare(conf, mm_win, RAISED, "%15s", mm, sel == 0); 364 drawsquare(conf, yy_win, RAISED, "%15d", yy, sel == 1); 365 print_calendar(conf, dd_win, yy, mm, dd, sel == 2); 366 doupdate(); 367 368 if (get_wch(&input) == ERR) 369 continue; 370 switch(input) { 371 case KEY_ENTER: 372 case 10: /* Enter */ 373 if (focusbuttons || conf->button.always_active) { 374 retval = BUTTONVALUE(d.bs); 375 loop = false; 376 } 377 break; 378 case 27: /* Esc */ 379 if (conf->key.enable_esc) { 380 retval = BSDDIALOG_ESC; 381 loop = false; 382 } 383 break; 384 case '\t': /* TAB */ 385 if (focusbuttons) { 386 d.bs.curr++; 387 if (d.bs.curr >= (int)d.bs.nbuttons) { 388 focusbuttons = false; 389 sel = 0; 390 d.bs.curr = conf->button.always_active ? 391 0 : -1; 392 } 393 } else { 394 sel++; 395 if (sel > 2) { 396 focusbuttons = true; 397 sel = -1; 398 d.bs.curr = 0; 399 } 400 } 401 DRAW_BUTTONS(d); 402 break; 403 case KEY_CTRL('n'): 404 case KEY_RIGHT: 405 if (focusbuttons) { 406 d.bs.curr++; 407 if (d.bs.curr >= (int)d.bs.nbuttons) { 408 focusbuttons = false; 409 sel = 0; 410 d.bs.curr = conf->button.always_active ? 411 0 : -1; 412 } 413 } else if (sel == 2) { 414 datectl(RIGHT_DAY, &yy, &mm, &dd); 415 } else { /* Month or Year*/ 416 sel++; 417 } 418 DRAW_BUTTONS(d); 419 break; 420 case KEY_CTRL('p'): 421 case KEY_LEFT: 422 if (focusbuttons) { 423 d.bs.curr--; 424 if (d.bs.curr < 0) { 425 focusbuttons = false; 426 sel = 2; 427 d.bs.curr = conf->button.always_active ? 428 0 : -1; 429 } 430 } else if (sel == 2) { 431 datectl(LEFT_DAY, &yy, &mm, &dd); 432 } else if (sel == 1) { 433 sel = 0; 434 } else { /* sel = 0, Month */ 435 focusbuttons = true; 436 sel = -1; 437 d.bs.curr = 0; 438 } 439 DRAW_BUTTONS(d); 440 break; 441 case KEY_UP: 442 if (focusbuttons) { 443 sel = 2; 444 focusbuttons = false; 445 d.bs.curr = conf->button.always_active ? 0 : -1; 446 DRAW_BUTTONS(d); 447 } else if (sel == 0) { 448 datectl(UP_MONTH, &yy, &mm, &dd); 449 } else if (sel == 1) { 450 datectl(UP_YEAR, &yy, &mm, &dd); 451 } else { /* sel = 2 */ 452 datectl(UP_DAY, &yy, &mm, &dd); 453 } 454 break; 455 case KEY_DOWN: 456 if (focusbuttons) { 457 break; 458 } else if (sel == 0) { 459 datectl(DOWN_MONTH, &yy, &mm, &dd); 460 } else if (sel == 1) { 461 datectl(DOWN_YEAR, &yy, &mm, &dd); 462 } else { /* sel = 2 */ 463 datectl(DOWN_DAY, &yy, &mm, &dd); 464 } 465 break; 466 case '-': 467 if (focusbuttons) { 468 break; 469 } else if (sel == 0) { 470 datectl(UP_MONTH, &yy, &mm, &dd); 471 } else if (sel == 1) { 472 datectl(UP_YEAR, &yy, &mm, &dd); 473 } else { /* sel = 2 */ 474 datectl(LEFT_DAY, &yy, &mm, &dd); 475 } 476 break; 477 case '+': 478 if (focusbuttons) { 479 break; 480 } else if (sel == 0) { 481 datectl(DOWN_MONTH, &yy, &mm, &dd); 482 } else if (sel == 1) { 483 datectl(DOWN_YEAR, &yy, &mm, &dd); 484 } else { /* sel = 2 */ 485 datectl(RIGHT_DAY, &yy, &mm, &dd); 486 } 487 break; 488 case KEY_HOME: 489 datectl(UP_MONTH, &yy, &mm, &dd); 490 break; 491 case KEY_END: 492 datectl(DOWN_MONTH, &yy, &mm, &dd); 493 break; 494 case KEY_PPAGE: 495 datectl(UP_YEAR, &yy, &mm, &dd); 496 break; 497 case KEY_NPAGE: 498 datectl(DOWN_YEAR, &yy, &mm, &dd); 499 break; 500 case KEY_F(1): 501 if (conf->key.f1_file == NULL && 502 conf->key.f1_message == NULL) 503 break; 504 if (f1help_dialog(conf) != 0) 505 return (BSDDIALOG_ERROR); 506 if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0) 507 return (BSDDIALOG_ERROR); 508 break; 509 case KEY_CTRL('l'): 510 case KEY_RESIZE: 511 if (calendar_redraw(&d, yy_win, mm_win, dd_win) != 0) 512 return (BSDDIALOG_ERROR); 513 break; 514 default: 515 if (shortcut_buttons(input, &d.bs)) { 516 DRAW_BUTTONS(d); 517 doupdate(); 518 retval = BUTTONVALUE(d.bs); 519 loop = false; 520 } 521 } 522 } 523 524 *year = yy; 525 *month = mm; 526 *day = dd; 527 528 delwin(yy_win); 529 delwin(mm_win); 530 delwin(dd_win); 531 end_dialog(&d); 532 533 return (retval); 534 } 535 536 static int datebox_redraw(struct dialog *d, struct dateitem *di) 537 { 538 int y, x; 539 540 if (d->built) { 541 hide_dialog(d); 542 refresh(); /* Important for decreasing screen */ 543 } 544 if (dialog_size_position(d, 3 /*windows*/, MINWDATE, NULL) != 0) 545 return (BSDDIALOG_ERROR); 546 if (draw_dialog(d) != 0) 547 return (BSDDIALOG_ERROR); 548 if (d->built) 549 refresh(); /* Important to fix grey lines expanding screen */ 550 TEXTPAD(d, 3 /*windows*/ + HBUTTONS); 551 552 y = d->y + d->h - 6; 553 x = (d->x + d->w / 2) - 11; 554 update_box(d->conf, di[0].win, y, x, 3, di[0].width, LOWERED); 555 mvwaddch(d->widget, d->h - 5, x - d->x + di[0].width, '/'); 556 x += di[0].width + 1; 557 update_box(d->conf, di[1].win, y, x , 3, di[1].width, LOWERED); 558 mvwaddch(d->widget, d->h - 5, x - d->x + di[1].width, '/'); 559 x += di[1].width + 1; 560 update_box(d->conf, di[2].win, y, x, 3, di[2].width, LOWERED); 561 wnoutrefresh(d->widget); 562 563 return (0); 564 } 565 566 static int 567 build_dateitem(const char *format, int *yy, int *mm, int *dd, 568 struct dateitem *dt) 569 { 570 int i; 571 wchar_t *wformat; 572 struct dateitem init[3] = { 573 {UP_YEAR, DOWN_YEAR, NULL, 6, "%4d", yy}, 574 {UP_MONTH, DOWN_MONTH, NULL, 11, "%9s", mm}, 575 {LEFT_DAY, RIGHT_DAY, NULL, 4, "%02d", dd}, 576 }; 577 578 for (i = 0; i < 3; i++) { 579 if ((init[i].win = newwin(1, 1, 1, 1)) == NULL) 580 RETURN_FMTERROR("Cannot build WINDOW dateitem[%d]", i); 581 wbkgd(init[i].win, t.dialog.color); 582 } 583 584 if ((wformat = alloc_mbstows(CHECK_STR(format))) == NULL) 585 RETURN_ERROR("Cannot allocate conf.date.format in wchar_t*"); 586 if (format == NULL || wcscmp(wformat, L"d/m/y") == 0) { 587 dt[0] = init[2]; 588 dt[1] = init[1]; 589 dt[2] = init[0]; 590 } else if (wcscmp(wformat, L"m/d/y") == 0) { 591 dt[0] = init[1]; 592 dt[1] = init[2]; 593 dt[2] = init[0]; 594 } else if (wcscmp(wformat, L"y/m/d") == 0) { 595 dt[0] = init[0]; 596 dt[1] = init[1]; 597 dt[2] = init[2]; 598 } else 599 RETURN_FMTERROR("Invalid conf.date.format=\"%s\"", format); 600 free(wformat); 601 602 return (0); 603 } 604 605 int 606 bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows, 607 int cols, unsigned int *year, unsigned int *month, unsigned int *day) 608 { 609 bool loop, focusbuttons; 610 int retval, i, sel, yy, mm, dd; 611 wint_t input; 612 struct dateitem di[3]; 613 struct dialog d; 614 615 CHECK_PTR(year); 616 CHECK_PTR(month); 617 CHECK_PTR(day); 618 minyear = MIN_YEAR_DATE; 619 maxyear = MAX_YEAR_DATE; 620 init_date(year, month, day, &yy, &mm, &dd); 621 622 if (prepare_dialog(conf, text, rows, cols, &d) != 0) 623 return (BSDDIALOG_ERROR); 624 set_buttons(&d, true, OK_LABEL, CANCEL_LABEL); 625 if (build_dateitem(conf->date.format, &yy, &mm, &dd, di) != 0) 626 return (BSDDIALOG_ERROR); 627 if (datebox_redraw(&d, di) != 0) 628 return (BSDDIALOG_ERROR); 629 630 sel = -1; 631 loop = focusbuttons = true; 632 while (loop) { 633 for (i = 0; i < 3; i++) 634 drawsquare(conf, di[i].win, LOWERED, di[i].fmt, 635 *di[i].value, sel == i); 636 doupdate(); 637 638 if (get_wch(&input) == ERR) 639 continue; 640 switch(input) { 641 case KEY_ENTER: 642 case 10: /* Enter */ 643 if (focusbuttons || conf->button.always_active) { 644 retval = BUTTONVALUE(d.bs); 645 loop = false; 646 } 647 break; 648 case 27: /* Esc */ 649 if (conf->key.enable_esc) { 650 retval = BSDDIALOG_ESC; 651 loop = false; 652 } 653 break; 654 case '\t': /* TAB */ 655 case KEY_CTRL('n'): 656 case KEY_RIGHT: 657 if (focusbuttons) { 658 d.bs.curr++; 659 focusbuttons = d.bs.curr < (int)d.bs.nbuttons ? 660 true : false; 661 if (focusbuttons == false) { 662 sel = 0; 663 d.bs.curr = conf->button.always_active ? 664 0 : -1; 665 } 666 } else { 667 sel++; 668 focusbuttons = sel > 2 ? true : false; 669 if (focusbuttons) { 670 d.bs.curr = 0; 671 } 672 } 673 DRAW_BUTTONS(d); 674 break; 675 case KEY_CTRL('p'): 676 case KEY_LEFT: 677 if (focusbuttons) { 678 d.bs.curr--; 679 focusbuttons = d.bs.curr < 0 ? false : true; 680 if (focusbuttons == false) { 681 sel = 2; 682 d.bs.curr = conf->button.always_active ? 683 0 : -1; 684 } 685 } else { 686 sel--; 687 focusbuttons = sel < 0 ? true : false; 688 if (focusbuttons) 689 d.bs.curr = (int)d.bs.nbuttons - 1; 690 } 691 DRAW_BUTTONS(d); 692 break; 693 case '-': 694 if (focusbuttons == false) 695 datectl(di[sel].up, &yy, &mm, &dd); 696 break; 697 case KEY_UP: 698 if (focusbuttons) { 699 sel = 0; 700 focusbuttons = false; 701 d.bs.curr = conf->button.always_active ? 0 : -1; 702 DRAW_BUTTONS(d); 703 } else { 704 datectl(di[sel].up, &yy, &mm, &dd); 705 } 706 break; 707 case '+': 708 case KEY_DOWN: 709 if (focusbuttons) 710 break; 711 datectl(di[sel].down, &yy, &mm, &dd); 712 break; 713 case KEY_F(1): 714 if (conf->key.f1_file == NULL && 715 conf->key.f1_message == NULL) 716 break; 717 if (f1help_dialog(conf) != 0) 718 return (BSDDIALOG_ERROR); 719 if (datebox_redraw(&d, di) != 0) 720 return (BSDDIALOG_ERROR); 721 break; 722 case KEY_CTRL('l'): 723 case KEY_RESIZE: 724 if (datebox_redraw(&d, di) != 0) 725 return (BSDDIALOG_ERROR); 726 break; 727 default: 728 if (shortcut_buttons(input, &d.bs)) { 729 DRAW_BUTTONS(d); 730 doupdate(); 731 retval = BUTTONVALUE(d.bs); 732 loop = false; 733 } 734 } 735 } 736 737 *year = yy; 738 *month = mm; 739 *day = dd; 740 741 for (i = 0; i < 3 ; i++) 742 delwin(di[i].win); 743 end_dialog(&d); 744 745 return (retval); 746 }