xref: /freebsd/contrib/bsddialog/lib/timebox.c (revision b319d934379f5b819cd195be7e03dbd407566fd4)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4263660c0SAlfonso Siciliano  * Copyright (c) 2021-2022 Alfonso Sabato Siciliano
5c76f0793SBaptiste Daroussin  *
6c76f0793SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
7c76f0793SBaptiste Daroussin  * modification, are permitted provided that the following conditions
8c76f0793SBaptiste Daroussin  * are met:
9c76f0793SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
10c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
11c76f0793SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
12c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
13c76f0793SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
14c76f0793SBaptiste Daroussin  *
15c76f0793SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c76f0793SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c76f0793SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c76f0793SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c76f0793SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c76f0793SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c76f0793SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c76f0793SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c76f0793SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c76f0793SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c76f0793SBaptiste Daroussin  * SUCH DAMAGE.
26c76f0793SBaptiste Daroussin  */
27c76f0793SBaptiste Daroussin 
28f499134dSBaptiste Daroussin #include <sys/param.h>
29f499134dSBaptiste Daroussin 
30d93b4d32SBaptiste Daroussin #include <ctype.h>
31263660c0SAlfonso Siciliano #include <curses.h>
32f499134dSBaptiste Daroussin #include <string.h>
33f499134dSBaptiste Daroussin 
34c76f0793SBaptiste Daroussin #include "bsddialog.h"
35*b319d934SAlfonso S. Siciliano #include "bsddialog_theme.h"
36263660c0SAlfonso Siciliano #include "lib_util.h"
37c76f0793SBaptiste Daroussin 
38263660c0SAlfonso Siciliano #define MINWDATE   23 /* 3 windows and their borders */
39263660c0SAlfonso Siciliano #define MINWTIME   14 /* 3 windows and their borders */
40f499134dSBaptiste Daroussin 
41*b319d934SAlfonso S. Siciliano static void
42*b319d934SAlfonso S. Siciliano drawquare(struct bsddialog_conf *conf, WINDOW *win, const char *fmt,
43*b319d934SAlfonso S. Siciliano     const void *value, bool focus)
44*b319d934SAlfonso S. Siciliano {
45*b319d934SAlfonso S. Siciliano 	int h, l, w;
46*b319d934SAlfonso S. Siciliano 
47*b319d934SAlfonso S. Siciliano 	getmaxyx(win, h, w);
48*b319d934SAlfonso S. Siciliano 	draw_borders(conf, win, h, w, LOWERED);
49*b319d934SAlfonso S. Siciliano 	if (focus) {
50*b319d934SAlfonso S. Siciliano 		l = 2 + w%2;
51*b319d934SAlfonso S. Siciliano 		wattron(win, t.dialog.arrowcolor);
52*b319d934SAlfonso S. Siciliano 		mvwhline(win, 0, w/2 - l/2,
53*b319d934SAlfonso S. Siciliano 		    conf->ascii_lines ? '^' : ACS_UARROW, l);
54*b319d934SAlfonso S. Siciliano 		mvwhline(win, h-1, w/2 - l/2,
55*b319d934SAlfonso S. Siciliano 		    conf->ascii_lines ? 'v' : ACS_DARROW, l);
56*b319d934SAlfonso S. Siciliano 		wattroff(win, t.dialog.arrowcolor);
57*b319d934SAlfonso S. Siciliano 	}
58*b319d934SAlfonso S. Siciliano 
59*b319d934SAlfonso S. Siciliano 	if (focus)
60*b319d934SAlfonso S. Siciliano 		wattron(win, t.menu.f_namecolor);
61*b319d934SAlfonso S. Siciliano 	if (strchr(fmt, 's') != NULL)
62*b319d934SAlfonso S. Siciliano 		mvwprintw(win, 1, 1, fmt, (const char*)value);
63*b319d934SAlfonso S. Siciliano 	else
64*b319d934SAlfonso S. Siciliano 		mvwprintw(win, 1, 1, fmt, *((const int*)value));
65*b319d934SAlfonso S. Siciliano 	if (focus)
66*b319d934SAlfonso S. Siciliano 		wattroff(win, t.menu.f_namecolor);
67*b319d934SAlfonso S. Siciliano 
68*b319d934SAlfonso S. Siciliano 	wrefresh(win);
69*b319d934SAlfonso S. Siciliano }
70*b319d934SAlfonso S. Siciliano 
71f499134dSBaptiste Daroussin static int
72f499134dSBaptiste Daroussin datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
73263660c0SAlfonso Siciliano     int *w, int minw, const char *text, struct buttons bs)
74f499134dSBaptiste Daroussin {
75263660c0SAlfonso Siciliano 	int htext, wtext;
76f499134dSBaptiste Daroussin 
77263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
78263660c0SAlfonso Siciliano 		if (text_size(conf, rows, cols, text, &bs, 3, minw, &htext,
79263660c0SAlfonso Siciliano 		    &wtext) != 0)
80263660c0SAlfonso Siciliano 			return (BSDDIALOG_ERROR);
81f499134dSBaptiste Daroussin 	}
82f499134dSBaptiste Daroussin 
83263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE)
84*b319d934SAlfonso S. Siciliano 		*w = widget_min_width(conf, wtext, minw, &bs);
85f499134dSBaptiste Daroussin 
86263660c0SAlfonso Siciliano 	if (rows == BSDDIALOG_AUTOSIZE)
87263660c0SAlfonso Siciliano 		*h = widget_min_height(conf, htext, 3 /* windows */, true);
88263660c0SAlfonso Siciliano 
89263660c0SAlfonso Siciliano 	return (0);
90f499134dSBaptiste Daroussin }
91f499134dSBaptiste Daroussin 
92f499134dSBaptiste Daroussin static int
93263660c0SAlfonso Siciliano datetime_checksize(int rows, int cols, int minw, struct buttons bs)
94f499134dSBaptiste Daroussin {
95f499134dSBaptiste Daroussin 	int mincols;
96f499134dSBaptiste Daroussin 
97f499134dSBaptiste Daroussin 	mincols = VBORDERS;
98*b319d934SAlfonso S. Siciliano 	mincols += buttons_min_width(bs);
99f499134dSBaptiste Daroussin 	mincols = MAX(minw, mincols);
100f499134dSBaptiste Daroussin 
101f499134dSBaptiste Daroussin 	if (cols < mincols)
102f499134dSBaptiste Daroussin 		RETURN_ERROR("Few cols for this timebox/datebox");
103f499134dSBaptiste Daroussin 
104263660c0SAlfonso Siciliano 	if (rows < 7) /* 2 button + 2 borders + 3 windows */
105263660c0SAlfonso Siciliano 		RETURN_ERROR("Few rows for this timebox/datebox, at least 7");
106f499134dSBaptiste Daroussin 
107263660c0SAlfonso Siciliano 	return (0);
108f499134dSBaptiste Daroussin }
109f499134dSBaptiste Daroussin 
110263660c0SAlfonso Siciliano int
111263660c0SAlfonso Siciliano bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
112263660c0SAlfonso Siciliano     int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
113c76f0793SBaptiste Daroussin {
114bce40c02SAlfonso S. Siciliano 	bool loop, focusbuttons;
115*b319d934SAlfonso S. Siciliano 	int i, retval, y, x, h, w, sel;
116*b319d934SAlfonso S. Siciliano 	wint_t input;
117263660c0SAlfonso Siciliano 	WINDOW *widget, *textpad, *shadow;
118263660c0SAlfonso Siciliano 	struct buttons bs;
119c76f0793SBaptiste Daroussin 	struct myclockstruct {
120c76f0793SBaptiste Daroussin 		unsigned int max;
121f499134dSBaptiste Daroussin 		unsigned int value;
122c76f0793SBaptiste Daroussin 		WINDOW *win;
123f499134dSBaptiste Daroussin 	};
124c76f0793SBaptiste Daroussin 
125f499134dSBaptiste Daroussin 	if (hh == NULL || mm == NULL || ss == NULL)
126f499134dSBaptiste Daroussin 		RETURN_ERROR("hh / mm / ss cannot be NULL");
127c76f0793SBaptiste Daroussin 
128f499134dSBaptiste Daroussin 	struct myclockstruct c[3] = {
129f499134dSBaptiste Daroussin 		{23, *hh, NULL},
130f499134dSBaptiste Daroussin 		{59, *mm, NULL},
131f499134dSBaptiste Daroussin 		{59, *ss, NULL}
132f499134dSBaptiste Daroussin 	};
133f499134dSBaptiste Daroussin 
134f499134dSBaptiste Daroussin 	for (i = 0 ; i < 3; i++) {
135f499134dSBaptiste Daroussin 		if (c[i].value > c[i].max)
136f499134dSBaptiste Daroussin 			c[i].value = c[i].max;
137f499134dSBaptiste Daroussin 	}
138c76f0793SBaptiste Daroussin 
139263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
140c76f0793SBaptiste Daroussin 
141f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
142263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
143263660c0SAlfonso Siciliano 	if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text,
144263660c0SAlfonso Siciliano 	    bs) != 0)
145263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
146263660c0SAlfonso Siciliano 	if (datetime_checksize(h, w, MINWTIME, bs) != 0)
147263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
148f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
149263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
150f499134dSBaptiste Daroussin 
151263660c0SAlfonso Siciliano 	if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
152263660c0SAlfonso Siciliano 	    true) != 0)
153263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
154f499134dSBaptiste Daroussin 
155263660c0SAlfonso Siciliano 	pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
156263660c0SAlfonso Siciliano 	doupdate();
157f499134dSBaptiste Daroussin 
158f499134dSBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 7, 3, 4, LOWERED);
159f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 - 3, ':');
160f499134dSBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 2, 3, 4, LOWERED);
161f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 + 2, ':');
162f499134dSBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 3, 3, 4, LOWERED);
163f499134dSBaptiste Daroussin 
164f499134dSBaptiste Daroussin 	wrefresh(widget);
165f499134dSBaptiste Daroussin 
166*b319d934SAlfonso S. Siciliano 	sel = -1;
167bce40c02SAlfonso S. Siciliano 	loop = focusbuttons = true;
168c76f0793SBaptiste Daroussin 	while (loop) {
169*b319d934SAlfonso S. Siciliano 		for (i = 0; i < 3; i++)
170*b319d934SAlfonso S. Siciliano 			drawquare(conf, c[i].win, "%02d", &c[i].value,
171*b319d934SAlfonso S. Siciliano 			    sel == i);
172bce40c02SAlfonso S. Siciliano 
173*b319d934SAlfonso S. Siciliano 		if (get_wch(&input) == ERR)
174*b319d934SAlfonso S. Siciliano 			continue;
175c76f0793SBaptiste Daroussin 		switch(input) {
176f499134dSBaptiste Daroussin 		case KEY_ENTER:
177c76f0793SBaptiste Daroussin 		case 10: /* Enter */
178*b319d934SAlfonso S. Siciliano 			if (focusbuttons || conf->button.always_active) {
179*b319d934SAlfonso S. Siciliano 				retval = bs.value[bs.curr];
180c76f0793SBaptiste Daroussin 				loop = false;
181*b319d934SAlfonso S. Siciliano 			}
182c76f0793SBaptiste Daroussin 			break;
183c76f0793SBaptiste Daroussin 		case 27: /* Esc */
184263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
185*b319d934SAlfonso S. Siciliano 				retval = BSDDIALOG_ESC;
186c76f0793SBaptiste Daroussin 				loop = false;
187263660c0SAlfonso Siciliano 			}
188c76f0793SBaptiste Daroussin 			break;
189bce40c02SAlfonso S. Siciliano 		case KEY_RIGHT:
190c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
191bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
192bce40c02SAlfonso S. Siciliano 				bs.curr++;
193bce40c02SAlfonso S. Siciliano 				focusbuttons = bs.curr < (int)bs.nbuttons ?
194bce40c02SAlfonso S. Siciliano 				    true : false;
195bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
196bce40c02SAlfonso S. Siciliano 					sel = 0;
197*b319d934SAlfonso S. Siciliano 					bs.curr = conf->button.always_active ? 0 : -1;
198bce40c02SAlfonso S. Siciliano 				}
199bce40c02SAlfonso S. Siciliano 			} else {
200bce40c02SAlfonso S. Siciliano 				sel++;
201bce40c02SAlfonso S. Siciliano 				focusbuttons = sel > 2 ? true : false;
202bce40c02SAlfonso S. Siciliano 				if (focusbuttons) {
203bce40c02SAlfonso S. Siciliano 					bs.curr = 0;
204bce40c02SAlfonso S. Siciliano 				}
205bce40c02SAlfonso S. Siciliano 			}
206263660c0SAlfonso Siciliano 			draw_buttons(widget, bs, true);
207263660c0SAlfonso Siciliano 			wrefresh(widget);
208c76f0793SBaptiste Daroussin 			break;
209c76f0793SBaptiste Daroussin 		case KEY_LEFT:
210bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
211bce40c02SAlfonso S. Siciliano 				bs.curr--;
212bce40c02SAlfonso S. Siciliano 				focusbuttons = bs.curr < 0 ? false : true;
213bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
214bce40c02SAlfonso S. Siciliano 					sel = 2;
215*b319d934SAlfonso S. Siciliano 					bs.curr = conf->button.always_active ? 0 : -1;
216bce40c02SAlfonso S. Siciliano 				}
217bce40c02SAlfonso S. Siciliano 			} else {
218bce40c02SAlfonso S. Siciliano 				sel--;
219bce40c02SAlfonso S. Siciliano 				focusbuttons = sel < 0 ? true : false;
220*b319d934SAlfonso S. Siciliano 				if (focusbuttons)
221bce40c02SAlfonso S. Siciliano 					bs.curr = (int)bs.nbuttons - 1;
222bce40c02SAlfonso S. Siciliano 			}
223bce40c02SAlfonso S. Siciliano 			draw_buttons(widget, bs, true);
224bce40c02SAlfonso S. Siciliano 			wrefresh(widget);
225c76f0793SBaptiste Daroussin 			break;
226c76f0793SBaptiste Daroussin 		case KEY_UP:
227*b319d934SAlfonso S. Siciliano 			if (focusbuttons) {
228*b319d934SAlfonso S. Siciliano 				sel = 0;
229*b319d934SAlfonso S. Siciliano 				focusbuttons = false;
230*b319d934SAlfonso S. Siciliano 				bs.curr = conf->button.always_active ? 0 : -1;
231*b319d934SAlfonso S. Siciliano 				draw_buttons(widget, bs, true);
232*b319d934SAlfonso S. Siciliano 				wrefresh(widget);
233*b319d934SAlfonso S. Siciliano 			} else { c[sel].value = c[sel].value > 0 ?
234263660c0SAlfonso Siciliano 			    c[sel].value - 1 : c[sel].max;
235*b319d934SAlfonso S. Siciliano 			}
236c76f0793SBaptiste Daroussin 			break;
237bce40c02SAlfonso S. Siciliano 		case KEY_DOWN:
238bce40c02SAlfonso S. Siciliano 			if (focusbuttons)
239bce40c02SAlfonso S. Siciliano 				break;
240bce40c02SAlfonso S. Siciliano 			c[sel].value = c[sel].value < c[sel].max ?
241bce40c02SAlfonso S. Siciliano 			    c[sel].value + 1 : 0;
242bce40c02SAlfonso S. Siciliano 			break;
243f499134dSBaptiste Daroussin 		case KEY_F(1):
244bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
245bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
246f499134dSBaptiste Daroussin 				break;
247f499134dSBaptiste Daroussin 			if (f1help(conf) != 0)
248263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
249263660c0SAlfonso Siciliano 			/* No break, screen size can change */
250f499134dSBaptiste Daroussin 		case KEY_RESIZE:
251263660c0SAlfonso Siciliano 			/* Important for decreasing screen */
252f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w, conf->shadow);
253f499134dSBaptiste Daroussin 			refresh();
254f499134dSBaptiste Daroussin 
255f499134dSBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
256263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
257263660c0SAlfonso Siciliano 			if (datetime_autosize(conf, rows, cols, &h, &w,
258263660c0SAlfonso Siciliano 			    MINWTIME, text, bs) != 0)
259263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
260263660c0SAlfonso Siciliano 			if (datetime_checksize(h, w, MINWTIME, bs) != 0)
261263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
262f499134dSBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
263263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
264f499134dSBaptiste Daroussin 
265263660c0SAlfonso Siciliano 			if (update_dialog(conf, shadow, widget, y, x, h, w,
266263660c0SAlfonso Siciliano 			    textpad, text, &bs, true) != 0)
267263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
268f499134dSBaptiste Daroussin 
269263660c0SAlfonso Siciliano 			doupdate();
270f499134dSBaptiste Daroussin 
271f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 - 3, ':');
272f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 + 2, ':');
273f499134dSBaptiste Daroussin 			wrefresh(widget);
274f499134dSBaptiste Daroussin 
275f499134dSBaptiste Daroussin 			prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
276f499134dSBaptiste Daroussin 
277f499134dSBaptiste Daroussin 			wclear(c[0].win);
278f499134dSBaptiste Daroussin 			mvwin(c[0].win, y + h - 6, x + w/2 - 7);
279f499134dSBaptiste Daroussin 			wclear(c[1].win);
280f499134dSBaptiste Daroussin 			mvwin(c[1].win, y + h - 6, x + w/2 - 2);
281f499134dSBaptiste Daroussin 			wclear(c[2].win);
282f499134dSBaptiste Daroussin 			mvwin(c[2].win, y + h - 6, x + w/2 + 3);
283f499134dSBaptiste Daroussin 
284f499134dSBaptiste Daroussin 			/* Important to avoid grey lines expanding screen */
285f499134dSBaptiste Daroussin 			refresh();
286f499134dSBaptiste Daroussin 			break;
287f499134dSBaptiste Daroussin 		default:
288263660c0SAlfonso Siciliano 			if (shortcut_buttons(input, &bs)) {
289*b319d934SAlfonso S. Siciliano 				retval = bs.value[bs.curr];
290f499134dSBaptiste Daroussin 				loop = false;
291f499134dSBaptiste Daroussin 			}
292c76f0793SBaptiste Daroussin 		}
293c76f0793SBaptiste Daroussin 	}
294c76f0793SBaptiste Daroussin 
295*b319d934SAlfonso S. Siciliano 	if (retval == BSDDIALOG_OK) {
296bce40c02SAlfonso S. Siciliano 		*hh = c[0].value;
297bce40c02SAlfonso S. Siciliano 		*mm = c[1].value;
298bce40c02SAlfonso S. Siciliano 		*ss = c[2].value;
299bce40c02SAlfonso S. Siciliano 	}
300bce40c02SAlfonso S. Siciliano 
301c76f0793SBaptiste Daroussin 	for (i = 0; i < 3; i++)
302c76f0793SBaptiste Daroussin 		delwin(c[i].win);
303263660c0SAlfonso Siciliano 	end_dialog(conf, shadow, widget, textpad);
304c76f0793SBaptiste Daroussin 
305*b319d934SAlfonso S. Siciliano 	return (retval);
306c76f0793SBaptiste Daroussin }
307c76f0793SBaptiste Daroussin 
308f499134dSBaptiste Daroussin int
309263660c0SAlfonso Siciliano bsddialog_datebox(struct bsddialog_conf *conf, const char *text, int rows,
310263660c0SAlfonso Siciliano     int cols, unsigned int *yy, unsigned int *mm, unsigned int *dd)
311c76f0793SBaptiste Daroussin {
312bce40c02SAlfonso S. Siciliano 	bool loop, focusbuttons;
313*b319d934SAlfonso S. Siciliano 	int i, retval, y, x, h, w, sel;
314*b319d934SAlfonso S. Siciliano 	wint_t input;
315263660c0SAlfonso Siciliano 	WINDOW *widget, *textpad, *shadow;
316263660c0SAlfonso Siciliano 	struct buttons bs;
317c76f0793SBaptiste Daroussin 	struct calendar {
318f499134dSBaptiste Daroussin 		int max;
319f499134dSBaptiste Daroussin 		int value;
320c76f0793SBaptiste Daroussin 		WINDOW *win;
321c76f0793SBaptiste Daroussin 		unsigned int x;
322f499134dSBaptiste Daroussin 	};
323c76f0793SBaptiste Daroussin 	struct month {
324bce40c02SAlfonso S. Siciliano 		const char *name;
325c76f0793SBaptiste Daroussin 		unsigned int days;
326c76f0793SBaptiste Daroussin 	};
327c76f0793SBaptiste Daroussin 
328f499134dSBaptiste Daroussin 	if (yy == NULL || mm == NULL || dd == NULL)
329f499134dSBaptiste Daroussin 		RETURN_ERROR("yy / mm / dd cannot be NULL");
330c76f0793SBaptiste Daroussin 
331f499134dSBaptiste Daroussin 	struct calendar c[3] = {
332f499134dSBaptiste Daroussin 		{9999, *yy, NULL, 4 },
333f499134dSBaptiste Daroussin 		{12,   *mm, NULL, 9 },
334f499134dSBaptiste Daroussin 		{31,   *dd, NULL, 2 }
335f499134dSBaptiste Daroussin 	};
336c76f0793SBaptiste Daroussin 
337f499134dSBaptiste Daroussin 	struct month m[12] = {
338f499134dSBaptiste Daroussin 		{ "January", 31 }, { "February", 28 }, { "March",     31 },
339f499134dSBaptiste Daroussin 		{ "April",   30 }, { "May",      31 }, { "June",      30 },
340f499134dSBaptiste Daroussin 		{ "July",    31 }, { "August",   31 }, { "September", 30 },
341f499134dSBaptiste Daroussin 		{ "October", 31 }, { "November", 30 }, { "December",  31 }
342f499134dSBaptiste Daroussin 	};
343f499134dSBaptiste Daroussin 
344f499134dSBaptiste Daroussin #define ISLEAF(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
345f499134dSBaptiste Daroussin 
346f499134dSBaptiste Daroussin 	for (i = 0 ; i < 3; i++) {
347f499134dSBaptiste Daroussin 		if (c[i].value > c[i].max)
348f499134dSBaptiste Daroussin 			c[i].value = c[i].max;
349f499134dSBaptiste Daroussin 		if (c[i].value < 1)
350f499134dSBaptiste Daroussin 			c[i].value = 1;
351f499134dSBaptiste Daroussin 	}
352f499134dSBaptiste Daroussin 	c[2].max = m[c[1].value -1].days;
353f499134dSBaptiste Daroussin 	if (c[1].value == 2 && ISLEAF(c[0].value))
354f499134dSBaptiste Daroussin 		c[2].max = 29;
355f499134dSBaptiste Daroussin 	if (c[2].value > c[2].max)
356f499134dSBaptiste Daroussin 		c[2].value = c[2].max;
357c76f0793SBaptiste Daroussin 
358263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, BUTTON_OK_LABEL, BUTTON_CANCEL_LABEL);
359c76f0793SBaptiste Daroussin 
360f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
361263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
362263660c0SAlfonso Siciliano 	if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text,
363263660c0SAlfonso Siciliano 	    bs) != 0)
364263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
365263660c0SAlfonso Siciliano 	if (datetime_checksize(h, w, MINWDATE, bs) != 0)
366263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
367f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
368263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
369f499134dSBaptiste Daroussin 
370263660c0SAlfonso Siciliano 	if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
371263660c0SAlfonso Siciliano 	    true) != 0)
372263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
373f499134dSBaptiste Daroussin 
374263660c0SAlfonso Siciliano 	pnoutrefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
375263660c0SAlfonso Siciliano 	doupdate();
376f499134dSBaptiste Daroussin 
377f499134dSBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y+h-6, x + w/2 - 11, 3, 6, LOWERED);
378f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 - 5, '/');
379f499134dSBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y+h-6, x + w/2 - 4, 3, 11, LOWERED);
380f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 + 7, '/');
381f499134dSBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y+h-6, x + w/2 + 8, 3, 4, LOWERED);
382f499134dSBaptiste Daroussin 
383f499134dSBaptiste Daroussin 	wrefresh(widget);
384f499134dSBaptiste Daroussin 
385*b319d934SAlfonso S. Siciliano 	sel = -1;
386bce40c02SAlfonso S. Siciliano 	loop = focusbuttons = true;
387c76f0793SBaptiste Daroussin 	while (loop) {
388*b319d934SAlfonso S. Siciliano 		drawquare(conf, c[0].win, "%4d", &c[0].value, sel == 0);
389*b319d934SAlfonso S. Siciliano 		drawquare(conf, c[1].win, "%9s", m[c[1].value-1].name,
390*b319d934SAlfonso S. Siciliano 		    sel == 1);
391*b319d934SAlfonso S. Siciliano 		drawquare(conf, c[2].win, "%02d", &c[2].value, sel == 2);
392c76f0793SBaptiste Daroussin 
393*b319d934SAlfonso S. Siciliano 		if (get_wch(&input) == ERR)
394*b319d934SAlfonso S. Siciliano 			continue;
395c76f0793SBaptiste Daroussin 		switch(input) {
396f499134dSBaptiste Daroussin 		case KEY_ENTER:
397f499134dSBaptiste Daroussin 		case 10: /* Enter */
398*b319d934SAlfonso S. Siciliano 			if (focusbuttons || conf->button.always_active) {
399*b319d934SAlfonso S. Siciliano 				retval = bs.value[bs.curr];
400c76f0793SBaptiste Daroussin 				loop = false;
401*b319d934SAlfonso S. Siciliano 			}
402c76f0793SBaptiste Daroussin 			break;
403f499134dSBaptiste Daroussin 		case 27: /* Esc */
404263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
405*b319d934SAlfonso S. Siciliano 				retval = BSDDIALOG_ESC;
406c76f0793SBaptiste Daroussin 				loop = false;
407263660c0SAlfonso Siciliano 			}
408c76f0793SBaptiste Daroussin 			break;
409bce40c02SAlfonso S. Siciliano 		case KEY_RIGHT:
410f499134dSBaptiste Daroussin 		case '\t': /* TAB */
411bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
412bce40c02SAlfonso S. Siciliano 				bs.curr++;
413bce40c02SAlfonso S. Siciliano 				focusbuttons = bs.curr < (int)bs.nbuttons ?
414bce40c02SAlfonso S. Siciliano 				    true : false;
415bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
416bce40c02SAlfonso S. Siciliano 					sel = 0;
417*b319d934SAlfonso S. Siciliano 					bs.curr = conf->button.always_active ? 0 : -1;
418bce40c02SAlfonso S. Siciliano 				}
419bce40c02SAlfonso S. Siciliano 			} else {
420bce40c02SAlfonso S. Siciliano 				sel++;
421bce40c02SAlfonso S. Siciliano 				focusbuttons = sel > 2 ? true : false;
422bce40c02SAlfonso S. Siciliano 				if (focusbuttons) {
423bce40c02SAlfonso S. Siciliano 					bs.curr = 0;
424bce40c02SAlfonso S. Siciliano 				}
425bce40c02SAlfonso S. Siciliano 			}
426263660c0SAlfonso Siciliano 			draw_buttons(widget, bs, true);
427263660c0SAlfonso Siciliano 			wrefresh(widget);
428c76f0793SBaptiste Daroussin 			break;
429c76f0793SBaptiste Daroussin 		case KEY_LEFT:
430bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
431bce40c02SAlfonso S. Siciliano 				bs.curr--;
432bce40c02SAlfonso S. Siciliano 				focusbuttons = bs.curr < 0 ? false : true;
433bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
434bce40c02SAlfonso S. Siciliano 					sel = 2;
435*b319d934SAlfonso S. Siciliano 					bs.curr = conf->button.always_active ? 0 : -1;
436bce40c02SAlfonso S. Siciliano 				}
437bce40c02SAlfonso S. Siciliano 			} else {
438bce40c02SAlfonso S. Siciliano 				sel--;
439bce40c02SAlfonso S. Siciliano 				focusbuttons = sel < 0 ? true : false;
440*b319d934SAlfonso S. Siciliano 				if (focusbuttons)
441bce40c02SAlfonso S. Siciliano 					bs.curr = (int)bs.nbuttons - 1;
442bce40c02SAlfonso S. Siciliano 			}
443bce40c02SAlfonso S. Siciliano 			draw_buttons(widget, bs, true);
444bce40c02SAlfonso S. Siciliano 			wrefresh(widget);
445c76f0793SBaptiste Daroussin 			break;
446c76f0793SBaptiste Daroussin 		case KEY_UP:
447*b319d934SAlfonso S. Siciliano 			if (focusbuttons) {
448*b319d934SAlfonso S. Siciliano 				sel = 0;
449*b319d934SAlfonso S. Siciliano 				focusbuttons = false;
450*b319d934SAlfonso S. Siciliano 				bs.curr = conf->button.always_active ? 0 : -1;
451*b319d934SAlfonso S. Siciliano 				draw_buttons(widget, bs, true);
452*b319d934SAlfonso S. Siciliano 				wrefresh(widget);
453*b319d934SAlfonso S. Siciliano 			} else {
454263660c0SAlfonso Siciliano 				c[sel].value = c[sel].value > 1 ?
455263660c0SAlfonso Siciliano 				    c[sel].value - 1 : c[sel].max ;
456f499134dSBaptiste Daroussin 				/* if mount change */
457f499134dSBaptiste Daroussin 				c[2].max = m[c[1].value -1].days;
458f499134dSBaptiste Daroussin 				/* if year change */
459f499134dSBaptiste Daroussin 				if (c[1].value == 2 && ISLEAF(c[0].value))
460f499134dSBaptiste Daroussin 					c[2].max = 29;
461f499134dSBaptiste Daroussin 				/* set new day */
462f499134dSBaptiste Daroussin 				if (c[2].value > c[2].max)
463f499134dSBaptiste Daroussin 					c[2].value = c[2].max;
464*b319d934SAlfonso S. Siciliano 			}
465c76f0793SBaptiste Daroussin 			break;
466c76f0793SBaptiste Daroussin 		case KEY_DOWN:
467bce40c02SAlfonso S. Siciliano 			if (focusbuttons)
468bce40c02SAlfonso S. Siciliano 				break;
469263660c0SAlfonso Siciliano 			c[sel].value = c[sel].value < c[sel].max ?
470263660c0SAlfonso Siciliano 			    c[sel].value + 1 : 1;
471f499134dSBaptiste Daroussin 			/* if mount change */
472f499134dSBaptiste Daroussin 			c[2].max = m[c[1].value -1].days;
473f499134dSBaptiste Daroussin 			/* if year change */
474f499134dSBaptiste Daroussin 			if (c[1].value == 2 && ISLEAF(c[0].value))
475f499134dSBaptiste Daroussin 				c[2].max = 29;
476f499134dSBaptiste Daroussin 			/* set new day */
477f499134dSBaptiste Daroussin 			if (c[2].value > c[2].max)
478f499134dSBaptiste Daroussin 				c[2].value = c[2].max;
479c76f0793SBaptiste Daroussin 			break;
480f499134dSBaptiste Daroussin 		case KEY_F(1):
481bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
482bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
483f499134dSBaptiste Daroussin 				break;
484f499134dSBaptiste Daroussin 			if (f1help(conf) != 0)
485263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
486263660c0SAlfonso Siciliano 			/* No break, screen size can change */
487f499134dSBaptiste Daroussin 		case KEY_RESIZE:
488263660c0SAlfonso Siciliano 			/* Important for decreasing screen */
489f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w, conf->shadow);
490f499134dSBaptiste Daroussin 			refresh();
491f499134dSBaptiste Daroussin 
492f499134dSBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
493263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
494263660c0SAlfonso Siciliano 			if (datetime_autosize(conf, rows, cols, &h, &w,
495263660c0SAlfonso Siciliano 			    MINWDATE, text, bs) != 0)
496263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
497263660c0SAlfonso Siciliano 			if (datetime_checksize(h, w, MINWDATE, bs) != 0)
498263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
499f499134dSBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
500263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
501f499134dSBaptiste Daroussin 
502263660c0SAlfonso Siciliano 			if (update_dialog(conf, shadow, widget, y, x, h, w,
503263660c0SAlfonso Siciliano 			    textpad, text, &bs, true) != 0)
504263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
505263660c0SAlfonso Siciliano 			doupdate();
506f499134dSBaptiste Daroussin 
507f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 - 5, '/');
508f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 + 7, '/');
509f499134dSBaptiste Daroussin 			wrefresh(widget);
510f499134dSBaptiste Daroussin 
511f499134dSBaptiste Daroussin 			prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
512f499134dSBaptiste Daroussin 
513f499134dSBaptiste Daroussin 			wclear(c[0].win);
514f499134dSBaptiste Daroussin 			mvwin(c[0].win, y + h - 6, x + w/2 - 11);
515f499134dSBaptiste Daroussin 			wclear(c[1].win);
516f499134dSBaptiste Daroussin 			mvwin(c[1].win, y + h - 6, x + w/2 - 4);
517f499134dSBaptiste Daroussin 			wclear(c[2].win);
518f499134dSBaptiste Daroussin 			mvwin(c[2].win, y + h - 6, x + w/2 + 8);
519f499134dSBaptiste Daroussin 
520f499134dSBaptiste Daroussin 			/* Important to avoid grey lines expanding screen */
521f499134dSBaptiste Daroussin 			refresh();
522f499134dSBaptiste Daroussin 			break;
523f499134dSBaptiste Daroussin 		default:
524263660c0SAlfonso Siciliano 			if (shortcut_buttons(input, &bs)) {
525*b319d934SAlfonso S. Siciliano 				retval = bs.value[bs.curr];
526f499134dSBaptiste Daroussin 				loop = false;
527f499134dSBaptiste Daroussin 			}
528c76f0793SBaptiste Daroussin 		}
529c76f0793SBaptiste Daroussin 	}
530c76f0793SBaptiste Daroussin 
531*b319d934SAlfonso S. Siciliano 	if (retval == BSDDIALOG_OK) {
532bce40c02SAlfonso S. Siciliano 		*yy = c[0].value;
533bce40c02SAlfonso S. Siciliano 		*mm = c[1].value;
534bce40c02SAlfonso S. Siciliano 		*dd = c[2].value;
535bce40c02SAlfonso S. Siciliano 	}
536bce40c02SAlfonso S. Siciliano 
537c76f0793SBaptiste Daroussin 	for (i = 0; i < 3; i++)
538c76f0793SBaptiste Daroussin 		delwin(c[i].win);
539263660c0SAlfonso Siciliano 	end_dialog(conf, shadow, widget, textpad);
540c76f0793SBaptiste Daroussin 
541*b319d934SAlfonso S. Siciliano 	return (retval);
542c76f0793SBaptiste Daroussin }
543