1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021-2025 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 <stdarg.h>
29 #include <curses.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <wctype.h>
34
35 #include "bsddialog.h"
36 #include "bsddialog_theme.h"
37 #include "lib_util.h"
38
39 /*
40 * -1- Error and diagnostic
41 *
42 * get_error_string();
43 * set_error_string();
44 * set_fmt_error_string();
45 *
46 * ----------------------------------------------------
47 * -2- (Unicode) Multicolumn character strings
48 *
49 * alloc_mbstows();
50 * mvwaddwch();
51 * str_props();
52 * strcols();
53 *
54 * ----------------------------------------------------
55 * -3- Buttons
56 *
57 * [static] buttons_min_width();
58 * [static] draw_button();
59 * draw_buttons();
60 * set_buttons(); (to call 1 time after prepare_dialog()).
61 * shortcut_buttons();
62 *
63 * ----------------------------------------------------
64 * -4- (Auto) Sizing and (Auto) Position
65 *
66 * [static] widget_max_height(conf);
67 * [static] widget_max_width(struct bsddialog_conf *conf)
68 * [static] is_wtext_attr();
69 * [static] text_properties();
70 * [static] text_autosize();
71 * [static] text_size();
72 * [static] widget_min_height(conf, htext, hnotext, bool buttons);
73 * [static] widget_min_width(conf, wtext, minw, buttons);
74 * set_widget_size();
75 * set_widget_autosize(); (not for all dialogs).
76 * widget_checksize(); (not for all dialogs).
77 * set_widget_position();
78 * dialog_size_position(struct dialog); (not for all dialogs).
79 *
80 * ----------------------------------------------------
81 * -5- (Dialog) Widget components and utils
82 *
83 * hide_dialog(struct dialog);
84 * f1help_dialog(conf);
85 * draw_borders(conf, win, elev);
86 * update_box(conf, win, y, x, h, w, elev);
87 * rtextpad(); (helper for pnoutrefresh(textpad)).
88 *
89 * ----------------------------------------------------
90 * -6- Dialog init/build, update/draw, destroy
91 *
92 * end_dialog(struct dialog);
93 * [static] check_set_wtext_attr();
94 * [static] print_string(); (word wrapping).
95 * [static] print_textpad();
96 * draw_dialog(struct dialog);
97 * prepare_dialog(struct dialog);
98 */
99
100 /*
101 * -1- Error and diagnostic
102 */
103 #define ERRBUFLEN 1024
104
105 static char errorbuffer[ERRBUFLEN];
106
get_error_string(void)107 const char *get_error_string(void)
108 {
109 return (errorbuffer);
110 }
111
set_error_string(const char * str)112 void set_error_string(const char *str)
113 {
114 strncpy(errorbuffer, str, ERRBUFLEN-1);
115 }
116
set_fmt_error_string(const char * fmt,...)117 void set_fmt_error_string(const char *fmt, ...)
118 {
119 va_list arg_ptr;
120
121 va_start(arg_ptr, fmt);
122 vsnprintf(errorbuffer, ERRBUFLEN-1, fmt, arg_ptr);
123 va_end(arg_ptr);
124 }
125
126 /*
127 * -2- (Unicode) Multicolumn character strings
128 */
alloc_mbstows(const char * mbstring)129 wchar_t* alloc_mbstows(const char *mbstring)
130 {
131 size_t charlen, nchar;
132 mbstate_t mbs;
133 const char *pmbstring;
134 wchar_t *wstring;
135
136 nchar = 1;
137 pmbstring = mbstring;
138 memset(&mbs, 0, sizeof(mbs));
139 while ((charlen = mbrlen(pmbstring, MB_CUR_MAX, &mbs)) != 0 &&
140 charlen != (size_t)-1 && charlen != (size_t)-2) {
141 pmbstring += charlen;
142 nchar++;
143 }
144
145 if ((wstring = calloc(nchar, sizeof(wchar_t))) == NULL)
146 return (NULL);
147 mbstowcs(wstring, mbstring, nchar);
148
149 return (wstring);
150 }
151
mvwaddwch(WINDOW * w,int y,int x,wchar_t wch)152 void mvwaddwch(WINDOW *w, int y, int x, wchar_t wch)
153 {
154 wchar_t ws[2];
155
156 ws[0] = wch;
157 ws[1] = L'\0';
158 mvwaddwstr(w, y, x, ws);
159 }
160
str_props(const char * mbstring,unsigned int * cols,bool * has_multi_col)161 int str_props(const char *mbstring, unsigned int *cols, bool *has_multi_col)
162 {
163 bool multicol;
164 int w;
165 unsigned int ncol;
166 size_t charlen, mb_cur_max;
167 wchar_t wch;
168 mbstate_t mbs;
169
170 multicol = false;
171 mb_cur_max = MB_CUR_MAX;
172 ncol = 0;
173 memset(&mbs, 0, sizeof(mbs));
174 while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
175 charlen != (size_t)-1 && charlen != (size_t)-2) {
176 if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
177 return (-1);
178 w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
179 ncol += (w < 0) ? 0 : w;
180 if (w > 1 && wch != L'\t')
181 multicol = true;
182 mbstring += charlen;
183 }
184
185 if (cols != NULL)
186 *cols = ncol;
187 if (has_multi_col != NULL)
188 *has_multi_col = multicol;
189
190 return (0);
191 }
192
strcols(const char * mbstring)193 unsigned int strcols(const char *mbstring)
194 {
195 int w;
196 unsigned int ncol;
197 size_t charlen, mb_cur_max;
198 wchar_t wch;
199 mbstate_t mbs;
200
201 mb_cur_max = MB_CUR_MAX;
202 ncol = 0;
203 memset(&mbs, 0, sizeof(mbs));
204 while ((charlen = mbrlen(mbstring, mb_cur_max, &mbs)) != 0 &&
205 charlen != (size_t)-1 && charlen != (size_t)-2) {
206 if (mbtowc(&wch, mbstring, mb_cur_max) < 0)
207 return (0);
208 w = (wch == L'\t') ? TABSIZE : wcwidth(wch);
209 ncol += (w < 0) ? 0 : w;
210 mbstring += charlen;
211 }
212
213 return (ncol);
214 }
215
216 /*
217 * -3- Buttons
218 */
buttons_min_width(struct buttons * bs)219 static int buttons_min_width(struct buttons *bs)
220 {
221 unsigned int width;
222
223 width = bs->nbuttons * bs->sizebutton;
224 if (bs->nbuttons > 0)
225 width += (bs->nbuttons - 1) * t.button.minmargin;
226
227 return (width);
228 }
229
230 static void
draw_button(WINDOW * window,int y,int x,int size,const char * text,wchar_t first,bool selected,bool shortcut)231 draw_button(WINDOW *window, int y, int x, int size, const char *text,
232 wchar_t first, bool selected, bool shortcut)
233 {
234 int i, color_arrows, color_shortkey, color_button;
235
236 if (selected) {
237 color_arrows = t.button.f_delimcolor;
238 color_shortkey = t.button.f_shortcutcolor;
239 color_button = t.button.f_color;
240 } else {
241 color_arrows = t.button.delimcolor;
242 color_shortkey = t.button.shortcutcolor;
243 color_button = t.button.color;
244 }
245
246 wattron(window, color_arrows);
247 mvwaddch(window, y, x, t.button.leftdelim);
248 wattroff(window, color_arrows);
249 wattron(window, color_button);
250 for (i = 1; i < size - 1; i++)
251 waddch(window, ' ');
252 wattroff(window, color_button);
253 wattron(window, color_arrows);
254 mvwaddch(window, y, x + i, t.button.rightdelim);
255 wattroff(window, color_arrows);
256
257 x = x + 1 + ((size - 2 - strcols(text))/2);
258 wattron(window, color_button);
259 mvwaddstr(window, y, x, text);
260 wattroff(window, color_button);
261
262 if (shortcut) {
263 wattron(window, color_shortkey);
264 mvwaddwch(window, y, x, first);
265 wattroff(window, color_shortkey);
266 }
267 }
268
draw_buttons(struct dialog * d)269 void draw_buttons(struct dialog *d)
270 {
271 int i, x, startx, y;
272 unsigned int newmargin, margin, wbuttons;
273
274 y = d->h - 2;
275
276 newmargin = d->w - BORDERS - (d->bs.nbuttons * d->bs.sizebutton);
277 newmargin /= (d->bs.nbuttons + 1);
278 newmargin = MIN(newmargin, t.button.maxmargin);
279 if (newmargin == 0) {
280 margin = t.button.minmargin;
281 wbuttons = buttons_min_width(&d->bs);
282 } else {
283 margin = newmargin;
284 wbuttons = d->bs.nbuttons * d->bs.sizebutton;
285 wbuttons += (d->bs.nbuttons + 1) * margin;
286 }
287
288 startx = d->w/2 - wbuttons/2 + newmargin;
289 for (i = 0; i < (int)d->bs.nbuttons; i++) {
290 x = i * (d->bs.sizebutton + margin);
291 draw_button(d->widget, y, startx + x, d->bs.sizebutton,
292 d->bs.label[i], d->bs.first[i], i == d->bs.curr,
293 d->bs.shortcut);
294 }
295 }
296
297 void
set_buttons(struct dialog * d,bool shortcut,const char * oklabel,const char * cancellabel)298 set_buttons(struct dialog *d, bool shortcut, const char *oklabel,
299 const char *cancellabel)
300 {
301 int i;
302 #define SIZEBUTTON 8
303 #define DEFAULT_BUTTON_LABEL OK_LABEL
304 #define DEFAULT_BUTTON_VALUE BSDDIALOG_OK
305 wchar_t first;
306
307 d->bs.nbuttons = 0;
308 d->bs.curr = 0;
309 d->bs.sizebutton = 0;
310 d->bs.shortcut = shortcut;
311
312 if (d->conf->button.left1_label != NULL) {
313 d->bs.label[d->bs.nbuttons] = d->conf->button.left1_label;
314 d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT1;
315 d->bs.nbuttons += 1;
316 }
317
318 if (d->conf->button.left2_label != NULL) {
319 d->bs.label[d->bs.nbuttons] = d->conf->button.left2_label;
320 d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT2;
321 d->bs.nbuttons += 1;
322 }
323
324 if (d->conf->button.left3_label != NULL) {
325 d->bs.label[d->bs.nbuttons] = d->conf->button.left3_label;
326 d->bs.value[d->bs.nbuttons] = BSDDIALOG_LEFT3;
327 d->bs.nbuttons += 1;
328 }
329
330 if (oklabel != NULL && d->conf->button.without_ok == false) {
331 d->bs.label[d->bs.nbuttons] = d->conf->button.ok_label != NULL ?
332 d->conf->button.ok_label : oklabel;
333 d->bs.value[d->bs.nbuttons] = BSDDIALOG_OK;
334 d->bs.nbuttons += 1;
335 }
336
337 if (d->conf->button.with_extra) {
338 d->bs.label[d->bs.nbuttons] = d->conf->button.extra_label != NULL ?
339 d->conf->button.extra_label : "Extra";
340 d->bs.value[d->bs.nbuttons] = BSDDIALOG_EXTRA;
341 d->bs.nbuttons += 1;
342 }
343
344 if (cancellabel != NULL && d->conf->button.without_cancel == false) {
345 d->bs.label[d->bs.nbuttons] = d->conf->button.cancel_label ?
346 d->conf->button.cancel_label : cancellabel;
347 d->bs.value[d->bs.nbuttons] = BSDDIALOG_CANCEL;
348 if (d->conf->button.default_cancel)
349 d->bs.curr = d->bs.nbuttons;
350 d->bs.nbuttons += 1;
351 }
352
353 if (d->conf->button.with_help) {
354 d->bs.label[d->bs.nbuttons] = d->conf->button.help_label != NULL ?
355 d->conf->button.help_label : "Help";
356 d->bs.value[d->bs.nbuttons] = BSDDIALOG_HELP;
357 d->bs.nbuttons += 1;
358 }
359
360 if (d->conf->button.right1_label != NULL) {
361 d->bs.label[d->bs.nbuttons] = d->conf->button.right1_label;
362 d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT1;
363 d->bs.nbuttons += 1;
364 }
365
366 if (d->conf->button.right2_label != NULL) {
367 d->bs.label[d->bs.nbuttons] = d->conf->button.right2_label;
368 d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT2;
369 d->bs.nbuttons += 1;
370 }
371
372 if (d->conf->button.right3_label != NULL) {
373 d->bs.label[d->bs.nbuttons] = d->conf->button.right3_label;
374 d->bs.value[d->bs.nbuttons] = BSDDIALOG_RIGHT3;
375 d->bs.nbuttons += 1;
376 }
377
378 if (d->bs.nbuttons == 0) {
379 d->bs.label[0] = DEFAULT_BUTTON_LABEL;
380 d->bs.value[0] = DEFAULT_BUTTON_VALUE;
381 d->bs.nbuttons = 1;
382 }
383
384 for (i = 0; i < (int)d->bs.nbuttons; i++) {
385 mbtowc(&first, d->bs.label[i], MB_CUR_MAX);
386 d->bs.first[i] = first;
387 }
388
389 if (d->conf->button.default_label != NULL) {
390 for (i = 0; i < (int)d->bs.nbuttons; i++) {
391 if (strcmp(d->conf->button.default_label,
392 d->bs.label[i]) == 0)
393 d->bs.curr = i;
394 }
395 }
396
397 d->bs.sizebutton = MAX(SIZEBUTTON - 2, strcols(d->bs.label[0]));
398 for (i = 1; i < (int)d->bs.nbuttons; i++)
399 d->bs.sizebutton = MAX(d->bs.sizebutton, strcols(d->bs.label[i]));
400 d->bs.sizebutton += 2;
401 }
402
shortcut_buttons(wint_t key,struct buttons * bs)403 bool shortcut_buttons(wint_t key, struct buttons *bs)
404 {
405 bool match;
406 unsigned int i;
407
408 match = false;
409 for (i = 0; i < bs->nbuttons; i++) {
410 if (towlower(key) == towlower(bs->first[i])) {
411 bs->curr = i;
412 match = true;
413 break;
414 }
415 }
416
417 return (match);
418 }
419
420 /*
421 * -4- (Auto) Sizing and (Auto) Position
422 */
widget_max_height(struct bsddialog_conf * conf)423 static int widget_max_height(struct bsddialog_conf *conf)
424 {
425 int maxheight;
426
427 maxheight = conf->shadow ? SCREENLINES - (int)t.shadow.y : SCREENLINES;
428 if (maxheight <= 0)
429 RETURN_ERROR("Terminal too small, screen lines - shadow <= 0");
430
431 if (conf->y != BSDDIALOG_CENTER && conf->auto_topmargin > 0)
432 RETURN_ERROR("conf.y > 0 and conf->auto_topmargin > 0");
433 else if (conf->y == BSDDIALOG_CENTER) {
434 maxheight -= conf->auto_topmargin;
435 if (maxheight <= 0)
436 RETURN_ERROR("Terminal too small, screen lines - top "
437 "margins <= 0");
438 } else if (conf->y > 0) {
439 maxheight -= conf->y;
440 if (maxheight <= 0)
441 RETURN_ERROR("Terminal too small, screen lines - "
442 "shadow - y <= 0");
443 }
444
445 maxheight -= conf->auto_downmargin;
446 if (maxheight <= 0)
447 RETURN_ERROR("Terminal too small, screen lines - Down margins "
448 "<= 0");
449
450 return (maxheight);
451 }
452
widget_max_width(struct bsddialog_conf * conf)453 static int widget_max_width(struct bsddialog_conf *conf)
454 {
455 int maxwidth;
456
457 maxwidth = conf->shadow ? SCREENCOLS - (int)t.shadow.x : SCREENCOLS;
458 if (maxwidth <= 0)
459 RETURN_ERROR("Terminal too small, screen cols - shadow <= 0");
460
461 if (conf->x > 0) {
462 maxwidth -= conf->x;
463 if (maxwidth <= 0)
464 RETURN_ERROR("Terminal too small, screen cols - shadow "
465 "- x <= 0");
466 }
467
468 return (maxwidth);
469 }
470
is_wtext_attr(const wchar_t * wtext)471 static bool is_wtext_attr(const wchar_t *wtext)
472 {
473 bool att;
474
475 if (wcsnlen(wtext, 3) < 3)
476 return (false);
477 if (wtext[0] != L'\\' || wtext[1] != L'Z')
478 return (false);
479
480 att = wcschr(L"nbBdDkKrRsSuU01234567", wtext[2]) == NULL ? false : true;
481
482 return (att);
483 }
484
485 #define NL -1
486 #define WS -2
487 #define TB -3
488
489 struct textproperties {
490 int nword;
491 int *words;
492 uint8_t *wletters;
493 int maxwordcols;
494 int maxline;
495 bool hasnewline;
496 };
497
498 static int
text_properties(struct bsddialog_conf * conf,const char * text,struct textproperties * tp)499 text_properties(struct bsddialog_conf *conf, const char *text,
500 struct textproperties *tp)
501 {
502 int i, l, currlinecols, maxwords, wtextlen, tablen, wordcols;
503 wchar_t *wtext;
504
505 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
506
507 maxwords = 1024;
508 if ((tp->words = calloc(maxwords, sizeof(int))) == NULL)
509 RETURN_ERROR("Cannot alloc memory for text autosize");
510
511 if ((wtext = alloc_mbstows(text)) == NULL)
512 RETURN_ERROR("Cannot allocate/autosize text in wchar_t*");
513 wtextlen = wcslen(wtext);
514 if ((tp->wletters = calloc(wtextlen, sizeof(uint8_t))) == NULL)
515 RETURN_ERROR("Cannot allocate wletters for text autosizing");
516
517 tp->nword = 0;
518 tp->maxline = 0;
519 tp->maxwordcols = 0;
520 tp->hasnewline = false;
521 currlinecols = 0;
522 wordcols = 0;
523 l = 0;
524 for (i = 0; i < wtextlen; i++) {
525 if (conf->text.escape && is_wtext_attr(wtext + i)) {
526 i += 2; /* +1 for update statement */
527 continue;
528 }
529
530 if (tp->nword + 1 >= maxwords) {
531 maxwords += 1024;
532 tp->words = realloc(tp->words, maxwords * sizeof(int));
533 if (tp->words == NULL)
534 RETURN_ERROR("Cannot realloc memory for text "
535 "autosize");
536 }
537
538 if (wcschr(L"\t\n ", wtext[i]) != NULL) {
539 tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
540
541 if (wordcols != 0) {
542 /* line */
543 currlinecols += wordcols;
544 /* word */
545 tp->words[tp->nword] = wordcols;
546 tp->nword += 1;
547 wordcols = 0;
548 }
549
550 switch (wtext[i]) {
551 case L'\t':
552 /* line */
553 currlinecols += tablen;
554 /* word */
555 tp->words[tp->nword] = TB;
556 break;
557 case L'\n':
558 /* line */
559 tp->hasnewline = true;
560 tp->maxline = MAX(tp->maxline, currlinecols);
561 currlinecols = 0;
562 /* word */
563 tp->words[tp->nword] = NL;
564 break;
565 case L' ':
566 /* line */
567 currlinecols += 1;
568 /* word */
569 tp->words[tp->nword] = WS;
570 break;
571 }
572 tp->nword += 1;
573 } else {
574 tp->wletters[l] = wcwidth(wtext[i]);
575 wordcols += tp->wletters[l];
576 l++;
577 }
578 }
579 /* word */
580 if (wordcols != 0) {
581 tp->words[tp->nword] = wordcols;
582 tp->nword += 1;
583 tp->maxwordcols = MAX(wordcols, tp->maxwordcols);
584 }
585 /* line */
586 tp->maxline = MAX(tp->maxline, currlinecols);
587
588 free(wtext);
589
590 return (0);
591 }
592
593 static int
text_autosize(struct bsddialog_conf * conf,struct textproperties * tp,int maxrows,int mincols,bool increasecols,int * h,int * w)594 text_autosize(struct bsddialog_conf *conf, struct textproperties *tp,
595 int maxrows, int mincols, bool increasecols, int *h, int *w)
596 {
597 int i, j, x, y, z, l, line, maxwidth, tablen;
598
599 maxwidth = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
600 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
601
602 if (increasecols) {
603 mincols = MAX(mincols, tp->maxwordcols);
604 mincols = MAX(mincols,
605 (int)conf->auto_minwidth - BORDERS - TEXTHMARGINS);
606 mincols = MIN(mincols, maxwidth);
607 }
608
609 while (true) {
610 x = 0;
611 y = 1;
612 line=0;
613 l = 0;
614 for (i = 0; i < tp->nword; i++) {
615 switch (tp->words[i]) {
616 case TB:
617 for (j = 0; j < tablen; j++) {
618 if (x >= mincols) {
619 x = 0;
620 y++;
621 }
622 x++;
623 }
624 break;
625 case NL:
626 y++;
627 x = 0;
628 break;
629 case WS:
630 x++;
631 if (x >= mincols) {
632 x = 0;
633 y++;
634 }
635 break;
636 default:
637 if (tp->words[i] + x <= mincols) {
638 x += tp->words[i];
639 for (z = 0 ; z != tp->words[i]; l++ )
640 z += tp->wletters[l];
641 } else if (tp->words[i] <= mincols) {
642 y++;
643 x = tp->words[i];
644 for (z = 0 ; z != tp->words[i]; l++ )
645 z += tp->wletters[l];
646 } else {
647 for (j = tp->words[i]; j > 0; ) {
648 y = (x == 0) ? y : y + 1;
649 z = 0;
650 while (z != j && z < mincols) {
651 z += tp->wletters[l];
652 l++;
653 }
654 x = z;
655 line = MAX(line, x);
656 j -= z;
657 }
658 }
659 }
660 line = MAX(line, x);
661 }
662
663 if (increasecols == false)
664 break;
665 if (mincols >= maxwidth)
666 break;
667 if (line >= y * (int)conf->text.cols_per_row && y <= maxrows)
668 break;
669 mincols++;
670 }
671
672 *h = (tp->nword == 0) ? 0 : y;
673 *w = MIN(mincols, line); /* wtext can be less than mincols */
674
675 return (0);
676 }
677
678 static int
text_size(struct bsddialog_conf * conf,int rows,int cols,const char * text,struct buttons * bs,int rowsnotext,int startwtext,int * htext,int * wtext)679 text_size(struct bsddialog_conf *conf, int rows, int cols, const char *text,
680 struct buttons *bs, int rowsnotext, int startwtext, int *htext, int *wtext)
681 {
682 bool changewtext;
683 int wbuttons, maxhtext;
684 struct textproperties tp;
685
686 wbuttons = 0;
687 if (bs->nbuttons > 0)
688 wbuttons = buttons_min_width(bs);
689
690 /* Rows */
691 if (rows == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_FULLSCREEN) {
692 maxhtext = widget_max_height(conf) - BORDERS - rowsnotext;
693 } else { /* fixed */
694 maxhtext = rows - BORDERS - rowsnotext;
695 }
696 if (bs->nbuttons > 0)
697 maxhtext -= 2;
698 if (maxhtext <= 0)
699 maxhtext = 1; /* text_autosize() computes always htext */
700
701 /* Cols */
702 if (cols == BSDDIALOG_AUTOSIZE) {
703 startwtext = MAX(startwtext, wbuttons - TEXTHMARGINS);
704 changewtext = true;
705 } else if (cols == BSDDIALOG_FULLSCREEN) {
706 startwtext = widget_max_width(conf) - BORDERS - TEXTHMARGINS;
707 changewtext = false;
708 } else { /* fixed */
709 startwtext = cols - BORDERS - TEXTHMARGINS;
710 changewtext = false;
711 }
712
713 if (startwtext <= 0 && changewtext)
714 startwtext = 1;
715
716 /* Sizing calculation */
717 if (text_properties(conf, text, &tp) != 0)
718 return (BSDDIALOG_ERROR);
719 if (tp.nword > 0 && startwtext <= 0)
720 RETURN_FMTERROR("(fixed cols or fullscreen) "
721 "needed at least %d cols to draw text",
722 BORDERS + TEXTHMARGINS + 1);
723 if (text_autosize(conf, &tp, maxhtext, startwtext, changewtext, htext,
724 wtext) != 0)
725 return (BSDDIALOG_ERROR);
726
727 free(tp.words);
728 free(tp.wletters);
729
730 return (0);
731 }
732
733 static int
widget_min_height(struct bsddialog_conf * conf,int htext,int hnotext,bool withbuttons)734 widget_min_height(struct bsddialog_conf *conf, int htext, int hnotext,
735 bool withbuttons)
736 {
737 int min;
738
739 /* dialog borders */
740 min = BORDERS;
741
742 /* text */
743 min += htext;
744
745 /* specific widget lines without text */
746 min += hnotext;
747
748 /* buttons */
749 if (withbuttons)
750 min += HBUTTONS; /* buttons and their up-border */
751
752 /* conf.auto_minheight */
753 min = MAX(min, (int)conf->auto_minheight);
754
755 return (min);
756 }
757
758 static int
widget_min_width(struct bsddialog_conf * conf,int wtext,int minwidget,struct buttons * bs)759 widget_min_width(struct bsddialog_conf *conf, int wtext, int minwidget,
760 struct buttons *bs)
761
762 {
763 int min, delimtitle, wbottomtitle, wtitle;
764
765 min = 0;
766
767 /* buttons */
768 if (bs->nbuttons > 0)
769 min += buttons_min_width(bs);
770
771 /* text */
772 if (wtext > 0)
773 min = MAX(min, wtext + TEXTHMARGINS);
774
775 /* specific widget min width */
776 min = MAX(min, minwidget);
777
778 /* title */
779 if (conf->title != NULL) {
780 delimtitle = t.dialog.delimtitle ? 2 : 0;
781 wtitle = strcols(conf->title);
782 min = MAX(min, wtitle + 2 + delimtitle);
783 }
784
785 /* bottom title */
786 if (conf->bottomtitle != NULL) {
787 wbottomtitle = strcols(conf->bottomtitle);
788 min = MAX(min, wbottomtitle + 4);
789 }
790
791 /* dialog borders */
792 min += BORDERS;
793 /* conf.auto_minwidth */
794 min = MAX(min, (int)conf->auto_minwidth);
795
796 return (min);
797 }
798
799 int
set_widget_size(struct bsddialog_conf * conf,int rows,int cols,int * h,int * w)800 set_widget_size(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w)
801 {
802 int maxheight, maxwidth;
803
804 if ((maxheight = widget_max_height(conf)) == BSDDIALOG_ERROR)
805 return (BSDDIALOG_ERROR);
806
807 if (rows == BSDDIALOG_FULLSCREEN)
808 *h = maxheight;
809 else if (rows < BSDDIALOG_FULLSCREEN)
810 RETURN_ERROR("Negative (less than -1) height");
811 else if (rows > BSDDIALOG_AUTOSIZE) /* fixed rows */
812 *h = MIN(rows, maxheight); /* rows is at most maxheight */
813 /* rows == AUTOSIZE: each widget has to set its size */
814
815 if ((maxwidth = widget_max_width(conf)) == BSDDIALOG_ERROR)
816 return (BSDDIALOG_ERROR);
817
818 if (cols == BSDDIALOG_FULLSCREEN)
819 *w = maxwidth;
820 else if (cols < BSDDIALOG_FULLSCREEN)
821 RETURN_ERROR("Negative (less than -1) width");
822 else if (cols > BSDDIALOG_AUTOSIZE) /* fixed cols */
823 *w = MIN(cols, maxwidth); /* cols is at most maxwidth */
824 /* cols == AUTOSIZE: each widget has to set its size */
825
826 return (0);
827 }
828
829 int
set_widget_autosize(struct bsddialog_conf * conf,int rows,int cols,int * h,int * w,const char * text,int * rowstext,struct buttons * bs,int hnotext,int minw)830 set_widget_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h,
831 int *w, const char *text, int *rowstext, struct buttons *bs, int hnotext,
832 int minw)
833 {
834 int htext, wtext;
835
836 if (rows == BSDDIALOG_AUTOSIZE || cols == BSDDIALOG_AUTOSIZE ||
837 rowstext != NULL) {
838 if (text_size(conf, rows, cols, text, bs, hnotext, minw,
839 &htext, &wtext) != 0)
840 return (BSDDIALOG_ERROR);
841 if (rowstext != NULL)
842 *rowstext = htext;
843 }
844
845 if (rows == BSDDIALOG_AUTOSIZE) {
846 *h = widget_min_height(conf, htext, hnotext, bs->nbuttons > 0);
847 *h = MIN(*h, widget_max_height(conf));
848 }
849
850 if (cols == BSDDIALOG_AUTOSIZE) {
851 *w = widget_min_width(conf, wtext, minw, bs);
852 *w = MIN(*w, widget_max_width(conf));
853 }
854
855 return (0);
856 }
857
widget_checksize(int h,int w,struct buttons * bs,int hnotext,int minw)858 int widget_checksize(int h, int w, struct buttons *bs, int hnotext, int minw)
859 {
860 int minheight, minwidth;
861
862 minheight = BORDERS + hnotext;
863 if (bs->nbuttons > 0)
864 minheight += HBUTTONS;
865 if (h < minheight)
866 RETURN_FMTERROR("Current rows: %d, needed at least: %d",
867 h, minheight);
868
869 minwidth = 0;
870 if (bs->nbuttons > 0)
871 minwidth = buttons_min_width(bs);
872 minwidth = MAX(minwidth, minw);
873 minwidth += BORDERS;
874 if (w < minwidth)
875 RETURN_FMTERROR("Current cols: %d, nedeed at least %d",
876 w, minwidth);
877
878 return (0);
879 }
880
881 int
set_widget_position(struct bsddialog_conf * conf,int * y,int * x,int h,int w)882 set_widget_position(struct bsddialog_conf *conf, int *y, int *x, int h, int w)
883 {
884 int hshadow = conf->shadow ? (int)t.shadow.y : 0;
885 int wshadow = conf->shadow ? (int)t.shadow.x : 0;
886
887 if (conf->y == BSDDIALOG_CENTER) {
888 *y = SCREENLINES/2 - (h + hshadow)/2;
889 if (*y < (int)conf->auto_topmargin)
890 *y = conf->auto_topmargin;
891 if (*y + h + hshadow > SCREENLINES - (int)conf->auto_downmargin)
892 *y = SCREENLINES - h - hshadow - conf->auto_downmargin;
893 }
894 else if (conf->y < BSDDIALOG_CENTER)
895 RETURN_ERROR("Negative begin y (less than -1)");
896 else if (conf->y >= SCREENLINES)
897 RETURN_ERROR("Begin Y under the terminal");
898 else
899 *y = conf->y;
900
901 if (*y + h + hshadow > SCREENLINES)
902 RETURN_ERROR("The lower of the box under the terminal "
903 "(begin Y + height (+ shadow) > terminal lines)");
904
905
906 if (conf->x == BSDDIALOG_CENTER)
907 *x = SCREENCOLS/2 - (w + wshadow)/2;
908 else if (conf->x < BSDDIALOG_CENTER)
909 RETURN_ERROR("Negative begin x (less than -1)");
910 else if (conf->x >= SCREENCOLS)
911 RETURN_ERROR("Begin X over the right of the terminal");
912 else
913 *x = conf->x;
914
915 if ((*x + w + wshadow) > SCREENCOLS)
916 RETURN_ERROR("The right of the box over the terminal "
917 "(begin X + width (+ shadow) > terminal cols)");
918
919 return (0);
920 }
921
dialog_size_position(struct dialog * d,int hnotext,int minw,int * htext)922 int dialog_size_position(struct dialog *d, int hnotext, int minw, int *htext)
923 {
924 if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
925 return (BSDDIALOG_ERROR);
926 if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
927 d->text, htext, &d->bs, hnotext, minw) != 0)
928 return (BSDDIALOG_ERROR);
929 if (widget_checksize(d->h, d->w, &d->bs, hnotext, minw) != 0)
930 return (BSDDIALOG_ERROR);
931 if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
932 return (BSDDIALOG_ERROR);
933
934 return (0);
935 }
936
937 /*
938 * -5- Widget components and utilities
939 */
hide_dialog(struct dialog * d)940 int hide_dialog(struct dialog *d)
941 {
942 WINDOW *clear;
943
944 if ((clear = newwin(d->h, d->w, d->y, d->x)) == NULL)
945 RETURN_ERROR("Cannot hide the widget");
946 wbkgd(clear, t.screen.color);
947 wrefresh(clear);
948
949 if (d->conf->shadow) {
950 mvwin(clear, d->y + t.shadow.y, d->x + t.shadow.x);
951 wrefresh(clear);
952 }
953
954 delwin(clear);
955
956 return (0);
957 }
958
f1help_dialog(struct bsddialog_conf * conf)959 int f1help_dialog(struct bsddialog_conf *conf)
960 {
961 int output;
962 struct bsddialog_conf hconf;
963
964 bsddialog_initconf(&hconf);
965 hconf.title = "HELP";
966 hconf.button.ok_label = "EXIT";
967 hconf.clear = true;
968 hconf.ascii_lines = conf->ascii_lines;
969 hconf.no_lines = conf->no_lines;
970 hconf.shadow = conf->shadow;
971 hconf.text.escape = conf->text.escape;
972
973 output = BSDDIALOG_OK;
974 if (conf->key.f1_message != NULL)
975 output = bsddialog_msgbox(&hconf, conf->key.f1_message, 0, 0);
976
977 if (output != BSDDIALOG_ERROR && conf->key.f1_file != NULL)
978 output = bsddialog_textbox(&hconf, conf->key.f1_file, 0, 0);
979
980 return (output == BSDDIALOG_ERROR ? BSDDIALOG_ERROR : 0);
981 }
982
draw_borders(struct bsddialog_conf * conf,WINDOW * win,enum elevation elev)983 void draw_borders(struct bsddialog_conf *conf, WINDOW *win, enum elevation elev)
984 {
985 int h, w;
986 int leftcolor, rightcolor;
987 cchar_t *ls, *rs, *ts, *bs, *tl, *tr, *bl, *br;
988 cchar_t hline, vline, corner;
989
990 if (conf->no_lines)
991 return;
992
993 if (conf->ascii_lines) {
994 setcchar(&hline, L"|", 0, 0, NULL);
995 ls = rs = &hline;
996 setcchar(&vline, L"-", 0, 0, NULL);
997 ts = bs = &vline;
998 setcchar(&corner, L"+", 0, 0, NULL);
999 tl = tr = bl = br = &corner;
1000 } else {
1001 ls = rs = WACS_VLINE;
1002 ts = bs = WACS_HLINE;
1003 tl = WACS_ULCORNER;
1004 tr = WACS_URCORNER;
1005 bl = WACS_LLCORNER;
1006 br = WACS_LRCORNER;
1007 }
1008
1009 getmaxyx(win, h, w);
1010 leftcolor = (elev == RAISED) ?
1011 t.dialog.lineraisecolor : t.dialog.linelowercolor;
1012 rightcolor = (elev == RAISED) ?
1013 t.dialog.linelowercolor : t.dialog.lineraisecolor;
1014
1015 wattron(win, leftcolor);
1016 wborder_set(win, ls, rs, ts, bs, tl, tr, bl, br);
1017 wattroff(win, leftcolor);
1018
1019 wattron(win, rightcolor);
1020 mvwadd_wch(win, 0, w-1, tr);
1021 mvwvline_set(win, 1, w-1, rs, h-2);
1022 mvwadd_wch(win, h-1, w-1, br);
1023 mvwhline_set(win, h-1, 1, bs, w-2);
1024 wattroff(win, rightcolor);
1025 }
1026
1027 void
update_box(struct bsddialog_conf * conf,WINDOW * win,int y,int x,int h,int w,enum elevation elev)1028 update_box(struct bsddialog_conf *conf, WINDOW *win, int y, int x, int h, int w,
1029 enum elevation elev)
1030 {
1031 wclear(win);
1032 wresize(win, h, w);
1033 mvwin(win, y, x);
1034 draw_borders(conf, win, elev);
1035 }
1036
1037 void
rtextpad(struct dialog * d,int ytext,int xtext,int upnotext,int downnotext)1038 rtextpad(struct dialog *d, int ytext, int xtext, int upnotext, int downnotext)
1039 {
1040 pnoutrefresh(d->textpad, ytext, xtext,
1041 d->y + BORDER + upnotext,
1042 d->x + BORDER + TEXTHMARGIN,
1043 d->y + d->h - 1 - downnotext - BORDER,
1044 d->x + d->w - TEXTHMARGIN - BORDER);
1045 }
1046
1047 /*
1048 * -6- Dialog init/build, update/draw, destroy
1049 */
end_dialog(struct dialog * d)1050 void end_dialog(struct dialog *d)
1051 {
1052 if (d->conf->sleep > 0)
1053 sleep(d->conf->sleep);
1054
1055 delwin(d->textpad);
1056 delwin(d->widget);
1057 if (d->conf->shadow)
1058 delwin(d->shadow);
1059
1060 if (d->conf->clear)
1061 hide_dialog(d);
1062
1063 if (d->conf->get_height != NULL)
1064 *d->conf->get_height = d->h;
1065 if (d->conf->get_width != NULL)
1066 *d->conf->get_width = d->w;
1067 }
1068
check_set_wtext_attr(WINDOW * win,wchar_t * wtext)1069 static bool check_set_wtext_attr(WINDOW *win, wchar_t *wtext)
1070 {
1071 enum bsddialog_color bg;
1072
1073 if (is_wtext_attr(wtext) == false)
1074 return (false);
1075
1076 if ((wtext[2] >= L'0') && (wtext[2] <= L'7')) {
1077 bsddialog_color_attrs(t.dialog.color, NULL, &bg, NULL);
1078 wattron(win, bsddialog_color(wtext[2] - L'0', bg, 0));
1079 return (true);
1080 }
1081
1082 switch (wtext[2]) {
1083 case L'n':
1084 wattron(win, t.dialog.color);
1085 wattrset(win, A_NORMAL);
1086 break;
1087 case L'b':
1088 wattron(win, A_BOLD);
1089 break;
1090 case L'B':
1091 wattroff(win, A_BOLD);
1092 break;
1093 case L'd':
1094 wattron(win, A_DIM);
1095 break;
1096 case L'D':
1097 wattroff(win, A_DIM);
1098 break;
1099 case L'k':
1100 wattron(win, A_BLINK);
1101 break;
1102 case L'K':
1103 wattroff(win, A_BLINK);
1104 break;
1105 case L'r':
1106 wattron(win, A_REVERSE);
1107 break;
1108 case L'R':
1109 wattroff(win, A_REVERSE);
1110 break;
1111 case L's':
1112 wattron(win, A_STANDOUT);
1113 break;
1114 case L'S':
1115 wattroff(win, A_STANDOUT);
1116 break;
1117 case L'u':
1118 wattron(win, A_UNDERLINE);
1119 break;
1120 case L'U':
1121 wattroff(win, A_UNDERLINE);
1122 break;
1123 }
1124
1125 return (true);
1126 }
1127
1128 static void
print_string(WINDOW * win,int * rows,int cols,int * y,int * x,wchar_t * str,bool color)1129 print_string(WINDOW *win, int *rows, int cols, int *y, int *x, wchar_t *str,
1130 bool color)
1131 {
1132 int charwidth, i, j, strlen, strwidth;
1133 wchar_t ws[2];
1134
1135 ws[1] = L'\0';
1136
1137 strlen = wcslen(str);
1138 if (color) {
1139 strwidth = 0;
1140 i=0;
1141 while (i < strlen) {
1142 if (is_wtext_attr(str+i) == false) {
1143 strwidth += wcwidth(str[i]);
1144 i++;
1145 } else {
1146 i += 3;
1147 }
1148 }
1149 } else
1150 strwidth = wcswidth(str, strlen);
1151
1152 i = 0;
1153 while (i < strlen) {
1154 if (*x + strwidth > cols) {
1155 if (*x != 0)
1156 *y = *y + 1;
1157 if (*y >= *rows) {
1158 *rows = *y + 1;
1159 wresize(win, *rows, cols);
1160 }
1161 *x = 0;
1162 }
1163 j = *x;
1164 while (i < strlen) {
1165 if (color && check_set_wtext_attr(win, str+i)) {
1166 i += 3;
1167 continue;
1168 }
1169
1170 charwidth = wcwidth(str[i]);
1171 if (j + wcwidth(str[i]) > cols)
1172 break;
1173 /* inline mvwaddwch() for efficiency */
1174 ws[0] = str[i];
1175 mvwaddwstr(win, *y, j, ws);
1176 strwidth -= charwidth;
1177 j += charwidth;
1178 *x = j;
1179 i++;
1180 }
1181 }
1182 }
1183
1184 static int
print_textpad(struct bsddialog_conf * conf,WINDOW * pad,const char * text)1185 print_textpad(struct bsddialog_conf *conf, WINDOW *pad, const char *text)
1186 {
1187 bool loop;
1188 int i, j, z, rows, cols, x, y, tablen;
1189 wchar_t *wtext, *string;
1190
1191 if ((wtext = alloc_mbstows(text)) == NULL)
1192 RETURN_ERROR("Cannot allocate/print text in wchar_t*");
1193
1194 if ((string = calloc(wcslen(wtext) + 1, sizeof(wchar_t))) == NULL)
1195 RETURN_ERROR("Cannot build (analyze) text");
1196
1197 getmaxyx(pad, rows, cols);
1198 tablen = (conf->text.tablen == 0) ? TABSIZE : (int)conf->text.tablen;
1199
1200 i = j = x = y = 0;
1201 loop = true;
1202 while (loop) {
1203 string[j] = wtext[i];
1204
1205 if (wcschr(L"\n\t ", string[j]) != NULL || string[j] == L'\0') {
1206 string[j] = L'\0';
1207 print_string(pad, &rows, cols, &y, &x, string,
1208 conf->text.escape);
1209 }
1210
1211 switch (wtext[i]) {
1212 case L'\0':
1213 loop = false;
1214 break;
1215 case L'\n':
1216 x = 0;
1217 y++;
1218 j = -1;
1219 break;
1220 case L'\t':
1221 for (z = 0; z < tablen; z++) {
1222 if (x >= cols) {
1223 x = 0;
1224 y++;
1225 }
1226 x++;
1227 }
1228 j = -1;
1229 break;
1230 case L' ':
1231 x++;
1232 if (x >= cols) {
1233 x = 0;
1234 y++;
1235 }
1236 j = -1;
1237 }
1238
1239 if (y >= rows) {
1240 rows = y + 1;
1241 wresize(pad, rows, cols);
1242 }
1243
1244 j++;
1245 i++;
1246 }
1247
1248 free(wtext);
1249 free(string);
1250
1251 return (0);
1252 }
1253
draw_dialog(struct dialog * d)1254 int draw_dialog(struct dialog *d)
1255 {
1256 int wtitle, wbottomtitle;
1257 cchar_t ts, ltee, rtee;
1258
1259 if (d->conf->ascii_lines) {
1260 setcchar(&ts, L"-", 0, 0, NULL);
1261 setcchar(<ee, L"+", 0, 0,NULL);
1262 setcchar(&rtee, L"+", 0, 0, NULL);
1263 } else {
1264 ts = *WACS_HLINE;
1265 ltee = *WACS_LTEE;
1266 rtee = *WACS_RTEE;
1267 }
1268
1269 if (d->conf->shadow) {
1270 wclear(d->shadow);
1271 wresize(d->shadow, d->h, d->w);
1272 mvwin(d->shadow, d->y + t.shadow.y, d->x + t.shadow.x);
1273 wnoutrefresh(d->shadow);
1274 }
1275
1276 wclear(d->widget);
1277 wresize(d->widget, d->h, d->w);
1278 mvwin(d->widget, d->y, d->x);
1279 draw_borders(d->conf, d->widget, RAISED);
1280
1281 if (d->conf->title != NULL) {
1282 if ((wtitle = strcols(d->conf->title)) < 0)
1283 return (BSDDIALOG_ERROR);
1284 if (t.dialog.delimtitle && d->conf->no_lines == false) {
1285 wattron(d->widget, t.dialog.lineraisecolor);
1286 mvwadd_wch(d->widget, 0, d->w/2 - wtitle/2 -1, &rtee);
1287 wattroff(d->widget, t.dialog.lineraisecolor);
1288 }
1289 wattron(d->widget, t.dialog.titlecolor);
1290 mvwaddstr(d->widget, 0, d->w/2 - wtitle/2, d->conf->title);
1291 wattroff(d->widget, t.dialog.titlecolor);
1292 if (t.dialog.delimtitle && d->conf->no_lines == false) {
1293 wattron(d->widget, t.dialog.lineraisecolor);
1294 wadd_wch(d->widget, <ee);
1295 wattroff(d->widget, t.dialog.lineraisecolor);
1296 }
1297 }
1298
1299 if (d->bs.nbuttons > 0) {
1300 if (d->conf->no_lines == false) {
1301 wattron(d->widget, t.dialog.lineraisecolor);
1302 mvwadd_wch(d->widget, d->h-3, 0, <ee);
1303 mvwhline_set(d->widget, d->h-3, 1, &ts, d->w-2);
1304 wattroff(d->widget, t.dialog.lineraisecolor);
1305
1306 wattron(d->widget, t.dialog.linelowercolor);
1307 mvwadd_wch(d->widget, d->h-3, d->w-1, &rtee);
1308 wattroff(d->widget, t.dialog.linelowercolor);
1309 }
1310 draw_buttons(d);
1311 }
1312
1313 if (d->conf->bottomtitle != NULL) {
1314 if ((wbottomtitle = strcols(d->conf->bottomtitle)) < 0)
1315 return (BSDDIALOG_ERROR);
1316 wattron(d->widget, t.dialog.bottomtitlecolor);
1317 wmove(d->widget, d->h - 1, d->w/2 - wbottomtitle/2 - 1);
1318 waddch(d->widget, ' ');
1319 waddstr(d->widget, d->conf->bottomtitle);
1320 waddch(d->widget, ' ');
1321 wattroff(d->widget, t.dialog.bottomtitlecolor);
1322 }
1323
1324 wnoutrefresh(d->widget);
1325
1326 wclear(d->textpad);
1327 /* `infobox "" 0 2` fails but text is empty and textpad remains 1 1 */
1328 wresize(d->textpad, 1, d->w - BORDERS - TEXTHMARGINS);
1329
1330 if (print_textpad(d->conf, d->textpad, d->text) != 0)
1331 return (BSDDIALOG_ERROR);
1332
1333 d->built = true;
1334
1335 return (0);
1336 }
1337
1338 int
prepare_dialog(struct bsddialog_conf * conf,const char * text,int rows,int cols,struct dialog * d)1339 prepare_dialog(struct bsddialog_conf *conf, const char *text, int rows,
1340 int cols, struct dialog *d)
1341 {
1342 CHECK_PTR(conf);
1343
1344 d->built = false;
1345 d->conf = conf;
1346 d->rows = rows;
1347 d->cols = cols;
1348 d->text = CHECK_STR(text);
1349 d->bs.nbuttons = 0;
1350
1351 if (d->conf->shadow) {
1352 if ((d->shadow = newwin(1, 1, 1, 1)) == NULL)
1353 RETURN_ERROR("Cannot build WINDOW shadow");
1354 wbkgd(d->shadow, t.shadow.color);
1355 }
1356
1357 if ((d->widget = newwin(1, 1, 1, 1)) == NULL)
1358 RETURN_ERROR("Cannot build WINDOW widget");
1359 wbkgd(d->widget, t.dialog.color);
1360
1361 /* fake for textpad */
1362 if ((d->textpad = newpad(1, 1)) == NULL)
1363 RETURN_ERROR("Cannot build the pad WINDOW for text");
1364 wbkgd(d->textpad, t.dialog.color);
1365
1366 return (0);
1367 }