xref: /freebsd/contrib/bsddialog/lib/lib_util.c (revision 681ce946)
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 <sys/param.h>
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #ifdef PORTNCURSES
35 #include <ncurses/ncurses.h>
36 #else
37 #include <ncurses.h>
38 #endif
39 
40 #include "bsddialog.h"
41 #include "lib_util.h"
42 #include "bsddialog_theme.h"
43 
44 extern struct bsddialog_theme t;
45 
46 /* Error buffer */
47 
48 #define ERRBUFLEN 1024
49 static char errorbuffer[ERRBUFLEN];
50 
51 const char *get_error_string(void)
52 {
53 	return errorbuffer;
54 }
55 
56 void set_error_string(char *str)
57 {
58 
59 	strncpy(errorbuffer, str, ERRBUFLEN-1);
60 }
61 
62 /* cleaner */
63 int hide_widget(int y, int x, int h, int w, bool withshadow)
64 {
65 	WINDOW *clear;
66 
67 	/* no check: y, x, h and w are checked by the builders */
68 	if ((clear = newwin(h, w, y + t.shadow.h, x + t.shadow.w)) == NULL)
69 		RETURN_ERROR("Cannot hide the widget");
70 	wbkgd(clear, t.terminal.color);
71 
72 	if (withshadow)
73 		wrefresh(clear);
74 
75 	mvwin(clear, y, x);
76 	wrefresh(clear);
77 
78 	delwin(clear);
79 
80 	return 0;
81 }
82 
83 /* F1 help */
84 int f1help(struct bsddialog_conf *conf)
85 {
86 	int output;
87 	struct bsddialog_conf hconf;
88 
89 	//memcpy(&hconf, conf, sizeof(struct bsddialog_conf));
90 	bsddialog_initconf(&hconf);
91 	hconf.title = "HELP";
92 	hconf.button.ok_label = "EXIT";
93 	hconf.clear = true;
94 	hconf.ascii_lines = conf->ascii_lines;
95 	hconf.no_lines = conf->no_lines;
96 	hconf.shadow = conf->shadow;
97 	hconf.text.colors = conf->text.colors;
98 
99 	output = BSDDIALOG_OK;
100 	if (conf->f1_message != NULL)
101 		output = bsddialog_msgbox(&hconf, conf->f1_message, 0, 0);
102 
103 	if (output != BSDDIALOG_ERROR && conf->f1_file != NULL)
104 		output = bsddialog_textbox(&hconf, conf->f1_file, 0, 0);
105 
106 	return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
107 }
108 
109 /* Buttons */
110 void
111 draw_button(WINDOW *window, int y, int x, int size, char *text, bool selected,
112     bool shortkey)
113 {
114 	int i, color_arrows, color_shortkey, color_button;
115 
116 	if (selected) {
117 		color_arrows = t.button.f_delimcolor;
118 		color_shortkey = t.button.f_shortcutcolor;
119 		color_button = t.button.f_color;
120 	} else {
121 		color_arrows = t.button.delimcolor;
122 		color_shortkey = t.button.shortcutcolor;
123 		color_button = t.button.color;
124 	}
125 
126 	wattron(window, color_arrows);
127 	mvwaddch(window, y, x, t.button.leftch);
128 	wattroff(window, color_arrows);
129 	wattron(window, color_button);
130 	for(i = 1; i < size - 1; i++)
131 		waddch(window, ' ');
132 	wattroff(window, color_button);
133 	wattron(window, color_arrows);
134 	mvwaddch(window, y, x + i, t.button.rightch);
135 	wattroff(window, color_arrows);
136 
137 	x = x + 1 + ((size - 2 - strlen(text))/2);
138 	wattron(window, color_button);
139 	mvwaddstr(window, y, x, text);
140 	wattroff(window, color_button);
141 
142 	if (shortkey) {
143 		wattron(window, color_shortkey);
144 		mvwaddch(window, y, x, text[0]);
145 		wattroff(window, color_shortkey);
146 	}
147 }
148 
149 void
150 draw_buttons(WINDOW *window, int y, int cols, struct buttons bs, bool shortkey)
151 {
152 	int i, x, start_x;
153 
154 	start_x = bs.sizebutton * bs.nbuttons + (bs.nbuttons - 1) * t.button.space;
155 	start_x = cols/2 - start_x/2;
156 
157 	for (i = 0; i < (int) bs.nbuttons; i++) {
158 		x = i * (bs.sizebutton + t.button.space);
159 		draw_button(window, y, start_x + x, bs.sizebutton, bs.label[i],
160 		    i == bs.curr, shortkey);
161 	}
162 }
163 
164 void
165 get_buttons(struct bsddialog_conf *conf, struct buttons *bs, char *yesoklabel,
166     char *extralabel, char *nocancellabel, char *helplabel)
167 {
168 	int i;
169 #define SIZEBUTTON  8
170 #define DEFAULT_BUTTON_LABEL	LABEL_ok_label
171 #define DEFAULT_BUTTON_VALUE	BSDDIALOG_OK
172 
173 
174 	bs->nbuttons = 0;
175 	bs->curr = 0;
176 	bs->sizebutton = 0;
177 
178 	if (yesoklabel != NULL && conf->button.without_ok == false) {
179 		bs->label[0] = yesoklabel;
180 		bs->value[0] = BSDDIALOG_OK;
181 		bs->nbuttons += 1;
182 	}
183 
184 	if (extralabel != NULL && conf->button.with_extra) {
185 		bs->label[bs->nbuttons] = extralabel;
186 		bs->value[bs->nbuttons] = BSDDIALOG_EXTRA;
187 		bs->nbuttons += 1;
188 	}
189 
190 	if (nocancellabel != NULL && conf->button.without_cancel == false) {
191 		bs->label[bs->nbuttons] = nocancellabel;
192 		bs->value[bs->nbuttons] = BSDDIALOG_CANCEL;
193 		if (conf->button.default_cancel)
194 			bs->curr = bs->nbuttons;
195 		bs->nbuttons += 1;
196 	}
197 
198 	if (helplabel != NULL && conf->button.with_help) {
199 		bs->label[bs->nbuttons] = helplabel;
200 		bs->value[bs->nbuttons] = BSDDIALOG_HELP;
201 		bs->nbuttons += 1;
202 	}
203 
204 	if (conf->button.generic1_label != NULL) {
205 		bs->label[bs->nbuttons] = conf->button.generic1_label;
206 		bs->value[bs->nbuttons] = BSDDIALOG_GENERIC1;
207 		bs->nbuttons += 1;
208 	}
209 
210 	if (conf->button.generic2_label != NULL) {
211 		bs->label[bs->nbuttons] = conf->button.generic2_label;
212 		bs->value[bs->nbuttons] = BSDDIALOG_GENERIC2;
213 		bs->nbuttons += 1;
214 	}
215 
216 	if (bs->nbuttons == 0) {
217 		bs->label[0] = DEFAULT_BUTTON_LABEL;
218 		bs->value[0] = DEFAULT_BUTTON_VALUE;
219 		bs->nbuttons = 1;
220 	}
221 
222 	if (conf->button.default_label != NULL) {
223 		for (i=0; i<(int)bs->nbuttons; i++) {
224 			if (strcmp(conf->button.default_label, bs->label[i]) == 0)
225 				bs->curr = i;
226 		}
227 	}
228 
229 	bs->sizebutton = MAX(SIZEBUTTON - 2, strlen(bs->label[0]));
230 	for (i=1; i < (int) bs->nbuttons; i++)
231 		bs->sizebutton = MAX(bs->sizebutton, strlen(bs->label[i]));
232 	bs->sizebutton += 2;
233 }
234 
235 /* Text */
236 static bool is_ncurses_attr(char *text)
237 {
238 
239 	if (strnlen(text, 3) < 3)
240 		return false;
241 
242 	if (text[0] != '\\' || text[1] != 'Z')
243 		return false;
244 
245 	return (strchr("nbBrRuU01234567", text[2]) == NULL ? false : true);
246 }
247 
248 static bool check_set_ncurses_attr(WINDOW *win, char *text)
249 {
250 
251 	if (is_ncurses_attr(text) == false)
252 		return false;
253 
254 	if ((text[2] - '0') >= 0 && (text[2] - '0') < 8) {
255 		wattron(win, bsddialog_color( text[2] - '0', COLOR_WHITE, 0));
256 		return true;
257 	}
258 
259 	switch (text[2]) {
260 	case 'n':
261 		wattrset(win, A_NORMAL);
262 		break;
263 	case 'b':
264 		wattron(win, A_BOLD);
265 		break;
266 	case 'B':
267 		wattroff(win, A_BOLD);
268 		break;
269 	case 'r':
270 		wattron(win, A_REVERSE);
271 		break;
272 	case 'R':
273 		wattroff(win, A_REVERSE);
274 		break;
275 	case 'u':
276 		wattron(win, A_UNDERLINE);
277 		break;
278 	case 'U':
279 		wattroff(win, A_UNDERLINE);
280 		break;
281 	}
282 
283 	return true;
284 }
285 
286 static void
287 print_str(WINDOW *win, int *rows, int *y, int *x, int cols, char *str, bool color)
288 {
289 	int i, j, len, reallen;
290 
291 	if(strlen(str) == 0)
292 		return;
293 
294 	len = reallen = strlen(str);
295 	if (color) {
296 		i=0;
297 		while (i < len) {
298 			if (is_ncurses_attr(str+i))
299 				reallen -= 3;
300 			i++;
301 		}
302 	}
303 
304 	i = 0;
305 	while (i < len) {
306 		if (*x + reallen > cols) {
307 			*y = (*x != 0 ? *y+1 : *y);
308 			if (*y >= *rows) {
309 				*rows = *y + 1;
310 				wresize(win, *rows, cols);
311 			}
312 			*x = 0;
313 		}
314 		j = *x;
315 		while (j < cols && i < len) {
316 			if (color && check_set_ncurses_attr(win, str+i)) {
317 				i += 3;
318 			} else {
319 				mvwaddch(win, *y, j, str[i]);
320 				i++;
321 				reallen--;
322 				j++;
323 				*x = j;
324 			}
325 		}
326 	}
327 }
328 
329 int
330 get_text_properties(struct bsddialog_conf *conf, char *text, int *maxword,
331     int *maxline, int *nlines)
332 {
333 	int i, buflen, wordlen, linelen;
334 
335 
336 	buflen = strlen(text) + 1;
337 	*maxword = 0;
338 	wordlen = 0;
339 	for (i=0; i < buflen; i++) {
340 		if (text[i] == '\t' || text[i] == '\n' || text[i] == ' ' || text[i] == '\0')
341 			if (wordlen != 0) {
342 				*maxword = MAX(*maxword, wordlen);
343 				wordlen = 0;
344 				continue;
345 			}
346 		if (conf->text.colors && is_ncurses_attr(text + i))
347 			i += 3;
348 		else
349 			wordlen++;
350 	}
351 
352 	*maxline = linelen = 0;
353 	*nlines = 1;
354 	for (i=0; i < buflen; i++) {
355 		switch (text[i]) {
356 		case '\n':
357 			*nlines = *nlines + 1;
358 		case '\0':
359 			*maxline = MAX(*maxline, linelen);
360 			linelen = 0;
361 			break;
362 		default:
363 			if (conf->text.colors && is_ncurses_attr(text + i))
364 				i += 3;
365 			else
366 				linelen++;
367 		}
368 	}
369 	if (*nlines == 1 && *maxline == 0)
370 		*nlines = 0;
371 
372 	//free(buf);
373 
374 	return 0;
375 }
376 
377 int
378 print_textpad(struct bsddialog_conf *conf, WINDOW *pad, int *rows, int cols,
379     char *text)
380 {
381 	char *string;
382 	int i, j, x, y;
383 	bool loop;
384 
385 	if ((string = malloc(strlen(text) + 1)) == NULL)
386 		RETURN_ERROR("Cannot build (analyze) text");
387 
388 	i = j = x = y = 0;
389 	loop = true;
390 	while (loop) {
391 		string[j] = text[i];
392 
393 		if (string[j] == '\0' || string[j] == '\n' ||
394 		    string[j] == '\t' || string[j] == ' ') {
395 			if (j != 0) {
396 				string[j] = '\0';
397 				print_str(pad, rows, &y, &x, cols, string,
398 				    conf->text.colors);
399 			}
400 		}
401 
402 		switch (text[i]) {
403 		case '\0':
404 			loop = false;
405 			break;
406 		case '\n':
407 			j = -1;
408 			x = 0;
409 			y++;
410 			break;
411 		case '\t':
412 			for (j=0; j<4 /*tablen*/; j++) {
413 				x++;
414 				if (x >= cols) {
415 					x = 0;
416 					y++;
417 				}
418 			}
419 			j = -1;
420 			break;
421 		case ' ':
422 			x++;
423 			if (x >= cols) {
424 				x = 0;
425 				y++;
426 			}
427 			j = -1;
428 		}
429 
430 		if (y >= *rows) { /* check for whitespaces */
431 			*rows = y + 1;
432 			wresize(pad, *rows, cols);
433 		}
434 
435 		j++;
436 		i++;
437 	}
438 
439 	free(string);
440 
441 	return 0;
442 }
443 
444 /* autosize */
445 
446 /*
447  * max y, that is from 0 to LINES - 1 - t.shadowrows,
448  * could not be max height but avoids problems with checksize
449  */
450 int widget_max_height(struct bsddialog_conf *conf)
451 {
452 	int maxheight;
453 
454 	if ((maxheight = conf->shadow ? LINES - 1 - t.shadow.h : LINES - 1) <= 0)
455 		RETURN_ERROR("Terminal too small, LINES - shadow <= 0");
456 
457 	if (conf->y > 0)
458 		if ((maxheight -= conf->y) <=0)
459 			RETURN_ERROR("Terminal too small, LINES - shadow - y <= 0");
460 
461 	return maxheight;
462 }
463 
464 /*
465  * max x, that is from 0 to COLS - 1 - t.shadowcols,
466  *  * could not be max height but avoids problems with checksize
467  */
468 int widget_max_width(struct bsddialog_conf *conf)
469 {
470 	int maxwidth;
471 
472 	if ((maxwidth = conf->shadow ? COLS - 1 - t.shadow.w : COLS - 1)  <= 0)
473 		RETURN_ERROR("Terminal too small, COLS - shadow <= 0");
474 	if (conf->x > 0)
475 		if ((maxwidth -= conf->x) <=0)
476 			RETURN_ERROR("Terminal too small, COLS - shadow - x <= 0");
477 
478 	return maxwidth;
479 }
480 
481 int
482 set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
483 {
484 	int maxheight, maxwidth;
485 
486 	if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
487 		return BSDDIALOG_ERROR;
488 
489 	if (rows == BSDDIALOG_FULLSCREEN)
490 		*h = maxheight;
491 	else if (rows < BSDDIALOG_FULLSCREEN)
492 		RETURN_ERROR("Negative (less than -1) height");
493 	else if (rows > BSDDIALOG_AUTOSIZE) {
494 		if ((*h = rows) > maxheight)
495 			RETURN_ERROR("Height too big (> terminal height - "\
496 			    "shadow");
497 	}
498 	/* rows == AUTOSIZE: each widget has to set its size */
499 
500 	if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
501 		return BSDDIALOG_ERROR;
502 
503 	if (cols == BSDDIALOG_FULLSCREEN)
504 		*w = maxwidth;
505 	else if (cols < BSDDIALOG_FULLSCREEN)
506 		RETURN_ERROR("Negative (less than -1) width");
507 	else if (cols > BSDDIALOG_AUTOSIZE) {
508 		if ((*w = cols) > maxwidth)
509 			RETURN_ERROR("Width too big (> terminal width - shadow)");
510 	}
511 	/* cols == AUTOSIZE: each widget has to set its size */
512 
513 	return 0;
514 }
515 
516 int
517 set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
518 {
519 
520 	if (conf->y == BSDDIALOG_CENTER)
521 		*y = LINES/2 - h/2;
522 	else if (conf->y < BSDDIALOG_CENTER)
523 		RETURN_ERROR("Negative begin y (less than -1)");
524 	else if (conf->y >= LINES)
525 		RETURN_ERROR("Begin Y under the terminal");
526 	else
527 		*y = conf->y;
528 
529 	if ((*y + h + (conf->shadow ? (int) t.shadow.h : 0)) > LINES)
530 		RETURN_ERROR("The lower of the box under the terminal "\
531 		    "(begin Y + height (+ shadow) > terminal lines)");
532 
533 
534 	if (conf->x == BSDDIALOG_CENTER)
535 		*x = COLS/2 - w/2;
536 	else if (conf->x < BSDDIALOG_CENTER)
537 		RETURN_ERROR("Negative begin x (less than -1)");
538 	else if (conf->x >= COLS)
539 		RETURN_ERROR("Begin X over the right of the terminal");
540 	else
541 		*x = conf->x;
542 
543 	if ((*x + w + (conf->shadow ? (int) t.shadow.w : 0)) > COLS)
544 		RETURN_ERROR("The right of the box over the terminal "\
545 		    "(begin X + width (+ shadow) > terminal cols)");
546 
547 	return 0;
548 }
549 
550 /* Widgets builders */
551 void
552 draw_borders(struct bsddialog_conf *conf, WINDOW *win, int rows, int cols,
553     enum elevation elev)
554 {
555 	int leftcolor, rightcolor;
556 	int ls, rs, ts, bs, tl, tr, bl, br;
557 	int ltee, rtee;
558 
559 	ls = rs = ACS_VLINE;
560 	ts = bs = ACS_HLINE;
561 	tl = ACS_ULCORNER;
562 	tr = ACS_URCORNER;
563 	bl = ACS_LLCORNER;
564 	br = ACS_LRCORNER;
565 	ltee = ACS_LTEE;
566 	rtee = ACS_RTEE;
567 
568 	if (conf->no_lines == false) {
569 		if (conf->ascii_lines) {
570 			ls = rs = '|';
571 			ts = bs = '-';
572 			tl = tr = bl = br = ltee = rtee = '+';
573 		}
574 		leftcolor  = elev == RAISED ?
575 		    t.dialog.lineraisecolor : t.dialog.linelowercolor;
576 		rightcolor = elev == RAISED ?
577 		    t.dialog.linelowercolor : t.dialog.lineraisecolor;
578 		wattron(win, leftcolor);
579 		wborder(win, ls, rs, ts, bs, tl, tr, bl, br);
580 		wattroff(win, leftcolor);
581 
582 		wattron(win, rightcolor);
583 		mvwaddch(win, 0, cols-1, tr);
584 		mvwvline(win, 1, cols-1, rs, rows-2);
585 		mvwaddch(win, rows-1, cols-1, br);
586 		mvwhline(win, rows-1, 1, bs, cols-2);
587 		wattroff(win, rightcolor);
588 	}
589 }
590 
591 WINDOW *
592 new_boxed_window(struct bsddialog_conf *conf, int y, int x, int rows, int cols,
593     enum elevation elev)
594 {
595 	WINDOW *win;
596 
597 	if ((win = newwin(rows, cols, y, x)) == NULL) {
598 		set_error_string("Cannot build boxed window");
599 		return NULL;
600 	}
601 
602 	wbkgd(win, t.dialog.color);
603 
604 	draw_borders(conf, win, rows, cols, elev);
605 
606 	return win;
607 }
608 
609 /*
610  * `enum elevation elev` could be useless because it should be always RAISED,
611  * to check at the end.
612  */
613 static int
614 draw_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow,
615     WINDOW *widget, int h, int w, enum elevation elev,
616     WINDOW *textpad, int *htextpad, char *text, bool buttons)
617 {
618 	int ts, ltee, rtee;
619 	int colordelimtitle;
620 
621 	ts = conf->ascii_lines ? '-' : ACS_HLINE;
622 	ltee = conf->ascii_lines ? '+' : ACS_LTEE;
623 	rtee = conf->ascii_lines ? '+' : ACS_RTEE;
624 	colordelimtitle = elev == RAISED ?
625 	    t.dialog.lineraisecolor : t.dialog.linelowercolor;
626 
627 	if (shadow != NULL)
628 		wnoutrefresh(shadow);
629 
630 	// move / resize now or the caller?
631 	draw_borders(conf, widget, h, w, elev);
632 
633 	if (conf->title != NULL) {
634 		if (t.dialog.delimtitle && conf->no_lines == false) {
635 			wattron(widget, colordelimtitle);
636 			mvwaddch(widget, 0, w/2 - strlen(conf->title)/2 - 1, rtee);
637 			wattroff(widget, colordelimtitle);
638 		}
639 		wattron(widget, t.dialog.titlecolor);
640 		mvwaddstr(widget, 0, w/2 - strlen(conf->title)/2, conf->title);
641 		wattroff(widget, t.dialog.titlecolor);
642 		if (t.dialog.delimtitle && conf->no_lines == false) {
643 			wattron(widget, colordelimtitle);
644 			waddch(widget, ltee);
645 			wattroff(widget, colordelimtitle);
646 		}
647 	}
648 
649 	if (conf->bottomtitle != NULL) {
650 		wattron(widget, t.dialog.bottomtitlecolor);
651 		wmove(widget, h - 1, w/2 - strlen(conf->bottomtitle)/2 - 1);
652 		waddch(widget, '[');
653 		waddstr(widget, conf->bottomtitle);
654 		waddch(widget, ']');
655 		wattroff(widget, t.dialog.bottomtitlecolor);
656 	}
657 
658 	//if (textpad == NULL && text != NULL) /* no pad, text null for textbox */
659 	//	print_text(conf, widget, 1, 2, w-3, text);
660 
661 	if (buttons && conf->no_lines == false) {
662 		wattron(widget, t.dialog.lineraisecolor);
663 		mvwaddch(widget, h-3, 0, ltee);
664 		mvwhline(widget, h-3, 1, ts, w-2);
665 		wattroff(widget, t.dialog.lineraisecolor);
666 
667 		wattron(widget, t.dialog.linelowercolor);
668 		mvwaddch(widget, h-3, w-1, rtee);
669 		wattroff(widget, t.dialog.linelowercolor);
670 	}
671 
672 	wnoutrefresh(widget);
673 
674 	if (textpad == NULL)
675 		return 0; /* widget_init() ends */
676 
677 	if (text != NULL) /* programbox etc */
678 		if (print_textpad(conf, textpad, htextpad,
679 		    w - HBORDERS - t.text.hmargin * 2, text) !=0)
680 			return BSDDIALOG_ERROR;
681 
682 	return 0;
683 }
684 
685 /*
686  * `enum elevation elev` could be useless because it should be always RAISED,
687  * to check at the end.
688  */
689 int
690 update_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *shadow,
691     WINDOW *widget, int h, int w, enum elevation elev,
692     WINDOW *textpad, int *htextpad, char *text, bool buttons)
693 {
694 	int error;
695 
696 	/* nothing for now */
697 
698 	error =  draw_widget_withtextpad(conf, shadow, widget, h, w,
699 	    elev, textpad, htextpad, text, buttons);
700 
701 	return error;
702 }
703 
704 /*
705  * `enum elevation elev` could be useless because it should be always RAISED,
706  * to check at the end.
707  */
708 int
709 new_widget_withtextpad(struct bsddialog_conf *conf, WINDOW **shadow,
710     WINDOW **widget, int y, int x, int h, int w, enum elevation elev,
711     WINDOW **textpad, int *htextpad, char *text, bool buttons)
712 {
713 	int error;
714 
715 	if (conf->shadow) {
716 		*shadow = newwin(h, w, y + t.shadow.h, x + t.shadow.w);
717 		if (*shadow == NULL)
718 			RETURN_ERROR("Cannot build shadow");
719 		wbkgd(*shadow, t.shadow.color);
720 	}
721 
722 	if ((*widget = new_boxed_window(conf, y, x, h, w, elev)) == NULL) {
723 		if (conf->shadow)
724 			delwin(*shadow);
725 		return BSDDIALOG_ERROR;
726 	}
727 
728 	if (textpad == NULL) { /* widget_init() */
729 		error =  draw_widget_withtextpad(conf, *shadow, *widget, h, w,
730 		    elev, NULL, NULL, text, buttons);
731 		return error;
732 	}
733 
734 	if (text != NULL) { /* programbox etc */
735 		*htextpad = 1;
736 		*textpad = newpad(*htextpad, w - HBORDERS - t.text.hmargin * 2);
737 		if (*textpad == NULL) {
738 			delwin(*textpad);
739 			if (conf->shadow)
740 				delwin(*shadow);
741 			RETURN_ERROR("Cannot build the pad window for text");
742 		}
743 		wbkgd(*textpad, t.dialog.color);
744 	}
745 
746 	error =  draw_widget_withtextpad(conf, *shadow, *widget, h, w, elev,
747 	    *textpad, htextpad, text, buttons);
748 
749 	return error;
750 }
751 
752 void
753 end_widget_withtextpad(struct bsddialog_conf *conf, WINDOW *window, int h, int w,
754     WINDOW *textpad, WINDOW *shadow)
755 {
756 	int y, x;
757 
758 	getbegyx(window, y, x); /* for clear, add y & x to args? */
759 
760 	if (conf->sleep > 0)
761 		sleep(conf->sleep);
762 
763 	if (textpad != NULL)
764 		delwin(textpad);
765 
766 	delwin(window);
767 
768 	if (conf->shadow)
769 		delwin(shadow);
770 
771 	if (conf->clear)
772 		hide_widget(y, x, h, w, shadow != NULL);
773 
774 	if (conf->get_height != NULL)
775 		*conf->get_height = h;
776 	if (conf->get_width != NULL)
777 		*conf->get_width = w;
778 }
779