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