15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez * $Id: checklist.c,v 1.170 2022/04/04 22:25:11 tom Exp $
35382d832SPeter Avalos *
45382d832SPeter Avalos * checklist.c -- implements the checklist box
55382d832SPeter Avalos *
6*a8e38dc0SAntonio Huete Jimenez * Copyright 2000-2020,2022 Thomas E. Dickey
75382d832SPeter Avalos *
85382d832SPeter Avalos * This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos * it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos * as published by the Free Software Foundation.
115382d832SPeter Avalos *
125382d832SPeter Avalos * This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos * WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
155382d832SPeter Avalos * Lesser General Public License for more details.
165382d832SPeter Avalos *
175382d832SPeter Avalos * You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos * License along with this program; if not, write to
195382d832SPeter Avalos * Free Software Foundation, Inc.
205382d832SPeter Avalos * 51 Franklin St., Fifth Floor
215382d832SPeter Avalos * Boston, MA 02110, USA.
225382d832SPeter Avalos *
235382d832SPeter Avalos * An earlier version of this program lists as authors:
245382d832SPeter Avalos * Savio Lam (lam836@cs.cuhk.hk)
255382d832SPeter Avalos * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
265382d832SPeter Avalos * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
275382d832SPeter Avalos */
285382d832SPeter Avalos
29*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
305382d832SPeter Avalos #include <dlg_keys.h>
315382d832SPeter Avalos
325382d832SPeter Avalos #define MIN_HIGH (1 + (5 * MARGIN))
335382d832SPeter Avalos
345382d832SPeter Avalos typedef struct {
355382d832SPeter Avalos /* the outer-window */
365382d832SPeter Avalos WINDOW *dialog;
375382d832SPeter Avalos int box_y;
385382d832SPeter Avalos int box_x;
395382d832SPeter Avalos int check_x;
405382d832SPeter Avalos int item_x;
415382d832SPeter Avalos int checkflag;
425382d832SPeter Avalos int use_height;
435382d832SPeter Avalos int use_width;
445382d832SPeter Avalos /* the inner-window */
455382d832SPeter Avalos WINDOW *list;
465382d832SPeter Avalos DIALOG_LISTITEM *items;
475382d832SPeter Avalos int item_no;
485382d832SPeter Avalos const char *states;
495382d832SPeter Avalos } ALL_DATA;
505382d832SPeter Avalos
515382d832SPeter Avalos /*
525382d832SPeter Avalos * Print list item. The 'selected' parameter is true if 'choice' is the
535382d832SPeter Avalos * current item. That one is colored differently from the other items.
545382d832SPeter Avalos */
555382d832SPeter Avalos static void
print_item(ALL_DATA * data,WINDOW * win,DIALOG_LISTITEM * item,const char * states,int choice,int selected)565382d832SPeter Avalos print_item(ALL_DATA * data,
575382d832SPeter Avalos WINDOW *win,
585382d832SPeter Avalos DIALOG_LISTITEM * item,
595382d832SPeter Avalos const char *states,
605382d832SPeter Avalos int choice,
615382d832SPeter Avalos int selected)
625382d832SPeter Avalos {
635382d832SPeter Avalos chtype save = dlg_get_attrs(win);
645382d832SPeter Avalos int i;
655382d832SPeter Avalos bool both = (!dialog_vars.no_tags && !dialog_vars.no_items);
665382d832SPeter Avalos bool first = TRUE;
675382d832SPeter Avalos int climit = (getmaxx(win) - data->check_x + 1);
685382d832SPeter Avalos const char *show = (dialog_vars.no_items
695382d832SPeter Avalos ? item->name
705382d832SPeter Avalos : item->text);
715382d832SPeter Avalos
725382d832SPeter Avalos /* Clear 'residue' of last item */
735940c9abSDaniel Fojt dlg_attrset(win, menubox_attr);
745382d832SPeter Avalos (void) wmove(win, choice, 0);
755382d832SPeter Avalos for (i = 0; i < data->use_width; i++)
765382d832SPeter Avalos (void) waddch(win, ' ');
775382d832SPeter Avalos
785382d832SPeter Avalos (void) wmove(win, choice, data->check_x);
795940c9abSDaniel Fojt dlg_attrset(win, selected ? check_selected_attr : check_attr);
805382d832SPeter Avalos (void) wprintw(win,
815382d832SPeter Avalos (data->checkflag == FLAG_CHECK) ? "[%c]" : "(%c)",
825382d832SPeter Avalos states[item->state]);
835940c9abSDaniel Fojt dlg_attrset(win, menubox_attr);
845382d832SPeter Avalos (void) waddch(win, ' ');
855382d832SPeter Avalos
865382d832SPeter Avalos if (both) {
875382d832SPeter Avalos dlg_print_listitem(win, item->name, climit, first, selected);
885382d832SPeter Avalos first = FALSE;
895382d832SPeter Avalos }
905382d832SPeter Avalos
915382d832SPeter Avalos (void) wmove(win, choice, data->item_x);
925382d832SPeter Avalos dlg_print_listitem(win, show, climit, first, selected);
935382d832SPeter Avalos
945382d832SPeter Avalos if (selected) {
955382d832SPeter Avalos dlg_item_help(item->help);
965382d832SPeter Avalos }
975940c9abSDaniel Fojt dlg_attrset(win, save);
985382d832SPeter Avalos }
995382d832SPeter Avalos
1005382d832SPeter Avalos static void
print_list(ALL_DATA * data,int choice,int scrollamt,int max_choice,int max_items)101*a8e38dc0SAntonio Huete Jimenez print_list(ALL_DATA * data, int choice, int scrollamt, int max_choice, int max_items)
1025382d832SPeter Avalos {
1035382d832SPeter Avalos int i;
1045382d832SPeter Avalos int cur_y, cur_x;
1055382d832SPeter Avalos
1065382d832SPeter Avalos getyx(data->dialog, cur_y, cur_x);
1075382d832SPeter Avalos for (i = 0; i < max_choice; i++) {
108*a8e38dc0SAntonio Huete Jimenez int ii = i + scrollamt;
109*a8e38dc0SAntonio Huete Jimenez if (ii < max_items)
1105382d832SPeter Avalos print_item(data,
1115382d832SPeter Avalos data->list,
112*a8e38dc0SAntonio Huete Jimenez &data->items[ii],
1135382d832SPeter Avalos data->states,
1145382d832SPeter Avalos i, i == choice);
1155382d832SPeter Avalos }
1165382d832SPeter Avalos (void) wnoutrefresh(data->list);
1175382d832SPeter Avalos
1185382d832SPeter Avalos dlg_draw_scrollbar(data->dialog,
1195382d832SPeter Avalos (long) (scrollamt),
1205382d832SPeter Avalos (long) (scrollamt),
1215382d832SPeter Avalos (long) (scrollamt + max_choice),
1225382d832SPeter Avalos (long) (data->item_no),
1235382d832SPeter Avalos data->box_x + data->check_x,
1245382d832SPeter Avalos data->box_x + data->use_width,
1255382d832SPeter Avalos data->box_y,
1265382d832SPeter Avalos data->box_y + data->use_height + 1,
1275382d832SPeter Avalos menubox_border2_attr,
1285382d832SPeter Avalos menubox_border_attr);
1295382d832SPeter Avalos
1305382d832SPeter Avalos (void) wmove(data->dialog, cur_y, cur_x);
1315382d832SPeter Avalos }
1325382d832SPeter Avalos
1335382d832SPeter Avalos static bool
check_hotkey(DIALOG_LISTITEM * items,int choice)1345382d832SPeter Avalos check_hotkey(DIALOG_LISTITEM * items, int choice)
1355382d832SPeter Avalos {
1365382d832SPeter Avalos bool result = FALSE;
1375382d832SPeter Avalos
1385382d832SPeter Avalos if (dlg_match_char(dlg_last_getc(),
1395382d832SPeter Avalos (dialog_vars.no_tags
1405382d832SPeter Avalos ? items[choice].text
1415382d832SPeter Avalos : items[choice].name))) {
1425382d832SPeter Avalos result = TRUE;
1435382d832SPeter Avalos }
1445382d832SPeter Avalos return result;
1455382d832SPeter Avalos }
1465382d832SPeter Avalos
1475382d832SPeter Avalos /*
1485382d832SPeter Avalos * This is an alternate interface to 'checklist' which allows the application
1495382d832SPeter Avalos * to read the list item states back directly without putting them in the
1505382d832SPeter Avalos * output buffer. It also provides for more than two states over which the
1515382d832SPeter Avalos * check/radio box can display.
1525382d832SPeter Avalos */
1535382d832SPeter Avalos int
dlg_checklist(const char * title,const char * cprompt,int height,int width,int list_height,int item_no,DIALOG_LISTITEM * items,const char * states,int flag,int * current_item)1545382d832SPeter Avalos dlg_checklist(const char *title,
1555382d832SPeter Avalos const char *cprompt,
1565382d832SPeter Avalos int height,
1575382d832SPeter Avalos int width,
1585382d832SPeter Avalos int list_height,
1595382d832SPeter Avalos int item_no,
1605382d832SPeter Avalos DIALOG_LISTITEM * items,
1615382d832SPeter Avalos const char *states,
1625382d832SPeter Avalos int flag,
1635382d832SPeter Avalos int *current_item)
1645382d832SPeter Avalos {
1655382d832SPeter Avalos /* *INDENT-OFF* */
1665382d832SPeter Avalos static DLG_KEYS_BINDING binding[] = {
1675382d832SPeter Avalos HELPKEY_BINDINGS,
1685382d832SPeter Avalos ENTERKEY_BINDINGS,
1695382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
1705382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
1715382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
1725382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
1735382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ),
1745382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ),
1755382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ),
1765382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ),
1775382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ),
1785382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ),
1795382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ),
1805382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ),
1815382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ),
1825382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ),
1835382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ),
1845382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ),
1855382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ),
1865940c9abSDaniel Fojt TOGGLEKEY_BINDINGS,
1875382d832SPeter Avalos END_KEYS_BINDING
1885382d832SPeter Avalos };
1895382d832SPeter Avalos /* *INDENT-ON* */
1905382d832SPeter Avalos
1915382d832SPeter Avalos #ifdef KEY_RESIZE
1925382d832SPeter Avalos int old_height = height;
1935382d832SPeter Avalos int old_width = width;
1945382d832SPeter Avalos #endif
1955382d832SPeter Avalos ALL_DATA all;
1965382d832SPeter Avalos int i, j, key2, found, x, y, cur_x, cur_y;
1975940c9abSDaniel Fojt int key, fkey;
1985382d832SPeter Avalos int button = dialog_state.visit_items ? -1 : dlg_default_button();
1995382d832SPeter Avalos int choice = dlg_default_listitem(items);
2005382d832SPeter Avalos int scrollamt = 0;
2015382d832SPeter Avalos int max_choice;
2025382d832SPeter Avalos int use_width, list_width, name_width, text_width;
2035382d832SPeter Avalos int result = DLG_EXIT_UNKNOWN;
2045382d832SPeter Avalos int num_states;
2055382d832SPeter Avalos WINDOW *dialog;
2065940c9abSDaniel Fojt char *prompt;
2075382d832SPeter Avalos const char **buttons = dlg_ok_labels();
2085382d832SPeter Avalos const char *widget_name;
2095382d832SPeter Avalos
2105940c9abSDaniel Fojt DLG_TRACE(("# %s args:\n", flag ? "checklist" : "radiolist"));
2115940c9abSDaniel Fojt DLG_TRACE2S("title", title);
2125940c9abSDaniel Fojt DLG_TRACE2S("message", cprompt);
2135940c9abSDaniel Fojt DLG_TRACE2N("height", height);
2145940c9abSDaniel Fojt DLG_TRACE2N("width", width);
2155940c9abSDaniel Fojt DLG_TRACE2N("lheight", list_height);
2165940c9abSDaniel Fojt DLG_TRACE2N("llength", item_no);
2175940c9abSDaniel Fojt /* FIXME dump the items[][] too */
2185940c9abSDaniel Fojt DLG_TRACE2S("states", states);
2195940c9abSDaniel Fojt DLG_TRACE2N("flag", flag);
2205940c9abSDaniel Fojt DLG_TRACE2N("current", *current_item);
2215940c9abSDaniel Fojt
2221ef6786aSJohn Marino dialog_state.plain_buttons = TRUE;
2231ef6786aSJohn Marino
2245382d832SPeter Avalos memset(&all, 0, sizeof(all));
2255382d832SPeter Avalos all.items = items;
2265382d832SPeter Avalos all.item_no = item_no;
2275382d832SPeter Avalos
2285382d832SPeter Avalos dlg_does_output();
2295382d832SPeter Avalos
2305382d832SPeter Avalos /*
2315382d832SPeter Avalos * If this is a radiobutton list, ensure that no more than one item is
2325382d832SPeter Avalos * selected initially. Allow none to be selected, since some users may
2335382d832SPeter Avalos * wish to provide this flavor.
2345382d832SPeter Avalos */
2355382d832SPeter Avalos if (flag == FLAG_RADIO) {
2365382d832SPeter Avalos bool first = TRUE;
2375382d832SPeter Avalos
2385382d832SPeter Avalos for (i = 0; i < item_no; i++) {
2395382d832SPeter Avalos if (items[i].state) {
2405382d832SPeter Avalos if (first) {
2415382d832SPeter Avalos first = FALSE;
2425382d832SPeter Avalos } else {
2435382d832SPeter Avalos items[i].state = 0;
2445382d832SPeter Avalos }
2455382d832SPeter Avalos }
2465382d832SPeter Avalos }
2475382d832SPeter Avalos widget_name = "radiolist";
2485382d832SPeter Avalos } else {
2495382d832SPeter Avalos widget_name = "checklist";
2505382d832SPeter Avalos }
2515382d832SPeter Avalos #ifdef KEY_RESIZE
2525382d832SPeter Avalos retry:
2535382d832SPeter Avalos #endif
2545382d832SPeter Avalos
2555940c9abSDaniel Fojt prompt = dlg_strclone(cprompt);
2565940c9abSDaniel Fojt dlg_tab_correct_str(prompt);
2575940c9abSDaniel Fojt
2585382d832SPeter Avalos all.use_height = list_height;
2595382d832SPeter Avalos use_width = dlg_calc_list_width(item_no, items) + 10;
2605382d832SPeter Avalos use_width = MAX(26, use_width);
2615382d832SPeter Avalos if (all.use_height == 0) {
2625382d832SPeter Avalos /* calculate height without items (4) */
2635382d832SPeter Avalos dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width);
2645382d832SPeter Avalos dlg_calc_listh(&height, &all.use_height, item_no);
2655382d832SPeter Avalos } else {
2665382d832SPeter Avalos dlg_auto_size(title, prompt,
2675382d832SPeter Avalos &height, &width,
2685382d832SPeter Avalos MIN_HIGH + all.use_height, use_width);
2695382d832SPeter Avalos }
2705382d832SPeter Avalos dlg_button_layout(buttons, &width);
2715382d832SPeter Avalos dlg_print_size(height, width);
2725382d832SPeter Avalos dlg_ctl_size(height, width);
2735382d832SPeter Avalos
2745382d832SPeter Avalos /* we need at least two states */
2755382d832SPeter Avalos if (states == 0 || strlen(states) < 2)
2765382d832SPeter Avalos states = " *";
2775382d832SPeter Avalos num_states = (int) strlen(states);
2785382d832SPeter Avalos all.states = states;
2795382d832SPeter Avalos
2805382d832SPeter Avalos all.checkflag = flag;
2815382d832SPeter Avalos
2825382d832SPeter Avalos x = dlg_box_x_ordinate(width);
2835382d832SPeter Avalos y = dlg_box_y_ordinate(height);
2845382d832SPeter Avalos
2855382d832SPeter Avalos dialog = dlg_new_window(height, width, y, x);
2865382d832SPeter Avalos all.dialog = dialog;
2875382d832SPeter Avalos dlg_register_window(dialog, widget_name, binding);
2885382d832SPeter Avalos dlg_register_buttons(dialog, widget_name, buttons);
2895382d832SPeter Avalos
2905382d832SPeter Avalos dlg_mouse_setbase(x, y);
2915382d832SPeter Avalos
2925382d832SPeter Avalos dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
2935382d832SPeter Avalos dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
2945382d832SPeter Avalos dlg_draw_title(dialog, title);
2955382d832SPeter Avalos
2965940c9abSDaniel Fojt dlg_attrset(dialog, dialog_attr);
2975382d832SPeter Avalos dlg_print_autowrap(dialog, prompt, height, width);
2985382d832SPeter Avalos
2995382d832SPeter Avalos all.use_width = width - 6;
3005382d832SPeter Avalos getyx(dialog, cur_y, cur_x);
3015382d832SPeter Avalos all.box_y = cur_y + 1;
3025382d832SPeter Avalos all.box_x = (width - all.use_width) / 2 - 1;
3035382d832SPeter Avalos
3045382d832SPeter Avalos /*
3055382d832SPeter Avalos * After displaying the prompt, we know how much space we really have.
3065382d832SPeter Avalos * Limit the list to avoid overwriting the ok-button.
3075382d832SPeter Avalos */
3085382d832SPeter Avalos all.use_height = height - MIN_HIGH - cur_y;
3095382d832SPeter Avalos if (all.use_height <= 0)
3105382d832SPeter Avalos all.use_height = 1;
3115382d832SPeter Avalos
3125382d832SPeter Avalos max_choice = MIN(all.use_height, item_no);
3131ef6786aSJohn Marino max_choice = MAX(max_choice, 1);
3145382d832SPeter Avalos
3155382d832SPeter Avalos /* create new window for the list */
3165382d832SPeter Avalos all.list = dlg_sub_window(dialog, all.use_height, all.use_width,
3175382d832SPeter Avalos y + all.box_y + 1, x + all.box_x + 1);
3185382d832SPeter Avalos
3195382d832SPeter Avalos /* draw a box around the list items */
3205382d832SPeter Avalos dlg_draw_box(dialog, all.box_y, all.box_x,
3215382d832SPeter Avalos all.use_height + 2 * MARGIN,
3225382d832SPeter Avalos all.use_width + 2 * MARGIN,
3235382d832SPeter Avalos menubox_border_attr, menubox_border2_attr);
3245382d832SPeter Avalos
3255382d832SPeter Avalos text_width = 0;
3265382d832SPeter Avalos name_width = 0;
3275382d832SPeter Avalos /* Find length of longest item to center checklist */
3285382d832SPeter Avalos for (i = 0; i < item_no; i++) {
3295382d832SPeter Avalos text_width = MAX(text_width, dlg_count_columns(items[i].text));
3305382d832SPeter Avalos name_width = MAX(name_width, dlg_count_columns(items[i].name));
3315382d832SPeter Avalos }
3325382d832SPeter Avalos
3335382d832SPeter Avalos /* If the name+text is wider than the list is allowed, then truncate
3345382d832SPeter Avalos * one or both of them. If the name is no wider than 1/4 of the list,
3355382d832SPeter Avalos * leave it intact.
3365382d832SPeter Avalos */
3375382d832SPeter Avalos use_width = (all.use_width - 6);
3385382d832SPeter Avalos if (dialog_vars.no_tags) {
3395382d832SPeter Avalos list_width = MIN(all.use_width, text_width);
3405382d832SPeter Avalos } else if (dialog_vars.no_items) {
3415382d832SPeter Avalos list_width = MIN(all.use_width, name_width);
3425382d832SPeter Avalos } else {
3435382d832SPeter Avalos if (text_width >= 0
3445382d832SPeter Avalos && name_width >= 0
3455382d832SPeter Avalos && use_width > 0
3465382d832SPeter Avalos && text_width + name_width > use_width) {
3475382d832SPeter Avalos int need = (int) (0.25 * use_width);
3485382d832SPeter Avalos if (name_width > need) {
3495382d832SPeter Avalos int want = (int) (use_width * ((double) name_width) /
3505382d832SPeter Avalos (text_width + name_width));
3515382d832SPeter Avalos name_width = (want > need) ? want : need;
3525382d832SPeter Avalos }
3535382d832SPeter Avalos text_width = use_width - name_width;
3545382d832SPeter Avalos }
3555382d832SPeter Avalos list_width = (text_width + name_width);
3565382d832SPeter Avalos }
3575382d832SPeter Avalos
3585382d832SPeter Avalos all.check_x = (use_width - list_width) / 2;
3595382d832SPeter Avalos all.item_x = ((dialog_vars.no_tags
3605382d832SPeter Avalos ? 0
3615382d832SPeter Avalos : (dialog_vars.no_items
3625382d832SPeter Avalos ? 0
3635382d832SPeter Avalos : (2 + name_width)))
3645382d832SPeter Avalos + all.check_x + 4);
3655382d832SPeter Avalos
3665382d832SPeter Avalos /* ensure we are scrolled to show the current choice */
3671ef6786aSJohn Marino scrollamt = MIN(scrollamt, max_choice + item_no - 1);
3681ef6786aSJohn Marino if (choice >= (max_choice + scrollamt - 1)) {
3691ef6786aSJohn Marino scrollamt = MAX(0, choice - max_choice + 1);
3705382d832SPeter Avalos choice = max_choice - 1;
3715382d832SPeter Avalos }
372*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no);
3735382d832SPeter Avalos
3745382d832SPeter Avalos /* register the new window, along with its borders */
3755382d832SPeter Avalos dlg_mouse_mkbigregion(all.box_y + 1, all.box_x,
3765382d832SPeter Avalos all.use_height, all.use_width + 2,
3775382d832SPeter Avalos KEY_MAX, 1, 1, 1 /* by lines */ );
3785382d832SPeter Avalos
3795382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
3805382d832SPeter Avalos
3815382d832SPeter Avalos dlg_trace_win(dialog);
3825940c9abSDaniel Fojt
3835382d832SPeter Avalos while (result == DLG_EXIT_UNKNOWN) {
3845940c9abSDaniel Fojt int was_mouse;
3855940c9abSDaniel Fojt
3865382d832SPeter Avalos if (button < 0) /* --visit-items */
3875382d832SPeter Avalos wmove(dialog, all.box_y + choice + 1, all.box_x + all.check_x + 2);
3885382d832SPeter Avalos
3895382d832SPeter Avalos key = dlg_mouse_wgetch(dialog, &fkey);
3905940c9abSDaniel Fojt if (dlg_result_key(key, fkey, &result)) {
3915940c9abSDaniel Fojt if (!dlg_button_key(result, &button, &key, &fkey))
3925382d832SPeter Avalos break;
3935940c9abSDaniel Fojt }
3945382d832SPeter Avalos
3955382d832SPeter Avalos was_mouse = (fkey && is_DLGK_MOUSE(key));
3965382d832SPeter Avalos if (was_mouse)
3975382d832SPeter Avalos key -= M_EVENT;
3985382d832SPeter Avalos
3995382d832SPeter Avalos if (was_mouse && (key >= KEY_MAX)) {
4005382d832SPeter Avalos getyx(dialog, cur_y, cur_x);
4015382d832SPeter Avalos i = (key - KEY_MAX);
4025382d832SPeter Avalos if (i < max_choice) {
4035382d832SPeter Avalos choice = (key - KEY_MAX);
404*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no);
4055382d832SPeter Avalos
4065940c9abSDaniel Fojt key = DLGK_TOGGLE; /* force the selected item to toggle */
4075382d832SPeter Avalos } else {
4085382d832SPeter Avalos beep();
4095382d832SPeter Avalos continue;
4105382d832SPeter Avalos }
4115382d832SPeter Avalos fkey = FALSE;
4125382d832SPeter Avalos } else if (was_mouse && key >= KEY_MIN) {
4135382d832SPeter Avalos key = dlg_lookup_key(dialog, key, &fkey);
4145382d832SPeter Avalos }
4155382d832SPeter Avalos
4165382d832SPeter Avalos /*
4175382d832SPeter Avalos * A space toggles the item status. We handle either a checklist
4185382d832SPeter Avalos * (any number of items can be selected) or radio list (zero or one
4195382d832SPeter Avalos * items can be selected).
4205382d832SPeter Avalos */
4215940c9abSDaniel Fojt if (key == DLGK_TOGGLE) {
4225382d832SPeter Avalos int current = scrollamt + choice;
4235382d832SPeter Avalos int next = items[current].state + 1;
4245382d832SPeter Avalos
4255382d832SPeter Avalos if (next >= num_states)
4265382d832SPeter Avalos next = 0;
4275382d832SPeter Avalos
4285382d832SPeter Avalos if (flag == FLAG_CHECK) { /* checklist? */
4295382d832SPeter Avalos getyx(dialog, cur_y, cur_x);
4305382d832SPeter Avalos items[current].state = next;
4315382d832SPeter Avalos print_item(&all, all.list,
4325382d832SPeter Avalos &items[scrollamt + choice],
4335382d832SPeter Avalos states,
4345382d832SPeter Avalos choice, TRUE);
4355382d832SPeter Avalos (void) wnoutrefresh(all.list);
4365382d832SPeter Avalos (void) wmove(dialog, cur_y, cur_x);
4375382d832SPeter Avalos } else { /* radiolist */
4385382d832SPeter Avalos for (i = 0; i < item_no; i++) {
4395382d832SPeter Avalos if (i != current) {
4405382d832SPeter Avalos items[i].state = 0;
4415382d832SPeter Avalos }
4425382d832SPeter Avalos }
4435382d832SPeter Avalos if (items[current].state) {
4445382d832SPeter Avalos getyx(dialog, cur_y, cur_x);
4455382d832SPeter Avalos items[current].state = next ? next : 1;
4465382d832SPeter Avalos print_item(&all, all.list,
4475382d832SPeter Avalos &items[current],
4485382d832SPeter Avalos states,
4495382d832SPeter Avalos choice, TRUE);
4505382d832SPeter Avalos (void) wnoutrefresh(all.list);
4515382d832SPeter Avalos (void) wmove(dialog, cur_y, cur_x);
4525382d832SPeter Avalos } else {
4535382d832SPeter Avalos items[current].state = 1;
454*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no);
4555382d832SPeter Avalos }
4565382d832SPeter Avalos }
4575382d832SPeter Avalos continue; /* wait for another key press */
4585382d832SPeter Avalos }
4595382d832SPeter Avalos
4605382d832SPeter Avalos /*
4615382d832SPeter Avalos * Check if key pressed matches first character of any item tag in
4625382d832SPeter Avalos * list. If there is more than one match, we will cycle through
4635382d832SPeter Avalos * each one as the same key is pressed repeatedly.
4645382d832SPeter Avalos */
4655382d832SPeter Avalos found = FALSE;
4665382d832SPeter Avalos if (!fkey) {
4675382d832SPeter Avalos if (button < 0 || !dialog_state.visit_items) {
4685382d832SPeter Avalos for (j = scrollamt + choice + 1; j < item_no; j++) {
4695382d832SPeter Avalos if (check_hotkey(items, j)) {
4705382d832SPeter Avalos found = TRUE;
4715382d832SPeter Avalos i = j - scrollamt;
4725382d832SPeter Avalos break;
4735382d832SPeter Avalos }
4745382d832SPeter Avalos }
4755382d832SPeter Avalos if (!found) {
4765382d832SPeter Avalos for (j = 0; j <= scrollamt + choice; j++) {
4775382d832SPeter Avalos if (check_hotkey(items, j)) {
4785382d832SPeter Avalos found = TRUE;
4795382d832SPeter Avalos i = j - scrollamt;
4805382d832SPeter Avalos break;
4815382d832SPeter Avalos }
4825382d832SPeter Avalos }
4835382d832SPeter Avalos }
4845382d832SPeter Avalos if (found)
4855382d832SPeter Avalos dlg_flush_getc();
4865382d832SPeter Avalos } else if ((j = dlg_char_to_button(key, buttons)) >= 0) {
4875382d832SPeter Avalos button = j;
4885382d832SPeter Avalos ungetch('\n');
4895382d832SPeter Avalos continue;
4905382d832SPeter Avalos }
4915382d832SPeter Avalos }
4925382d832SPeter Avalos
4935382d832SPeter Avalos /*
4945382d832SPeter Avalos * A single digit (1-9) positions the selection to that line in the
4955382d832SPeter Avalos * current screen.
4965382d832SPeter Avalos */
4975382d832SPeter Avalos if (!found
4985382d832SPeter Avalos && (key <= '9')
4995382d832SPeter Avalos && (key > '0')
5005382d832SPeter Avalos && (key - '1' < max_choice)) {
5015382d832SPeter Avalos found = TRUE;
5025382d832SPeter Avalos i = key - '1';
5035382d832SPeter Avalos }
5045382d832SPeter Avalos
5055382d832SPeter Avalos if (!found) {
5065382d832SPeter Avalos if (fkey) {
5075382d832SPeter Avalos found = TRUE;
5085382d832SPeter Avalos switch (key) {
5095382d832SPeter Avalos case DLGK_ITEM_FIRST:
5105382d832SPeter Avalos i = -scrollamt;
5115382d832SPeter Avalos break;
5125382d832SPeter Avalos case DLGK_ITEM_LAST:
5135382d832SPeter Avalos i = item_no - 1 - scrollamt;
5145382d832SPeter Avalos break;
5155382d832SPeter Avalos case DLGK_PAGE_PREV:
5165382d832SPeter Avalos if (choice)
5175382d832SPeter Avalos i = 0;
5185382d832SPeter Avalos else if (scrollamt != 0)
5195382d832SPeter Avalos i = -MIN(scrollamt, max_choice);
5205382d832SPeter Avalos else
5215382d832SPeter Avalos continue;
5225382d832SPeter Avalos break;
5235382d832SPeter Avalos case DLGK_PAGE_NEXT:
5245382d832SPeter Avalos i = MIN(choice + max_choice, item_no - scrollamt - 1);
5255382d832SPeter Avalos break;
5265382d832SPeter Avalos case DLGK_ITEM_PREV:
5275382d832SPeter Avalos i = choice - 1;
5285382d832SPeter Avalos if (choice == 0 && scrollamt == 0)
5295382d832SPeter Avalos continue;
5305382d832SPeter Avalos break;
5315382d832SPeter Avalos case DLGK_ITEM_NEXT:
5325382d832SPeter Avalos i = choice + 1;
5335382d832SPeter Avalos if (scrollamt + choice >= item_no - 1)
5345382d832SPeter Avalos continue;
5355382d832SPeter Avalos break;
5365382d832SPeter Avalos default:
5375382d832SPeter Avalos found = FALSE;
5385382d832SPeter Avalos break;
5395382d832SPeter Avalos }
5405382d832SPeter Avalos }
5415382d832SPeter Avalos }
5425382d832SPeter Avalos
5435382d832SPeter Avalos if (found) {
5445382d832SPeter Avalos if (i != choice) {
5455382d832SPeter Avalos getyx(dialog, cur_y, cur_x);
5465382d832SPeter Avalos if (i < 0 || i >= max_choice) {
5475382d832SPeter Avalos if (i < 0) {
5485382d832SPeter Avalos scrollamt += i;
5495382d832SPeter Avalos choice = 0;
5505382d832SPeter Avalos } else {
5515382d832SPeter Avalos choice = max_choice - 1;
5525382d832SPeter Avalos scrollamt += (i - max_choice + 1);
5535382d832SPeter Avalos }
554*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no);
5555382d832SPeter Avalos } else {
5565382d832SPeter Avalos choice = i;
557*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no);
5585382d832SPeter Avalos }
5595382d832SPeter Avalos }
5605382d832SPeter Avalos continue; /* wait for another key press */
5615382d832SPeter Avalos }
5625382d832SPeter Avalos
5635382d832SPeter Avalos if (fkey) {
5645382d832SPeter Avalos switch (key) {
5655382d832SPeter Avalos case DLGK_ENTER:
5665382d832SPeter Avalos result = dlg_enter_buttoncode(button);
5675382d832SPeter Avalos break;
568*a8e38dc0SAntonio Huete Jimenez case DLGK_LEAVE:
569*a8e38dc0SAntonio Huete Jimenez result = dlg_ok_buttoncode(button);
570*a8e38dc0SAntonio Huete Jimenez break;
5715382d832SPeter Avalos case DLGK_FIELD_PREV:
5725382d832SPeter Avalos button = dlg_prev_button(buttons, button);
5735382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
5745382d832SPeter Avalos FALSE, width);
5755382d832SPeter Avalos break;
5765382d832SPeter Avalos case DLGK_FIELD_NEXT:
5775382d832SPeter Avalos button = dlg_next_button(buttons, button);
5785382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
5795382d832SPeter Avalos FALSE, width);
5805382d832SPeter Avalos break;
5815382d832SPeter Avalos #ifdef KEY_RESIZE
5825382d832SPeter Avalos case KEY_RESIZE:
5835940c9abSDaniel Fojt dlg_will_resize(dialog);
5845382d832SPeter Avalos /* reset data */
5855382d832SPeter Avalos height = old_height;
5865382d832SPeter Avalos width = old_width;
5875940c9abSDaniel Fojt free(prompt);
5885940c9abSDaniel Fojt _dlg_resize_cleanup(dialog);
589*a8e38dc0SAntonio Huete Jimenez /* keep position */
590*a8e38dc0SAntonio Huete Jimenez choice += scrollamt;
591*a8e38dc0SAntonio Huete Jimenez scrollamt = 0;
5925382d832SPeter Avalos /* repaint */
5935382d832SPeter Avalos goto retry;
5945382d832SPeter Avalos #endif
5955382d832SPeter Avalos default:
5965382d832SPeter Avalos if (was_mouse) {
5975382d832SPeter Avalos if ((key2 = dlg_ok_buttoncode(key)) >= 0) {
5985382d832SPeter Avalos result = key2;
5995382d832SPeter Avalos break;
6005382d832SPeter Avalos }
6015382d832SPeter Avalos beep();
6025382d832SPeter Avalos }
6035382d832SPeter Avalos }
6045940c9abSDaniel Fojt } else if (key > 0) {
6055382d832SPeter Avalos beep();
6065382d832SPeter Avalos }
6075382d832SPeter Avalos }
6085382d832SPeter Avalos
6095382d832SPeter Avalos dlg_del_window(dialog);
6105382d832SPeter Avalos dlg_mouse_free_regions();
6115382d832SPeter Avalos free(prompt);
6125382d832SPeter Avalos *current_item = (scrollamt + choice);
6135382d832SPeter Avalos return result;
6145382d832SPeter Avalos }
6155382d832SPeter Avalos
6165382d832SPeter Avalos /*
6175382d832SPeter Avalos * Display a dialog box with a list of options that can be turned on or off
6185382d832SPeter Avalos * The `flag' parameter is used to select between radiolist and checklist.
6195382d832SPeter Avalos */
6205382d832SPeter Avalos int
dialog_checklist(const char * title,const char * cprompt,int height,int width,int list_height,int item_no,char ** items,int flag)6215382d832SPeter Avalos dialog_checklist(const char *title,
6225382d832SPeter Avalos const char *cprompt,
6235382d832SPeter Avalos int height,
6245382d832SPeter Avalos int width,
6255382d832SPeter Avalos int list_height,
6265382d832SPeter Avalos int item_no,
6275382d832SPeter Avalos char **items,
6285382d832SPeter Avalos int flag)
6295382d832SPeter Avalos {
6305382d832SPeter Avalos int result;
6315382d832SPeter Avalos int i, j;
6325382d832SPeter Avalos DIALOG_LISTITEM *listitems;
6335382d832SPeter Avalos bool separate_output = ((flag == FLAG_CHECK)
6345382d832SPeter Avalos && (dialog_vars.separate_output));
6355382d832SPeter Avalos bool show_status = FALSE;
6365382d832SPeter Avalos int current = 0;
6371ef6786aSJohn Marino char *help_result;
6385382d832SPeter Avalos
6395382d832SPeter Avalos listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1);
6405382d832SPeter Avalos assert_ptr(listitems, "dialog_checklist");
6415382d832SPeter Avalos
6425382d832SPeter Avalos for (i = j = 0; i < item_no; ++i) {
6435382d832SPeter Avalos listitems[i].name = items[j++];
6445382d832SPeter Avalos listitems[i].text = (dialog_vars.no_items
6455382d832SPeter Avalos ? dlg_strempty()
6465382d832SPeter Avalos : items[j++]);
6475382d832SPeter Avalos listitems[i].state = !dlg_strcmp(items[j++], "on");
6485382d832SPeter Avalos listitems[i].help = ((dialog_vars.item_help)
6495382d832SPeter Avalos ? items[j++]
6505382d832SPeter Avalos : dlg_strempty());
6515382d832SPeter Avalos }
6525382d832SPeter Avalos dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no);
6535382d832SPeter Avalos
6545382d832SPeter Avalos result = dlg_checklist(title,
6555382d832SPeter Avalos cprompt,
6565382d832SPeter Avalos height,
6575382d832SPeter Avalos width,
6585382d832SPeter Avalos list_height,
6595382d832SPeter Avalos item_no,
6605382d832SPeter Avalos listitems,
6615382d832SPeter Avalos NULL,
6625382d832SPeter Avalos flag,
6635382d832SPeter Avalos ¤t);
6645382d832SPeter Avalos
6655382d832SPeter Avalos switch (result) {
6665382d832SPeter Avalos case DLG_EXIT_OK: /* FALLTHRU */
6675382d832SPeter Avalos case DLG_EXIT_EXTRA:
6685382d832SPeter Avalos show_status = TRUE;
6695382d832SPeter Avalos break;
6705382d832SPeter Avalos case DLG_EXIT_HELP:
6711ef6786aSJohn Marino dlg_add_help_listitem(&result, &help_result, &listitems[current]);
6721ef6786aSJohn Marino if ((show_status = dialog_vars.help_status)) {
6735382d832SPeter Avalos if (separate_output) {
6741ef6786aSJohn Marino dlg_add_string(help_result);
6755382d832SPeter Avalos dlg_add_separator();
6765382d832SPeter Avalos } else {
6771ef6786aSJohn Marino dlg_add_quoted(help_result);
6785382d832SPeter Avalos }
6795382d832SPeter Avalos } else {
6801ef6786aSJohn Marino dlg_add_string(help_result);
6815382d832SPeter Avalos }
6825382d832SPeter Avalos break;
6835382d832SPeter Avalos }
6845382d832SPeter Avalos
6855382d832SPeter Avalos if (show_status) {
6865382d832SPeter Avalos for (i = 0; i < item_no; i++) {
6875382d832SPeter Avalos if (listitems[i].state) {
6885382d832SPeter Avalos if (separate_output) {
6895382d832SPeter Avalos dlg_add_string(listitems[i].name);
6905382d832SPeter Avalos dlg_add_separator();
6915382d832SPeter Avalos } else {
6925382d832SPeter Avalos if (dlg_need_separator())
6935382d832SPeter Avalos dlg_add_separator();
6945382d832SPeter Avalos if (flag == FLAG_CHECK)
6955382d832SPeter Avalos dlg_add_quoted(listitems[i].name);
6965382d832SPeter Avalos else
6975382d832SPeter Avalos dlg_add_string(listitems[i].name);
6985382d832SPeter Avalos }
6995382d832SPeter Avalos }
7005382d832SPeter Avalos }
7011ef6786aSJohn Marino dlg_add_last_key(separate_output);
7025382d832SPeter Avalos }
7035382d832SPeter Avalos
7045382d832SPeter Avalos dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no);
7055382d832SPeter Avalos free(listitems);
7065382d832SPeter Avalos return result;
7075382d832SPeter Avalos }
708