xref: /freebsd-src/contrib/bsddialog/lib/messagebox.c (revision 263660c061ac76d449cbca7bdd0db2ecdfad76d9)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4*263660c0SAlfonso 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 
28c76f0793SBaptiste Daroussin #include <sys/param.h>
29c76f0793SBaptiste Daroussin 
30*263660c0SAlfonso Siciliano #include <curses.h>
31d93b4d32SBaptiste Daroussin #include <string.h>
32c76f0793SBaptiste Daroussin 
33c76f0793SBaptiste Daroussin #include "bsddialog.h"
34c76f0793SBaptiste Daroussin #include "bsddialog_theme.h"
35*263660c0SAlfonso Siciliano #include "lib_util.h"
36c76f0793SBaptiste Daroussin 
37c76f0793SBaptiste Daroussin extern struct bsddialog_theme t;
38c76f0793SBaptiste Daroussin 
39c76f0793SBaptiste Daroussin static int
40d93b4d32SBaptiste Daroussin message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
41*263660c0SAlfonso Siciliano     int *w, const char *text, struct buttons bs)
42c76f0793SBaptiste Daroussin {
43*263660c0SAlfonso Siciliano 	int htext, wtext;
44c76f0793SBaptiste Daroussin 
45*263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
46*263660c0SAlfonso Siciliano 		if (text_size(conf, rows, cols, text, &bs, 0, SCREENCOLS/2,
47*263660c0SAlfonso Siciliano 		    &htext, &wtext) != 0)
48*263660c0SAlfonso Siciliano 			return (BSDDIALOG_ERROR);
49c76f0793SBaptiste Daroussin 	}
50c76f0793SBaptiste Daroussin 
51*263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE)
52*263660c0SAlfonso Siciliano 		*w = widget_min_width(conf, wtext, 0, &bs);
53c76f0793SBaptiste Daroussin 
54*263660c0SAlfonso Siciliano 	if (rows == BSDDIALOG_AUTOSIZE)
55*263660c0SAlfonso Siciliano 		*h = widget_min_height(conf, htext, 0, true);
56*263660c0SAlfonso Siciliano 
57*263660c0SAlfonso Siciliano 	return (0);
58c76f0793SBaptiste Daroussin }
59c76f0793SBaptiste Daroussin 
60c76f0793SBaptiste Daroussin static int message_checksize(int rows, int cols, struct buttons bs)
61c76f0793SBaptiste Daroussin {
62c76f0793SBaptiste Daroussin 	int mincols;
63c76f0793SBaptiste Daroussin 
64c76f0793SBaptiste Daroussin 	mincols = VBORDERS;
65c76f0793SBaptiste Daroussin 	mincols += bs.nbuttons * bs.sizebutton;
66f499134dSBaptiste Daroussin 	mincols += bs.nbuttons > 0 ? (bs.nbuttons-1) * t.button.space : 0;
67c76f0793SBaptiste Daroussin 
68c76f0793SBaptiste Daroussin 	if (cols < mincols)
69*263660c0SAlfonso Siciliano 		RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "
70c76f0793SBaptiste Daroussin 		    "for borders, buttons and spaces between buttons");
71c76f0793SBaptiste Daroussin 
72*263660c0SAlfonso Siciliano 	if (rows < HBORDERS + 2 /*buttons*/)
73*263660c0SAlfonso Siciliano 		RETURN_ERROR("Msgbox and Yesno need at least height 4");
74c76f0793SBaptiste Daroussin 
75*263660c0SAlfonso Siciliano 	return (0);
76c76f0793SBaptiste Daroussin }
77c76f0793SBaptiste Daroussin 
78c76f0793SBaptiste Daroussin static void
79*263660c0SAlfonso Siciliano textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad)
80c76f0793SBaptiste Daroussin {
81*263660c0SAlfonso Siciliano 	int y, x, h, w;
82c76f0793SBaptiste Daroussin 
83*263660c0SAlfonso Siciliano 	getbegyx(widget, y, x);
84*263660c0SAlfonso Siciliano 	getmaxyx(widget, h, w);
85*263660c0SAlfonso Siciliano 
86c76f0793SBaptiste Daroussin 	if (htextpad > h - 4) {
87c76f0793SBaptiste Daroussin 		mvwprintw(widget, h-3, w-6, "%3d%%",
88*263660c0SAlfonso Siciliano 		    100 * (ytextpad+h-4)/ htextpad);
89c76f0793SBaptiste Daroussin 		wnoutrefresh(widget);
90c76f0793SBaptiste Daroussin 	}
91c76f0793SBaptiste Daroussin 
92*263660c0SAlfonso Siciliano 	pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2);
93c76f0793SBaptiste Daroussin }
94c76f0793SBaptiste Daroussin 
95c76f0793SBaptiste Daroussin static int
96*263660c0SAlfonso Siciliano do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
97d93b4d32SBaptiste Daroussin     struct buttons bs)
98c76f0793SBaptiste Daroussin {
99c76f0793SBaptiste Daroussin 	bool loop;
100*263660c0SAlfonso Siciliano 	int y, x, h, w, input, output, ytextpad, htextpad, unused;
101*263660c0SAlfonso Siciliano 	WINDOW *widget, *textpad, *shadow;
102c76f0793SBaptiste Daroussin 
103c76f0793SBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
104*263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
105c76f0793SBaptiste Daroussin 	if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
106*263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
107c76f0793SBaptiste Daroussin 	if (message_checksize(h, w, bs) != 0)
108*263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
109c76f0793SBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
110*263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
111c76f0793SBaptiste Daroussin 
112*263660c0SAlfonso Siciliano 	if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
113*263660c0SAlfonso Siciliano 	    true) != 0)
114*263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
115c76f0793SBaptiste Daroussin 
116*263660c0SAlfonso Siciliano 	ytextpad = 0;
117*263660c0SAlfonso Siciliano 	getmaxyx(textpad, htextpad, unused);
118*263660c0SAlfonso Siciliano 	unused++; /* fix unused error */
119*263660c0SAlfonso Siciliano 	textupdate(widget, textpad, htextpad, ytextpad);
120c76f0793SBaptiste Daroussin 	loop = true;
121c76f0793SBaptiste Daroussin 	while (loop) {
122c76f0793SBaptiste Daroussin 		doupdate();
123c76f0793SBaptiste Daroussin 		input = getch();
124c76f0793SBaptiste Daroussin 		switch (input) {
125*263660c0SAlfonso Siciliano 		case KEY_ENTER:
126c76f0793SBaptiste Daroussin 		case 10: /* Enter */
127c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
128c76f0793SBaptiste Daroussin 			loop = false;
129c76f0793SBaptiste Daroussin 			break;
130c76f0793SBaptiste Daroussin 		case 27: /* Esc */
131*263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
132c76f0793SBaptiste Daroussin 				output = BSDDIALOG_ESC;
133c76f0793SBaptiste Daroussin 				loop = false;
134*263660c0SAlfonso Siciliano 			}
135c76f0793SBaptiste Daroussin 			break;
136c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
137c76f0793SBaptiste Daroussin 			bs.curr = (bs.curr + 1) % bs.nbuttons;
138*263660c0SAlfonso Siciliano 			draw_buttons(widget, bs, true);
139*263660c0SAlfonso Siciliano 			wnoutrefresh(widget);
140c76f0793SBaptiste Daroussin 			break;
141c76f0793SBaptiste Daroussin 		case KEY_LEFT:
142c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
143c76f0793SBaptiste Daroussin 				bs.curr--;
144*263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, true);
145*263660c0SAlfonso Siciliano 				wnoutrefresh(widget);
146c76f0793SBaptiste Daroussin 			}
147c76f0793SBaptiste Daroussin 			break;
148c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
149c76f0793SBaptiste Daroussin 			if (bs.curr < (int)bs.nbuttons - 1) {
150c76f0793SBaptiste Daroussin 				bs.curr++;
151*263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, true);
152*263660c0SAlfonso Siciliano 				wnoutrefresh(widget);
153c76f0793SBaptiste Daroussin 			}
154c76f0793SBaptiste Daroussin 			break;
155*263660c0SAlfonso Siciliano 		case KEY_F(1):
156*263660c0SAlfonso Siciliano 			if (conf->f1_file == NULL && conf->f1_message == NULL)
157*263660c0SAlfonso Siciliano 				break;
158*263660c0SAlfonso Siciliano 			if (f1help(conf) != 0)
159*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
160*263660c0SAlfonso Siciliano 			/* No break, screen size can change */
161*263660c0SAlfonso Siciliano 		case KEY_RESIZE:
162*263660c0SAlfonso Siciliano 			/* Important for decreasing screen */
163*263660c0SAlfonso Siciliano 			hide_widget(y, x, h, w, conf->shadow);
164*263660c0SAlfonso Siciliano 			refresh();
165*263660c0SAlfonso Siciliano 
166*263660c0SAlfonso Siciliano 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
167*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
168*263660c0SAlfonso Siciliano 			if (message_autosize(conf, rows, cols, &h, &w, text,
169*263660c0SAlfonso Siciliano 			    bs) != 0)
170*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
171*263660c0SAlfonso Siciliano 			if (message_checksize(h, w, bs) != 0)
172*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
173*263660c0SAlfonso Siciliano 			if (set_widget_position(conf, &y, &x, h, w) != 0)
174*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
175*263660c0SAlfonso Siciliano 
176*263660c0SAlfonso Siciliano 			if (update_dialog(conf, shadow, widget, y, x, h, w,
177*263660c0SAlfonso Siciliano 			    textpad, text, &bs, true) != 0)
178*263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
179*263660c0SAlfonso Siciliano 
180*263660c0SAlfonso Siciliano 			getmaxyx(textpad, htextpad, unused);
181*263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
182*263660c0SAlfonso Siciliano 
183*263660c0SAlfonso Siciliano 			/* Important to fix grey lines expanding screen */
184*263660c0SAlfonso Siciliano 			refresh();
185*263660c0SAlfonso Siciliano 			break;
186*263660c0SAlfonso Siciliano 		case KEY_UP:
187*263660c0SAlfonso Siciliano 			if (ytextpad == 0)
188*263660c0SAlfonso Siciliano 				break;
189*263660c0SAlfonso Siciliano 			ytextpad--;
190*263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
191*263660c0SAlfonso Siciliano 			break;
192*263660c0SAlfonso Siciliano 		case KEY_DOWN:
193*263660c0SAlfonso Siciliano 			if (ytextpad + h - 4 >= htextpad)
194*263660c0SAlfonso Siciliano 				break;
195*263660c0SAlfonso Siciliano 			ytextpad++;
196*263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
197*263660c0SAlfonso Siciliano 			break;
198c76f0793SBaptiste Daroussin 		default:
199*263660c0SAlfonso Siciliano 			if (shortcut_buttons(input, &bs)) {
200*263660c0SAlfonso Siciliano 				output = bs.value[bs.curr];
201c76f0793SBaptiste Daroussin 				loop = false;
202c76f0793SBaptiste Daroussin 			}
203c76f0793SBaptiste Daroussin 		}
204c76f0793SBaptiste Daroussin 	}
205c76f0793SBaptiste Daroussin 
206*263660c0SAlfonso Siciliano 	end_dialog(conf, shadow, widget, textpad);
207c76f0793SBaptiste Daroussin 
208*263660c0SAlfonso Siciliano 	return (output);
209c76f0793SBaptiste Daroussin }
210c76f0793SBaptiste Daroussin 
211c76f0793SBaptiste Daroussin /* API */
212c76f0793SBaptiste Daroussin int
213*263660c0SAlfonso Siciliano bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
214*263660c0SAlfonso Siciliano     int cols)
215c76f0793SBaptiste Daroussin {
216c76f0793SBaptiste Daroussin 	struct buttons bs;
217c76f0793SBaptiste Daroussin 
218*263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL);
219c76f0793SBaptiste Daroussin 
220*263660c0SAlfonso Siciliano 	return (do_message(conf, text, rows, cols, bs));
221c76f0793SBaptiste Daroussin }
222c76f0793SBaptiste Daroussin 
223c76f0793SBaptiste Daroussin int
224*263660c0SAlfonso Siciliano bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
225*263660c0SAlfonso Siciliano     int cols)
226c76f0793SBaptiste Daroussin {
227c76f0793SBaptiste Daroussin 	struct buttons bs;
228c76f0793SBaptiste Daroussin 
229*263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, "Yes", "No");
230c76f0793SBaptiste Daroussin 
231*263660c0SAlfonso Siciliano 	return (do_message(conf, text, rows, cols, bs));
232c76f0793SBaptiste Daroussin }