1c76f0793SBaptiste Daroussin /*-
2c76f0793SBaptiste Daroussin * SPDX-License-Identifier: BSD-2-Clause
3c76f0793SBaptiste Daroussin *
4*a6d8be45SAlfonso S. Siciliano * Copyright (c) 2021-2024 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
3461ba55bcSBaptiste Daroussin struct scrolltext {
3561ba55bcSBaptiste Daroussin WINDOW *pad;
3661ba55bcSBaptiste Daroussin int ypad;
3761ba55bcSBaptiste Daroussin int xpad;
3861ba55bcSBaptiste Daroussin int ys;
3961ba55bcSBaptiste Daroussin int ye;
4061ba55bcSBaptiste Daroussin int xs;
4161ba55bcSBaptiste Daroussin int xe;
4261ba55bcSBaptiste Daroussin int hpad;
4361ba55bcSBaptiste Daroussin int wpad;
4461ba55bcSBaptiste Daroussin int margin; /* 2 with multicolumn char, 0 otherwise */
4561ba55bcSBaptiste Daroussin int printrows; /* d.h - BORDERS - HBUTTONS */
4661ba55bcSBaptiste Daroussin };
4761ba55bcSBaptiste Daroussin
updateborders(struct dialog * d,struct scrolltext * st)4861ba55bcSBaptiste Daroussin static void updateborders(struct dialog *d, struct scrolltext *st)
49b319d934SAlfonso S. Siciliano {
50*a6d8be45SAlfonso S. Siciliano chtype arrowch;
51*a6d8be45SAlfonso S. Siciliano cchar_t borderch;
52b319d934SAlfonso S. Siciliano
5361ba55bcSBaptiste Daroussin if (d->conf->no_lines)
54*a6d8be45SAlfonso S. Siciliano setcchar(&borderch, L" ", 0, 0, NULL);
5561ba55bcSBaptiste Daroussin else if (d->conf->ascii_lines)
56*a6d8be45SAlfonso S. Siciliano setcchar(&borderch, L"|", 0, 0, NULL);
57b319d934SAlfonso S. Siciliano else
58*a6d8be45SAlfonso S. Siciliano borderch = *WACS_VLINE;
59b319d934SAlfonso S. Siciliano
6061ba55bcSBaptiste Daroussin if (st->xpad > 0) {
61*a6d8be45SAlfonso S. Siciliano arrowch = LARROW(d->conf) | t.dialog.arrowcolor;
6261ba55bcSBaptiste Daroussin mvwvline(d->widget, (d->h / 2) - 2, 0, arrowch, 4);
63*a6d8be45SAlfonso S. Siciliano } else {
64*a6d8be45SAlfonso S. Siciliano wattron(d->widget, t.dialog.lineraisecolor);
65*a6d8be45SAlfonso S. Siciliano mvwvline_set(d->widget, (d->h / 2) - 2, 0, &borderch, 4);
66*a6d8be45SAlfonso S. Siciliano wattroff(d->widget, t.dialog.lineraisecolor);
67*a6d8be45SAlfonso S. Siciliano }
68b319d934SAlfonso S. Siciliano
6961ba55bcSBaptiste Daroussin if (st->xpad + d->w - 2 - st->margin < st->wpad) {
70*a6d8be45SAlfonso S. Siciliano arrowch = RARROW(d->conf) | t.dialog.arrowcolor;
7161ba55bcSBaptiste Daroussin mvwvline(d->widget, (d->h / 2) - 2, d->w - 1, arrowch, 4);
72*a6d8be45SAlfonso S. Siciliano } else {
73*a6d8be45SAlfonso S. Siciliano wattron(d->widget, t.dialog.linelowercolor);
74*a6d8be45SAlfonso S. Siciliano mvwvline_set(d->widget, (d->h / 2) - 2, d->w - 1, &borderch, 4);
75*a6d8be45SAlfonso S. Siciliano wattroff(d->widget, t.dialog.linelowercolor);
76*a6d8be45SAlfonso S. Siciliano }
77b319d934SAlfonso S. Siciliano
7861ba55bcSBaptiste Daroussin if (st->hpad > d->h - 4) {
7961ba55bcSBaptiste Daroussin wattron(d->widget, t.dialog.arrowcolor);
8061ba55bcSBaptiste Daroussin mvwprintw(d->widget, d->h - 3, d->w - 6,
8161ba55bcSBaptiste Daroussin "%3d%%", 100 * (st->ypad + d->h - 4) / st->hpad);
8261ba55bcSBaptiste Daroussin wattroff(d->widget, t.dialog.arrowcolor);
83b319d934SAlfonso S. Siciliano }
84b319d934SAlfonso S. Siciliano }
85b319d934SAlfonso S. Siciliano
textbox_size_position(struct dialog * d,struct scrolltext * st)8661ba55bcSBaptiste Daroussin static int textbox_size_position(struct dialog *d, struct scrolltext *st)
87c76f0793SBaptiste Daroussin {
8861ba55bcSBaptiste Daroussin int minw;
89c76f0793SBaptiste Daroussin
9061ba55bcSBaptiste Daroussin if (set_widget_size(d->conf, d->rows, d->cols, &d->h, &d->w) != 0)
9161ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
9261ba55bcSBaptiste Daroussin if (set_widget_autosize(d->conf, d->rows, d->cols, &d->h, &d->w,
9361ba55bcSBaptiste Daroussin d->text, NULL, &d->bs, st->hpad, st->wpad + st->margin) != 0)
9461ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
9561ba55bcSBaptiste Daroussin minw = (st->wpad > 0) ? 2 /*multicolumn char*/ + st->margin : 0 ;
9661ba55bcSBaptiste Daroussin if (widget_checksize(d->h, d->w, &d->bs, MIN(st->hpad, 1), minw) != 0)
9761ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
9861ba55bcSBaptiste Daroussin if (set_widget_position(d->conf, &d->y, &d->x, d->h, d->w) != 0)
9961ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
10061ba55bcSBaptiste Daroussin
10161ba55bcSBaptiste Daroussin return (0);
102c76f0793SBaptiste Daroussin }
103c76f0793SBaptiste Daroussin
textbox_draw(struct dialog * d,struct scrolltext * st)10461ba55bcSBaptiste Daroussin static int textbox_draw(struct dialog *d, struct scrolltext *st)
105c76f0793SBaptiste Daroussin {
10661ba55bcSBaptiste Daroussin if (d->built) {
10761ba55bcSBaptiste Daroussin hide_dialog(d);
10861ba55bcSBaptiste Daroussin refresh(); /* Important for decreasing screen */
10961ba55bcSBaptiste Daroussin }
11061ba55bcSBaptiste Daroussin if (textbox_size_position(d, st) != 0)
11161ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
11261ba55bcSBaptiste Daroussin if (draw_dialog(d) != 0)
11361ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
11461ba55bcSBaptiste Daroussin if (d->built)
11561ba55bcSBaptiste Daroussin refresh(); /* Important to fix grey lines expanding screen */
116c76f0793SBaptiste Daroussin
11761ba55bcSBaptiste Daroussin st->ys = d->y + 1;
11861ba55bcSBaptiste Daroussin st->xs = (st->margin == 0) ? d->x + 1 : d->x + 2;
11961ba55bcSBaptiste Daroussin st->ye = st->ys + d->h - 5;
12061ba55bcSBaptiste Daroussin st->xe = st->xs + d->w - 3 - st->margin;
12161ba55bcSBaptiste Daroussin st->ypad = st->xpad = 0;
12261ba55bcSBaptiste Daroussin st->printrows = d->h-4;
123c76f0793SBaptiste Daroussin
124263660c0SAlfonso Siciliano return (0);
125c76f0793SBaptiste Daroussin }
126c76f0793SBaptiste Daroussin
127263660c0SAlfonso Siciliano /* API */
128f499134dSBaptiste Daroussin int
bsddialog_textbox(struct bsddialog_conf * conf,const char * file,int rows,int cols)129263660c0SAlfonso Siciliano bsddialog_textbox(struct bsddialog_conf *conf, const char *file, int rows,
130263660c0SAlfonso Siciliano int cols)
131c76f0793SBaptiste Daroussin {
13261ba55bcSBaptiste Daroussin bool loop, has_multicol_ch;
13361ba55bcSBaptiste Daroussin int i, retval;
134b319d934SAlfonso S. Siciliano unsigned int defaulttablen, linecols;
135b319d934SAlfonso S. Siciliano wint_t input;
136263660c0SAlfonso Siciliano char buf[BUFSIZ];
137263660c0SAlfonso Siciliano FILE *fp;
13861ba55bcSBaptiste Daroussin struct scrolltext st;
13961ba55bcSBaptiste Daroussin struct dialog d;
140c76f0793SBaptiste Daroussin
14161ba55bcSBaptiste Daroussin if (file == NULL)
14261ba55bcSBaptiste Daroussin RETURN_ERROR("*file is NULL");
143f499134dSBaptiste Daroussin if ((fp = fopen(file, "r")) == NULL)
14461ba55bcSBaptiste Daroussin RETURN_FMTERROR("Cannot open file \"%s\"", file);
14561ba55bcSBaptiste Daroussin
14661ba55bcSBaptiste Daroussin if (prepare_dialog(conf, "" /* fake */, rows, cols, &d) != 0)
14761ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
14861ba55bcSBaptiste Daroussin set_buttons(&d, true, "EXIT", NULL);
149f499134dSBaptiste Daroussin
150b319d934SAlfonso S. Siciliano defaulttablen = TABSIZE;
15161ba55bcSBaptiste Daroussin if (conf->text.tablen > 0)
15261ba55bcSBaptiste Daroussin set_tabsize(conf->text.tablen);
15361ba55bcSBaptiste Daroussin st.hpad = 1;
15461ba55bcSBaptiste Daroussin st.wpad = 1;
15561ba55bcSBaptiste Daroussin st.pad = newpad(st.hpad, st.wpad);
15661ba55bcSBaptiste Daroussin wbkgd(st.pad, t.dialog.color);
15761ba55bcSBaptiste Daroussin st.margin = 0;
158c76f0793SBaptiste Daroussin i = 0;
159c76f0793SBaptiste Daroussin while (fgets(buf, BUFSIZ, fp) != NULL) {
16061ba55bcSBaptiste Daroussin if (str_props(buf, &linecols, &has_multicol_ch) != 0)
161b319d934SAlfonso S. Siciliano continue;
16261ba55bcSBaptiste Daroussin if ((int)linecols > st.wpad) {
16361ba55bcSBaptiste Daroussin st.wpad = linecols;
16461ba55bcSBaptiste Daroussin wresize(st.pad, st.hpad, st.wpad);
165c76f0793SBaptiste Daroussin }
16661ba55bcSBaptiste Daroussin if (i > st.hpad-1) {
16761ba55bcSBaptiste Daroussin st.hpad++;
16861ba55bcSBaptiste Daroussin wresize(st.pad, st.hpad, st.wpad);
169c76f0793SBaptiste Daroussin }
17061ba55bcSBaptiste Daroussin mvwaddstr(st.pad, i, 0, buf);
171c76f0793SBaptiste Daroussin i++;
17261ba55bcSBaptiste Daroussin if (has_multicol_ch)
17361ba55bcSBaptiste Daroussin st.margin = 2;
174c76f0793SBaptiste Daroussin }
175c76f0793SBaptiste Daroussin fclose(fp);
17661ba55bcSBaptiste Daroussin set_tabsize(defaulttablen); /* reset because it is curses global */
177c76f0793SBaptiste Daroussin
17861ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0)
179263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR);
180c76f0793SBaptiste Daroussin
181c76f0793SBaptiste Daroussin loop = true;
182c76f0793SBaptiste Daroussin while (loop) {
18361ba55bcSBaptiste Daroussin updateborders(&d, &st);
184b319d934SAlfonso S. Siciliano /*
185*a6d8be45SAlfonso S. Siciliano * Trick, overflow multicolumn charchter right border:
186b319d934SAlfonso S. Siciliano * wnoutrefresh(widget);
187b319d934SAlfonso S. Siciliano * pnoutrefresh(pad, ypad, xpad, ys, xs, ye, xe);
188b319d934SAlfonso S. Siciliano * doupdate();
189b319d934SAlfonso S. Siciliano */
19061ba55bcSBaptiste Daroussin wrefresh(d.widget);
19161ba55bcSBaptiste Daroussin prefresh(st.pad, st.ypad, st.xpad, st.ys, st.xs, st.ye, st.xe);
192b319d934SAlfonso S. Siciliano if (get_wch(&input) == ERR)
193b319d934SAlfonso S. Siciliano continue;
19461ba55bcSBaptiste Daroussin if (shortcut_buttons(input, &d.bs)) {
19561ba55bcSBaptiste Daroussin DRAW_BUTTONS(d);
19661ba55bcSBaptiste Daroussin doupdate();
19761ba55bcSBaptiste Daroussin retval = BUTTONVALUE(d.bs);
19861ba55bcSBaptiste Daroussin break; /* loop */
19961ba55bcSBaptiste Daroussin }
200c76f0793SBaptiste Daroussin switch(input) {
201c76f0793SBaptiste Daroussin case KEY_ENTER:
202c76f0793SBaptiste Daroussin case 10: /* Enter */
203b319d934SAlfonso S. Siciliano retval = BSDDIALOG_OK;
204c76f0793SBaptiste Daroussin loop = false;
205c76f0793SBaptiste Daroussin break;
206c76f0793SBaptiste Daroussin case 27: /* Esc */
207263660c0SAlfonso Siciliano if (conf->key.enable_esc) {
208b319d934SAlfonso S. Siciliano retval = BSDDIALOG_ESC;
209c76f0793SBaptiste Daroussin loop = false;
210263660c0SAlfonso Siciliano }
211c76f0793SBaptiste Daroussin break;
21261ba55bcSBaptiste Daroussin case '\t': /* TAB */
21361ba55bcSBaptiste Daroussin d.bs.curr = (d.bs.curr + 1) % d.bs.nbuttons;
21461ba55bcSBaptiste Daroussin DRAW_BUTTONS(d);
21561ba55bcSBaptiste Daroussin break;
216c76f0793SBaptiste Daroussin case KEY_HOME:
21761ba55bcSBaptiste Daroussin st.ypad = 0;
218c76f0793SBaptiste Daroussin break;
219c76f0793SBaptiste Daroussin case KEY_END:
22061ba55bcSBaptiste Daroussin st.ypad = MAX(st.hpad - st.printrows, 0);
221c76f0793SBaptiste Daroussin break;
222c76f0793SBaptiste Daroussin case KEY_PPAGE:
22361ba55bcSBaptiste Daroussin st.ypad = MAX(st.ypad - st.printrows, 0);
224c76f0793SBaptiste Daroussin break;
225c76f0793SBaptiste Daroussin case KEY_NPAGE:
22661ba55bcSBaptiste Daroussin st.ypad += st.printrows;
22761ba55bcSBaptiste Daroussin if (st.ypad + st.printrows > st.hpad)
22861ba55bcSBaptiste Daroussin st.ypad = st.hpad - st.printrows;
229c76f0793SBaptiste Daroussin break;
230c76f0793SBaptiste Daroussin case '0':
23161ba55bcSBaptiste Daroussin st.xpad = 0;
23261ba55bcSBaptiste Daroussin break;
233c76f0793SBaptiste Daroussin case KEY_LEFT:
234c76f0793SBaptiste Daroussin case 'h':
23561ba55bcSBaptiste Daroussin st.xpad = MAX(st.xpad - 1, 0);
236c76f0793SBaptiste Daroussin break;
237c76f0793SBaptiste Daroussin case KEY_RIGHT:
238c76f0793SBaptiste Daroussin case 'l':
23961ba55bcSBaptiste Daroussin if (st.xpad + d.w - 2 - st.margin < st.wpad)
24061ba55bcSBaptiste Daroussin st.xpad++;
241c76f0793SBaptiste Daroussin break;
242c76f0793SBaptiste Daroussin case KEY_UP:
243c76f0793SBaptiste Daroussin case 'k':
24461ba55bcSBaptiste Daroussin st.ypad = MAX(st.ypad - 1, 0);
245c76f0793SBaptiste Daroussin break;
246c76f0793SBaptiste Daroussin case KEY_DOWN:
247c76f0793SBaptiste Daroussin case'j':
24861ba55bcSBaptiste Daroussin if (st.ypad + st.printrows <= st.hpad -1)
24961ba55bcSBaptiste Daroussin st.ypad++;
250c76f0793SBaptiste Daroussin break;
251c76f0793SBaptiste Daroussin case KEY_F(1):
252bce40c02SAlfonso S. Siciliano if (conf->key.f1_file == NULL &&
253bce40c02SAlfonso S. Siciliano conf->key.f1_message == NULL)
254c76f0793SBaptiste Daroussin break;
25561ba55bcSBaptiste Daroussin if (f1help_dialog(conf) != 0)
256263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR);
25761ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0)
258263660c0SAlfonso Siciliano return (BSDDIALOG_ERROR);
259c76f0793SBaptiste Daroussin break;
260*a6d8be45SAlfonso S. Siciliano case KEY_CTRL('l'):
26161ba55bcSBaptiste Daroussin case KEY_RESIZE:
26261ba55bcSBaptiste Daroussin if (textbox_draw(&d, &st) != 0)
26361ba55bcSBaptiste Daroussin return (BSDDIALOG_ERROR);
26461ba55bcSBaptiste Daroussin break;
265c76f0793SBaptiste Daroussin }
266c76f0793SBaptiste Daroussin }
267c76f0793SBaptiste Daroussin
26861ba55bcSBaptiste Daroussin delwin(st.pad);
26961ba55bcSBaptiste Daroussin end_dialog(&d);
270c76f0793SBaptiste Daroussin
271b319d934SAlfonso S. Siciliano return (retval);
272c76f0793SBaptiste Daroussin }
273