1217309Snwhitehorn/* 2255852Sdteske * $Id: checklist.c,v 1.153 2013/09/02 17:01:02 tom Exp $ 3217309Snwhitehorn * 4217309Snwhitehorn * checklist.c -- implements the checklist box 5217309Snwhitehorn * 6251843Sbapt * Copyright 2000-2012,2013 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn * 23217309Snwhitehorn * An earlier version of this program lists as authors: 24217309Snwhitehorn * Savio Lam (lam836@cs.cuhk.hk) 25217309Snwhitehorn * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension 26217309Snwhitehorn * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two 27217309Snwhitehorn */ 28217309Snwhitehorn 29217309Snwhitehorn#include <dialog.h> 30217309Snwhitehorn#include <dlg_keys.h> 31217309Snwhitehorn 32217309Snwhitehorn#define MIN_HIGH (1 + (5 * MARGIN)) 33217309Snwhitehorn 34251843Sbapttypedef struct { 35251843Sbapt /* the outer-window */ 36251843Sbapt WINDOW *dialog; 37251843Sbapt int box_y; 38251843Sbapt int box_x; 39251843Sbapt int check_x; 40251843Sbapt int item_x; 41251843Sbapt int checkflag; 42251843Sbapt int use_height; 43251843Sbapt int use_width; 44251843Sbapt /* the inner-window */ 45251843Sbapt WINDOW *list; 46251843Sbapt DIALOG_LISTITEM *items; 47251843Sbapt int item_no; 48251843Sbapt const char *states; 49251843Sbapt} ALL_DATA; 50217309Snwhitehorn 51217309Snwhitehorn/* 52217309Snwhitehorn * Print list item. The 'selected' parameter is true if 'choice' is the 53217309Snwhitehorn * current item. That one is colored differently from the other items. 54217309Snwhitehorn */ 55217309Snwhitehornstatic void 56251843Sbaptprint_item(ALL_DATA * data, 57251843Sbapt WINDOW *win, 58217309Snwhitehorn DIALOG_LISTITEM * item, 59217309Snwhitehorn const char *states, 60217309Snwhitehorn int choice, 61217309Snwhitehorn int selected) 62217309Snwhitehorn{ 63220749Snwhitehorn chtype save = dlg_get_attrs(win); 64217309Snwhitehorn int i; 65251843Sbapt bool both = (!dialog_vars.no_tags && !dialog_vars.no_items); 66251843Sbapt bool first = TRUE; 67251843Sbapt int climit = (getmaxx(win) - data->check_x + 1); 68251843Sbapt const char *show = (dialog_vars.no_items 69251843Sbapt ? item->name 70251843Sbapt : item->text); 71217309Snwhitehorn 72217309Snwhitehorn /* Clear 'residue' of last item */ 73251843Sbapt (void) wattrset(win, menubox_attr); 74217309Snwhitehorn (void) wmove(win, choice, 0); 75251843Sbapt for (i = 0; i < data->use_width; i++) 76217309Snwhitehorn (void) waddch(win, ' '); 77217309Snwhitehorn 78251843Sbapt (void) wmove(win, choice, data->check_x); 79251843Sbapt (void) wattrset(win, selected ? check_selected_attr : check_attr); 80217309Snwhitehorn (void) wprintw(win, 81251843Sbapt (data->checkflag == FLAG_CHECK) ? "[%c]" : "(%c)", 82217309Snwhitehorn states[item->state]); 83251843Sbapt (void) wattrset(win, menubox_attr); 84217309Snwhitehorn (void) waddch(win, ' '); 85217309Snwhitehorn 86251843Sbapt if (both) { 87251843Sbapt dlg_print_listitem(win, item->name, climit, first, selected); 88251843Sbapt first = FALSE; 89251843Sbapt } 90217309Snwhitehorn 91251843Sbapt (void) wmove(win, choice, data->item_x); 92251843Sbapt dlg_print_listitem(win, show, climit, first, selected); 93217309Snwhitehorn 94251843Sbapt if (selected) { 95251843Sbapt dlg_item_help(item->help); 96217309Snwhitehorn } 97251843Sbapt (void) wattrset(win, save); 98251843Sbapt} 99217309Snwhitehorn 100251843Sbaptstatic void 101251843Sbaptprint_list(ALL_DATA * data, int choice, int scrollamt, int max_choice) 102251843Sbapt{ 103251843Sbapt int i; 104251843Sbapt int cur_y, cur_x; 105217309Snwhitehorn 106251843Sbapt getyx(data->dialog, cur_y, cur_x); 107251843Sbapt for (i = 0; i < max_choice; i++) { 108251843Sbapt print_item(data, 109251843Sbapt data->list, 110251843Sbapt &data->items[i + scrollamt], 111251843Sbapt data->states, 112251843Sbapt i, i == choice); 113217309Snwhitehorn } 114251843Sbapt (void) wnoutrefresh(data->list); 115217309Snwhitehorn 116251843Sbapt dlg_draw_scrollbar(data->dialog, 117251843Sbapt (long) (scrollamt), 118251843Sbapt (long) (scrollamt), 119251843Sbapt (long) (scrollamt + max_choice), 120251843Sbapt (long) (data->item_no), 121251843Sbapt data->box_x + data->check_x, 122251843Sbapt data->box_x + data->use_width, 123251843Sbapt data->box_y, 124251843Sbapt data->box_y + data->use_height + 1, 125251843Sbapt menubox_border2_attr, 126251843Sbapt menubox_border_attr); 127251843Sbapt 128251843Sbapt (void) wmove(data->dialog, cur_y, cur_x); 129251843Sbapt} 130251843Sbapt 131251843Sbaptstatic bool 132251843Sbaptcheck_hotkey(DIALOG_LISTITEM * items, int choice) 133251843Sbapt{ 134251843Sbapt bool result = FALSE; 135251843Sbapt 136251843Sbapt if (dlg_match_char(dlg_last_getc(), 137251843Sbapt (dialog_vars.no_tags 138251843Sbapt ? items[choice].text 139251843Sbapt : items[choice].name))) { 140251843Sbapt result = TRUE; 141217309Snwhitehorn } 142251843Sbapt return result; 143217309Snwhitehorn} 144217309Snwhitehorn 145217309Snwhitehorn/* 146217309Snwhitehorn * This is an alternate interface to 'checklist' which allows the application 147217309Snwhitehorn * to read the list item states back directly without putting them in the 148217309Snwhitehorn * output buffer. It also provides for more than two states over which the 149217309Snwhitehorn * check/radio box can display. 150217309Snwhitehorn */ 151217309Snwhitehornint 152217309Snwhitehorndlg_checklist(const char *title, 153217309Snwhitehorn const char *cprompt, 154217309Snwhitehorn int height, 155217309Snwhitehorn int width, 156217309Snwhitehorn int list_height, 157217309Snwhitehorn int item_no, 158217309Snwhitehorn DIALOG_LISTITEM * items, 159217309Snwhitehorn const char *states, 160217309Snwhitehorn int flag, 161217309Snwhitehorn int *current_item) 162217309Snwhitehorn{ 163217309Snwhitehorn /* *INDENT-OFF* */ 164217309Snwhitehorn static DLG_KEYS_BINDING binding[] = { 165224014Snwhitehorn HELPKEY_BINDINGS, 166217309Snwhitehorn ENTERKEY_BINDINGS, 167217309Snwhitehorn DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), 168217309Snwhitehorn DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), 169217309Snwhitehorn DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), 170217309Snwhitehorn DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ), 171217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_FIRST, KEY_HOME ), 172217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_END ), 173217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_LAST, KEY_LL ), 174217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ), 175217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), 176217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), 177217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ), 178217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), 179217309Snwhitehorn DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), 180217309Snwhitehorn DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), 181217309Snwhitehorn DLG_KEYS_DATA( DLGK_PAGE_NEXT, DLGK_MOUSE(KEY_NPAGE) ), 182217309Snwhitehorn DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ), 183217309Snwhitehorn DLG_KEYS_DATA( DLGK_PAGE_PREV, DLGK_MOUSE(KEY_PPAGE) ), 184217309Snwhitehorn END_KEYS_BINDING 185217309Snwhitehorn }; 186217309Snwhitehorn /* *INDENT-ON* */ 187217309Snwhitehorn 188217309Snwhitehorn#ifdef KEY_RESIZE 189217309Snwhitehorn int old_height = height; 190217309Snwhitehorn int old_width = width; 191217309Snwhitehorn#endif 192251843Sbapt ALL_DATA all; 193251843Sbapt int i, j, key2, found, x, y, cur_x, cur_y; 194217309Snwhitehorn int key = 0, fkey; 195251843Sbapt int button = dialog_state.visit_items ? -1 : dlg_default_button(); 196217309Snwhitehorn int choice = dlg_default_listitem(items); 197217309Snwhitehorn int scrollamt = 0; 198217309Snwhitehorn int max_choice; 199217309Snwhitehorn int was_mouse; 200251843Sbapt int use_width, list_width, name_width, text_width; 201217309Snwhitehorn int result = DLG_EXIT_UNKNOWN; 202217309Snwhitehorn int num_states; 203251843Sbapt WINDOW *dialog; 204217309Snwhitehorn char *prompt = dlg_strclone(cprompt); 205217309Snwhitehorn const char **buttons = dlg_ok_labels(); 206251843Sbapt const char *widget_name; 207217309Snwhitehorn 208251843Sbapt memset(&all, 0, sizeof(all)); 209251843Sbapt all.items = items; 210251843Sbapt all.item_no = item_no; 211251843Sbapt 212217309Snwhitehorn dlg_does_output(); 213217309Snwhitehorn dlg_tab_correct_str(prompt); 214217309Snwhitehorn 215224014Snwhitehorn /* 216224014Snwhitehorn * If this is a radiobutton list, ensure that no more than one item is 217224014Snwhitehorn * selected initially. Allow none to be selected, since some users may 218224014Snwhitehorn * wish to provide this flavor. 219224014Snwhitehorn */ 220224014Snwhitehorn if (flag == FLAG_RADIO) { 221224014Snwhitehorn bool first = TRUE; 222224014Snwhitehorn 223224014Snwhitehorn for (i = 0; i < item_no; i++) { 224224014Snwhitehorn if (items[i].state) { 225224014Snwhitehorn if (first) { 226224014Snwhitehorn first = FALSE; 227224014Snwhitehorn } else { 228224014Snwhitehorn items[i].state = 0; 229224014Snwhitehorn } 230224014Snwhitehorn } 231224014Snwhitehorn } 232251843Sbapt widget_name = "radiolist"; 233251843Sbapt } else { 234251843Sbapt widget_name = "checklist"; 235224014Snwhitehorn } 236217309Snwhitehorn#ifdef KEY_RESIZE 237217309Snwhitehorn retry: 238217309Snwhitehorn#endif 239217309Snwhitehorn 240251843Sbapt all.use_height = list_height; 241251843Sbapt use_width = dlg_calc_list_width(item_no, items) + 10; 242251843Sbapt use_width = MAX(26, use_width); 243251843Sbapt if (all.use_height == 0) { 244217309Snwhitehorn /* calculate height without items (4) */ 245251843Sbapt dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 246251843Sbapt dlg_calc_listh(&height, &all.use_height, item_no); 247217309Snwhitehorn } else { 248251843Sbapt dlg_auto_size(title, prompt, 249251843Sbapt &height, &width, 250251843Sbapt MIN_HIGH + all.use_height, use_width); 251217309Snwhitehorn } 252217309Snwhitehorn dlg_button_layout(buttons, &width); 253217309Snwhitehorn dlg_print_size(height, width); 254217309Snwhitehorn dlg_ctl_size(height, width); 255217309Snwhitehorn 256217309Snwhitehorn /* we need at least two states */ 257217309Snwhitehorn if (states == 0 || strlen(states) < 2) 258217309Snwhitehorn states = " *"; 259217309Snwhitehorn num_states = (int) strlen(states); 260251843Sbapt all.states = states; 261217309Snwhitehorn 262251843Sbapt all.checkflag = flag; 263217309Snwhitehorn 264217309Snwhitehorn x = dlg_box_x_ordinate(width); 265217309Snwhitehorn y = dlg_box_y_ordinate(height); 266217309Snwhitehorn 267217309Snwhitehorn dialog = dlg_new_window(height, width, y, x); 268251843Sbapt all.dialog = dialog; 269251843Sbapt dlg_register_window(dialog, widget_name, binding); 270251843Sbapt dlg_register_buttons(dialog, widget_name, buttons); 271217309Snwhitehorn 272217309Snwhitehorn dlg_mouse_setbase(x, y); 273217309Snwhitehorn 274251843Sbapt dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 275251843Sbapt dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 276217309Snwhitehorn dlg_draw_title(dialog, title); 277217309Snwhitehorn 278251843Sbapt (void) wattrset(dialog, dialog_attr); 279217309Snwhitehorn dlg_print_autowrap(dialog, prompt, height, width); 280217309Snwhitehorn 281251843Sbapt all.use_width = width - 6; 282217309Snwhitehorn getyx(dialog, cur_y, cur_x); 283251843Sbapt all.box_y = cur_y + 1; 284251843Sbapt all.box_x = (width - all.use_width) / 2 - 1; 285217309Snwhitehorn 286217309Snwhitehorn /* 287217309Snwhitehorn * After displaying the prompt, we know how much space we really have. 288217309Snwhitehorn * Limit the list to avoid overwriting the ok-button. 289217309Snwhitehorn */ 290251843Sbapt if (all.use_height + MIN_HIGH > height - cur_y) 291251843Sbapt all.use_height = height - MIN_HIGH - cur_y; 292251843Sbapt if (all.use_height <= 0) 293251843Sbapt all.use_height = 1; 294217309Snwhitehorn 295251843Sbapt max_choice = MIN(all.use_height, item_no); 296251843Sbapt max_choice = MAX(max_choice, 1); 297217309Snwhitehorn 298217309Snwhitehorn /* create new window for the list */ 299251843Sbapt all.list = dlg_sub_window(dialog, all.use_height, all.use_width, 300251843Sbapt y + all.box_y + 1, x + all.box_x + 1); 301217309Snwhitehorn 302217309Snwhitehorn /* draw a box around the list items */ 303251843Sbapt dlg_draw_box(dialog, all.box_y, all.box_x, 304251843Sbapt all.use_height + 2 * MARGIN, 305251843Sbapt all.use_width + 2 * MARGIN, 306251843Sbapt menubox_border_attr, menubox_border2_attr); 307217309Snwhitehorn 308217309Snwhitehorn text_width = 0; 309217309Snwhitehorn name_width = 0; 310217309Snwhitehorn /* Find length of longest item to center checklist */ 311217309Snwhitehorn for (i = 0; i < item_no; i++) { 312217309Snwhitehorn text_width = MAX(text_width, dlg_count_columns(items[i].text)); 313217309Snwhitehorn name_width = MAX(name_width, dlg_count_columns(items[i].name)); 314217309Snwhitehorn } 315217309Snwhitehorn 316217309Snwhitehorn /* If the name+text is wider than the list is allowed, then truncate 317217309Snwhitehorn * one or both of them. If the name is no wider than 1/4 of the list, 318217309Snwhitehorn * leave it intact. 319217309Snwhitehorn */ 320251843Sbapt use_width = (all.use_width - 6); 321251843Sbapt if (dialog_vars.no_tags) { 322251843Sbapt list_width = MIN(all.use_width, text_width); 323251843Sbapt } else if (dialog_vars.no_items) { 324251843Sbapt list_width = MIN(all.use_width, name_width); 325251843Sbapt } else { 326251843Sbapt if (text_width >= 0 327251843Sbapt && name_width >= 0 328251843Sbapt && use_width > 0 329251843Sbapt && text_width + name_width > use_width) { 330251843Sbapt int need = (int) (0.25 * use_width); 331251843Sbapt if (name_width > need) { 332251843Sbapt int want = (int) (use_width * ((double) name_width) / 333251843Sbapt (text_width + name_width)); 334251843Sbapt name_width = (want > need) ? want : need; 335251843Sbapt } 336251843Sbapt text_width = use_width - name_width; 337217309Snwhitehorn } 338251843Sbapt list_width = (text_width + name_width); 339217309Snwhitehorn } 340217309Snwhitehorn 341251843Sbapt all.check_x = (use_width - list_width) / 2; 342251843Sbapt all.item_x = ((dialog_vars.no_tags 343251843Sbapt ? 0 344251843Sbapt : (dialog_vars.no_items 345251843Sbapt ? 0 346251843Sbapt : (2 + name_width))) 347251843Sbapt + all.check_x + 4); 348217309Snwhitehorn 349217309Snwhitehorn /* ensure we are scrolled to show the current choice */ 350251843Sbapt scrollamt = MIN(scrollamt, max_choice + item_no - 1); 351251843Sbapt if (choice >= (max_choice + scrollamt - 1)) { 352251843Sbapt scrollamt = MAX(0, choice - max_choice + 1); 353217309Snwhitehorn choice = max_choice - 1; 354217309Snwhitehorn } 355251843Sbapt print_list(&all, choice, scrollamt, max_choice); 356217309Snwhitehorn 357217309Snwhitehorn /* register the new window, along with its borders */ 358251843Sbapt dlg_mouse_mkbigregion(all.box_y + 1, all.box_x, 359251843Sbapt all.use_height, all.use_width + 2, 360217309Snwhitehorn KEY_MAX, 1, 1, 1 /* by lines */ ); 361217309Snwhitehorn 362217309Snwhitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 363217309Snwhitehorn 364251843Sbapt dlg_trace_win(dialog); 365217309Snwhitehorn while (result == DLG_EXIT_UNKNOWN) { 366217309Snwhitehorn if (button < 0) /* --visit-items */ 367251843Sbapt wmove(dialog, all.box_y + choice + 1, all.box_x + all.check_x + 2); 368217309Snwhitehorn 369217309Snwhitehorn key = dlg_mouse_wgetch(dialog, &fkey); 370217309Snwhitehorn if (dlg_result_key(key, fkey, &result)) 371217309Snwhitehorn break; 372217309Snwhitehorn 373217309Snwhitehorn was_mouse = (fkey && is_DLGK_MOUSE(key)); 374217309Snwhitehorn if (was_mouse) 375217309Snwhitehorn key -= M_EVENT; 376217309Snwhitehorn 377217309Snwhitehorn if (was_mouse && (key >= KEY_MAX)) { 378217309Snwhitehorn getyx(dialog, cur_y, cur_x); 379217309Snwhitehorn i = (key - KEY_MAX); 380217309Snwhitehorn if (i < max_choice) { 381217309Snwhitehorn choice = (key - KEY_MAX); 382251843Sbapt print_list(&all, choice, scrollamt, max_choice); 383217309Snwhitehorn 384217309Snwhitehorn key = ' '; /* force the selected item to toggle */ 385217309Snwhitehorn } else { 386217309Snwhitehorn beep(); 387217309Snwhitehorn continue; 388217309Snwhitehorn } 389217309Snwhitehorn fkey = FALSE; 390217309Snwhitehorn } else if (was_mouse && key >= KEY_MIN) { 391217309Snwhitehorn key = dlg_lookup_key(dialog, key, &fkey); 392217309Snwhitehorn } 393217309Snwhitehorn 394217309Snwhitehorn /* 395217309Snwhitehorn * A space toggles the item status. We handle either a checklist 396217309Snwhitehorn * (any number of items can be selected) or radio list (zero or one 397217309Snwhitehorn * items can be selected). 398217309Snwhitehorn */ 399217309Snwhitehorn if (key == ' ') { 400217309Snwhitehorn int current = scrollamt + choice; 401217309Snwhitehorn int next = items[current].state + 1; 402217309Snwhitehorn 403217309Snwhitehorn if (next >= num_states) 404217309Snwhitehorn next = 0; 405217309Snwhitehorn 406217309Snwhitehorn if (flag == FLAG_CHECK) { /* checklist? */ 407251843Sbapt getyx(dialog, cur_y, cur_x); 408217309Snwhitehorn items[current].state = next; 409251843Sbapt print_item(&all, all.list, 410217309Snwhitehorn &items[scrollamt + choice], 411217309Snwhitehorn states, 412217309Snwhitehorn choice, TRUE); 413251843Sbapt (void) wnoutrefresh(all.list); 414251843Sbapt (void) wmove(dialog, cur_y, cur_x); 415217309Snwhitehorn } else { /* radiolist */ 416217309Snwhitehorn for (i = 0; i < item_no; i++) { 417217309Snwhitehorn if (i != current) { 418217309Snwhitehorn items[i].state = 0; 419217309Snwhitehorn } 420217309Snwhitehorn } 421217309Snwhitehorn if (items[current].state) { 422251843Sbapt getyx(dialog, cur_y, cur_x); 423217309Snwhitehorn items[current].state = next ? next : 1; 424251843Sbapt print_item(&all, all.list, 425217309Snwhitehorn &items[current], 426217309Snwhitehorn states, 427217309Snwhitehorn choice, TRUE); 428251843Sbapt (void) wnoutrefresh(all.list); 429251843Sbapt (void) wmove(dialog, cur_y, cur_x); 430217309Snwhitehorn } else { 431217309Snwhitehorn items[current].state = 1; 432251843Sbapt print_list(&all, choice, scrollamt, max_choice); 433217309Snwhitehorn } 434217309Snwhitehorn } 435217309Snwhitehorn continue; /* wait for another key press */ 436217309Snwhitehorn } 437217309Snwhitehorn 438217309Snwhitehorn /* 439217309Snwhitehorn * Check if key pressed matches first character of any item tag in 440217309Snwhitehorn * list. If there is more than one match, we will cycle through 441217309Snwhitehorn * each one as the same key is pressed repeatedly. 442217309Snwhitehorn */ 443217309Snwhitehorn found = FALSE; 444217309Snwhitehorn if (!fkey) { 445217309Snwhitehorn if (button < 0 || !dialog_state.visit_items) { 446217309Snwhitehorn for (j = scrollamt + choice + 1; j < item_no; j++) { 447251843Sbapt if (check_hotkey(items, j)) { 448217309Snwhitehorn found = TRUE; 449217309Snwhitehorn i = j - scrollamt; 450217309Snwhitehorn break; 451217309Snwhitehorn } 452217309Snwhitehorn } 453217309Snwhitehorn if (!found) { 454217309Snwhitehorn for (j = 0; j <= scrollamt + choice; j++) { 455251843Sbapt if (check_hotkey(items, j)) { 456217309Snwhitehorn found = TRUE; 457217309Snwhitehorn i = j - scrollamt; 458217309Snwhitehorn break; 459217309Snwhitehorn } 460217309Snwhitehorn } 461217309Snwhitehorn } 462217309Snwhitehorn if (found) 463217309Snwhitehorn dlg_flush_getc(); 464217309Snwhitehorn } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 465217309Snwhitehorn button = j; 466217309Snwhitehorn ungetch('\n'); 467217309Snwhitehorn continue; 468217309Snwhitehorn } 469217309Snwhitehorn } 470217309Snwhitehorn 471217309Snwhitehorn /* 472217309Snwhitehorn * A single digit (1-9) positions the selection to that line in the 473217309Snwhitehorn * current screen. 474217309Snwhitehorn */ 475217309Snwhitehorn if (!found 476217309Snwhitehorn && (key <= '9') 477217309Snwhitehorn && (key > '0') 478217309Snwhitehorn && (key - '1' < max_choice)) { 479217309Snwhitehorn found = TRUE; 480217309Snwhitehorn i = key - '1'; 481217309Snwhitehorn } 482217309Snwhitehorn 483217309Snwhitehorn if (!found) { 484217309Snwhitehorn if (fkey) { 485217309Snwhitehorn found = TRUE; 486217309Snwhitehorn switch (key) { 487217309Snwhitehorn case DLGK_ITEM_FIRST: 488217309Snwhitehorn i = -scrollamt; 489217309Snwhitehorn break; 490217309Snwhitehorn case DLGK_ITEM_LAST: 491217309Snwhitehorn i = item_no - 1 - scrollamt; 492217309Snwhitehorn break; 493217309Snwhitehorn case DLGK_PAGE_PREV: 494217309Snwhitehorn if (choice) 495217309Snwhitehorn i = 0; 496217309Snwhitehorn else if (scrollamt != 0) 497217309Snwhitehorn i = -MIN(scrollamt, max_choice); 498217309Snwhitehorn else 499217309Snwhitehorn continue; 500217309Snwhitehorn break; 501217309Snwhitehorn case DLGK_PAGE_NEXT: 502217309Snwhitehorn i = MIN(choice + max_choice, item_no - scrollamt - 1); 503217309Snwhitehorn break; 504217309Snwhitehorn case DLGK_ITEM_PREV: 505217309Snwhitehorn i = choice - 1; 506217309Snwhitehorn if (choice == 0 && scrollamt == 0) 507217309Snwhitehorn continue; 508217309Snwhitehorn break; 509217309Snwhitehorn case DLGK_ITEM_NEXT: 510217309Snwhitehorn i = choice + 1; 511217309Snwhitehorn if (scrollamt + choice >= item_no - 1) 512217309Snwhitehorn continue; 513217309Snwhitehorn break; 514217309Snwhitehorn default: 515217309Snwhitehorn found = FALSE; 516217309Snwhitehorn break; 517217309Snwhitehorn } 518217309Snwhitehorn } 519217309Snwhitehorn } 520217309Snwhitehorn 521217309Snwhitehorn if (found) { 522217309Snwhitehorn if (i != choice) { 523217309Snwhitehorn getyx(dialog, cur_y, cur_x); 524217309Snwhitehorn if (i < 0 || i >= max_choice) { 525251843Sbapt if (i < 0) { 526251843Sbapt scrollamt += i; 527251843Sbapt choice = 0; 528251843Sbapt } else { 529251843Sbapt choice = max_choice - 1; 530251843Sbapt scrollamt += (i - max_choice + 1); 531217309Snwhitehorn } 532251843Sbapt print_list(&all, choice, scrollamt, max_choice); 533217309Snwhitehorn } else { 534217309Snwhitehorn choice = i; 535251843Sbapt print_list(&all, choice, scrollamt, max_choice); 536217309Snwhitehorn } 537217309Snwhitehorn } 538217309Snwhitehorn continue; /* wait for another key press */ 539217309Snwhitehorn } 540217309Snwhitehorn 541217309Snwhitehorn if (fkey) { 542217309Snwhitehorn switch (key) { 543217309Snwhitehorn case DLGK_ENTER: 544224014Snwhitehorn result = dlg_enter_buttoncode(button); 545217309Snwhitehorn break; 546217309Snwhitehorn case DLGK_FIELD_PREV: 547217309Snwhitehorn button = dlg_prev_button(buttons, button); 548217309Snwhitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 549217309Snwhitehorn FALSE, width); 550217309Snwhitehorn break; 551217309Snwhitehorn case DLGK_FIELD_NEXT: 552217309Snwhitehorn button = dlg_next_button(buttons, button); 553217309Snwhitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 554217309Snwhitehorn FALSE, width); 555217309Snwhitehorn break; 556217309Snwhitehorn#ifdef KEY_RESIZE 557217309Snwhitehorn case KEY_RESIZE: 558217309Snwhitehorn /* reset data */ 559217309Snwhitehorn height = old_height; 560217309Snwhitehorn width = old_width; 561217309Snwhitehorn /* repaint */ 562217309Snwhitehorn dlg_clear(); 563217309Snwhitehorn dlg_del_window(dialog); 564217309Snwhitehorn refresh(); 565217309Snwhitehorn dlg_mouse_free_regions(); 566217309Snwhitehorn goto retry; 567217309Snwhitehorn#endif 568217309Snwhitehorn default: 569217309Snwhitehorn if (was_mouse) { 570217309Snwhitehorn if ((key2 = dlg_ok_buttoncode(key)) >= 0) { 571217309Snwhitehorn result = key2; 572217309Snwhitehorn break; 573217309Snwhitehorn } 574217309Snwhitehorn beep(); 575217309Snwhitehorn } 576217309Snwhitehorn } 577217309Snwhitehorn } else { 578217309Snwhitehorn beep(); 579217309Snwhitehorn } 580217309Snwhitehorn } 581217309Snwhitehorn 582217309Snwhitehorn dlg_del_window(dialog); 583217309Snwhitehorn dlg_mouse_free_regions(); 584217309Snwhitehorn free(prompt); 585217309Snwhitehorn *current_item = (scrollamt + choice); 586217309Snwhitehorn return result; 587217309Snwhitehorn} 588217309Snwhitehorn 589217309Snwhitehorn/* 590217309Snwhitehorn * Display a dialog box with a list of options that can be turned on or off 591217309Snwhitehorn * The `flag' parameter is used to select between radiolist and checklist. 592217309Snwhitehorn */ 593217309Snwhitehornint 594217309Snwhitehorndialog_checklist(const char *title, 595217309Snwhitehorn const char *cprompt, 596217309Snwhitehorn int height, 597217309Snwhitehorn int width, 598217309Snwhitehorn int list_height, 599217309Snwhitehorn int item_no, 600217309Snwhitehorn char **items, 601217309Snwhitehorn int flag) 602217309Snwhitehorn{ 603217309Snwhitehorn int result; 604251843Sbapt int i, j; 605217309Snwhitehorn DIALOG_LISTITEM *listitems; 606217309Snwhitehorn bool separate_output = ((flag == FLAG_CHECK) 607217309Snwhitehorn && (dialog_vars.separate_output)); 608217309Snwhitehorn bool show_status = FALSE; 609217309Snwhitehorn int current = 0; 610255852Sdteske char *help_result; 611217309Snwhitehorn 612217309Snwhitehorn listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 613217309Snwhitehorn assert_ptr(listitems, "dialog_checklist"); 614217309Snwhitehorn 615251843Sbapt for (i = j = 0; i < item_no; ++i) { 616251843Sbapt listitems[i].name = items[j++]; 617251843Sbapt listitems[i].text = (dialog_vars.no_items 618251843Sbapt ? dlg_strempty() 619251843Sbapt : items[j++]); 620251843Sbapt listitems[i].state = !dlg_strcmp(items[j++], "on"); 621217309Snwhitehorn listitems[i].help = ((dialog_vars.item_help) 622251843Sbapt ? items[j++] 623217309Snwhitehorn : dlg_strempty()); 624217309Snwhitehorn } 625220749Snwhitehorn dlg_align_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 626217309Snwhitehorn 627217309Snwhitehorn result = dlg_checklist(title, 628217309Snwhitehorn cprompt, 629217309Snwhitehorn height, 630217309Snwhitehorn width, 631217309Snwhitehorn list_height, 632217309Snwhitehorn item_no, 633217309Snwhitehorn listitems, 634217309Snwhitehorn NULL, 635217309Snwhitehorn flag, 636217309Snwhitehorn ¤t); 637217309Snwhitehorn 638217309Snwhitehorn switch (result) { 639217309Snwhitehorn case DLG_EXIT_OK: /* FALLTHRU */ 640217309Snwhitehorn case DLG_EXIT_EXTRA: 641217309Snwhitehorn show_status = TRUE; 642217309Snwhitehorn break; 643217309Snwhitehorn case DLG_EXIT_HELP: 644255852Sdteske dlg_add_help_listitem(&result, &help_result, &listitems[current]); 645255852Sdteske if ((show_status = dialog_vars.help_status)) { 646255852Sdteske if (separate_output) { 647255852Sdteske dlg_add_string(help_result); 648255852Sdteske dlg_add_separator(); 649217309Snwhitehorn } else { 650255852Sdteske dlg_add_quoted(help_result); 651217309Snwhitehorn } 652217309Snwhitehorn } else { 653255852Sdteske dlg_add_string(help_result); 654217309Snwhitehorn } 655217309Snwhitehorn break; 656217309Snwhitehorn } 657217309Snwhitehorn 658217309Snwhitehorn if (show_status) { 659217309Snwhitehorn for (i = 0; i < item_no; i++) { 660217309Snwhitehorn if (listitems[i].state) { 661217309Snwhitehorn if (separate_output) { 662217309Snwhitehorn dlg_add_string(listitems[i].name); 663217309Snwhitehorn dlg_add_separator(); 664217309Snwhitehorn } else { 665217309Snwhitehorn if (dlg_need_separator()) 666217309Snwhitehorn dlg_add_separator(); 667251843Sbapt if (flag == FLAG_CHECK) 668251843Sbapt dlg_add_quoted(listitems[i].name); 669251843Sbapt else 670251843Sbapt dlg_add_string(listitems[i].name); 671217309Snwhitehorn } 672217309Snwhitehorn } 673217309Snwhitehorn } 674251843Sbapt dlg_add_last_key(separate_output); 675217309Snwhitehorn } 676217309Snwhitehorn 677220749Snwhitehorn dlg_free_columns(&listitems[0].text, (int) sizeof(DIALOG_LISTITEM), item_no); 678217309Snwhitehorn free(listitems); 679217309Snwhitehorn return result; 680217309Snwhitehorn} 681