diff options
Diffstat (limited to 'contrib/dialog/menubox.c')
-rw-r--r-- | contrib/dialog/menubox.c | 465 |
1 files changed, 213 insertions, 252 deletions
diff --git a/contrib/dialog/menubox.c b/contrib/dialog/menubox.c index 25005a4..3117443 100644 --- a/contrib/dialog/menubox.c +++ b/contrib/dialog/menubox.c @@ -1,9 +1,9 @@ /* - * $Id: menubox.c,v 1.122 2011/06/29 09:48:46 tom Exp $ + * $Id: menubox.c,v 1.145 2012/12/30 21:11:02 tom Exp $ * * menubox.c -- implements the menu box * - * Copyright 2000-2010,2011 Thomas E. Dickey + * Copyright 2000-2011,2012 Thomas E. Dickey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public Licens, version 2.1e @@ -27,141 +27,97 @@ #include <dialog.h> #include <dlg_keys.h> -static int menu_width, tag_x, item_x; - typedef enum { Unselected = 0, Selected, Editing } Mode; +typedef struct { + /* the outer-window */ + WINDOW *dialog; + int box_y; + int box_x; + int tag_x; + int item_x; + int menu_height; + int menu_width; + /* the inner-window */ + WINDOW *menu; + DIALOG_LISTITEM *items; + int item_no; +} ALL_DATA; + #define MIN_HIGH (1 + (5 * MARGIN)) #define INPUT_ROWS 3 /* rows per inputmenu entry */ -#define LLEN(n) ((n) * MENUBOX_TAGS) -#define ItemName(i) items[LLEN(i)] -#define ItemText(i) items[LLEN(i) + 1] -#define ItemHelp(i) items[LLEN(i) + 2] - #define RowHeight(i) (is_inputmenu ? ((i) * INPUT_ROWS) : ((i) * 1)) #define ItemToRow(i) (is_inputmenu ? ((i) * INPUT_ROWS + 1) : (i)) #define RowToItem(i) (is_inputmenu ? ((i) / INPUT_ROWS + 0) : (i)) -static void -print_arrows(WINDOW *win, - int box_x, - int box_y, - int scrollamt, - int max_choice, - int item_no, - int menu_height) -{ - dlg_draw_scrollbar(win, - scrollamt, - scrollamt, - scrollamt + max_choice, - item_no, - box_x, - box_x + menu_width, - box_y, - box_y + menu_height + 1, - menubox_attr, - menubox_border_attr); -} - -/* - * Print the tag of a menu-item - */ -static void -print_tag(WINDOW *win, - DIALOG_LISTITEM * item, - int choice, - Mode selected, - bool is_inputmenu) -{ - int my_x = item_x; - int my_y = ItemToRow(choice); - int tag_width = (my_x - tag_x - GUTTER); - const int *cols; - const int *indx; - int limit; - int prefix; - - cols = dlg_index_columns(item->name); - indx = dlg_index_wchars(item->name); - limit = dlg_count_wchars(item->name); - prefix = (indx[1] - indx[0]); - - /* highlight first char of the tag to be special */ - (void) wmove(win, my_y, tag_x); - wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); - if (strlen(item->name) != 0) - (void) waddnstr(win, item->name, prefix); - /* print rest of the string */ - wattrset(win, selected ? tag_selected_attr : tag_attr); - if ((int) strlen(item->name) > prefix) { - limit = dlg_limit_columns(item->name, tag_width, 1); - if (limit > 0) - (void) waddnstr(win, item->name + indx[1], indx[limit] - indx[1]); - } -} - /* * Print menu item */ static void -print_item(WINDOW *win, - DIALOG_LISTITEM * items, +print_item(ALL_DATA * data, + WINDOW *win, + DIALOG_LISTITEM * item, int choice, Mode selected, bool is_inputmenu) { chtype save = dlg_get_attrs(win); int n; - int my_width = menu_width; - int my_x = item_x; + int climit = (data->item_x - data->tag_x - GUTTER); + int my_width = data->menu_width; + int my_x = data->item_x; int my_y = ItemToRow(choice); - chtype attr = A_NORMAL; - chtype textchar; + bool both = (!dialog_vars.no_tags && !dialog_vars.no_items); + bool first = TRUE; chtype bordchar; + const char *show = (dialog_vars.no_items + ? item->name + : item->text); switch (selected) { default: case Unselected: - textchar = item_attr; bordchar = item_attr; break; case Selected: - textchar = item_selected_attr; bordchar = item_selected_attr; break; case Editing: - textchar = inputbox_attr; bordchar = dialog_attr; break; } /* Clear 'residue' of last item and mark current current item */ if (is_inputmenu) { - wattrset(win, (selected != Unselected) ? item_selected_attr : item_attr); + (void) wattrset(win, (selected != Unselected) ? item_selected_attr : item_attr); for (n = my_y - 1; n < my_y + INPUT_ROWS - 1; n++) { wmove(win, n, 0); wprintw(win, "%*s", my_width, " "); } } else { - wattrset(win, menubox_attr); + (void) wattrset(win, menubox_attr); wmove(win, my_y, 0); wprintw(win, "%*s", my_width, " "); } - print_tag(win, items, choice, selected, is_inputmenu); + /* highlight first char of the tag to be special */ + if (both) { + (void) wmove(win, my_y, data->tag_x); + dlg_print_listitem(win, item->name, climit, first, selected); + first = FALSE; + } /* Draw the input field box (only for inputmenu) */ (void) wmove(win, my_y, my_x); if (is_inputmenu) { my_width -= 1; - dlg_draw_box(win, my_y - 1, my_x, INPUT_ROWS, my_width - my_x - tag_x, + dlg_draw_box(win, my_y - 1, my_x, INPUT_ROWS, my_width - my_x - data->tag_x, bordchar, bordchar); my_width -= 1; @@ -170,25 +126,24 @@ print_item(WINDOW *win, /* print actual item */ wmove(win, my_y, my_x); - wattrset(win, textchar); - dlg_print_text(win, items->text, my_width - my_x, &attr); + dlg_print_listitem(win, show, my_width - my_x, first, selected); if (selected) { - dlg_item_help(items->help); + dlg_item_help(item->help); } - wattrset(win, save); + (void) wattrset(win, save); } /* * Allow the user to edit the text of a menu entry. */ static int -input_menu_edit(WINDOW *win, +input_menu_edit(ALL_DATA * data, DIALOG_LISTITEM * items, int choice, char **resultp) { - chtype save = dlg_get_attrs(win); + chtype save = dlg_get_attrs(data->menu); char *result; int offset = 0; int key = 0, fkey = 0; @@ -206,15 +161,17 @@ input_menu_edit(WINDOW *win, result[0] = '\0'; strcpy(result, items->text); - print_item(win, items, choice, Editing, TRUE); + print_item(data, data->menu, items, choice, Editing, TRUE); /* taken out of inputbox.c - but somewhat modified */ for (;;) { if (!first) - key = dlg_mouse_wgetch(win, &fkey); + key = dlg_mouse_wgetch(data->menu, &fkey); if (dlg_edit_string(result, &offset, key, fkey, first)) { - dlg_show_string(win, result, offset, inputbox_attr, - y, item_x + 1, menu_width - item_x - 3, + dlg_show_string(data->menu, result, offset, inputbox_attr, + y, + data->item_x + 1, + data->menu_width - data->item_x - 3, FALSE, first); first = FALSE; } else if (key == ESC || key == TAB) { @@ -224,8 +181,8 @@ input_menu_edit(WINDOW *win, break; } } - print_item(win, items, choice, Selected, TRUE); - wattrset(win, save); + print_item(data, data->menu, items, choice, Selected, TRUE); + (void) wattrset(data->menu, save); *resultp = result; return code; @@ -252,7 +209,7 @@ handle_button(int code, DIALOG_LISTITEM * items, int choice) return code; } -static int +int dlg_renamed_menutext(DIALOG_LISTITEM * items, int current, char *newtext) { if (dialog_vars.input_result) @@ -264,7 +221,7 @@ dlg_renamed_menutext(DIALOG_LISTITEM * items, int current, char *newtext) return DLG_EXIT_EXTRA; } -static int +int dlg_dummy_menutext(DIALOG_LISTITEM * items, int current, char *newtext) { (void) items; @@ -273,6 +230,63 @@ dlg_dummy_menutext(DIALOG_LISTITEM * items, int current, char *newtext) return DLG_EXIT_ERROR; } +static void +print_menu(ALL_DATA * data, int choice, int scrollamt, int max_choice, bool is_inputmenu) +{ + int i; + + for (i = 0; i < max_choice; i++) { + print_item(data, + data->menu, + &data->items[i + scrollamt], + i, + (i == choice) ? Selected : Unselected, + is_inputmenu); + } + + /* Clean bottom lines */ + if (is_inputmenu) { + int spare_lines, x_count; + spare_lines = data->menu_height % INPUT_ROWS; + (void) wattrset(data->menu, menubox_attr); + for (; spare_lines; spare_lines--) { + wmove(data->menu, data->menu_height - spare_lines, 0); + for (x_count = 0; x_count < data->menu_width; + x_count++) { + waddch(data->menu, ' '); + } + } + } + + (void) wnoutrefresh(data->menu); + + dlg_draw_scrollbar(data->dialog, + scrollamt, + scrollamt, + scrollamt + max_choice, + data->item_no, + data->box_x, + data->box_x + data->menu_width, + data->box_y, + data->box_y + data->menu_height + 1, + menubox_border2_attr, + menubox_border_attr); +} + +static bool +check_hotkey(DIALOG_LISTITEM * items, int choice) +{ + bool result = FALSE; + + if (dlg_match_char(dlg_last_getc(), + (dialog_vars.no_tags + ? items[choice].text + : items[choice].name))) { + result = TRUE; + } + return result; +} + /* * This is an alternate interface to 'menu' which allows the application * to read the list item states back directly without putting them in the @@ -323,19 +337,24 @@ dlg_menu(const char *title, int old_height = height; int old_width = width; #endif - int i, j, x, y, cur_x, cur_y, box_x, box_y; + ALL_DATA all; + int i, j, x, y, cur_x, cur_y; int key = 0, fkey; - int button = dialog_state.visit_items ? -1 : dlg_defaultno_button(); + int button = dialog_state.visit_items ? -1 : dlg_default_button(); int choice = dlg_default_listitem(items); int result = DLG_EXIT_UNKNOWN; int scrollamt = 0; - int max_choice, min_width; + int max_choice; int found; - int use_height, use_width, name_width, text_width; + int use_width, name_width, text_width, list_width; WINDOW *dialog, *menu; char *prompt = dlg_strclone(cprompt); const char **buttons = dlg_ok_labels(); - bool is_inputmenu = (rename_menutext == dlg_renamed_menutext); + bool is_inputmenu = ((rename_menutext != 0) + && (rename_menutext != dlg_dummy_menutext)); + + all.items = items; + all.item_no = item_no; dlg_does_output(); dlg_tab_correct_str(prompt); @@ -344,14 +363,17 @@ dlg_menu(const char *title, retry: #endif - use_height = menu_height; - if (use_height == 0) { - min_width = dlg_calc_list_width(item_no, items) + 10; + all.menu_height = menu_height; + use_width = dlg_calc_list_width(item_no, items) + 10; + use_width = MAX(26, use_width); + if (all.menu_height == 0) { /* calculate height without items (4) */ - dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, MAX(26, min_width)); - dlg_calc_listh(&height, &use_height, item_no); + dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); + dlg_calc_listh(&height, &all.menu_height, item_no); } else { - dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, 26); + dlg_auto_size(title, prompt, + &height, &width, + MIN_HIGH + all.menu_height, use_width); } dlg_button_layout(buttons, &width); dlg_print_size(height, width); @@ -361,48 +383,54 @@ dlg_menu(const char *title, y = dlg_box_y_ordinate(height); dialog = dlg_new_window(height, width, y, x); + all.dialog = dialog; + dlg_register_window(dialog, "menubox", binding); dlg_register_buttons(dialog, "menubox", buttons); dlg_mouse_setbase(x, y); - dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); - dlg_draw_bottom_box(dialog); + dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); + dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); dlg_draw_title(dialog, title); - wattrset(dialog, dialog_attr); + (void) wattrset(dialog, dialog_attr); dlg_print_autowrap(dialog, prompt, height, width); - menu_width = width - 6; + all.menu_width = width - 6; getyx(dialog, cur_y, cur_x); - box_y = cur_y + 1; - box_x = (width - menu_width) / 2 - 1; + all.box_y = cur_y + 1; + all.box_x = (width - all.menu_width) / 2 - 1; /* * After displaying the prompt, we know how much space we really have. * Limit the list to avoid overwriting the ok-button. */ - if (use_height + MIN_HIGH > height - cur_y) - use_height = height - MIN_HIGH - cur_y; - if (use_height <= 0) - use_height = 1; + if (all.menu_height + MIN_HIGH > height - cur_y) + all.menu_height = height - MIN_HIGH - cur_y; + if (all.menu_height <= 0) + all.menu_height = 1; /* Find out maximal number of displayable items at once. */ - max_choice = MIN(use_height, + max_choice = MIN(all.menu_height, RowHeight(item_no)); if (is_inputmenu) max_choice /= INPUT_ROWS; /* create new window for the menu */ - menu = dlg_sub_window(dialog, use_height, menu_width, - y + box_y + 1, - x + box_x + 1); + menu = dlg_sub_window(dialog, all.menu_height, all.menu_width, + y + all.box_y + 1, + x + all.box_x + 1); + all.menu = menu; + dlg_register_window(menu, "menu", binding2); dlg_register_buttons(menu, "menu", buttons); /* draw a box around the menu items */ - dlg_draw_box(dialog, box_y, box_x, use_height + 2, menu_width + 2, - menubox_border_attr, menubox_attr); + dlg_draw_box(dialog, + all.box_y, all.box_x, + all.menu_height + 2, all.menu_width + 2, + menubox_border_attr, menubox_border2_attr); name_width = 0; text_width = 0; @@ -421,49 +449,58 @@ dlg_menu(const char *title, * * FIXME: the gutter width and name/list ratio should be configurable. */ - use_width = (menu_width - GUTTER); - if (text_width + name_width > use_width) { - int need = (int) (0.30 * use_width); - if (name_width > need) { - int want = (int) (use_width - * ((double) name_width) - / (text_width + name_width)); - name_width = (want > need) ? want : need; + use_width = (all.menu_width - GUTTER); + if (dialog_vars.no_tags) { + list_width = MIN(use_width, text_width); + } else if (dialog_vars.no_items) { + list_width = MIN(use_width, name_width); + } else { + if (text_width >= 0 + && name_width >= 0 + && use_width > 0 + && text_width + name_width > use_width) { + int need = (int) (0.30 * use_width); + if (name_width > need) { + int want = (int) (use_width + * ((double) name_width) + / (text_width + name_width)); + name_width = (want > need) ? want : need; + } + text_width = use_width - name_width; } - text_width = use_width - name_width; + list_width = (text_width + name_width); } - tag_x = (is_inputmenu - ? 0 - : (use_width - text_width - name_width) / 2); - item_x = name_width + tag_x + GUTTER; + all.tag_x = (is_inputmenu + ? 0 + : (use_width - list_width) / 2); + all.item_x = ((dialog_vars.no_tags + ? 0 + : (dialog_vars.no_items + ? 0 + : (GUTTER + name_width))) + + all.tag_x); if (choice - scrollamt >= max_choice) { scrollamt = choice - (max_choice - 1); choice = max_choice - 1; } - /* Print the menu */ - for (i = 0; i < max_choice; i++) { - print_item(menu, - &items[i + scrollamt], - i, - (i == choice) ? Selected : Unselected, - is_inputmenu); - } - (void) wnoutrefresh(menu); + print_menu(&all, choice, scrollamt, max_choice, is_inputmenu); /* register the new window, along with its borders */ - dlg_mouse_mkbigregion(box_y + 1, box_x, use_height + 2, menu_width + 2, + dlg_mouse_mkbigregion(all.box_y + 1, all.box_x, + all.menu_height + 2, all.menu_width + 2, KEY_MAX, 1, 1, 1 /* by lines */ ); - print_arrows(dialog, box_x, box_y, scrollamt, max_choice, item_no, use_height); - dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); + dlg_trace_win(dialog); while (result == DLG_EXIT_UNKNOWN) { if (button < 0) /* --visit-items */ - wmove(dialog, box_y + ItemToRow(choice) + 1, box_x + tag_x + 1); + wmove(dialog, + all.box_y + ItemToRow(choice) + 1, + all.box_x + all.tag_x + 1); key = dlg_mouse_wgetch(dialog, &fkey); if (dlg_result_key(key, fkey, &result)) @@ -500,7 +537,7 @@ dlg_menu(const char *title, */ if (button < 0 || !dialog_state.visit_items) { for (j = scrollamt + choice + 1; j < item_no; j++) { - if (dlg_match_char(dlg_last_getc(), items[j].name)) { + if (check_hotkey(items, j)) { found = TRUE; i = j - scrollamt; break; @@ -508,7 +545,7 @@ dlg_menu(const char *title, } if (!found) { for (j = 0; j <= scrollamt + choice; j++) { - if (dlg_match_char(dlg_last_getc(), items[j].name)) { + if (check_hotkey(items, j)) { found = TRUE; i = j - scrollamt; break; @@ -578,95 +615,17 @@ dlg_menu(const char *title, if (i != choice) { getyx(dialog, cur_y, cur_x); if (i < 0 || i >= max_choice) { -#if defined(NCURSES_VERSION_MAJOR) && NCURSES_VERSION_MAJOR < 5 - /* - * Using wscrl to assist ncurses scrolling is not needed - * in version 5.x - */ - if (i == -1) { - if (use_height > 1) { - /* De-highlight current first item */ - print_item(menu, - &items[scrollamt], - 0, Unselected, is_inputmenu); - scrollok(menu, TRUE); - wscrl(menu, -RowHeight(1)); - scrollok(menu, FALSE); - } - scrollamt--; - print_item(menu, - &items[scrollamt], - 0, Selected, is_inputmenu); - } else if (i == max_choice) { - if (use_height > 1) { - /* De-highlight current last item before scrolling up */ - print_item(menu, - &items[scrollamt + max_choice - 1], - max_choice - 1, - Unselected, - is_inputmenu); - scrollok(menu, TRUE); - wscrl(menu, RowHeight(1)); - scrollok(menu, FALSE); - } - scrollamt++; - print_item(menu, - &items[scrollamt + max_choice - 1], - max_choice - 1, TRUE, - is_inputmenu); - } else -#endif - { - if (i < 0) { - scrollamt += i; - choice = 0; - } else { - choice = max_choice - 1; - scrollamt += (i - max_choice + 1); - } - for (i = 0; i < max_choice; i++) { - print_item(menu, - &items[scrollamt + i], - i, - (i == choice) ? Selected : Unselected, - is_inputmenu); - } - } - /* Clean bottom lines */ - if (is_inputmenu) { - int spare_lines, x_count; - spare_lines = use_height % INPUT_ROWS; - wattrset(menu, menubox_attr); - for (; spare_lines; spare_lines--) { - wmove(menu, use_height - spare_lines, 0); - for (x_count = 0; x_count < menu_width; - x_count++) { - waddch(menu, ' '); - } - } + if (i < 0) { + scrollamt += i; + choice = 0; + } else { + choice = max_choice - 1; + scrollamt += (i - max_choice + 1); } - (void) wnoutrefresh(menu); - print_arrows(dialog, - box_x, box_y, - scrollamt, max_choice, item_no, use_height); + print_menu(&all, choice, scrollamt, max_choice, is_inputmenu); } else { - /* De-highlight current item */ - print_item(menu, - &items[scrollamt + choice], - choice, - Unselected, - is_inputmenu); - /* Highlight new item */ choice = i; - print_item(menu, - &items[scrollamt + choice], - choice, - Selected, - is_inputmenu); - (void) wnoutrefresh(menu); - print_arrows(dialog, - box_x, box_y, - scrollamt, max_choice, item_no, use_height); + print_menu(&all, choice, scrollamt, max_choice, is_inputmenu); (void) wmove(dialog, cur_y, cur_x); wrefresh(dialog); } @@ -687,17 +646,14 @@ dlg_menu(const char *title, FALSE, width); break; case DLGK_ENTER: - result = dlg_enter_buttoncode(button); + if (is_inputmenu) + result = dlg_ok_buttoncode(button); + else + result = dlg_enter_buttoncode(button); /* * If dlg_menu() is called from dialog_menu(), we want to - * capture the results into dialog_vars.input_result, but not - * if dlg_menu() is called directly from an application. We - * can check this by testing if rename_menutext is the function - * pointer owned by dialog_menu(). It would be nicer to have - * this logic inside dialog_menu(), but that cannot be done - * since we would lose compatibility for the results reported - * after input_menu_edit(). + * capture the results into dialog_vars.input_result. */ if (result == DLG_EXIT_ERROR) { result = DLG_EXIT_UNKNOWN; @@ -720,7 +676,7 @@ dlg_menu(const char *title, if (is_inputmenu && result == DLG_EXIT_EXTRA) { char *tmp; - if (input_menu_edit(menu, + if (input_menu_edit(&all, &items[scrollamt + choice], choice, &tmp)) { @@ -732,7 +688,8 @@ dlg_menu(const char *title, } } else { result = DLG_EXIT_UNKNOWN; - print_item(menu, + print_item(&all, + menu, &items[scrollamt + choice], choice, Selected, @@ -789,17 +746,19 @@ dialog_menu(const char *title, { int result; int choice; - int i; + int i, j; DIALOG_LISTITEM *listitems; listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); assert_ptr(listitems, "dialog_menu"); - for (i = 0; i < item_no; ++i) { - listitems[i].name = ItemName(i); - listitems[i].text = ItemText(i); + for (i = j = 0; i < item_no; ++i) { + listitems[i].name = items[j++]; + listitems[i].text = (dialog_vars.no_items + ? dlg_strempty() + : items[j++]); listitems[i].help = ((dialog_vars.item_help) - ? ItemHelp(i) + ? items[j++] : dlg_strempty()); } dlg_align_columns(&listitems[0].text, sizeof(DIALOG_LISTITEM), item_no); @@ -812,7 +771,9 @@ dialog_menu(const char *title, item_no, listitems, &choice, - dialog_vars.input_menu ? dlg_renamed_menutext : dlg_dummy_menutext); + (dialog_vars.input_menu + ? dlg_renamed_menutext + : dlg_dummy_menutext)); dlg_free_columns(&listitems[0].text, sizeof(DIALOG_LISTITEM), item_no); free(listitems); |