xref: /freebsd-src/contrib/bsddialog/lib/timebox.c (revision d93b4d32034df7cd70e80b496e8fe8c1bc57c629)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4c76f0793SBaptiste Daroussin  * Copyright (c) 2021 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 
30*d93b4d32SBaptiste Daroussin #include <ctype.h>
31c76f0793SBaptiste Daroussin #ifdef PORTNCURSES
328c4f4028SBaptiste Daroussin #include <ncurses/ncurses.h>
33c76f0793SBaptiste Daroussin #else
348c4f4028SBaptiste Daroussin #include <ncurses.h>
35c76f0793SBaptiste Daroussin #endif
36f499134dSBaptiste Daroussin #include <string.h>
37f499134dSBaptiste Daroussin 
38c76f0793SBaptiste Daroussin #include "bsddialog.h"
39c76f0793SBaptiste Daroussin #include "lib_util.h"
40f499134dSBaptiste Daroussin #include "bsddialog_theme.h"
41c76f0793SBaptiste Daroussin 
42f499134dSBaptiste Daroussin #define MINWDATE 25 /* 23 wins + 2 VBORDERS */
43f499134dSBaptiste Daroussin #define MINWTIME 16 /*14 wins + 2 VBORDERS */
44f499134dSBaptiste Daroussin #define MINHEIGHT 8 /* 2 for text */
45c76f0793SBaptiste Daroussin 
46f499134dSBaptiste Daroussin /* "Time": timebox - datebox */
47f499134dSBaptiste Daroussin 
48f499134dSBaptiste Daroussin extern struct bsddialog_theme t;
49f499134dSBaptiste Daroussin 
50f499134dSBaptiste Daroussin static int
51f499134dSBaptiste Daroussin datetime_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
52f499134dSBaptiste Daroussin     int *w, int minw, char *text, struct buttons bs)
53f499134dSBaptiste Daroussin {
54f499134dSBaptiste Daroussin 	int maxword, maxline, nlines, line;
55f499134dSBaptiste Daroussin 
56f499134dSBaptiste Daroussin 	if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
57f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
58f499134dSBaptiste Daroussin 
59f499134dSBaptiste Daroussin 	if (cols == BSDDIALOG_AUTOSIZE) {
60f499134dSBaptiste Daroussin 		*w = VBORDERS;
61f499134dSBaptiste Daroussin 		/* buttons size */
62f499134dSBaptiste Daroussin 		*w += bs.nbuttons * bs.sizebutton;
63f499134dSBaptiste Daroussin 		*w += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
64f499134dSBaptiste Daroussin 		/* text size */
65f499134dSBaptiste Daroussin 		line = maxline + VBORDERS + t.text.hmargin * 2;
66f499134dSBaptiste Daroussin 		line = MAX(line, (int) (maxword + VBORDERS + t.text.hmargin * 2));
67f499134dSBaptiste Daroussin 		*w = MAX(*w, line);
68f499134dSBaptiste Daroussin 		/* date windows */
69f499134dSBaptiste Daroussin 		*w = MAX(*w, minw);
708c4f4028SBaptiste Daroussin 		/* conf.auto_minwidth */
718c4f4028SBaptiste Daroussin 		*w = MAX(*w, (int)conf->auto_minwidth);
72f499134dSBaptiste Daroussin 		/* avoid terminal overflow */
73f499134dSBaptiste Daroussin 		*w = MIN(*w, widget_max_width(conf) -1);
74f499134dSBaptiste Daroussin 	}
75f499134dSBaptiste Daroussin 
76f499134dSBaptiste Daroussin 	if (rows == BSDDIALOG_AUTOSIZE) {
77f499134dSBaptiste Daroussin 		*h = MINHEIGHT;
78f499134dSBaptiste Daroussin 		if (maxword > 0)
798c4f4028SBaptiste Daroussin 			*h += MAX(nlines, (int)(*w / GET_ASPECT_RATIO(conf)));
808c4f4028SBaptiste Daroussin 		/* conf.auto_minheight */
818c4f4028SBaptiste Daroussin 		*h = MAX(*h, (int)conf->auto_minheight);
82f499134dSBaptiste Daroussin 		/* avoid terminal overflow */
83f499134dSBaptiste Daroussin 		*h = MIN(*h, widget_max_height(conf) -1);
84f499134dSBaptiste Daroussin 	}
85f499134dSBaptiste Daroussin 
86f499134dSBaptiste Daroussin 	return 0;
87f499134dSBaptiste Daroussin }
88f499134dSBaptiste Daroussin 
89f499134dSBaptiste Daroussin static int
90f499134dSBaptiste Daroussin datetime_checksize(int rows, int cols, char *text, int minw, struct buttons bs)
91f499134dSBaptiste Daroussin {
92f499134dSBaptiste Daroussin 	int mincols;
93f499134dSBaptiste Daroussin 
94f499134dSBaptiste Daroussin 	mincols = VBORDERS;
95f499134dSBaptiste Daroussin 	mincols += bs.nbuttons * bs.sizebutton;
96f499134dSBaptiste Daroussin 	mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
97f499134dSBaptiste Daroussin 	mincols = MAX(minw, mincols);
98f499134dSBaptiste Daroussin 
99f499134dSBaptiste Daroussin 	if (cols < mincols)
100f499134dSBaptiste Daroussin 		RETURN_ERROR("Few cols for this timebox/datebox");
101f499134dSBaptiste Daroussin 
102f499134dSBaptiste Daroussin 	if (rows < MINHEIGHT + (strlen(text) > 0 ? 1 : 0))
103f499134dSBaptiste Daroussin 		RETURN_ERROR("Few rows for this timebox/datebox");
104f499134dSBaptiste Daroussin 
105f499134dSBaptiste Daroussin 	return 0;
106f499134dSBaptiste Daroussin }
107f499134dSBaptiste Daroussin 
108f499134dSBaptiste Daroussin int bsddialog_timebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
109c76f0793SBaptiste Daroussin     unsigned int *hh, unsigned int *mm, unsigned int *ss)
110c76f0793SBaptiste Daroussin {
111f499134dSBaptiste Daroussin 	WINDOW *widget, *textpad, *shadow;
112f499134dSBaptiste Daroussin 	int i, input, output, y, x, h, w, sel, htextpad;
113c76f0793SBaptiste Daroussin 	struct buttons bs;
114f499134dSBaptiste Daroussin 	bool loop;
115c76f0793SBaptiste Daroussin 	struct myclockstruct {
116c76f0793SBaptiste Daroussin 		unsigned int max;
117f499134dSBaptiste Daroussin 		unsigned int value;
118c76f0793SBaptiste Daroussin 		WINDOW *win;
119f499134dSBaptiste Daroussin 	};
120c76f0793SBaptiste Daroussin 
121f499134dSBaptiste Daroussin 	if (hh == NULL || mm == NULL || ss == NULL)
122f499134dSBaptiste Daroussin 		RETURN_ERROR("hh / mm / ss cannot be NULL");
123c76f0793SBaptiste Daroussin 
124f499134dSBaptiste Daroussin 	struct myclockstruct c[3] = {
125f499134dSBaptiste Daroussin 		{23, *hh, NULL},
126f499134dSBaptiste Daroussin 		{59, *mm, NULL},
127f499134dSBaptiste Daroussin 		{59, *ss, NULL}
128f499134dSBaptiste Daroussin 	};
129f499134dSBaptiste Daroussin 
130f499134dSBaptiste Daroussin 	for (i = 0 ; i < 3; i++) {
131f499134dSBaptiste Daroussin 		if (c[i].value > c[i].max)
132f499134dSBaptiste Daroussin 			c[i].value = c[i].max;
133f499134dSBaptiste Daroussin 	}
134c76f0793SBaptiste Daroussin 
135c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
136c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
137c76f0793SBaptiste Daroussin 
138f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
139f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
140f499134dSBaptiste Daroussin 	if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text, bs) != 0)
141f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
142f499134dSBaptiste Daroussin 	if (datetime_checksize(h, w, text, MINWTIME, bs) != 0)
143f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
144f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
145f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
146f499134dSBaptiste Daroussin 
147f499134dSBaptiste Daroussin 	if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
148f499134dSBaptiste Daroussin 	    &textpad, &htextpad, text, true) != 0)
149f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
150f499134dSBaptiste Daroussin 
151f499134dSBaptiste Daroussin 	draw_buttons(widget, h-2, w, bs, true);
152f499134dSBaptiste Daroussin 
153f499134dSBaptiste Daroussin 	wrefresh(widget);
154f499134dSBaptiste Daroussin 
155f499134dSBaptiste Daroussin 	prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
156f499134dSBaptiste Daroussin 
157f499134dSBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y + h - 6, x + w/2 - 7, 3, 4, LOWERED);
158f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 - 3, ':');
159f499134dSBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y + h - 6, x + w/2 - 2, 3, 4, LOWERED);
160f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 + 2, ':');
161f499134dSBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y + h - 6, x + w/2 + 3, 3, 4, LOWERED);
162f499134dSBaptiste Daroussin 
163f499134dSBaptiste Daroussin 	wrefresh(widget);
164f499134dSBaptiste Daroussin 
165c76f0793SBaptiste Daroussin 	sel = 0;
166c76f0793SBaptiste Daroussin 	curs_set(2);
167f499134dSBaptiste Daroussin 	loop = true;
168c76f0793SBaptiste Daroussin 	while(loop) {
169c76f0793SBaptiste Daroussin 		for (i=0; i<3; i++) {
170f499134dSBaptiste Daroussin 			mvwprintw(c[i].win, 1, 1, "%2d", c[i].value);
171c76f0793SBaptiste Daroussin 			wrefresh(c[i].win);
172c76f0793SBaptiste Daroussin 		}
173c76f0793SBaptiste Daroussin 		wmove(c[sel].win, 1, 2);
174c76f0793SBaptiste Daroussin 		wrefresh(c[sel].win);
175c76f0793SBaptiste Daroussin 
176c76f0793SBaptiste Daroussin 		input = getch();
177c76f0793SBaptiste Daroussin 		switch(input) {
178f499134dSBaptiste Daroussin 		case KEY_ENTER:
179c76f0793SBaptiste Daroussin 		case 10: /* Enter */
180c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
1818c4f4028SBaptiste Daroussin 			if (output == BSDDIALOG_OK) {
182f499134dSBaptiste Daroussin 				*hh = c[0].value;
183f499134dSBaptiste Daroussin 				*mm = c[1].value;
184f499134dSBaptiste Daroussin 				*ss = c[2].value;
185c76f0793SBaptiste Daroussin 			}
186c76f0793SBaptiste Daroussin 			loop = false;
187c76f0793SBaptiste Daroussin 			break;
188c76f0793SBaptiste Daroussin 		case 27: /* Esc */
189c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
190c76f0793SBaptiste Daroussin 			loop = false;
191c76f0793SBaptiste Daroussin 			break;
192c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
193c76f0793SBaptiste Daroussin 			sel = (sel + 1) % 3;
194c76f0793SBaptiste Daroussin 			break;
195c76f0793SBaptiste Daroussin 		case KEY_LEFT:
196c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
197c76f0793SBaptiste Daroussin 				bs.curr--;
198f499134dSBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, true);
199f499134dSBaptiste Daroussin 				wrefresh(widget);
200c76f0793SBaptiste Daroussin 			}
201c76f0793SBaptiste Daroussin 			break;
202c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
203c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
204c76f0793SBaptiste Daroussin 				bs.curr++;
205f499134dSBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, true);
206f499134dSBaptiste Daroussin 				wrefresh(widget);
207c76f0793SBaptiste Daroussin 			}
208c76f0793SBaptiste Daroussin 			break;
209c76f0793SBaptiste Daroussin 		case KEY_UP:
210f499134dSBaptiste Daroussin 			c[sel].value = c[sel].value < c[sel].max ? c[sel].value + 1 : 0;
211c76f0793SBaptiste Daroussin 			break;
212c76f0793SBaptiste Daroussin 		case KEY_DOWN:
213f499134dSBaptiste Daroussin 			c[sel].value = c[sel].value > 0 ? c[sel].value - 1 : c[sel].max;
214c76f0793SBaptiste Daroussin 			break;
215f499134dSBaptiste Daroussin 		case KEY_F(1):
2168c4f4028SBaptiste Daroussin 			if (conf->f1_file == NULL && conf->f1_message == NULL)
217f499134dSBaptiste Daroussin 				break;
218f499134dSBaptiste Daroussin 			curs_set(0);
219f499134dSBaptiste Daroussin 			if (f1help(conf) != 0)
220f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
221f499134dSBaptiste Daroussin 			curs_set(2);
222f499134dSBaptiste Daroussin 			/* No break! the terminal size can change */
223f499134dSBaptiste Daroussin 		case KEY_RESIZE:
224f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w,conf->shadow);
225f499134dSBaptiste Daroussin 
226f499134dSBaptiste Daroussin 			/*
227f499134dSBaptiste Daroussin 			 * Unnecessary, but, when the columns decrease the
228f499134dSBaptiste Daroussin 			 * following "refresh" seem not work
229f499134dSBaptiste Daroussin 			 */
230f499134dSBaptiste Daroussin 			refresh();
231f499134dSBaptiste Daroussin 
232f499134dSBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
233f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
234f499134dSBaptiste Daroussin 			if (datetime_autosize(conf, rows, cols, &h, &w, MINWTIME, text, bs) != 0)
235f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
236f499134dSBaptiste Daroussin 			if (datetime_checksize(h, w, text, MINWTIME, bs) != 0)
237f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
238f499134dSBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
239f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
240f499134dSBaptiste Daroussin 
241f499134dSBaptiste Daroussin 			wclear(shadow);
242f499134dSBaptiste Daroussin 			mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
243f499134dSBaptiste Daroussin 			wresize(shadow, h, w);
244f499134dSBaptiste Daroussin 
245f499134dSBaptiste Daroussin 			wclear(widget);
246f499134dSBaptiste Daroussin 			mvwin(widget, y, x);
247f499134dSBaptiste Daroussin 			wresize(widget, h, w);
248f499134dSBaptiste Daroussin 
249f499134dSBaptiste Daroussin 			htextpad = 1;
250f499134dSBaptiste Daroussin 			wclear(textpad);
251f499134dSBaptiste Daroussin 			wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
252f499134dSBaptiste Daroussin 
253f499134dSBaptiste Daroussin 			if(update_widget_withtextpad(conf, shadow, widget, h, w,
254f499134dSBaptiste Daroussin 			    RAISED, textpad, &htextpad, text, true) != 0)
255f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
256f499134dSBaptiste Daroussin 
257f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 - 3, ':');
258f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 + 2, ':');
259f499134dSBaptiste Daroussin 
260f499134dSBaptiste Daroussin 			draw_buttons(widget, h-2, w, bs, true);
261f499134dSBaptiste Daroussin 
262f499134dSBaptiste Daroussin 			wrefresh(widget);
263f499134dSBaptiste Daroussin 
264f499134dSBaptiste Daroussin 			prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
265f499134dSBaptiste Daroussin 
266f499134dSBaptiste Daroussin 			wclear(c[0].win);
267f499134dSBaptiste Daroussin 			mvwin(c[0].win, y + h - 6, x + w/2 - 7);
268f499134dSBaptiste Daroussin 			draw_borders(conf, c[0].win, 3, 4, LOWERED);
269f499134dSBaptiste Daroussin 			wrefresh(c[0].win);
270f499134dSBaptiste Daroussin 
271f499134dSBaptiste Daroussin 			wclear(c[1].win);
272f499134dSBaptiste Daroussin 			mvwin(c[1].win, y + h - 6, x + w/2 - 2);
273f499134dSBaptiste Daroussin 			draw_borders(conf, c[1].win, 3, 4, LOWERED);
274f499134dSBaptiste Daroussin 			wrefresh(c[1].win);
275f499134dSBaptiste Daroussin 
276f499134dSBaptiste Daroussin 			wclear(c[2].win);
277f499134dSBaptiste Daroussin 			mvwin(c[2].win, y + h - 6, x + w/2 + 3);
278f499134dSBaptiste Daroussin 			draw_borders(conf, c[2].win, 3, 4, LOWERED);
279f499134dSBaptiste Daroussin 			wrefresh(c[2].win);
280f499134dSBaptiste Daroussin 
281f499134dSBaptiste Daroussin 			/* Important to avoid grey lines expanding screen */
282f499134dSBaptiste Daroussin 			refresh();
283f499134dSBaptiste Daroussin 			break;
284f499134dSBaptiste Daroussin 		default:
285f499134dSBaptiste Daroussin 			for (i = 0; i < (int) bs.nbuttons; i++)
286f499134dSBaptiste Daroussin 				if (tolower(input) == tolower((bs.label[i])[0])) {
287f499134dSBaptiste Daroussin 					output = bs.value[i];
288f499134dSBaptiste Daroussin 					loop = false;
289f499134dSBaptiste Daroussin 			}
290c76f0793SBaptiste Daroussin 		}
291c76f0793SBaptiste Daroussin 	}
292c76f0793SBaptiste Daroussin 
293c76f0793SBaptiste Daroussin 	curs_set(0);
294c76f0793SBaptiste Daroussin 
295c76f0793SBaptiste Daroussin 	for (i=0; i<3; i++)
296c76f0793SBaptiste Daroussin 		delwin(c[i].win);
297f499134dSBaptiste Daroussin 	end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
298c76f0793SBaptiste Daroussin 
299c76f0793SBaptiste Daroussin 	return output;
300c76f0793SBaptiste Daroussin }
301c76f0793SBaptiste Daroussin 
302f499134dSBaptiste Daroussin int
303f499134dSBaptiste Daroussin bsddialog_datebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
304c76f0793SBaptiste Daroussin     unsigned int *yy, unsigned int *mm, unsigned int *dd)
305c76f0793SBaptiste Daroussin {
306f499134dSBaptiste Daroussin 	WINDOW *widget, *textpad, *shadow;
307f499134dSBaptiste Daroussin 	int i, input, output, y, x, h, w, sel, htextpad;
308c76f0793SBaptiste Daroussin 	struct buttons bs;
309f499134dSBaptiste Daroussin 	bool loop;
310c76f0793SBaptiste Daroussin 	struct calendar {
311f499134dSBaptiste Daroussin 		int max;
312f499134dSBaptiste Daroussin 		int value;
313c76f0793SBaptiste Daroussin 		WINDOW *win;
314c76f0793SBaptiste Daroussin 		unsigned int x;
315f499134dSBaptiste Daroussin 	};
316c76f0793SBaptiste Daroussin 	struct month {
317c76f0793SBaptiste Daroussin 		char *name;
318c76f0793SBaptiste Daroussin 		unsigned int days;
319c76f0793SBaptiste Daroussin 	};
320c76f0793SBaptiste Daroussin 
321f499134dSBaptiste Daroussin 	if (yy == NULL || mm == NULL || dd == NULL)
322f499134dSBaptiste Daroussin 		RETURN_ERROR("yy / mm / dd cannot be NULL");
323c76f0793SBaptiste Daroussin 
324f499134dSBaptiste Daroussin 	struct calendar c[3] = {
325f499134dSBaptiste Daroussin 		{9999, *yy, NULL, 4 },
326f499134dSBaptiste Daroussin 		{12,   *mm, NULL, 9 },
327f499134dSBaptiste Daroussin 		{31,   *dd, NULL, 2 }
328f499134dSBaptiste Daroussin 	};
329c76f0793SBaptiste Daroussin 
330f499134dSBaptiste Daroussin 	struct month m[12] = {
331f499134dSBaptiste Daroussin 		{ "January", 31 }, { "February", 28 }, { "March",     31 },
332f499134dSBaptiste Daroussin 		{ "April",   30 }, { "May",      31 }, { "June",      30 },
333f499134dSBaptiste Daroussin 		{ "July",    31 }, { "August",   31 }, { "September", 30 },
334f499134dSBaptiste Daroussin 		{ "October", 31 }, { "November", 30 }, { "December",  31 }
335f499134dSBaptiste Daroussin 	};
336f499134dSBaptiste Daroussin 
337f499134dSBaptiste Daroussin #define ISLEAF(year) ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
338f499134dSBaptiste Daroussin 
339f499134dSBaptiste Daroussin 	for (i = 0 ; i < 3; i++) {
340f499134dSBaptiste Daroussin 		if (c[i].value > c[i].max)
341f499134dSBaptiste Daroussin 			c[i].value = c[i].max;
342f499134dSBaptiste Daroussin 		if (c[i].value < 1)
343f499134dSBaptiste Daroussin 			c[i].value = 1;
344f499134dSBaptiste Daroussin 	}
345f499134dSBaptiste Daroussin 	c[2].max = m[c[1].value -1].days;
346f499134dSBaptiste Daroussin 	if (c[1].value == 2 && ISLEAF(c[0].value))
347f499134dSBaptiste Daroussin 		c[2].max = 29;
348f499134dSBaptiste Daroussin 	if (c[2].value > c[2].max)
349f499134dSBaptiste Daroussin 		c[2].value = c[2].max;
350c76f0793SBaptiste Daroussin 
351c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
352c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
353c76f0793SBaptiste Daroussin 
354f499134dSBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
355f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
356f499134dSBaptiste Daroussin 	if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text, bs) != 0)
357f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
358f499134dSBaptiste Daroussin 	if (datetime_checksize(h, w, text, MINWDATE, bs) != 0)
359f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
360f499134dSBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
361f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
362f499134dSBaptiste Daroussin 
363f499134dSBaptiste Daroussin 	if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
364f499134dSBaptiste Daroussin 	    &textpad, &htextpad, text, true) != 0)
365f499134dSBaptiste Daroussin 		return BSDDIALOG_ERROR;
366f499134dSBaptiste Daroussin 
367f499134dSBaptiste Daroussin 	draw_buttons(widget, h-2, w, bs, true);
368f499134dSBaptiste Daroussin 
369f499134dSBaptiste Daroussin 	wrefresh(widget);
370f499134dSBaptiste Daroussin 
371f499134dSBaptiste Daroussin 	prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
372f499134dSBaptiste Daroussin 
373f499134dSBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y + h - 6, x + w/2 - 11, 3, 6, LOWERED);
374f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 - 5, '/');
375f499134dSBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y + h - 6, x + w/2 - 4, 3, 11, LOWERED);
376f499134dSBaptiste Daroussin 	mvwaddch(widget, h - 5, w/2 + 7, '/');
377f499134dSBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y + h - 6, x + w/2 + 8, 3, 4, LOWERED);
378f499134dSBaptiste Daroussin 
379f499134dSBaptiste Daroussin 	wrefresh(widget);
380f499134dSBaptiste Daroussin 
381c76f0793SBaptiste Daroussin 	sel = 2;
382c76f0793SBaptiste Daroussin 	curs_set(2);
383f499134dSBaptiste Daroussin 	loop = true;
384c76f0793SBaptiste Daroussin 	while(loop) {
385f499134dSBaptiste Daroussin 		mvwprintw(c[0].win, 1, 1, "%4d", c[0].value);
386f499134dSBaptiste Daroussin 		mvwprintw(c[1].win, 1, 1, "%9s", m[c[1].value-1].name);
387f499134dSBaptiste Daroussin 		mvwprintw(c[2].win, 1, 1, "%2d", c[2].value);
388c76f0793SBaptiste Daroussin 		for (i=0; i<3; i++) {
389c76f0793SBaptiste Daroussin 			wrefresh(c[i].win);
390c76f0793SBaptiste Daroussin 		}
391c76f0793SBaptiste Daroussin 		wmove(c[sel].win, 1, c[sel].x);
392c76f0793SBaptiste Daroussin 		wrefresh(c[sel].win);
393c76f0793SBaptiste Daroussin 
394c76f0793SBaptiste Daroussin 		input = getch();
395c76f0793SBaptiste Daroussin 		switch(input) {
396f499134dSBaptiste Daroussin 		case KEY_ENTER:
397f499134dSBaptiste Daroussin 		case 10: /* Enter */
398f499134dSBaptiste Daroussin 			output = bs.value[bs.curr];
3998c4f4028SBaptiste Daroussin 			if (output == BSDDIALOG_OK) {
400f499134dSBaptiste Daroussin 				*yy = c[0].value;
401f499134dSBaptiste Daroussin 				*mm = c[1].value;
402f499134dSBaptiste Daroussin 				*dd = c[2].value;
403c76f0793SBaptiste Daroussin 			}
404c76f0793SBaptiste Daroussin 			loop = false;
405c76f0793SBaptiste Daroussin 			break;
406f499134dSBaptiste Daroussin 		case 27: /* Esc */
407c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
408c76f0793SBaptiste Daroussin 			loop = false;
409c76f0793SBaptiste Daroussin 			break;
410f499134dSBaptiste Daroussin 		case '\t': /* TAB */
411c76f0793SBaptiste Daroussin 			sel = (sel + 1) % 3;
412c76f0793SBaptiste Daroussin 			break;
413c76f0793SBaptiste Daroussin 		case KEY_LEFT:
414c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
415c76f0793SBaptiste Daroussin 				bs.curr--;
416f499134dSBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, true);
417f499134dSBaptiste Daroussin 				wrefresh(widget);
418c76f0793SBaptiste Daroussin 			}
419c76f0793SBaptiste Daroussin 			break;
420c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
421c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
422c76f0793SBaptiste Daroussin 				bs.curr++;
423f499134dSBaptiste Daroussin 				draw_buttons(widget, h-2, w, bs, true);
424f499134dSBaptiste Daroussin 				wrefresh(widget);
425c76f0793SBaptiste Daroussin 			}
426c76f0793SBaptiste Daroussin 			break;
427c76f0793SBaptiste Daroussin 		case KEY_UP:
428f499134dSBaptiste Daroussin 			c[sel].value = c[sel].value > 1 ? c[sel].value - 1 : c[sel].max ;
429f499134dSBaptiste Daroussin 			/* if mount change */
430f499134dSBaptiste Daroussin 			c[2].max = m[c[1].value -1].days;
431f499134dSBaptiste Daroussin 			/* if year change */
432f499134dSBaptiste Daroussin 			if (c[1].value == 2 && ISLEAF(c[0].value))
433f499134dSBaptiste Daroussin 				c[2].max = 29;
434f499134dSBaptiste Daroussin 			/* set new day */
435f499134dSBaptiste Daroussin 			if (c[2].value > c[2].max)
436f499134dSBaptiste Daroussin 				c[2].value = c[2].max;
437c76f0793SBaptiste Daroussin 			break;
438c76f0793SBaptiste Daroussin 		case KEY_DOWN:
439f499134dSBaptiste Daroussin 			c[sel].value = c[sel].value < c[sel].max ? c[sel].value + 1 : 1;
440f499134dSBaptiste Daroussin 			/* if mount change */
441f499134dSBaptiste Daroussin 			c[2].max = m[c[1].value -1].days;
442f499134dSBaptiste Daroussin 			/* if year change */
443f499134dSBaptiste Daroussin 			if (c[1].value == 2 && ISLEAF(c[0].value))
444f499134dSBaptiste Daroussin 				c[2].max = 29;
445f499134dSBaptiste Daroussin 			/* set new day */
446f499134dSBaptiste Daroussin 			if (c[2].value > c[2].max)
447f499134dSBaptiste Daroussin 				c[2].value = c[2].max;
448c76f0793SBaptiste Daroussin 			break;
449f499134dSBaptiste Daroussin 		case KEY_F(1):
4508c4f4028SBaptiste Daroussin 			if (conf->f1_file == NULL && conf->f1_message == NULL)
451f499134dSBaptiste Daroussin 				break;
452f499134dSBaptiste Daroussin 			curs_set(0);
453f499134dSBaptiste Daroussin 			if (f1help(conf) != 0)
454f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
455f499134dSBaptiste Daroussin 			curs_set(2);
456f499134dSBaptiste Daroussin 			/* No break! the terminal size can change */
457f499134dSBaptiste Daroussin 		case KEY_RESIZE:
458f499134dSBaptiste Daroussin 			hide_widget(y, x, h, w,conf->shadow);
459f499134dSBaptiste Daroussin 
460f499134dSBaptiste Daroussin 			/*
461f499134dSBaptiste Daroussin 			 * Unnecessary, but, when the columns decrease the
462f499134dSBaptiste Daroussin 			 * following "refresh" seem not work
463f499134dSBaptiste Daroussin 			 */
464f499134dSBaptiste Daroussin 			refresh();
465f499134dSBaptiste Daroussin 
466f499134dSBaptiste Daroussin 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
467f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
468f499134dSBaptiste Daroussin 			if (datetime_autosize(conf, rows, cols, &h, &w, MINWDATE, text, bs) != 0)
469f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
470f499134dSBaptiste Daroussin 			if (datetime_checksize(h, w, text, MINWDATE, bs) != 0)
471f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
472f499134dSBaptiste Daroussin 			if (set_widget_position(conf, &y, &x, h, w) != 0)
473f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
474f499134dSBaptiste Daroussin 
475f499134dSBaptiste Daroussin 			wclear(shadow);
476f499134dSBaptiste Daroussin 			mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
477f499134dSBaptiste Daroussin 			wresize(shadow, h, w);
478f499134dSBaptiste Daroussin 
479f499134dSBaptiste Daroussin 			wclear(widget);
480f499134dSBaptiste Daroussin 			mvwin(widget, y, x);
481f499134dSBaptiste Daroussin 			wresize(widget, h, w);
482f499134dSBaptiste Daroussin 
483f499134dSBaptiste Daroussin 			htextpad = 1;
484f499134dSBaptiste Daroussin 			wclear(textpad);
485f499134dSBaptiste Daroussin 			wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
486f499134dSBaptiste Daroussin 
487f499134dSBaptiste Daroussin 			if(update_widget_withtextpad(conf, shadow, widget, h, w,
488f499134dSBaptiste Daroussin 			    RAISED, textpad, &htextpad, text, true) != 0)
489f499134dSBaptiste Daroussin 				return BSDDIALOG_ERROR;
490f499134dSBaptiste Daroussin 
491f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 - 5, '/');
492f499134dSBaptiste Daroussin 			mvwaddch(widget, h - 5, w/2 + 7, '/');
493f499134dSBaptiste Daroussin 
494f499134dSBaptiste Daroussin 			draw_buttons(widget, h-2, w, bs, true);
495f499134dSBaptiste Daroussin 
496f499134dSBaptiste Daroussin 			wrefresh(widget);
497f499134dSBaptiste Daroussin 
498f499134dSBaptiste Daroussin 			prefresh(textpad, 0, 0, y+1, x+2, y+h-7, x+w-2);
499f499134dSBaptiste Daroussin 
500f499134dSBaptiste Daroussin 			wclear(c[0].win);
501f499134dSBaptiste Daroussin 			mvwin(c[0].win, y + h - 6, x + w/2 - 11);
502f499134dSBaptiste Daroussin 			draw_borders(conf, c[0].win, 3, 6, LOWERED);
503f499134dSBaptiste Daroussin 			wrefresh(c[0].win);
504f499134dSBaptiste Daroussin 
505f499134dSBaptiste Daroussin 			wclear(c[1].win);
506f499134dSBaptiste Daroussin 			mvwin(c[1].win, y + h - 6, x + w/2 - 4);
507f499134dSBaptiste Daroussin 			draw_borders(conf, c[1].win, 3, 11, LOWERED);
508f499134dSBaptiste Daroussin 			wrefresh(c[1].win);
509f499134dSBaptiste Daroussin 
510f499134dSBaptiste Daroussin 			wclear(c[2].win);
511f499134dSBaptiste Daroussin 			mvwin(c[2].win, y + h - 6, x + w/2 + 8);
512f499134dSBaptiste Daroussin 			draw_borders(conf, c[2].win, 3, 4, LOWERED);
513f499134dSBaptiste Daroussin 			wrefresh(c[2].win);
514f499134dSBaptiste Daroussin 
515f499134dSBaptiste Daroussin 			/* Important to avoid grey lines expanding screen */
516f499134dSBaptiste Daroussin 			refresh();
517f499134dSBaptiste Daroussin 			break;
518f499134dSBaptiste Daroussin 		default:
519f499134dSBaptiste Daroussin 			for (i = 0; i < (int) bs.nbuttons; i++)
520f499134dSBaptiste Daroussin 				if (tolower(input) == tolower((bs.label[i])[0])) {
521f499134dSBaptiste Daroussin 					output = bs.value[i];
522f499134dSBaptiste Daroussin 					loop = false;
523f499134dSBaptiste Daroussin 			}
524c76f0793SBaptiste Daroussin 		}
525c76f0793SBaptiste Daroussin 	}
526c76f0793SBaptiste Daroussin 
527c76f0793SBaptiste Daroussin 	curs_set(0);
528c76f0793SBaptiste Daroussin 
529c76f0793SBaptiste Daroussin 	for (i=0; i<3; i++)
530c76f0793SBaptiste Daroussin 		delwin(c[i].win);
531f499134dSBaptiste Daroussin 	end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
532c76f0793SBaptiste Daroussin 
533c76f0793SBaptiste Daroussin 	return output;
534c76f0793SBaptiste Daroussin }
535