15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez * $Id: treeview.c,v 1.46 2022/04/05 00:15:15 tom Exp $
35382d832SPeter Avalos *
45382d832SPeter Avalos * treeview.c -- implements the treeview dialog
55382d832SPeter Avalos *
6*a8e38dc0SAntonio Huete Jimenez * Copyright 2012-2021,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
245940c9abSDaniel Fojt #include <dlg_internals.h>
255382d832SPeter Avalos #include <dlg_keys.h>
265382d832SPeter Avalos
275382d832SPeter Avalos #define INDENT 3
285382d832SPeter Avalos #define MIN_HIGH (1 + (5 * MARGIN))
295382d832SPeter Avalos
305382d832SPeter Avalos typedef struct {
315382d832SPeter Avalos /* the outer-window */
325382d832SPeter Avalos WINDOW *dialog;
335382d832SPeter Avalos bool is_check;
345382d832SPeter Avalos int box_y;
355382d832SPeter Avalos int box_x;
365382d832SPeter Avalos int check_x;
375382d832SPeter Avalos int item_x;
385382d832SPeter Avalos int use_height;
395382d832SPeter Avalos int use_width;
405382d832SPeter Avalos /* the inner-window */
415382d832SPeter Avalos WINDOW *list;
425382d832SPeter Avalos DIALOG_LISTITEM *items;
435382d832SPeter Avalos int item_no;
445382d832SPeter Avalos int *depths;
455382d832SPeter Avalos const char *states;
465382d832SPeter Avalos } ALL_DATA;
475382d832SPeter Avalos
485382d832SPeter Avalos /*
495382d832SPeter Avalos * Print list item. The 'selected' parameter is true if 'choice' is the
505382d832SPeter Avalos * current item. That one is colored differently from the other items.
515382d832SPeter Avalos */
525382d832SPeter Avalos static void
print_item(ALL_DATA * data,DIALOG_LISTITEM * item,const char * states,int depths,int choice,int selected)535382d832SPeter Avalos print_item(ALL_DATA * data,
545382d832SPeter Avalos DIALOG_LISTITEM * item,
555382d832SPeter Avalos const char *states,
565382d832SPeter Avalos int depths,
575382d832SPeter Avalos int choice,
585382d832SPeter Avalos int selected)
595382d832SPeter Avalos {
605382d832SPeter Avalos WINDOW *win = data->list;
615382d832SPeter Avalos chtype save = dlg_get_attrs(win);
625382d832SPeter Avalos int i;
635382d832SPeter Avalos bool first = TRUE;
645382d832SPeter Avalos int climit = (getmaxx(win) - data->check_x + 1);
655382d832SPeter Avalos const char *show = (dialog_vars.no_items
665382d832SPeter Avalos ? item->name
675382d832SPeter Avalos : item->text);
685382d832SPeter Avalos
695382d832SPeter Avalos /* Clear 'residue' of last item */
705940c9abSDaniel Fojt dlg_attrset(win, menubox_attr);
715382d832SPeter Avalos (void) wmove(win, choice, 0);
725382d832SPeter Avalos for (i = 0; i < data->use_width; i++)
735382d832SPeter Avalos (void) waddch(win, ' ');
745382d832SPeter Avalos
755382d832SPeter Avalos (void) wmove(win, choice, data->check_x);
765940c9abSDaniel Fojt dlg_attrset(win, selected ? check_selected_attr : check_attr);
775382d832SPeter Avalos (void) wprintw(win,
785382d832SPeter Avalos data->is_check ? "[%c]" : "(%c)",
795382d832SPeter Avalos states[item->state]);
805940c9abSDaniel Fojt dlg_attrset(win, menubox_attr);
815382d832SPeter Avalos
825940c9abSDaniel Fojt dlg_attrset(win, selected ? item_selected_attr : item_attr);
835382d832SPeter Avalos for (i = 0; i < depths; ++i) {
845382d832SPeter Avalos int j;
855382d832SPeter Avalos (void) wmove(win, choice, data->item_x + INDENT * i);
865382d832SPeter Avalos (void) waddch(win, ACS_VLINE);
875382d832SPeter Avalos for (j = INDENT - 1; j > 0; --j)
885382d832SPeter Avalos (void) waddch(win, ' ');
895382d832SPeter Avalos }
905382d832SPeter Avalos (void) wmove(win, choice, data->item_x + INDENT * depths);
915382d832SPeter Avalos
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)1015382d832SPeter Avalos print_list(ALL_DATA * data,
1025382d832SPeter Avalos int choice,
1035382d832SPeter Avalos int scrollamt,
104*a8e38dc0SAntonio Huete Jimenez int max_choice,
105*a8e38dc0SAntonio Huete Jimenez int max_items)
1065382d832SPeter Avalos {
1075382d832SPeter Avalos int i;
1085382d832SPeter Avalos int cur_y, cur_x;
1095382d832SPeter Avalos
1105382d832SPeter Avalos getyx(data->dialog, cur_y, cur_x);
1115382d832SPeter Avalos
1125382d832SPeter Avalos for (i = 0; i < max_choice; i++) {
113*a8e38dc0SAntonio Huete Jimenez int ii = i + scrollamt;
114*a8e38dc0SAntonio Huete Jimenez if (ii < max_items)
1155382d832SPeter Avalos print_item(data,
116*a8e38dc0SAntonio Huete Jimenez &data->items[ii],
1175382d832SPeter Avalos data->states,
118*a8e38dc0SAntonio Huete Jimenez data->depths[ii],
1195382d832SPeter Avalos i, i == choice);
1205382d832SPeter Avalos }
1215382d832SPeter Avalos (void) wnoutrefresh(data->list);
1225382d832SPeter Avalos
1235382d832SPeter Avalos dlg_draw_scrollbar(data->dialog,
1245382d832SPeter Avalos (long) (scrollamt),
1255382d832SPeter Avalos (long) (scrollamt),
1265382d832SPeter Avalos (long) (scrollamt + max_choice),
1275382d832SPeter Avalos (long) (data->item_no),
1285382d832SPeter Avalos data->box_x + data->check_x,
1295382d832SPeter Avalos data->box_x + data->use_width,
1305382d832SPeter Avalos data->box_y,
1315382d832SPeter Avalos data->box_y + data->use_height + 1,
1325382d832SPeter Avalos menubox_border2_attr,
1335382d832SPeter Avalos menubox_border_attr);
1345382d832SPeter Avalos
1355382d832SPeter Avalos (void) wmove(data->dialog, cur_y, cur_x);
1365382d832SPeter Avalos }
1375382d832SPeter Avalos
1385382d832SPeter Avalos static bool
check_hotkey(DIALOG_LISTITEM * items,int choice)1395382d832SPeter Avalos check_hotkey(DIALOG_LISTITEM * items, int choice)
1405382d832SPeter Avalos {
1415382d832SPeter Avalos bool result = FALSE;
1425382d832SPeter Avalos
1435382d832SPeter Avalos if (dlg_match_char(dlg_last_getc(),
1445382d832SPeter Avalos (dialog_vars.no_tags
1455382d832SPeter Avalos ? items[choice].text
1465382d832SPeter Avalos : items[choice].name))) {
1475382d832SPeter Avalos result = TRUE;
1485382d832SPeter Avalos }
1495382d832SPeter Avalos return result;
1505382d832SPeter Avalos }
1515382d832SPeter Avalos
1525382d832SPeter Avalos /*
1535382d832SPeter Avalos * This is an alternate interface to 'treeview' which allows the application
1545382d832SPeter Avalos * to read the list item states back directly without putting them in the
1555382d832SPeter Avalos * output buffer.
1565382d832SPeter Avalos */
1575382d832SPeter Avalos int
dlg_treeview(const char * title,const char * cprompt,int height,int width,int list_height,int item_no,DIALOG_LISTITEM * items,const char * states,int * depths,int flag,int * current_item)1585382d832SPeter Avalos dlg_treeview(const char *title,
1595382d832SPeter Avalos const char *cprompt,
1605382d832SPeter Avalos int height,
1615382d832SPeter Avalos int width,
1625382d832SPeter Avalos int list_height,
1635382d832SPeter Avalos int item_no,
1645382d832SPeter Avalos DIALOG_LISTITEM * items,
1655382d832SPeter Avalos const char *states,
1665382d832SPeter Avalos int *depths,
1675382d832SPeter Avalos int flag,
1685382d832SPeter Avalos int *current_item)
1695382d832SPeter Avalos {
1705382d832SPeter Avalos /* *INDENT-OFF* */
1715382d832SPeter Avalos static DLG_KEYS_BINDING binding[] = {
1725382d832SPeter Avalos HELPKEY_BINDINGS,
1735382d832SPeter Avalos ENTERKEY_BINDINGS,
1745382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ),
1755382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
1765382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
1775382d832SPeter Avalos DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ),
1785382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ),
1795382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ),
1805382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ),
1815382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ),
1825382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ),
1835382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ),
1845382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ),
1855382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ),
1865382d832SPeter Avalos DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ),
1875382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ),
1885382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ),
1895382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ),
1905382d832SPeter Avalos DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ),
1915940c9abSDaniel Fojt TOGGLEKEY_BINDINGS,
1925382d832SPeter Avalos END_KEYS_BINDING
1935382d832SPeter Avalos };
1945382d832SPeter Avalos /* *INDENT-ON* */
1955382d832SPeter Avalos
1965382d832SPeter Avalos #ifdef KEY_RESIZE
1975382d832SPeter Avalos int old_height = height;
1985382d832SPeter Avalos int old_width = width;
1995382d832SPeter Avalos #endif
2005382d832SPeter Avalos ALL_DATA all;
2011ef6786aSJohn Marino int i, j, key2, found, x, y, cur_y, box_x, box_y;
2025940c9abSDaniel Fojt int key, fkey;
2035382d832SPeter Avalos int button = dialog_state.visit_items ? -1 : dlg_default_button();
2045382d832SPeter Avalos int choice = dlg_default_listitem(items);
2055382d832SPeter Avalos int scrollamt = 0;
2065382d832SPeter Avalos int max_choice;
2075382d832SPeter Avalos int use_height;
2085382d832SPeter Avalos int use_width, name_width, text_width, tree_width;
2095382d832SPeter Avalos int result = DLG_EXIT_UNKNOWN;
2105382d832SPeter Avalos int num_states;
2115382d832SPeter Avalos WINDOW *dialog, *list;
2125382d832SPeter Avalos char *prompt = dlg_strclone(cprompt);
2135382d832SPeter Avalos const char **buttons = dlg_ok_labels();
2145382d832SPeter Avalos const char *widget_name;
2155382d832SPeter Avalos
2165382d832SPeter Avalos /* we need at least two states */
2175382d832SPeter Avalos if (states == 0 || strlen(states) < 2)
2185382d832SPeter Avalos states = " *";
2195382d832SPeter Avalos num_states = (int) strlen(states);
2205382d832SPeter Avalos
2211ef6786aSJohn Marino dialog_state.plain_buttons = TRUE;
2221ef6786aSJohn Marino
2235382d832SPeter Avalos memset(&all, 0, sizeof(all));
2245382d832SPeter Avalos all.items = items;
2255382d832SPeter Avalos all.item_no = item_no;
2265382d832SPeter Avalos all.states = states;
2275382d832SPeter Avalos all.depths = depths;
2285382d832SPeter Avalos
2295382d832SPeter Avalos dlg_does_output();
2305382d832SPeter Avalos dlg_tab_correct_str(prompt);
2315382d832SPeter Avalos
2325382d832SPeter Avalos /*
2335382d832SPeter Avalos * If this is a radiobutton list, ensure that no more than one item is
2345382d832SPeter Avalos * selected initially. Allow none to be selected, since some users may
2355382d832SPeter Avalos * wish to provide this flavor.
2365382d832SPeter Avalos */
2375382d832SPeter Avalos if (flag == FLAG_RADIO) {
2385382d832SPeter Avalos bool first = TRUE;
2395382d832SPeter Avalos
2405382d832SPeter Avalos for (i = 0; i < item_no; i++) {
2415382d832SPeter Avalos if (items[i].state) {
2425382d832SPeter Avalos if (first) {
2435382d832SPeter Avalos first = FALSE;
2445382d832SPeter Avalos } else {
2455382d832SPeter Avalos items[i].state = 0;
2465382d832SPeter Avalos }
2475382d832SPeter Avalos }
2485382d832SPeter Avalos }
2495382d832SPeter Avalos } else {
2505382d832SPeter Avalos all.is_check = TRUE;
2515382d832SPeter Avalos }
2525382d832SPeter Avalos widget_name = "treeview";
2535382d832SPeter Avalos #ifdef KEY_RESIZE
2545382d832SPeter Avalos retry:
2555382d832SPeter Avalos #endif
2565382d832SPeter Avalos
2575382d832SPeter Avalos use_height = list_height;
2585382d832SPeter Avalos use_width = dlg_calc_list_width(item_no, items) + 10;
2595382d832SPeter Avalos use_width = MAX(26, use_width);
2605382d832SPeter Avalos if (use_height == 0) {
2615382d832SPeter Avalos /* calculate height without items (4) */
2625382d832SPeter Avalos dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width);
2635382d832SPeter Avalos dlg_calc_listh(&height, &use_height, item_no);
2645382d832SPeter Avalos } else {
2655382d832SPeter Avalos dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, use_width);
2665382d832SPeter Avalos }
2675382d832SPeter Avalos dlg_button_layout(buttons, &width);
2685382d832SPeter Avalos dlg_print_size(height, width);
2695382d832SPeter Avalos dlg_ctl_size(height, width);
2705382d832SPeter Avalos
2715382d832SPeter Avalos x = dlg_box_x_ordinate(width);
2725382d832SPeter Avalos y = dlg_box_y_ordinate(height);
2735382d832SPeter Avalos
2745382d832SPeter Avalos dialog = dlg_new_window(height, width, y, x);
2755382d832SPeter Avalos dlg_register_window(dialog, widget_name, binding);
2765382d832SPeter Avalos dlg_register_buttons(dialog, widget_name, buttons);
2775382d832SPeter Avalos
2785382d832SPeter Avalos dlg_mouse_setbase(x, y);
2795382d832SPeter Avalos
2805382d832SPeter Avalos dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
2815382d832SPeter Avalos dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
2825382d832SPeter Avalos dlg_draw_title(dialog, title);
2835382d832SPeter Avalos
2845940c9abSDaniel Fojt dlg_attrset(dialog, dialog_attr);
2855382d832SPeter Avalos dlg_print_autowrap(dialog, prompt, height, width);
2865382d832SPeter Avalos
2875382d832SPeter Avalos all.use_width = width - 4;
2881ef6786aSJohn Marino cur_y = getcury(dialog);
2895382d832SPeter Avalos box_y = cur_y + 1;
2905382d832SPeter Avalos box_x = (width - all.use_width) / 2 - 1;
2915382d832SPeter Avalos
2925382d832SPeter Avalos /*
2935382d832SPeter Avalos * After displaying the prompt, we know how much space we really have.
2945382d832SPeter Avalos * Limit the list to avoid overwriting the ok-button.
2955382d832SPeter Avalos */
2965382d832SPeter Avalos use_height = height - MIN_HIGH - cur_y;
2975382d832SPeter Avalos if (use_height <= 0)
2985382d832SPeter Avalos use_height = 1;
2995382d832SPeter Avalos
3005382d832SPeter Avalos max_choice = MIN(use_height, item_no);
3015382d832SPeter Avalos
3025382d832SPeter Avalos /* create new window for the list */
3035382d832SPeter Avalos list = dlg_sub_window(dialog, use_height, all.use_width,
3045382d832SPeter Avalos y + box_y + 1, x + box_x + 1);
3055382d832SPeter Avalos
3065382d832SPeter Avalos /* draw a box around the list items */
3075382d832SPeter Avalos dlg_draw_box(dialog, box_y, box_x,
3085382d832SPeter Avalos use_height + 2 * MARGIN,
3095382d832SPeter Avalos all.use_width + 2 * MARGIN,
3105382d832SPeter Avalos menubox_border_attr, menubox_border2_attr);
3115382d832SPeter Avalos
3125382d832SPeter Avalos text_width = 0;
3135382d832SPeter Avalos name_width = 0;
3145382d832SPeter Avalos tree_width = 0;
3155382d832SPeter Avalos /* Find length of longest item to center treeview */
3165382d832SPeter Avalos for (i = 0; i < item_no; i++) {
3175382d832SPeter Avalos tree_width = MAX(tree_width, INDENT * depths[i]);
3185382d832SPeter Avalos text_width = MAX(text_width, dlg_count_columns(items[i].text));
3195382d832SPeter Avalos name_width = MAX(name_width, dlg_count_columns(items[i].name));
3205382d832SPeter Avalos }
3215382d832SPeter Avalos if (dialog_vars.no_tags && !dialog_vars.no_items) {
3225382d832SPeter Avalos tree_width += text_width;
3235382d832SPeter Avalos } else if (dialog_vars.no_items) {
3245382d832SPeter Avalos tree_width += name_width;
3255382d832SPeter Avalos } else {
3265382d832SPeter Avalos tree_width += (text_width + name_width);
3275382d832SPeter Avalos }
3285382d832SPeter Avalos
3295382d832SPeter Avalos use_width = (all.use_width - 4);
3305382d832SPeter Avalos tree_width = MIN(tree_width, all.use_width);
3315382d832SPeter Avalos
3325382d832SPeter Avalos all.check_x = (use_width - tree_width) / 2;
3335382d832SPeter Avalos all.item_x = ((dialog_vars.no_tags
3345382d832SPeter Avalos ? 0
3355382d832SPeter Avalos : (dialog_vars.no_items
3365382d832SPeter Avalos ? 0
3375382d832SPeter Avalos : (2 + name_width)))
3385382d832SPeter Avalos + all.check_x + 4);
3395382d832SPeter Avalos
3405382d832SPeter Avalos /* ensure we are scrolled to show the current choice */
3415382d832SPeter Avalos if (choice >= (max_choice + scrollamt)) {
3425382d832SPeter Avalos scrollamt = choice - max_choice + 1;
3435382d832SPeter Avalos choice = max_choice - 1;
3445382d832SPeter Avalos }
3455382d832SPeter Avalos
3465382d832SPeter Avalos /* register the new window, along with its borders */
3475382d832SPeter Avalos dlg_mouse_mkbigregion(box_y + 1, box_x,
3485382d832SPeter Avalos use_height, all.use_width + 2,
3495382d832SPeter Avalos KEY_MAX, 1, 1, 1 /* by lines */ );
3505382d832SPeter Avalos
3515382d832SPeter Avalos all.dialog = dialog;
3525382d832SPeter Avalos all.box_x = box_x;
3535382d832SPeter Avalos all.box_y = box_y;
3545382d832SPeter Avalos all.use_height = use_height;
3555382d832SPeter Avalos all.list = list;
356*a8e38dc0SAntonio Huete Jimenez #define PrintList() \
357*a8e38dc0SAntonio Huete Jimenez print_list(&all, choice, scrollamt, max_choice, item_no)
358*a8e38dc0SAntonio Huete Jimenez PrintList();
3595382d832SPeter Avalos
3605382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
3615382d832SPeter Avalos
3625382d832SPeter Avalos dlg_trace_win(dialog);
3635940c9abSDaniel Fojt
3645382d832SPeter Avalos while (result == DLG_EXIT_UNKNOWN) {
3655940c9abSDaniel Fojt int was_mouse;
3665940c9abSDaniel Fojt
3675382d832SPeter Avalos if (button < 0) /* --visit-items */
3685382d832SPeter Avalos wmove(dialog, box_y + choice + 1, box_x + all.check_x + 2);
3695382d832SPeter Avalos
3705382d832SPeter Avalos key = dlg_mouse_wgetch(dialog, &fkey);
3715940c9abSDaniel Fojt if (dlg_result_key(key, fkey, &result)) {
3725940c9abSDaniel Fojt if (!dlg_button_key(result, &button, &key, &fkey))
3735382d832SPeter Avalos break;
3745940c9abSDaniel Fojt }
3755382d832SPeter Avalos
3765382d832SPeter Avalos was_mouse = (fkey && is_DLGK_MOUSE(key));
3775382d832SPeter Avalos if (was_mouse)
3785382d832SPeter Avalos key -= M_EVENT;
3795382d832SPeter Avalos
3805382d832SPeter Avalos if (was_mouse && (key >= KEY_MAX)) {
3815382d832SPeter Avalos i = (key - KEY_MAX);
3825382d832SPeter Avalos if (i < max_choice) {
3835382d832SPeter Avalos choice = (key - KEY_MAX);
384*a8e38dc0SAntonio Huete Jimenez PrintList();
3855382d832SPeter Avalos
3865940c9abSDaniel Fojt key = DLGK_TOGGLE; /* force the selected item to toggle */
3875382d832SPeter Avalos } else {
3885382d832SPeter Avalos beep();
3895382d832SPeter Avalos continue;
3905382d832SPeter Avalos }
3915382d832SPeter Avalos fkey = FALSE;
3925382d832SPeter Avalos } else if (was_mouse && key >= KEY_MIN) {
3935382d832SPeter Avalos key = dlg_lookup_key(dialog, key, &fkey);
3945382d832SPeter Avalos }
3955382d832SPeter Avalos
3965382d832SPeter Avalos /*
3975382d832SPeter Avalos * A space toggles the item status.
3985382d832SPeter Avalos */
3995940c9abSDaniel Fojt if (key == DLGK_TOGGLE) {
4005382d832SPeter Avalos int current = scrollamt + choice;
4015382d832SPeter Avalos int next = items[current].state + 1;
4025382d832SPeter Avalos
4035382d832SPeter Avalos if (next >= num_states)
4045382d832SPeter Avalos next = 0;
4055382d832SPeter Avalos
4065382d832SPeter Avalos if (flag == FLAG_CHECK) { /* checklist? */
4075382d832SPeter Avalos items[current].state = next;
4085382d832SPeter Avalos } else {
4095382d832SPeter Avalos for (i = 0; i < item_no; i++) {
4105382d832SPeter Avalos if (i != current) {
4115382d832SPeter Avalos items[i].state = 0;
4125382d832SPeter Avalos }
4135382d832SPeter Avalos }
4145382d832SPeter Avalos if (items[current].state) {
4155382d832SPeter Avalos items[current].state = next ? next : 1;
4165382d832SPeter Avalos } else {
4175382d832SPeter Avalos items[current].state = 1;
4185382d832SPeter Avalos }
4195382d832SPeter Avalos }
420*a8e38dc0SAntonio Huete Jimenez PrintList();
4215382d832SPeter Avalos continue; /* wait for another key press */
4225382d832SPeter Avalos }
4235382d832SPeter Avalos
4245382d832SPeter Avalos /*
4255382d832SPeter Avalos * Check if key pressed matches first character of any item tag in
4265382d832SPeter Avalos * list. If there is more than one match, we will cycle through
4275382d832SPeter Avalos * each one as the same key is pressed repeatedly.
4285382d832SPeter Avalos */
4295382d832SPeter Avalos found = FALSE;
4305382d832SPeter Avalos if (!fkey) {
4315382d832SPeter Avalos if (button < 0 || !dialog_state.visit_items) {
4325382d832SPeter Avalos for (j = scrollamt + choice + 1; j < item_no; j++) {
4335382d832SPeter Avalos if (check_hotkey(items, j)) {
4345382d832SPeter Avalos found = TRUE;
4355382d832SPeter Avalos i = j - scrollamt;
4365382d832SPeter Avalos break;
4375382d832SPeter Avalos }
4385382d832SPeter Avalos }
4395382d832SPeter Avalos if (!found) {
4405382d832SPeter Avalos for (j = 0; j <= scrollamt + choice; j++) {
4415382d832SPeter Avalos if (check_hotkey(items, j)) {
4425382d832SPeter Avalos found = TRUE;
4435382d832SPeter Avalos i = j - scrollamt;
4445382d832SPeter Avalos break;
4455382d832SPeter Avalos }
4465382d832SPeter Avalos }
4475382d832SPeter Avalos }
4485382d832SPeter Avalos if (found)
4495382d832SPeter Avalos dlg_flush_getc();
4505382d832SPeter Avalos } else if ((j = dlg_char_to_button(key, buttons)) >= 0) {
4515382d832SPeter Avalos button = j;
4525382d832SPeter Avalos ungetch('\n');
4535382d832SPeter Avalos continue;
4545382d832SPeter Avalos }
4555382d832SPeter Avalos }
4565382d832SPeter Avalos
4575382d832SPeter Avalos /*
4585382d832SPeter Avalos * A single digit (1-9) positions the selection to that line in the
4595382d832SPeter Avalos * current screen.
4605382d832SPeter Avalos */
4615382d832SPeter Avalos if (!found
4625382d832SPeter Avalos && (key <= '9')
4635382d832SPeter Avalos && (key > '0')
4645382d832SPeter Avalos && (key - '1' < max_choice)) {
4655382d832SPeter Avalos found = TRUE;
4665382d832SPeter Avalos i = key - '1';
4675382d832SPeter Avalos }
4685382d832SPeter Avalos
4695382d832SPeter Avalos if (!found) {
4705382d832SPeter Avalos if (fkey) {
4715382d832SPeter Avalos found = TRUE;
4725382d832SPeter Avalos switch (key) {
4735382d832SPeter Avalos case DLGK_ITEM_FIRST:
4745382d832SPeter Avalos i = -scrollamt;
4755382d832SPeter Avalos break;
4765382d832SPeter Avalos case DLGK_ITEM_LAST:
4775382d832SPeter Avalos i = item_no - 1 - scrollamt;
4785382d832SPeter Avalos break;
4795382d832SPeter Avalos case DLGK_PAGE_PREV:
4805382d832SPeter Avalos if (choice)
4815382d832SPeter Avalos i = 0;
4825382d832SPeter Avalos else if (scrollamt != 0)
4835382d832SPeter Avalos i = -MIN(scrollamt, max_choice);
4845382d832SPeter Avalos else
4855382d832SPeter Avalos continue;
4865382d832SPeter Avalos break;
4875382d832SPeter Avalos case DLGK_PAGE_NEXT:
4885382d832SPeter Avalos i = MIN(choice + max_choice, item_no - scrollamt - 1);
4895382d832SPeter Avalos break;
4905382d832SPeter Avalos case DLGK_ITEM_PREV:
4915382d832SPeter Avalos i = choice - 1;
4925382d832SPeter Avalos if (choice == 0 && scrollamt == 0)
4935382d832SPeter Avalos continue;
4945382d832SPeter Avalos break;
4955382d832SPeter Avalos case DLGK_ITEM_NEXT:
4965382d832SPeter Avalos i = choice + 1;
4975382d832SPeter Avalos if (scrollamt + choice >= item_no - 1)
4985382d832SPeter Avalos continue;
4995382d832SPeter Avalos break;
5005382d832SPeter Avalos default:
5015382d832SPeter Avalos found = FALSE;
5025382d832SPeter Avalos break;
5035382d832SPeter Avalos }
5045382d832SPeter Avalos }
5055382d832SPeter Avalos }
5065382d832SPeter Avalos
5075382d832SPeter Avalos if (found) {
5085382d832SPeter Avalos if (i != choice) {
5095382d832SPeter Avalos if (i < 0 || i >= max_choice) {
5105382d832SPeter Avalos if (i < 0) {
5115382d832SPeter Avalos scrollamt += i;
5125382d832SPeter Avalos choice = 0;
5135382d832SPeter Avalos } else {
5145382d832SPeter Avalos choice = max_choice - 1;
5155382d832SPeter Avalos scrollamt += (i - max_choice + 1);
5165382d832SPeter Avalos }
517*a8e38dc0SAntonio Huete Jimenez PrintList();
5185382d832SPeter Avalos } else {
5195382d832SPeter Avalos choice = i;
520*a8e38dc0SAntonio Huete Jimenez PrintList();
5215382d832SPeter Avalos }
5225382d832SPeter Avalos }
5235382d832SPeter Avalos continue; /* wait for another key press */
5245382d832SPeter Avalos }
5255382d832SPeter Avalos
5265382d832SPeter Avalos if (fkey) {
5275382d832SPeter Avalos switch (key) {
5285382d832SPeter Avalos case DLGK_ENTER:
5295382d832SPeter Avalos result = dlg_enter_buttoncode(button);
5305382d832SPeter Avalos break;
531*a8e38dc0SAntonio Huete Jimenez case DLGK_LEAVE:
532*a8e38dc0SAntonio Huete Jimenez result = dlg_ok_buttoncode(button);
533*a8e38dc0SAntonio Huete Jimenez break;
5345382d832SPeter Avalos case DLGK_FIELD_PREV:
5355382d832SPeter Avalos button = dlg_prev_button(buttons, button);
5365382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
5375382d832SPeter Avalos FALSE, width);
5385382d832SPeter Avalos break;
5395382d832SPeter Avalos case DLGK_FIELD_NEXT:
5405382d832SPeter Avalos button = dlg_next_button(buttons, button);
5415382d832SPeter Avalos dlg_draw_buttons(dialog, height - 2, 0, buttons, button,
5425382d832SPeter Avalos FALSE, width);
5435382d832SPeter Avalos break;
5445382d832SPeter Avalos #ifdef KEY_RESIZE
5455382d832SPeter Avalos case KEY_RESIZE:
5465940c9abSDaniel Fojt dlg_will_resize(dialog);
5475382d832SPeter Avalos /* reset data */
5485382d832SPeter Avalos height = old_height;
5495382d832SPeter Avalos width = old_width;
5505382d832SPeter Avalos /* repaint */
5515940c9abSDaniel Fojt _dlg_resize_cleanup(dialog);
552*a8e38dc0SAntonio Huete Jimenez /* keep position */
553*a8e38dc0SAntonio Huete Jimenez choice += scrollamt;
554*a8e38dc0SAntonio Huete Jimenez scrollamt = 0;
5555382d832SPeter Avalos goto retry;
5565382d832SPeter Avalos #endif
5575382d832SPeter Avalos default:
5585382d832SPeter Avalos if (was_mouse) {
5595382d832SPeter Avalos if ((key2 = dlg_ok_buttoncode(key)) >= 0) {
5605382d832SPeter Avalos result = key2;
5615382d832SPeter Avalos break;
5625382d832SPeter Avalos }
5635382d832SPeter Avalos beep();
5645382d832SPeter Avalos }
5655382d832SPeter Avalos }
5665940c9abSDaniel Fojt } else if (key > 0) {
5675382d832SPeter Avalos beep();
5685382d832SPeter Avalos }
5695382d832SPeter Avalos }
5705382d832SPeter Avalos
5715382d832SPeter Avalos dlg_del_window(dialog);
5725382d832SPeter Avalos dlg_mouse_free_regions();
5735382d832SPeter Avalos free(prompt);
5745382d832SPeter Avalos *current_item = (scrollamt + choice);
5755382d832SPeter Avalos return result;
5765382d832SPeter Avalos }
5775382d832SPeter Avalos
5785382d832SPeter Avalos /*
5795382d832SPeter Avalos * Display a set of items as a tree.
5805382d832SPeter Avalos */
5815382d832SPeter Avalos int
dialog_treeview(const char * title,const char * cprompt,int height,int width,int list_height,int item_no,char ** items,int flag)5825382d832SPeter Avalos dialog_treeview(const char *title,
5835382d832SPeter Avalos const char *cprompt,
5845382d832SPeter Avalos int height,
5855382d832SPeter Avalos int width,
5865382d832SPeter Avalos int list_height,
5875382d832SPeter Avalos int item_no,
5885382d832SPeter Avalos char **items,
5895382d832SPeter Avalos int flag)
5905382d832SPeter Avalos {
5915382d832SPeter Avalos int result;
5925382d832SPeter Avalos int i, j;
5935382d832SPeter Avalos DIALOG_LISTITEM *listitems;
5945382d832SPeter Avalos int *depths;
5955382d832SPeter Avalos bool show_status = FALSE;
5965382d832SPeter Avalos int current = 0;
5971ef6786aSJohn Marino char *help_result;
5985382d832SPeter Avalos
5995940c9abSDaniel Fojt DLG_TRACE(("# treeview args:\n"));
6005940c9abSDaniel Fojt DLG_TRACE2S("title", title);
6015940c9abSDaniel Fojt DLG_TRACE2S("message", cprompt);
6025940c9abSDaniel Fojt DLG_TRACE2N("height", height);
6035940c9abSDaniel Fojt DLG_TRACE2N("width", width);
6045940c9abSDaniel Fojt DLG_TRACE2N("lheight", list_height);
6055940c9abSDaniel Fojt DLG_TRACE2N("llength", item_no);
6065940c9abSDaniel Fojt /* FIXME dump the items[][] too */
6075940c9abSDaniel Fojt DLG_TRACE2N("flag", flag);
6085940c9abSDaniel Fojt
6095382d832SPeter Avalos listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1);
6105382d832SPeter Avalos assert_ptr(listitems, "dialog_treeview");
6115382d832SPeter Avalos
6125382d832SPeter Avalos depths = dlg_calloc(int, (size_t) item_no + 1);
6135382d832SPeter Avalos assert_ptr(depths, "dialog_treeview");
6145382d832SPeter Avalos
6155382d832SPeter Avalos for (i = j = 0; i < item_no; ++i) {
6165382d832SPeter Avalos listitems[i].name = items[j++];
6175382d832SPeter Avalos listitems[i].text = (dialog_vars.no_items
6185382d832SPeter Avalos ? dlg_strempty()
6195382d832SPeter Avalos : items[j++]);
6205382d832SPeter Avalos listitems[i].state = !dlg_strcmp(items[j++], "on");
6215382d832SPeter Avalos depths[i] = atoi(items[j++]);
6225382d832SPeter Avalos listitems[i].help = ((dialog_vars.item_help)
6235382d832SPeter Avalos ? items[j++]
6245382d832SPeter Avalos : dlg_strempty());
6255382d832SPeter Avalos }
6265382d832SPeter Avalos dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no);
6275382d832SPeter Avalos
6285382d832SPeter Avalos result = dlg_treeview(title,
6295382d832SPeter Avalos cprompt,
6305382d832SPeter Avalos height,
6315382d832SPeter Avalos width,
6325382d832SPeter Avalos list_height,
6335382d832SPeter Avalos item_no,
6345382d832SPeter Avalos listitems,
6355382d832SPeter Avalos NULL,
6365382d832SPeter Avalos depths,
6375382d832SPeter Avalos flag,
6385382d832SPeter Avalos ¤t);
6395382d832SPeter Avalos
6405382d832SPeter Avalos switch (result) {
6415382d832SPeter Avalos case DLG_EXIT_OK: /* FALLTHRU */
6425382d832SPeter Avalos case DLG_EXIT_EXTRA:
6435382d832SPeter Avalos show_status = TRUE;
6445382d832SPeter Avalos break;
6455382d832SPeter Avalos case DLG_EXIT_HELP:
6461ef6786aSJohn Marino dlg_add_help_listitem(&result, &help_result, &listitems[current]);
6471ef6786aSJohn Marino if ((show_status = dialog_vars.help_status)) {
6485382d832SPeter Avalos if (dialog_vars.separate_output) {
6491ef6786aSJohn Marino dlg_add_string(help_result);
6505382d832SPeter Avalos dlg_add_separator();
6515382d832SPeter Avalos } else {
6521ef6786aSJohn Marino dlg_add_quoted(help_result);
6535382d832SPeter Avalos }
6545382d832SPeter Avalos } else {
6551ef6786aSJohn Marino dlg_add_string(help_result);
6565382d832SPeter Avalos }
6575382d832SPeter Avalos break;
6585382d832SPeter Avalos }
6595382d832SPeter Avalos
6605382d832SPeter Avalos if (show_status) {
6615382d832SPeter Avalos for (i = 0; i < item_no; i++) {
6625382d832SPeter Avalos if (listitems[i].state) {
6635382d832SPeter Avalos if (dlg_need_separator())
6645382d832SPeter Avalos dlg_add_separator();
6655940c9abSDaniel Fojt if (dialog_vars.separate_output) {
6665940c9abSDaniel Fojt dlg_add_string(listitems[i].name);
6675940c9abSDaniel Fojt } else {
6685382d832SPeter Avalos if (flag == FLAG_CHECK)
6695382d832SPeter Avalos dlg_add_quoted(listitems[i].name);
6705382d832SPeter Avalos else
6715382d832SPeter Avalos dlg_add_string(listitems[i].name);
6725382d832SPeter Avalos }
6735382d832SPeter Avalos }
6745382d832SPeter Avalos }
6755940c9abSDaniel Fojt AddLastKey();
6765382d832SPeter Avalos }
6775382d832SPeter Avalos
6785382d832SPeter Avalos dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no);
6795382d832SPeter Avalos free(depths);
6805382d832SPeter Avalos free(listitems);
6815382d832SPeter Avalos return result;
6825382d832SPeter Avalos }
683