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