]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bsddialog/lib/messagebox.c
zfs: merge openzfs/zfs@e0bd8118d
[FreeBSD/FreeBSD.git] / contrib / bsddialog / lib / messagebox.c
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 }