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 <stdarg.h> 23 24 #include "dialog.h" 25 26 /* Needed in signal handler in mconf.c */ 27 int saved_x, saved_y; 28 29 struct dialog_info dlg; 30 31 static void set_mono_theme(void) 32 { 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; 54 dlg.tag.atr = A_BOLD; 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; 62 } 63 64 #define DLG_COLOR(dialog, f, b, h) \ 65 do { \ 66 dlg.dialog.fg = (f); \ 67 dlg.dialog.bg = (b); \ 68 dlg.dialog.hl = (h); \ 69 } while (0) 70 71 static void set_classic_theme(void) 72 { 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); 102 } 103 104 static void set_blackbg_theme(void) 105 { 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); 111 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); 118 119 DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); 120 DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); 121 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); 125 126 DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); 127 128 DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); 129 DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); 130 131 DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); 132 DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); 133 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); 138 139 DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); 140 DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); 141 142 DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); 143 DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); 144 } 145 146 static void set_bluetitle_theme(void) 147 { 148 set_classic_theme(); 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); 156 157 } 158 159 /* 160 * Select color theme 161 */ 162 static int set_theme(const char *theme) 163 { 164 int use_color = 1; 165 if (!theme) 166 set_bluetitle_theme(); 167 else if (strcmp(theme, "classic") == 0) 168 set_classic_theme(); 169 else if (strcmp(theme, "bluetitle") == 0) 170 set_bluetitle_theme(); 171 else if (strcmp(theme, "blackbg") == 0) 172 set_blackbg_theme(); 173 else if (strcmp(theme, "mono") == 0) 174 use_color = 0; 175 176 return use_color; 177 } 178 179 static void init_one_color(struct dialog_color *color) 180 { 181 static int pair = 0; 182 183 pair++; 184 init_pair(pair, color->fg, color->bg); 185 if (color->hl) 186 color->atr = A_BOLD | COLOR_PAIR(pair); 187 else 188 color->atr = COLOR_PAIR(pair); 189 } 190 191 static void init_dialog_colors(void) 192 { 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); 222 } 223 224 /* 225 * Setup for color display 226 */ 227 static void color_setup(const char *theme) 228 { 229 int use_color; 230 231 use_color = set_theme(theme); 232 if (use_color && has_colors()) { 233 start_color(); 234 init_dialog_colors(); 235 } else 236 set_mono_theme(); 237 } 238 239 /* 240 * Set window to attribute 'attr' 241 */ 242 void attr_clear(WINDOW * win, int height, int width, chtype attr) 243 { 244 int i, j; 245 246 wattrset(win, attr); 247 for (i = 0; i < height; i++) { 248 wmove(win, i, 0); 249 for (j = 0; j < width; j++) 250 waddch(win, ' '); 251 } 252 touchwin(win); 253 } 254 255 void dialog_clear(void) 256 { 257 int lines, columns; 258 259 lines = getmaxy(stdscr); 260 columns = getmaxx(stdscr); 261 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; 267 268 wattrset(stdscr, dlg.screen.atr); 269 mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); 270 271 for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { 272 /* 3 is for the arrow and spaces */ 273 len += strlen(pos->text) + 3; 274 } 275 276 wmove(stdscr, 1, 1); 277 if (len > columns - 2) { 278 const char *ellipsis = "[...] "; 279 waddstr(stdscr, ellipsis); 280 skip = len - (columns - 2 - strlen(ellipsis)); 281 } 282 283 for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { 284 if (skip == 0) 285 waddch(stdscr, ACS_RARROW); 286 else 287 skip--; 288 289 if (skip == 0) 290 waddch(stdscr, ' '); 291 else 292 skip--; 293 294 if (skip < strlen(pos->text)) { 295 waddstr(stdscr, pos->text + skip); 296 skip = 0; 297 } else 298 skip -= strlen(pos->text); 299 300 if (skip == 0) 301 waddch(stdscr, ' '); 302 else 303 skip--; 304 } 305 306 for (i = len + 1; i < columns - 1; i++) 307 waddch(stdscr, ACS_HLINE); 308 } 309 wnoutrefresh(stdscr); 310 } 311 312 /* 313 * Do some initialization for dialog 314 */ 315 int init_dialog(const char *backtitle) 316 { 317 int height, width; 318 319 initscr(); /* Init curses */ 320 321 /* Get current cursor position for signal handler in mconf.c */ 322 getyx(stdscr, saved_y, saved_x); 323 324 getmaxyx(stdscr, height, width); 325 if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { 326 endwin(); 327 return -ERRDISPLAYTOOSMALL; 328 } 329 330 dlg.backtitle = backtitle; 331 color_setup(getenv("MENUCONFIG_COLOR")); 332 333 keypad(stdscr, TRUE); 334 cbreak(); 335 noecho(); 336 dialog_clear(); 337 338 return 0; 339 } 340 341 void set_dialog_backtitle(const char *backtitle) 342 { 343 dlg.backtitle = backtitle; 344 } 345 346 void set_dialog_subtitles(struct subtitle_list *subtitles) 347 { 348 dlg.subtitles = subtitles; 349 } 350 351 /* 352 * End using dialog functions. 353 */ 354 void end_dialog(int x, int y) 355 { 356 /* move cursor back to original position */ 357 move(y, x); 358 refresh(); 359 endwin(); 360 } 361 362 /* Print the title of the dialog. Center the title and truncate 363 * tile if wider than dialog (- 2 chars). 364 **/ 365 void print_title(WINDOW *dialog, const char *title, int width) 366 { 367 if (title) { 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); 372 waddch(dialog, ' '); 373 } 374 } 375 376 /* 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. 381 */ 382 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) 383 { 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; 387 388 strcpy(tempstr, prompt); 389 390 prompt_len = strlen(tempstr); 391 392 if (prompt_len <= width - x * 2) { /* If prompt is short */ 393 wmove(win, y, (width - prompt_len) / 2); 394 waddstr(win, tempstr); 395 } else { 396 cur_x = x; 397 cur_y = y; 398 newl = 1; 399 word = tempstr; 400 while (word && *word) { 401 sp = strpbrk(word, "\n "); 402 if (sp && *sp == '\n') 403 newline_separator = sp; 404 405 if (sp) 406 *sp++ = 0; 407 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; 412 wlen = strlen(word); 413 if (wlen > room || 414 (newl && wlen < 4 && sp 415 && wlen + 1 + strlen(sp) > room 416 && (!(sp2 = strpbrk(sp, "\n ")) 417 || wlen + 1 + (sp2 - sp) > room))) { 418 cur_y++; 419 cur_x = x; 420 } 421 wmove(win, cur_y, cur_x); 422 waddstr(win, word); 423 getyx(win, cur_y, cur_x); 424 425 /* Move to the next line if the word separator was a newline */ 426 if (newline_separator) { 427 cur_y++; 428 cur_x = x; 429 newline_separator = 0; 430 } else 431 cur_x++; 432 433 if (sp && *sp == ' ') { 434 cur_x++; /* double space */ 435 while (*++sp == ' ') ; 436 newl = 1; 437 } else 438 newl = 0; 439 word = sp; 440 } 441 } 442 } 443 444 /* 445 * Print a button 446 */ 447 void print_button(WINDOW * win, const char *label, int y, int x, int selected) 448 { 449 int i, temp; 450 451 wmove(win, y, x); 452 wattrset(win, selected ? dlg.button_active.atr 453 : dlg.button_inactive.atr); 454 waddstr(win, "<"); 455 temp = strspn(label, " "); 456 label += temp; 457 wattrset(win, selected ? dlg.button_label_active.atr 458 : dlg.button_label_inactive.atr); 459 for (i = 0; i < temp; i++) 460 waddch(win, ' '); 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); 469 waddstr(win, ">"); 470 wmove(win, y, x + temp + 1); 471 } 472 473 /* 474 * Draw a rectangular box with line drawing characters 475 */ 476 void 477 draw_box(WINDOW * win, int y, int x, int height, int width, 478 chtype box, chtype border) 479 { 480 int i, j; 481 482 wattrset(win, 0); 483 for (i = 0; i < height; i++) { 484 wmove(win, y + i, x); 485 for (j = 0; j < width; j++) 486 if (!i && !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); 494 else if (!i) 495 waddch(win, border | ACS_HLINE); 496 else if (i == height - 1) 497 waddch(win, box | ACS_HLINE); 498 else if (!j) 499 waddch(win, border | ACS_VLINE); 500 else if (j == width - 1) 501 waddch(win, box | ACS_VLINE); 502 else 503 waddch(win, box | ' '); 504 } 505 } 506 507 /* 508 * Draw shadows along the right and bottom edge to give a more 3D look 509 * to the boxes 510 */ 511 void draw_shadow(WINDOW * win, int y, int x, int height, int width) 512 { 513 int i; 514 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); 524 } 525 wnoutrefresh(win); 526 } 527 } 528 529 /* 530 * Return the position of the first alphabetic character in a string. 531 */ 532 int first_alpha(const char *string, const char *exempt) 533 { 534 int i, in_paren = 0, c; 535 536 for (i = 0; i < strlen(string); i++) { 537 c = tolower(string[i]); 538 539 if (strchr("<[(", c)) 540 ++in_paren; 541 if (strchr(">])", c) && in_paren > 0) 542 --in_paren; 543 544 if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) 545 return i; 546 } 547 548 return 0; 549 } 550 551 /* 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. 559 */ 560 int on_key_esc(WINDOW *win) 561 { 562 int key; 563 int key2; 564 int key3; 565 566 nodelay(win, TRUE); 567 keypad(win, FALSE); 568 key = wgetch(win); 569 key2 = wgetch(win); 570 do { 571 key3 = wgetch(win); 572 } while (key3 != ERR); 573 nodelay(win, FALSE); 574 keypad(win, TRUE); 575 if (key == KEY_ESC && key2 == ERR) 576 return KEY_ESC; 577 else if (key != ERR && key != KEY_ESC && key2 == ERR) 578 ungetch(key); 579 580 return -1; 581 } 582 583 /* redraw screen in new size */ 584 int on_key_resize(void) 585 { 586 dialog_clear(); 587 return KEY_RESIZE; 588 } 589 590 struct dialog_list *item_cur; 591 struct dialog_list item_nil; 592 struct dialog_list *item_head; 593 594 void item_reset(void) 595 { 596 struct dialog_list *p, *next; 597 598 for (p = item_head; p; p = next) { 599 next = p->next; 600 free(p); 601 } 602 item_head = NULL; 603 item_cur = &item_nil; 604 } 605 606 void item_make(const char *fmt, ...) 607 { 608 va_list ap; 609 struct dialog_list *p = malloc(sizeof(*p)); 610 611 if (item_head) 612 item_cur->next = p; 613 else 614 item_head = p; 615 item_cur = p; 616 memset(p, 0, sizeof(*p)); 617 618 va_start(ap, fmt); 619 vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); 620 va_end(ap); 621 } 622 623 void item_add_str(const char *fmt, ...) 624 { 625 va_list ap; 626 size_t avail; 627 628 avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); 629 630 va_start(ap, fmt); 631 vsnprintf(item_cur->node.str + strlen(item_cur->node.str), 632 avail, fmt, ap); 633 item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; 634 va_end(ap); 635 } 636 637 void item_set_tag(char tag) 638 { 639 item_cur->node.tag = tag; 640 } 641 void item_set_data(void *ptr) 642 { 643 item_cur->node.data = ptr; 644 } 645 646 void item_set_selected(int val) 647 { 648 item_cur->node.selected = val; 649 } 650 651 int item_activate_selected(void) 652 { 653 item_foreach() 654 if (item_is_selected()) 655 return 1; 656 return 0; 657 } 658 659 void *item_data(void) 660 { 661 return item_cur->node.data; 662 } 663 664 char item_tag(void) 665 { 666 return item_cur->node.tag; 667 } 668 669 int item_count(void) 670 { 671 int n = 0; 672 struct dialog_list *p; 673 674 for (p = item_head; p; p = p->next) 675 n++; 676 return n; 677 } 678 679 void item_set(int n) 680 { 681 int i = 0; 682 item_foreach() 683 if (i++ == n) 684 return; 685 } 686 687 int item_n(void) 688 { 689 int n = 0; 690 struct dialog_list *p; 691 692 for (p = item_head; p; p = p->next) { 693 if (p == item_cur) 694 return n; 695 n++; 696 } 697 return 0; 698 } 699 700 const char *item_str(void) 701 { 702 return item_cur->node.str; 703 } 704 705 int item_is_selected(void) 706 { 707 return (item_cur->node.selected != 0); 708 } 709 710 int item_is_tag(char tag) 711 { 712 return (item_cur->node.tag == tag); 713 } 714