12a3e3873SBaptiste Daroussin /* 2*f4f33ea0SBaptiste Daroussin * $Id: treeview.c,v 1.32 2018/06/19 22:57:01 tom Exp $ 32a3e3873SBaptiste Daroussin * 42a3e3873SBaptiste Daroussin * treeview.c -- implements the treeview dialog 52a3e3873SBaptiste Daroussin * 6*f4f33ea0SBaptiste Daroussin * Copyright 2012-2016,2018 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 */ 70*f4f33ea0SBaptiste Daroussin dlg_attrset(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); 76*f4f33ea0SBaptiste Daroussin dlg_attrset(win, selected ? check_selected_attr : check_attr); 772a3e3873SBaptiste Daroussin (void) wprintw(win, 782a3e3873SBaptiste Daroussin data->is_check ? "[%c]" : "(%c)", 792a3e3873SBaptiste Daroussin states[item->state]); 80*f4f33ea0SBaptiste Daroussin dlg_attrset(win, menubox_attr); 812a3e3873SBaptiste Daroussin 82*f4f33ea0SBaptiste Daroussin dlg_attrset(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 } 97*f4f33ea0SBaptiste Daroussin dlg_attrset(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) ), 188*f4f33ea0SBaptiste Daroussin TOGGLEKEY_BINDINGS, 1892a3e3873SBaptiste Daroussin END_KEYS_BINDING 1902a3e3873SBaptiste Daroussin }; 1912a3e3873SBaptiste Daroussin /* *INDENT-ON* */ 1922a3e3873SBaptiste Daroussin 1932a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 1942a3e3873SBaptiste Daroussin int old_height = height; 1952a3e3873SBaptiste Daroussin int old_width = width; 1962a3e3873SBaptiste Daroussin #endif 1972a3e3873SBaptiste Daroussin ALL_DATA all; 1982a3e3873SBaptiste Daroussin int i, j, key2, found, x, y, cur_y, box_x, box_y; 1992a3e3873SBaptiste Daroussin int key = 0, fkey; 2002a3e3873SBaptiste Daroussin int button = dialog_state.visit_items ? -1 : dlg_default_button(); 2012a3e3873SBaptiste Daroussin int choice = dlg_default_listitem(items); 2022a3e3873SBaptiste Daroussin int scrollamt = 0; 2032a3e3873SBaptiste Daroussin int max_choice; 2042a3e3873SBaptiste Daroussin int was_mouse; 2052a3e3873SBaptiste Daroussin int use_height; 2062a3e3873SBaptiste Daroussin int use_width, name_width, text_width, tree_width; 2072a3e3873SBaptiste Daroussin int result = DLG_EXIT_UNKNOWN; 2082a3e3873SBaptiste Daroussin int num_states; 2092a3e3873SBaptiste Daroussin WINDOW *dialog, *list; 2102a3e3873SBaptiste Daroussin char *prompt = dlg_strclone(cprompt); 2112a3e3873SBaptiste Daroussin const char **buttons = dlg_ok_labels(); 2122a3e3873SBaptiste Daroussin const char *widget_name; 2132a3e3873SBaptiste Daroussin 2142a3e3873SBaptiste Daroussin /* we need at least two states */ 2152a3e3873SBaptiste Daroussin if (states == 0 || strlen(states) < 2) 2162a3e3873SBaptiste Daroussin states = " *"; 2172a3e3873SBaptiste Daroussin num_states = (int) strlen(states); 2182a3e3873SBaptiste Daroussin 219*f4f33ea0SBaptiste Daroussin dialog_state.plain_buttons = TRUE; 220*f4f33ea0SBaptiste Daroussin 2212a3e3873SBaptiste Daroussin memset(&all, 0, sizeof(all)); 2222a3e3873SBaptiste Daroussin all.items = items; 2232a3e3873SBaptiste Daroussin all.item_no = item_no; 2242a3e3873SBaptiste Daroussin all.states = states; 2252a3e3873SBaptiste Daroussin all.depths = depths; 2262a3e3873SBaptiste Daroussin 2272a3e3873SBaptiste Daroussin dlg_does_output(); 2282a3e3873SBaptiste Daroussin dlg_tab_correct_str(prompt); 2292a3e3873SBaptiste Daroussin 2302a3e3873SBaptiste Daroussin /* 2312a3e3873SBaptiste Daroussin * If this is a radiobutton list, ensure that no more than one item is 2322a3e3873SBaptiste Daroussin * selected initially. Allow none to be selected, since some users may 2332a3e3873SBaptiste Daroussin * wish to provide this flavor. 2342a3e3873SBaptiste Daroussin */ 2352a3e3873SBaptiste Daroussin if (flag == FLAG_RADIO) { 2362a3e3873SBaptiste Daroussin bool first = TRUE; 2372a3e3873SBaptiste Daroussin 2382a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 2392a3e3873SBaptiste Daroussin if (items[i].state) { 2402a3e3873SBaptiste Daroussin if (first) { 2412a3e3873SBaptiste Daroussin first = FALSE; 2422a3e3873SBaptiste Daroussin } else { 2432a3e3873SBaptiste Daroussin items[i].state = 0; 2442a3e3873SBaptiste Daroussin } 2452a3e3873SBaptiste Daroussin } 2462a3e3873SBaptiste Daroussin } 2472a3e3873SBaptiste Daroussin } else { 2482a3e3873SBaptiste Daroussin all.is_check = TRUE; 2492a3e3873SBaptiste Daroussin } 2502a3e3873SBaptiste Daroussin widget_name = "treeview"; 2512a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 2522a3e3873SBaptiste Daroussin retry: 2532a3e3873SBaptiste Daroussin #endif 2542a3e3873SBaptiste Daroussin 2552a3e3873SBaptiste Daroussin use_height = list_height; 2562a3e3873SBaptiste Daroussin use_width = dlg_calc_list_width(item_no, items) + 10; 2572a3e3873SBaptiste Daroussin use_width = MAX(26, use_width); 2582a3e3873SBaptiste Daroussin if (use_height == 0) { 2592a3e3873SBaptiste Daroussin /* calculate height without items (4) */ 2602a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 2612a3e3873SBaptiste Daroussin dlg_calc_listh(&height, &use_height, item_no); 2622a3e3873SBaptiste Daroussin } else { 2632a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, use_width); 2642a3e3873SBaptiste Daroussin } 2652a3e3873SBaptiste Daroussin dlg_button_layout(buttons, &width); 2662a3e3873SBaptiste Daroussin dlg_print_size(height, width); 2672a3e3873SBaptiste Daroussin dlg_ctl_size(height, width); 2682a3e3873SBaptiste Daroussin 2692a3e3873SBaptiste Daroussin x = dlg_box_x_ordinate(width); 2702a3e3873SBaptiste Daroussin y = dlg_box_y_ordinate(height); 2712a3e3873SBaptiste Daroussin 2722a3e3873SBaptiste Daroussin dialog = dlg_new_window(height, width, y, x); 2732a3e3873SBaptiste Daroussin dlg_register_window(dialog, widget_name, binding); 2742a3e3873SBaptiste Daroussin dlg_register_buttons(dialog, widget_name, buttons); 2752a3e3873SBaptiste Daroussin 2762a3e3873SBaptiste Daroussin dlg_mouse_setbase(x, y); 2772a3e3873SBaptiste Daroussin 2782a3e3873SBaptiste Daroussin dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 2792a3e3873SBaptiste Daroussin dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 2802a3e3873SBaptiste Daroussin dlg_draw_title(dialog, title); 2812a3e3873SBaptiste Daroussin 282*f4f33ea0SBaptiste Daroussin dlg_attrset(dialog, dialog_attr); 2832a3e3873SBaptiste Daroussin dlg_print_autowrap(dialog, prompt, height, width); 2842a3e3873SBaptiste Daroussin 2852a3e3873SBaptiste Daroussin all.use_width = width - 4; 2862a3e3873SBaptiste Daroussin cur_y = getcury(dialog); 2872a3e3873SBaptiste Daroussin box_y = cur_y + 1; 2882a3e3873SBaptiste Daroussin box_x = (width - all.use_width) / 2 - 1; 2892a3e3873SBaptiste Daroussin 2902a3e3873SBaptiste Daroussin /* 2912a3e3873SBaptiste Daroussin * After displaying the prompt, we know how much space we really have. 2922a3e3873SBaptiste Daroussin * Limit the list to avoid overwriting the ok-button. 2932a3e3873SBaptiste Daroussin */ 2942a3e3873SBaptiste Daroussin if (use_height + MIN_HIGH > height - cur_y) 2952a3e3873SBaptiste Daroussin use_height = height - MIN_HIGH - cur_y; 2962a3e3873SBaptiste Daroussin if (use_height <= 0) 2972a3e3873SBaptiste Daroussin use_height = 1; 2982a3e3873SBaptiste Daroussin 2992a3e3873SBaptiste Daroussin max_choice = MIN(use_height, item_no); 3002a3e3873SBaptiste Daroussin 3012a3e3873SBaptiste Daroussin /* create new window for the list */ 3022a3e3873SBaptiste Daroussin list = dlg_sub_window(dialog, use_height, all.use_width, 3032a3e3873SBaptiste Daroussin y + box_y + 1, x + box_x + 1); 3042a3e3873SBaptiste Daroussin 3052a3e3873SBaptiste Daroussin /* draw a box around the list items */ 3062a3e3873SBaptiste Daroussin dlg_draw_box(dialog, box_y, box_x, 3072a3e3873SBaptiste Daroussin use_height + 2 * MARGIN, 3082a3e3873SBaptiste Daroussin all.use_width + 2 * MARGIN, 3092a3e3873SBaptiste Daroussin menubox_border_attr, menubox_border2_attr); 3102a3e3873SBaptiste Daroussin 3112a3e3873SBaptiste Daroussin text_width = 0; 3122a3e3873SBaptiste Daroussin name_width = 0; 3132a3e3873SBaptiste Daroussin tree_width = 0; 3142a3e3873SBaptiste Daroussin /* Find length of longest item to center treeview */ 3152a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 3162a3e3873SBaptiste Daroussin tree_width = MAX(tree_width, INDENT * depths[i]); 3172a3e3873SBaptiste Daroussin text_width = MAX(text_width, dlg_count_columns(items[i].text)); 3182a3e3873SBaptiste Daroussin name_width = MAX(name_width, dlg_count_columns(items[i].name)); 3192a3e3873SBaptiste Daroussin } 3202a3e3873SBaptiste Daroussin if (dialog_vars.no_tags && !dialog_vars.no_items) { 3212a3e3873SBaptiste Daroussin tree_width += text_width; 3222a3e3873SBaptiste Daroussin } else if (dialog_vars.no_items) { 3232a3e3873SBaptiste Daroussin tree_width += name_width; 3242a3e3873SBaptiste Daroussin } else { 3252a3e3873SBaptiste Daroussin tree_width += (text_width + name_width); 3262a3e3873SBaptiste Daroussin } 3272a3e3873SBaptiste Daroussin 3282a3e3873SBaptiste Daroussin use_width = (all.use_width - 4); 3292a3e3873SBaptiste Daroussin tree_width = MIN(tree_width, all.use_width); 3302a3e3873SBaptiste Daroussin 3312a3e3873SBaptiste Daroussin all.check_x = (use_width - tree_width) / 2; 3322a3e3873SBaptiste Daroussin all.item_x = ((dialog_vars.no_tags 3332a3e3873SBaptiste Daroussin ? 0 3342a3e3873SBaptiste Daroussin : (dialog_vars.no_items 3352a3e3873SBaptiste Daroussin ? 0 3362a3e3873SBaptiste Daroussin : (2 + name_width))) 3372a3e3873SBaptiste Daroussin + all.check_x + 4); 3382a3e3873SBaptiste Daroussin 3392a3e3873SBaptiste Daroussin /* ensure we are scrolled to show the current choice */ 3402a3e3873SBaptiste Daroussin if (choice >= (max_choice + scrollamt)) { 3412a3e3873SBaptiste Daroussin scrollamt = choice - max_choice + 1; 3422a3e3873SBaptiste Daroussin choice = max_choice - 1; 3432a3e3873SBaptiste Daroussin } 3442a3e3873SBaptiste Daroussin 3452a3e3873SBaptiste Daroussin /* register the new window, along with its borders */ 3462a3e3873SBaptiste Daroussin dlg_mouse_mkbigregion(box_y + 1, box_x, 3472a3e3873SBaptiste Daroussin use_height, all.use_width + 2, 3482a3e3873SBaptiste Daroussin KEY_MAX, 1, 1, 1 /* by lines */ ); 3492a3e3873SBaptiste Daroussin 3502a3e3873SBaptiste Daroussin all.dialog = dialog; 3512a3e3873SBaptiste Daroussin all.box_x = box_x; 3522a3e3873SBaptiste Daroussin all.box_y = box_y; 3532a3e3873SBaptiste Daroussin all.use_height = use_height; 3542a3e3873SBaptiste Daroussin all.list = list; 3552a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 3562a3e3873SBaptiste Daroussin 3572a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 3582a3e3873SBaptiste Daroussin 3592a3e3873SBaptiste Daroussin dlg_trace_win(dialog); 3602a3e3873SBaptiste Daroussin while (result == DLG_EXIT_UNKNOWN) { 3612a3e3873SBaptiste Daroussin if (button < 0) /* --visit-items */ 3622a3e3873SBaptiste Daroussin wmove(dialog, box_y + choice + 1, box_x + all.check_x + 2); 3632a3e3873SBaptiste Daroussin 3642a3e3873SBaptiste Daroussin key = dlg_mouse_wgetch(dialog, &fkey); 3652a3e3873SBaptiste Daroussin if (dlg_result_key(key, fkey, &result)) 3662a3e3873SBaptiste Daroussin break; 3672a3e3873SBaptiste Daroussin 3682a3e3873SBaptiste Daroussin was_mouse = (fkey && is_DLGK_MOUSE(key)); 3692a3e3873SBaptiste Daroussin if (was_mouse) 3702a3e3873SBaptiste Daroussin key -= M_EVENT; 3712a3e3873SBaptiste Daroussin 3722a3e3873SBaptiste Daroussin if (was_mouse && (key >= KEY_MAX)) { 3732a3e3873SBaptiste Daroussin i = (key - KEY_MAX); 3742a3e3873SBaptiste Daroussin if (i < max_choice) { 3752a3e3873SBaptiste Daroussin choice = (key - KEY_MAX); 3762a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 3772a3e3873SBaptiste Daroussin 378*f4f33ea0SBaptiste Daroussin key = DLGK_TOGGLE; /* force the selected item to toggle */ 3792a3e3873SBaptiste Daroussin } else { 3802a3e3873SBaptiste Daroussin beep(); 3812a3e3873SBaptiste Daroussin continue; 3822a3e3873SBaptiste Daroussin } 3832a3e3873SBaptiste Daroussin fkey = FALSE; 3842a3e3873SBaptiste Daroussin } else if (was_mouse && key >= KEY_MIN) { 3852a3e3873SBaptiste Daroussin key = dlg_lookup_key(dialog, key, &fkey); 3862a3e3873SBaptiste Daroussin } 3872a3e3873SBaptiste Daroussin 3882a3e3873SBaptiste Daroussin /* 3892a3e3873SBaptiste Daroussin * A space toggles the item status. 3902a3e3873SBaptiste Daroussin */ 391*f4f33ea0SBaptiste Daroussin if (key == DLGK_TOGGLE) { 3922a3e3873SBaptiste Daroussin int current = scrollamt + choice; 3932a3e3873SBaptiste Daroussin int next = items[current].state + 1; 3942a3e3873SBaptiste Daroussin 3952a3e3873SBaptiste Daroussin if (next >= num_states) 3962a3e3873SBaptiste Daroussin next = 0; 3972a3e3873SBaptiste Daroussin 3982a3e3873SBaptiste Daroussin if (flag == FLAG_CHECK) { /* checklist? */ 3992a3e3873SBaptiste Daroussin items[current].state = next; 4002a3e3873SBaptiste Daroussin } else { 4012a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 4022a3e3873SBaptiste Daroussin if (i != current) { 4032a3e3873SBaptiste Daroussin items[i].state = 0; 4042a3e3873SBaptiste Daroussin } 4052a3e3873SBaptiste Daroussin } 4062a3e3873SBaptiste Daroussin if (items[current].state) { 4072a3e3873SBaptiste Daroussin items[current].state = next ? next : 1; 4082a3e3873SBaptiste Daroussin } else { 4092a3e3873SBaptiste Daroussin items[current].state = 1; 4102a3e3873SBaptiste Daroussin } 4112a3e3873SBaptiste Daroussin } 4122a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 4132a3e3873SBaptiste Daroussin continue; /* wait for another key press */ 4142a3e3873SBaptiste Daroussin } 4152a3e3873SBaptiste Daroussin 4162a3e3873SBaptiste Daroussin /* 4172a3e3873SBaptiste Daroussin * Check if key pressed matches first character of any item tag in 4182a3e3873SBaptiste Daroussin * list. If there is more than one match, we will cycle through 4192a3e3873SBaptiste Daroussin * each one as the same key is pressed repeatedly. 4202a3e3873SBaptiste Daroussin */ 4212a3e3873SBaptiste Daroussin found = FALSE; 4222a3e3873SBaptiste Daroussin if (!fkey) { 4232a3e3873SBaptiste Daroussin if (button < 0 || !dialog_state.visit_items) { 4242a3e3873SBaptiste Daroussin for (j = scrollamt + choice + 1; j < item_no; j++) { 4252a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4262a3e3873SBaptiste Daroussin found = TRUE; 4272a3e3873SBaptiste Daroussin i = j - scrollamt; 4282a3e3873SBaptiste Daroussin break; 4292a3e3873SBaptiste Daroussin } 4302a3e3873SBaptiste Daroussin } 4312a3e3873SBaptiste Daroussin if (!found) { 4322a3e3873SBaptiste Daroussin for (j = 0; j <= scrollamt + choice; j++) { 4332a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4342a3e3873SBaptiste Daroussin found = TRUE; 4352a3e3873SBaptiste Daroussin i = j - scrollamt; 4362a3e3873SBaptiste Daroussin break; 4372a3e3873SBaptiste Daroussin } 4382a3e3873SBaptiste Daroussin } 4392a3e3873SBaptiste Daroussin } 4402a3e3873SBaptiste Daroussin if (found) 4412a3e3873SBaptiste Daroussin dlg_flush_getc(); 4422a3e3873SBaptiste Daroussin } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 4432a3e3873SBaptiste Daroussin button = j; 4442a3e3873SBaptiste Daroussin ungetch('\n'); 4452a3e3873SBaptiste Daroussin continue; 4462a3e3873SBaptiste Daroussin } 4472a3e3873SBaptiste Daroussin } 4482a3e3873SBaptiste Daroussin 4492a3e3873SBaptiste Daroussin /* 4502a3e3873SBaptiste Daroussin * A single digit (1-9) positions the selection to that line in the 4512a3e3873SBaptiste Daroussin * current screen. 4522a3e3873SBaptiste Daroussin */ 4532a3e3873SBaptiste Daroussin if (!found 4542a3e3873SBaptiste Daroussin && (key <= '9') 4552a3e3873SBaptiste Daroussin && (key > '0') 4562a3e3873SBaptiste Daroussin && (key - '1' < max_choice)) { 4572a3e3873SBaptiste Daroussin found = TRUE; 4582a3e3873SBaptiste Daroussin i = key - '1'; 4592a3e3873SBaptiste Daroussin } 4602a3e3873SBaptiste Daroussin 4612a3e3873SBaptiste Daroussin if (!found) { 4622a3e3873SBaptiste Daroussin if (fkey) { 4632a3e3873SBaptiste Daroussin found = TRUE; 4642a3e3873SBaptiste Daroussin switch (key) { 4652a3e3873SBaptiste Daroussin case DLGK_ITEM_FIRST: 4662a3e3873SBaptiste Daroussin i = -scrollamt; 4672a3e3873SBaptiste Daroussin break; 4682a3e3873SBaptiste Daroussin case DLGK_ITEM_LAST: 4692a3e3873SBaptiste Daroussin i = item_no - 1 - scrollamt; 4702a3e3873SBaptiste Daroussin break; 4712a3e3873SBaptiste Daroussin case DLGK_PAGE_PREV: 4722a3e3873SBaptiste Daroussin if (choice) 4732a3e3873SBaptiste Daroussin i = 0; 4742a3e3873SBaptiste Daroussin else if (scrollamt != 0) 4752a3e3873SBaptiste Daroussin i = -MIN(scrollamt, max_choice); 4762a3e3873SBaptiste Daroussin else 4772a3e3873SBaptiste Daroussin continue; 4782a3e3873SBaptiste Daroussin break; 4792a3e3873SBaptiste Daroussin case DLGK_PAGE_NEXT: 4802a3e3873SBaptiste Daroussin i = MIN(choice + max_choice, item_no - scrollamt - 1); 4812a3e3873SBaptiste Daroussin break; 4822a3e3873SBaptiste Daroussin case DLGK_ITEM_PREV: 4832a3e3873SBaptiste Daroussin i = choice - 1; 4842a3e3873SBaptiste Daroussin if (choice == 0 && scrollamt == 0) 4852a3e3873SBaptiste Daroussin continue; 4862a3e3873SBaptiste Daroussin break; 4872a3e3873SBaptiste Daroussin case DLGK_ITEM_NEXT: 4882a3e3873SBaptiste Daroussin i = choice + 1; 4892a3e3873SBaptiste Daroussin if (scrollamt + choice >= item_no - 1) 4902a3e3873SBaptiste Daroussin continue; 4912a3e3873SBaptiste Daroussin break; 4922a3e3873SBaptiste Daroussin default: 4932a3e3873SBaptiste Daroussin found = FALSE; 4942a3e3873SBaptiste Daroussin break; 4952a3e3873SBaptiste Daroussin } 4962a3e3873SBaptiste Daroussin } 4972a3e3873SBaptiste Daroussin } 4982a3e3873SBaptiste Daroussin 4992a3e3873SBaptiste Daroussin if (found) { 5002a3e3873SBaptiste Daroussin if (i != choice) { 5012a3e3873SBaptiste Daroussin if (i < 0 || i >= max_choice) { 5022a3e3873SBaptiste Daroussin if (i < 0) { 5032a3e3873SBaptiste Daroussin scrollamt += i; 5042a3e3873SBaptiste Daroussin choice = 0; 5052a3e3873SBaptiste Daroussin } else { 5062a3e3873SBaptiste Daroussin choice = max_choice - 1; 5072a3e3873SBaptiste Daroussin scrollamt += (i - max_choice + 1); 5082a3e3873SBaptiste Daroussin } 5092a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5102a3e3873SBaptiste Daroussin } else { 5112a3e3873SBaptiste Daroussin choice = i; 5122a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5132a3e3873SBaptiste Daroussin } 5142a3e3873SBaptiste Daroussin } 5152a3e3873SBaptiste Daroussin continue; /* wait for another key press */ 5162a3e3873SBaptiste Daroussin } 5172a3e3873SBaptiste Daroussin 5182a3e3873SBaptiste Daroussin if (fkey) { 5192a3e3873SBaptiste Daroussin switch (key) { 5202a3e3873SBaptiste Daroussin case DLGK_ENTER: 5212a3e3873SBaptiste Daroussin result = dlg_enter_buttoncode(button); 5222a3e3873SBaptiste Daroussin break; 5232a3e3873SBaptiste Daroussin case DLGK_FIELD_PREV: 5242a3e3873SBaptiste Daroussin button = dlg_prev_button(buttons, button); 5252a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5262a3e3873SBaptiste Daroussin FALSE, width); 5272a3e3873SBaptiste Daroussin break; 5282a3e3873SBaptiste Daroussin case DLGK_FIELD_NEXT: 5292a3e3873SBaptiste Daroussin button = dlg_next_button(buttons, button); 5302a3e3873SBaptiste Daroussin dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5312a3e3873SBaptiste Daroussin FALSE, width); 5322a3e3873SBaptiste Daroussin break; 5332a3e3873SBaptiste Daroussin #ifdef KEY_RESIZE 5342a3e3873SBaptiste Daroussin case KEY_RESIZE: 535*f4f33ea0SBaptiste Daroussin dlg_will_resize(dialog); 5362a3e3873SBaptiste Daroussin /* reset data */ 5372a3e3873SBaptiste Daroussin height = old_height; 5382a3e3873SBaptiste Daroussin width = old_width; 5392a3e3873SBaptiste Daroussin /* repaint */ 5402a3e3873SBaptiste Daroussin dlg_clear(); 5412a3e3873SBaptiste Daroussin dlg_del_window(dialog); 5422a3e3873SBaptiste Daroussin refresh(); 5432a3e3873SBaptiste Daroussin dlg_mouse_free_regions(); 5442a3e3873SBaptiste Daroussin goto retry; 5452a3e3873SBaptiste Daroussin #endif 5462a3e3873SBaptiste Daroussin default: 5472a3e3873SBaptiste Daroussin if (was_mouse) { 5482a3e3873SBaptiste Daroussin if ((key2 = dlg_ok_buttoncode(key)) >= 0) { 5492a3e3873SBaptiste Daroussin result = key2; 5502a3e3873SBaptiste Daroussin break; 5512a3e3873SBaptiste Daroussin } 5522a3e3873SBaptiste Daroussin beep(); 5532a3e3873SBaptiste Daroussin } 5542a3e3873SBaptiste Daroussin } 5552a3e3873SBaptiste Daroussin } else { 5562a3e3873SBaptiste Daroussin beep(); 5572a3e3873SBaptiste Daroussin } 5582a3e3873SBaptiste Daroussin } 5592a3e3873SBaptiste Daroussin 5602a3e3873SBaptiste Daroussin dlg_del_window(dialog); 5612a3e3873SBaptiste Daroussin dlg_mouse_free_regions(); 5622a3e3873SBaptiste Daroussin free(prompt); 5632a3e3873SBaptiste Daroussin *current_item = (scrollamt + choice); 5642a3e3873SBaptiste Daroussin return result; 5652a3e3873SBaptiste Daroussin } 5662a3e3873SBaptiste Daroussin 5672a3e3873SBaptiste Daroussin /* 5682a3e3873SBaptiste Daroussin * Display a set of items as a tree. 5692a3e3873SBaptiste Daroussin */ 5702a3e3873SBaptiste Daroussin int 5712a3e3873SBaptiste Daroussin dialog_treeview(const char *title, 5722a3e3873SBaptiste Daroussin const char *cprompt, 5732a3e3873SBaptiste Daroussin int height, 5742a3e3873SBaptiste Daroussin int width, 5752a3e3873SBaptiste Daroussin int list_height, 5762a3e3873SBaptiste Daroussin int item_no, 5772a3e3873SBaptiste Daroussin char **items, 5782a3e3873SBaptiste Daroussin int flag) 5792a3e3873SBaptiste Daroussin { 5802a3e3873SBaptiste Daroussin int result; 5812a3e3873SBaptiste Daroussin int i, j; 5822a3e3873SBaptiste Daroussin DIALOG_LISTITEM *listitems; 5832a3e3873SBaptiste Daroussin int *depths; 5842a3e3873SBaptiste Daroussin bool show_status = FALSE; 5852a3e3873SBaptiste Daroussin int current = 0; 586febdb468SDevin Teske char *help_result; 5872a3e3873SBaptiste Daroussin 588*f4f33ea0SBaptiste Daroussin DLG_TRACE(("# treeview args:\n")); 589*f4f33ea0SBaptiste Daroussin DLG_TRACE2S("title", title); 590*f4f33ea0SBaptiste Daroussin DLG_TRACE2S("message", cprompt); 591*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("height", height); 592*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("width", width); 593*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("lheight", list_height); 594*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("llength", item_no); 595*f4f33ea0SBaptiste Daroussin /* FIXME dump the items[][] too */ 596*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("flag", flag); 597*f4f33ea0SBaptiste Daroussin 5982a3e3873SBaptiste Daroussin listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 5992a3e3873SBaptiste Daroussin assert_ptr(listitems, "dialog_treeview"); 6002a3e3873SBaptiste Daroussin 6012a3e3873SBaptiste Daroussin depths = dlg_calloc(int, (size_t) item_no + 1); 6022a3e3873SBaptiste Daroussin assert_ptr(depths, "dialog_treeview"); 6032a3e3873SBaptiste Daroussin 6042a3e3873SBaptiste Daroussin for (i = j = 0; i < item_no; ++i) { 6052a3e3873SBaptiste Daroussin listitems[i].name = items[j++]; 6062a3e3873SBaptiste Daroussin listitems[i].text = (dialog_vars.no_items 6072a3e3873SBaptiste Daroussin ? dlg_strempty() 6082a3e3873SBaptiste Daroussin : items[j++]); 6092a3e3873SBaptiste Daroussin listitems[i].state = !dlg_strcmp(items[j++], "on"); 6102a3e3873SBaptiste Daroussin depths[i] = atoi(items[j++]); 6112a3e3873SBaptiste Daroussin listitems[i].help = ((dialog_vars.item_help) 6122a3e3873SBaptiste Daroussin ? items[j++] 6132a3e3873SBaptiste Daroussin : dlg_strempty()); 6142a3e3873SBaptiste Daroussin } 6152a3e3873SBaptiste Daroussin dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6162a3e3873SBaptiste Daroussin 6172a3e3873SBaptiste Daroussin result = dlg_treeview(title, 6182a3e3873SBaptiste Daroussin cprompt, 6192a3e3873SBaptiste Daroussin height, 6202a3e3873SBaptiste Daroussin width, 6212a3e3873SBaptiste Daroussin list_height, 6222a3e3873SBaptiste Daroussin item_no, 6232a3e3873SBaptiste Daroussin listitems, 6242a3e3873SBaptiste Daroussin NULL, 6252a3e3873SBaptiste Daroussin depths, 6262a3e3873SBaptiste Daroussin flag, 6272a3e3873SBaptiste Daroussin ¤t); 6282a3e3873SBaptiste Daroussin 6292a3e3873SBaptiste Daroussin switch (result) { 6302a3e3873SBaptiste Daroussin case DLG_EXIT_OK: /* FALLTHRU */ 6312a3e3873SBaptiste Daroussin case DLG_EXIT_EXTRA: 6322a3e3873SBaptiste Daroussin show_status = TRUE; 6332a3e3873SBaptiste Daroussin break; 6342a3e3873SBaptiste Daroussin case DLG_EXIT_HELP: 635febdb468SDevin Teske dlg_add_help_listitem(&result, &help_result, &listitems[current]); 636febdb468SDevin Teske if ((show_status = dialog_vars.help_status)) { 6372a3e3873SBaptiste Daroussin if (dialog_vars.separate_output) { 638febdb468SDevin Teske dlg_add_string(help_result); 6392a3e3873SBaptiste Daroussin dlg_add_separator(); 6402a3e3873SBaptiste Daroussin } else { 641febdb468SDevin Teske dlg_add_quoted(help_result); 6422a3e3873SBaptiste Daroussin } 6432a3e3873SBaptiste Daroussin } else { 644febdb468SDevin Teske dlg_add_string(help_result); 6452a3e3873SBaptiste Daroussin } 6462a3e3873SBaptiste Daroussin break; 6472a3e3873SBaptiste Daroussin } 6482a3e3873SBaptiste Daroussin 6492a3e3873SBaptiste Daroussin if (show_status) { 6502a3e3873SBaptiste Daroussin for (i = 0; i < item_no; i++) { 6512a3e3873SBaptiste Daroussin if (listitems[i].state) { 6522a3e3873SBaptiste Daroussin if (dialog_vars.separate_output) { 6532a3e3873SBaptiste Daroussin dlg_add_string(listitems[i].name); 6542a3e3873SBaptiste Daroussin dlg_add_separator(); 6552a3e3873SBaptiste Daroussin } else { 6562a3e3873SBaptiste Daroussin if (dlg_need_separator()) 6572a3e3873SBaptiste Daroussin dlg_add_separator(); 6582a3e3873SBaptiste Daroussin if (flag == FLAG_CHECK) 6592a3e3873SBaptiste Daroussin dlg_add_quoted(listitems[i].name); 6602a3e3873SBaptiste Daroussin else 6612a3e3873SBaptiste Daroussin dlg_add_string(listitems[i].name); 6622a3e3873SBaptiste Daroussin } 6632a3e3873SBaptiste Daroussin } 6642a3e3873SBaptiste Daroussin } 6652a3e3873SBaptiste Daroussin dlg_add_last_key(-1); 6662a3e3873SBaptiste Daroussin } 6672a3e3873SBaptiste Daroussin 6682a3e3873SBaptiste Daroussin dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6692a3e3873SBaptiste Daroussin free(depths); 6702a3e3873SBaptiste Daroussin free(listitems); 6712a3e3873SBaptiste Daroussin return result; 6722a3e3873SBaptiste Daroussin } 673