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
month_days(int yy,int mm)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
week_day(int yy,int mm,int dd)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
init_date(unsigned int * year,unsigned int * month,unsigned int * day,int * yy,int * mm,int * dd)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
datectl(enum operation op,int * yy,int * mm,int * dd)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
drawsquare(struct bsddialog_conf * conf,WINDOW * win,enum elevation elev,const char * fmt,int value,bool focus)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
print_calendar(struct bsddialog_conf * conf,WINDOW * win,int yy,int mm,int dd,bool active)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
calendar_redraw(struct dialog * d,WINDOW * yy_win,WINDOW * mm_win,WINDOW * dd_win)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
bsddialog_calendar(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int * year,unsigned int * month,unsigned int * day)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
datebox_redraw(struct dialog * d,struct dateitem * di)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
build_dateitem(const char * format,int * yy,int * mm,int * dd,struct dateitem * dt)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
bsddialog_datebox(struct bsddialog_conf * conf,const char * text,int rows,int cols,unsigned int * year,unsigned int * month,unsigned int * day)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 }