12a3e3873SBaptiste Daroussin /* 2*febdb468SDevin Teske * $Id: treeview.c,v 1.24 2013/09/02 17:13:33 tom Exp $ 32a3e3873SBaptiste Daroussin * 42a3e3873SBaptiste Daroussin * treeview.c -- implements the treeview dialog 52a3e3873SBaptiste Daroussin * 62a3e3873SBaptiste Daroussin * Copyright 2012,2013 Thomas E. Dickey 72a3e3873SBaptiste Daroussin * 82a3e3873SBaptiste Daroussin * This program is free software; you can redistribute it and/or modify 92a3e3873SBaptiste Daroussin * it under the terms of the GNU Lesser General Public License, version 2.1 102a3e3873SBaptiste Daroussin * as published by the Free Software Foundation. 112a3e3873SBaptiste Daroussin * 122a3e3873SBaptiste Daroussin * This program is distributed in the hope that it will be useful, but 132a3e3873SBaptiste Daroussin * WITHOUT ANY WARRANTY; without even the implied warranty of 142a3e3873SBaptiste Daroussin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 152a3e3873SBaptiste Daroussin * Lesser General Public License for more details. 162a3e3873SBaptiste Daroussin * 172a3e3873SBaptiste Daroussin * You should have received a copy of the GNU Lesser General Public 182a3e3873SBaptiste Daroussin * License along with this program; if not, write to 192a3e3873SBaptiste Daroussin * Free Software Foundation, Inc. 202a3e3873SBaptiste Daroussin * 51 Franklin St., Fifth Floor 212a3e3873SBaptiste Daroussin * Boston, MA 02110, USA. 222a3e3873SBaptiste Daroussin */ 232a3e3873SBaptiste Daroussin 242a3e3873SBaptiste Daroussin #include <dialog.h> 252a3e3873SBaptiste Daroussin #include <dlg_keys.h> 262a3e3873SBaptiste Daroussin 272a3e3873SBaptiste Daroussin #define INDENT 3 282a3e3873SBaptiste Daroussin #define MIN_HIGH (1 + (5 * MARGIN)) 292a3e3873SBaptiste Daroussin 302a3e3873SBaptiste Daroussin typedef struct { 312a3e3873SBaptiste Daroussin /* the outer-window */ 322a3e3873SBaptiste Daroussin WINDOW *dialog; 332a3e3873SBaptiste Daroussin bool is_check; 342a3e3873SBaptiste Daroussin int box_y; 352a3e3873SBaptiste Daroussin int box_x; 362a3e3873SBaptiste Daroussin int check_x; 372a3e3873SBaptiste Daroussin int item_x; 382a3e3873SBaptiste Daroussin int use_height; 392a3e3873SBaptiste Daroussin int use_width; 402a3e3873SBaptiste Daroussin /* the inner-window */ 412a3e3873SBaptiste Daroussin WINDOW *list; 422a3e3873SBaptiste Daroussin DIALOG_LISTITEM *items; 432a3e3873SBaptiste Daroussin int item_no; 442a3e3873SBaptiste Daroussin int *depths; 452a3e3873SBaptiste Daroussin const char *states; 462a3e3873SBaptiste Daroussin } ALL_DATA; 472a3e3873SBaptiste Daroussin 482a3e3873SBaptiste Daroussin /* 492a3e3873SBaptiste Daroussin * Print list item. The 'selected' parameter is true if 'choice' is the 502a3e3873SBaptiste Daroussin * current item. That one is colored differently from the other items. 512a3e3873SBaptiste Daroussin */ 522a3e3873SBaptiste Daroussin static void 532a3e3873SBaptiste Daroussin print_item(ALL_DATA * data, 542a3e3873SBaptiste Daroussin DIALOG_LISTITEM * item, 552a3e3873SBaptiste Daroussin const char *states, 562a3e3873SBaptiste Daroussin int depths, 572a3e3873SBaptiste Daroussin int choice, 582a3e3873SBaptiste Daroussin int selected) 592a3e3873SBaptiste Daroussin { 602a3e3873SBaptiste Daroussin WINDOW *win = data->list; 612a3e3873SBaptiste Daroussin chtype save = dlg_get_attrs(win); 622a3e3873SBaptiste Daroussin int i; 632a3e3873SBaptiste Daroussin bool first = TRUE; 642a3e3873SBaptiste Daroussin int climit = (getmaxx(win) - data->check_x + 1); 652a3e3873SBaptiste Daroussin const char *show = (dialog_vars.no_items 662a3e3873SBaptiste Daroussin ? item->name 672a3e3873SBaptiste Daroussin : item->text); 682a3e3873SBaptiste Daroussin 692a3e3873SBaptiste Daroussin /* Clear 'residue' of last item */ 702a3e3873SBaptiste Daroussin (void) wattrset(win, menubox_attr); 712a3e3873SBaptiste Daroussin (void) wmove(win, choice, 0); 722a3e3873SBaptiste Daroussin for (i = 0; i < data->use_width; i++) 732a3e3873SBaptiste Daroussin (void) waddch(win, ' '); 742a3e3873SBaptiste Daroussin 752a3e3873SBaptiste Daroussin (void) wmove(win, choice, data->check_x); 762a3e3873SBaptiste Daroussin (void) wattrset(win, selected ? check_selected_attr : check_attr); 772a3e3873SBaptiste Daroussin (void) wprintw(win, 782a3e3873SBaptiste Daroussin data->is_check ? "[%c]" : "(%c)", 792a3e3873SBaptiste Daroussin states[item->state]); 802a3e3873SBaptiste Daroussin (void) wattrset(win, menubox_attr); 812a3e3873SBaptiste Daroussin 822a3e3873SBaptiste Daroussin (void) wattrset(win, selected ? item_selected_attr : item_attr); 832a3e3873SBaptiste Daroussin for (i = 0; i < depths; ++i) { 842a3e3873SBaptiste Daroussin int j; 852a3e3873SBaptiste Daroussin (void) wmove(win, choice, data->item_x + INDENT * i); 862a3e3873SBaptiste Daroussin (void) waddch(win, ACS_VLINE); 872a3e3873SBaptiste Daroussin for (j = INDENT - 1; j > 0; --j) 882a3e3873SBaptiste Daroussin (void) waddch(win, ' '); 892a3e3873SBaptiste Daroussin } 902a3e3873SBaptiste Daroussin (void) wmove(win, choice, data->item_x + INDENT * depths); 912a3e3873SBaptiste Daroussin 922a3e3873SBaptiste Daroussin dlg_print_listitem(win, show, climit, first, selected); 932a3e3873SBaptiste Daroussin 942a3e3873SBaptiste Daroussin if (selected) { 952a3e3873SBaptiste Daroussin dlg_item_help(item->help); 962a3e3873SBaptiste Daroussin } 972a3e3873SBaptiste Daroussin (void) wattrset(win, save); 982a3e3873SBaptiste Daroussin } 992a3e3873SBaptiste Daroussin 1002a3e3873SBaptiste Daroussin static void 1012a3e3873SBaptiste Daroussin print_list(ALL_DATA * data, 1022a3e3873SBaptiste Daroussin int choice, 1032a3e3873SBaptiste Daroussin int scrollamt, 1042a3e3873SBaptiste Daroussin int max_choice) 1052a3e3873SBaptiste Daroussin { 1062a3e3873SBaptiste Daroussin int i; 1072a3e3873SBaptiste Daroussin int cur_y, cur_x; 1082a3e3873SBaptiste Daroussin 1092a3e3873SBaptiste Daroussin getyx(data->dialog, cur_y, cur_x); 1102a3e3873SBaptiste Daroussin 1112a3e3873SBaptiste Daroussin for (i = 0; i < max_choice; i++) { 1122a3e3873SBaptiste Daroussin print_item(data, 1132a3e3873SBaptiste Daroussin &data->items[scrollamt + i], 1142a3e3873SBaptiste Daroussin data->states, 1152a3e3873SBaptiste Daroussin data->depths[scrollamt + i], 1162a3e3873SBaptiste Daroussin i, i == choice); 1172a3e3873SBaptiste Daroussin } 1182a3e3873SBaptiste Daroussin (void) wnoutrefresh(data->list); 1192a3e3873SBaptiste Daroussin 1202a3e3873SBaptiste Daroussin dlg_draw_scrollbar(data->dialog, 1212a3e3873SBaptiste Daroussin (long) (scrollamt), 1222a3e3873SBaptiste Daroussin (long) (scrollamt), 1232a3e3873SBaptiste Daroussin (long) (scrollamt + max_choice), 1242a3e3873SBaptiste Daroussin (long) (data->item_no), 1252a3e3873SBaptiste Daroussin data->box_x + data->check_x, 1262a3e3873SBaptiste Daroussin data->box_x + data->use_width, 1272a3e3873SBaptiste Daroussin data->box_y, 1282a3e3873SBaptiste Daroussin data->box_y + data->use_height + 1, 1292a3e3873SBaptiste Daroussin menubox_border2_attr, 1302a3e3873SBaptiste Daroussin menubox_border_attr); 1312a3e3873SBaptiste Daroussin 1322a3e3873SBaptiste Daroussin (void) wmove(data->dialog, cur_y, cur_x); 1332a3e3873SBaptiste Daroussin } 1342a3e3873SBaptiste Daroussin 1352a3e3873SBaptiste Daroussin static bool 1362a3e3873SBaptiste Daroussin check_hotkey(DIALOG_LISTITEM * items, int choice) 1372a3e3873SBaptiste Daroussin { 1382a3e3873SBaptiste Daroussin bool result = FALSE; 1392a3e3873SBaptiste Daroussin 1402a3e3873SBaptiste Daroussin if (dlg_match_char(dlg_last_getc(), 1412a3e3873SBaptiste Daroussin (dialog_vars.no_tags 1422a3e3873SBaptiste Daroussin ? items[choice].text 1432a3e3873SBaptiste Daroussin : items[choice].name))) { 1442a3e3873SBaptiste Daroussin result = TRUE; 1452a3e3873SBaptiste Daroussin } 1462a3e3873SBaptiste Daroussin return result; 1472a3e3873SBaptiste Daroussin } 1482a3e3873SBaptiste Daroussin 1492a3e3873SBaptiste Daroussin /* 1502a3e3873SBaptiste Daroussin * This is an alternate interface to 'treeview' which allows the application 1512a3e3873SBaptiste Daroussin * to read the list item states back directly without putting them in the 1522a3e3873SBaptiste Daroussin * output buffer. 1532a3e3873SBaptiste Daroussin */ 1542a3e3873SBaptiste Daroussin int 1552a3e3873SBaptiste Daroussin dlg_treeview(const char *title, 1562a3e3873SBaptiste Daroussin const char *cprompt, 1572a3e3873SBaptiste Daroussin int height, 1582a3e3873SBaptiste Daroussin int width, 1592a3e3873SBaptiste Daroussin int list_height, 1602a3e3873SBaptiste Daroussin int item_no, 1612a3e3873SBaptiste Daroussin DIALOG_LISTITEM * items, 1622a3e3873SBaptiste Daroussin const char *states, 1632a3e3873SBaptiste Daroussin int *depths, 1642a3e3873SBaptiste Daroussin int flag, 1652a3e3873SBaptiste Daroussin int *current_item) 1662a3e3873SBaptiste Daroussin { 1672a3e3873SBaptiste Daroussin /* *INDENT-OFF* */ 1682a3e3873SBaptiste Daroussin static DLG_KEYS_BINDING binding[] = { 1692a3e3873SBaptiste Daroussin HELPKEY_BINDINGS, 1702a3e3873SBaptiste Daroussin ENTERKEY_BINDINGS, 1712a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), 1722a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), 1732a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), 1742a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ), 1752a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ), 1762a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ), 1772a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ), 1782a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ), 1792a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), 1802a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), 1812a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ), 1822a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), 1832a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), 1842a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), 1852a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ), 1862a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ), 1872a3e3873SBaptiste Daroussin DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ), 1882a3e3873SBaptiste Daroussin END_KEYS_BINDING 1892a3e3873SBaptiste Daroussin }; 1902a3e3873SBaptiste Daroussin /* *INDENT-ON* */ 1912a3e3873SBaptiste Daroussin 1922a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 1932a3e3873SBaptiste Daroussin int old_height = height; 1942a3e3873SBaptiste Daroussin int old_width = width; 1952a3e3873SBaptiste Daroussin #endif 1962a3e3873SBaptiste Daroussin ALL_DATA all; 1972a3e3873SBaptiste Daroussin int i, j, key2, found, x, y, cur_y, box_x, box_y; 1982a3e3873SBaptiste Daroussin int key = 0, fkey; 1992a3e3873SBaptiste Daroussin int button = dialog_state.visit_items ? -1 : dlg_default_button(); 2002a3e3873SBaptiste Daroussin int choice = dlg_default_listitem(items); 2012a3e3873SBaptiste Daroussin int scrollamt = 0; 2022a3e3873SBaptiste Daroussin int max_choice; 2032a3e3873SBaptiste Daroussin int was_mouse; 2042a3e3873SBaptiste Daroussin int use_height; 2052a3e3873SBaptiste Daroussin int use_width, name_width, text_width, tree_width; 2062a3e3873SBaptiste Daroussin int result = DLG_EXIT_UNKNOWN; 2072a3e3873SBaptiste Daroussin int num_states; 2082a3e3873SBaptiste Daroussin WINDOW *dialog, *list; 2092a3e3873SBaptiste Daroussin char *prompt = dlg_strclone(cprompt); 2102a3e3873SBaptiste Daroussin const char **buttons = dlg_ok_labels(); 2112a3e3873SBaptiste Daroussin const char *widget_name; 2122a3e3873SBaptiste Daroussin 2132a3e3873SBaptiste Daroussin /* we need at least two states */ 2142a3e3873SBaptiste Daroussin if (states == 0 || strlen(states) < 2) 2152a3e3873SBaptiste Daroussin states = " *"; 2162a3e3873SBaptiste Daroussin num_states = (int) strlen(states); 2172a3e3873SBaptiste Daroussin 2182a3e3873SBaptiste Daroussin memset(&all, 0, sizeof(all)); 2192a3e3873SBaptiste Daroussin all.items = items; 2202a3e3873SBaptiste Daroussin all.item_no = item_no; 2212a3e3873SBaptiste Daroussin all.states = states; 2222a3e3873SBaptiste Daroussin all.depths = depths; 2232a3e3873SBaptiste Daroussin 2242a3e3873SBaptiste Daroussin dlg_does_output(); 2252a3e3873SBaptiste Daroussin dlg_tab_correct_str(prompt); 2262a3e3873SBaptiste Daroussin 2272a3e3873SBaptiste Daroussin /* 2282a3e3873SBaptiste Daroussin * If this is a radiobutton list, ensure that no more than one item is 2292a3e3873SBaptiste Daroussin * selected initially. Allow none to be selected, since some users may 2302a3e3873SBaptiste Daroussin * wish to provide this flavor. 2312a3e3873SBaptiste Daroussin */ 2322a3e3873SBaptiste Daroussin if (flag == FLAG_RADIO) { 2332a3e3873SBaptiste Daroussin bool first = TRUE; 2342a3e3873SBaptiste Daroussin 2352a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 2362a3e3873SBaptiste Daroussin if (items[i].state) { 2372a3e3873SBaptiste Daroussin if (first) { 2382a3e3873SBaptiste Daroussin first = FALSE; 2392a3e3873SBaptiste Daroussin } else { 2402a3e3873SBaptiste Daroussin items[i].state = 0; 2412a3e3873SBaptiste Daroussin } 2422a3e3873SBaptiste Daroussin } 2432a3e3873SBaptiste Daroussin } 2442a3e3873SBaptiste Daroussin } else { 2452a3e3873SBaptiste Daroussin all.is_check = TRUE; 2462a3e3873SBaptiste Daroussin } 2472a3e3873SBaptiste Daroussin widget_name = "treeview"; 2482a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 2492a3e3873SBaptiste Daroussin retry: 2502a3e3873SBaptiste Daroussin #endif 2512a3e3873SBaptiste Daroussin 2522a3e3873SBaptiste Daroussin use_height = list_height; 2532a3e3873SBaptiste Daroussin use_width = dlg_calc_list_width(item_no, items) + 10; 2542a3e3873SBaptiste Daroussin use_width = MAX(26, use_width); 2552a3e3873SBaptiste Daroussin if (use_height == 0) { 2562a3e3873SBaptiste Daroussin /* calculate height without items (4) */ 2572a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 2582a3e3873SBaptiste Daroussin dlg_calc_listh(&height, &use_height, item_no); 2592a3e3873SBaptiste Daroussin } else { 2602a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, use_width); 2612a3e3873SBaptiste Daroussin } 2622a3e3873SBaptiste Daroussin dlg_button_layout(buttons, &width); 2632a3e3873SBaptiste Daroussin dlg_print_size(height, width); 2642a3e3873SBaptiste Daroussin dlg_ctl_size(height, width); 2652a3e3873SBaptiste Daroussin 2662a3e3873SBaptiste Daroussin x = dlg_box_x_ordinate(width); 2672a3e3873SBaptiste Daroussin y = dlg_box_y_ordinate(height); 2682a3e3873SBaptiste Daroussin 2692a3e3873SBaptiste Daroussin dialog = dlg_new_window(height, width, y, x); 2702a3e3873SBaptiste Daroussin dlg_register_window(dialog, widget_name, binding); 2712a3e3873SBaptiste Daroussin dlg_register_buttons(dialog, widget_name, buttons); 2722a3e3873SBaptiste Daroussin 2732a3e3873SBaptiste Daroussin dlg_mouse_setbase(x, y); 2742a3e3873SBaptiste Daroussin 2752a3e3873SBaptiste Daroussin dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 2762a3e3873SBaptiste Daroussin dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 2772a3e3873SBaptiste Daroussin dlg_draw_title(dialog, title); 2782a3e3873SBaptiste Daroussin 2792a3e3873SBaptiste Daroussin (void) wattrset(dialog, dialog_attr); 2802a3e3873SBaptiste Daroussin dlg_print_autowrap(dialog, prompt, height, width); 2812a3e3873SBaptiste Daroussin 2822a3e3873SBaptiste Daroussin all.use_width = width - 4; 2832a3e3873SBaptiste Daroussin cur_y = getcury(dialog); 2842a3e3873SBaptiste Daroussin box_y = cur_y + 1; 2852a3e3873SBaptiste Daroussin box_x = (width - all.use_width) / 2 - 1; 2862a3e3873SBaptiste Daroussin 2872a3e3873SBaptiste Daroussin /* 2882a3e3873SBaptiste Daroussin * After displaying the prompt, we know how much space we really have. 2892a3e3873SBaptiste Daroussin * Limit the list to avoid overwriting the ok-button. 2902a3e3873SBaptiste Daroussin */ 2912a3e3873SBaptiste Daroussin if (use_height + MIN_HIGH > height - cur_y) 2922a3e3873SBaptiste Daroussin use_height = height - MIN_HIGH - cur_y; 2932a3e3873SBaptiste Daroussin if (use_height <= 0) 2942a3e3873SBaptiste Daroussin use_height = 1; 2952a3e3873SBaptiste Daroussin 2962a3e3873SBaptiste Daroussin max_choice = MIN(use_height, item_no); 2972a3e3873SBaptiste Daroussin 2982a3e3873SBaptiste Daroussin /* create new window for the list */ 2992a3e3873SBaptiste Daroussin list = dlg_sub_window(dialog, use_height, all.use_width, 3002a3e3873SBaptiste Daroussin y + box_y + 1, x + box_x + 1); 3012a3e3873SBaptiste Daroussin 3022a3e3873SBaptiste Daroussin /* draw a box around the list items */ 3032a3e3873SBaptiste Daroussin dlg_draw_box(dialog, box_y, box_x, 3042a3e3873SBaptiste Daroussin use_height + 2 * MARGIN, 3052a3e3873SBaptiste Daroussin all.use_width + 2 * MARGIN, 3062a3e3873SBaptiste Daroussin menubox_border_attr, menubox_border2_attr); 3072a3e3873SBaptiste Daroussin 3082a3e3873SBaptiste Daroussin text_width = 0; 3092a3e3873SBaptiste Daroussin name_width = 0; 3102a3e3873SBaptiste Daroussin tree_width = 0; 3112a3e3873SBaptiste Daroussin /* Find length of longest item to center treeview */ 3122a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 3132a3e3873SBaptiste Daroussin tree_width = MAX(tree_width, INDENT * depths[i]); 3142a3e3873SBaptiste Daroussin text_width = MAX(text_width, dlg_count_columns(items[i].text)); 3152a3e3873SBaptiste Daroussin name_width = MAX(name_width, dlg_count_columns(items[i].name)); 3162a3e3873SBaptiste Daroussin } 3172a3e3873SBaptiste Daroussin if (dialog_vars.no_tags && !dialog_vars.no_items) { 3182a3e3873SBaptiste Daroussin tree_width += text_width; 3192a3e3873SBaptiste Daroussin } else if (dialog_vars.no_items) { 3202a3e3873SBaptiste Daroussin tree_width += name_width; 3212a3e3873SBaptiste Daroussin } else { 3222a3e3873SBaptiste Daroussin tree_width += (text_width + name_width); 3232a3e3873SBaptiste Daroussin } 3242a3e3873SBaptiste Daroussin 3252a3e3873SBaptiste Daroussin use_width = (all.use_width - 4); 3262a3e3873SBaptiste Daroussin tree_width = MIN(tree_width, all.use_width); 3272a3e3873SBaptiste Daroussin 3282a3e3873SBaptiste Daroussin all.check_x = (use_width - tree_width) / 2; 3292a3e3873SBaptiste Daroussin all.item_x = ((dialog_vars.no_tags 3302a3e3873SBaptiste Daroussin ? 0 3312a3e3873SBaptiste Daroussin : (dialog_vars.no_items 3322a3e3873SBaptiste Daroussin ? 0 3332a3e3873SBaptiste Daroussin : (2 + name_width))) 3342a3e3873SBaptiste Daroussin + all.check_x + 4); 3352a3e3873SBaptiste Daroussin 3362a3e3873SBaptiste Daroussin /* ensure we are scrolled to show the current choice */ 3372a3e3873SBaptiste Daroussin if (choice >= (max_choice + scrollamt)) { 3382a3e3873SBaptiste Daroussin scrollamt = choice - max_choice + 1; 3392a3e3873SBaptiste Daroussin choice = max_choice - 1; 3402a3e3873SBaptiste Daroussin } 3412a3e3873SBaptiste Daroussin 3422a3e3873SBaptiste Daroussin /* register the new window, along with its borders */ 3432a3e3873SBaptiste Daroussin dlg_mouse_mkbigregion(box_y + 1, box_x, 3442a3e3873SBaptiste Daroussin use_height, all.use_width + 2, 3452a3e3873SBaptiste Daroussin KEY_MAX, 1, 1, 1 /* by lines */ ); 3462a3e3873SBaptiste Daroussin 3472a3e3873SBaptiste Daroussin all.dialog = dialog; 3482a3e3873SBaptiste Daroussin all.box_x = box_x; 3492a3e3873SBaptiste Daroussin all.box_y = box_y; 3502a3e3873SBaptiste Daroussin all.use_height = use_height; 3512a3e3873SBaptiste Daroussin all.list = list; 3522a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 3532a3e3873SBaptiste Daroussin 3542a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 3552a3e3873SBaptiste Daroussin 3562a3e3873SBaptiste Daroussin dlg_trace_win(dialog); 3572a3e3873SBaptiste Daroussin while (result == DLG_EXIT_UNKNOWN) { 3582a3e3873SBaptiste Daroussin if (button < 0) /* --visit-items */ 3592a3e3873SBaptiste Daroussin wmove(dialog, box_y + choice + 1, box_x + all.check_x + 2); 3602a3e3873SBaptiste Daroussin 3612a3e3873SBaptiste Daroussin key = dlg_mouse_wgetch(dialog, &fkey); 3622a3e3873SBaptiste Daroussin if (dlg_result_key(key, fkey, &result)) 3632a3e3873SBaptiste Daroussin break; 3642a3e3873SBaptiste Daroussin 3652a3e3873SBaptiste Daroussin was_mouse = (fkey && is_DLGK_MOUSE(key)); 3662a3e3873SBaptiste Daroussin if (was_mouse) 3672a3e3873SBaptiste Daroussin key -= M_EVENT; 3682a3e3873SBaptiste Daroussin 3692a3e3873SBaptiste Daroussin if (was_mouse && (key >= KEY_MAX)) { 3702a3e3873SBaptiste Daroussin i = (key - KEY_MAX); 3712a3e3873SBaptiste Daroussin if (i < max_choice) { 3722a3e3873SBaptiste Daroussin choice = (key - KEY_MAX); 3732a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 3742a3e3873SBaptiste Daroussin 3752a3e3873SBaptiste Daroussin key = ' '; /* force the selected item to toggle */ 3762a3e3873SBaptiste Daroussin } else { 3772a3e3873SBaptiste Daroussin beep(); 3782a3e3873SBaptiste Daroussin continue; 3792a3e3873SBaptiste Daroussin } 3802a3e3873SBaptiste Daroussin fkey = FALSE; 3812a3e3873SBaptiste Daroussin } else if (was_mouse && key >= KEY_MIN) { 3822a3e3873SBaptiste Daroussin key = dlg_lookup_key(dialog, key, &fkey); 3832a3e3873SBaptiste Daroussin } 3842a3e3873SBaptiste Daroussin 3852a3e3873SBaptiste Daroussin /* 3862a3e3873SBaptiste Daroussin * A space toggles the item status. 3872a3e3873SBaptiste Daroussin */ 3882a3e3873SBaptiste Daroussin if (key == ' ') { 3892a3e3873SBaptiste Daroussin int current = scrollamt + choice; 3902a3e3873SBaptiste Daroussin int next = items[current].state + 1; 3912a3e3873SBaptiste Daroussin 3922a3e3873SBaptiste Daroussin if (next >= num_states) 3932a3e3873SBaptiste Daroussin next = 0; 3942a3e3873SBaptiste Daroussin 3952a3e3873SBaptiste Daroussin if (flag == FLAG_CHECK) { /* checklist? */ 3962a3e3873SBaptiste Daroussin items[current].state = next; 3972a3e3873SBaptiste Daroussin } else { 3982a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 3992a3e3873SBaptiste Daroussin if (i != current) { 4002a3e3873SBaptiste Daroussin items[i].state = 0; 4012a3e3873SBaptiste Daroussin } 4022a3e3873SBaptiste Daroussin } 4032a3e3873SBaptiste Daroussin if (items[current].state) { 4042a3e3873SBaptiste Daroussin items[current].state = next ? next : 1; 4052a3e3873SBaptiste Daroussin } else { 4062a3e3873SBaptiste Daroussin items[current].state = 1; 4072a3e3873SBaptiste Daroussin } 4082a3e3873SBaptiste Daroussin } 4092a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 4102a3e3873SBaptiste Daroussin continue; /* wait for another key press */ 4112a3e3873SBaptiste Daroussin } 4122a3e3873SBaptiste Daroussin 4132a3e3873SBaptiste Daroussin /* 4142a3e3873SBaptiste Daroussin * Check if key pressed matches first character of any item tag in 4152a3e3873SBaptiste Daroussin * list. If there is more than one match, we will cycle through 4162a3e3873SBaptiste Daroussin * each one as the same key is pressed repeatedly. 4172a3e3873SBaptiste Daroussin */ 4182a3e3873SBaptiste Daroussin found = FALSE; 4192a3e3873SBaptiste Daroussin if (!fkey) { 4202a3e3873SBaptiste Daroussin if (button < 0 || !dialog_state.visit_items) { 4212a3e3873SBaptiste Daroussin for (j = scrollamt + choice + 1; j < item_no; j++) { 4222a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4232a3e3873SBaptiste Daroussin found = TRUE; 4242a3e3873SBaptiste Daroussin i = j - scrollamt; 4252a3e3873SBaptiste Daroussin break; 4262a3e3873SBaptiste Daroussin } 4272a3e3873SBaptiste Daroussin } 4282a3e3873SBaptiste Daroussin if (!found) { 4292a3e3873SBaptiste Daroussin for (j = 0; j <= scrollamt + choice; j++) { 4302a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4312a3e3873SBaptiste Daroussin found = TRUE; 4322a3e3873SBaptiste Daroussin i = j - scrollamt; 4332a3e3873SBaptiste Daroussin break; 4342a3e3873SBaptiste Daroussin } 4352a3e3873SBaptiste Daroussin } 4362a3e3873SBaptiste Daroussin } 4372a3e3873SBaptiste Daroussin if (found) 4382a3e3873SBaptiste Daroussin dlg_flush_getc(); 4392a3e3873SBaptiste Daroussin } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 4402a3e3873SBaptiste Daroussin button = j; 4412a3e3873SBaptiste Daroussin ungetch('\n'); 4422a3e3873SBaptiste Daroussin continue; 4432a3e3873SBaptiste Daroussin } 4442a3e3873SBaptiste Daroussin } 4452a3e3873SBaptiste Daroussin 4462a3e3873SBaptiste Daroussin /* 4472a3e3873SBaptiste Daroussin * A single digit (1-9) positions the selection to that line in the 4482a3e3873SBaptiste Daroussin * current screen. 4492a3e3873SBaptiste Daroussin */ 4502a3e3873SBaptiste Daroussin if (!found 4512a3e3873SBaptiste Daroussin && (key <= '9') 4522a3e3873SBaptiste Daroussin && (key > '0') 4532a3e3873SBaptiste Daroussin && (key - '1' < max_choice)) { 4542a3e3873SBaptiste Daroussin found = TRUE; 4552a3e3873SBaptiste Daroussin i = key - '1'; 4562a3e3873SBaptiste Daroussin } 4572a3e3873SBaptiste Daroussin 4582a3e3873SBaptiste Daroussin if (!found) { 4592a3e3873SBaptiste Daroussin if (fkey) { 4602a3e3873SBaptiste Daroussin found = TRUE; 4612a3e3873SBaptiste Daroussin switch (key) { 4622a3e3873SBaptiste Daroussin case DLGK_ITEM_FIRST: 4632a3e3873SBaptiste Daroussin i = -scrollamt; 4642a3e3873SBaptiste Daroussin break; 4652a3e3873SBaptiste Daroussin case DLGK_ITEM_LAST: 4662a3e3873SBaptiste Daroussin i = item_no - 1 - scrollamt; 4672a3e3873SBaptiste Daroussin break; 4682a3e3873SBaptiste Daroussin case DLGK_PAGE_PREV: 4692a3e3873SBaptiste Daroussin if (choice) 4702a3e3873SBaptiste Daroussin i = 0; 4712a3e3873SBaptiste Daroussin else if (scrollamt != 0) 4722a3e3873SBaptiste Daroussin i = -MIN(scrollamt, max_choice); 4732a3e3873SBaptiste Daroussin else 4742a3e3873SBaptiste Daroussin continue; 4752a3e3873SBaptiste Daroussin break; 4762a3e3873SBaptiste Daroussin case DLGK_PAGE_NEXT: 4772a3e3873SBaptiste Daroussin i = MIN(choice + max_choice, item_no - scrollamt - 1); 4782a3e3873SBaptiste Daroussin break; 4792a3e3873SBaptiste Daroussin case DLGK_ITEM_PREV: 4802a3e3873SBaptiste Daroussin i = choice - 1; 4812a3e3873SBaptiste Daroussin if (choice == 0 && scrollamt == 0) 4822a3e3873SBaptiste Daroussin continue; 4832a3e3873SBaptiste Daroussin break; 4842a3e3873SBaptiste Daroussin case DLGK_ITEM_NEXT: 4852a3e3873SBaptiste Daroussin i = choice + 1; 4862a3e3873SBaptiste Daroussin if (scrollamt + choice >= item_no - 1) 4872a3e3873SBaptiste Daroussin continue; 4882a3e3873SBaptiste Daroussin break; 4892a3e3873SBaptiste Daroussin default: 4902a3e3873SBaptiste Daroussin found = FALSE; 4912a3e3873SBaptiste Daroussin break; 4922a3e3873SBaptiste Daroussin } 4932a3e3873SBaptiste Daroussin } 4942a3e3873SBaptiste Daroussin } 4952a3e3873SBaptiste Daroussin 4962a3e3873SBaptiste Daroussin if (found) { 4972a3e3873SBaptiste Daroussin if (i != choice) { 4982a3e3873SBaptiste Daroussin if (i < 0 || i >= max_choice) { 4992a3e3873SBaptiste Daroussin if (i < 0) { 5002a3e3873SBaptiste Daroussin scrollamt += i; 5012a3e3873SBaptiste Daroussin choice = 0; 5022a3e3873SBaptiste Daroussin } else { 5032a3e3873SBaptiste Daroussin choice = max_choice - 1; 5042a3e3873SBaptiste Daroussin scrollamt += (i - max_choice + 1); 5052a3e3873SBaptiste Daroussin } 5062a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5072a3e3873SBaptiste Daroussin } else { 5082a3e3873SBaptiste Daroussin choice = i; 5092a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5102a3e3873SBaptiste Daroussin } 5112a3e3873SBaptiste Daroussin } 5122a3e3873SBaptiste Daroussin continue; /* wait for another key press */ 5132a3e3873SBaptiste Daroussin } 5142a3e3873SBaptiste Daroussin 5152a3e3873SBaptiste Daroussin if (fkey) { 5162a3e3873SBaptiste Daroussin switch (key) { 5172a3e3873SBaptiste Daroussin case DLGK_ENTER: 5182a3e3873SBaptiste Daroussin result = dlg_enter_buttoncode(button); 5192a3e3873SBaptiste Daroussin break; 5202a3e3873SBaptiste Daroussin case DLGK_FIELD_PREV: 5212a3e3873SBaptiste Daroussin button = dlg_prev_button(buttons, button); 5222a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5232a3e3873SBaptiste Daroussin FALSE, width); 5242a3e3873SBaptiste Daroussin break; 5252a3e3873SBaptiste Daroussin case DLGK_FIELD_NEXT: 5262a3e3873SBaptiste Daroussin button = dlg_next_button(buttons, button); 5272a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5282a3e3873SBaptiste Daroussin FALSE, width); 5292a3e3873SBaptiste Daroussin break; 5302a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 5312a3e3873SBaptiste Daroussin case KEY_RESIZE: 5322a3e3873SBaptiste Daroussin /* reset data */ 5332a3e3873SBaptiste Daroussin height = old_height; 5342a3e3873SBaptiste Daroussin width = old_width; 5352a3e3873SBaptiste Daroussin /* repaint */ 5362a3e3873SBaptiste Daroussin dlg_clear(); 5372a3e3873SBaptiste Daroussin dlg_del_window(dialog); 5382a3e3873SBaptiste Daroussin refresh(); 5392a3e3873SBaptiste Daroussin dlg_mouse_free_regions(); 5402a3e3873SBaptiste Daroussin goto retry; 5412a3e3873SBaptiste Daroussin #endif 5422a3e3873SBaptiste Daroussin default: 5432a3e3873SBaptiste Daroussin if (was_mouse) { 5442a3e3873SBaptiste Daroussin if ((key2 = dlg_ok_buttoncode(key)) >= 0) { 5452a3e3873SBaptiste Daroussin result = key2; 5462a3e3873SBaptiste Daroussin break; 5472a3e3873SBaptiste Daroussin } 5482a3e3873SBaptiste Daroussin beep(); 5492a3e3873SBaptiste Daroussin } 5502a3e3873SBaptiste Daroussin } 5512a3e3873SBaptiste Daroussin } else { 5522a3e3873SBaptiste Daroussin beep(); 5532a3e3873SBaptiste Daroussin } 5542a3e3873SBaptiste Daroussin } 5552a3e3873SBaptiste Daroussin 5562a3e3873SBaptiste Daroussin dlg_del_window(dialog); 5572a3e3873SBaptiste Daroussin dlg_mouse_free_regions(); 5582a3e3873SBaptiste Daroussin free(prompt); 5592a3e3873SBaptiste Daroussin *current_item = (scrollamt + choice); 5602a3e3873SBaptiste Daroussin return result; 5612a3e3873SBaptiste Daroussin } 5622a3e3873SBaptiste Daroussin 5632a3e3873SBaptiste Daroussin /* 5642a3e3873SBaptiste Daroussin * Display a set of items as a tree. 5652a3e3873SBaptiste Daroussin */ 5662a3e3873SBaptiste Daroussin int 5672a3e3873SBaptiste Daroussin dialog_treeview(const char *title, 5682a3e3873SBaptiste Daroussin const char *cprompt, 5692a3e3873SBaptiste Daroussin int height, 5702a3e3873SBaptiste Daroussin int width, 5712a3e3873SBaptiste Daroussin int list_height, 5722a3e3873SBaptiste Daroussin int item_no, 5732a3e3873SBaptiste Daroussin char **items, 5742a3e3873SBaptiste Daroussin int flag) 5752a3e3873SBaptiste Daroussin { 5762a3e3873SBaptiste Daroussin int result; 5772a3e3873SBaptiste Daroussin int i, j; 5782a3e3873SBaptiste Daroussin DIALOG_LISTITEM *listitems; 5792a3e3873SBaptiste Daroussin int *depths; 5802a3e3873SBaptiste Daroussin bool show_status = FALSE; 5812a3e3873SBaptiste Daroussin int current = 0; 582*febdb468SDevin Teske char *help_result; 5832a3e3873SBaptiste Daroussin 5842a3e3873SBaptiste Daroussin listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 5852a3e3873SBaptiste Daroussin assert_ptr(listitems, "dialog_treeview"); 5862a3e3873SBaptiste Daroussin 5872a3e3873SBaptiste Daroussin depths = dlg_calloc(int, (size_t) item_no + 1); 5882a3e3873SBaptiste Daroussin assert_ptr(depths, "dialog_treeview"); 5892a3e3873SBaptiste Daroussin 5902a3e3873SBaptiste Daroussin for (i = j = 0; i < item_no; ++i) { 5912a3e3873SBaptiste Daroussin listitems[i].name = items[j++]; 5922a3e3873SBaptiste Daroussin listitems[i].text = (dialog_vars.no_items 5932a3e3873SBaptiste Daroussin ? dlg_strempty() 5942a3e3873SBaptiste Daroussin : items[j++]); 5952a3e3873SBaptiste Daroussin listitems[i].state = !dlg_strcmp(items[j++], "on"); 5962a3e3873SBaptiste Daroussin depths[i] = atoi(items[j++]); 5972a3e3873SBaptiste Daroussin listitems[i].help = ((dialog_vars.item_help) 5982a3e3873SBaptiste Daroussin ? items[j++] 5992a3e3873SBaptiste Daroussin : dlg_strempty()); 6002a3e3873SBaptiste Daroussin } 6012a3e3873SBaptiste Daroussin dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6022a3e3873SBaptiste Daroussin 6032a3e3873SBaptiste Daroussin result = dlg_treeview(title, 6042a3e3873SBaptiste Daroussin cprompt, 6052a3e3873SBaptiste Daroussin height, 6062a3e3873SBaptiste Daroussin width, 6072a3e3873SBaptiste Daroussin list_height, 6082a3e3873SBaptiste Daroussin item_no, 6092a3e3873SBaptiste Daroussin listitems, 6102a3e3873SBaptiste Daroussin NULL, 6112a3e3873SBaptiste Daroussin depths, 6122a3e3873SBaptiste Daroussin flag, 6132a3e3873SBaptiste Daroussin ¤t); 6142a3e3873SBaptiste Daroussin 6152a3e3873SBaptiste Daroussin switch (result) { 6162a3e3873SBaptiste Daroussin case DLG_EXIT_OK: /* FALLTHRU */ 6172a3e3873SBaptiste Daroussin case DLG_EXIT_EXTRA: 6182a3e3873SBaptiste Daroussin show_status = TRUE; 6192a3e3873SBaptiste Daroussin break; 6202a3e3873SBaptiste Daroussin case DLG_EXIT_HELP: 621*febdb468SDevin Teske dlg_add_help_listitem(&result, &help_result, &listitems[current]); 622*febdb468SDevin Teske if ((show_status = dialog_vars.help_status)) { 6232a3e3873SBaptiste Daroussin if (dialog_vars.separate_output) { 624*febdb468SDevin Teske dlg_add_string(help_result); 6252a3e3873SBaptiste Daroussin dlg_add_separator(); 6262a3e3873SBaptiste Daroussin } else { 627*febdb468SDevin Teske dlg_add_quoted(help_result); 6282a3e3873SBaptiste Daroussin } 6292a3e3873SBaptiste Daroussin } else { 630*febdb468SDevin Teske dlg_add_string(help_result); 6312a3e3873SBaptiste Daroussin } 6322a3e3873SBaptiste Daroussin break; 6332a3e3873SBaptiste Daroussin } 6342a3e3873SBaptiste Daroussin 6352a3e3873SBaptiste Daroussin if (show_status) { 6362a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 6372a3e3873SBaptiste Daroussin if (listitems[i].state) { 6382a3e3873SBaptiste Daroussin if (dialog_vars.separate_output) { 6392a3e3873SBaptiste Daroussin dlg_add_string(listitems[i].name); 6402a3e3873SBaptiste Daroussin dlg_add_separator(); 6412a3e3873SBaptiste Daroussin } else { 6422a3e3873SBaptiste Daroussin if (dlg_need_separator()) 6432a3e3873SBaptiste Daroussin dlg_add_separator(); 6442a3e3873SBaptiste Daroussin if (flag == FLAG_CHECK) 6452a3e3873SBaptiste Daroussin dlg_add_quoted(listitems[i].name); 6462a3e3873SBaptiste Daroussin else 6472a3e3873SBaptiste Daroussin dlg_add_string(listitems[i].name); 6482a3e3873SBaptiste Daroussin } 6492a3e3873SBaptiste Daroussin } 6502a3e3873SBaptiste Daroussin } 6512a3e3873SBaptiste Daroussin dlg_add_last_key(-1); 6522a3e3873SBaptiste Daroussin } 6532a3e3873SBaptiste Daroussin 6542a3e3873SBaptiste Daroussin dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6552a3e3873SBaptiste Daroussin free(depths); 6562a3e3873SBaptiste Daroussin free(listitems); 6572a3e3873SBaptiste Daroussin return result; 6582a3e3873SBaptiste Daroussin } 659