xref: /linux-6.15/scripts/kconfig/lxdialog/util.c (revision 98e5a157)
1 /*
2  *  util.c
3  *
4  *  ORIGINAL AUTHOR: Savio Lam ([email protected])
5  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
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 }
398