xref: /freebsd/contrib/bsddialog/lib/timebox.c (revision a6d8be451f62d425b71a4874f7d4e133b9fb393c)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4*a6d8be45SAlfonso S. Siciliano  * Copyright (c) 2021-2024 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 
28263660c0SAlfonso Siciliano #include <curses.h>
29f499134dSBaptiste Daroussin 
30c76f0793SBaptiste Daroussin #include "bsddialog.h"
31b319d934SAlfonso S. Siciliano #include "bsddialog_theme.h"
32263660c0SAlfonso Siciliano #include "lib_util.h"
33c76f0793SBaptiste Daroussin 
34263660c0SAlfonso Siciliano #define MINWTIME   14 /* 3 windows and their borders */
3561ba55bcSBaptiste Daroussin #define HBOX        3
3661ba55bcSBaptiste Daroussin #define WBOX        4
37f499134dSBaptiste Daroussin 
3861ba55bcSBaptiste Daroussin struct clock {
39c76f0793SBaptiste Daroussin 	unsigned int max;
40f499134dSBaptiste Daroussin 	unsigned int value;
41c76f0793SBaptiste Daroussin 	WINDOW *win;
42f499134dSBaptiste Daroussin };
43c76f0793SBaptiste Daroussin 
4461ba55bcSBaptiste Daroussin static void
4561ba55bcSBaptiste Daroussin drawsquare(struct bsddialog_conf *conf, WINDOW *win, unsigned int value,
4661ba55bcSBaptiste Daroussin     bool focus)
4761ba55bcSBaptiste Daroussin {
4861ba55bcSBaptiste Daroussin 	draw_borders(conf, win, LOWERED);
4961ba55bcSBaptiste Daroussin 	if (focus) {
5061ba55bcSBaptiste Daroussin 		wattron(win, t.dialog.arrowcolor);
51*a6d8be45SAlfonso S. Siciliano 		mvwhline(win, 0, 1, UARROW(conf), 2);
52*a6d8be45SAlfonso S. Siciliano 		mvwhline(win, 2, 1, DARROW(conf), 2);
5361ba55bcSBaptiste Daroussin 		wattroff(win, t.dialog.arrowcolor);
5461ba55bcSBaptiste Daroussin 	}
55c76f0793SBaptiste Daroussin 
5661ba55bcSBaptiste Daroussin 	if (focus)
5761ba55bcSBaptiste Daroussin 		wattron(win, t.menu.f_namecolor);
5861ba55bcSBaptiste Daroussin 	mvwprintw(win, 1, 1, "%02u", value);
5961ba55bcSBaptiste Daroussin 	if (focus)
6061ba55bcSBaptiste Daroussin 		wattroff(win, t.menu.f_namecolor);
6161ba55bcSBaptiste Daroussin 
6261ba55bcSBaptiste Daroussin 	wnoutrefresh(win);
6361ba55bcSBaptiste Daroussin }
6461ba55bcSBaptiste Daroussin 
6561ba55bcSBaptiste Daroussin static int timebox_redraw(struct dialog *d, struct clock *c)
6661ba55bcSBaptiste Daroussin {
6761ba55bcSBaptiste Daroussin 	int y, x;
6861ba55bcSBaptiste Daroussin 
6961ba55bcSBaptiste Daroussin 	if (d->built) {
7061ba55bcSBaptiste Daroussin 		hide_dialog(d);
7161ba55bcSBaptiste Daroussin 		refresh(); /* Important for decreasing screen */
7261ba55bcSBaptiste Daroussin 	}
7361ba55bcSBaptiste Daroussin 	if (dialog_size_position(d, HBOX, MINWTIME, NULL) != 0)
7461ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
7561ba55bcSBaptiste Daroussin 	if (draw_dialog(d) != 0)
7661ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
7761ba55bcSBaptiste Daroussin 	if (d->built)
7861ba55bcSBaptiste Daroussin 		refresh(); /* Important to fix grey lines expanding screen */
7961ba55bcSBaptiste Daroussin 	TEXTPAD(d, HBOX + HBUTTONS);
8061ba55bcSBaptiste Daroussin 
8161ba55bcSBaptiste Daroussin 	y = d->y + d->h - BORDER - HBUTTONS - HBOX;
8261ba55bcSBaptiste Daroussin 	x = d->x + d->w/2 - 7;
8361ba55bcSBaptiste Daroussin 	update_box(d->conf, c[0].win, y, x, HBOX, WBOX, LOWERED);
8461ba55bcSBaptiste Daroussin 	mvwaddch(d->widget, d->h - 5, d->w/2 - 3, ':');
8561ba55bcSBaptiste Daroussin 	update_box(d->conf, c[1].win, y, x += 5, HBOX, WBOX, LOWERED);
8661ba55bcSBaptiste Daroussin 	mvwaddch(d->widget, d->h - 5, d->w/2 + 2, ':');
8761ba55bcSBaptiste Daroussin 	update_box(d->conf, c[2].win, y, x + 5, HBOX, WBOX, LOWERED);
8861ba55bcSBaptiste Daroussin 	wnoutrefresh(d->widget); /* for mvwaddch(':') */
8961ba55bcSBaptiste Daroussin 
9061ba55bcSBaptiste Daroussin 	return (0);
9161ba55bcSBaptiste Daroussin }
9261ba55bcSBaptiste Daroussin 
9361ba55bcSBaptiste Daroussin /* API */
9461ba55bcSBaptiste Daroussin int
9561ba55bcSBaptiste Daroussin bsddialog_timebox(struct bsddialog_conf *conf, const char* text, int rows,
9661ba55bcSBaptiste Daroussin     int cols, unsigned int *hh, unsigned int *mm, unsigned int *ss)
9761ba55bcSBaptiste Daroussin {
9861ba55bcSBaptiste Daroussin 	bool loop, focusbuttons;
9961ba55bcSBaptiste Daroussin 	int i, retval, sel;
10061ba55bcSBaptiste Daroussin 	wint_t input;
10161ba55bcSBaptiste Daroussin 	struct dialog d;
10261ba55bcSBaptiste Daroussin 	struct clock c[3] = {
103f499134dSBaptiste Daroussin 		{23, *hh, NULL},
104f499134dSBaptiste Daroussin 		{59, *mm, NULL},
105f499134dSBaptiste Daroussin 		{59, *ss, NULL}
106f499134dSBaptiste Daroussin 	};
107f499134dSBaptiste Daroussin 
10861ba55bcSBaptiste Daroussin 	CHECK_PTR(hh);
10961ba55bcSBaptiste Daroussin 	CHECK_PTR(mm);
11061ba55bcSBaptiste Daroussin 	CHECK_PTR(ss);
11161ba55bcSBaptiste Daroussin 	if (prepare_dialog(conf, text, rows, cols, &d) != 0)
11261ba55bcSBaptiste Daroussin 		return (BSDDIALOG_ERROR);
11361ba55bcSBaptiste Daroussin 	set_buttons(&d, true, OK_LABEL, CANCEL_LABEL);
114f499134dSBaptiste Daroussin 	for (i=0; i<3; i++) {
11561ba55bcSBaptiste Daroussin 		if ((c[i].win = newwin(1, 1, 1, 1)) == NULL)
11661ba55bcSBaptiste Daroussin 			RETURN_FMTERROR("Cannot build WINDOW for time[%d]", i);
11761ba55bcSBaptiste Daroussin 		wbkgd(c[i].win, t.dialog.color);
11861ba55bcSBaptiste Daroussin 		c[i].value = MIN(c[i].value, c[i].max);
119f499134dSBaptiste Daroussin 	}
12061ba55bcSBaptiste Daroussin 	if (timebox_redraw(&d, c) != 0)
121263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
122f499134dSBaptiste Daroussin 
123b319d934SAlfonso S. Siciliano 	sel = -1;
124bce40c02SAlfonso S. Siciliano 	loop = focusbuttons = true;
125c76f0793SBaptiste Daroussin 	while (loop) {
126b319d934SAlfonso S. Siciliano 		for (i = 0; i < 3; i++)
12761ba55bcSBaptiste Daroussin 			drawsquare(conf, c[i].win, c[i].value, sel == i);
12861ba55bcSBaptiste Daroussin 		doupdate();
129b319d934SAlfonso S. Siciliano 		if (get_wch(&input) == ERR)
130b319d934SAlfonso S. Siciliano 			continue;
131c76f0793SBaptiste Daroussin 		switch(input) {
132f499134dSBaptiste Daroussin 		case KEY_ENTER:
133c76f0793SBaptiste Daroussin 		case 10: /* Enter */
134b319d934SAlfonso S. Siciliano 			if (focusbuttons || conf->button.always_active) {
13561ba55bcSBaptiste Daroussin 				retval = BUTTONVALUE(d.bs);
136c76f0793SBaptiste Daroussin 				loop = false;
137b319d934SAlfonso S. Siciliano 			}
138c76f0793SBaptiste Daroussin 			break;
139c76f0793SBaptiste Daroussin 		case 27: /* Esc */
140263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
141b319d934SAlfonso S. Siciliano 				retval = BSDDIALOG_ESC;
142c76f0793SBaptiste Daroussin 				loop = false;
143263660c0SAlfonso Siciliano 			}
144c76f0793SBaptiste Daroussin 			break;
145c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
146*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('n'):
147*a6d8be45SAlfonso S. Siciliano 		case KEY_RIGHT:
148bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
14961ba55bcSBaptiste Daroussin 				d.bs.curr++;
15061ba55bcSBaptiste Daroussin 				focusbuttons = d.bs.curr < (int)d.bs.nbuttons ?
151bce40c02SAlfonso S. Siciliano 				    true : false;
152bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
153bce40c02SAlfonso S. Siciliano 					sel = 0;
15461ba55bcSBaptiste Daroussin 					d.bs.curr =
15561ba55bcSBaptiste Daroussin 					    conf->button.always_active ? 0 : -1;
156bce40c02SAlfonso S. Siciliano 				}
157bce40c02SAlfonso S. Siciliano 			} else {
158bce40c02SAlfonso S. Siciliano 				sel++;
159bce40c02SAlfonso S. Siciliano 				focusbuttons = sel > 2 ? true : false;
160bce40c02SAlfonso S. Siciliano 				if (focusbuttons) {
16161ba55bcSBaptiste Daroussin 					d.bs.curr = 0;
162bce40c02SAlfonso S. Siciliano 				}
163bce40c02SAlfonso S. Siciliano 			}
16461ba55bcSBaptiste Daroussin 			DRAW_BUTTONS(d);
165c76f0793SBaptiste Daroussin 			break;
166*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('p'):
167c76f0793SBaptiste Daroussin 		case KEY_LEFT:
168bce40c02SAlfonso S. Siciliano 			if (focusbuttons) {
16961ba55bcSBaptiste Daroussin 				d.bs.curr--;
17061ba55bcSBaptiste Daroussin 				focusbuttons = d.bs.curr < 0 ? false : true;
171bce40c02SAlfonso S. Siciliano 				if (focusbuttons == false) {
172bce40c02SAlfonso S. Siciliano 					sel = 2;
17361ba55bcSBaptiste Daroussin 					d.bs.curr =
17461ba55bcSBaptiste Daroussin 					    conf->button.always_active ? 0 : -1;
175bce40c02SAlfonso S. Siciliano 				}
176bce40c02SAlfonso S. Siciliano 			} else {
177bce40c02SAlfonso S. Siciliano 				sel--;
178bce40c02SAlfonso S. Siciliano 				focusbuttons = sel < 0 ? true : false;
179b319d934SAlfonso S. Siciliano 				if (focusbuttons)
18061ba55bcSBaptiste Daroussin 					d.bs.curr = (int)d.bs.nbuttons - 1;
181bce40c02SAlfonso S. Siciliano 			}
18261ba55bcSBaptiste Daroussin 			DRAW_BUTTONS(d);
183c76f0793SBaptiste Daroussin 			break;
184*a6d8be45SAlfonso S. Siciliano 		case '-':
185*a6d8be45SAlfonso S. Siciliano 			if (focusbuttons == false)
186*a6d8be45SAlfonso S. Siciliano 				c[sel].value = c[sel].value > 0 ?
187*a6d8be45SAlfonso S. Siciliano 				    c[sel].value - 1 : c[sel].max;
188*a6d8be45SAlfonso S. Siciliano 			break;
189c76f0793SBaptiste Daroussin 		case KEY_UP:
190b319d934SAlfonso S. Siciliano 			if (focusbuttons) {
191b319d934SAlfonso S. Siciliano 				sel = 0;
192b319d934SAlfonso S. Siciliano 				focusbuttons = false;
19361ba55bcSBaptiste Daroussin 				d.bs.curr = conf->button.always_active ? 0 : -1;
19461ba55bcSBaptiste Daroussin 				DRAW_BUTTONS(d);
19561ba55bcSBaptiste Daroussin 			} else {
19661ba55bcSBaptiste Daroussin 				c[sel].value = c[sel].value > 0 ?
197263660c0SAlfonso Siciliano 				    c[sel].value - 1 : c[sel].max;
198b319d934SAlfonso S. Siciliano 			}
199c76f0793SBaptiste Daroussin 			break;
200*a6d8be45SAlfonso S. Siciliano 		case '+':
201bce40c02SAlfonso S. Siciliano 		case KEY_DOWN:
202bce40c02SAlfonso S. Siciliano 			if (focusbuttons)
203bce40c02SAlfonso S. Siciliano 				break;
204bce40c02SAlfonso S. Siciliano 			c[sel].value = c[sel].value < c[sel].max ?
205bce40c02SAlfonso S. Siciliano 			    c[sel].value + 1 : 0;
206bce40c02SAlfonso S. Siciliano 			break;
207f499134dSBaptiste Daroussin 		case KEY_F(1):
208bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
209bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
210f499134dSBaptiste Daroussin 				break;
21161ba55bcSBaptiste Daroussin 			if (f1help_dialog(conf) != 0)
212263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
21361ba55bcSBaptiste Daroussin 			if (timebox_redraw(&d, c) != 0)
21461ba55bcSBaptiste Daroussin 				return (BSDDIALOG_ERROR);
21561ba55bcSBaptiste Daroussin 			break;
216*a6d8be45SAlfonso S. Siciliano 		case KEY_CTRL('l'):
217f499134dSBaptiste Daroussin 		case KEY_RESIZE:
21861ba55bcSBaptiste Daroussin 			if (timebox_redraw(&d, c) != 0)
219263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
220f499134dSBaptiste Daroussin 			break;
221f499134dSBaptiste Daroussin 		default:
22261ba55bcSBaptiste Daroussin 			if (shortcut_buttons(input, &d.bs)) {
22361ba55bcSBaptiste Daroussin 				DRAW_BUTTONS(d);
22461ba55bcSBaptiste Daroussin 				doupdate();
22561ba55bcSBaptiste Daroussin 				retval = BUTTONVALUE(d.bs);
226f499134dSBaptiste Daroussin 				loop = false;
227f499134dSBaptiste Daroussin 			}
228c76f0793SBaptiste Daroussin 		}
229c76f0793SBaptiste Daroussin 	}
230c76f0793SBaptiste Daroussin 
231bce40c02SAlfonso S. Siciliano 	*hh = c[0].value;
232bce40c02SAlfonso S. Siciliano 	*mm = c[1].value;
233bce40c02SAlfonso S. Siciliano 	*ss = c[2].value;
234bce40c02SAlfonso S. Siciliano 
235c76f0793SBaptiste Daroussin 	for (i = 0; i < 3; i++)
236c76f0793SBaptiste Daroussin 		delwin(c[i].win);
23761ba55bcSBaptiste Daroussin 	end_dialog(&d);
238c76f0793SBaptiste Daroussin 
239b319d934SAlfonso S. Siciliano 	return (retval);
240c76f0793SBaptiste Daroussin }
241