xref: /freebsd-src/contrib/bsddialog/lib/messagebox.c (revision bce40c0242b167a541cc051b6b0dbcc5f3d04319)
1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin  * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin  *
4263660c0SAlfonso 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 
30263660c0SAlfonso Siciliano #include <curses.h>
31d93b4d32SBaptiste Daroussin #include <string.h>
32c76f0793SBaptiste Daroussin 
33c76f0793SBaptiste Daroussin #include "bsddialog.h"
34263660c0SAlfonso Siciliano #include "lib_util.h"
35c76f0793SBaptiste Daroussin 
36c76f0793SBaptiste Daroussin static int
37d93b4d32SBaptiste Daroussin message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
38263660c0SAlfonso Siciliano     int *w, const char *text, struct buttons bs)
39c76f0793SBaptiste Daroussin {
40263660c0SAlfonso Siciliano 	int htext, wtext;
41c76f0793SBaptiste Daroussin 
42263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE) {
43263660c0SAlfonso Siciliano 		if (text_size(conf, rows, cols, text, &bs, 0, SCREENCOLS/2,
44263660c0SAlfonso Siciliano 		    &htext, &wtext) != 0)
45263660c0SAlfonso Siciliano 			return (BSDDIALOG_ERROR);
46c76f0793SBaptiste Daroussin 	}
47c76f0793SBaptiste Daroussin 
48263660c0SAlfonso Siciliano 	if (cols == BSDDIALOG_AUTOSIZE)
49263660c0SAlfonso Siciliano 		*w = widget_min_width(conf, wtext, 0, &bs);
50c76f0793SBaptiste Daroussin 
51263660c0SAlfonso Siciliano 	if (rows == BSDDIALOG_AUTOSIZE)
52263660c0SAlfonso Siciliano 		*h = widget_min_height(conf, htext, 0, true);
53263660c0SAlfonso Siciliano 
54263660c0SAlfonso Siciliano 	return (0);
55c76f0793SBaptiste Daroussin }
56c76f0793SBaptiste Daroussin 
57c76f0793SBaptiste Daroussin static int message_checksize(int rows, int cols, struct buttons bs)
58c76f0793SBaptiste Daroussin {
59c76f0793SBaptiste Daroussin 	int mincols;
60c76f0793SBaptiste Daroussin 
61c76f0793SBaptiste Daroussin 	mincols = VBORDERS;
62*bce40c02SAlfonso S. Siciliano 	mincols += buttons_width(bs);
63c76f0793SBaptiste Daroussin 
64c76f0793SBaptiste Daroussin 	if (cols < mincols)
65263660c0SAlfonso Siciliano 		RETURN_ERROR("Few cols, Msgbox and Yesno need at least width "
66c76f0793SBaptiste Daroussin 		    "for borders, buttons and spaces between buttons");
67c76f0793SBaptiste Daroussin 
68263660c0SAlfonso Siciliano 	if (rows < HBORDERS + 2 /*buttons*/)
69263660c0SAlfonso Siciliano 		RETURN_ERROR("Msgbox and Yesno need at least height 4");
70c76f0793SBaptiste Daroussin 
71263660c0SAlfonso Siciliano 	return (0);
72c76f0793SBaptiste Daroussin }
73c76f0793SBaptiste Daroussin 
74c76f0793SBaptiste Daroussin static void
75263660c0SAlfonso Siciliano textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad)
76c76f0793SBaptiste Daroussin {
77263660c0SAlfonso Siciliano 	int y, x, h, w;
78c76f0793SBaptiste Daroussin 
79263660c0SAlfonso Siciliano 	getbegyx(widget, y, x);
80263660c0SAlfonso Siciliano 	getmaxyx(widget, h, w);
81263660c0SAlfonso Siciliano 
82c76f0793SBaptiste Daroussin 	if (htextpad > h - 4) {
83c76f0793SBaptiste Daroussin 		mvwprintw(widget, h-3, w-6, "%3d%%",
84263660c0SAlfonso Siciliano 		    100 * (ytextpad+h-4)/ htextpad);
85c76f0793SBaptiste Daroussin 		wnoutrefresh(widget);
86c76f0793SBaptiste Daroussin 	}
87c76f0793SBaptiste Daroussin 
88263660c0SAlfonso Siciliano 	pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2);
89c76f0793SBaptiste Daroussin }
90c76f0793SBaptiste Daroussin 
91c76f0793SBaptiste Daroussin static int
92263660c0SAlfonso Siciliano do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols,
93d93b4d32SBaptiste Daroussin     struct buttons bs)
94c76f0793SBaptiste Daroussin {
95c76f0793SBaptiste Daroussin 	bool loop;
96263660c0SAlfonso Siciliano 	int y, x, h, w, input, output, ytextpad, htextpad, unused;
97263660c0SAlfonso Siciliano 	WINDOW *widget, *textpad, *shadow;
98c76f0793SBaptiste Daroussin 
99c76f0793SBaptiste Daroussin 	if (set_widget_size(conf, rows, cols, &h, &w) != 0)
100263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
101c76f0793SBaptiste Daroussin 	if (message_autosize(conf, rows, cols, &h, &w, text, bs) != 0)
102263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
103c76f0793SBaptiste Daroussin 	if (message_checksize(h, w, bs) != 0)
104263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
105c76f0793SBaptiste Daroussin 	if (set_widget_position(conf, &y, &x, h, w) != 0)
106263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
107c76f0793SBaptiste Daroussin 
108263660c0SAlfonso Siciliano 	if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs,
109263660c0SAlfonso Siciliano 	    true) != 0)
110263660c0SAlfonso Siciliano 		return (BSDDIALOG_ERROR);
111c76f0793SBaptiste Daroussin 
112263660c0SAlfonso Siciliano 	ytextpad = 0;
113263660c0SAlfonso Siciliano 	getmaxyx(textpad, htextpad, unused);
114263660c0SAlfonso Siciliano 	unused++; /* fix unused error */
115263660c0SAlfonso Siciliano 	textupdate(widget, textpad, htextpad, ytextpad);
116c76f0793SBaptiste Daroussin 	loop = true;
117c76f0793SBaptiste Daroussin 	while (loop) {
118c76f0793SBaptiste Daroussin 		doupdate();
119c76f0793SBaptiste Daroussin 		input = getch();
120c76f0793SBaptiste Daroussin 		switch (input) {
121263660c0SAlfonso Siciliano 		case KEY_ENTER:
122c76f0793SBaptiste Daroussin 		case 10: /* Enter */
123c76f0793SBaptiste Daroussin 			output = bs.value[bs.curr];
124c76f0793SBaptiste Daroussin 			loop = false;
125c76f0793SBaptiste Daroussin 			break;
126c76f0793SBaptiste Daroussin 		case 27: /* Esc */
127263660c0SAlfonso Siciliano 			if (conf->key.enable_esc) {
128c76f0793SBaptiste Daroussin 				output = BSDDIALOG_ESC;
129c76f0793SBaptiste Daroussin 				loop = false;
130263660c0SAlfonso Siciliano 			}
131c76f0793SBaptiste Daroussin 			break;
132c76f0793SBaptiste Daroussin 		case '\t': /* TAB */
133c76f0793SBaptiste Daroussin 			bs.curr = (bs.curr + 1) % bs.nbuttons;
134263660c0SAlfonso Siciliano 			draw_buttons(widget, bs, true);
135263660c0SAlfonso Siciliano 			wnoutrefresh(widget);
136c76f0793SBaptiste Daroussin 			break;
137c76f0793SBaptiste Daroussin 		case KEY_LEFT:
138c76f0793SBaptiste Daroussin 			if (bs.curr > 0) {
139c76f0793SBaptiste Daroussin 				bs.curr--;
140263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, true);
141263660c0SAlfonso Siciliano 				wnoutrefresh(widget);
142c76f0793SBaptiste Daroussin 			}
143c76f0793SBaptiste Daroussin 			break;
144c76f0793SBaptiste Daroussin 		case KEY_RIGHT:
145c76f0793SBaptiste Daroussin 			if (bs.curr < (int)bs.nbuttons - 1) {
146c76f0793SBaptiste Daroussin 				bs.curr++;
147263660c0SAlfonso Siciliano 				draw_buttons(widget, bs, true);
148263660c0SAlfonso Siciliano 				wnoutrefresh(widget);
149c76f0793SBaptiste Daroussin 			}
150c76f0793SBaptiste Daroussin 			break;
151263660c0SAlfonso Siciliano 		case KEY_F(1):
152*bce40c02SAlfonso S. Siciliano 			if (conf->key.f1_file == NULL &&
153*bce40c02SAlfonso S. Siciliano 			    conf->key.f1_message == NULL)
154263660c0SAlfonso Siciliano 				break;
155263660c0SAlfonso Siciliano 			if (f1help(conf) != 0)
156263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
157263660c0SAlfonso Siciliano 			/* No break, screen size can change */
158263660c0SAlfonso Siciliano 		case KEY_RESIZE:
159263660c0SAlfonso Siciliano 			/* Important for decreasing screen */
160263660c0SAlfonso Siciliano 			hide_widget(y, x, h, w, conf->shadow);
161263660c0SAlfonso Siciliano 			refresh();
162263660c0SAlfonso Siciliano 
163263660c0SAlfonso Siciliano 			if (set_widget_size(conf, rows, cols, &h, &w) != 0)
164263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
165263660c0SAlfonso Siciliano 			if (message_autosize(conf, rows, cols, &h, &w, text,
166263660c0SAlfonso Siciliano 			    bs) != 0)
167263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
168263660c0SAlfonso Siciliano 			if (message_checksize(h, w, bs) != 0)
169263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
170263660c0SAlfonso Siciliano 			if (set_widget_position(conf, &y, &x, h, w) != 0)
171263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
172263660c0SAlfonso Siciliano 
173263660c0SAlfonso Siciliano 			if (update_dialog(conf, shadow, widget, y, x, h, w,
174263660c0SAlfonso Siciliano 			    textpad, text, &bs, true) != 0)
175263660c0SAlfonso Siciliano 				return (BSDDIALOG_ERROR);
176263660c0SAlfonso Siciliano 
177263660c0SAlfonso Siciliano 			getmaxyx(textpad, htextpad, unused);
178263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
179263660c0SAlfonso Siciliano 
180263660c0SAlfonso Siciliano 			/* Important to fix grey lines expanding screen */
181263660c0SAlfonso Siciliano 			refresh();
182263660c0SAlfonso Siciliano 			break;
183263660c0SAlfonso Siciliano 		case KEY_UP:
184263660c0SAlfonso Siciliano 			if (ytextpad == 0)
185263660c0SAlfonso Siciliano 				break;
186263660c0SAlfonso Siciliano 			ytextpad--;
187263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
188263660c0SAlfonso Siciliano 			break;
189263660c0SAlfonso Siciliano 		case KEY_DOWN:
190263660c0SAlfonso Siciliano 			if (ytextpad + h - 4 >= htextpad)
191263660c0SAlfonso Siciliano 				break;
192263660c0SAlfonso Siciliano 			ytextpad++;
193263660c0SAlfonso Siciliano 			textupdate(widget, textpad, htextpad, ytextpad);
194263660c0SAlfonso Siciliano 			break;
195c76f0793SBaptiste Daroussin 		default:
196263660c0SAlfonso Siciliano 			if (shortcut_buttons(input, &bs)) {
197263660c0SAlfonso Siciliano 				output = bs.value[bs.curr];
198c76f0793SBaptiste Daroussin 				loop = false;
199c76f0793SBaptiste Daroussin 			}
200c76f0793SBaptiste Daroussin 		}
201c76f0793SBaptiste Daroussin 	}
202c76f0793SBaptiste Daroussin 
203263660c0SAlfonso Siciliano 	end_dialog(conf, shadow, widget, textpad);
204c76f0793SBaptiste Daroussin 
205263660c0SAlfonso Siciliano 	return (output);
206c76f0793SBaptiste Daroussin }
207c76f0793SBaptiste Daroussin 
208c76f0793SBaptiste Daroussin /* API */
209c76f0793SBaptiste Daroussin int
210263660c0SAlfonso Siciliano bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows,
211263660c0SAlfonso Siciliano     int cols)
212c76f0793SBaptiste Daroussin {
213c76f0793SBaptiste Daroussin 	struct buttons bs;
214c76f0793SBaptiste Daroussin 
215263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL);
216c76f0793SBaptiste Daroussin 
217263660c0SAlfonso Siciliano 	return (do_message(conf, text, rows, cols, bs));
218c76f0793SBaptiste Daroussin }
219c76f0793SBaptiste Daroussin 
220c76f0793SBaptiste Daroussin int
221263660c0SAlfonso Siciliano bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows,
222263660c0SAlfonso Siciliano     int cols)
223c76f0793SBaptiste Daroussin {
224c76f0793SBaptiste Daroussin 	struct buttons bs;
225c76f0793SBaptiste Daroussin 
226263660c0SAlfonso Siciliano 	get_buttons(conf, &bs, "Yes", "No");
227c76f0793SBaptiste Daroussin 
228263660c0SAlfonso Siciliano 	return (do_message(conf, text, rows, cols, bs));
229c76f0793SBaptiste Daroussin }