14c8945a0SNathan Whitehorn /* 2*f4f33ea0SBaptiste Daroussin * $Id: checklist.c,v 1.160 2018/06/19 22:57:01 tom Exp $ 34c8945a0SNathan Whitehorn * 44c8945a0SNathan Whitehorn * checklist.c -- implements the checklist box 54c8945a0SNathan Whitehorn * 6*f4f33ea0SBaptiste Daroussin * Copyright 2000-2016,2018 Thomas E. Dickey 74c8945a0SNathan Whitehorn * 84c8945a0SNathan Whitehorn * This program is free software; you can redistribute it and/or modify 94c8945a0SNathan Whitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 104c8945a0SNathan Whitehorn * as published by the Free Software Foundation. 114c8945a0SNathan Whitehorn * 124c8945a0SNathan Whitehorn * This program is distributed in the hope that it will be useful, but 134c8945a0SNathan Whitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 144c8945a0SNathan Whitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 154c8945a0SNathan Whitehorn * Lesser General Public License for more details. 164c8945a0SNathan Whitehorn * 174c8945a0SNathan Whitehorn * You should have received a copy of the GNU Lesser General Public 184c8945a0SNathan Whitehorn * License along with this program; if not, write to 194c8945a0SNathan Whitehorn * Free Software Foundation, Inc. 204c8945a0SNathan Whitehorn * 51 Franklin St., Fifth Floor 214c8945a0SNathan Whitehorn * Boston, MA 02110, USA. 224c8945a0SNathan Whitehorn * 234c8945a0SNathan Whitehorn * An earlier version of this program lists as authors: 244c8945a0SNathan Whitehorn * Savio Lam (lam836@cs.cuhk.hk) 254c8945a0SNathan Whitehorn * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension 264c8945a0SNathan Whitehorn * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two 274c8945a0SNathan Whitehorn */ 284c8945a0SNathan Whitehorn 294c8945a0SNathan Whitehorn #include <dialog.h> 304c8945a0SNathan Whitehorn #include <dlg_keys.h> 314c8945a0SNathan Whitehorn 324c8945a0SNathan Whitehorn #define MIN_HIGH (1 + (5 * MARGIN)) 334c8945a0SNathan Whitehorn 342a3e3873SBaptiste Daroussin typedef struct { 352a3e3873SBaptiste Daroussin /* the outer-window */ 362a3e3873SBaptiste Daroussin WINDOW *dialog; 372a3e3873SBaptiste Daroussin int box_y; 382a3e3873SBaptiste Daroussin int box_x; 392a3e3873SBaptiste Daroussin int check_x; 402a3e3873SBaptiste Daroussin int item_x; 412a3e3873SBaptiste Daroussin int checkflag; 422a3e3873SBaptiste Daroussin int use_height; 432a3e3873SBaptiste Daroussin int use_width; 442a3e3873SBaptiste Daroussin /* the inner-window */ 452a3e3873SBaptiste Daroussin WINDOW *list; 462a3e3873SBaptiste Daroussin DIALOG_LISTITEM *items; 472a3e3873SBaptiste Daroussin int item_no; 482a3e3873SBaptiste Daroussin const char *states; 492a3e3873SBaptiste Daroussin } ALL_DATA; 504c8945a0SNathan Whitehorn 514c8945a0SNathan Whitehorn /* 524c8945a0SNathan Whitehorn * Print list item. The 'selected' parameter is true if 'choice' is the 534c8945a0SNathan Whitehorn * current item. That one is colored differently from the other items. 544c8945a0SNathan Whitehorn */ 554c8945a0SNathan Whitehorn static void 562a3e3873SBaptiste Daroussin print_item(ALL_DATA * data, 572a3e3873SBaptiste Daroussin WINDOW *win, 584c8945a0SNathan Whitehorn DIALOG_LISTITEM * item, 594c8945a0SNathan Whitehorn const char *states, 604c8945a0SNathan Whitehorn int choice, 614c8945a0SNathan Whitehorn int selected) 624c8945a0SNathan Whitehorn { 637a1c0d96SNathan Whitehorn chtype save = dlg_get_attrs(win); 644c8945a0SNathan Whitehorn int i; 652a3e3873SBaptiste Daroussin bool both = (!dialog_vars.no_tags && !dialog_vars.no_items); 662a3e3873SBaptiste Daroussin bool first = TRUE; 672a3e3873SBaptiste Daroussin int climit = (getmaxx(win) - data->check_x + 1); 682a3e3873SBaptiste Daroussin const char *show = (dialog_vars.no_items 692a3e3873SBaptiste Daroussin ? item->name 702a3e3873SBaptiste Daroussin : item->text); 714c8945a0SNathan Whitehorn 724c8945a0SNathan Whitehorn /* Clear 'residue' of last item */ 73*f4f33ea0SBaptiste Daroussin dlg_attrset(win, menubox_attr); 744c8945a0SNathan Whitehorn (void) wmove(win, choice, 0); 752a3e3873SBaptiste Daroussin for (i = 0; i < data->use_width; i++) 764c8945a0SNathan Whitehorn (void) waddch(win, ' '); 774c8945a0SNathan Whitehorn 782a3e3873SBaptiste Daroussin (void) wmove(win, choice, data->check_x); 79*f4f33ea0SBaptiste Daroussin dlg_attrset(win, selected ? check_selected_attr : check_attr); 804c8945a0SNathan Whitehorn (void) wprintw(win, 812a3e3873SBaptiste Daroussin (data->checkflag == FLAG_CHECK) ? "[%c]" : "(%c)", 824c8945a0SNathan Whitehorn states[item->state]); 83*f4f33ea0SBaptiste Daroussin dlg_attrset(win, menubox_attr); 844c8945a0SNathan Whitehorn (void) waddch(win, ' '); 854c8945a0SNathan Whitehorn 862a3e3873SBaptiste Daroussin if (both) { 872a3e3873SBaptiste Daroussin dlg_print_listitem(win, item->name, climit, first, selected); 882a3e3873SBaptiste Daroussin first = FALSE; 894c8945a0SNathan Whitehorn } 904c8945a0SNathan Whitehorn 912a3e3873SBaptiste Daroussin (void) wmove(win, choice, data->item_x); 922a3e3873SBaptiste Daroussin dlg_print_listitem(win, show, climit, first, selected); 934c8945a0SNathan Whitehorn 944c8945a0SNathan Whitehorn if (selected) { 954c8945a0SNathan Whitehorn dlg_item_help(item->help); 964c8945a0SNathan Whitehorn } 97*f4f33ea0SBaptiste Daroussin dlg_attrset(win, save); 982a3e3873SBaptiste Daroussin } 992a3e3873SBaptiste Daroussin 1002a3e3873SBaptiste Daroussin static void 1012a3e3873SBaptiste Daroussin print_list(ALL_DATA * data, int choice, int scrollamt, int max_choice) 1022a3e3873SBaptiste Daroussin { 1032a3e3873SBaptiste Daroussin int i; 1042a3e3873SBaptiste Daroussin int cur_y, cur_x; 1052a3e3873SBaptiste Daroussin 1062a3e3873SBaptiste Daroussin getyx(data->dialog, cur_y, cur_x); 1072a3e3873SBaptiste Daroussin for (i = 0; i < max_choice; i++) { 1082a3e3873SBaptiste Daroussin print_item(data, 1092a3e3873SBaptiste Daroussin data->list, 1102a3e3873SBaptiste Daroussin &data->items[i + scrollamt], 1112a3e3873SBaptiste Daroussin data->states, 1122a3e3873SBaptiste Daroussin i, i == choice); 1132a3e3873SBaptiste Daroussin } 1142a3e3873SBaptiste Daroussin (void) wnoutrefresh(data->list); 1152a3e3873SBaptiste Daroussin 1162a3e3873SBaptiste Daroussin dlg_draw_scrollbar(data->dialog, 1172a3e3873SBaptiste Daroussin (long) (scrollamt), 1182a3e3873SBaptiste Daroussin (long) (scrollamt), 1192a3e3873SBaptiste Daroussin (long) (scrollamt + max_choice), 1202a3e3873SBaptiste Daroussin (long) (data->item_no), 1212a3e3873SBaptiste Daroussin data->box_x + data->check_x, 1222a3e3873SBaptiste Daroussin data->box_x + data->use_width, 1232a3e3873SBaptiste Daroussin data->box_y, 1242a3e3873SBaptiste Daroussin data->box_y + data->use_height + 1, 1252a3e3873SBaptiste Daroussin menubox_border2_attr, 1262a3e3873SBaptiste Daroussin menubox_border_attr); 1272a3e3873SBaptiste Daroussin 1282a3e3873SBaptiste Daroussin (void) wmove(data->dialog, cur_y, cur_x); 1292a3e3873SBaptiste Daroussin } 1302a3e3873SBaptiste Daroussin 1312a3e3873SBaptiste Daroussin static bool 1322a3e3873SBaptiste Daroussin check_hotkey(DIALOG_LISTITEM * items, int choice) 1332a3e3873SBaptiste Daroussin { 1342a3e3873SBaptiste Daroussin bool result = FALSE; 1352a3e3873SBaptiste Daroussin 1362a3e3873SBaptiste Daroussin if (dlg_match_char(dlg_last_getc(), 1372a3e3873SBaptiste Daroussin (dialog_vars.no_tags 1382a3e3873SBaptiste Daroussin ? items[choice].text 1392a3e3873SBaptiste Daroussin : items[choice].name))) { 1402a3e3873SBaptiste Daroussin result = TRUE; 1412a3e3873SBaptiste Daroussin } 1422a3e3873SBaptiste Daroussin return result; 1434c8945a0SNathan Whitehorn } 1444c8945a0SNathan Whitehorn 1454c8945a0SNathan Whitehorn /* 1464c8945a0SNathan Whitehorn * This is an alternate interface to 'checklist' which allows the application 1474c8945a0SNathan Whitehorn * to read the list item states back directly without putting them in the 1484c8945a0SNathan Whitehorn * output buffer. It also provides for more than two states over which the 1494c8945a0SNathan Whitehorn * check/radio box can display. 1504c8945a0SNathan Whitehorn */ 1514c8945a0SNathan Whitehorn int 1524c8945a0SNathan Whitehorn dlg_checklist(const char *title, 1534c8945a0SNathan Whitehorn const char *cprompt, 1544c8945a0SNathan Whitehorn int height, 1554c8945a0SNathan Whitehorn int width, 1564c8945a0SNathan Whitehorn int list_height, 1574c8945a0SNathan Whitehorn int item_no, 1584c8945a0SNathan Whitehorn DIALOG_LISTITEM * items, 1594c8945a0SNathan Whitehorn const char *states, 1604c8945a0SNathan Whitehorn int flag, 1614c8945a0SNathan Whitehorn int *current_item) 1624c8945a0SNathan Whitehorn { 1634c8945a0SNathan Whitehorn /* *INDENT-OFF* */ 1644c8945a0SNathan Whitehorn static DLG_KEYS_BINDING binding[] = { 165682c9e0fSNathan Whitehorn HELPKEY_BINDINGS, 1664c8945a0SNathan Whitehorn ENTERKEY_BINDINGS, 1674c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), 1684c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), 1694c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), 1704c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ), 1714c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ), 1724c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ), 1734c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ), 1744c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ), 1754c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), 1764c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), 1774c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ), 1784c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), 1794c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), 1804c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), 1814c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ), 1824c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ), 1834c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ), 184*f4f33ea0SBaptiste Daroussin TOGGLEKEY_BINDINGS, 1854c8945a0SNathan Whitehorn END_KEYS_BINDING 1864c8945a0SNathan Whitehorn }; 1874c8945a0SNathan Whitehorn /* *INDENT-ON* */ 1884c8945a0SNathan Whitehorn 1894c8945a0SNathan Whitehorn #ifdef KEY_RESIZE 1904c8945a0SNathan Whitehorn int old_height = height; 1914c8945a0SNathan Whitehorn int old_width = width; 1924c8945a0SNathan Whitehorn #endif 1932a3e3873SBaptiste Daroussin ALL_DATA all; 1942a3e3873SBaptiste Daroussin int i, j, key2, found, x, y, cur_x, cur_y; 1954c8945a0SNathan Whitehorn int key = 0, fkey; 1962a3e3873SBaptiste Daroussin int button = dialog_state.visit_items ? -1 : dlg_default_button(); 1974c8945a0SNathan Whitehorn int choice = dlg_default_listitem(items); 1984c8945a0SNathan Whitehorn int scrollamt = 0; 1994c8945a0SNathan Whitehorn int max_choice; 2004c8945a0SNathan Whitehorn int was_mouse; 2012a3e3873SBaptiste Daroussin int use_width, list_width, name_width, text_width; 2024c8945a0SNathan Whitehorn int result = DLG_EXIT_UNKNOWN; 2034c8945a0SNathan Whitehorn int num_states; 2042a3e3873SBaptiste Daroussin WINDOW *dialog; 205*f4f33ea0SBaptiste Daroussin char *prompt; 2064c8945a0SNathan Whitehorn const char **buttons = dlg_ok_labels(); 2072a3e3873SBaptiste Daroussin const char *widget_name; 2082a3e3873SBaptiste Daroussin 209*f4f33ea0SBaptiste Daroussin DLG_TRACE(("# %s args:\n", flag ? "checklist" : "radiolist")); 210*f4f33ea0SBaptiste Daroussin DLG_TRACE2S("title", title); 211*f4f33ea0SBaptiste Daroussin DLG_TRACE2S("message", cprompt); 212*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("height", height); 213*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("width", width); 214*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("lheight", list_height); 215*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("llength", item_no); 216*f4f33ea0SBaptiste Daroussin /* FIXME dump the items[][] too */ 217*f4f33ea0SBaptiste Daroussin DLG_TRACE2S("states", states); 218*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("flag", flag); 219*f4f33ea0SBaptiste Daroussin DLG_TRACE2N("current", *current_item); 220*f4f33ea0SBaptiste Daroussin 221*f4f33ea0SBaptiste Daroussin dialog_state.plain_buttons = TRUE; 222*f4f33ea0SBaptiste Daroussin 2232a3e3873SBaptiste Daroussin memset(&all, 0, sizeof(all)); 2242a3e3873SBaptiste Daroussin all.items = items; 2252a3e3873SBaptiste Daroussin all.item_no = item_no; 2264c8945a0SNathan Whitehorn 2274c8945a0SNathan Whitehorn dlg_does_output(); 2284c8945a0SNathan Whitehorn 229682c9e0fSNathan Whitehorn /* 230682c9e0fSNathan Whitehorn * If this is a radiobutton list, ensure that no more than one item is 231682c9e0fSNathan Whitehorn * selected initially. Allow none to be selected, since some users may 232682c9e0fSNathan Whitehorn * wish to provide this flavor. 233682c9e0fSNathan Whitehorn */ 234682c9e0fSNathan Whitehorn if (flag == FLAG_RADIO) { 235682c9e0fSNathan Whitehorn bool first = TRUE; 236682c9e0fSNathan Whitehorn 237682c9e0fSNathan Whitehorn for (i = 0; i < item_no; i++) { 238682c9e0fSNathan Whitehorn if (items[i].state) { 239682c9e0fSNathan Whitehorn if (first) { 240682c9e0fSNathan Whitehorn first = FALSE; 241682c9e0fSNathan Whitehorn } else { 242682c9e0fSNathan Whitehorn items[i].state = 0; 243682c9e0fSNathan Whitehorn } 244682c9e0fSNathan Whitehorn } 245682c9e0fSNathan Whitehorn } 2462a3e3873SBaptiste Daroussin widget_name = "radiolist"; 2472a3e3873SBaptiste Daroussin } else { 2482a3e3873SBaptiste Daroussin widget_name = "checklist"; 249682c9e0fSNathan Whitehorn } 2504c8945a0SNathan Whitehorn #ifdef KEY_RESIZE 2514c8945a0SNathan Whitehorn retry: 2524c8945a0SNathan Whitehorn #endif 2534c8945a0SNathan Whitehorn 254*f4f33ea0SBaptiste Daroussin prompt = dlg_strclone(cprompt); 255*f4f33ea0SBaptiste Daroussin dlg_tab_correct_str(prompt); 256*f4f33ea0SBaptiste Daroussin 2572a3e3873SBaptiste Daroussin all.use_height = list_height; 25819718649SNathan Whitehorn use_width = dlg_calc_list_width(item_no, items) + 10; 2592a3e3873SBaptiste Daroussin use_width = MAX(26, use_width); 2602a3e3873SBaptiste Daroussin if (all.use_height == 0) { 2614c8945a0SNathan Whitehorn /* calculate height without items (4) */ 2622a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 2632a3e3873SBaptiste Daroussin dlg_calc_listh(&height, &all.use_height, item_no); 2644c8945a0SNathan Whitehorn } else { 2652a3e3873SBaptiste Daroussin dlg_auto_size(title, prompt, 2662a3e3873SBaptiste Daroussin &height, &width, 2672a3e3873SBaptiste Daroussin MIN_HIGH + all.use_height, use_width); 2684c8945a0SNathan Whitehorn } 2694c8945a0SNathan Whitehorn dlg_button_layout(buttons, &width); 2704c8945a0SNathan Whitehorn dlg_print_size(height, width); 2714c8945a0SNathan Whitehorn dlg_ctl_size(height, width); 2724c8945a0SNathan Whitehorn 2734c8945a0SNathan Whitehorn /* we need at least two states */ 2744c8945a0SNathan Whitehorn if (states == 0 || strlen(states) < 2) 2754c8945a0SNathan Whitehorn states = " *"; 2764c8945a0SNathan Whitehorn num_states = (int) strlen(states); 2772a3e3873SBaptiste Daroussin all.states = states; 2784c8945a0SNathan Whitehorn 2792a3e3873SBaptiste Daroussin all.checkflag = flag; 2804c8945a0SNathan Whitehorn 2814c8945a0SNathan Whitehorn x = dlg_box_x_ordinate(width); 2824c8945a0SNathan Whitehorn y = dlg_box_y_ordinate(height); 2834c8945a0SNathan Whitehorn 2844c8945a0SNathan Whitehorn dialog = dlg_new_window(height, width, y, x); 2852a3e3873SBaptiste Daroussin all.dialog = dialog; 2862a3e3873SBaptiste Daroussin dlg_register_window(dialog, widget_name, binding); 2872a3e3873SBaptiste Daroussin dlg_register_buttons(dialog, widget_name, buttons); 2884c8945a0SNathan Whitehorn 2894c8945a0SNathan Whitehorn dlg_mouse_setbase(x, y); 2904c8945a0SNathan Whitehorn 2912a3e3873SBaptiste Daroussin dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 2922a3e3873SBaptiste Daroussin dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 2934c8945a0SNathan Whitehorn dlg_draw_title(dialog, title); 2944c8945a0SNathan Whitehorn 295*f4f33ea0SBaptiste Daroussin dlg_attrset(dialog, dialog_attr); 2964c8945a0SNathan Whitehorn dlg_print_autowrap(dialog, prompt, height, width); 2974c8945a0SNathan Whitehorn 2982a3e3873SBaptiste Daroussin all.use_width = width - 6; 2994c8945a0SNathan Whitehorn getyx(dialog, cur_y, cur_x); 3002a3e3873SBaptiste Daroussin all.box_y = cur_y + 1; 3012a3e3873SBaptiste Daroussin all.box_x = (width - all.use_width) / 2 - 1; 3024c8945a0SNathan Whitehorn 3034c8945a0SNathan Whitehorn /* 3044c8945a0SNathan Whitehorn * After displaying the prompt, we know how much space we really have. 3054c8945a0SNathan Whitehorn * Limit the list to avoid overwriting the ok-button. 3064c8945a0SNathan Whitehorn */ 3072a3e3873SBaptiste Daroussin if (all.use_height + MIN_HIGH > height - cur_y) 3082a3e3873SBaptiste Daroussin all.use_height = height - MIN_HIGH - cur_y; 3092a3e3873SBaptiste Daroussin if (all.use_height <= 0) 3102a3e3873SBaptiste Daroussin all.use_height = 1; 3114c8945a0SNathan Whitehorn 3122a3e3873SBaptiste Daroussin max_choice = MIN(all.use_height, item_no); 3132a3e3873SBaptiste Daroussin max_choice = MAX(max_choice, 1); 3144c8945a0SNathan Whitehorn 3154c8945a0SNathan Whitehorn /* create new window for the list */ 3162a3e3873SBaptiste Daroussin all.list = dlg_sub_window(dialog, all.use_height, all.use_width, 3172a3e3873SBaptiste Daroussin y + all.box_y + 1, x + all.box_x + 1); 3184c8945a0SNathan Whitehorn 3194c8945a0SNathan Whitehorn /* draw a box around the list items */ 3202a3e3873SBaptiste Daroussin dlg_draw_box(dialog, all.box_y, all.box_x, 3212a3e3873SBaptiste Daroussin all.use_height + 2 * MARGIN, 3222a3e3873SBaptiste Daroussin all.use_width + 2 * MARGIN, 3232a3e3873SBaptiste Daroussin menubox_border_attr, menubox_border2_attr); 3244c8945a0SNathan Whitehorn 3254c8945a0SNathan Whitehorn text_width = 0; 3264c8945a0SNathan Whitehorn name_width = 0; 3274c8945a0SNathan Whitehorn /* Find length of longest item to center checklist */ 3284c8945a0SNathan Whitehorn for (i = 0; i < item_no; i++) { 3294c8945a0SNathan Whitehorn text_width = MAX(text_width, dlg_count_columns(items[i].text)); 3304c8945a0SNathan Whitehorn name_width = MAX(name_width, dlg_count_columns(items[i].name)); 3314c8945a0SNathan Whitehorn } 3324c8945a0SNathan Whitehorn 3334c8945a0SNathan Whitehorn /* If the name+text is wider than the list is allowed, then truncate 3344c8945a0SNathan Whitehorn * one or both of them. If the name is no wider than 1/4 of the list, 3354c8945a0SNathan Whitehorn * leave it intact. 3364c8945a0SNathan Whitehorn */ 3372a3e3873SBaptiste Daroussin use_width = (all.use_width - 6); 3382a3e3873SBaptiste Daroussin if (dialog_vars.no_tags) { 3392a3e3873SBaptiste Daroussin list_width = MIN(all.use_width, text_width); 3402a3e3873SBaptiste Daroussin } else if (dialog_vars.no_items) { 3412a3e3873SBaptiste Daroussin list_width = MIN(all.use_width, name_width); 3422a3e3873SBaptiste Daroussin } else { 3432a3e3873SBaptiste Daroussin if (text_width >= 0 3442a3e3873SBaptiste Daroussin && name_width >= 0 3452a3e3873SBaptiste Daroussin && use_width > 0 3462a3e3873SBaptiste Daroussin && text_width + name_width > use_width) { 3474c8945a0SNathan Whitehorn int need = (int) (0.25 * use_width); 3484c8945a0SNathan Whitehorn if (name_width > need) { 3494c8945a0SNathan Whitehorn int want = (int) (use_width * ((double) name_width) / 3504c8945a0SNathan Whitehorn (text_width + name_width)); 3514c8945a0SNathan Whitehorn name_width = (want > need) ? want : need; 3524c8945a0SNathan Whitehorn } 3534c8945a0SNathan Whitehorn text_width = use_width - name_width; 3544c8945a0SNathan Whitehorn } 3552a3e3873SBaptiste Daroussin list_width = (text_width + name_width); 3562a3e3873SBaptiste Daroussin } 3574c8945a0SNathan Whitehorn 3582a3e3873SBaptiste Daroussin all.check_x = (use_width - list_width) / 2; 3592a3e3873SBaptiste Daroussin all.item_x = ((dialog_vars.no_tags 3602a3e3873SBaptiste Daroussin ? 0 3612a3e3873SBaptiste Daroussin : (dialog_vars.no_items 3622a3e3873SBaptiste Daroussin ? 0 3632a3e3873SBaptiste Daroussin : (2 + name_width))) 3642a3e3873SBaptiste Daroussin + all.check_x + 4); 3654c8945a0SNathan Whitehorn 3664c8945a0SNathan Whitehorn /* ensure we are scrolled to show the current choice */ 3672a3e3873SBaptiste Daroussin scrollamt = MIN(scrollamt, max_choice + item_no - 1); 3682a3e3873SBaptiste Daroussin if (choice >= (max_choice + scrollamt - 1)) { 3692a3e3873SBaptiste Daroussin scrollamt = MAX(0, choice - max_choice + 1); 3704c8945a0SNathan Whitehorn choice = max_choice - 1; 3714c8945a0SNathan Whitehorn } 3722a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 3734c8945a0SNathan Whitehorn 3744c8945a0SNathan Whitehorn /* register the new window, along with its borders */ 3752a3e3873SBaptiste Daroussin dlg_mouse_mkbigregion(all.box_y + 1, all.box_x, 3762a3e3873SBaptiste Daroussin all.use_height, all.use_width + 2, 3774c8945a0SNathan Whitehorn KEY_MAX, 1, 1, 1 /* by lines */ ); 3784c8945a0SNathan Whitehorn 3794c8945a0SNathan Whitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 3804c8945a0SNathan Whitehorn 3812a3e3873SBaptiste Daroussin dlg_trace_win(dialog); 3824c8945a0SNathan Whitehorn while (result == DLG_EXIT_UNKNOWN) { 3834c8945a0SNathan Whitehorn if (button < 0) /* --visit-items */ 3842a3e3873SBaptiste Daroussin wmove(dialog, all.box_y + choice + 1, all.box_x + all.check_x + 2); 3854c8945a0SNathan Whitehorn 3864c8945a0SNathan Whitehorn key = dlg_mouse_wgetch(dialog, &fkey); 3874c8945a0SNathan Whitehorn if (dlg_result_key(key, fkey, &result)) 3884c8945a0SNathan Whitehorn break; 3894c8945a0SNathan Whitehorn 3904c8945a0SNathan Whitehorn was_mouse = (fkey && is_DLGK_MOUSE(key)); 3914c8945a0SNathan Whitehorn if (was_mouse) 3924c8945a0SNathan Whitehorn key -= M_EVENT; 3934c8945a0SNathan Whitehorn 3944c8945a0SNathan Whitehorn if (was_mouse && (key >= KEY_MAX)) { 3954c8945a0SNathan Whitehorn getyx(dialog, cur_y, cur_x); 3964c8945a0SNathan Whitehorn i = (key - KEY_MAX); 3974c8945a0SNathan Whitehorn if (i < max_choice) { 3984c8945a0SNathan Whitehorn choice = (key - KEY_MAX); 3992a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 4004c8945a0SNathan Whitehorn 401*f4f33ea0SBaptiste Daroussin key = DLGK_TOGGLE; /* force the selected item to toggle */ 4024c8945a0SNathan Whitehorn } else { 4034c8945a0SNathan Whitehorn beep(); 4044c8945a0SNathan Whitehorn continue; 4054c8945a0SNathan Whitehorn } 4064c8945a0SNathan Whitehorn fkey = FALSE; 4074c8945a0SNathan Whitehorn } else if (was_mouse && key >= KEY_MIN) { 4084c8945a0SNathan Whitehorn key = dlg_lookup_key(dialog, key, &fkey); 4094c8945a0SNathan Whitehorn } 4104c8945a0SNathan Whitehorn 4114c8945a0SNathan Whitehorn /* 4124c8945a0SNathan Whitehorn * A space toggles the item status. We handle either a checklist 4134c8945a0SNathan Whitehorn * (any number of items can be selected) or radio list (zero or one 4144c8945a0SNathan Whitehorn * items can be selected). 4154c8945a0SNathan Whitehorn */ 416*f4f33ea0SBaptiste Daroussin if (key == DLGK_TOGGLE) { 4174c8945a0SNathan Whitehorn int current = scrollamt + choice; 4184c8945a0SNathan Whitehorn int next = items[current].state + 1; 4194c8945a0SNathan Whitehorn 4204c8945a0SNathan Whitehorn if (next >= num_states) 4214c8945a0SNathan Whitehorn next = 0; 4224c8945a0SNathan Whitehorn 4234c8945a0SNathan Whitehorn if (flag == FLAG_CHECK) { /* checklist? */ 4242a3e3873SBaptiste Daroussin getyx(dialog, cur_y, cur_x); 4254c8945a0SNathan Whitehorn items[current].state = next; 4262a3e3873SBaptiste Daroussin print_item(&all, all.list, 4274c8945a0SNathan Whitehorn &items[scrollamt + choice], 4284c8945a0SNathan Whitehorn states, 4294c8945a0SNathan Whitehorn choice, TRUE); 4302a3e3873SBaptiste Daroussin (void) wnoutrefresh(all.list); 4312a3e3873SBaptiste Daroussin (void) wmove(dialog, cur_y, cur_x); 4324c8945a0SNathan Whitehorn } else { /* radiolist */ 4334c8945a0SNathan Whitehorn for (i = 0; i < item_no; i++) { 4344c8945a0SNathan Whitehorn if (i != current) { 4354c8945a0SNathan Whitehorn items[i].state = 0; 4364c8945a0SNathan Whitehorn } 4374c8945a0SNathan Whitehorn } 4384c8945a0SNathan Whitehorn if (items[current].state) { 4392a3e3873SBaptiste Daroussin getyx(dialog, cur_y, cur_x); 4404c8945a0SNathan Whitehorn items[current].state = next ? next : 1; 4412a3e3873SBaptiste Daroussin print_item(&all, all.list, 4424c8945a0SNathan Whitehorn &items[current], 4434c8945a0SNathan Whitehorn states, 4444c8945a0SNathan Whitehorn choice, TRUE); 4452a3e3873SBaptiste Daroussin (void) wnoutrefresh(all.list); 4462a3e3873SBaptiste Daroussin (void) wmove(dialog, cur_y, cur_x); 4474c8945a0SNathan Whitehorn } else { 4484c8945a0SNathan Whitehorn items[current].state = 1; 4492a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 4504c8945a0SNathan Whitehorn } 4514c8945a0SNathan Whitehorn } 4524c8945a0SNathan Whitehorn continue; /* wait for another key press */ 4534c8945a0SNathan Whitehorn } 4544c8945a0SNathan Whitehorn 4554c8945a0SNathan Whitehorn /* 4564c8945a0SNathan Whitehorn * Check if key pressed matches first character of any item tag in 4574c8945a0SNathan Whitehorn * list. If there is more than one match, we will cycle through 4584c8945a0SNathan Whitehorn * each one as the same key is pressed repeatedly. 4594c8945a0SNathan Whitehorn */ 4604c8945a0SNathan Whitehorn found = FALSE; 4614c8945a0SNathan Whitehorn if (!fkey) { 4624c8945a0SNathan Whitehorn if (button < 0 || !dialog_state.visit_items) { 4634c8945a0SNathan Whitehorn for (j = scrollamt + choice + 1; j < item_no; j++) { 4642a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4654c8945a0SNathan Whitehorn found = TRUE; 4664c8945a0SNathan Whitehorn i = j - scrollamt; 4674c8945a0SNathan Whitehorn break; 4684c8945a0SNathan Whitehorn } 4694c8945a0SNathan Whitehorn } 4704c8945a0SNathan Whitehorn if (!found) { 4714c8945a0SNathan Whitehorn for (j = 0; j <= scrollamt + choice; j++) { 4722a3e3873SBaptiste Daroussin if (check_hotkey(items, j)) { 4734c8945a0SNathan Whitehorn found = TRUE; 4744c8945a0SNathan Whitehorn i = j - scrollamt; 4754c8945a0SNathan Whitehorn break; 4764c8945a0SNathan Whitehorn } 4774c8945a0SNathan Whitehorn } 4784c8945a0SNathan Whitehorn } 4794c8945a0SNathan Whitehorn if (found) 4804c8945a0SNathan Whitehorn dlg_flush_getc(); 4814c8945a0SNathan Whitehorn } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 4824c8945a0SNathan Whitehorn button = j; 4834c8945a0SNathan Whitehorn ungetch('\n'); 4844c8945a0SNathan Whitehorn continue; 4854c8945a0SNathan Whitehorn } 4864c8945a0SNathan Whitehorn } 4874c8945a0SNathan Whitehorn 4884c8945a0SNathan Whitehorn /* 4894c8945a0SNathan Whitehorn * A single digit (1-9) positions the selection to that line in the 4904c8945a0SNathan Whitehorn * current screen. 4914c8945a0SNathan Whitehorn */ 4924c8945a0SNathan Whitehorn if (!found 4934c8945a0SNathan Whitehorn && (key <= '9') 4944c8945a0SNathan Whitehorn && (key > '0') 4954c8945a0SNathan Whitehorn && (key - '1' < max_choice)) { 4964c8945a0SNathan Whitehorn found = TRUE; 4974c8945a0SNathan Whitehorn i = key - '1'; 4984c8945a0SNathan Whitehorn } 4994c8945a0SNathan Whitehorn 5004c8945a0SNathan Whitehorn if (!found) { 5014c8945a0SNathan Whitehorn if (fkey) { 5024c8945a0SNathan Whitehorn found = TRUE; 5034c8945a0SNathan Whitehorn switch (key) { 5044c8945a0SNathan Whitehorn case DLGK_ITEM_FIRST: 5054c8945a0SNathan Whitehorn i = -scrollamt; 5064c8945a0SNathan Whitehorn break; 5074c8945a0SNathan Whitehorn case DLGK_ITEM_LAST: 5084c8945a0SNathan Whitehorn i = item_no - 1 - scrollamt; 5094c8945a0SNathan Whitehorn break; 5104c8945a0SNathan Whitehorn case DLGK_PAGE_PREV: 5114c8945a0SNathan Whitehorn if (choice) 5124c8945a0SNathan Whitehorn i = 0; 5134c8945a0SNathan Whitehorn else if (scrollamt != 0) 5144c8945a0SNathan Whitehorn i = -MIN(scrollamt, max_choice); 5154c8945a0SNathan Whitehorn else 5164c8945a0SNathan Whitehorn continue; 5174c8945a0SNathan Whitehorn break; 5184c8945a0SNathan Whitehorn case DLGK_PAGE_NEXT: 5194c8945a0SNathan Whitehorn i = MIN(choice + max_choice, item_no - scrollamt - 1); 5204c8945a0SNathan Whitehorn break; 5214c8945a0SNathan Whitehorn case DLGK_ITEM_PREV: 5224c8945a0SNathan Whitehorn i = choice - 1; 5234c8945a0SNathan Whitehorn if (choice == 0 && scrollamt == 0) 5244c8945a0SNathan Whitehorn continue; 5254c8945a0SNathan Whitehorn break; 5264c8945a0SNathan Whitehorn case DLGK_ITEM_NEXT: 5274c8945a0SNathan Whitehorn i = choice + 1; 5284c8945a0SNathan Whitehorn if (scrollamt + choice >= item_no - 1) 5294c8945a0SNathan Whitehorn continue; 5304c8945a0SNathan Whitehorn break; 5314c8945a0SNathan Whitehorn default: 5324c8945a0SNathan Whitehorn found = FALSE; 5334c8945a0SNathan Whitehorn break; 5344c8945a0SNathan Whitehorn } 5354c8945a0SNathan Whitehorn } 5364c8945a0SNathan Whitehorn } 5374c8945a0SNathan Whitehorn 5384c8945a0SNathan Whitehorn if (found) { 5394c8945a0SNathan Whitehorn if (i != choice) { 5404c8945a0SNathan Whitehorn getyx(dialog, cur_y, cur_x); 5414c8945a0SNathan Whitehorn if (i < 0 || i >= max_choice) { 5424c8945a0SNathan Whitehorn if (i < 0) { 5434c8945a0SNathan Whitehorn scrollamt += i; 5444c8945a0SNathan Whitehorn choice = 0; 5454c8945a0SNathan Whitehorn } else { 5464c8945a0SNathan Whitehorn choice = max_choice - 1; 5474c8945a0SNathan Whitehorn scrollamt += (i - max_choice + 1); 5484c8945a0SNathan Whitehorn } 5492a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5504c8945a0SNathan Whitehorn } else { 5514c8945a0SNathan Whitehorn choice = i; 5522a3e3873SBaptiste Daroussin print_list(&all, choice, scrollamt, max_choice); 5534c8945a0SNathan Whitehorn } 5544c8945a0SNathan Whitehorn } 5554c8945a0SNathan Whitehorn continue; /* wait for another key press */ 5564c8945a0SNathan Whitehorn } 5574c8945a0SNathan Whitehorn 5584c8945a0SNathan Whitehorn if (fkey) { 5594c8945a0SNathan Whitehorn switch (key) { 5604c8945a0SNathan Whitehorn case DLGK_ENTER: 561682c9e0fSNathan Whitehorn result = dlg_enter_buttoncode(button); 5624c8945a0SNathan Whitehorn break; 5634c8945a0SNathan Whitehorn case DLGK_FIELD_PREV: 5644c8945a0SNathan Whitehorn button = dlg_prev_button(buttons, button); 5654c8945a0SNathan Whitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5664c8945a0SNathan Whitehorn FALSE, width); 5674c8945a0SNathan Whitehorn break; 5684c8945a0SNathan Whitehorn case DLGK_FIELD_NEXT: 5694c8945a0SNathan Whitehorn button = dlg_next_button(buttons, button); 5704c8945a0SNathan Whitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 5714c8945a0SNathan Whitehorn FALSE, width); 5724c8945a0SNathan Whitehorn break; 5734c8945a0SNathan Whitehorn #ifdef KEY_RESIZE 5744c8945a0SNathan Whitehorn case KEY_RESIZE: 575*f4f33ea0SBaptiste Daroussin dlg_will_resize(dialog); 5764c8945a0SNathan Whitehorn /* reset data */ 5774c8945a0SNathan Whitehorn height = old_height; 5784c8945a0SNathan Whitehorn width = old_width; 579*f4f33ea0SBaptiste Daroussin free(prompt); 5804c8945a0SNathan Whitehorn dlg_clear(); 5814c8945a0SNathan Whitehorn dlg_del_window(dialog); 5824c8945a0SNathan Whitehorn dlg_mouse_free_regions(); 583*f4f33ea0SBaptiste Daroussin /* repaint */ 5844c8945a0SNathan Whitehorn goto retry; 5854c8945a0SNathan Whitehorn #endif 5864c8945a0SNathan Whitehorn default: 5874c8945a0SNathan Whitehorn if (was_mouse) { 5884c8945a0SNathan Whitehorn if ((key2 = dlg_ok_buttoncode(key)) >= 0) { 5894c8945a0SNathan Whitehorn result = key2; 5904c8945a0SNathan Whitehorn break; 5914c8945a0SNathan Whitehorn } 5924c8945a0SNathan Whitehorn beep(); 5934c8945a0SNathan Whitehorn } 5944c8945a0SNathan Whitehorn } 5954c8945a0SNathan Whitehorn } else { 5964c8945a0SNathan Whitehorn beep(); 5974c8945a0SNathan Whitehorn } 5984c8945a0SNathan Whitehorn } 5994c8945a0SNathan Whitehorn 6004c8945a0SNathan Whitehorn dlg_del_window(dialog); 6014c8945a0SNathan Whitehorn dlg_mouse_free_regions(); 6024c8945a0SNathan Whitehorn free(prompt); 6034c8945a0SNathan Whitehorn *current_item = (scrollamt + choice); 6044c8945a0SNathan Whitehorn return result; 6054c8945a0SNathan Whitehorn } 6064c8945a0SNathan Whitehorn 6074c8945a0SNathan Whitehorn /* 6084c8945a0SNathan Whitehorn * Display a dialog box with a list of options that can be turned on or off 6094c8945a0SNathan Whitehorn * The `flag' parameter is used to select between radiolist and checklist. 6104c8945a0SNathan Whitehorn */ 6114c8945a0SNathan Whitehorn int 6124c8945a0SNathan Whitehorn dialog_checklist(const char *title, 6134c8945a0SNathan Whitehorn const char *cprompt, 6144c8945a0SNathan Whitehorn int height, 6154c8945a0SNathan Whitehorn int width, 6164c8945a0SNathan Whitehorn int list_height, 6174c8945a0SNathan Whitehorn int item_no, 6184c8945a0SNathan Whitehorn char **items, 6194c8945a0SNathan Whitehorn int flag) 6204c8945a0SNathan Whitehorn { 6214c8945a0SNathan Whitehorn int result; 6222a3e3873SBaptiste Daroussin int i, j; 6234c8945a0SNathan Whitehorn DIALOG_LISTITEM *listitems; 6244c8945a0SNathan Whitehorn bool separate_output = ((flag == FLAG_CHECK) 6254c8945a0SNathan Whitehorn && (dialog_vars.separate_output)); 6264c8945a0SNathan Whitehorn bool show_status = FALSE; 6274c8945a0SNathan Whitehorn int current = 0; 628febdb468SDevin Teske char *help_result; 6294c8945a0SNathan Whitehorn 6304c8945a0SNathan Whitehorn listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 6314c8945a0SNathan Whitehorn assert_ptr(listitems, "dialog_checklist"); 6324c8945a0SNathan Whitehorn 6332a3e3873SBaptiste Daroussin for (i = j = 0; i < item_no; ++i) { 6342a3e3873SBaptiste Daroussin listitems[i].name = items[j++]; 6352a3e3873SBaptiste Daroussin listitems[i].text = (dialog_vars.no_items 6362a3e3873SBaptiste Daroussin ? dlg_strempty() 6372a3e3873SBaptiste Daroussin : items[j++]); 6382a3e3873SBaptiste Daroussin listitems[i].state = !dlg_strcmp(items[j++], "on"); 6394c8945a0SNathan Whitehorn listitems[i].help = ((dialog_vars.item_help) 6402a3e3873SBaptiste Daroussin ? items[j++] 6414c8945a0SNathan Whitehorn : dlg_strempty()); 6424c8945a0SNathan Whitehorn } 6437a1c0d96SNathan Whitehorn dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6444c8945a0SNathan Whitehorn 6454c8945a0SNathan Whitehorn result = dlg_checklist(title, 6464c8945a0SNathan Whitehorn cprompt, 6474c8945a0SNathan Whitehorn height, 6484c8945a0SNathan Whitehorn width, 6494c8945a0SNathan Whitehorn list_height, 6504c8945a0SNathan Whitehorn item_no, 6514c8945a0SNathan Whitehorn listitems, 6524c8945a0SNathan Whitehorn NULL, 6534c8945a0SNathan Whitehorn flag, 6544c8945a0SNathan Whitehorn ¤t); 6554c8945a0SNathan Whitehorn 6564c8945a0SNathan Whitehorn switch (result) { 6574c8945a0SNathan Whitehorn case DLG_EXIT_OK: /* FALLTHRU */ 6584c8945a0SNathan Whitehorn case DLG_EXIT_EXTRA: 6594c8945a0SNathan Whitehorn show_status = TRUE; 6604c8945a0SNathan Whitehorn break; 6614c8945a0SNathan Whitehorn case DLG_EXIT_HELP: 662febdb468SDevin Teske dlg_add_help_listitem(&result, &help_result, &listitems[current]); 663febdb468SDevin Teske if ((show_status = dialog_vars.help_status)) { 6644c8945a0SNathan Whitehorn if (separate_output) { 665febdb468SDevin Teske dlg_add_string(help_result); 6664c8945a0SNathan Whitehorn dlg_add_separator(); 6674c8945a0SNathan Whitehorn } else { 668febdb468SDevin Teske dlg_add_quoted(help_result); 6694c8945a0SNathan Whitehorn } 6704c8945a0SNathan Whitehorn } else { 671febdb468SDevin Teske dlg_add_string(help_result); 6724c8945a0SNathan Whitehorn } 6734c8945a0SNathan Whitehorn break; 6744c8945a0SNathan Whitehorn } 6754c8945a0SNathan Whitehorn 6764c8945a0SNathan Whitehorn if (show_status) { 6774c8945a0SNathan Whitehorn for (i = 0; i < item_no; i++) { 6784c8945a0SNathan Whitehorn if (listitems[i].state) { 6794c8945a0SNathan Whitehorn if (separate_output) { 6804c8945a0SNathan Whitehorn dlg_add_string(listitems[i].name); 6814c8945a0SNathan Whitehorn dlg_add_separator(); 6824c8945a0SNathan Whitehorn } else { 6834c8945a0SNathan Whitehorn if (dlg_need_separator()) 6844c8945a0SNathan Whitehorn dlg_add_separator(); 6852a3e3873SBaptiste Daroussin if (flag == FLAG_CHECK) 6862a3e3873SBaptiste Daroussin dlg_add_quoted(listitems[i].name); 6872a3e3873SBaptiste Daroussin else 6884c8945a0SNathan Whitehorn dlg_add_string(listitems[i].name); 6894c8945a0SNathan Whitehorn } 6904c8945a0SNathan Whitehorn } 6914c8945a0SNathan Whitehorn } 6922a3e3873SBaptiste Daroussin dlg_add_last_key(separate_output); 6934c8945a0SNathan Whitehorn } 6944c8945a0SNathan Whitehorn 6957a1c0d96SNathan Whitehorn dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 6964c8945a0SNathan Whitehorn free(listitems); 6974c8945a0SNathan Whitehorn return result; 6984c8945a0SNathan Whitehorn } 699