1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021-2023 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 <curses.h> 29 30 #include "bsddialog.h" 31 #include "bsddialog_theme.h" 32 #include "lib_util.h" 33 34 struct scroll { 35 int ypad; /* y scrollable pad */ 36 int htext; /* real h text to draw, to use with htextpad */ 37 int htextpad; /* h textpad, draw_dialog() set at least 1 */ 38 int printrows; /* h - BORDER - HBUTTONS - BORDER */ 39 }; 40 41 static void textupdate(struct dialog *d, struct scroll *s) 42 { 43 if (s->htext > 0 && s->htextpad > s->printrows) { 44 wattron(d->widget, t.dialog.arrowcolor); 45 mvwprintw(d->widget, d->h - HBUTTONS - BORDER, 46 d->w - 4 - TEXTHMARGIN - BORDER, 47 "%3d%%", 100 * (s->ypad + s->printrows) / s->htextpad); 48 wattroff(d->widget, t.dialog.arrowcolor); 49 wnoutrefresh(d->widget); 50 } 51 rtextpad(d, s->ypad, 0, 0, HBUTTONS); 52 } 53 54 static int message_size_position(struct dialog *d, int *htext) 55 { 56 int minw; 57 58 if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0) 59 return (BSDDIALOG_ERROR); 60 if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w, 61 d->text, (*htext < 0) ? htext : NULL, &d->bs, 0, 0) != 0) 62 return (BSDDIALOG_ERROR); 63 minw = (*htext > 0) ? 1 + TEXTHMARGINS : 0 ; 64 if (widget_checksize(d->h, d->w, &d->bs, MIN(*htext, 1), minw) != 0) 65 return (BSDDIALOG_ERROR); 66 if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0) 67 return (BSDDIALOG_ERROR); 68 69 return (0); 70 } 71 72 static int message_draw(struct dialog *d, struct scroll *s) 73 { 74 int unused; 75 76 if (d->built) { 77 hide_dialog(d); 78 refresh(); /* Important for decreasing screen */ 79 } 80 if (message_size_position(d, &s->htext) != 0) 81 return (BSDDIALOG_ERROR); 82 if (draw_dialog(d) != 0) 83 return (BSDDIALOG_ERROR); 84 if (d->built) 85 refresh(); /* Important to fix grey lines expanding screen */ 86 87 s->printrows = d->h - BORDER - HBUTTONS - BORDER; 88 s->ypad = 0; 89 getmaxyx(d->textpad, s->htextpad, unused); 90 unused++; /* fix unused error */ 91 92 return (0); 93 } 94 95 static int 96 do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols, 97 const char *oklabel, const char *cancellabel) 98 { 99 bool loop; 100 int retval; 101 wint_t input; 102 struct scroll s; 103 struct dialog d; 104 105 if (prepare_dialog(conf, text, rows, cols, &d) != 0) 106 return (BSDDIALOG_ERROR); 107 set_buttons(&d, true, oklabel, cancellabel); 108 s.htext = -1; 109 if(message_draw(&d, &s) != 0) 110 return (BSDDIALOG_ERROR); 111 112 loop = true; 113 while (loop) { 114 textupdate(&d, &s); 115 doupdate(); 116 if (get_wch(&input) == ERR) 117 continue; 118 switch (input) { 119 case KEY_ENTER: 120 case 10: /* Enter */ 121 retval = BUTTONVALUE(d.bs); 122 loop = false; 123 break; 124 case 27: /* Esc */ 125 if (d.conf->key.enable_esc) { 126 retval = BSDDIALOG_ESC; 127 loop = false; 128 } 129 break; 130 case '\t': /* TAB */ 131 case KEY_RIGHT: 132 d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons; 133 DRAW_BUTTONS(d); 134 break; 135 case KEY_LEFT: 136 d.bs.curr--; 137 if (d.bs.curr < 0) 138 d.bs.curr = d.bs.nbuttons - 1; 139 DRAW_BUTTONS(d); 140 break; 141 case KEY_UP: 142 if (s.ypad > 0) 143 s.ypad--; 144 break; 145 case KEY_DOWN: 146 if (s.ypad + s.printrows < s.htextpad) 147 s.ypad++; 148 break; 149 case KEY_HOME: 150 s.ypad = 0; 151 break; 152 case KEY_END: 153 s.ypad = MAX(s.htextpad - s.printrows, 0); 154 break; 155 case KEY_PPAGE: 156 s.ypad = MAX(s.ypad - s.printrows, 0); 157 break; 158 case KEY_NPAGE: 159 s.ypad += s.printrows; 160 if (s.ypad + s.printrows > s.htextpad) 161 s.ypad = s.htextpad - s.printrows; 162 break; 163 case KEY_F(1): 164 if (d.conf->key.f1_file == NULL && 165 d.conf->key.f1_message == NULL) 166 break; 167 if (f1help_dialog(d.conf) != 0) 168 return (BSDDIALOG_ERROR); 169 if(message_draw(&d, &s) != 0) 170 return (BSDDIALOG_ERROR); 171 break; 172 case KEY_RESIZE: 173 if(message_draw(&d, &s) != 0) 174 return (BSDDIALOG_ERROR); 175 break; 176 default: 177 if (shortcut_buttons(input, &d.bs)) { 178 DRAW_BUTTONS(d); 179 doupdate(); 180 retval = BUTTONVALUE(d.bs); 181 loop = false; 182 } 183 } 184 } 185 186 end_dialog(&d); 187 188 return (retval); 189 } 190 191 /* API */ 192 int 193 bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows, 194 int cols) 195 { 196 return (do_message(conf, text, rows, cols, OK_LABEL, NULL)); 197 } 198 199 int 200 bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows, 201 int cols) 202 { 203 return (do_message(conf, text, rows, cols, "Yes", "No")); 204 } 205 206 int 207 bsddialog_infobox(struct bsddialog_conf *conf, const char *text, int rows, 208 int cols) 209 { 210 int htext; 211 struct dialog d; 212 213 if (prepare_dialog(conf, text, rows, cols, &d) != 0) 214 return (BSDDIALOG_ERROR); 215 htext = -1; 216 if (message_size_position(&d, &htext) != 0) 217 return (BSDDIALOG_ERROR); 218 if (draw_dialog(&d) != 0) 219 return (BSDDIALOG_ERROR); 220 TEXTPAD(&d, 0); 221 doupdate(); 222 223 end_dialog(&d); 224 225 return (BSDDIALOG_OK); 226 } 227