1251839Sbapt/* 2255852Sdteske * $Id: treeview.c,v 1.24 2013/09/02 17:13:33 tom Exp $ 3251839Sbapt * 4251839Sbapt * treeview.c -- implements the treeview dialog 5251839Sbapt * 6251839Sbapt * Copyright 2012,2013 Thomas E. Dickey 7251839Sbapt * 8251839Sbapt * This program is free software; you can redistribute it and/or modify 9251839Sbapt * it under the terms of the GNU Lesser General Public License, version 2.1 10251839Sbapt * as published by the Free Software Foundation. 11251839Sbapt * 12251839Sbapt * This program is distributed in the hope that it will be useful, but 13251839Sbapt * WITHOUT ANY WARRANTY; without even the implied warranty of 14251839Sbapt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15251839Sbapt * Lesser General Public License for more details. 16251839Sbapt * 17251839Sbapt * You should have received a copy of the GNU Lesser General Public 18251839Sbapt * License along with this program; if not, write to 19251839Sbapt * Free Software Foundation, Inc. 20251839Sbapt * 51 Franklin St., Fifth Floor 21251839Sbapt * Boston, MA 02110, USA. 22251839Sbapt */ 23251839Sbapt 24251839Sbapt#include <dialog.h> 25251839Sbapt#include <dlg_keys.h> 26251839Sbapt 27251839Sbapt#define INDENT 3 28251839Sbapt#define MIN_HIGH (1 + (5 * MARGIN)) 29251839Sbapt 30251839Sbapttypedef struct { 31251839Sbapt /* the outer-window */ 32251839Sbapt WINDOW *dialog; 33251839Sbapt bool is_check; 34251839Sbapt int box_y; 35251839Sbapt int box_x; 36251839Sbapt int check_x; 37251839Sbapt int item_x; 38251839Sbapt int use_height; 39251839Sbapt int use_width; 40251839Sbapt /* the inner-window */ 41251839Sbapt WINDOW *list; 42251839Sbapt DIALOG_LISTITEM *items; 43251839Sbapt int item_no; 44251839Sbapt int *depths; 45251839Sbapt const char *states; 46251839Sbapt} ALL_DATA; 47251839Sbapt 48251839Sbapt/* 49251839Sbapt * Print list item. The 'selected' parameter is true if 'choice' is the 50251839Sbapt * current item. That one is colored differently from the other items. 51251839Sbapt */ 52251839Sbaptstatic void 53251839Sbaptprint_item(ALL_DATA * data, 54251839Sbapt DIALOG_LISTITEM * item, 55251839Sbapt const char *states, 56251839Sbapt int depths, 57251839Sbapt int choice, 58251839Sbapt int selected) 59251839Sbapt{ 60251839Sbapt WINDOW *win = data->list; 61251839Sbapt chtype save = dlg_get_attrs(win); 62251839Sbapt int i; 63251839Sbapt bool first = TRUE; 64251839Sbapt int climit = (getmaxx(win) - data->check_x + 1); 65251839Sbapt const char *show = (dialog_vars.no_items 66251839Sbapt ? item->name 67251839Sbapt : item->text); 68251839Sbapt 69251839Sbapt /* Clear 'residue' of last item */ 70251839Sbapt (void) wattrset(win, menubox_attr); 71251839Sbapt (void) wmove(win, choice, 0); 72251839Sbapt for (i = 0; i < data->use_width; i++) 73251839Sbapt (void) waddch(win, ' '); 74251839Sbapt 75251839Sbapt (void) wmove(win, choice, data->check_x); 76251839Sbapt (void) wattrset(win, selected ? check_selected_attr : check_attr); 77251839Sbapt (void) wprintw(win, 78251839Sbapt data->is_check ? "[%c]" : "(%c)", 79251839Sbapt states[item->state]); 80251839Sbapt (void) wattrset(win, menubox_attr); 81251839Sbapt 82251839Sbapt (void) wattrset(win, selected ? item_selected_attr : item_attr); 83251839Sbapt for (i = 0; i < depths; ++i) { 84251839Sbapt int j; 85251839Sbapt (void) wmove(win, choice, data->item_x + INDENT * i); 86251839Sbapt (void) waddch(win, ACS_VLINE); 87251839Sbapt for (j = INDENT - 1; j > 0; --j) 88251839Sbapt (void) waddch(win, ' '); 89251839Sbapt } 90251839Sbapt (void) wmove(win, choice, data->item_x + INDENT * depths); 91251839Sbapt 92251839Sbapt dlg_print_listitem(win, show, climit, first, selected); 93251839Sbapt 94251839Sbapt if (selected) { 95251839Sbapt dlg_item_help(item->help); 96251839Sbapt } 97251839Sbapt (void) wattrset(win, save); 98251839Sbapt} 99251839Sbapt 100251839Sbaptstatic void 101251839Sbaptprint_list(ALL_DATA * data, 102251839Sbapt int choice, 103251839Sbapt int scrollamt, 104251839Sbapt int max_choice) 105251839Sbapt{ 106251839Sbapt int i; 107251839Sbapt int cur_y, cur_x; 108251839Sbapt 109251839Sbapt getyx(data->dialog, cur_y, cur_x); 110251839Sbapt 111251839Sbapt for (i = 0; i < max_choice; i++) { 112251839Sbapt print_item(data, 113251839Sbapt &data->items[scrollamt + i], 114251839Sbapt data->states, 115251839Sbapt data->depths[scrollamt + i], 116251839Sbapt i, i == choice); 117251839Sbapt } 118251839Sbapt (void) wnoutrefresh(data->list); 119251839Sbapt 120251839Sbapt dlg_draw_scrollbar(data->dialog, 121251839Sbapt (long) (scrollamt), 122251839Sbapt (long) (scrollamt), 123251839Sbapt (long) (scrollamt + max_choice), 124251839Sbapt (long) (data->item_no), 125251839Sbapt data->box_x + data->check_x, 126251839Sbapt data->box_x + data->use_width, 127251839Sbapt data->box_y, 128251839Sbapt data->box_y + data->use_height + 1, 129251839Sbapt menubox_border2_attr, 130251839Sbapt menubox_border_attr); 131251839Sbapt 132251839Sbapt (void) wmove(data->dialog, cur_y, cur_x); 133251839Sbapt} 134251839Sbapt 135251839Sbaptstatic bool 136251839Sbaptcheck_hotkey(DIALOG_LISTITEM * items, int choice) 137251839Sbapt{ 138251839Sbapt bool result = FALSE; 139251839Sbapt 140251839Sbapt if (dlg_match_char(dlg_last_getc(), 141251839Sbapt (dialog_vars.no_tags 142251839Sbapt ? items[choice].text 143251839Sbapt : items[choice].name))) { 144251839Sbapt result = TRUE; 145251839Sbapt } 146251839Sbapt return result; 147251839Sbapt} 148251839Sbapt 149251839Sbapt/* 150251839Sbapt * This is an alternate interface to 'treeview' which allows the application 151251839Sbapt * to read the list item states back directly without putting them in the 152251839Sbapt * output buffer. 153251839Sbapt */ 154251839Sbaptint 155251839Sbaptdlg_treeview(const char *title, 156251839Sbapt const char *cprompt, 157251839Sbapt int height, 158251839Sbapt int width, 159251839Sbapt int list_height, 160251839Sbapt int item_no, 161251839Sbapt DIALOG_LISTITEM * items, 162251839Sbapt const char *states, 163251839Sbapt int *depths, 164251839Sbapt int flag, 165251839Sbapt int *current_item) 166251839Sbapt{ 167251839Sbapt /* *INDENT-OFF* */ 168251839Sbapt static DLG_KEYS_BINDING binding[] = { 169251839Sbapt HELPKEY_BINDINGS, 170251839Sbapt ENTERKEY_BINDINGS, 171251839Sbapt DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), 172251839Sbapt DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), 173251839Sbapt DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), 174251839Sbapt DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ), 175251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ), 176251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ), 177251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ), 178251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ), 179251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), 180251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), 181251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ), 182251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), 183251839Sbapt DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), 184251839Sbapt DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), 185251839Sbapt DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ), 186251839Sbapt DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ), 187251839Sbapt DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ), 188251839Sbapt END_KEYS_BINDING 189251839Sbapt }; 190251839Sbapt /* *INDENT-ON* */ 191251839Sbapt 192251839Sbapt#ifdef KEY_RESIZE 193251839Sbapt int old_height = height; 194251839Sbapt int old_width = width; 195251839Sbapt#endif 196251839Sbapt ALL_DATA all; 197251839Sbapt int i, j, key2, found, x, y, cur_y, box_x, box_y; 198251839Sbapt int key = 0, fkey; 199251839Sbapt int button = dialog_state.visit_items ? -1 : dlg_default_button(); 200251839Sbapt int choice = dlg_default_listitem(items); 201251839Sbapt int scrollamt = 0; 202251839Sbapt int max_choice; 203251839Sbapt int was_mouse; 204251839Sbapt int use_height; 205251839Sbapt int use_width, name_width, text_width, tree_width; 206251839Sbapt int result = DLG_EXIT_UNKNOWN; 207251839Sbapt int num_states; 208251839Sbapt WINDOW *dialog, *list; 209251839Sbapt char *prompt = dlg_strclone(cprompt); 210251839Sbapt const char **buttons = dlg_ok_labels(); 211251839Sbapt const char *widget_name; 212251839Sbapt 213251839Sbapt /* we need at least two states */ 214251839Sbapt if (states == 0 || strlen(states) < 2) 215251839Sbapt states = " *"; 216251839Sbapt num_states = (int) strlen(states); 217251839Sbapt 218251839Sbapt memset(&all, 0, sizeof(all)); 219251839Sbapt all.items = items; 220251839Sbapt all.item_no = item_no; 221251839Sbapt all.states = states; 222251839Sbapt all.depths = depths; 223251839Sbapt 224251839Sbapt dlg_does_output(); 225251839Sbapt dlg_tab_correct_str(prompt); 226251839Sbapt 227251839Sbapt /* 228251839Sbapt * If this is a radiobutton list, ensure that no more than one item is 229251839Sbapt * selected initially. Allow none to be selected, since some users may 230251839Sbapt * wish to provide this flavor. 231251839Sbapt */ 232251839Sbapt if (flag == FLAG_RADIO) { 233251839Sbapt bool first = TRUE; 234251839Sbapt 235251839Sbapt for (i = 0; i < item_no; i++) { 236251839Sbapt if (items[i].state) { 237251839Sbapt if (first) { 238251839Sbapt first = FALSE; 239251839Sbapt } else { 240251839Sbapt items[i].state = 0; 241251839Sbapt } 242251839Sbapt } 243251839Sbapt } 244251839Sbapt } else { 245251839Sbapt all.is_check = TRUE; 246251839Sbapt } 247251839Sbapt widget_name = "treeview"; 248251839Sbapt#ifdef KEY_RESIZE 249251839Sbapt retry: 250251839Sbapt#endif 251251839Sbapt 252251839Sbapt use_height = list_height; 253251839Sbapt use_width = dlg_calc_list_width(item_no, items) + 10; 254251839Sbapt use_width = MAX(26, use_width); 255251839Sbapt if (use_height == 0) { 256251839Sbapt /* calculate height without items (4) */ 257251839Sbapt dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 258251839Sbapt dlg_calc_listh(&height, &use_height, item_no); 259251839Sbapt } else { 260251839Sbapt dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, use_width); 261251839Sbapt } 262251839Sbapt dlg_button_layout(buttons, &width); 263251839Sbapt dlg_print_size(height, width); 264251839Sbapt dlg_ctl_size(height, width); 265251839Sbapt 266251839Sbapt x = dlg_box_x_ordinate(width); 267251839Sbapt y = dlg_box_y_ordinate(height); 268251839Sbapt 269251839Sbapt dialog = dlg_new_window(height, width, y, x); 270251839Sbapt dlg_register_window(dialog, widget_name, binding); 271251839Sbapt dlg_register_buttons(dialog, widget_name, buttons); 272251839Sbapt 273251839Sbapt dlg_mouse_setbase(x, y); 274251839Sbapt 275251839Sbapt dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 276251839Sbapt dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 277251839Sbapt dlg_draw_title(dialog, title); 278251839Sbapt 279251839Sbapt (void) wattrset(dialog, dialog_attr); 280251839Sbapt dlg_print_autowrap(dialog, prompt, height, width); 281251839Sbapt 282251839Sbapt all.use_width = width - 4; 283251839Sbapt cur_y = getcury(dialog); 284251839Sbapt box_y = cur_y + 1; 285251839Sbapt box_x = (width - all.use_width) / 2 - 1; 286251839Sbapt 287251839Sbapt /* 288251839Sbapt * After displaying the prompt, we know how much space we really have. 289251839Sbapt * Limit the list to avoid overwriting the ok-button. 290251839Sbapt */ 291251839Sbapt if (use_height + MIN_HIGH > height - cur_y) 292251839Sbapt use_height = height - MIN_HIGH - cur_y; 293251839Sbapt if (use_height <= 0) 294251839Sbapt use_height = 1; 295251839Sbapt 296251839Sbapt max_choice = MIN(use_height, item_no); 297251839Sbapt 298251839Sbapt /* create new window for the list */ 299251839Sbapt list = dlg_sub_window(dialog, use_height, all.use_width, 300251839Sbapt y + box_y + 1, x + box_x + 1); 301251839Sbapt 302251839Sbapt /* draw a box around the list items */ 303251839Sbapt dlg_draw_box(dialog, box_y, box_x, 304251839Sbapt use_height + 2 * MARGIN, 305251839Sbapt all.use_width + 2 * MARGIN, 306251839Sbapt menubox_border_attr, menubox_border2_attr); 307251839Sbapt 308251839Sbapt text_width = 0; 309251839Sbapt name_width = 0; 310251839Sbapt tree_width = 0; 311251839Sbapt /* Find length of longest item to center treeview */ 312251839Sbapt for (i = 0; i < item_no; i++) { 313251839Sbapt tree_width = MAX(tree_width, INDENT * depths[i]); 314251839Sbapt text_width = MAX(text_width, dlg_count_columns(items[i].text)); 315251839Sbapt name_width = MAX(name_width, dlg_count_columns(items[i].name)); 316251839Sbapt } 317251839Sbapt if (dialog_vars.no_tags && !dialog_vars.no_items) { 318251839Sbapt tree_width += text_width; 319251839Sbapt } else if (dialog_vars.no_items) { 320251839Sbapt tree_width += name_width; 321251839Sbapt } else { 322251839Sbapt tree_width += (text_width + name_width); 323251839Sbapt } 324251839Sbapt 325251839Sbapt use_width = (all.use_width - 4); 326251839Sbapt tree_width = MIN(tree_width, all.use_width); 327251839Sbapt 328251839Sbapt all.check_x = (use_width - tree_width) / 2; 329251839Sbapt all.item_x = ((dialog_vars.no_tags 330251839Sbapt ? 0 331251839Sbapt : (dialog_vars.no_items 332251839Sbapt ? 0 333251839Sbapt : (2 + name_width))) 334251839Sbapt + all.check_x + 4); 335251839Sbapt 336251839Sbapt /* ensure we are scrolled to show the current choice */ 337251839Sbapt if (choice >= (max_choice + scrollamt)) { 338251839Sbapt scrollamt = choice - max_choice + 1; 339251839Sbapt choice = max_choice - 1; 340251839Sbapt } 341251839Sbapt 342251839Sbapt /* register the new window, along with its borders */ 343251839Sbapt dlg_mouse_mkbigregion(box_y + 1, box_x, 344251839Sbapt use_height, all.use_width + 2, 345251839Sbapt KEY_MAX, 1, 1, 1 /* by lines */ ); 346251839Sbapt 347251839Sbapt all.dialog = dialog; 348251839Sbapt all.box_x = box_x; 349251839Sbapt all.box_y = box_y; 350251839Sbapt all.use_height = use_height; 351251839Sbapt all.list = list; 352251839Sbapt print_list(&all, choice, scrollamt, max_choice); 353251839Sbapt 354251839Sbapt dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 355251839Sbapt 356251839Sbapt dlg_trace_win(dialog); 357251839Sbapt while (result == DLG_EXIT_UNKNOWN) { 358251839Sbapt if (button < 0) /* --visit-items */ 359251839Sbapt wmove(dialog, box_y + choice + 1, box_x + all.check_x + 2); 360251839Sbapt 361251839Sbapt key = dlg_mouse_wgetch(dialog, &fkey); 362251839Sbapt if (dlg_result_key(key, fkey, &result)) 363251839Sbapt break; 364251839Sbapt 365251839Sbapt was_mouse = (fkey && is_DLGK_MOUSE(key)); 366251839Sbapt if (was_mouse) 367251839Sbapt key -= M_EVENT; 368251839Sbapt 369251839Sbapt if (was_mouse && (key >= KEY_MAX)) { 370251839Sbapt i = (key - KEY_MAX); 371251839Sbapt if (i < max_choice) { 372251839Sbapt choice = (key - KEY_MAX); 373251839Sbapt print_list(&all, choice, scrollamt, max_choice); 374251839Sbapt 375251839Sbapt key = ' '; /* force the selected item to toggle */ 376251839Sbapt } else { 377251839Sbapt beep(); 378251839Sbapt continue; 379251839Sbapt } 380251839Sbapt fkey = FALSE; 381251839Sbapt } else if (was_mouse && key >= KEY_MIN) { 382251839Sbapt key = dlg_lookup_key(dialog, key, &fkey); 383251839Sbapt } 384251839Sbapt 385251839Sbapt /* 386251839Sbapt * A space toggles the item status. 387251839Sbapt */ 388251839Sbapt if (key == ' ') { 389251839Sbapt int current = scrollamt + choice; 390251839Sbapt int next = items[current].state + 1; 391251839Sbapt 392251839Sbapt if (next >= num_states) 393251839Sbapt next = 0; 394251839Sbapt 395251839Sbapt if (flag == FLAG_CHECK) { /* checklist? */ 396251839Sbapt items[current].state = next; 397251839Sbapt } else { 398251839Sbapt for (i = 0; i < item_no; i++) { 399251839Sbapt if (i != current) { 400251839Sbapt items[i].state = 0; 401251839Sbapt } 402251839Sbapt } 403251839Sbapt if (items[current].state) { 404251839Sbapt items[current].state = next ? next : 1; 405251839Sbapt } else { 406251839Sbapt items[current].state = 1; 407251839Sbapt } 408251839Sbapt } 409251839Sbapt print_list(&all, choice, scrollamt, max_choice); 410251839Sbapt continue; /* wait for another key press */ 411251839Sbapt } 412251839Sbapt 413251839Sbapt /* 414251839Sbapt * Check if key pressed matches first character of any item tag in 415251839Sbapt * list. If there is more than one match, we will cycle through 416251839Sbapt * each one as the same key is pressed repeatedly. 417251839Sbapt */ 418251839Sbapt found = FALSE; 419251839Sbapt if (!fkey) { 420251839Sbapt if (button < 0 || !dialog_state.visit_items) { 421251839Sbapt for (j = scrollamt + choice + 1; j < item_no; j++) { 422251839Sbapt if (check_hotkey(items, j)) { 423251839Sbapt found = TRUE; 424251839Sbapt i = j - scrollamt; 425251839Sbapt break; 426251839Sbapt } 427251839Sbapt } 428251839Sbapt if (!found) { 429251839Sbapt for (j = 0; j <= scrollamt + choice; j++) { 430251839Sbapt if (check_hotkey(items, j)) { 431251839Sbapt found = TRUE; 432251839Sbapt i = j - scrollamt; 433251839Sbapt break; 434251839Sbapt } 435251839Sbapt } 436251839Sbapt } 437251839Sbapt if (found) 438251839Sbapt dlg_flush_getc(); 439251839Sbapt } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 440251839Sbapt button = j; 441251839Sbapt ungetch('\n'); 442251839Sbapt continue; 443251839Sbapt } 444251839Sbapt } 445251839Sbapt 446251839Sbapt /* 447251839Sbapt * A single digit (1-9) positions the selection to that line in the 448251839Sbapt * current screen. 449251839Sbapt */ 450251839Sbapt if (!found 451251839Sbapt && (key <= '9') 452251839Sbapt && (key > '0') 453251839Sbapt && (key - '1' < max_choice)) { 454251839Sbapt found = TRUE; 455251839Sbapt i = key - '1'; 456251839Sbapt } 457251839Sbapt 458251839Sbapt if (!found) { 459251839Sbapt if (fkey) { 460251839Sbapt found = TRUE; 461251839Sbapt switch (key) { 462251839Sbapt case DLGK_ITEM_FIRST: 463251839Sbapt i = -scrollamt; 464251839Sbapt break; 465251839Sbapt case DLGK_ITEM_LAST: 466251839Sbapt i = item_no - 1 - scrollamt; 467251839Sbapt break; 468251839Sbapt case DLGK_PAGE_PREV: 469251839Sbapt if (choice) 470251839Sbapt i = 0; 471251839Sbapt else if (scrollamt != 0) 472251839Sbapt i = -MIN(scrollamt, max_choice); 473251839Sbapt else 474251839Sbapt continue; 475251839Sbapt break; 476251839Sbapt case DLGK_PAGE_NEXT: 477251839Sbapt i = MIN(choice + max_choice, item_no - scrollamt - 1); 478251839Sbapt break; 479251839Sbapt case DLGK_ITEM_PREV: 480251839Sbapt i = choice - 1; 481251839Sbapt if (choice == 0 && scrollamt == 0) 482251839Sbapt continue; 483251839Sbapt break; 484251839Sbapt case DLGK_ITEM_NEXT: 485251839Sbapt i = choice + 1; 486251839Sbapt if (scrollamt + choice >= item_no - 1) 487251839Sbapt continue; 488251839Sbapt break; 489251839Sbapt default: 490251839Sbapt found = FALSE; 491251839Sbapt break; 492251839Sbapt } 493251839Sbapt } 494251839Sbapt } 495251839Sbapt 496251839Sbapt if (found) { 497251839Sbapt if (i != choice) { 498251839Sbapt if (i < 0 || i >= max_choice) { 499251839Sbapt if (i < 0) { 500251839Sbapt scrollamt += i; 501251839Sbapt choice = 0; 502251839Sbapt } else { 503251839Sbapt choice = max_choice - 1; 504251839Sbapt scrollamt += (i - max_choice + 1); 505251839Sbapt } 506251839Sbapt print_list(&all, choice, scrollamt, max_choice); 507251839Sbapt } else { 508251839Sbapt choice = i; 509251839Sbapt print_list(&all, choice, scrollamt, max_choice); 510251839Sbapt } 511251839Sbapt } 512251839Sbapt continue; /* wait for another key press */ 513251839Sbapt } 514251839Sbapt 515251839Sbapt if (fkey) { 516251839Sbapt switch (key) { 517251839Sbapt case DLGK_ENTER: 518251839Sbapt result = dlg_enter_buttoncode(button); 519251839Sbapt break; 520251839Sbapt case DLGK_FIELD_PREV: 521251839Sbapt button = dlg_prev_button(buttons, button); 522251839Sbapt dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 523251839Sbapt FALSE, width); 524251839Sbapt break; 525251839Sbapt case DLGK_FIELD_NEXT: 526251839Sbapt button = dlg_next_button(buttons, button); 527251839Sbapt dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 528251839Sbapt FALSE, width); 529251839Sbapt break; 530251839Sbapt#ifdef KEY_RESIZE 531251839Sbapt case KEY_RESIZE: 532251839Sbapt /* reset data */ 533251839Sbapt height = old_height; 534251839Sbapt width = old_width; 535251839Sbapt /* repaint */ 536251839Sbapt dlg_clear(); 537251839Sbapt dlg_del_window(dialog); 538251839Sbapt refresh(); 539251839Sbapt dlg_mouse_free_regions(); 540251839Sbapt goto retry; 541251839Sbapt#endif 542251839Sbapt default: 543251839Sbapt if (was_mouse) { 544251839Sbapt if ((key2 = dlg_ok_buttoncode(key)) >= 0) { 545251839Sbapt result = key2; 546251839Sbapt break; 547251839Sbapt } 548251839Sbapt beep(); 549251839Sbapt } 550251839Sbapt } 551251839Sbapt } else { 552251839Sbapt beep(); 553251839Sbapt } 554251839Sbapt } 555251839Sbapt 556251839Sbapt dlg_del_window(dialog); 557251839Sbapt dlg_mouse_free_regions(); 558251839Sbapt free(prompt); 559251839Sbapt *current_item = (scrollamt + choice); 560251839Sbapt return result; 561251839Sbapt} 562251839Sbapt 563251839Sbapt/* 564251839Sbapt * Display a set of items as a tree. 565251839Sbapt */ 566251839Sbaptint 567251839Sbaptdialog_treeview(const char *title, 568251839Sbapt const char *cprompt, 569251839Sbapt int height, 570251839Sbapt int width, 571251839Sbapt int list_height, 572251839Sbapt int item_no, 573251839Sbapt char **items, 574251839Sbapt int flag) 575251839Sbapt{ 576251839Sbapt int result; 577251839Sbapt int i, j; 578251839Sbapt DIALOG_LISTITEM *listitems; 579251839Sbapt int *depths; 580251839Sbapt bool show_status = FALSE; 581251839Sbapt int current = 0; 582255852Sdteske char *help_result; 583251839Sbapt 584251839Sbapt listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 585251839Sbapt assert_ptr(listitems, "dialog_treeview"); 586251839Sbapt 587251839Sbapt depths = dlg_calloc(int, (size_t) item_no + 1); 588251839Sbapt assert_ptr(depths, "dialog_treeview"); 589251839Sbapt 590251839Sbapt for (i = j = 0; i < item_no; ++i) { 591251839Sbapt listitems[i].name = items[j++]; 592251839Sbapt listitems[i].text = (dialog_vars.no_items 593251839Sbapt ? dlg_strempty() 594251839Sbapt : items[j++]); 595251839Sbapt listitems[i].state = !dlg_strcmp(items[j++], "on"); 596251839Sbapt depths[i] = atoi(items[j++]); 597251839Sbapt listitems[i].help = ((dialog_vars.item_help) 598251839Sbapt ? items[j++] 599251839Sbapt : dlg_strempty()); 600251839Sbapt } 601251839Sbapt dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 602251839Sbapt 603251839Sbapt result = dlg_treeview(title, 604251839Sbapt cprompt, 605251839Sbapt height, 606251839Sbapt width, 607251839Sbapt list_height, 608251839Sbapt item_no, 609251839Sbapt listitems, 610251839Sbapt NULL, 611251839Sbapt depths, 612251839Sbapt flag, 613251839Sbapt ¤t); 614251839Sbapt 615251839Sbapt switch (result) { 616251839Sbapt case DLG_EXIT_OK: /* FALLTHRU */ 617251839Sbapt case DLG_EXIT_EXTRA: 618251839Sbapt show_status = TRUE; 619251839Sbapt break; 620251839Sbapt case DLG_EXIT_HELP: 621255852Sdteske dlg_add_help_listitem(&result, &help_result, &listitems[current]); 622255852Sdteske if ((show_status = dialog_vars.help_status)) { 623255852Sdteske if (dialog_vars.separate_output) { 624255852Sdteske dlg_add_string(help_result); 625255852Sdteske dlg_add_separator(); 626251839Sbapt } else { 627255852Sdteske dlg_add_quoted(help_result); 628251839Sbapt } 629251839Sbapt } else { 630255852Sdteske dlg_add_string(help_result); 631251839Sbapt } 632251839Sbapt break; 633251839Sbapt } 634251839Sbapt 635251839Sbapt if (show_status) { 636251839Sbapt for (i = 0; i < item_no; i++) { 637251839Sbapt if (listitems[i].state) { 638251839Sbapt if (dialog_vars.separate_output) { 639251839Sbapt dlg_add_string(listitems[i].name); 640251839Sbapt dlg_add_separator(); 641251839Sbapt } else { 642251839Sbapt if (dlg_need_separator()) 643251839Sbapt dlg_add_separator(); 644251839Sbapt if (flag == FLAG_CHECK) 645251839Sbapt dlg_add_quoted(listitems[i].name); 646251839Sbapt else 647251839Sbapt dlg_add_string(listitems[i].name); 648251839Sbapt } 649251839Sbapt } 650251839Sbapt } 651251839Sbapt dlg_add_last_key(-1); 652251839Sbapt } 653251839Sbapt 654251839Sbapt dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 655251839Sbapt free(depths); 656251839Sbapt free(listitems); 657251839Sbapt return result; 658251839Sbapt} 659