4 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
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.
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.
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.
26 /* Needed in signal handler in mconf.c */
29 struct dialog_info dlg
;
31 static void set_mono_theme(void)
33 dlg
.screen
.atr
= A_NORMAL
;
34 dlg
.shadow
.atr
= A_NORMAL
;
35 dlg
.dialog
.atr
= A_NORMAL
;
36 dlg
.title
.atr
= A_BOLD
;
37 dlg
.border
.atr
= A_NORMAL
;
38 dlg
.button_active
.atr
= A_REVERSE
;
39 dlg
.button_inactive
.atr
= A_DIM
;
40 dlg
.button_key_active
.atr
= A_REVERSE
;
41 dlg
.button_key_inactive
.atr
= A_BOLD
;
42 dlg
.button_label_active
.atr
= A_REVERSE
;
43 dlg
.button_label_inactive
.atr
= A_NORMAL
;
44 dlg
.inputbox
.atr
= A_NORMAL
;
45 dlg
.inputbox_border
.atr
= A_NORMAL
;
46 dlg
.searchbox
.atr
= A_NORMAL
;
47 dlg
.searchbox_title
.atr
= A_BOLD
;
48 dlg
.searchbox_border
.atr
= A_NORMAL
;
49 dlg
.position_indicator
.atr
= A_BOLD
;
50 dlg
.menubox
.atr
= A_NORMAL
;
51 dlg
.menubox_border
.atr
= A_NORMAL
;
52 dlg
.item
.atr
= A_NORMAL
;
53 dlg
.item_selected
.atr
= A_REVERSE
;
55 dlg
.tag_selected
.atr
= A_REVERSE
;
56 dlg
.tag_key
.atr
= A_BOLD
;
57 dlg
.tag_key_selected
.atr
= A_REVERSE
;
58 dlg
.check
.atr
= A_BOLD
;
59 dlg
.check_selected
.atr
= A_REVERSE
;
60 dlg
.uarrow
.atr
= A_BOLD
;
61 dlg
.darrow
.atr
= A_BOLD
;
64 #define DLG_COLOR(dialog, f, b, h) \
66 dlg.dialog.fg = (f); \
67 dlg.dialog.bg = (b); \
68 dlg.dialog.hl = (h); \
71 static void set_classic_theme(void)
73 DLG_COLOR(screen
, COLOR_CYAN
, COLOR_BLUE
, true);
74 DLG_COLOR(shadow
, COLOR_BLACK
, COLOR_BLACK
, true);
75 DLG_COLOR(dialog
, COLOR_BLACK
, COLOR_WHITE
, false);
76 DLG_COLOR(title
, COLOR_YELLOW
, COLOR_WHITE
, true);
77 DLG_COLOR(border
, COLOR_WHITE
, COLOR_WHITE
, true);
78 DLG_COLOR(button_active
, COLOR_WHITE
, COLOR_BLUE
, true);
79 DLG_COLOR(button_inactive
, COLOR_BLACK
, COLOR_WHITE
, false);
80 DLG_COLOR(button_key_active
, COLOR_WHITE
, COLOR_BLUE
, true);
81 DLG_COLOR(button_key_inactive
, COLOR_RED
, COLOR_WHITE
, false);
82 DLG_COLOR(button_label_active
, COLOR_YELLOW
, COLOR_BLUE
, true);
83 DLG_COLOR(button_label_inactive
, COLOR_BLACK
, COLOR_WHITE
, true);
84 DLG_COLOR(inputbox
, COLOR_BLACK
, COLOR_WHITE
, false);
85 DLG_COLOR(inputbox_border
, COLOR_BLACK
, COLOR_WHITE
, false);
86 DLG_COLOR(searchbox
, COLOR_BLACK
, COLOR_WHITE
, false);
87 DLG_COLOR(searchbox_title
, COLOR_YELLOW
, COLOR_WHITE
, true);
88 DLG_COLOR(searchbox_border
, COLOR_WHITE
, COLOR_WHITE
, true);
89 DLG_COLOR(position_indicator
, COLOR_YELLOW
, COLOR_WHITE
, true);
90 DLG_COLOR(menubox
, COLOR_BLACK
, COLOR_WHITE
, false);
91 DLG_COLOR(menubox_border
, COLOR_WHITE
, COLOR_WHITE
, true);
92 DLG_COLOR(item
, COLOR_BLACK
, COLOR_WHITE
, false);
93 DLG_COLOR(item_selected
, COLOR_WHITE
, COLOR_BLUE
, true);
94 DLG_COLOR(tag
, COLOR_YELLOW
, COLOR_WHITE
, true);
95 DLG_COLOR(tag_selected
, COLOR_YELLOW
, COLOR_BLUE
, true);
96 DLG_COLOR(tag_key
, COLOR_YELLOW
, COLOR_WHITE
, true);
97 DLG_COLOR(tag_key_selected
, COLOR_YELLOW
, COLOR_BLUE
, true);
98 DLG_COLOR(check
, COLOR_BLACK
, COLOR_WHITE
, false);
99 DLG_COLOR(check_selected
, COLOR_WHITE
, COLOR_BLUE
, true);
100 DLG_COLOR(uarrow
, COLOR_GREEN
, COLOR_WHITE
, true);
101 DLG_COLOR(darrow
, COLOR_GREEN
, COLOR_WHITE
, true);
104 static void set_blackbg_theme(void)
106 DLG_COLOR(screen
, COLOR_RED
, COLOR_BLACK
, true);
107 DLG_COLOR(shadow
, COLOR_BLACK
, COLOR_BLACK
, false);
108 DLG_COLOR(dialog
, COLOR_WHITE
, COLOR_BLACK
, false);
109 DLG_COLOR(title
, COLOR_RED
, COLOR_BLACK
, false);
110 DLG_COLOR(border
, COLOR_BLACK
, COLOR_BLACK
, true);
112 DLG_COLOR(button_active
, COLOR_YELLOW
, COLOR_RED
, false);
113 DLG_COLOR(button_inactive
, COLOR_YELLOW
, COLOR_BLACK
, false);
114 DLG_COLOR(button_key_active
, COLOR_YELLOW
, COLOR_RED
, true);
115 DLG_COLOR(button_key_inactive
, COLOR_RED
, COLOR_BLACK
, false);
116 DLG_COLOR(button_label_active
, COLOR_WHITE
, COLOR_RED
, false);
117 DLG_COLOR(button_label_inactive
, COLOR_BLACK
, COLOR_BLACK
, true);
119 DLG_COLOR(inputbox
, COLOR_YELLOW
, COLOR_BLACK
, false);
120 DLG_COLOR(inputbox_border
, COLOR_YELLOW
, COLOR_BLACK
, false);
122 DLG_COLOR(searchbox
, COLOR_YELLOW
, COLOR_BLACK
, false);
123 DLG_COLOR(searchbox_title
, COLOR_YELLOW
, COLOR_BLACK
, true);
124 DLG_COLOR(searchbox_border
, COLOR_BLACK
, COLOR_BLACK
, true);
126 DLG_COLOR(position_indicator
, COLOR_RED
, COLOR_BLACK
, false);
128 DLG_COLOR(menubox
, COLOR_YELLOW
, COLOR_BLACK
, false);
129 DLG_COLOR(menubox_border
, COLOR_BLACK
, COLOR_BLACK
, true);
131 DLG_COLOR(item
, COLOR_WHITE
, COLOR_BLACK
, false);
132 DLG_COLOR(item_selected
, COLOR_WHITE
, COLOR_RED
, false);
134 DLG_COLOR(tag
, COLOR_RED
, COLOR_BLACK
, false);
135 DLG_COLOR(tag_selected
, COLOR_YELLOW
, COLOR_RED
, true);
136 DLG_COLOR(tag_key
, COLOR_RED
, COLOR_BLACK
, false);
137 DLG_COLOR(tag_key_selected
, COLOR_YELLOW
, COLOR_RED
, true);
139 DLG_COLOR(check
, COLOR_YELLOW
, COLOR_BLACK
, false);
140 DLG_COLOR(check_selected
, COLOR_YELLOW
, COLOR_RED
, true);
142 DLG_COLOR(uarrow
, COLOR_RED
, COLOR_BLACK
, false);
143 DLG_COLOR(darrow
, COLOR_RED
, COLOR_BLACK
, false);
146 static void set_bluetitle_theme(void)
149 DLG_COLOR(title
, COLOR_BLUE
, COLOR_WHITE
, true);
150 DLG_COLOR(button_key_active
, COLOR_YELLOW
, COLOR_BLUE
, true);
151 DLG_COLOR(button_label_active
, COLOR_WHITE
, COLOR_BLUE
, true);
152 DLG_COLOR(searchbox_title
, COLOR_BLUE
, COLOR_WHITE
, true);
153 DLG_COLOR(position_indicator
, COLOR_BLUE
, COLOR_WHITE
, true);
154 DLG_COLOR(tag
, COLOR_BLUE
, COLOR_WHITE
, true);
155 DLG_COLOR(tag_key
, COLOR_BLUE
, COLOR_WHITE
, true);
162 static int set_theme(const char *theme
)
166 set_bluetitle_theme();
167 else if (strcmp(theme
, "classic") == 0)
169 else if (strcmp(theme
, "bluetitle") == 0)
170 set_bluetitle_theme();
171 else if (strcmp(theme
, "blackbg") == 0)
173 else if (strcmp(theme
, "mono") == 0)
179 static void init_one_color(struct dialog_color
*color
)
184 init_pair(pair
, color
->fg
, color
->bg
);
186 color
->atr
= A_BOLD
| COLOR_PAIR(pair
);
188 color
->atr
= COLOR_PAIR(pair
);
191 static void init_dialog_colors(void)
193 init_one_color(&dlg
.screen
);
194 init_one_color(&dlg
.shadow
);
195 init_one_color(&dlg
.dialog
);
196 init_one_color(&dlg
.title
);
197 init_one_color(&dlg
.border
);
198 init_one_color(&dlg
.button_active
);
199 init_one_color(&dlg
.button_inactive
);
200 init_one_color(&dlg
.button_key_active
);
201 init_one_color(&dlg
.button_key_inactive
);
202 init_one_color(&dlg
.button_label_active
);
203 init_one_color(&dlg
.button_label_inactive
);
204 init_one_color(&dlg
.inputbox
);
205 init_one_color(&dlg
.inputbox_border
);
206 init_one_color(&dlg
.searchbox
);
207 init_one_color(&dlg
.searchbox_title
);
208 init_one_color(&dlg
.searchbox_border
);
209 init_one_color(&dlg
.position_indicator
);
210 init_one_color(&dlg
.menubox
);
211 init_one_color(&dlg
.menubox_border
);
212 init_one_color(&dlg
.item
);
213 init_one_color(&dlg
.item_selected
);
214 init_one_color(&dlg
.tag
);
215 init_one_color(&dlg
.tag_selected
);
216 init_one_color(&dlg
.tag_key
);
217 init_one_color(&dlg
.tag_key_selected
);
218 init_one_color(&dlg
.check
);
219 init_one_color(&dlg
.check_selected
);
220 init_one_color(&dlg
.uarrow
);
221 init_one_color(&dlg
.darrow
);
225 * Setup for color display
227 static void color_setup(const char *theme
)
231 use_color
= set_theme(theme
);
232 if (use_color
&& has_colors()) {
234 init_dialog_colors();
240 * Set window to attribute 'attr'
242 void attr_clear(WINDOW
* win
, int height
, int width
, chtype attr
)
247 for (i
= 0; i
< height
; i
++) {
249 for (j
= 0; j
< width
; j
++)
255 void dialog_clear(void)
259 lines
= getmaxy(stdscr
);
260 columns
= getmaxx(stdscr
);
262 attr_clear(stdscr
, lines
, columns
, dlg
.screen
.atr
);
263 /* Display background title if it exists ... - SLH */
264 if (dlg
.backtitle
!= NULL
) {
265 int i
, len
= 0, skip
= 0;
266 struct subtitle_list
*pos
;
268 wattrset(stdscr
, dlg
.screen
.atr
);
269 mvwaddstr(stdscr
, 0, 1, (char *)dlg
.backtitle
);
271 for (pos
= dlg
.subtitles
; pos
!= NULL
; pos
= pos
->next
) {
272 /* 3 is for the arrow and spaces */
273 len
+= strlen(pos
->text
) + 3;
277 if (len
> columns
- 2) {
278 const char *ellipsis
= "[...] ";
279 waddstr(stdscr
, ellipsis
);
280 skip
= len
- (columns
- 2 - strlen(ellipsis
));
283 for (pos
= dlg
.subtitles
; pos
!= NULL
; pos
= pos
->next
) {
285 waddch(stdscr
, ACS_RARROW
);
294 if (skip
< strlen(pos
->text
)) {
295 waddstr(stdscr
, pos
->text
+ skip
);
298 skip
-= strlen(pos
->text
);
306 for (i
= len
+ 1; i
< columns
- 1; i
++)
307 waddch(stdscr
, ACS_HLINE
);
309 wnoutrefresh(stdscr
);
313 * Do some initialization for dialog
315 int init_dialog(const char *backtitle
)
319 initscr(); /* Init curses */
321 /* Get current cursor position for signal handler in mconf.c */
322 getyx(stdscr
, saved_y
, saved_x
);
324 getmaxyx(stdscr
, height
, width
);
325 if (height
< WINDOW_HEIGTH_MIN
|| width
< WINDOW_WIDTH_MIN
) {
327 return -ERRDISPLAYTOOSMALL
;
330 dlg
.backtitle
= backtitle
;
331 color_setup(getenv("MENUCONFIG_COLOR"));
333 keypad(stdscr
, TRUE
);
341 void set_dialog_backtitle(const char *backtitle
)
343 dlg
.backtitle
= backtitle
;
346 void set_dialog_subtitles(struct subtitle_list
*subtitles
)
348 dlg
.subtitles
= subtitles
;
352 * End using dialog functions.
354 void end_dialog(int x
, int y
)
356 /* move cursor back to original position */
362 /* Print the title of the dialog. Center the title and truncate
363 * tile if wider than dialog (- 2 chars).
365 void print_title(WINDOW
*dialog
, const char *title
, int width
)
368 int tlen
= MIN(width
- 2, strlen(title
));
369 wattrset(dialog
, dlg
.title
.atr
);
370 mvwaddch(dialog
, 0, (width
- tlen
) / 2 - 1, ' ');
371 mvwaddnstr(dialog
, 0, (width
- tlen
)/2, title
, tlen
);
377 * Print a string of text in a window, automatically wrap around to the
378 * next line if the string is too long to fit on one line. Newline
379 * characters '\n' are propperly processed. We start on a new line
380 * if there is no room for at least 4 nonblanks following a double-space.
382 void print_autowrap(WINDOW
* win
, const char *prompt
, int width
, int y
, int x
)
384 int newl
, cur_x
, cur_y
;
385 int prompt_len
, room
, wlen
;
386 char tempstr
[MAX_LEN
+ 1], *word
, *sp
, *sp2
, *newline_separator
= 0;
388 strcpy(tempstr
, prompt
);
390 prompt_len
= strlen(tempstr
);
392 if (prompt_len
<= width
- x
* 2) { /* If prompt is short */
393 wmove(win
, y
, (width
- prompt_len
) / 2);
394 waddstr(win
, tempstr
);
400 while (word
&& *word
) {
401 sp
= strpbrk(word
, "\n ");
402 if (sp
&& *sp
== '\n')
403 newline_separator
= sp
;
408 /* Wrap to next line if either the word does not fit,
409 or it is the first word of a new sentence, and it is
410 short, and the next word does not fit. */
411 room
= width
- cur_x
;
414 (newl
&& wlen
< 4 && sp
415 && wlen
+ 1 + strlen(sp
) > room
416 && (!(sp2
= strpbrk(sp
, "\n "))
417 || wlen
+ 1 + (sp2
- sp
) > room
))) {
421 wmove(win
, cur_y
, cur_x
);
423 getyx(win
, cur_y
, cur_x
);
425 /* Move to the next line if the word separator was a newline */
426 if (newline_separator
) {
429 newline_separator
= 0;
433 if (sp
&& *sp
== ' ') {
434 cur_x
++; /* double space */
435 while (*++sp
== ' ') ;
447 void print_button(WINDOW
* win
, const char *label
, int y
, int x
, int selected
)
452 wattrset(win
, selected
? dlg
.button_active
.atr
453 : dlg
.button_inactive
.atr
);
455 temp
= strspn(label
, " ");
457 wattrset(win
, selected
? dlg
.button_label_active
.atr
458 : dlg
.button_label_inactive
.atr
);
459 for (i
= 0; i
< temp
; i
++)
461 wattrset(win
, selected
? dlg
.button_key_active
.atr
462 : dlg
.button_key_inactive
.atr
);
463 waddch(win
, label
[0]);
464 wattrset(win
, selected
? dlg
.button_label_active
.atr
465 : dlg
.button_label_inactive
.atr
);
466 waddstr(win
, (char *)label
+ 1);
467 wattrset(win
, selected
? dlg
.button_active
.atr
468 : dlg
.button_inactive
.atr
);
470 wmove(win
, y
, x
+ temp
+ 1);
474 * Draw a rectangular box with line drawing characters
477 draw_box(WINDOW
* win
, int y
, int x
, int height
, int width
,
478 chtype box
, chtype border
)
483 for (i
= 0; i
< height
; i
++) {
484 wmove(win
, y
+ i
, x
);
485 for (j
= 0; j
< width
; j
++)
487 waddch(win
, border
| ACS_ULCORNER
);
488 else if (i
== height
- 1 && !j
)
489 waddch(win
, border
| ACS_LLCORNER
);
490 else if (!i
&& j
== width
- 1)
491 waddch(win
, box
| ACS_URCORNER
);
492 else if (i
== height
- 1 && j
== width
- 1)
493 waddch(win
, box
| ACS_LRCORNER
);
495 waddch(win
, border
| ACS_HLINE
);
496 else if (i
== height
- 1)
497 waddch(win
, box
| ACS_HLINE
);
499 waddch(win
, border
| ACS_VLINE
);
500 else if (j
== width
- 1)
501 waddch(win
, box
| ACS_VLINE
);
503 waddch(win
, box
| ' ');
508 * Draw shadows along the right and bottom edge to give a more 3D look
511 void draw_shadow(WINDOW
* win
, int y
, int x
, int height
, int width
)
515 if (has_colors()) { /* Whether terminal supports color? */
516 wattrset(win
, dlg
.shadow
.atr
);
517 wmove(win
, y
+ height
, x
+ 2);
518 for (i
= 0; i
< width
; i
++)
519 waddch(win
, winch(win
) & A_CHARTEXT
);
520 for (i
= y
+ 1; i
< y
+ height
+ 1; i
++) {
521 wmove(win
, i
, x
+ width
);
522 waddch(win
, winch(win
) & A_CHARTEXT
);
523 waddch(win
, winch(win
) & A_CHARTEXT
);
530 * Return the position of the first alphabetic character in a string.
532 int first_alpha(const char *string
, const char *exempt
)
534 int i
, in_paren
= 0, c
;
536 for (i
= 0; i
< strlen(string
); i
++) {
537 c
= tolower(string
[i
]);
539 if (strchr("<[(", c
))
541 if (strchr(">])", c
) && in_paren
> 0)
544 if ((!in_paren
) && isalpha(c
) && strchr(exempt
, c
) == 0)
552 * ncurses uses ESC to detect escaped char sequences. This resutl in
553 * a small timeout before ESC is actually delivered to the application.
554 * lxdialog suggest <ESC> <ESC> which is correctly translated to two
555 * times esc. But then we need to ignore the second esc to avoid stepping
556 * out one menu too much. Filter away all escaped key sequences since
557 * keypad(FALSE) turn off ncurses support for escape sequences - and thats
558 * needed to make notimeout() do as expected.
560 int on_key_esc(WINDOW
*win
)
572 } while (key3
!= ERR
);
575 if (key
== KEY_ESC
&& key2
== ERR
)
577 else if (key
!= ERR
&& key
!= KEY_ESC
&& key2
== ERR
)
583 /* redraw screen in new size */
584 int on_key_resize(void)
590 struct dialog_list
*item_cur
;
591 struct dialog_list item_nil
;
592 struct dialog_list
*item_head
;
594 void item_reset(void)
596 struct dialog_list
*p
, *next
;
598 for (p
= item_head
; p
; p
= next
) {
603 item_cur
= &item_nil
;
606 void item_make(const char *fmt
, ...)
609 struct dialog_list
*p
= malloc(sizeof(*p
));
616 memset(p
, 0, sizeof(*p
));
619 vsnprintf(item_cur
->node
.str
, sizeof(item_cur
->node
.str
), fmt
, ap
);
623 void item_add_str(const char *fmt
, ...)
628 avail
= sizeof(item_cur
->node
.str
) - strlen(item_cur
->node
.str
);
631 vsnprintf(item_cur
->node
.str
+ strlen(item_cur
->node
.str
),
633 item_cur
->node
.str
[sizeof(item_cur
->node
.str
) - 1] = '\0';
637 void item_set_tag(char tag
)
639 item_cur
->node
.tag
= tag
;
641 void item_set_data(void *ptr
)
643 item_cur
->node
.data
= ptr
;
646 void item_set_selected(int val
)
648 item_cur
->node
.selected
= val
;
651 int item_activate_selected(void)
654 if (item_is_selected())
659 void *item_data(void)
661 return item_cur
->node
.data
;
666 return item_cur
->node
.tag
;
672 struct dialog_list
*p
;
674 for (p
= item_head
; p
; p
= p
->next
)
690 struct dialog_list
*p
;
692 for (p
= item_head
; p
; p
= p
->next
) {
700 const char *item_str(void)
702 return item_cur
->node
.str
;
705 int item_is_selected(void)
707 return (item_cur
->node
.selected
!= 0);
710 int item_is_tag(char tag
)
712 return (item_cur
->node
.tag
== tag
);