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 set_blackbg_theme(void) 100 { 101 DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); 102 DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); 103 DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); 104 DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); 105 DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); 106 107 DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); 108 DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); 109 DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); 110 DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); 111 DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); 112 DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); 113 114 DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); 115 DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); 116 117 DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); 118 DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); 119 DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); 120 121 DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); 122 123 DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); 124 DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); 125 126 DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); 127 DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); 128 129 DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); 130 DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); 131 DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); 132 DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); 133 134 DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); 135 DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); 136 137 DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); 138 DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); 139 } 140 141 /* 142 * Select color theme 143 */ 144 static int set_theme(const char *theme) 145 { 146 int use_color = 1; 147 if (!theme) 148 set_classic_theme(); 149 else if (strcmp(theme, "classic") == 0) 150 set_classic_theme(); 151 else if (strcmp(theme, "blackbg") == 0) 152 set_blackbg_theme(); 153 else if (strcmp(theme, "mono") == 0) 154 use_color = 0; 155 156 return use_color; 157 } 158 159 static void init_one_color(struct dialog_color *color) 160 { 161 static int pair = 0; 162 163 pair++; 164 init_pair(pair, color->fg, color->bg); 165 if (color->hl) 166 color->atr = A_BOLD | COLOR_PAIR(pair); 167 else 168 color->atr = COLOR_PAIR(pair); 169 } 170 171 static void init_dialog_colors(void) 172 { 173 init_one_color(&dlg.screen); 174 init_one_color(&dlg.shadow); 175 init_one_color(&dlg.dialog); 176 init_one_color(&dlg.title); 177 init_one_color(&dlg.border); 178 init_one_color(&dlg.button_active); 179 init_one_color(&dlg.button_inactive); 180 init_one_color(&dlg.button_key_active); 181 init_one_color(&dlg.button_key_inactive); 182 init_one_color(&dlg.button_label_active); 183 init_one_color(&dlg.button_label_inactive); 184 init_one_color(&dlg.inputbox); 185 init_one_color(&dlg.inputbox_border); 186 init_one_color(&dlg.searchbox); 187 init_one_color(&dlg.searchbox_title); 188 init_one_color(&dlg.searchbox_border); 189 init_one_color(&dlg.position_indicator); 190 init_one_color(&dlg.menubox); 191 init_one_color(&dlg.menubox_border); 192 init_one_color(&dlg.item); 193 init_one_color(&dlg.item_selected); 194 init_one_color(&dlg.tag); 195 init_one_color(&dlg.tag_selected); 196 init_one_color(&dlg.tag_key); 197 init_one_color(&dlg.tag_key_selected); 198 init_one_color(&dlg.check); 199 init_one_color(&dlg.check_selected); 200 init_one_color(&dlg.uarrow); 201 init_one_color(&dlg.darrow); 202 } 203 204 /* 205 * Setup for color display 206 */ 207 static void color_setup(const char *theme) 208 { 209 if (set_theme(theme)) { 210 if (has_colors()) { /* Terminal supports color? */ 211 start_color(); 212 init_dialog_colors(); 213 } 214 } 215 else 216 { 217 set_mono_theme(); 218 } 219 } 220 221 /* 222 * Set window to attribute 'attr' 223 */ 224 void attr_clear(WINDOW * win, int height, int width, chtype attr) 225 { 226 int i, j; 227 228 wattrset(win, attr); 229 for (i = 0; i < height; i++) { 230 wmove(win, i, 0); 231 for (j = 0; j < width; j++) 232 waddch(win, ' '); 233 } 234 touchwin(win); 235 } 236 237 void dialog_clear(void) 238 { 239 attr_clear(stdscr, LINES, COLS, dlg.screen.atr); 240 /* Display background title if it exists ... - SLH */ 241 if (dlg.backtitle != NULL) { 242 int i; 243 244 wattrset(stdscr, dlg.screen.atr); 245 mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); 246 wmove(stdscr, 1, 1); 247 for (i = 1; i < COLS - 1; i++) 248 waddch(stdscr, ACS_HLINE); 249 } 250 wnoutrefresh(stdscr); 251 } 252 253 /* 254 * Do some initialization for dialog 255 */ 256 void init_dialog(void) 257 { 258 initscr(); /* Init curses */ 259 keypad(stdscr, TRUE); 260 cbreak(); 261 noecho(); 262 color_setup(getenv("MENUCONFIG_COLOR")); 263 dialog_clear(); 264 } 265 266 /* 267 * End using dialog functions. 268 */ 269 void end_dialog(void) 270 { 271 endwin(); 272 } 273 274 /* Print the title of the dialog. Center the title and truncate 275 * tile if wider than dialog (- 2 chars). 276 **/ 277 void print_title(WINDOW *dialog, const char *title, int width) 278 { 279 if (title) { 280 int tlen = MIN(width - 2, strlen(title)); 281 wattrset(dialog, dlg.title.atr); 282 mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); 283 mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); 284 waddch(dialog, ' '); 285 } 286 } 287 288 /* 289 * Print a string of text in a window, automatically wrap around to the 290 * next line if the string is too long to fit on one line. Newline 291 * characters '\n' are replaced by spaces. We start on a new line 292 * if there is no room for at least 4 nonblanks following a double-space. 293 */ 294 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) 295 { 296 int newl, cur_x, cur_y; 297 int i, prompt_len, room, wlen; 298 char tempstr[MAX_LEN + 1], *word, *sp, *sp2; 299 300 strcpy(tempstr, prompt); 301 302 prompt_len = strlen(tempstr); 303 304 /* 305 * Remove newlines 306 */ 307 for (i = 0; i < prompt_len; i++) { 308 if (tempstr[i] == '\n') 309 tempstr[i] = ' '; 310 } 311 312 if (prompt_len <= width - x * 2) { /* If prompt is short */ 313 wmove(win, y, (width - prompt_len) / 2); 314 waddstr(win, tempstr); 315 } else { 316 cur_x = x; 317 cur_y = y; 318 newl = 1; 319 word = tempstr; 320 while (word && *word) { 321 sp = index(word, ' '); 322 if (sp) 323 *sp++ = 0; 324 325 /* Wrap to next line if either the word does not fit, 326 or it is the first word of a new sentence, and it is 327 short, and the next word does not fit. */ 328 room = width - cur_x; 329 wlen = strlen(word); 330 if (wlen > room || 331 (newl && wlen < 4 && sp 332 && wlen + 1 + strlen(sp) > room 333 && (!(sp2 = index(sp, ' ')) 334 || wlen + 1 + (sp2 - sp) > room))) { 335 cur_y++; 336 cur_x = x; 337 } 338 wmove(win, cur_y, cur_x); 339 waddstr(win, word); 340 getyx(win, cur_y, cur_x); 341 cur_x++; 342 if (sp && *sp == ' ') { 343 cur_x++; /* double space */ 344 while (*++sp == ' ') ; 345 newl = 1; 346 } else 347 newl = 0; 348 word = sp; 349 } 350 } 351 } 352 353 /* 354 * Print a button 355 */ 356 void print_button(WINDOW * win, const char *label, int y, int x, int selected) 357 { 358 int i, temp; 359 360 wmove(win, y, x); 361 wattrset(win, selected ? dlg.button_active.atr 362 : dlg.button_inactive.atr); 363 waddstr(win, "<"); 364 temp = strspn(label, " "); 365 label += temp; 366 wattrset(win, selected ? dlg.button_label_active.atr 367 : dlg.button_label_inactive.atr); 368 for (i = 0; i < temp; i++) 369 waddch(win, ' '); 370 wattrset(win, selected ? dlg.button_key_active.atr 371 : dlg.button_key_inactive.atr); 372 waddch(win, label[0]); 373 wattrset(win, selected ? dlg.button_label_active.atr 374 : dlg.button_label_inactive.atr); 375 waddstr(win, (char *)label + 1); 376 wattrset(win, selected ? dlg.button_active.atr 377 : dlg.button_inactive.atr); 378 waddstr(win, ">"); 379 wmove(win, y, x + temp + 1); 380 } 381 382 /* 383 * Draw a rectangular box with line drawing characters 384 */ 385 void 386 draw_box(WINDOW * win, int y, int x, int height, int width, 387 chtype box, chtype border) 388 { 389 int i, j; 390 391 wattrset(win, 0); 392 for (i = 0; i < height; i++) { 393 wmove(win, y + i, x); 394 for (j = 0; j < width; j++) 395 if (!i && !j) 396 waddch(win, border | ACS_ULCORNER); 397 else if (i == height - 1 && !j) 398 waddch(win, border | ACS_LLCORNER); 399 else if (!i && j == width - 1) 400 waddch(win, box | ACS_URCORNER); 401 else if (i == height - 1 && j == width - 1) 402 waddch(win, box | ACS_LRCORNER); 403 else if (!i) 404 waddch(win, border | ACS_HLINE); 405 else if (i == height - 1) 406 waddch(win, box | ACS_HLINE); 407 else if (!j) 408 waddch(win, border | ACS_VLINE); 409 else if (j == width - 1) 410 waddch(win, box | ACS_VLINE); 411 else 412 waddch(win, box | ' '); 413 } 414 } 415 416 /* 417 * Draw shadows along the right and bottom edge to give a more 3D look 418 * to the boxes 419 */ 420 void draw_shadow(WINDOW * win, int y, int x, int height, int width) 421 { 422 int i; 423 424 if (has_colors()) { /* Whether terminal supports color? */ 425 wattrset(win, dlg.shadow.atr); 426 wmove(win, y + height, x + 2); 427 for (i = 0; i < width; i++) 428 waddch(win, winch(win) & A_CHARTEXT); 429 for (i = y + 1; i < y + height + 1; i++) { 430 wmove(win, i, x + width); 431 waddch(win, winch(win) & A_CHARTEXT); 432 waddch(win, winch(win) & A_CHARTEXT); 433 } 434 wnoutrefresh(win); 435 } 436 } 437 438 /* 439 * Return the position of the first alphabetic character in a string. 440 */ 441 int first_alpha(const char *string, const char *exempt) 442 { 443 int i, in_paren = 0, c; 444 445 for (i = 0; i < strlen(string); i++) { 446 c = tolower(string[i]); 447 448 if (strchr("<[(", c)) 449 ++in_paren; 450 if (strchr(">])", c) && in_paren > 0) 451 --in_paren; 452 453 if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) 454 return i; 455 } 456 457 return 0; 458 } 459