yann@1: /* yann@1: * util.c yann@1: * yann@1: * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) yann@1: * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) yann@1: * yann@1: * This program is free software; you can redistribute it and/or yann@1: * modify it under the terms of the GNU General Public License yann@1: * as published by the Free Software Foundation; either version 2 yann@1: * of the License, or (at your option) any later version. yann@1: * yann@1: * This program is distributed in the hope that it will be useful, yann@1: * but WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@1: * GNU General Public License for more details. yann@1: * yann@1: * You should have received a copy of the GNU General Public License yann@1: * along with this program; if not, write to the Free Software yann@1: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. yann@1: */ yann@1: yann@1: #include "dialog.h" yann@1: yann@1: struct dialog_info dlg; yann@1: yann@1: static void set_mono_theme(void) yann@1: { yann@1: dlg.screen.atr = A_NORMAL; yann@1: dlg.shadow.atr = A_NORMAL; yann@1: dlg.dialog.atr = A_NORMAL; yann@1: dlg.title.atr = A_BOLD; yann@1: dlg.border.atr = A_NORMAL; yann@1: dlg.button_active.atr = A_REVERSE; yann@1: dlg.button_inactive.atr = A_DIM; yann@1: dlg.button_key_active.atr = A_REVERSE; yann@1: dlg.button_key_inactive.atr = A_BOLD; yann@1: dlg.button_label_active.atr = A_REVERSE; yann@1: dlg.button_label_inactive.atr = A_NORMAL; yann@1: dlg.inputbox.atr = A_NORMAL; yann@1: dlg.inputbox_border.atr = A_NORMAL; yann@1: dlg.searchbox.atr = A_NORMAL; yann@1: dlg.searchbox_title.atr = A_BOLD; yann@1: dlg.searchbox_border.atr = A_NORMAL; yann@1: dlg.position_indicator.atr = A_BOLD; yann@1: dlg.menubox.atr = A_NORMAL; yann@1: dlg.menubox_border.atr = A_NORMAL; yann@1: dlg.item.atr = A_NORMAL; yann@1: dlg.item_selected.atr = A_REVERSE; yann@1: dlg.tag.atr = A_BOLD; yann@1: dlg.tag_selected.atr = A_REVERSE; yann@1: dlg.tag_key.atr = A_BOLD; yann@1: dlg.tag_key_selected.atr = A_REVERSE; yann@1: dlg.check.atr = A_BOLD; yann@1: dlg.check_selected.atr = A_REVERSE; yann@1: dlg.uarrow.atr = A_BOLD; yann@1: dlg.darrow.atr = A_BOLD; yann@1: } yann@1: yann@1: #define DLG_COLOR(dialog, f, b, h) \ yann@1: do { \ yann@1: dlg.dialog.fg = (f); \ yann@1: dlg.dialog.bg = (b); \ yann@1: dlg.dialog.hl = (h); \ yann@1: } while (0) yann@1: yann@1: static void set_classic_theme(void) yann@1: { yann@1: DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true); yann@1: DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true); yann@1: DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true); yann@1: DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true); yann@1: DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true); yann@1: DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true); yann@1: DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false); yann@1: DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); yann@1: DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); yann@1: DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); yann@1: DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); yann@1: DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); yann@1: DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); yann@1: DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true); yann@1: DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true); yann@1: DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true); yann@1: DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true); yann@1: DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true); yann@1: DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false); yann@1: DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true); yann@1: DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true); yann@1: DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true); yann@1: } yann@1: yann@1: static void set_blackbg_theme(void) yann@1: { yann@1: DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); yann@1: DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); yann@1: DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); yann@1: DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); yann@1: DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); yann@1: yann@1: DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); yann@1: DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); yann@1: DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); yann@1: DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); yann@1: DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); yann@1: DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); yann@1: yann@1: DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); yann@1: DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); yann@1: yann@1: DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); yann@1: DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); yann@1: DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); yann@1: yann@1: DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); yann@1: yann@1: DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); yann@1: DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); yann@1: yann@1: DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); yann@1: DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); yann@1: yann@1: DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); yann@1: DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); yann@1: DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); yann@1: DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); yann@1: yann@1: DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); yann@1: DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); yann@1: yann@1: DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); yann@1: DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); yann@1: } yann@1: yann@1: static void set_bluetitle_theme(void) yann@1: { yann@1: set_classic_theme(); yann@1: DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); yann@1: DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); yann@1: DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); yann@1: DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); yann@1: DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); yann@1: DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); yann@1: DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); yann@1: yann@1: } yann@1: yann@1: /* yann@1: * Select color theme yann@1: */ yann@1: static int set_theme(const char *theme) yann@1: { yann@1: int use_color = 1; yann@1: if (!theme) yann@1: set_bluetitle_theme(); yann@1: else if (strcmp(theme, "classic") == 0) yann@1: set_classic_theme(); yann@1: else if (strcmp(theme, "bluetitle") == 0) yann@1: set_bluetitle_theme(); yann@1: else if (strcmp(theme, "blackbg") == 0) yann@1: set_blackbg_theme(); yann@1: else if (strcmp(theme, "mono") == 0) yann@1: use_color = 0; yann@1: yann@1: return use_color; yann@1: } yann@1: yann@1: static void init_one_color(struct dialog_color *color) yann@1: { yann@1: static int pair = 0; yann@1: yann@1: pair++; yann@1: init_pair(pair, color->fg, color->bg); yann@1: if (color->hl) yann@1: color->atr = A_BOLD | COLOR_PAIR(pair); yann@1: else yann@1: color->atr = COLOR_PAIR(pair); yann@1: } yann@1: yann@1: static void init_dialog_colors(void) yann@1: { yann@1: init_one_color(&dlg.screen); yann@1: init_one_color(&dlg.shadow); yann@1: init_one_color(&dlg.dialog); yann@1: init_one_color(&dlg.title); yann@1: init_one_color(&dlg.border); yann@1: init_one_color(&dlg.button_active); yann@1: init_one_color(&dlg.button_inactive); yann@1: init_one_color(&dlg.button_key_active); yann@1: init_one_color(&dlg.button_key_inactive); yann@1: init_one_color(&dlg.button_label_active); yann@1: init_one_color(&dlg.button_label_inactive); yann@1: init_one_color(&dlg.inputbox); yann@1: init_one_color(&dlg.inputbox_border); yann@1: init_one_color(&dlg.searchbox); yann@1: init_one_color(&dlg.searchbox_title); yann@1: init_one_color(&dlg.searchbox_border); yann@1: init_one_color(&dlg.position_indicator); yann@1: init_one_color(&dlg.menubox); yann@1: init_one_color(&dlg.menubox_border); yann@1: init_one_color(&dlg.item); yann@1: init_one_color(&dlg.item_selected); yann@1: init_one_color(&dlg.tag); yann@1: init_one_color(&dlg.tag_selected); yann@1: init_one_color(&dlg.tag_key); yann@1: init_one_color(&dlg.tag_key_selected); yann@1: init_one_color(&dlg.check); yann@1: init_one_color(&dlg.check_selected); yann@1: init_one_color(&dlg.uarrow); yann@1: init_one_color(&dlg.darrow); yann@1: } yann@1: yann@1: /* yann@1: * Setup for color display yann@1: */ yann@1: static void color_setup(const char *theme) yann@1: { yann@943: int use_color; yann@943: yann@943: use_color = set_theme(theme); yann@943: if (use_color && has_colors()) { yann@943: start_color(); yann@943: init_dialog_colors(); yann@943: } else yann@1: set_mono_theme(); yann@1: } yann@1: yann@1: /* yann@1: * Set window to attribute 'attr' yann@1: */ yann@1: void attr_clear(WINDOW * win, int height, int width, chtype attr) yann@1: { yann@1: int i, j; yann@1: yann@1: wattrset(win, attr); yann@1: for (i = 0; i < height; i++) { yann@1: wmove(win, i, 0); yann@1: for (j = 0; j < width; j++) yann@1: waddch(win, ' '); yann@1: } yann@1: touchwin(win); yann@1: } yann@1: yann@1: void dialog_clear(void) yann@1: { yann@1: attr_clear(stdscr, LINES, COLS, dlg.screen.atr); yann@1: /* Display background title if it exists ... - SLH */ yann@1: if (dlg.backtitle != NULL) { yann@1: int i; yann@1: yann@1: wattrset(stdscr, dlg.screen.atr); yann@1: mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); yann@1: wmove(stdscr, 1, 1); yann@1: for (i = 1; i < COLS - 1; i++) yann@1: waddch(stdscr, ACS_HLINE); yann@1: } yann@1: wnoutrefresh(stdscr); yann@1: } yann@1: yann@1: /* yann@1: * Do some initialization for dialog yann@1: */ yann@943: int init_dialog(const char *backtitle) yann@1: { yann@943: int height, width; yann@943: yann@943: initscr(); /* Init curses */ yann@943: getmaxyx(stdscr, height, width); yann@943: if (height < 19 || width < 80) { yann@943: endwin(); yann@943: return -ERRDISPLAYTOOSMALL; yann@943: } yann@943: yann@1: dlg.backtitle = backtitle; yann@1: color_setup(getenv("MENUCONFIG_COLOR")); yann@1: yann@1: keypad(stdscr, TRUE); yann@1: cbreak(); yann@1: noecho(); yann@1: dialog_clear(); yann@943: yann@943: return 0; yann@943: } yann@943: yann@943: void set_dialog_backtitle(const char *backtitle) yann@943: { yann@943: dlg.backtitle = backtitle; yann@1: } yann@1: yann@1: /* yann@1: * End using dialog functions. yann@1: */ yann@943: void end_dialog(int x, int y) yann@1: { yann@943: /* move cursor back to original position */ yann@943: move(y, x); yann@943: refresh(); yann@1: endwin(); yann@1: } yann@1: yann@1: /* Print the title of the dialog. Center the title and truncate yann@1: * tile if wider than dialog (- 2 chars). yann@1: **/ yann@1: void print_title(WINDOW *dialog, const char *title, int width) yann@1: { yann@1: if (title) { yann@1: int tlen = MIN(width - 2, strlen(title)); yann@1: wattrset(dialog, dlg.title.atr); yann@1: mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); yann@1: mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); yann@1: waddch(dialog, ' '); yann@1: } yann@1: } yann@1: yann@1: /* yann@1: * Print a string of text in a window, automatically wrap around to the yann@1: * next line if the string is too long to fit on one line. Newline yann@1: * characters '\n' are replaced by spaces. We start on a new line yann@1: * if there is no room for at least 4 nonblanks following a double-space. yann@1: */ yann@1: void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) yann@1: { yann@1: int newl, cur_x, cur_y; yann@1: int i, prompt_len, room, wlen; yann@1: char tempstr[MAX_LEN + 1], *word, *sp, *sp2; yann@1: yann@1: strcpy(tempstr, prompt); yann@1: yann@1: prompt_len = strlen(tempstr); yann@1: yann@1: /* yann@1: * Remove newlines yann@1: */ yann@1: for (i = 0; i < prompt_len; i++) { yann@1: if (tempstr[i] == '\n') yann@1: tempstr[i] = ' '; yann@1: } yann@1: yann@1: if (prompt_len <= width - x * 2) { /* If prompt is short */ yann@1: wmove(win, y, (width - prompt_len) / 2); yann@1: waddstr(win, tempstr); yann@1: } else { yann@1: cur_x = x; yann@1: cur_y = y; yann@1: newl = 1; yann@1: word = tempstr; yann@1: while (word && *word) { yann@943: sp = strchr(word, ' '); yann@1: if (sp) yann@1: *sp++ = 0; yann@1: yann@1: /* Wrap to next line if either the word does not fit, yann@1: or it is the first word of a new sentence, and it is yann@1: short, and the next word does not fit. */ yann@1: room = width - cur_x; yann@1: wlen = strlen(word); yann@1: if (wlen > room || yann@1: (newl && wlen < 4 && sp yann@1: && wlen + 1 + strlen(sp) > room yann@943: && (!(sp2 = strchr(sp, ' ')) yann@1: || wlen + 1 + (sp2 - sp) > room))) { yann@1: cur_y++; yann@1: cur_x = x; yann@1: } yann@1: wmove(win, cur_y, cur_x); yann@1: waddstr(win, word); yann@1: getyx(win, cur_y, cur_x); yann@1: cur_x++; yann@1: if (sp && *sp == ' ') { yann@1: cur_x++; /* double space */ yann@1: while (*++sp == ' ') ; yann@1: newl = 1; yann@1: } else yann@1: newl = 0; yann@1: word = sp; yann@1: } yann@1: } yann@1: } yann@1: yann@1: /* yann@1: * Print a button yann@1: */ yann@1: void print_button(WINDOW * win, const char *label, int y, int x, int selected) yann@1: { yann@1: int i, temp; yann@1: yann@1: wmove(win, y, x); yann@1: wattrset(win, selected ? dlg.button_active.atr yann@1: : dlg.button_inactive.atr); yann@1: waddstr(win, "<"); yann@1: temp = strspn(label, " "); yann@1: label += temp; yann@1: wattrset(win, selected ? dlg.button_label_active.atr yann@1: : dlg.button_label_inactive.atr); yann@1: for (i = 0; i < temp; i++) yann@1: waddch(win, ' '); yann@1: wattrset(win, selected ? dlg.button_key_active.atr yann@1: : dlg.button_key_inactive.atr); yann@1: waddch(win, label[0]); yann@1: wattrset(win, selected ? dlg.button_label_active.atr yann@1: : dlg.button_label_inactive.atr); yann@1: waddstr(win, (char *)label + 1); yann@1: wattrset(win, selected ? dlg.button_active.atr yann@1: : dlg.button_inactive.atr); yann@1: waddstr(win, ">"); yann@1: wmove(win, y, x + temp + 1); yann@1: } yann@1: yann@1: /* yann@1: * Draw a rectangular box with line drawing characters yann@1: */ yann@1: void yann@1: draw_box(WINDOW * win, int y, int x, int height, int width, yann@1: chtype box, chtype border) yann@1: { yann@1: int i, j; yann@1: yann@1: wattrset(win, 0); yann@1: for (i = 0; i < height; i++) { yann@1: wmove(win, y + i, x); yann@1: for (j = 0; j < width; j++) yann@1: if (!i && !j) yann@1: waddch(win, border | ACS_ULCORNER); yann@1: else if (i == height - 1 && !j) yann@1: waddch(win, border | ACS_LLCORNER); yann@1: else if (!i && j == width - 1) yann@1: waddch(win, box | ACS_URCORNER); yann@1: else if (i == height - 1 && j == width - 1) yann@1: waddch(win, box | ACS_LRCORNER); yann@1: else if (!i) yann@1: waddch(win, border | ACS_HLINE); yann@1: else if (i == height - 1) yann@1: waddch(win, box | ACS_HLINE); yann@1: else if (!j) yann@1: waddch(win, border | ACS_VLINE); yann@1: else if (j == width - 1) yann@1: waddch(win, box | ACS_VLINE); yann@1: else yann@1: waddch(win, box | ' '); yann@1: } yann@1: } yann@1: yann@1: /* yann@1: * Draw shadows along the right and bottom edge to give a more 3D look yann@1: * to the boxes yann@1: */ yann@1: void draw_shadow(WINDOW * win, int y, int x, int height, int width) yann@1: { yann@1: int i; yann@1: yann@1: if (has_colors()) { /* Whether terminal supports color? */ yann@1: wattrset(win, dlg.shadow.atr); yann@1: wmove(win, y + height, x + 2); yann@1: for (i = 0; i < width; i++) yann@1: waddch(win, winch(win) & A_CHARTEXT); yann@1: for (i = y + 1; i < y + height + 1; i++) { yann@1: wmove(win, i, x + width); yann@1: waddch(win, winch(win) & A_CHARTEXT); yann@1: waddch(win, winch(win) & A_CHARTEXT); yann@1: } yann@1: wnoutrefresh(win); yann@1: } yann@1: } yann@1: yann@1: /* yann@1: * Return the position of the first alphabetic character in a string. yann@1: */ yann@1: int first_alpha(const char *string, const char *exempt) yann@1: { yann@1: int i, in_paren = 0, c; yann@1: yann@1: for (i = 0; i < strlen(string); i++) { yann@1: c = tolower(string[i]); yann@1: yann@1: if (strchr("<[(", c)) yann@1: ++in_paren; yann@1: if (strchr(">])", c) && in_paren > 0) yann@1: --in_paren; yann@1: yann@1: if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) yann@1: return i; yann@1: } yann@1: yann@1: return 0; yann@1: } yann@1: yann@1: /* yann@1: * ncurses uses ESC to detect escaped char sequences. This resutl in yann@1: * a small timeout before ESC is actually delivered to the application. yann@1: * lxdialog suggest which is correctly translated to two yann@1: * times esc. But then we need to ignore the second esc to avoid stepping yann@1: * out one menu too much. Filter away all escaped key sequences since yann@1: * keypad(FALSE) turn off ncurses support for escape sequences - and thats yann@1: * needed to make notimeout() do as expected. yann@1: */ yann@1: int on_key_esc(WINDOW *win) yann@1: { yann@1: int key; yann@1: int key2; yann@1: int key3; yann@1: yann@1: nodelay(win, TRUE); yann@1: keypad(win, FALSE); yann@1: key = wgetch(win); yann@1: key2 = wgetch(win); yann@1: do { yann@1: key3 = wgetch(win); yann@1: } while (key3 != ERR); yann@1: nodelay(win, FALSE); yann@1: keypad(win, TRUE); yann@1: if (key == KEY_ESC && key2 == ERR) yann@1: return KEY_ESC; yann@1: else if (key != ERR && key != KEY_ESC && key2 == ERR) yann@1: ungetch(key); yann@1: yann@1: return -1; yann@1: } yann@1: yann@1: /* redraw screen in new size */ yann@1: int on_key_resize(void) yann@1: { yann@1: dialog_clear(); yann@1: return KEY_RESIZE; yann@1: } yann@1: yann@1: struct dialog_list *item_cur; yann@1: struct dialog_list item_nil; yann@1: struct dialog_list *item_head; yann@1: yann@1: void item_reset(void) yann@1: { yann@1: struct dialog_list *p, *next; yann@1: yann@1: for (p = item_head; p; p = next) { yann@1: next = p->next; yann@1: free(p); yann@1: } yann@1: item_head = NULL; yann@1: item_cur = &item_nil; yann@1: } yann@1: yann@1: void item_make(const char *fmt, ...) yann@1: { yann@1: va_list ap; yann@1: struct dialog_list *p = malloc(sizeof(*p)); yann@1: yann@1: if (item_head) yann@1: item_cur->next = p; yann@1: else yann@1: item_head = p; yann@1: item_cur = p; yann@1: memset(p, 0, sizeof(*p)); yann@1: yann@1: va_start(ap, fmt); yann@1: vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); yann@1: va_end(ap); yann@1: } yann@1: yann@1: void item_add_str(const char *fmt, ...) yann@1: { yann@1: va_list ap; yann@1: size_t avail; yann@1: yann@1: avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); yann@1: yann@1: va_start(ap, fmt); yann@1: vsnprintf(item_cur->node.str + strlen(item_cur->node.str), yann@1: avail, fmt, ap); yann@1: item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; yann@1: va_end(ap); yann@1: } yann@1: yann@1: void item_set_tag(char tag) yann@1: { yann@1: item_cur->node.tag = tag; yann@1: } yann@1: void item_set_data(void *ptr) yann@1: { yann@1: item_cur->node.data = ptr; yann@1: } yann@1: yann@1: void item_set_selected(int val) yann@1: { yann@1: item_cur->node.selected = val; yann@1: } yann@1: yann@1: int item_activate_selected(void) yann@1: { yann@1: item_foreach() yann@1: if (item_is_selected()) yann@1: return 1; yann@1: return 0; yann@1: } yann@1: yann@1: void *item_data(void) yann@1: { yann@1: return item_cur->node.data; yann@1: } yann@1: yann@1: char item_tag(void) yann@1: { yann@1: return item_cur->node.tag; yann@1: } yann@1: yann@1: int item_count(void) yann@1: { yann@1: int n = 0; yann@1: struct dialog_list *p; yann@1: yann@1: for (p = item_head; p; p = p->next) yann@1: n++; yann@1: return n; yann@1: } yann@1: yann@1: void item_set(int n) yann@1: { yann@1: int i = 0; yann@1: item_foreach() yann@1: if (i++ == n) yann@1: return; yann@1: } yann@1: yann@1: int item_n(void) yann@1: { yann@1: int n = 0; yann@1: struct dialog_list *p; yann@1: yann@1: for (p = item_head; p; p = p->next) { yann@1: if (p == item_cur) yann@1: return n; yann@1: n++; yann@1: } yann@1: return 0; yann@1: } yann@1: yann@1: const char *item_str(void) yann@1: { yann@1: return item_cur->node.str; yann@1: } yann@1: yann@1: int item_is_selected(void) yann@1: { yann@1: return (item_cur->node.selected != 0); yann@1: } yann@1: yann@1: int item_is_tag(char tag) yann@1: { yann@1: return (item_cur->node.tag == tag); yann@1: }