kconfig/lxdialog: refactor color support
[cascardo/linux.git] / scripts / kconfig / lxdialog / util.c
1 /*
2  *  util.c
3  *
4  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6  *
7  *  This program is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU General Public License
9  *  as published by the Free Software Foundation; either version 2
10  *  of the License, or (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "dialog.h"
23
24 struct dialog_info dlg;
25
26 static void set_mono_theme(void)
27 {
28         dlg.screen.atr = A_NORMAL;
29         dlg.shadow.atr = A_NORMAL;
30         dlg.dialog.atr = A_NORMAL;
31         dlg.title.atr = A_BOLD;
32         dlg.border.atr = A_NORMAL;
33         dlg.button_active.atr = A_REVERSE;
34         dlg.button_inactive.atr = A_DIM;
35         dlg.button_key_active.atr = A_REVERSE;
36         dlg.button_key_inactive.atr = A_BOLD;
37         dlg.button_label_active.atr = A_REVERSE;
38         dlg.button_label_inactive.atr = A_NORMAL;
39         dlg.inputbox.atr = A_NORMAL;
40         dlg.inputbox_border.atr = A_NORMAL;
41         dlg.searchbox.atr = A_NORMAL;
42         dlg.searchbox_title.atr = A_BOLD;
43         dlg.searchbox_border.atr = A_NORMAL;
44         dlg.position_indicator.atr = A_BOLD;
45         dlg.menubox.atr = A_NORMAL;
46         dlg.menubox_border.atr = A_NORMAL;
47         dlg.item.atr = A_NORMAL;
48         dlg.item_selected.atr = A_REVERSE;
49         dlg.tag.atr = A_BOLD;
50         dlg.tag_selected.atr = A_REVERSE;
51         dlg.tag_key.atr = A_BOLD;
52         dlg.tag_key_selected.atr = A_REVERSE;
53         dlg.check.atr = A_BOLD;
54         dlg.check_selected.atr = A_REVERSE;
55         dlg.uarrow.atr = A_BOLD;
56         dlg.darrow.atr = A_BOLD;
57 }
58
59 #define DLG_COLOR(dialog, f, b, h) \
60 do {                               \
61         dlg.dialog.fg = (f);       \
62         dlg.dialog.bg = (b);       \
63         dlg.dialog.hl = (h);       \
64 } while (0)
65
66 static void set_classic_theme(void)
67 {
68         DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
69         DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
70         DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
71         DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
72         DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
73         DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
74         DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
75         DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
76         DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
77         DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
78         DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
79         DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
80         DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
81         DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
82         DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
83         DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
84         DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
85         DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
86         DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
87         DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
88         DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
89         DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
90         DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
91         DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
92         DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
93         DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
94         DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
95         DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
96         DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
97 }
98
99 static void init_one_color(struct dialog_color *color)
100 {
101         static int pair = 0;
102
103         pair++;
104         init_pair(pair, color->fg, color->bg);
105         if (color->hl)
106                 color->atr = A_BOLD | COLOR_PAIR(pair);
107         else
108                 color->atr = COLOR_PAIR(pair);
109 }
110
111 static void init_dialog_colors(void)
112 {
113         init_one_color(&dlg.screen);
114         init_one_color(&dlg.shadow);
115         init_one_color(&dlg.dialog);
116         init_one_color(&dlg.title);
117         init_one_color(&dlg.border);
118         init_one_color(&dlg.button_active);
119         init_one_color(&dlg.button_inactive);
120         init_one_color(&dlg.button_key_active);
121         init_one_color(&dlg.button_key_inactive);
122         init_one_color(&dlg.button_label_active);
123         init_one_color(&dlg.button_label_inactive);
124         init_one_color(&dlg.inputbox);
125         init_one_color(&dlg.inputbox_border);
126         init_one_color(&dlg.searchbox);
127         init_one_color(&dlg.searchbox_title);
128         init_one_color(&dlg.searchbox_border);
129         init_one_color(&dlg.position_indicator);
130         init_one_color(&dlg.menubox);
131         init_one_color(&dlg.menubox_border);
132         init_one_color(&dlg.item);
133         init_one_color(&dlg.item_selected);
134         init_one_color(&dlg.tag);
135         init_one_color(&dlg.tag_selected);
136         init_one_color(&dlg.tag_key);
137         init_one_color(&dlg.tag_key_selected);
138         init_one_color(&dlg.check);
139         init_one_color(&dlg.check_selected);
140         init_one_color(&dlg.uarrow);
141         init_one_color(&dlg.darrow);
142 }
143
144 /*
145  * Setup for color display
146  */
147 static void color_setup(void)
148 {
149         if (has_colors()) {     /* Terminal supports color? */
150                 start_color();
151                 set_classic_theme();
152                 init_dialog_colors();
153         }
154         else
155         {
156                 set_mono_theme();
157         }
158 }
159
160 /*
161  * Set window to attribute 'attr'
162  */
163 void attr_clear(WINDOW * win, int height, int width, chtype attr)
164 {
165         int i, j;
166
167         wattrset(win, attr);
168         for (i = 0; i < height; i++) {
169                 wmove(win, i, 0);
170                 for (j = 0; j < width; j++)
171                         waddch(win, ' ');
172         }
173         touchwin(win);
174 }
175
176 void dialog_clear(void)
177 {
178         attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
179         /* Display background title if it exists ... - SLH */
180         if (dlg.backtitle != NULL) {
181                 int i;
182
183                 wattrset(stdscr, dlg.screen.atr);
184                 mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
185                 wmove(stdscr, 1, 1);
186                 for (i = 1; i < COLS - 1; i++)
187                         waddch(stdscr, ACS_HLINE);
188         }
189         wnoutrefresh(stdscr);
190 }
191
192 /*
193  * Do some initialization for dialog
194  */
195 void init_dialog(void)
196 {
197         initscr();              /* Init curses */
198         keypad(stdscr, TRUE);
199         cbreak();
200         noecho();
201         color_setup();
202         dialog_clear();
203 }
204
205 /*
206  * End using dialog functions.
207  */
208 void end_dialog(void)
209 {
210         endwin();
211 }
212
213 /* Print the title of the dialog. Center the title and truncate
214  * tile if wider than dialog (- 2 chars).
215  **/
216 void print_title(WINDOW *dialog, const char *title, int width)
217 {
218         if (title) {
219                 int tlen = MIN(width - 2, strlen(title));
220                 wattrset(dialog, dlg.title.atr);
221                 mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
222                 mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
223                 waddch(dialog, ' ');
224         }
225 }
226
227 /*
228  * Print a string of text in a window, automatically wrap around to the
229  * next line if the string is too long to fit on one line. Newline
230  * characters '\n' are replaced by spaces.  We start on a new line
231  * if there is no room for at least 4 nonblanks following a double-space.
232  */
233 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
234 {
235         int newl, cur_x, cur_y;
236         int i, prompt_len, room, wlen;
237         char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
238
239         strcpy(tempstr, prompt);
240
241         prompt_len = strlen(tempstr);
242
243         /*
244          * Remove newlines
245          */
246         for (i = 0; i < prompt_len; i++) {
247                 if (tempstr[i] == '\n')
248                         tempstr[i] = ' ';
249         }
250
251         if (prompt_len <= width - x * 2) {      /* If prompt is short */
252                 wmove(win, y, (width - prompt_len) / 2);
253                 waddstr(win, tempstr);
254         } else {
255                 cur_x = x;
256                 cur_y = y;
257                 newl = 1;
258                 word = tempstr;
259                 while (word && *word) {
260                         sp = index(word, ' ');
261                         if (sp)
262                                 *sp++ = 0;
263
264                         /* Wrap to next line if either the word does not fit,
265                            or it is the first word of a new sentence, and it is
266                            short, and the next word does not fit. */
267                         room = width - cur_x;
268                         wlen = strlen(word);
269                         if (wlen > room ||
270                             (newl && wlen < 4 && sp
271                              && wlen + 1 + strlen(sp) > room
272                              && (!(sp2 = index(sp, ' '))
273                                  || wlen + 1 + (sp2 - sp) > room))) {
274                                 cur_y++;
275                                 cur_x = x;
276                         }
277                         wmove(win, cur_y, cur_x);
278                         waddstr(win, word);
279                         getyx(win, cur_y, cur_x);
280                         cur_x++;
281                         if (sp && *sp == ' ') {
282                                 cur_x++;        /* double space */
283                                 while (*++sp == ' ') ;
284                                 newl = 1;
285                         } else
286                                 newl = 0;
287                         word = sp;
288                 }
289         }
290 }
291
292 /*
293  * Print a button
294  */
295 void print_button(WINDOW * win, const char *label, int y, int x, int selected)
296 {
297         int i, temp;
298
299         wmove(win, y, x);
300         wattrset(win, selected ? dlg.button_active.atr
301                  : dlg.button_inactive.atr);
302         waddstr(win, "<");
303         temp = strspn(label, " ");
304         label += temp;
305         wattrset(win, selected ? dlg.button_label_active.atr
306                  : dlg.button_label_inactive.atr);
307         for (i = 0; i < temp; i++)
308                 waddch(win, ' ');
309         wattrset(win, selected ? dlg.button_key_active.atr
310                  : dlg.button_key_inactive.atr);
311         waddch(win, label[0]);
312         wattrset(win, selected ? dlg.button_label_active.atr
313                  : dlg.button_label_inactive.atr);
314         waddstr(win, (char *)label + 1);
315         wattrset(win, selected ? dlg.button_active.atr
316                  : dlg.button_inactive.atr);
317         waddstr(win, ">");
318         wmove(win, y, x + temp + 1);
319 }
320
321 /*
322  * Draw a rectangular box with line drawing characters
323  */
324 void
325 draw_box(WINDOW * win, int y, int x, int height, int width,
326          chtype box, chtype border)
327 {
328         int i, j;
329
330         wattrset(win, 0);
331         for (i = 0; i < height; i++) {
332                 wmove(win, y + i, x);
333                 for (j = 0; j < width; j++)
334                         if (!i && !j)
335                                 waddch(win, border | ACS_ULCORNER);
336                         else if (i == height - 1 && !j)
337                                 waddch(win, border | ACS_LLCORNER);
338                         else if (!i && j == width - 1)
339                                 waddch(win, box | ACS_URCORNER);
340                         else if (i == height - 1 && j == width - 1)
341                                 waddch(win, box | ACS_LRCORNER);
342                         else if (!i)
343                                 waddch(win, border | ACS_HLINE);
344                         else if (i == height - 1)
345                                 waddch(win, box | ACS_HLINE);
346                         else if (!j)
347                                 waddch(win, border | ACS_VLINE);
348                         else if (j == width - 1)
349                                 waddch(win, box | ACS_VLINE);
350                         else
351                                 waddch(win, box | ' ');
352         }
353 }
354
355 /*
356  * Draw shadows along the right and bottom edge to give a more 3D look
357  * to the boxes
358  */
359 void draw_shadow(WINDOW * win, int y, int x, int height, int width)
360 {
361         int i;
362
363         if (has_colors()) {     /* Whether terminal supports color? */
364                 wattrset(win, dlg.shadow.atr);
365                 wmove(win, y + height, x + 2);
366                 for (i = 0; i < width; i++)
367                         waddch(win, winch(win) & A_CHARTEXT);
368                 for (i = y + 1; i < y + height + 1; i++) {
369                         wmove(win, i, x + width);
370                         waddch(win, winch(win) & A_CHARTEXT);
371                         waddch(win, winch(win) & A_CHARTEXT);
372                 }
373                 wnoutrefresh(win);
374         }
375 }
376
377 /*
378  *  Return the position of the first alphabetic character in a string.
379  */
380 int first_alpha(const char *string, const char *exempt)
381 {
382         int i, in_paren = 0, c;
383
384         for (i = 0; i < strlen(string); i++) {
385                 c = tolower(string[i]);
386
387                 if (strchr("<[(", c))
388                         ++in_paren;
389                 if (strchr(">])", c) && in_paren > 0)
390                         --in_paren;
391
392                 if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
393                         return i;
394         }
395
396         return 0;
397 }