installer: Move the installer from contrib/ to usr.sbin/.
[dragonfly.git] / usr.sbin / installer / dfuife_curses / curses_util.c
1 /*
2  * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of Cat's Eye Technologies nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /*
35  * curses_util.c
36  * $Id: curses_util.c,v 1.7 2005/02/08 07:49:03 cpressey Exp $
37  */
38
39 #include <ctype.h>
40 #include <ncurses.h>
41 #include <panel.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "curses_util.h"
47
48 unsigned int ymax, xmax;
49 int monochrome = 1;
50 int allocated_colors = 0;
51
52 struct curses_attr {
53         int pair_no;
54         int bold;
55 };
56
57 struct curses_attr colors_tab[CURSES_COLORS_MAX];
58
59 int colors[8] = {
60         COLOR_BLACK,
61         COLOR_RED,
62         COLOR_GREEN,
63         COLOR_YELLOW,
64         COLOR_BLUE,
65         COLOR_MAGENTA,
66         COLOR_CYAN,
67         COLOR_WHITE
68 };
69
70 /*
71  * If there is an established color pair with the given fg and bg
72  * colors, return it.  Else allocate a new pair with these colors
73  * and return that.
74  */
75 static int
76 curses_colors_find(int fg, int bg)
77 {
78         int pair_no;
79         short fge, bge;
80
81         for (pair_no = 0;
82              pair_no <= allocated_colors && pair_no < COLOR_PAIRS;
83              pair_no++) {
84                 pair_content(pair_no, &fge, &bge);
85                 if (fg == fge && bg == bge)
86                         return(pair_no);
87         }
88
89         /*
90          * No pair was found, allocate a new one.
91          */
92         if (allocated_colors < (COLOR_PAIRS-1)) {
93                 allocated_colors++;
94                 init_pair(allocated_colors, fg, bg);
95                 return(allocated_colors);
96         }
97
98         /*
99          * No space to allocate a new one, return error.
100          */
101         return(-1);
102 }
103
104 static void
105 curses_colors_cfg(int role, int fg, int bg, int bold)
106 {
107         int pair_no;
108
109         pair_no = curses_colors_find(fg, bg);
110         if (pair_no != -1) {
111                 colors_tab[role].pair_no = pair_no;
112                 colors_tab[role].bold = bold;
113         } else {
114                 colors_tab[role].pair_no = 0;
115                 colors_tab[role].bold = bold;
116         }
117 }
118
119 void
120 curses_colors_init(int force_monochrome)
121 {
122         if (!force_monochrome) {
123                 if (has_colors()) {
124                         monochrome = 0;
125                         start_color();
126                 }
127         }
128
129         /*
130          * By default, make it look kinda like the default libdialog.
131          */
132         curses_colors_cfg(CURSES_COLORS_NORMAL,    COLOR_BLACK,  COLOR_GREY,  0);
133         curses_colors_cfg(CURSES_COLORS_BACKDROP,  COLOR_WHITE,  COLOR_BLUE,  0);
134         curses_colors_cfg(CURSES_COLORS_MENUBAR,   COLOR_BLACK,  COLOR_GREY,  0);
135         curses_colors_cfg(CURSES_COLORS_STATUSBAR, COLOR_BLACK,  COLOR_GREY,  0);
136         curses_colors_cfg(CURSES_COLORS_BORDER,    COLOR_WHITE,  COLOR_GREY,  1);
137         curses_colors_cfg(CURSES_COLORS_FORMTITLE, COLOR_YELLOW, COLOR_GREY,  1);
138         curses_colors_cfg(CURSES_COLORS_LABEL,     COLOR_BLACK,  COLOR_GREY,  0);
139         curses_colors_cfg(CURSES_COLORS_CONTROL,   COLOR_BLACK,  COLOR_GREY,  0);
140         curses_colors_cfg(CURSES_COLORS_TEXT,      COLOR_BLACK,  COLOR_GREY,  0);
141         curses_colors_cfg(CURSES_COLORS_FOCUS,     COLOR_WHITE,  COLOR_BLUE,  1);
142         curses_colors_cfg(CURSES_COLORS_SCROLLAREA,COLOR_GREY,   COLOR_BLACK, 0);
143         curses_colors_cfg(CURSES_COLORS_SCROLLBAR, COLOR_WHITE,  COLOR_BLUE,  1);
144         curses_colors_cfg(CURSES_COLORS_ACCEL,     COLOR_WHITE,  COLOR_GREY,  1);
145         curses_colors_cfg(CURSES_COLORS_ACCELFOCUS,COLOR_YELLOW, COLOR_BLUE,  1);
146 }
147
148 void
149 curses_colors_set(WINDOW *w, int a)
150 {
151         if (!monochrome)
152                 wattrset(w, COLOR_PAIR(colors_tab[a].pair_no));
153         if (colors_tab[a].bold)
154                 wattron(w, A_BOLD);
155         else
156                 wattroff(w, A_BOLD);
157 }
158
159 void
160 curses_window_blank(WINDOW *w)
161 {
162         unsigned int i;
163
164         for (i = 0; i <= ymax; i++) {
165                 wmove(w, i, 0);
166                 whline(w, ' ', xmax);
167         }
168
169         wrefresh(w);
170 }
171
172 void
173 curses_frame_draw(int x, int y, int width, int height)
174 {
175         int i;
176
177         mvaddch(y, x, ACS_ULCORNER);
178         hline(ACS_HLINE, width - 2);
179         mvaddch(y, x + width - 1, ACS_URCORNER);
180
181         mvaddch(y + height - 1, x, ACS_LLCORNER);
182         hline(ACS_HLINE, width - 2);
183         mvaddch(y + height - 1, x + width - 1, ACS_LRCORNER);
184
185         move(y + 1, x);
186         vline(ACS_VLINE, height - 2);
187
188         move(y + 1, x + width - 1);
189         vline(ACS_VLINE, height - 2);
190
191         for (i = y + 1; i < y + height - 1; i++) {
192                 move(i, x + 1);
193                 hline(' ', width - 2);
194         }
195 }
196
197 void
198 curses_load_backdrop(WINDOW *w, const char *filename)
199 {
200         FILE *f;
201         char line[80];
202         int row = 1;
203         int my, mx;
204
205         getmaxyx(w, my, mx);
206         wclear(w);
207         curses_colors_set(w, CURSES_COLORS_BACKDROP);
208         curses_window_blank(w);
209
210         if ((f = fopen(filename, "r")) != NULL) {
211                 while (fgets(line, 79, f) != NULL) {
212                         if (row > my)
213                                 break;
214                         if (line[strlen(line) - 1] == '\n')
215                                 line[strlen(line) - 1] = '\0';
216                         mvwaddnstr(w, row++, 0, line, mx);
217                 }
218                 fclose(f);
219         }
220 }
221
222 void
223 curses_debug_str(const char *s)
224 {
225         char b[256];
226
227         move(1, 0);
228         sprintf(b, "[%77s]", s);
229         addstr(b);
230         refresh();
231 }
232
233 void
234 curses_debug_int(int i)
235 {
236         char b[256];
237
238         move(1, 0);
239         sprintf(b, "[%06d]", i);
240         addstr(b);
241         refresh();
242 }
243
244 void
245 curses_debug_key(int i)
246 {
247         char b[256];
248
249         move(1, 0);
250         sprintf(b, "[%06d] %s", i, keyname(i));
251         addstr(b);
252         refresh();
253 }
254
255 void
256 curses_debug_float(float f)
257 {
258         char b[256];
259
260         move(1, 0);
261         sprintf(b, "[%09.3f]", f);
262         addstr(b);
263         refresh();
264 }
265
266 /*
267  * Word wrapping.
268  *
269  * text:        The text to word-wrap, as one long string.  Spaces will be
270  *              compressed, but end-of-line characters will be honoured.
271  * line:        A buffer (must be allocated by the caller) to hold a single
272  *              line extracted from text.
273  * width:       The maximum width of a line.
274  * spos:        Pointer to the source position in text.  Should be initially
275  *              set to zero, and retained between calls to this function.
276  * Returns:     A boolean indicating whether the end of text was reached.
277  *              Typically this function should be called repeatedly until
278  *              it returns true.
279  */
280 int
281 extract_wrapped_line(const char *text, char *line, int width, int *spos)
282 {
283         int dpos = 0;
284         int saved_spos, saved_dpos;
285
286         for (;;) {
287                 /*
288                  * Skip over whitespace.  If we find a newline or the
289                  * end of the text, return a blank line.  Leave *spos
290                  * at the position of the 1st non-whitespace character.
291                  */
292                 while (isspace(text[*spos]) && text[*spos] != '\0') {
293                         if (text[*spos] == '\n') {
294                                 line[dpos] = '\0';
295                                 (*spos)++;
296                                 return(0);
297                         }
298                         (*spos)++;
299                 }
300
301                 /*
302                  * Save start position and destination position.
303                  */
304                 saved_spos = *spos;
305                 saved_dpos = dpos;
306
307                 /*
308                  * Read a word from *spos onward.
309                  */
310                 while (!isspace(text[*spos]) &&
311                        text[*spos] != '\0' &&
312                        dpos < width) {
313                         line[dpos++] = text[(*spos)++];
314                 }
315
316                 if (text[*spos] == '\0') {
317                         /*
318                          * End of string - return this word as the last.
319                          */
320                         line[dpos] = '\0';
321                         return(1);
322                 } else if (dpos >= width) {
323                         /*
324                          * Last word is too long to fit on this line.
325                          */
326                         if (dpos - saved_dpos >= width) {
327                                 /*
328                                  * In fact, it's too long to fit on any line!
329                                  * Truncate it.
330                                  */
331                                 line[width - 1] = '\0';
332                                 *spos = saved_spos + (dpos - saved_dpos);
333                                 return(0);
334                         } else {
335                                 /*
336                                  * Save it for the next pass.
337                                  */
338                                 *spos = saved_spos;
339                                 line[saved_dpos - 1] = '\0';
340                                 return(0);
341                         }
342                 } else {
343                         line[dpos++] = ' ';
344                 }
345         }
346 }