xref: /freebsd/contrib/bsddialog/lib/barbox.c (revision 7e1d3eefd410ca0fbae5a217422821244c3eeee4)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Alfonso Sabato Siciliano
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef PORTNCURSES
32 #include <ncurses/curses.h>
33 #else
34 #include <curses.h>
35 #endif
36 
37 #include "bsddialog.h"
38 #include "lib_util.h"
39 #include "bsddialog_theme.h"
40 
41 /* "Bar": gauge - mixedgauge - rangebox - pause */
42 
43 extern struct bsddialog_theme t;
44 
45 static void
46 draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel, int label)
47 {
48 	char labelstr[128];
49 	int i, blue_x, color;
50 
51 	blue_x = (int)((perc*(size))/100);
52 
53 	wmove(win, y, x);
54 	for (i = 0; i < size; i++) {
55 		color = (i <= blue_x) ? t.currbarcolor : t.barcolor;
56 		wattron(win, color);
57 		waddch(win, ' ');
58 		wattroff(win, color);
59 	}
60 
61 	if (withlabel)
62 		sprintf(labelstr, "%d", label);
63 	else
64 		sprintf(labelstr, "%3d%%", perc);
65 	wmove(win, y, x + size/2 - 2);
66 	for (i=0; i < (int) strlen(labelstr); i++) {
67 		color = ( (blue_x + 1) <= (size/2 - (int) strlen(labelstr)/2 + i) ) ?
68 		    t.barcolor : t.currbarcolor;
69 		wattron(win, color);
70 		waddch(win, labelstr[i]);
71 		wattroff(win, color);
72 	}
73 }
74 
75 int bsddialog_gauge(struct bsddialog_conf conf, char* text, int rows, int cols, int perc)
76 {
77 	WINDOW *widget, *bar, *shadow;
78 	char input[2048];
79 	int i, y, x;
80 	bool mainloop = true;
81 
82 	if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
83 	    false) <0)
84 		return -1;
85 
86 	bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED);
87 
88 	wrefresh(widget);
89 	wrefresh(bar);
90 
91 	while (mainloop) {
92 		draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/);
93 
94 		wrefresh(widget);
95 		wrefresh(bar);
96 
97 		while (true) {
98 			scanf("%s", input);
99 			if (strcmp(input,"EOF") == 0) {
100 				mainloop = false;
101 				break;
102 			}
103 			if (strcmp(input,"XXX") == 0)
104 				break;
105 		}
106 		scanf("%d", &perc);
107 		perc = perc < 0 ? 0 : perc;
108 		perc = perc > 100 ? 100 : perc;
109 		i = 2;
110 		wmove(widget, 1, 1);
111 		wclrtoeol(widget);
112 		while (true) {
113 			scanf("%s", input);
114 			if (strcmp(input,"EOF") == 0) {
115 				mainloop = false;
116 				break;
117 			}
118 			if (strcmp(input,"XXX") == 0)
119 				break;
120 			//print_text(conf, widget, 1, 1, cols-2, input);
121 			mvwaddstr(widget, 1, i, input);
122 			i = i + strlen(input) + 1;
123 			wrefresh(widget);
124 		}
125 	}
126 
127 	delwin(bar);
128 	end_widget(conf, widget, rows, cols, shadow);
129 
130 	return BSDDIALOG_YESOK;
131 }
132 
133 int bsddialog_mixedgauge(struct bsddialog_conf conf, char* text, int rows, int cols,
134     unsigned int perc, int argc, char **argv)
135 {
136 	WINDOW *widget, *bar, *shadow;
137 	int i, miniperc, y, x;
138 	char states[11][16] = {
139 	    "[  Succeeded  ]",
140 	    "[   Failed    ]",
141 	    "[   Passed    ]",
142 	    "[  Completed  ]",
143 	    "[   Checked   ]",
144 	    "[    Done     ]",
145 	    "[   Skipped   ]",
146 	    "[ In Progress ]",
147 	    "!!!  BLANK  !!!",
148 	    "[     N/A     ]",
149 	    "[   UNKNOWN   ]",};
150 
151 	if (new_widget(conf, &widget, &y, &x, NULL, &rows, &cols, &shadow,
152 	    false) <0)
153 		return -1;
154 
155 	bar = new_boxed_window(conf, y+rows -4, x+3, 3, cols-6, RAISED);
156 
157 	/* mini bars */
158 	for (i=0; i < (argc/2); i++) {
159 		miniperc = atol(argv[i*2 + 1]);
160 		if (miniperc == 8)
161 			continue;
162 		mvwaddstr(widget, i+1, 2, argv[i*2]);
163 		if (miniperc > 9)
164 			mvwaddstr(widget, i+1, cols-2-15, states[10]);
165 		else if (miniperc >= 0 && miniperc <= 9)
166 			mvwaddstr(widget, i+1, cols-2-15, states[miniperc]);
167 		else { //miniperc < 0
168 			miniperc = abs(miniperc);
169 			mvwaddstr(widget, i+1, cols-2-15, "[             ]");
170 			draw_perc_bar(widget, i+1, 1+cols-2-15, 13, miniperc,
171 			    false, -1 /*unused*/);
172 		}
173 	}
174 
175 	print_text(conf, widget, rows-6, 2, cols-2, text);
176 
177 	/* main bar */
178 	draw_perc_bar(bar, 1, 1, cols-8, perc, false, -1 /*unused*/);
179 
180 	wattron(bar, t.barcolor);
181 	mvwaddstr(bar, 0, 2, "Overall Progress");
182 	wattroff(bar, t.barcolor);
183 
184 	wrefresh(widget);
185 	wrefresh(bar);
186 
187 	getch();
188 
189 	delwin(bar);
190 	end_widget(conf, widget, rows, cols, shadow);
191 
192 	return BSDDIALOG_YESOK;
193 }
194 
195 int
196 bsddialog_rangebox(struct bsddialog_conf conf, char* text, int rows, int cols, int min,
197     int max, int *value)
198 {
199 	WINDOW *widget, *bar, *shadow;
200 	int y, x;
201 	bool loop, buttupdate, barupdate;
202 	int input, currvalue, output, sizebar;
203 	float perc;
204 	int positions = max - min + 1;
205 	struct buttons bs;
206 
207 	if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
208 	    true) <0)
209 		return -1;
210 
211 	bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED);
212 
213 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
214 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
215 
216 	if (value == NULL)
217 		RETURN_ERROR("*value == NULL");
218 
219 	currvalue = *value;
220 	sizebar = cols - 16;
221 	loop = buttupdate = barupdate = true;
222 	while(loop) {
223 		if (barupdate) {
224 			perc = ((float)(currvalue - min)*100) / ((float)positions-1);
225 			draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
226 			barupdate = false;
227 			wrefresh(bar);
228 		}
229 
230 		if (buttupdate) {
231 			draw_buttons(widget, rows-2, cols, bs, true);
232 			wrefresh(widget);
233 			buttupdate = false;
234 		}
235 
236 		input = getch();
237 		switch(input) {
238 		case 10: // Enter
239 			output = bs.value[bs.curr]; // values -> outputs
240 			*value = currvalue;
241 			loop = false;
242 			break;
243 		case 27: /* Esc */
244 			output = BSDDIALOG_ESC;
245 			loop = false;
246 			break;
247 		case '\t': // TAB
248 			bs.curr = (bs.curr + 1) % bs.nbuttons;
249 			buttupdate = true;
250 			break;
251 		case KEY_LEFT:
252 			if (bs.curr > 0) {
253 				bs.curr--;
254 				buttupdate = true;
255 			}
256 			break;
257 		case KEY_RIGHT:
258 			if (bs.curr < (int) bs.nbuttons - 1) {
259 				bs.curr++;
260 				buttupdate = true;
261 			}
262 			break;
263 		case KEY_UP:
264 			if (currvalue < max) {
265 				currvalue++;
266 				barupdate = true;
267 			}
268 			break;
269 		case KEY_DOWN:
270 			if (currvalue > min) {
271 				currvalue--;
272 				barupdate = true;
273 			}
274 			break;
275 		}
276 	}
277 
278 	delwin(bar);
279 	end_widget(conf, widget, rows, cols, shadow);
280 
281 	return output;
282 }
283 
284 int bsddialog_pause(struct bsddialog_conf conf, char* text, int rows, int cols, int sec)
285 {
286 	WINDOW *widget, *bar, *shadow;
287 	int output, y, x;
288 	bool loop, buttupdate, barupdate;
289 	int input, currvalue, sizebar;
290 	float perc;
291 	struct buttons bs;
292 
293 	if (new_widget(conf, &widget, &y, &x, text, &rows, &cols, &shadow,
294 	    true) <0)
295 		return -1;
296 
297 	bar = new_boxed_window(conf, y + rows - 6, x +7, 3, cols-14, RAISED);
298 
299 	get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
300 	    BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
301 
302 	currvalue = sec;
303 	sizebar = cols-16;
304 	nodelay(stdscr, TRUE);
305 	timeout(1000);
306 	//wtimeout(buttwin, 2);
307 	loop = buttupdate = barupdate = true;
308 	while(loop) {
309 		if (barupdate) {
310 			perc = ((float)(currvalue*100)) / ((float)sec);
311 			draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
312 			barupdate = false;
313 			wrefresh(bar);
314 		}
315 
316 		if (buttupdate) {
317 			draw_buttons(widget, rows-2, cols, bs, true);
318 			wrefresh(widget);
319 			buttupdate = false;
320 		}
321 
322 		input = getch();
323 		if(input < 0) {
324 			currvalue--;
325 			if (currvalue < 0) {
326 				output = BSDDIALOG_ERROR;
327 				break;
328 			}
329 			else {
330 				barupdate = true;
331 				continue;
332 			}
333 		}
334 		switch(input) {
335 		case 10: // Enter
336 			output = bs.value[bs.curr]; // values -> outputs
337 			loop = false;
338 			break;
339 		case 27: /* Esc */
340 			output = BSDDIALOG_ESC;
341 			loop = false;
342 			break;
343 		case '\t': // TAB
344 			bs.curr = (bs.curr + 1) % bs.nbuttons;
345 			buttupdate = true;
346 			break;
347 		case KEY_LEFT:
348 			if (bs.curr > 0) {
349 				bs.curr--;
350 				buttupdate = true;
351 			}
352 			break;
353 		case KEY_RIGHT:
354 			if (bs.curr < (int) bs.nbuttons - 1) {
355 				bs.curr++;
356 				buttupdate = true;
357 			}
358 			break;
359 		}
360 	}
361 
362 	nodelay(stdscr, FALSE);
363 
364 	delwin(bar);
365 	end_widget(conf, widget, rows, cols, shadow);
366 
367 	return output;
368 }
369 
370