1c76f0793SBaptiste Daroussin /*- 2c76f0793SBaptiste Daroussin * SPDX-License-Identifier: BSD-2-Clause 3c76f0793SBaptiste Daroussin * 4*61ba55bcSBaptiste Daroussin * Copyright (c) 2021-2023 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 28263660c0SAlfonso Siciliano #include <curses.h> 29c76f0793SBaptiste Daroussin 30c76f0793SBaptiste Daroussin #include "bsddialog.h" 31c76f0793SBaptiste Daroussin #include "bsddialog_theme.h" 32263660c0SAlfonso Siciliano #include "lib_util.h" 33c76f0793SBaptiste Daroussin 34*61ba55bcSBaptiste Daroussin struct scrolltext { 35*61ba55bcSBaptiste Daroussin WINDOW *pad; 36*61ba55bcSBaptiste Daroussin int ypad; 37*61ba55bcSBaptiste Daroussin int xpad; 38*61ba55bcSBaptiste Daroussin int ys; 39*61ba55bcSBaptiste Daroussin int ye; 40*61ba55bcSBaptiste Daroussin int xs; 41*61ba55bcSBaptiste Daroussin int xe; 42*61ba55bcSBaptiste Daroussin int hpad; 43*61ba55bcSBaptiste Daroussin int wpad; 44*61ba55bcSBaptiste Daroussin int margin; /* 2 with multicolumn char, 0 otherwise */ 45*61ba55bcSBaptiste Daroussin int printrows; /* d.h - BORDERS - HBUTTONS */ 46*61ba55bcSBaptiste Daroussin }; 47*61ba55bcSBaptiste Daroussin 48*61ba55bcSBaptiste Daroussin static void updateborders(struct dialog *d, struct scrolltext *st) 49b319d934SAlfonso S. Siciliano { 50b319d934SAlfonso S. Siciliano chtype arrowch, borderch; 51b319d934SAlfonso S. Siciliano 52*61ba55bcSBaptiste Daroussin if (d->conf->no_lines) 53b319d934SAlfonso S. Siciliano borderch = ' '; 54*61ba55bcSBaptiste Daroussin else if (d->conf->ascii_lines) 55b319d934SAlfonso S. Siciliano borderch = '|'; 56b319d934SAlfonso S. Siciliano else 57b319d934SAlfonso S. Siciliano borderch = ACS_VLINE; 58b319d934SAlfonso S. Siciliano 59*61ba55bcSBaptiste Daroussin if (st->xpad > 0) { 60*61ba55bcSBaptiste Daroussin arrowch = d->conf->ascii_lines ? '<' : ACS_LARROW; 61*61ba55bcSBaptiste Daroussin arrowch |= t.dialog.arrowcolor; 62b319d934SAlfonso S. Siciliano } else { 63b319d934SAlfonso S. Siciliano arrowch = borderch; 64*61ba55bcSBaptiste Daroussin arrowch |= t.dialog.lineraisecolor; 65b319d934SAlfonso S. Siciliano } 66*61ba55bcSBaptiste Daroussin mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4); 67b319d934SAlfonso S. Siciliano 68*61ba55bcSBaptiste Daroussin if (st->xpad + d->w - 2 - st->margin < st->wpad) { 69*61ba55bcSBaptiste Daroussin arrowch = d->conf->ascii_lines ? '>' : ACS_RARROW; 70*61ba55bcSBaptiste Daroussin arrowch |= t.dialog.arrowcolor; 71b319d934SAlfonso S. Siciliano } else { 72b319d934SAlfonso S. Siciliano arrowch = borderch; 73*61ba55bcSBaptiste Daroussin arrowch |= t.dialog.linelowercolor; 74b319d934SAlfonso S. Siciliano } 75*61ba55bcSBaptiste Daroussin mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4); 76b319d934SAlfonso S. Siciliano 77*61ba55bcSBaptiste Daroussin if (st->hpad > d->h - 4) { 78*61ba55bcSBaptiste Daroussin wattron(d->widget, t.dialog.arrowcolor); 79*61ba55bcSBaptiste Daroussin mvwprintw(d->widget, d->h - 3, d->w - 6, 80*61ba55bcSBaptiste Daroussin "%3d%%", 100 * (st->ypad + d->h - 4) / st->hpad); 81*61ba55bcSBaptiste Daroussin wattroff(d->widget, t.dialog.arrowcolor); 82b319d934SAlfonso S. Siciliano } 83b319d934SAlfonso S. Siciliano } 84b319d934SAlfonso S. Siciliano 85*61ba55bcSBaptiste Daroussin static int textbox_size_position(struct dialog *d, struct scrolltext *st) 86c76f0793SBaptiste Daroussin { 87*61ba55bcSBaptiste Daroussin int minw; 88c76f0793SBaptiste Daroussin 89*61ba55bcSBaptiste Daroussin if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0) 90*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 91*61ba55bcSBaptiste Daroussin if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w, 92*61ba55bcSBaptiste Daroussin d->text, NULL, &d->bs, st->hpad, st->wpad + st->margin) != 0) 93*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 94*61ba55bcSBaptiste Daroussin minw = (st->wpad > 0) ? 2 /*multicolumn char*/ + st->margin : 0 ; 95*61ba55bcSBaptiste Daroussin if (widget_checksize(d->h, d->w, &d->bs, MIN(st->hpad, 1), minw) != 0) 96*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 97*61ba55bcSBaptiste Daroussin if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0) 98*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 99*61ba55bcSBaptiste Daroussin 100*61ba55bcSBaptiste Daroussin return (0); 101c76f0793SBaptiste Daroussin } 102c76f0793SBaptiste Daroussin 103*61ba55bcSBaptiste Daroussin static int textbox_draw(struct dialog *d, struct scrolltext *st) 104c76f0793SBaptiste Daroussin { 105*61ba55bcSBaptiste Daroussin if (d->built) { 106*61ba55bcSBaptiste Daroussin hide_dialog(d); 107*61ba55bcSBaptiste Daroussin refresh(); /* Important for decreasing screen */ 108*61ba55bcSBaptiste Daroussin } 109*61ba55bcSBaptiste Daroussin if (textbox_size_position(d, st) != 0) 110*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 111*61ba55bcSBaptiste Daroussin if (draw_dialog(d) != 0) 112*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 113*61ba55bcSBaptiste Daroussin if (d->built) 114*61ba55bcSBaptiste Daroussin refresh(); /* Important to fix grey lines expanding screen */ 115c76f0793SBaptiste Daroussin 116*61ba55bcSBaptiste Daroussin st->ys = d->y + 1; 117*61ba55bcSBaptiste Daroussin st->xs = (st->margin == 0) ? d->x + 1 : d->x + 2; 118*61ba55bcSBaptiste Daroussin st->ye = st->ys + d->h - 5; 119*61ba55bcSBaptiste Daroussin st->xe = st->xs + d->w - 3 - st->margin; 120*61ba55bcSBaptiste Daroussin st->ypad = st->xpad = 0; 121*61ba55bcSBaptiste Daroussin st->printrows = d->h-4; 122c76f0793SBaptiste Daroussin 123263660c0SAlfonso Siciliano return (0); 124c76f0793SBaptiste Daroussin } 125c76f0793SBaptiste Daroussin 126263660c0SAlfonso Siciliano /* API */ 127f499134dSBaptiste Daroussin int 128263660c0SAlfonso Siciliano bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows, 129263660c0SAlfonso Siciliano int cols) 130c76f0793SBaptiste Daroussin { 131*61ba55bcSBaptiste Daroussin bool loop, has_multicol_ch; 132*61ba55bcSBaptiste Daroussin int i, retval; 133b319d934SAlfonso S. Siciliano unsigned int defaulttablen, linecols; 134b319d934SAlfonso S. Siciliano wint_t input; 135263660c0SAlfonso Siciliano char buf[BUFSIZ]; 136263660c0SAlfonso Siciliano FILE *fp; 137*61ba55bcSBaptiste Daroussin struct scrolltext st; 138*61ba55bcSBaptiste Daroussin struct dialog d; 139c76f0793SBaptiste Daroussin 140*61ba55bcSBaptiste Daroussin if (file == NULL) 141*61ba55bcSBaptiste Daroussin RETURN_ERROR("*file is NULL"); 142f499134dSBaptiste Daroussin if ((fp = fopen(file, "r")) == NULL) 143*61ba55bcSBaptiste Daroussin RETURN_FMTERROR("Cannot open file \"%s\"", file); 144*61ba55bcSBaptiste Daroussin 145*61ba55bcSBaptiste Daroussin if (prepare_dialog(conf, "" /* fake */, rows, cols, &d) != 0) 146*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 147*61ba55bcSBaptiste Daroussin set_buttons(&d, true, "EXIT", NULL); 148f499134dSBaptiste Daroussin 149b319d934SAlfonso S. Siciliano defaulttablen = TABSIZE; 150*61ba55bcSBaptiste Daroussin if (conf->text.tablen > 0) 151*61ba55bcSBaptiste Daroussin set_tabsize(conf->text.tablen); 152*61ba55bcSBaptiste Daroussin st.hpad = 1; 153*61ba55bcSBaptiste Daroussin st.wpad = 1; 154*61ba55bcSBaptiste Daroussin st.pad = newpad(st.hpad, st.wpad); 155*61ba55bcSBaptiste Daroussin wbkgd(st.pad, t.dialog.color); 156*61ba55bcSBaptiste Daroussin st.margin = 0; 157c76f0793SBaptiste Daroussin i = 0; 158c76f0793SBaptiste Daroussin while (fgets(buf, BUFSIZ, fp) != NULL) { 159*61ba55bcSBaptiste Daroussin if (str_props(buf, &linecols, &has_multicol_ch) != 0) 160b319d934SAlfonso S. Siciliano continue; 161*61ba55bcSBaptiste Daroussin if ((int)linecols > st.wpad) { 162*61ba55bcSBaptiste Daroussin st.wpad = linecols; 163*61ba55bcSBaptiste Daroussin wresize(st.pad, st.hpad, st.wpad); 164c76f0793SBaptiste Daroussin } 165*61ba55bcSBaptiste Daroussin if (i > st.hpad-1) { 166*61ba55bcSBaptiste Daroussin st.hpad++; 167*61ba55bcSBaptiste Daroussin wresize(st.pad, st.hpad, st.wpad); 168c76f0793SBaptiste Daroussin } 169*61ba55bcSBaptiste Daroussin mvwaddstr(st.pad, i, 0, buf); 170c76f0793SBaptiste Daroussin i++; 171*61ba55bcSBaptiste Daroussin if (has_multicol_ch) 172*61ba55bcSBaptiste Daroussin st.margin = 2; 173c76f0793SBaptiste Daroussin } 174c76f0793SBaptiste Daroussin fclose(fp); 175*61ba55bcSBaptiste Daroussin set_tabsize(defaulttablen); /* reset because it is curses global */ 176c76f0793SBaptiste Daroussin 177*61ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0) 178263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 179c76f0793SBaptiste Daroussin 180c76f0793SBaptiste Daroussin loop = true; 181c76f0793SBaptiste Daroussin while (loop) { 182*61ba55bcSBaptiste Daroussin updateborders(&d, &st); 183b319d934SAlfonso S. Siciliano /* 184b319d934SAlfonso S. Siciliano * Overflow multicolumn charchter right border: 185b319d934SAlfonso S. Siciliano * wnoutrefresh(widget); 186b319d934SAlfonso S. Siciliano * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe); 187b319d934SAlfonso S. Siciliano * doupdate(); 188b319d934SAlfonso S. Siciliano */ 189*61ba55bcSBaptiste Daroussin wrefresh(d.widget); 190*61ba55bcSBaptiste Daroussin prefresh(st.pad, st.ypad, st.xpad, st.ys, st.xs, st.ye, st.xe); 191b319d934SAlfonso S. Siciliano if (get_wch(&input) == ERR) 192b319d934SAlfonso S. Siciliano continue; 193*61ba55bcSBaptiste Daroussin if (shortcut_buttons(input, &d.bs)) { 194*61ba55bcSBaptiste Daroussin DRAW_BUTTONS(d); 195*61ba55bcSBaptiste Daroussin doupdate(); 196*61ba55bcSBaptiste Daroussin retval = BUTTONVALUE(d.bs); 197*61ba55bcSBaptiste Daroussin break; /* loop */ 198*61ba55bcSBaptiste Daroussin } 199c76f0793SBaptiste Daroussin switch(input) { 200c76f0793SBaptiste Daroussin case KEY_ENTER: 201c76f0793SBaptiste Daroussin case 10: /* Enter */ 202b319d934SAlfonso S. Siciliano retval = BSDDIALOG_OK; 203c76f0793SBaptiste Daroussin loop = false; 204c76f0793SBaptiste Daroussin break; 205c76f0793SBaptiste Daroussin case 27: /* Esc */ 206263660c0SAlfonso Siciliano if (conf->key.enable_esc) { 207b319d934SAlfonso S. Siciliano retval = BSDDIALOG_ESC; 208c76f0793SBaptiste Daroussin loop = false; 209263660c0SAlfonso Siciliano } 210c76f0793SBaptiste Daroussin break; 211*61ba55bcSBaptiste Daroussin case '\t': /* TAB */ 212*61ba55bcSBaptiste Daroussin d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons; 213*61ba55bcSBaptiste Daroussin DRAW_BUTTONS(d); 214*61ba55bcSBaptiste Daroussin break; 215c76f0793SBaptiste Daroussin case KEY_HOME: 216*61ba55bcSBaptiste Daroussin st.ypad = 0; 217c76f0793SBaptiste Daroussin break; 218c76f0793SBaptiste Daroussin case KEY_END: 219*61ba55bcSBaptiste Daroussin st.ypad = MAX(st.hpad - st.printrows, 0); 220c76f0793SBaptiste Daroussin break; 221c76f0793SBaptiste Daroussin case KEY_PPAGE: 222*61ba55bcSBaptiste Daroussin st.ypad = MAX(st.ypad - st.printrows, 0); 223c76f0793SBaptiste Daroussin break; 224c76f0793SBaptiste Daroussin case KEY_NPAGE: 225*61ba55bcSBaptiste Daroussin st.ypad += st.printrows; 226*61ba55bcSBaptiste Daroussin if (st.ypad + st.printrows > st.hpad) 227*61ba55bcSBaptiste Daroussin st.ypad = st.hpad - st.printrows; 228c76f0793SBaptiste Daroussin break; 229c76f0793SBaptiste Daroussin case '0': 230*61ba55bcSBaptiste Daroussin st.xpad = 0; 231*61ba55bcSBaptiste Daroussin break; 232c76f0793SBaptiste Daroussin case KEY_LEFT: 233c76f0793SBaptiste Daroussin case 'h': 234*61ba55bcSBaptiste Daroussin st.xpad = MAX(st.xpad - 1, 0); 235c76f0793SBaptiste Daroussin break; 236c76f0793SBaptiste Daroussin case KEY_RIGHT: 237c76f0793SBaptiste Daroussin case 'l': 238*61ba55bcSBaptiste Daroussin if (st.xpad + d.w - 2 - st.margin < st.wpad) 239*61ba55bcSBaptiste Daroussin st.xpad++; 240c76f0793SBaptiste Daroussin break; 241c76f0793SBaptiste Daroussin case KEY_UP: 242c76f0793SBaptiste Daroussin case 'k': 243*61ba55bcSBaptiste Daroussin st.ypad = MAX(st.ypad - 1, 0); 244c76f0793SBaptiste Daroussin break; 245c76f0793SBaptiste Daroussin case KEY_DOWN: 246c76f0793SBaptiste Daroussin case'j': 247*61ba55bcSBaptiste Daroussin if (st.ypad + st.printrows <= st.hpad -1) 248*61ba55bcSBaptiste Daroussin st.ypad++; 249c76f0793SBaptiste Daroussin break; 250c76f0793SBaptiste Daroussin case KEY_F(1): 251bce40c02SAlfonso S. Siciliano if (conf->key.f1_file == NULL && 252bce40c02SAlfonso S. Siciliano conf->key.f1_message == NULL) 253c76f0793SBaptiste Daroussin break; 254*61ba55bcSBaptiste Daroussin if (f1help_dialog(conf) != 0) 255263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 256*61ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0) 257263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR); 258c76f0793SBaptiste Daroussin break; 259*61ba55bcSBaptiste Daroussin case KEY_RESIZE: 260*61ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0) 261*61ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR); 262*61ba55bcSBaptiste Daroussin break; 263c76f0793SBaptiste Daroussin } 264c76f0793SBaptiste Daroussin } 265c76f0793SBaptiste Daroussin 266*61ba55bcSBaptiste Daroussin delwin(st.pad); 267*61ba55bcSBaptiste Daroussin end_dialog(&d); 268c76f0793SBaptiste Daroussin 269b319d934SAlfonso S. Siciliano return (retval); 270c76f0793SBaptiste Daroussin } 271