xref: /freebsd-src/contrib/bsddialog/lib/timebox.c (revision c76f07938c44264c7ebd400c23f218e561960d23)
1*c76f0793SBaptiste Daroussin /*-
2*c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3*c76f0793SBaptiste Daroussin  *
4*c76f0793SBaptiste Daroussin  * Copyright (c) 2021 Alfonso Sabato Siciliano
5*c76f0793SBaptiste Daroussin  *
6*c76f0793SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
7*c76f0793SBaptiste Daroussin  * modification, are permitted provided that the following conditions
8*c76f0793SBaptiste Daroussin  * are met:
9*c76f0793SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
10*c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
11*c76f0793SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
12*c76f0793SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
13*c76f0793SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
14*c76f0793SBaptiste Daroussin  *
15*c76f0793SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*c76f0793SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*c76f0793SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*c76f0793SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*c76f0793SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*c76f0793SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*c76f0793SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*c76f0793SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*c76f0793SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*c76f0793SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*c76f0793SBaptiste Daroussin  * SUCH DAMAGE.
26*c76f0793SBaptiste Daroussin  */
27*c76f0793SBaptiste Daroussin 
28*c76f0793SBaptiste Daroussin #ifdef PORTNCURSES
29*c76f0793SBaptiste Daroussin #include <ncurses/curses.h>
30*c76f0793SBaptiste Daroussin #else
31*c76f0793SBaptiste Daroussin #include <curses.h>
32*c76f0793SBaptiste Daroussin #endif
33*c76f0793SBaptiste Daroussin 
34*c76f0793SBaptiste Daroussin #include "bsddialog.h"
35*c76f0793SBaptiste Daroussin #include "lib_util.h"
36*c76f0793SBaptiste Daroussin 
37*c76f0793SBaptiste Daroussin /* "Time": timebox - calendar */
38*c76f0793SBaptiste Daroussin 
39*c76f0793SBaptiste Daroussin int bsddialog_timebox(struct bsddialog_conf conf, char* text, int rows, int cols,
40*c76f0793SBaptiste Daroussin     unsigned int *hh, unsigned int *mm, unsigned int *ss)
41*c76f0793SBaptiste Daroussin {
42*c76f0793SBaptiste Daroussin 	WINDOW *widget, *shadow;
43*c76f0793SBaptiste Daroussin 	int i, input, output, y, x, sel;
44*c76f0793SBaptiste Daroussin 	struct buttons bs;
45*c76f0793SBaptiste Daroussin 	bool loop, buttupdate;
46*c76f0793SBaptiste Daroussin 
47*c76f0793SBaptiste Daroussin 	if (hh == NULL || mm == NULL || ss == NULL)
48*c76f0793SBaptiste Daroussin 		RETURN_ERROR("hh or mm or ss == NULL");
49*c76f0793SBaptiste Daroussin 
50*c76f0793SBaptiste Daroussin 	struct myclockstruct {
51*c76f0793SBaptiste Daroussin 		unsigned int max;
52*c76f0793SBaptiste Daroussin 		unsigned int curr;
53*c76f0793SBaptiste Daroussin 		WINDOW *win;
54*c76f0793SBaptiste Daroussin 	} c[3] = { {23, *hh, NULL}, {59, *mm, NULL}, {59, *ss, NULL} };
55*c76f0793SBaptiste Daroussin 
56*c76f0793SBaptiste Daroussin 	if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
57*c76f0793SBaptiste Daroussin 	    true) <0)
58*c76f0793SBaptiste Daroussin 		return -1;
59*c76f0793SBaptiste Daroussin 
60*c76f0793SBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 7, 3, 4, LOWERED);
61*c76f0793SBaptiste Daroussin 	mvwaddch(widget, rows - 5, cols/2 - 3, ':');
62*c76f0793SBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 2, 3, 4, LOWERED);
63*c76f0793SBaptiste Daroussin 	mvwaddch(widget, rows - 5, cols/2 + 2, ':');
64*c76f0793SBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y + rows - 6, x + cols/2 + 3, 3, 4, LOWERED);
65*c76f0793SBaptiste Daroussin 
66*c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
67*c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
68*c76f0793SBaptiste Daroussin 
69*c76f0793SBaptiste Daroussin 	sel=0;
70*c76f0793SBaptiste Daroussin 	curs_set(2);
71*c76f0793SBaptiste Daroussin 	loop = buttupdate = true;
72*c76f0793SBaptiste Daroussin 	while(loop) {
73*c76f0793SBaptiste Daroussin 		if (buttupdate) {
74*c76f0793SBaptiste Daroussin 			draw_buttons(widget, rows-2, cols, bs, true);
75*c76f0793SBaptiste Daroussin 			wrefresh(widget);
76*c76f0793SBaptiste Daroussin 			buttupdate = false;
77*c76f0793SBaptiste Daroussin 		}
78*c76f0793SBaptiste Daroussin 
79*c76f0793SBaptiste Daroussin 		for (i=0; i<3; i++) {
80*c76f0793SBaptiste Daroussin 			mvwprintw(c[i].win, 1, 1, "%2d", c[i].curr);
81*c76f0793SBaptiste Daroussin 			wrefresh(c[i].win);
82*c76f0793SBaptiste Daroussin 		}
83*c76f0793SBaptiste Daroussin 		wmove(c[sel].win, 1, 2);
84*c76f0793SBaptiste Daroussin 		wrefresh(c[sel].win);
85*c76f0793SBaptiste Daroussin 
86*c76f0793SBaptiste Daroussin 		input = getch();
87*c76f0793SBaptiste Daroussin 		switch(input) {
88*c76f0793SBaptiste Daroussin 		case 10: /* Enter */
89*c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
90*c76f0793SBaptiste Daroussin 			if (output == BSDDIALOG_YESOK) {
91*c76f0793SBaptiste Daroussin 				*hh = c[0].curr - 1900;
92*c76f0793SBaptiste Daroussin 				*mm = c[1].curr;
93*c76f0793SBaptiste Daroussin 				*ss = c[2].curr;
94*c76f0793SBaptiste Daroussin 			}
95*c76f0793SBaptiste Daroussin 			loop = false;
96*c76f0793SBaptiste Daroussin 			break;
97*c76f0793SBaptiste Daroussin 		case 27: /* Esc */
98*c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
99*c76f0793SBaptiste Daroussin 			loop = false;
100*c76f0793SBaptiste Daroussin 			break;
101*c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
102*c76f0793SBaptiste Daroussin 			sel = (sel + 1) % 3;
103*c76f0793SBaptiste Daroussin 			break;
104*c76f0793SBaptiste Daroussin 		case KEY_LEFT:
105*c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
106*c76f0793SBaptiste Daroussin 				bs.curr--;
107*c76f0793SBaptiste Daroussin 				buttupdate = true;
108*c76f0793SBaptiste Daroussin 			}
109*c76f0793SBaptiste Daroussin 			break;
110*c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
111*c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
112*c76f0793SBaptiste Daroussin 				bs.curr++;
113*c76f0793SBaptiste Daroussin 				buttupdate = true;
114*c76f0793SBaptiste Daroussin 			}
115*c76f0793SBaptiste Daroussin 			break;
116*c76f0793SBaptiste Daroussin 		case KEY_UP:
117*c76f0793SBaptiste Daroussin 			c[sel].curr = c[sel].curr < c[sel].max ? c[sel].curr + 1 : 0;
118*c76f0793SBaptiste Daroussin 			break;
119*c76f0793SBaptiste Daroussin 		case KEY_DOWN:
120*c76f0793SBaptiste Daroussin 			c[sel].curr = c[sel].curr > 0 ? c[sel].curr - 1 : c[sel].max;
121*c76f0793SBaptiste Daroussin 			break;
122*c76f0793SBaptiste Daroussin 		}
123*c76f0793SBaptiste Daroussin 	}
124*c76f0793SBaptiste Daroussin 
125*c76f0793SBaptiste Daroussin 	curs_set(0);
126*c76f0793SBaptiste Daroussin 
127*c76f0793SBaptiste Daroussin 	for (i=0; i<3; i++)
128*c76f0793SBaptiste Daroussin 		delwin(c[i].win);
129*c76f0793SBaptiste Daroussin 	end_widget(conf, widget, rows, cols, shadow);
130*c76f0793SBaptiste Daroussin 
131*c76f0793SBaptiste Daroussin 	return output;
132*c76f0793SBaptiste Daroussin }
133*c76f0793SBaptiste Daroussin 
134*c76f0793SBaptiste Daroussin int bsddialog_calendar(struct bsddialog_conf conf, char* text, int rows, int cols,
135*c76f0793SBaptiste Daroussin     unsigned int *yy, unsigned int *mm, unsigned int *dd)
136*c76f0793SBaptiste Daroussin {
137*c76f0793SBaptiste Daroussin 	WINDOW *widget, *shadow;
138*c76f0793SBaptiste Daroussin 	int i, input, output, y, x, sel;
139*c76f0793SBaptiste Daroussin 	struct buttons bs;
140*c76f0793SBaptiste Daroussin 	bool loop, buttupdate;
141*c76f0793SBaptiste Daroussin 
142*c76f0793SBaptiste Daroussin 	if (yy == NULL || mm == NULL || dd == NULL)
143*c76f0793SBaptiste Daroussin 		RETURN_ERROR("yy or mm or dd == NULL");
144*c76f0793SBaptiste Daroussin 
145*c76f0793SBaptiste Daroussin 	struct calendar {
146*c76f0793SBaptiste Daroussin 		unsigned int max;
147*c76f0793SBaptiste Daroussin 		unsigned int curr;
148*c76f0793SBaptiste Daroussin 		WINDOW *win;
149*c76f0793SBaptiste Daroussin 		unsigned int x;
150*c76f0793SBaptiste Daroussin 	} c[3] = {{9999, *yy, NULL, 4 }, {12, *mm, NULL, 9 }, {31, *dd, NULL, 2 }};
151*c76f0793SBaptiste Daroussin 	struct month {
152*c76f0793SBaptiste Daroussin 		char *name;
153*c76f0793SBaptiste Daroussin 		unsigned int days;
154*c76f0793SBaptiste Daroussin 	} m[12] = {
155*c76f0793SBaptiste Daroussin 	    { "January", 30 }, { "February", 30 }, { "March",     30 },
156*c76f0793SBaptiste Daroussin 	    { "April",   30 }, { "May",      30 }, { "June",      30 },
157*c76f0793SBaptiste Daroussin 	    { "July",    30 }, { "August",   30 }, { "September", 30 },
158*c76f0793SBaptiste Daroussin 	    { "October", 30 }, { "November", 30 }, { "December",  30 }
159*c76f0793SBaptiste Daroussin 	};
160*c76f0793SBaptiste Daroussin 
161*c76f0793SBaptiste Daroussin 	if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
162*c76f0793SBaptiste Daroussin 	    true) <0)
163*c76f0793SBaptiste Daroussin 		return -1;
164*c76f0793SBaptiste Daroussin 
165*c76f0793SBaptiste Daroussin 	c[0].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 12, 3, 6, LOWERED);
166*c76f0793SBaptiste Daroussin 	mvwaddch(widget, rows - 5, cols/2 - 6, '/');
167*c76f0793SBaptiste Daroussin 	c[1].win = new_boxed_window(conf, y + rows - 6, x + cols/2 - 5, 3, 11, LOWERED);
168*c76f0793SBaptiste Daroussin 	mvwaddch(widget, rows - 5, cols/2 + 6, '/');
169*c76f0793SBaptiste Daroussin 	c[2].win = new_boxed_window(conf, y + rows - 6, x + cols/2 + 7, 3, 4, LOWERED);
170*c76f0793SBaptiste Daroussin 
171*c76f0793SBaptiste Daroussin 	wrefresh(widget);
172*c76f0793SBaptiste Daroussin 
173*c76f0793SBaptiste Daroussin 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
174*c76f0793SBaptiste Daroussin 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
175*c76f0793SBaptiste Daroussin 
176*c76f0793SBaptiste Daroussin 	sel=2;
177*c76f0793SBaptiste Daroussin 	curs_set(2);
178*c76f0793SBaptiste Daroussin 	loop = buttupdate = true;
179*c76f0793SBaptiste Daroussin 	while(loop) {
180*c76f0793SBaptiste Daroussin 		if (buttupdate) {
181*c76f0793SBaptiste Daroussin 			draw_buttons(widget, rows-2, cols, bs, true);
182*c76f0793SBaptiste Daroussin 			wrefresh(widget);
183*c76f0793SBaptiste Daroussin 			buttupdate = false;
184*c76f0793SBaptiste Daroussin 		}
185*c76f0793SBaptiste Daroussin 
186*c76f0793SBaptiste Daroussin 		mvwprintw(c[0].win, 1, 1, "%4d", c[0].curr);
187*c76f0793SBaptiste Daroussin 		mvwprintw(c[1].win, 1, 1, "%9s", m[c[1].curr-1].name);
188*c76f0793SBaptiste Daroussin 		mvwprintw(c[2].win, 1, 1, "%2d", c[2].curr);
189*c76f0793SBaptiste Daroussin 		for (i=0; i<3; i++) {
190*c76f0793SBaptiste Daroussin 			wrefresh(c[i].win);
191*c76f0793SBaptiste Daroussin 		}
192*c76f0793SBaptiste Daroussin 		wmove(c[sel].win, 1, c[sel].x);
193*c76f0793SBaptiste Daroussin 		wrefresh(c[sel].win);
194*c76f0793SBaptiste Daroussin 
195*c76f0793SBaptiste Daroussin 		input = getch();
196*c76f0793SBaptiste Daroussin 		switch(input) {
197*c76f0793SBaptiste Daroussin 		case 10: // Enter
198*c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr]; // values -> outputs
199*c76f0793SBaptiste Daroussin 			if (output == BSDDIALOG_YESOK) {
200*c76f0793SBaptiste Daroussin 				*yy = c[0].curr - 1900;
201*c76f0793SBaptiste Daroussin 				*mm = c[1].curr;
202*c76f0793SBaptiste Daroussin 				*dd = c[2].curr;
203*c76f0793SBaptiste Daroussin 			}
204*c76f0793SBaptiste Daroussin 			loop = false;
205*c76f0793SBaptiste Daroussin 			break;
206*c76f0793SBaptiste Daroussin 		case 27: // Esc
207*c76f0793SBaptiste Daroussin 			output = BSDDIALOG_ESC;
208*c76f0793SBaptiste Daroussin 			loop = false;
209*c76f0793SBaptiste Daroussin 			break;
210*c76f0793SBaptiste Daroussin 		case '\t': // TAB
211*c76f0793SBaptiste Daroussin 			sel = (sel + 1) % 3;
212*c76f0793SBaptiste Daroussin 			break;
213*c76f0793SBaptiste Daroussin 		case KEY_LEFT:
214*c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
215*c76f0793SBaptiste Daroussin 				bs.curr--;
216*c76f0793SBaptiste Daroussin 				buttupdate = true;
217*c76f0793SBaptiste Daroussin 			}
218*c76f0793SBaptiste Daroussin 			break;
219*c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
220*c76f0793SBaptiste Daroussin 			if (bs.curr < (int) bs.nbuttons - 1) {
221*c76f0793SBaptiste Daroussin 				bs.curr++;
222*c76f0793SBaptiste Daroussin 				buttupdate = true;
223*c76f0793SBaptiste Daroussin 			}
224*c76f0793SBaptiste Daroussin 			break;
225*c76f0793SBaptiste Daroussin 		case KEY_UP:
226*c76f0793SBaptiste Daroussin 			c[sel].curr = c[sel].curr < c[sel].max ? c[sel].curr + 1 : 1;
227*c76f0793SBaptiste Daroussin 			break;
228*c76f0793SBaptiste Daroussin 		case KEY_DOWN:
229*c76f0793SBaptiste Daroussin 			c[sel].curr = c[sel].curr > 1 ? c[sel].curr - 1 : c[sel].max;
230*c76f0793SBaptiste Daroussin 			break;
231*c76f0793SBaptiste Daroussin 		}
232*c76f0793SBaptiste Daroussin 	}
233*c76f0793SBaptiste Daroussin 
234*c76f0793SBaptiste Daroussin 	curs_set(0);
235*c76f0793SBaptiste Daroussin 
236*c76f0793SBaptiste Daroussin 	for (i=0; i<3; i++)
237*c76f0793SBaptiste Daroussin 		delwin(c[i].win);
238*c76f0793SBaptiste Daroussin 	end_widget(conf, widget, rows, cols, shadow);
239*c76f0793SBaptiste Daroussin 
240*c76f0793SBaptiste Daroussin 	return output;
241*c76f0793SBaptiste Daroussin }
242