1 /* 2 * $Id: menubox.c,v 1.132 2012/07/01 16:30:04 Zoltan.Kelemen Exp $ 3 * 4 * menubox.c -- implements the menu box 5 * 6 * Copyright 2000-2011,2012 Thomas E. Dickey 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public Licens, version 2.1e 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, write to 19 * Free Software Foundation, Inc. 20 * 51 Franklin St., Fifth Floor 21 * Boston, MA 02110, USA. 22 * 23 * An earlier version of this program lists as authors 24 * Savio Lam (lam836@cs.cuhk.hk) 25 */ 26 27 #include <dialog.h> 28 #include <dlg_keys.h> 29 30 static int menu_width, tag_x, item_x; 31 32 typedef enum { 33 Unselected = 0, 34 Selected, 35 Editing 36 } Mode; 37 38 #define MIN_HIGH (1 + (5 * MARGIN)) 39 40 #define INPUT_ROWS 3 /* rows per inputmenu entry */ 41 42 #define LLEN(n) ((n) * MENUBOX_TAGS) 43 #define ItemName(i) items[LLEN(i)] 44 #define ItemText(i) items[LLEN(i) + 1] 45 #define ItemHelp(i) items[LLEN(i) + 2] 46 47 #define RowHeight(i) (is_inputmenu ? ((i) * INPUT_ROWS) : ((i) * 1)) 48 #define ItemToRow(i) (is_inputmenu ? ((i) * INPUT_ROWS + 1) : (i)) 49 #define RowToItem(i) (is_inputmenu ? ((i) / INPUT_ROWS + 0) : (i)) 50 51 static void 52 print_arrows(WINDOW *win, 53 int box_x, 54 int box_y, 55 int scrollamt, 56 int max_choice, 57 int item_no, 58 int menu_height) 59 { 60 dlg_draw_scrollbar(win, 61 scrollamt, 62 scrollamt, 63 scrollamt + max_choice, 64 item_no, 65 box_x, 66 box_x + menu_width, 67 box_y, 68 box_y + menu_height + 1, 69 menubox_border2_attr, 70 menubox_border_attr); 71 } 72 73 /* 74 * Print the tag of a menu-item 75 */ 76 static void 77 print_tag(WINDOW *win, 78 DIALOG_LISTITEM * item, 79 int choice, 80 Mode selected, 81 bool is_inputmenu) 82 { 83 int my_x = item_x; 84 int my_y = ItemToRow(choice); 85 int tag_width = (my_x - tag_x - GUTTER); 86 const int *indx; 87 int limit; 88 int prefix; 89 90 indx = dlg_index_wchars(item->name); 91 prefix = (indx[1] - indx[0]); 92 93 /* highlight first char of the tag to be special */ 94 (void) wmove(win, my_y, tag_x); 95 wattrset(win, selected ? tag_key_selected_attr : tag_key_attr); 96 if (strlen(item->name) != 0) 97 (void) waddnstr(win, item->name, prefix); 98 /* print rest of the string */ 99 wattrset(win, selected ? tag_selected_attr : tag_attr); 100 if ((int) strlen(item->name) > prefix) { 101 limit = dlg_limit_columns(item->name, tag_width, 1); 102 if (limit > 0) 103 (void) waddnstr(win, item->name + indx[1], indx[limit] - indx[1]); 104 } 105 } 106 107 /* 108 * Print menu item 109 */ 110 static void 111 print_item(WINDOW *win, 112 DIALOG_LISTITEM * items, 113 int choice, 114 Mode selected, 115 bool is_inputmenu) 116 { 117 chtype save = dlg_get_attrs(win); 118 int n; 119 int my_width = menu_width; 120 int my_x = item_x; 121 int my_y = ItemToRow(choice); 122 chtype attr = A_NORMAL; 123 chtype textchar; 124 chtype bordchar; 125 126 switch (selected) { 127 default: 128 case Unselected: 129 textchar = item_attr; 130 bordchar = item_attr; 131 break; 132 case Selected: 133 textchar = item_selected_attr; 134 bordchar = item_selected_attr; 135 break; 136 case Editing: 137 textchar = inputbox_attr; 138 bordchar = dialog_attr; 139 break; 140 } 141 142 /* Clear 'residue' of last item and mark current current item */ 143 if (is_inputmenu) { 144 wattrset(win, (selected != Unselected) ? item_selected_attr : item_attr); 145 for (n = my_y - 1; n < my_y + INPUT_ROWS - 1; n++) { 146 wmove(win, n, 0); 147 wprintw(win, "%*s", my_width, " "); 148 } 149 } else { 150 wattrset(win, menubox_attr); 151 wmove(win, my_y, 0); 152 wprintw(win, "%*s", my_width, " "); 153 } 154 155 print_tag(win, items, choice, selected, is_inputmenu); 156 157 /* Draw the input field box (only for inputmenu) */ 158 (void) wmove(win, my_y, my_x); 159 if (is_inputmenu) { 160 my_width -= 1; 161 dlg_draw_box(win, my_y - 1, my_x, INPUT_ROWS, my_width - my_x - tag_x, 162 bordchar, 163 bordchar); 164 my_width -= 1; 165 ++my_x; 166 } 167 168 /* print actual item */ 169 wmove(win, my_y, my_x); 170 wattrset(win, textchar); 171 dlg_print_text(win, items->text, my_width - my_x, &attr); 172 173 if (selected) { 174 dlg_item_help(items->help); 175 } 176 wattrset(win, save); 177 } 178 179 /* 180 * Allow the user to edit the text of a menu entry. 181 */ 182 static int 183 input_menu_edit(WINDOW *win, 184 DIALOG_LISTITEM * items, 185 int choice, 186 char **resultp) 187 { 188 chtype save = dlg_get_attrs(win); 189 char *result; 190 int offset = 0; 191 int key = 0, fkey = 0; 192 int first = TRUE; 193 /* see above */ 194 bool is_inputmenu = TRUE; 195 int y = ItemToRow(choice); 196 int code = TRUE; 197 int max_len = dlg_max_input(MAX((int) strlen(items->text) + 1, MAX_LEN)); 198 199 result = dlg_malloc(char, (size_t) max_len); 200 assert_ptr(result, "input_menu_edit"); 201 202 /* original item is used to initialize the input string. */ 203 result[0] = '\0'; 204 strcpy(result, items->text); 205 206 print_item(win, items, choice, Editing, TRUE); 207 208 /* taken out of inputbox.c - but somewhat modified */ 209 for (;;) { 210 if (!first) 211 key = dlg_mouse_wgetch(win, &fkey); 212 if (dlg_edit_string(result, &offset, key, fkey, first)) { 213 dlg_show_string(win, result, offset, inputbox_attr, 214 y, item_x + 1, menu_width - item_x - 3, 215 FALSE, first); 216 first = FALSE; 217 } else if (key == ESC || key == TAB) { 218 code = FALSE; 219 break; 220 } else { 221 break; 222 } 223 } 224 print_item(win, items, choice, Selected, TRUE); 225 wattrset(win, save); 226 227 *resultp = result; 228 return code; 229 } 230 231 static int 232 handle_button(int code, DIALOG_LISTITEM * items, int choice) 233 { 234 switch (code) { 235 case DLG_EXIT_OK: /* FALLTHRU */ 236 case DLG_EXIT_EXTRA: 237 dlg_add_string(items[choice].name); 238 break; 239 case DLG_EXIT_HELP: 240 dlg_add_result("HELP "); 241 if (USE_ITEM_HELP(items[choice].help)) { 242 dlg_add_string(items[choice].help); 243 code = DLG_EXIT_ITEM_HELP; 244 } else { 245 dlg_add_string(items[choice].name); 246 } 247 break; 248 } 249 return code; 250 } 251 252 int 253 dlg_renamed_menutext(DIALOG_LISTITEM * items, int current, char *newtext) 254 { 255 if (dialog_vars.input_result) 256 dialog_vars.input_result[0] = '\0'; 257 dlg_add_result("RENAMED "); 258 dlg_add_string(items[current].name); 259 dlg_add_result(" "); 260 dlg_add_string(newtext); 261 return DLG_EXIT_EXTRA; 262 } 263 264 int 265 dlg_dummy_menutext(DIALOG_LISTITEM * items, int current, char *newtext) 266 { 267 (void) items; 268 (void) current; 269 (void) newtext; 270 return DLG_EXIT_ERROR; 271 } 272 273 /* 274 * This is an alternate interface to 'menu' which allows the application 275 * to read the list item states back directly without putting them in the 276 * output buffer. 277 */ 278 int 279 dlg_menu(const char *title, 280 const char *cprompt, 281 int height, 282 int width, 283 int menu_height, 284 int item_no, 285 DIALOG_LISTITEM * items, 286 int *current_item, 287 DIALOG_INPUTMENU rename_menutext) 288 { 289 /* *INDENT-OFF* */ 290 static DLG_KEYS_BINDING binding[] = { 291 HELPKEY_BINDINGS, 292 ENTERKEY_BINDINGS, 293 DLG_KEYS_DATA( DLGK_FIELD_NEXT, ' ' ), 294 DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), 295 DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), 296 DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), 297 DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_LEFT ), 298 DLG_KEYS_DATA( DLGK_ITEM_NEXT, '+' ), 299 DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), 300 DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), 301 DLG_KEYS_DATA( DLGK_ITEM_PREV, '-' ), 302 DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), 303 DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), 304 DLG_KEYS_DATA( DLGK_PAGE_FIRST, KEY_HOME ), 305 DLG_KEYS_DATA( DLGK_PAGE_LAST, KEY_END ), 306 DLG_KEYS_DATA( DLGK_PAGE_LAST, KEY_LL ), 307 DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), 308 DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ), 309 END_KEYS_BINDING 310 }; 311 static DLG_KEYS_BINDING binding2[] = { 312 INPUTSTR_BINDINGS, 313 HELPKEY_BINDINGS, 314 ENTERKEY_BINDINGS, 315 END_KEYS_BINDING 316 }; 317 /* *INDENT-ON* */ 318 319 #ifdef KEY_RESIZE 320 int old_height = height; 321 int old_width = width; 322 #endif 323 int i, j, x, y, cur_x, cur_y, box_x, box_y; 324 int key = 0, fkey; 325 int button = dialog_state.visit_items ? -1 : dlg_default_button(); 326 int choice = dlg_default_listitem(items); 327 int result = DLG_EXIT_UNKNOWN; 328 int scrollamt = 0; 329 int max_choice; 330 int found; 331 int use_height, use_width, name_width, text_width; 332 WINDOW *dialog, *menu; 333 char *prompt = dlg_strclone(cprompt); 334 const char **buttons = dlg_ok_labels(); 335 bool is_inputmenu = ((rename_menutext != 0) 336 && (rename_menutext != dlg_dummy_menutext)); 337 338 dlg_does_output(); 339 dlg_tab_correct_str(prompt); 340 341 #ifdef KEY_RESIZE 342 retry: 343 #endif 344 345 use_height = menu_height; 346 use_width = dlg_calc_list_width(item_no, items) + 10; 347 use_width = MAX(26, use_width); 348 if (use_height == 0) { 349 /* calculate height without items (4) */ 350 dlg_auto_size(title, prompt, &height, &width, MIN_HIGH, use_width); 351 dlg_calc_listh(&height, &use_height, item_no); 352 } else { 353 dlg_auto_size(title, prompt, &height, &width, MIN_HIGH + use_height, use_width); 354 } 355 dlg_button_layout(buttons, &width); 356 dlg_print_size(height, width); 357 dlg_ctl_size(height, width); 358 359 x = dlg_box_x_ordinate(width); 360 y = dlg_box_y_ordinate(height); 361 362 dialog = dlg_new_window(height, width, y, x); 363 dlg_register_window(dialog, "menubox", binding); 364 dlg_register_buttons(dialog, "menubox", buttons); 365 366 dlg_mouse_setbase(x, y); 367 368 dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr); 369 dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr); 370 dlg_draw_title(dialog, title); 371 372 wattrset(dialog, dialog_attr); 373 dlg_print_autowrap(dialog, prompt, height, width); 374 375 menu_width = width - 6; 376 getyx(dialog, cur_y, cur_x); 377 box_y = cur_y + 1; 378 box_x = (width - menu_width) / 2 - 1; 379 380 /* 381 * After displaying the prompt, we know how much space we really have. 382 * Limit the list to avoid overwriting the ok-button. 383 */ 384 if (use_height + MIN_HIGH > height - cur_y) 385 use_height = height - MIN_HIGH - cur_y; 386 if (use_height <= 0) 387 use_height = 1; 388 389 /* Find out maximal number of displayable items at once. */ 390 max_choice = MIN(use_height, 391 RowHeight(item_no)); 392 if (is_inputmenu) 393 max_choice /= INPUT_ROWS; 394 395 /* create new window for the menu */ 396 menu = dlg_sub_window(dialog, use_height, menu_width, 397 y + box_y + 1, 398 x + box_x + 1); 399 dlg_register_window(menu, "menu", binding2); 400 dlg_register_buttons(menu, "menu", buttons); 401 402 /* draw a box around the menu items */ 403 dlg_draw_box(dialog, box_y, box_x, use_height + 2, menu_width + 2, 404 menubox_border_attr, menubox_border2_attr); 405 406 name_width = 0; 407 text_width = 0; 408 409 /* Find length of longest item to center menu * 410 * only if --menu was given, using --inputmenu * 411 * won't be centered. */ 412 for (i = 0; i < item_no; i++) { 413 name_width = MAX(name_width, dlg_count_columns(items[i].name)); 414 text_width = MAX(text_width, dlg_count_columns(items[i].text)); 415 } 416 417 /* If the name+text is wider than the list is allowed, then truncate 418 * one or both of them. If the name is no wider than 30% of the list, 419 * leave it intact. 420 * 421 * FIXME: the gutter width and name/list ratio should be configurable. 422 */ 423 use_width = (menu_width - GUTTER); 424 if (text_width + name_width > use_width) { 425 int need = (int) (0.30 * use_width); 426 if (name_width > need) { 427 int want = (int) (use_width 428 * ((double) name_width) 429 / (text_width + name_width)); 430 name_width = (want > need) ? want : need; 431 } 432 text_width = use_width - name_width; 433 } 434 435 tag_x = (is_inputmenu 436 ? 0 437 : (use_width - text_width - name_width) / 2); 438 item_x = name_width + tag_x + GUTTER; 439 440 if (choice - scrollamt >= max_choice) { 441 scrollamt = choice - (max_choice - 1); 442 choice = max_choice - 1; 443 } 444 445 /* Print the menu */ 446 for (i = 0; i < max_choice; i++) { 447 print_item(menu, 448 &items[i + scrollamt], 449 i, 450 (i == choice) ? Selected : Unselected, 451 is_inputmenu); 452 } 453 (void) wnoutrefresh(menu); 454 455 /* register the new window, along with its borders */ 456 dlg_mouse_mkbigregion(box_y + 1, box_x, use_height + 2, menu_width + 2, 457 KEY_MAX, 1, 1, 1 /* by lines */ ); 458 459 print_arrows(dialog, box_x, box_y, scrollamt, max_choice, item_no, use_height); 460 461 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width); 462 463 dlg_trace_win(dialog); 464 while (result == DLG_EXIT_UNKNOWN) { 465 if (button < 0) /* --visit-items */ 466 wmove(dialog, box_y + ItemToRow(choice) + 1, box_x + tag_x + 1); 467 468 key = dlg_mouse_wgetch(dialog, &fkey); 469 if (dlg_result_key(key, fkey, &result)) 470 break; 471 472 found = FALSE; 473 if (fkey) { 474 /* 475 * Allow a mouse-click on a box to switch selection to that box. 476 * Handling a button click is a little more complicated, since we 477 * push a KEY_ENTER back onto the input stream so we'll put the 478 * cursor at the right place before handling the "keypress". 479 */ 480 if (key >= DLGK_MOUSE(KEY_MAX)) { 481 key -= DLGK_MOUSE(KEY_MAX); 482 i = RowToItem(key); 483 if (i < max_choice) { 484 found = TRUE; 485 } else { 486 beep(); 487 continue; 488 } 489 } else if (is_DLGK_MOUSE(key) 490 && dlg_ok_buttoncode(key - M_EVENT) >= 0) { 491 button = (key - M_EVENT); 492 ungetch('\n'); 493 continue; 494 } 495 } else { 496 /* 497 * Check if key pressed matches first character of any item tag in 498 * list. If there is more than one match, we will cycle through 499 * each one as the same key is pressed repeatedly. 500 */ 501 if (button < 0 || !dialog_state.visit_items) { 502 for (j = scrollamt + choice + 1; j < item_no; j++) { 503 if (dlg_match_char(dlg_last_getc(), items[j].name)) { 504 found = TRUE; 505 i = j - scrollamt; 506 break; 507 } 508 } 509 if (!found) { 510 for (j = 0; j <= scrollamt + choice; j++) { 511 if (dlg_match_char(dlg_last_getc(), items[j].name)) { 512 found = TRUE; 513 i = j - scrollamt; 514 break; 515 } 516 } 517 } 518 if (found) 519 dlg_flush_getc(); 520 } else if ((j = dlg_char_to_button(key, buttons)) >= 0) { 521 button = j; 522 ungetch('\n'); 523 continue; 524 } 525 526 /* 527 * A single digit (1-9) positions the selection to that line in the 528 * current screen. 529 */ 530 if (!found 531 && (key <= '9') 532 && (key > '0') 533 && (key - '1' < max_choice)) { 534 found = TRUE; 535 i = key - '1'; 536 } 537 } 538 539 if (!found && fkey) { 540 found = TRUE; 541 switch (key) { 542 case DLGK_PAGE_FIRST: 543 i = -scrollamt; 544 break; 545 case DLGK_PAGE_LAST: 546 i = item_no - 1 - scrollamt; 547 break; 548 case DLGK_MOUSE(KEY_PPAGE): 549 case DLGK_PAGE_PREV: 550 if (choice) 551 i = 0; 552 else if (scrollamt != 0) 553 i = -MIN(scrollamt, max_choice); 554 else 555 continue; 556 break; 557 case DLGK_MOUSE(KEY_NPAGE): 558 case DLGK_PAGE_NEXT: 559 i = MIN(choice + max_choice, item_no - scrollamt - 1); 560 break; 561 case DLGK_ITEM_PREV: 562 i = choice - 1; 563 if (choice == 0 && scrollamt == 0) 564 continue; 565 break; 566 case DLGK_ITEM_NEXT: 567 i = choice + 1; 568 if (scrollamt + choice >= item_no - 1) 569 continue; 570 break; 571 default: 572 found = FALSE; 573 break; 574 } 575 } 576 577 if (found) { 578 if (i != choice) { 579 getyx(dialog, cur_y, cur_x); 580 if (i < 0 || i >= max_choice) { 581 #if defined(NCURSES_VERSION_MAJOR) && NCURSES_VERSION_MAJOR < 5 582 /* 583 * Using wscrl to assist ncurses scrolling is not needed 584 * in version 5.x 585 */ 586 if (i == -1) { 587 if (use_height > 1) { 588 /* De-highlight current first item */ 589 print_item(menu, 590 &items[scrollamt], 591 0, Unselected, is_inputmenu); 592 scrollok(menu, TRUE); 593 wscrl(menu, -RowHeight(1)); 594 scrollok(menu, FALSE); 595 } 596 scrollamt--; 597 print_item(menu, 598 &items[scrollamt], 599 0, Selected, is_inputmenu); 600 } else if (i == max_choice) { 601 if (use_height > 1) { 602 /* De-highlight current last item before scrolling up */ 603 print_item(menu, 604 &items[scrollamt + max_choice - 1], 605 max_choice - 1, 606 Unselected, 607 is_inputmenu); 608 scrollok(menu, TRUE); 609 wscrl(menu, RowHeight(1)); 610 scrollok(menu, FALSE); 611 } 612 scrollamt++; 613 print_item(menu, 614 &items[scrollamt + max_choice - 1], 615 max_choice - 1, TRUE, 616 is_inputmenu); 617 } else 618 #endif 619 { 620 if (i < 0) { 621 scrollamt += i; 622 choice = 0; 623 } else { 624 choice = max_choice - 1; 625 scrollamt += (i - max_choice + 1); 626 } 627 for (i = 0; i < max_choice; i++) { 628 print_item(menu, 629 &items[scrollamt + i], 630 i, 631 (i == choice) ? Selected : Unselected, 632 is_inputmenu); 633 } 634 } 635 /* Clean bottom lines */ 636 if (is_inputmenu) { 637 int spare_lines, x_count; 638 spare_lines = use_height % INPUT_ROWS; 639 wattrset(menu, menubox_attr); 640 for (; spare_lines; spare_lines--) { 641 wmove(menu, use_height - spare_lines, 0); 642 for (x_count = 0; x_count < menu_width; 643 x_count++) { 644 waddch(menu, ' '); 645 } 646 } 647 } 648 (void) wnoutrefresh(menu); 649 print_arrows(dialog, 650 box_x, box_y, 651 scrollamt, max_choice, item_no, use_height); 652 } else { 653 /* De-highlight current item */ 654 print_item(menu, 655 &items[scrollamt + choice], 656 choice, 657 Unselected, 658 is_inputmenu); 659 /* Highlight new item */ 660 choice = i; 661 print_item(menu, 662 &items[scrollamt + choice], 663 choice, 664 Selected, 665 is_inputmenu); 666 (void) wnoutrefresh(menu); 667 print_arrows(dialog, 668 box_x, box_y, 669 scrollamt, max_choice, item_no, use_height); 670 (void) wmove(dialog, cur_y, cur_x); 671 wrefresh(dialog); 672 } 673 } 674 continue; /* wait for another key press */ 675 } 676 677 if (fkey) { 678 switch (key) { 679 case DLGK_FIELD_PREV: 680 button = dlg_prev_button(buttons, button); 681 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 682 FALSE, width); 683 break; 684 case DLGK_FIELD_NEXT: 685 button = dlg_next_button(buttons, button); 686 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, 687 FALSE, width); 688 break; 689 case DLGK_ENTER: 690 if (is_inputmenu) 691 result = dlg_ok_buttoncode(button); 692 else 693 result = dlg_enter_buttoncode(button); 694 695 /* 696 * If dlg_menu() is called from dialog_menu(), we want to 697 * capture the results into dialog_vars.input_result. 698 */ 699 if (result == DLG_EXIT_ERROR) { 700 result = DLG_EXIT_UNKNOWN; 701 } else if (is_inputmenu 702 || rename_menutext == dlg_dummy_menutext) { 703 result = handle_button(result, 704 items, 705 scrollamt + choice); 706 } 707 708 /* 709 * If we have a rename_menutext function, interpret the Extra 710 * button as a request to rename the menu's text. If that 711 * function doesn't return "Unknown", we will exit from this 712 * function. Usually that is done for dialog_menu(), so the 713 * shell script can use the updated value. If it does return 714 * "Unknown", update the list item only. A direct caller of 715 * dlg_menu() can free the renamed value - we cannot. 716 */ 717 if (is_inputmenu && result == DLG_EXIT_EXTRA) { 718 char *tmp; 719 720 if (input_menu_edit(menu, 721 &items[scrollamt + choice], 722 choice, 723 &tmp)) { 724 result = rename_menutext(items, scrollamt + choice, tmp); 725 if (result == DLG_EXIT_UNKNOWN) { 726 items[scrollamt + choice].text = tmp; 727 } else { 728 free(tmp); 729 } 730 } else { 731 result = DLG_EXIT_UNKNOWN; 732 print_item(menu, 733 &items[scrollamt + choice], 734 choice, 735 Selected, 736 is_inputmenu); 737 (void) wnoutrefresh(menu); 738 free(tmp); 739 } 740 741 if (result == DLG_EXIT_UNKNOWN) { 742 dlg_draw_buttons(dialog, height - 2, 0, 743 buttons, button, FALSE, width); 744 } 745 } 746 break; 747 #ifdef KEY_RESIZE 748 case KEY_RESIZE: 749 /* reset data */ 750 height = old_height; 751 width = old_width; 752 /* repaint */ 753 dlg_clear(); 754 dlg_del_window(dialog); 755 refresh(); 756 dlg_mouse_free_regions(); 757 goto retry; 758 #endif 759 default: 760 flash(); 761 break; 762 } 763 } 764 } 765 766 dlg_mouse_free_regions(); 767 dlg_unregister_window(menu); 768 dlg_del_window(dialog); 769 free(prompt); 770 771 *current_item = scrollamt + choice; 772 return result; 773 } 774 775 /* 776 * Display a menu for choosing among a number of options 777 */ 778 int 779 dialog_menu(const char *title, 780 const char *cprompt, 781 int height, 782 int width, 783 int menu_height, 784 int item_no, 785 char **items) 786 { 787 int result; 788 int choice; 789 int i; 790 DIALOG_LISTITEM *listitems; 791 792 listitems = dlg_calloc(DIALOG_LISTITEM, (size_t) item_no + 1); 793 assert_ptr(listitems, "dialog_menu"); 794 795 for (i = 0; i < item_no; ++i) { 796 listitems[i].name = ItemName(i); 797 listitems[i].text = ItemText(i); 798 listitems[i].help = ((dialog_vars.item_help) 799 ? ItemHelp(i) 800 : dlg_strempty()); 801 } 802 dlg_align_columns(&listitems[0].text, sizeof(DIALOG_LISTITEM), item_no); 803 804 result = dlg_menu(title, 805 cprompt, 806 height, 807 width, 808 menu_height, 809 item_no, 810 listitems, 811 &choice, 812 (dialog_vars.input_menu 813 ? dlg_renamed_menutext 814 : dlg_dummy_menutext)); 815 816 dlg_free_columns(&listitems[0].text, sizeof(DIALOG_LISTITEM), item_no); 817 free(listitems); 818 return result; 819 } 820