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 <ctype.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifdef PORTNCURSES
35 #include <ncurses/curses.h>
36 #else
37 #include <curses.h>
38 #endif
39
40 #include "bsddialog.h"
41 #include "lib_util.h"
42 #include "bsddialog_theme.h"
43
44 #define BARMARGIN 3
45 #define MINBARWIDTH 10
46 #define MINWIDTH (VBORDERS + MINBARWIDTH + BARMARGIN * 2)
47 #define MINHEIGHT 7 /* without text */
48
49 /* "Bar": gauge - mixedgauge - rangebox - pause */
50
51 extern struct bsddialog_theme t;
52
53 static void
draw_perc_bar(WINDOW * win,int y,int x,int size,int perc,bool withlabel,int label)54 draw_perc_bar(WINDOW *win, int y, int x, int size, int perc, bool withlabel,
55 int label)
56 {
57 char labelstr[128];
58 int i, blue_x, color;
59
60 blue_x = (int)((perc*(size))/100);
61
62 wmove(win, y, x);
63 for (i = 0; i < size; i++) {
64 color = (i <= blue_x) ? t.bar.f_color : t.bar.color;
65 wattron(win, color);
66 waddch(win, ' ');
67 wattroff(win, color);
68 }
69
70 if (withlabel)
71 sprintf(labelstr, "%d", label);
72 else
73 sprintf(labelstr, "%3d%%", perc);
74 wmove(win, y, x + size/2 - 2);
75 for (i=0; i < (int) strlen(labelstr); i++) {
76 color = (blue_x + 1 <= size/2 - (int)strlen(labelstr)/2 + i ) ?
77 t.bar.color : t.bar.f_color;
78 wattron(win, color);
79 waddch(win, labelstr[i]);
80 wattroff(win, color);
81 }
82 }
83
84 static int
bar_autosize(struct bsddialog_conf * conf,int rows,int cols,int * h,int * w,char * text,struct buttons * bs)85 bar_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, int *w,
86 char *text, struct buttons *bs)
87 {
88 int maxword, maxline, nlines, buttonswidth;
89
90 if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
91 return BSDDIALOG_ERROR;
92
93 buttonswidth = 0;
94 if (bs != NULL) { /* gauge has not buttons */
95 buttonswidth= bs->nbuttons * bs->sizebutton;
96 if (bs->nbuttons > 0)
97 buttonswidth += (bs->nbuttons-1) * t.button.space;
98 }
99
100 if (cols == BSDDIALOG_AUTOSIZE) {
101 *w = VBORDERS;
102 /* buttons size */
103 *w += buttonswidth;
104 /* bar size */
105 *w = MAX(*w, MINWIDTH);
106 /* text size*/
107 *w = MAX((int)(maxline + VBORDERS + t.text.hmargin * 2), *w);
108 /* avoid terminal overflow */
109 *w = MIN(*w, widget_max_width(conf));
110 }
111
112 if (rows == BSDDIALOG_AUTOSIZE) {
113 *h = MINHEIGHT;
114 if (maxword > 0)
115 *h += 1;
116 /* avoid terminal overflow */
117 *h = MIN(*h, widget_max_height(conf));
118 }
119
120 return (0);
121 }
122
123 static int
bar_checksize(char * text,int rows,int cols,struct buttons * bs)124 bar_checksize(char *text, int rows, int cols, struct buttons *bs)
125 {
126 int minheight, minwidth;
127
128 minwidth = 0;
129 if (bs != NULL) { /* gauge has not buttons */
130 minwidth = bs->nbuttons * bs->sizebutton;
131 if (bs->nbuttons > 0)
132 minwidth += (bs->nbuttons-1) * t.button.space;
133 }
134 minwidth = MAX(minwidth + VBORDERS, MINBARWIDTH);
135
136 if (cols< minwidth)
137 RETURN_ERROR("Few cols for this widget");
138
139 minheight = MINHEIGHT + ((text != NULL && strlen(text) > 0) ? 1 : 0);
140 if (rows < minheight)
141 RETURN_ERROR("Few rows for this mixedgauge");
142
143 return 0;
144 }
145
146 int
bsddialog_gauge(struct bsddialog_conf * conf,char * text,int rows,int cols,unsigned int perc)147 bsddialog_gauge(struct bsddialog_conf *conf, char* text, int rows, int cols,
148 unsigned int perc)
149 {
150 WINDOW *widget, *textpad, *bar, *shadow;
151 char input[2048], ntext[2048], *pntext;
152 int y, x, h, w, htextpad;
153 bool mainloop;
154
155 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
156 return BSDDIALOG_ERROR;
157 if (bar_autosize(conf, rows, cols, &h, &w, text, NULL) != 0)
158 return BSDDIALOG_ERROR;
159 if (bar_checksize(text, h, w, NULL) != 0)
160 return BSDDIALOG_ERROR;
161 if (set_widget_position(conf, &y, &x, h, w) != 0)
162 return BSDDIALOG_ERROR;
163
164 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
165 &textpad, &htextpad, text, false) != 0)
166 return BSDDIALOG_ERROR;
167
168 bar = new_boxed_window(conf, y+h-4, x+3, 3, w-6, RAISED);
169
170 mainloop = true;
171 while (mainloop) {
172 wrefresh(widget);
173 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-4,
174 x+w-1-t.text.hmargin);
175 draw_perc_bar(bar, 1, 1, w-8, perc, false, -1 /*unused*/);
176 wrefresh(bar);
177
178 while (true) {
179 scanf("%s", input);
180 if (strcmp(input,"EOF") == 0) {
181 mainloop = false;
182 break;
183 }
184 if (strcmp(input,"XXX") == 0)
185 break;
186 }
187 scanf("%d", &perc);
188 perc = perc < 0 ? 0 : perc;
189 perc = perc > 100 ? 100 : perc;
190 htextpad = 1;
191 wclear(textpad);
192 pntext = &ntext[0];
193 ntext[0] = '\0';
194 while (true) {
195 scanf("%s", input);
196 if (strcmp(input,"EOF") == 0) {
197 mainloop = false;
198 break;
199 }
200 if (strcmp(input,"XXX") == 0)
201 break;
202 pntext[0] = ' ';
203 pntext++;
204 strcpy(pntext, input);
205 pntext += strlen(input);
206 }
207 print_textpad(conf, textpad, &htextpad, w-2-t.text.hmargin*2,
208 ntext);
209 }
210
211 delwin(bar);
212 end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
213
214 return BSDDIALOG_YESOK;
215 }
216
217 int
bsddialog_mixedgauge(struct bsddialog_conf * conf,char * text,int rows,int cols,unsigned int mainperc,unsigned int nminbars,char ** minibars)218 bsddialog_mixedgauge(struct bsddialog_conf *conf, char* text, int rows, int cols,
219 unsigned int mainperc, unsigned int nminbars, char **minibars)
220 {
221 WINDOW *widget, *textpad, *bar, *shadow;
222 int i, output, miniperc, y, x, h, w, max_minbarlen;
223 int maxword, maxline, nlines, htextpad, ypad;
224 char states[11][16] = {
225 "[ Succeeded ]",
226 "[ Failed ]",
227 "[ Passed ]",
228 "[ Completed ]",
229 "[ Checked ]",
230 "[ Done ]",
231 "[ Skipped ]",
232 "[ In Progress ]",
233 "!!! BLANK !!!",
234 "[ N/A ]",
235 "[ UNKNOWN ]",
236 };
237
238 if (nminbars % 2 !=0)
239 RETURN_ERROR("Mixedgauge wants a pair name/perc");
240
241 max_minbarlen = 0;
242 for (i=0; i < (int)(nminbars/2); i++)
243 max_minbarlen = MAX(max_minbarlen, (int) strlen(minibars[i*2]));
244 max_minbarlen += 3 + 16 /* seps + [...] or mainbar */;
245
246 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
247 return BSDDIALOG_ERROR;
248
249 /* mixedgauge autosize */
250 if (get_text_properties(conf, text, &maxword, &maxline, &nlines) != 0)
251 return BSDDIALOG_ERROR;
252
253 if (cols == BSDDIALOG_AUTOSIZE) {
254 w = max_minbarlen + HBORDERS;
255 w = MAX(max_minbarlen, maxline + 4);
256 w = MIN(w, widget_max_width(conf) - 1);
257 }
258 if (rows == BSDDIALOG_AUTOSIZE) {
259 h = 5; /* borders + mainbar */
260 h += nminbars/2;
261 h += (strlen(text) > 0 ? 3 : 0);
262 h = MIN(h, widget_max_height(conf) -1);
263 }
264
265 /* mixedgauge checksize */
266 if (w < max_minbarlen + 2)
267 RETURN_ERROR("Few cols for this mixedgauge");
268 if (h < 5 + (int)nminbars/2 + (strlen(text) > 0 ? 1 : 0))
269 RETURN_ERROR("Few rows for this mixedgauge");
270
271 if (set_widget_position(conf, &y, &x, h, w) != 0)
272 return BSDDIALOG_ERROR;
273
274 output = new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w,
275 RAISED, &textpad, &htextpad, text, false);
276 if (output == BSDDIALOG_ERROR)
277 return output;
278
279 /* mini bars */
280 for (i=0; i < (int)nminbars/2; i++) {
281 miniperc = atol(minibars[i*2 + 1]);
282 if (miniperc == 8)
283 continue;
284 mvwaddstr(widget, i+1, 2, minibars[i*2]);
285 if (miniperc > 9)
286 mvwaddstr(widget, i+1, w-2-15, states[10]);
287 else if (miniperc >= 0 && miniperc <= 9)
288 mvwaddstr(widget, i+1, w-2-15, states[miniperc]);
289 else { //miniperc < 0
290 miniperc = abs(miniperc);
291 mvwaddstr(widget, i+1, w-2-15, "[ ]");
292 draw_perc_bar(widget, i+1, 1+w-2-15, 13, miniperc,
293 false, -1 /*unused*/);
294 }
295 }
296
297 wrefresh(widget);
298 ypad = y + h - 5 - htextpad;
299 ypad = ypad < y+(int)nminbars/2 ? y+nminbars/2 : ypad;
300 prefresh(textpad, 0, 0, ypad, x+2, y+h-4, x+w-2);
301
302 /* main bar */
303 bar = new_boxed_window(conf, y+h -4, x+3, 3, w-6, RAISED);
304
305 draw_perc_bar(bar, 1, 1, w-8, mainperc, false, -1 /*unused*/);
306
307 wattron(bar, t.bar.color);
308 mvwaddstr(bar, 0, 2, "Overall Progress");
309 wattroff(bar, t.bar.color);
310
311 wrefresh(bar);
312
313 /* getch(); port ncurses shows nothing */
314
315 delwin(bar);
316 end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
317
318 return BSDDIALOG_YESOK;
319 }
320
321 int
bsddialog_rangebox(struct bsddialog_conf * conf,char * text,int rows,int cols,int min,int max,int * value)322 bsddialog_rangebox(struct bsddialog_conf *conf, char* text, int rows, int cols,
323 int min, int max, int *value)
324 {
325 WINDOW *widget, *textpad, *bar, *shadow;
326 int i, y, x, h, w, htextpad;
327 bool loop, buttupdate, barupdate;
328 int input, currvalue, output, sizebar, bigchange, positions;
329 float perc;
330 struct buttons bs;
331
332 if (value == NULL)
333 RETURN_ERROR("*value cannot be NULL");
334
335 if (min >= max)
336 RETURN_ERROR("min >= max");
337
338 currvalue = *value;
339 positions = max - min + 1;
340
341 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
342 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
343
344 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
345 return BSDDIALOG_ERROR;
346 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
347 return BSDDIALOG_ERROR;
348 if (bar_checksize(text, h, w, &bs) != 0)
349 return BSDDIALOG_ERROR;
350 if (set_widget_position(conf, &y, &x, h, w) != 0)
351 return BSDDIALOG_ERROR;
352
353 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
354 &textpad, &htextpad, text, true) != 0)
355 return BSDDIALOG_ERROR;
356
357 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
358 x+w-1-t.text.hmargin);
359
360 sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
361 bigchange = MAX(1, sizebar/10);
362
363 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3,
364 sizebar + 2, RAISED);
365
366 loop = buttupdate = barupdate = true;
367 while(loop) {
368 if (buttupdate) {
369 draw_buttons(widget, h-2, w, bs, true);
370 wrefresh(widget);
371 buttupdate = false;
372 }
373 if (barupdate) {
374 perc = ((float)(currvalue - min)*100) / (positions-1);
375 draw_perc_bar(bar, 1, 1, sizebar, perc, true, currvalue);
376 barupdate = false;
377 wrefresh(bar);
378 }
379
380 input = getch();
381 switch(input) {
382 case KEY_ENTER:
383 case 10: /* Enter */
384 output = bs.value[bs.curr];
385 *value = currvalue;
386 loop = false;
387 break;
388 case 27: /* Esc */
389 output = BSDDIALOG_ESC;
390 loop = false;
391 break;
392 case '\t': /* TAB */
393 bs.curr = (bs.curr + 1) % bs.nbuttons;
394 buttupdate = true;
395 break;
396 case KEY_LEFT:
397 if (bs.curr > 0) {
398 bs.curr--;
399 buttupdate = true;
400 }
401 break;
402 case KEY_RIGHT:
403 if (bs.curr < (int) bs.nbuttons - 1) {
404 bs.curr++;
405 buttupdate = true;
406 }
407 break;
408 case KEY_HOME:
409 currvalue = max;
410 barupdate = true;
411 break;
412 case KEY_END:
413 currvalue = min;
414 barupdate = true;
415 break;
416 case KEY_NPAGE:
417 currvalue -= bigchange;
418 if (currvalue < min)
419 currvalue = min;
420 barupdate = true;
421 break;
422 case KEY_PPAGE:
423 currvalue += bigchange;
424 if (currvalue > max)
425 currvalue = max;
426 barupdate = true;
427 break;
428 case KEY_UP:
429 if (currvalue < max) {
430 currvalue++;
431 barupdate = true;
432 }
433 break;
434 case KEY_DOWN:
435 if (currvalue > min) {
436 currvalue--;
437 barupdate = true;
438 }
439 break;
440 case KEY_F(1):
441 if (conf->hfile == NULL)
442 break;
443 if (f1help(conf) != 0)
444 return BSDDIALOG_ERROR;
445 /* No break! the terminal size can change */
446 case KEY_RESIZE:
447 hide_widget(y, x, h, w,conf->shadow);
448
449 /*
450 * Unnecessary, but, when the columns decrease the
451 * following "refresh" seem not work
452 */
453 refresh();
454
455 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
456 return BSDDIALOG_ERROR;
457 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
458 return BSDDIALOG_ERROR;
459 if (bar_checksize(text, h, w, &bs) != 0)
460 return BSDDIALOG_ERROR;
461 if (set_widget_position(conf, &y, &x, h, w) != 0)
462 return BSDDIALOG_ERROR;
463
464 wclear(shadow);
465 mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
466 wresize(shadow, h, w);
467
468 wclear(widget);
469 mvwin(widget, y, x);
470 wresize(widget, h, w);
471
472 htextpad = 1;
473 wclear(textpad);
474 wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
475
476 sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
477 bigchange = MAX(1, sizebar/10);
478 wclear(bar);
479 mvwin(bar, y + h - 6, x + 1 + BARMARGIN);
480 wresize(bar, 3, sizebar + 2);
481
482 if(update_widget_withtextpad(conf, shadow, widget, h, w,
483 RAISED, textpad, &htextpad, text, true) != 0)
484 return BSDDIALOG_ERROR;
485
486 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
487 x+w-1-t.text.hmargin);
488
489 draw_borders(conf, bar, 3, sizebar + 2, RAISED);
490
491 barupdate = true;
492 buttupdate = true;
493 break;
494 default:
495 for (i = 0; i < (int) bs.nbuttons; i++)
496 if (tolower(input) == tolower((bs.label[i])[0])) {
497 output = bs.value[i];
498 loop = false;
499 }
500 }
501 }
502
503 delwin(bar);
504 end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
505
506 return output;
507 }
508
509 int
bsddialog_pause(struct bsddialog_conf * conf,char * text,int rows,int cols,unsigned int sec)510 bsddialog_pause(struct bsddialog_conf *conf, char* text, int rows, int cols,
511 unsigned int sec)
512 {
513 WINDOW *widget, *textpad, *bar, *shadow;
514 int i, output, y, x, h, w, htextpad;
515 bool loop, buttupdate, barupdate;
516 int input, tout, sizebar;
517 float perc;
518 struct buttons bs;
519
520 get_buttons(conf, &bs, BUTTONLABEL(ok_label), BUTTONLABEL(extra_label),
521 BUTTONLABEL(cancel_label), BUTTONLABEL(help_label));
522
523 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
524 return BSDDIALOG_ERROR;
525 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
526 return BSDDIALOG_ERROR;
527 if (bar_checksize(text, h, w, &bs) != 0)
528 return BSDDIALOG_ERROR;
529 if (set_widget_position(conf, &y, &x, h, w) != 0)
530 return BSDDIALOG_ERROR;
531
532 if (new_widget_withtextpad(conf, &shadow, &widget, y, x, h, w, RAISED,
533 &textpad, &htextpad, text, true) != 0)
534 return BSDDIALOG_ERROR;
535
536 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
537 x+w-1-t.text.hmargin);
538
539 sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
540 bar = new_boxed_window(conf, y + h - 6, x + 1 + BARMARGIN, 3,
541 sizebar + 2, RAISED);
542
543 tout = sec;
544 nodelay(stdscr, TRUE);
545 timeout(1000);
546 loop = buttupdate = barupdate = true;
547 while(loop) {
548 if (barupdate) {
549 perc = (float)tout * 100 / sec;
550 draw_perc_bar(bar, 1, 1, sizebar, perc, true, tout);
551 barupdate = false;
552 wrefresh(bar);
553 }
554
555 if (buttupdate) {
556 draw_buttons(widget, h-2, w, bs, true);
557 wrefresh(widget);
558 buttupdate = false;
559 }
560
561 input = getch();
562 if(input < 0) { /* timeout */
563 tout--;
564 if (tout < 0) {
565 output = BSDDIALOG_TIMEOUT;
566 break;
567 }
568 else {
569 barupdate = true;
570 continue;
571 }
572 }
573 switch(input) {
574 case KEY_ENTER:
575 case 10: /* Enter */
576 output = bs.value[bs.curr];
577 loop = false;
578 break;
579 case 27: /* Esc */
580 output = BSDDIALOG_ESC;
581 loop = false;
582 break;
583 case '\t': /* TAB */
584 bs.curr = (bs.curr + 1) % bs.nbuttons;
585 buttupdate = true;
586 break;
587 case KEY_LEFT:
588 if (bs.curr > 0) {
589 bs.curr--;
590 buttupdate = true;
591 }
592 break;
593 case KEY_RIGHT:
594 if (bs.curr < (int) bs.nbuttons - 1) {
595 bs.curr++;
596 buttupdate = true;
597 }
598 break;
599 case KEY_F(1):
600 if (conf->hfile == NULL)
601 break;
602 if (f1help(conf) != 0)
603 return BSDDIALOG_ERROR;
604 /* No break! the terminal size can change */
605 case KEY_RESIZE:
606 hide_widget(y, x, h, w,conf->shadow);
607
608 /*
609 * Unnecessary, but, when the columns decrease the
610 * following "refresh" seem not work
611 */
612 refresh();
613
614 if (set_widget_size(conf, rows, cols, &h, &w) != 0)
615 return BSDDIALOG_ERROR;
616 if (bar_autosize(conf, rows, cols, &h, &w, text, &bs) != 0)
617 return BSDDIALOG_ERROR;
618 if (bar_checksize(text, h, w, &bs) != 0)
619 return BSDDIALOG_ERROR;
620 if (set_widget_position(conf, &y, &x, h, w) != 0)
621 return BSDDIALOG_ERROR;
622
623 wclear(shadow);
624 mvwin(shadow, y + t.shadow.h, x + t.shadow.w);
625 wresize(shadow, h, w);
626
627 wclear(widget);
628 mvwin(widget, y, x);
629 wresize(widget, h, w);
630
631 htextpad = 1;
632 wclear(textpad);
633 wresize(textpad, 1, w - HBORDERS - t.text.hmargin * 2);
634
635 sizebar = w - HBORDERS - 2 - BARMARGIN * 2;
636 wclear(bar);
637 mvwin(bar, y + h - 6, x + 1 + BARMARGIN);
638 wresize(bar, 3, sizebar + 2);
639
640 if(update_widget_withtextpad(conf, shadow, widget, h, w,
641 RAISED, textpad, &htextpad, text, true) != 0)
642 return BSDDIALOG_ERROR;
643
644 prefresh(textpad, 0, 0, y+1, x+1+t.text.hmargin, y+h-7,
645 x+w-1-t.text.hmargin);
646
647 draw_borders(conf, bar, 3, sizebar + 2, RAISED);
648
649 barupdate = true;
650 buttupdate = true;
651 break;
652 default:
653 for (i = 0; i < (int) bs.nbuttons; i++)
654 if (tolower(input) == tolower((bs.label[i])[0])) {
655 output = bs.value[i];
656 loop = false;
657 }
658 }
659 }
660
661 nodelay(stdscr, FALSE);
662
663 delwin(bar);
664 end_widget_withtextpad(conf, widget, h, w, textpad, shadow);
665
666 return output;
667 }
668