1c76f0793SBaptiste Daroussin /*- 2c76f0793SBaptiste Daroussin * SPDX-License-Identifier: BSD-2-Clause 3c76f0793SBaptiste Daroussin * 4263660c0SAlfonso Siciliano * Copyright (c) 2021-2022 Alfonso Sabato Siciliano 5c76f0793SBaptiste Daroussin * 6c76f0793SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 7c76f0793SBaptiste Daroussin * modification, are permitted provided that the following conditions 8c76f0793SBaptiste Daroussin * are met: 9c76f0793SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 10c76f0793SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 11c76f0793SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 12c76f0793SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 13c76f0793SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 14c76f0793SBaptiste Daroussin * 15c76f0793SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16c76f0793SBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17c76f0793SBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18c76f0793SBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19c76f0793SBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20c76f0793SBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21c76f0793SBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22c76f0793SBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23c76f0793SBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24c76f0793SBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25c76f0793SBaptiste Daroussin * SUCH DAMAGE. 26c76f0793SBaptiste Daroussin */ 27c76f0793SBaptiste Daroussin 28c76f0793SBaptiste Daroussin #include <sys/param.h> 29c76f0793SBaptiste Daroussin 30263660c0SAlfonso Siciliano #include <curses.h> 31d93b4d32SBaptiste Daroussin #include <string.h> 32c76f0793SBaptiste Daroussin 33c76f0793SBaptiste Daroussin #include "bsddialog.h" 34b319d934SAlfonso S. Siciliano #include "bsddialog_theme.h" 35263660c0SAlfonso Siciliano #include "lib_util.h" 36c76f0793SBaptiste Daroussin 37c76f0793SBaptiste Daroussin static int 38d93b4d32SBaptiste Daroussin message_autosize(struct bsddialog_conf *conf, int rows, int cols, int *h, 39b319d934SAlfonso S. Siciliano int *w, const char *text, bool *hastext, struct buttons bs) 40c76f0793SBaptiste Daroussin { 41263660c0SAlfonso Siciliano int htext, wtext; 42c76f0793SBaptiste Daroussin 43b319d934SAlfonso S. Siciliano if (cols == BSDDIALOG_AUTOSIZE || rows == BSDDIALOG_AUTOSIZE || 44b319d934SAlfonso S. Siciliano hastext != NULL) { 45b319d934SAlfonso S. Siciliano if (text_size(conf, rows, cols, text, &bs, 0, 1, &htext, 46b319d934SAlfonso S. Siciliano &wtext) != 0) 47263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 48b319d934SAlfonso S. Siciliano if (hastext != NULL) 49b319d934SAlfonso S. Siciliano *hastext = htext > 0 ? true : false; 50c76f0793SBaptiste Daroussin } 51c76f0793SBaptiste Daroussin 52263660c0SAlfonso Siciliano if (cols == BSDDIALOG_AUTOSIZE) 53263660c0SAlfonso Siciliano *w = widget_min_width(conf, wtext, 0, &bs); 54c76f0793SBaptiste Daroussin 55263660c0SAlfonso Siciliano if (rows == BSDDIALOG_AUTOSIZE) 56263660c0SAlfonso Siciliano *h = widget_min_height(conf, htext, 0, true); 57263660c0SAlfonso Siciliano 58263660c0SAlfonso Siciliano return (0); 59c76f0793SBaptiste Daroussin } 60c76f0793SBaptiste Daroussin 61b319d934SAlfonso S. Siciliano static int 62b319d934SAlfonso S. Siciliano message_checksize(int rows, int cols, bool hastext, struct buttons bs) 63c76f0793SBaptiste Daroussin { 64c76f0793SBaptiste Daroussin int mincols; 65c76f0793SBaptiste Daroussin 66c76f0793SBaptiste Daroussin mincols = VBORDERS; 67b319d934SAlfonso S. Siciliano mincols += buttons_min_width(bs); 68c76f0793SBaptiste Daroussin 69c76f0793SBaptiste Daroussin if (cols < mincols) 70263660c0SAlfonso Siciliano RETURN_ERROR("Few cols, Msgbox and Yesno need at least width " 71c76f0793SBaptiste Daroussin "for borders, buttons and spaces between buttons"); 72c76f0793SBaptiste Daroussin 73263660c0SAlfonso Siciliano if (rows < HBORDERS + 2 /* buttons */) 74b319d934SAlfonso S. Siciliano RETURN_ERROR("Msgbox and Yesno need at least 4 rows"); 75b319d934SAlfonso S. Siciliano if (hastext && rows < HBORDERS + 2 /*buttons*/ + 1 /* text row */) 76b319d934SAlfonso S. Siciliano RETURN_ERROR("Msgbox and Yesno with text need at least 5 rows"); 77c76f0793SBaptiste Daroussin 78263660c0SAlfonso Siciliano return (0); 79c76f0793SBaptiste Daroussin } 80c76f0793SBaptiste Daroussin 81c76f0793SBaptiste Daroussin static void 82b319d934SAlfonso S. Siciliano textupdate(WINDOW *widget, WINDOW *textpad, int htextpad, int ytextpad, 83b319d934SAlfonso S. Siciliano bool hastext) 84c76f0793SBaptiste Daroussin { 85263660c0SAlfonso Siciliano int y, x, h, w; 86c76f0793SBaptiste Daroussin 87263660c0SAlfonso Siciliano getbegyx(widget, y, x); 88263660c0SAlfonso Siciliano getmaxyx(widget, h, w); 89263660c0SAlfonso Siciliano 90b319d934SAlfonso S. Siciliano if (hastext && htextpad > h - 4) { 91b319d934SAlfonso S. Siciliano wattron(widget, t.dialog.arrowcolor); 92c76f0793SBaptiste Daroussin mvwprintw(widget, h-3, w-6, "%3d%%", 93263660c0SAlfonso Siciliano 100 * (ytextpad+h-4)/ htextpad); 94b319d934SAlfonso S. Siciliano wattroff(widget, t.dialog.arrowcolor); 95c76f0793SBaptiste Daroussin wnoutrefresh(widget); 96c76f0793SBaptiste Daroussin } 97c76f0793SBaptiste Daroussin 98263660c0SAlfonso Siciliano pnoutrefresh(textpad, ytextpad, 0, y+1, x+2, y+h-4, x+w-2); 99c76f0793SBaptiste Daroussin } 100c76f0793SBaptiste Daroussin 101c76f0793SBaptiste Daroussin static int 102263660c0SAlfonso Siciliano do_message(struct bsddialog_conf *conf, const char *text, int rows, int cols, 103d93b4d32SBaptiste Daroussin struct buttons bs) 104c76f0793SBaptiste Daroussin { 105b319d934SAlfonso S. Siciliano bool hastext, loop; 106*84823cc7SAlfonso S. Siciliano int y, x, h, w, retval, ytextpad, htextpad, printrows, unused; 107263660c0SAlfonso Siciliano WINDOW *widget, *textpad, *shadow; 108b319d934SAlfonso S. Siciliano wint_t input; 109c76f0793SBaptiste Daroussin 110c76f0793SBaptiste Daroussin if (set_widget_size(conf, rows, cols, &h, &w) != 0) 111263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 112b319d934SAlfonso S. Siciliano if (message_autosize(conf, rows, cols, &h, &w, text, &hastext, bs) != 0) 113263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 114b319d934SAlfonso S. Siciliano if (message_checksize(h, w, hastext, bs) != 0) 115263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 116c76f0793SBaptiste Daroussin if (set_widget_position(conf, &y, &x, h, w) != 0) 117263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 118c76f0793SBaptiste Daroussin 119263660c0SAlfonso Siciliano if (new_dialog(conf, &shadow, &widget, y, x, h, w, &textpad, text, &bs, 120263660c0SAlfonso Siciliano true) != 0) 121263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 122c76f0793SBaptiste Daroussin 123*84823cc7SAlfonso S. Siciliano printrows = h - 4; 124263660c0SAlfonso Siciliano ytextpad = 0; 125263660c0SAlfonso Siciliano getmaxyx(textpad, htextpad, unused); 126263660c0SAlfonso Siciliano unused++; /* fix unused error */ 127c76f0793SBaptiste Daroussin loop = true; 128c76f0793SBaptiste Daroussin while (loop) { 129*84823cc7SAlfonso S. Siciliano textupdate(widget, textpad, htextpad, ytextpad, hastext); 130c76f0793SBaptiste Daroussin doupdate(); 131b319d934SAlfonso S. Siciliano if (get_wch(&input) == ERR) 132b319d934SAlfonso S. Siciliano continue; 133c76f0793SBaptiste Daroussin switch (input) { 134263660c0SAlfonso Siciliano case KEY_ENTER: 135c76f0793SBaptiste Daroussin case 10: /* Enter */ 136b319d934SAlfonso S. Siciliano retval = bs.value[bs.curr]; 137c76f0793SBaptiste Daroussin loop = false; 138c76f0793SBaptiste Daroussin break; 139c76f0793SBaptiste Daroussin case 27: /* Esc */ 140263660c0SAlfonso Siciliano if (conf->key.enable_esc) { 141b319d934SAlfonso S. Siciliano retval = BSDDIALOG_ESC; 142c76f0793SBaptiste Daroussin loop = false; 143263660c0SAlfonso Siciliano } 144c76f0793SBaptiste Daroussin break; 145c76f0793SBaptiste Daroussin case '\t': /* TAB */ 146c76f0793SBaptiste Daroussin bs.curr = (bs.curr + 1) % bs.nbuttons; 147263660c0SAlfonso Siciliano draw_buttons(widget, bs, true); 148263660c0SAlfonso Siciliano wnoutrefresh(widget); 149c76f0793SBaptiste Daroussin break; 150c76f0793SBaptiste Daroussin case KEY_LEFT: 151c76f0793SBaptiste Daroussin if (bs.curr > 0) { 152c76f0793SBaptiste Daroussin bs.curr--; 153263660c0SAlfonso Siciliano draw_buttons(widget, bs, true); 154263660c0SAlfonso Siciliano wnoutrefresh(widget); 155c76f0793SBaptiste Daroussin } 156c76f0793SBaptiste Daroussin break; 157c76f0793SBaptiste Daroussin case KEY_RIGHT: 158c76f0793SBaptiste Daroussin if (bs.curr < (int)bs.nbuttons - 1) { 159c76f0793SBaptiste Daroussin bs.curr++; 160263660c0SAlfonso Siciliano draw_buttons(widget, bs, true); 161263660c0SAlfonso Siciliano wnoutrefresh(widget); 162c76f0793SBaptiste Daroussin } 163c76f0793SBaptiste Daroussin break; 164*84823cc7SAlfonso S. Siciliano case KEY_UP: 165*84823cc7SAlfonso S. Siciliano if (ytextpad > 0) 166*84823cc7SAlfonso S. Siciliano ytextpad--; 167*84823cc7SAlfonso S. Siciliano break; 168*84823cc7SAlfonso S. Siciliano case KEY_DOWN: 169*84823cc7SAlfonso S. Siciliano if (ytextpad + printrows < htextpad) 170*84823cc7SAlfonso S. Siciliano ytextpad++; 171*84823cc7SAlfonso S. Siciliano break; 172*84823cc7SAlfonso S. Siciliano case KEY_HOME: 173*84823cc7SAlfonso S. Siciliano ytextpad = 0; 174*84823cc7SAlfonso S. Siciliano break; 175*84823cc7SAlfonso S. Siciliano case KEY_END: 176*84823cc7SAlfonso S. Siciliano ytextpad = htextpad - printrows; 177*84823cc7SAlfonso S. Siciliano ytextpad = ytextpad < 0 ? 0 : ytextpad; 178*84823cc7SAlfonso S. Siciliano break; 179*84823cc7SAlfonso S. Siciliano case KEY_PPAGE: 180*84823cc7SAlfonso S. Siciliano ytextpad -= printrows; 181*84823cc7SAlfonso S. Siciliano ytextpad = ytextpad < 0 ? 0 : ytextpad; 182*84823cc7SAlfonso S. Siciliano break; 183*84823cc7SAlfonso S. Siciliano case KEY_NPAGE: 184*84823cc7SAlfonso S. Siciliano ytextpad += printrows; 185*84823cc7SAlfonso S. Siciliano if (ytextpad + printrows > htextpad) 186*84823cc7SAlfonso S. Siciliano ytextpad = htextpad - printrows; 187*84823cc7SAlfonso S. Siciliano break; 188263660c0SAlfonso Siciliano case KEY_F(1): 189bce40c02SAlfonso S. Siciliano if (conf->key.f1_file == NULL && 190bce40c02SAlfonso S. Siciliano conf->key.f1_message == NULL) 191263660c0SAlfonso Siciliano break; 192263660c0SAlfonso Siciliano if (f1help(conf) != 0) 193263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 194263660c0SAlfonso Siciliano /* No break, screen size can change */ 195263660c0SAlfonso Siciliano case KEY_RESIZE: 196263660c0SAlfonso Siciliano /* Important for decreasing screen */ 197263660c0SAlfonso Siciliano hide_widget(y, x, h, w, conf->shadow); 198263660c0SAlfonso Siciliano refresh(); 199263660c0SAlfonso Siciliano 200263660c0SAlfonso Siciliano if (set_widget_size(conf, rows, cols, &h, &w) != 0) 201263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 202263660c0SAlfonso Siciliano if (message_autosize(conf, rows, cols, &h, &w, text, 203b319d934SAlfonso S. Siciliano NULL, bs) != 0) 204263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 205b319d934SAlfonso S. Siciliano if (message_checksize(h, w, hastext, bs) != 0) 206263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 207263660c0SAlfonso Siciliano if (set_widget_position(conf, &y, &x, h, w) != 0) 208263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 209263660c0SAlfonso Siciliano 210263660c0SAlfonso Siciliano if (update_dialog(conf, shadow, widget, y, x, h, w, 211263660c0SAlfonso Siciliano textpad, text, &bs, true) != 0) 212263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 213263660c0SAlfonso Siciliano 214*84823cc7SAlfonso S. Siciliano printrows = h - 4; 215263660c0SAlfonso Siciliano getmaxyx(textpad, htextpad, unused); 216b319d934SAlfonso S. Siciliano ytextpad = 0; 217b319d934SAlfonso S. Siciliano textupdate(widget, textpad, htextpad, ytextpad, hastext); 218263660c0SAlfonso Siciliano 219263660c0SAlfonso Siciliano /* Important to fix grey lines expanding screen */ 220263660c0SAlfonso Siciliano refresh(); 221263660c0SAlfonso Siciliano break; 222c76f0793SBaptiste Daroussin default: 223263660c0SAlfonso Siciliano if (shortcut_buttons(input, &bs)) { 224b319d934SAlfonso S. Siciliano retval = bs.value[bs.curr]; 225c76f0793SBaptiste Daroussin loop = false; 226c76f0793SBaptiste Daroussin } 227c76f0793SBaptiste Daroussin } 228c76f0793SBaptiste Daroussin } 229c76f0793SBaptiste Daroussin 230263660c0SAlfonso Siciliano end_dialog(conf, shadow, widget, textpad); 231c76f0793SBaptiste Daroussin 232b319d934SAlfonso S. Siciliano return (retval); 233c76f0793SBaptiste Daroussin } 234c76f0793SBaptiste Daroussin 235c76f0793SBaptiste Daroussin /* API */ 236c76f0793SBaptiste Daroussin int 237263660c0SAlfonso Siciliano bsddialog_msgbox(struct bsddialog_conf *conf, const char *text, int rows, 238263660c0SAlfonso Siciliano int cols) 239c76f0793SBaptiste Daroussin { 240c76f0793SBaptiste Daroussin struct buttons bs; 241c76f0793SBaptiste Daroussin 242263660c0SAlfonso Siciliano get_buttons(conf, &bs, BUTTON_OK_LABEL, NULL); 243c76f0793SBaptiste Daroussin 244263660c0SAlfonso Siciliano return (do_message(conf, text, rows, cols, bs)); 245c76f0793SBaptiste Daroussin } 246c76f0793SBaptiste Daroussin 247c76f0793SBaptiste Daroussin int 248263660c0SAlfonso Siciliano bsddialog_yesno(struct bsddialog_conf *conf, const char *text, int rows, 249263660c0SAlfonso Siciliano int cols) 250c76f0793SBaptiste Daroussin { 251c76f0793SBaptiste Daroussin struct buttons bs; 252c76f0793SBaptiste Daroussin 253263660c0SAlfonso Siciliano get_buttons(conf, &bs, "Yes", "No"); 254c76f0793SBaptiste Daroussin 255263660c0SAlfonso Siciliano return (do_message(conf, text, rows, cols, bs)); 256c76f0793SBaptiste Daroussin }