menubox.c (8858) | menubox.c (12983) |
---|---|
1/* 2 * menubox.c -- implements the menu box 3 * 4 * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 5 * | 1/* 2 * menubox.c -- implements the menu box 3 * 4 * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 5 * |
6 * Substantial rennovation: 12/18/95, Jordan K. Hubbard 7 * |
|
6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 11 unchanged lines hidden (view full) --- 25 26static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected); 27 28static int menu_width, tag_x, item_x; 29 30/* 31 * Display a menu for choosing among a number of options 32 */ | 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 2 11 * of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 11 unchanged lines hidden (view full) --- 27 28static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected); 29 30static int menu_width, tag_x, item_x; 31 32/* 33 * Display a menu for choosing among a number of options 34 */ |
33int dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height, int item_no, unsigned char **items, unsigned char *result, int *ch, int *sc) | 35int dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height, 36 int item_no, void *it, unsigned char *result, int *ch, int *sc) |
34{ 35 int i, j, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0, 36 l, k, scroll = 0, max_choice, redraw_menu = FALSE; | 37{ 38 int i, j, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0, 39 l, k, scroll = 0, max_choice, redraw_menu = FALSE; |
40 char okButton, cancelButton; |
|
37 WINDOW *dialog, *menu; | 41 WINDOW *dialog, *menu; |
42 unsigned char **items; 43 dialogMenuItem *ditems; |
|
38 39 if (ch) /* restore menu item info */ 40 choice = *ch; 41 if (sc) 42 scroll = *sc; 43 | 44 45 if (ch) /* restore menu item info */ 46 choice = *ch; 47 if (sc) 48 scroll = *sc; 49 |
50 /* If item_no is a positive integer, use old item specification format */ 51 if (item_no >= 0) { 52 items = it; 53 ditems = NULL; 54 } 55 /* It's the new specification format - fake the rest of the code out */ 56 else { 57 item_no = abs(item_no); 58 ditems = it; 59 items = (unsigned char **)alloca((item_no * 2) * sizeof(unsigned char *)); 60 61 /* Initializes status */ 62 for (i = 0; i < item_no; i++) { 63 items[i*2] = ditems[i].prompt; 64 items[i*2 + 1] = ditems[i].title; 65 } 66 } |
|
44 max_choice = MIN(menu_height, item_no); 45 46 tag_x = 0; 47 item_x = 0; 48 /* Find length of longest item in order to center menu */ 49 for (i = 0; i < item_no; i++) { 50 l = strlen(items[i*2]); 51 for (j = 0; j < item_no; j++) { 52 k = strlen(items[j*2 + 1]); 53 tag_x = MAX(tag_x, l + k + 2); 54 } 55 item_x = MAX(item_x, l); 56 } 57 if (height < 0) | 67 max_choice = MIN(menu_height, item_no); 68 69 tag_x = 0; 70 item_x = 0; 71 /* Find length of longest item in order to center menu */ 72 for (i = 0; i < item_no; i++) { 73 l = strlen(items[i*2]); 74 for (j = 0; j < item_no; j++) { 75 k = strlen(items[j*2 + 1]); 76 tag_x = MAX(tag_x, l + k + 2); 77 } 78 item_x = MAX(item_x, l); 79 } 80 if (height < 0) |
58 height = strheight(prompt)+menu_height+4+2; | 81 height = strheight(prompt)+menu_height+4+2; |
59 if (width < 0) { | 82 if (width < 0) { |
60 i = strwidth(prompt); 61 j = ((title != NULL) ? strwidth(title) : 0); 62 width = MAX(i,j); 63 width = MAX(width,tag_x+4)+4; | 83 i = strwidth(prompt); 84 j = ((title != NULL) ? strwidth(title) : 0); 85 width = MAX(i,j); 86 width = MAX(width,tag_x+4)+4; |
64 } 65 width = MAX(width,24); 66 67 if (width > COLS) | 87 } 88 width = MAX(width,24); 89 90 if (width > COLS) |
68 width = COLS; | 91 width = COLS; |
69 if (height > LINES) | 92 if (height > LINES) |
70 height = LINES; | 93 height = LINES; |
71 /* center dialog box on screen */ 72 x = (COLS - width)/2; 73 y = (LINES - height)/2; 74 75#ifdef HAVE_NCURSES 76 if (use_shadow) 77 draw_shadow(stdscr, y, x, height, width); 78#endif 79 dialog = newwin(height, width, y, x); 80 if (dialog == NULL) { 81 endwin(); 82 fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x); | 94 /* center dialog box on screen */ 95 x = (COLS - width)/2; 96 y = (LINES - height)/2; 97 98#ifdef HAVE_NCURSES 99 if (use_shadow) 100 draw_shadow(stdscr, y, x, height, width); 101#endif 102 dialog = newwin(height, width, y, x); 103 if (dialog == NULL) { 104 endwin(); 105 fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x); |
83 exit(1); | 106 return -1; |
84 } 85 keypad(dialog, TRUE); 86 87 draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); 88 wattrset(dialog, border_attr); 89 wmove(dialog, height-3, 0); 90 waddch(dialog, ACS_LTEE); 91 for (i = 0; i < width-2; i++) --- 20 unchanged lines hidden (view full) --- 112 box_y = cur_y + 1; 113 box_x = (width - menu_width)/2 - 1; 114 115 /* create new window for the menu */ 116 menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1); 117 if (menu == NULL) { 118 endwin(); 119 fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", menu_height,menu_width,y+box_y+1,x+box_x+1); | 107 } 108 keypad(dialog, TRUE); 109 110 draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr); 111 wattrset(dialog, border_attr); 112 wmove(dialog, height-3, 0); 113 waddch(dialog, ACS_LTEE); 114 for (i = 0; i < width-2; i++) --- 20 unchanged lines hidden (view full) --- 135 box_y = cur_y + 1; 136 box_x = (width - menu_width)/2 - 1; 137 138 /* create new window for the menu */ 139 menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1); 140 if (menu == NULL) { 141 endwin(); 142 fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", menu_height,menu_width,y+box_y+1,x+box_x+1); |
120 exit(1); | 143 return -1; |
121 } 122 keypad(menu, TRUE); 123 124 /* draw a box around the menu items */ 125 draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr); 126 127 tag_x = (menu_width - tag_x) / 2; 128 item_x = tag_x + item_x + 2; 129 130 /* Print the menu */ 131 for (i = 0; i < max_choice; i++) 132 print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); 133 wnoutrefresh(menu); 134 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 135 136 display_helpline(dialog, height-1, width); 137 138 x = width/2-11; 139 y = height-2; | 144 } 145 keypad(menu, TRUE); 146 147 /* draw a box around the menu items */ 148 draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr); 149 150 tag_x = (menu_width - tag_x) / 2; 151 item_x = tag_x + item_x + 2; 152 153 /* Print the menu */ 154 for (i = 0; i < max_choice; i++) 155 print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); 156 wnoutrefresh(menu); 157 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 158 159 display_helpline(dialog, height-1, width); 160 161 x = width/2-11; 162 y = height-2; |
140 print_button(dialog, "Cancel", y, x+14, FALSE); 141 print_button(dialog, " OK ", y, x, TRUE); | |
142 | 163 |
164 if (ditems && result) { 165 cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]); 166 print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, 167 ditems[CANCEL_BUTTON].checked ? (*ditems[CANCEL_BUTTON].checked)(&ditems[CANCEL_BUTTON]) : FALSE); 168 okButton = toupper(ditems[OK_BUTTON].prompt[0]); 169 print_button(dialog, ditems[OK_BUTTON].prompt, y, x, 170 ditems[OK_BUTTON].checked ? (*ditems[OK_BUTTON].checked)(&ditems[OK_BUTTON]) : TRUE); 171 } 172 else { 173 cancelButton = 'C'; 174 print_button(dialog, "Cancel", y, x + 14, FALSE); 175 okButton = 'O'; 176 print_button(dialog, " OK ", y, x, TRUE); 177 } 178 |
|
143 wrefresh(dialog); 144 145 while (key != ESC) { 146 key = wgetch(dialog); | 179 wrefresh(dialog); 180 181 while (key != ESC) { 182 key = wgetch(dialog); |
183 184 /* Shortcut to OK? */ 185 if (toupper(key) == okButton) { 186 if (ditems && result && ditems[OK_BUTTON].fire) { 187 if ((*ditems[OK_BUTTON].fire)(&ditems[OK_BUTTON]) == DITEM_FAILURE) 188 continue; 189 else 190 delwin(dialog); 191 } 192 else { 193 delwin(dialog); 194 strcpy(result, items[(scroll+choice)*2]); 195 } 196 return 0; 197 } 198 /* Shortcut to cancel? */ 199 else if (toupper(key) == cancelButton) { 200 if (ditems && result && ditems[CANCEL_BUTTON].fire) { 201 if ((*ditems[CANCEL_BUTTON].fire)(&ditems[CANCEL_BUTTON]) == DITEM_FAILURE) 202 continue; 203 } 204 delwin(dialog); 205 return 1; 206 } 207 |
|
147 /* Check if key pressed matches first character of any item tag in menu */ 148 for (i = 0; i < max_choice; i++) 149 if (key < 0x100 && toupper(key) == toupper(items[(scroll+i)*2][0])) 150 break; 151 152 if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || 153 key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') { 154 if (key >= '1' && key <= MIN('9', '0'+max_choice)) 155 i = key - '1'; 156 else if (key == KEY_UP || key == '-') { 157 if (!choice) { 158 if (scroll) { | 208 /* Check if key pressed matches first character of any item tag in menu */ 209 for (i = 0; i < max_choice; i++) 210 if (key < 0x100 && toupper(key) == toupper(items[(scroll+i)*2][0])) 211 break; 212 213 if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || 214 key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') { 215 if (key >= '1' && key <= MIN('9', '0'+max_choice)) 216 i = key - '1'; 217 else if (key == KEY_UP || key == '-') { 218 if (!choice) { 219 if (scroll) { |
159#ifdef BROKEN_WSCRL 160 /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation 161 violation when scrolling windows of height = 4, so scrolling is not 162 used for now */ 163 scroll--; 164 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 165 /* Reprint menu to scroll down */ 166 for (i = 0; i < max_choice; i++) 167 print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); 168 169#else 170 | |
171 /* Scroll menu down */ 172 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 173 if (menu_height > 1) { 174 /* De-highlight current first item before scrolling down */ 175 print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, FALSE); 176 scrollok(menu, TRUE); 177 wscrl(menu, -1); 178 scrollok(menu, FALSE); 179 } 180 scroll--; 181 print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, TRUE); | 220 /* Scroll menu down */ 221 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 222 if (menu_height > 1) { 223 /* De-highlight current first item before scrolling down */ 224 print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, FALSE); 225 scrollok(menu, TRUE); 226 wscrl(menu, -1); 227 scrollok(menu, FALSE); 228 } 229 scroll--; 230 print_item(menu, items[scroll*2], items[scroll*2 + 1], 0, TRUE); |
182#endif | |
183 wnoutrefresh(menu); 184 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 185 wrefresh(dialog); 186 } 187 continue; /* wait for another key press */ 188 } 189 else 190 i = choice - 1; 191 } 192 else if (key == KEY_DOWN || key == '+') 193 if (choice == max_choice - 1) { 194 if (scroll+choice < item_no-1) { | 231 wnoutrefresh(menu); 232 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 233 wrefresh(dialog); 234 } 235 continue; /* wait for another key press */ 236 } 237 else 238 i = choice - 1; 239 } 240 else if (key == KEY_DOWN || key == '+') 241 if (choice == max_choice - 1) { 242 if (scroll+choice < item_no-1) { |
195#ifdef BROKEN_WSCRL 196 /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation 197 violation when scrolling windows of height = 4, so scrolling is not 198 used for now */ 199 scroll++; 200 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 201 /* Reprint menu to scroll up */ 202 for (i = 0; i < max_choice; i++) 203 print_item(menu, items[(scroll+i)*2], items[(scroll+i)*2 + 1], i, i == choice); 204 205#else 206 | |
207 /* Scroll menu up */ 208 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 209 if (menu_height > 1) { 210 /* De-highlight current last item before scrolling up */ 211 print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, FALSE); 212 scrollok(menu, TRUE); 213 scroll(menu); 214 scrollok(menu, FALSE); 215 } 216 scroll++; 217 print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, TRUE); | 243 /* Scroll menu up */ 244 getyx(dialog, cur_y, cur_x); /* Save cursor position */ 245 if (menu_height > 1) { 246 /* De-highlight current last item before scrolling up */ 247 print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, FALSE); 248 scrollok(menu, TRUE); 249 scroll(menu); 250 scrollok(menu, FALSE); 251 } 252 scroll++; 253 print_item(menu, items[(scroll+max_choice-1)*2], items[(scroll+max_choice-1)*2 + 1], max_choice-1, TRUE); |
218#endif | |
219 wnoutrefresh(menu); 220 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 221 wrefresh(dialog); 222 } 223 continue; /* wait for another key press */ 224 } 225 else 226 i = choice + 1; --- 23 unchanged lines hidden (view full) --- 250 case KEY_PPAGE: 251 if (scroll > height-4) { /* can we go up? */ 252 scroll -= (height-4); 253 } else { 254 scroll = 0; 255 } 256 redraw_menu = TRUE; 257 break; | 254 wnoutrefresh(menu); 255 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 256 wrefresh(dialog); 257 } 258 continue; /* wait for another key press */ 259 } 260 else 261 i = choice + 1; --- 23 unchanged lines hidden (view full) --- 285 case KEY_PPAGE: 286 if (scroll > height-4) { /* can we go up? */ 287 scroll -= (height-4); 288 } else { 289 scroll = 0; 290 } 291 redraw_menu = TRUE; 292 break; |
293 |
|
258 case KEY_NPAGE: 259 if (scroll + menu_height >= item_no-1 - menu_height) { /* can we go down a full page? */ 260 scroll = item_no - menu_height; 261 if (scroll < 0) scroll = 0; 262 } else { 263 scroll += menu_height; 264 } 265 redraw_menu = TRUE; 266 break; | 294 case KEY_NPAGE: 295 if (scroll + menu_height >= item_no-1 - menu_height) { /* can we go down a full page? */ 296 scroll = item_no - menu_height; 297 if (scroll < 0) scroll = 0; 298 } else { 299 scroll += menu_height; 300 } 301 redraw_menu = TRUE; 302 break; |
303 |
|
267 case KEY_HOME: 268 scroll = 0; 269 choice = 0; 270 redraw_menu = TRUE; 271 break; | 304 case KEY_HOME: 305 scroll = 0; 306 choice = 0; 307 redraw_menu = TRUE; 308 break; |
309 |
|
272 case KEY_END: 273 scroll = item_no - menu_height; 274 if (scroll < 0) scroll = 0; 275 choice = max_choice - 1; 276 redraw_menu = TRUE; 277 break; | 310 case KEY_END: 311 scroll = item_no - menu_height; 312 if (scroll < 0) scroll = 0; 313 choice = max_choice - 1; 314 redraw_menu = TRUE; 315 break; |
278 case 'O': 279 case 'o': 280 delwin(dialog); 281 strcpy(result, items[(scroll+choice)*2]); 282 return 0; 283 case 'C': 284 case 'c': 285 delwin(dialog); 286 return 1; | 316 |
287 case KEY_BTAB: 288 case TAB: 289 case KEY_LEFT: 290 case KEY_RIGHT: | 317 case KEY_BTAB: 318 case TAB: 319 case KEY_LEFT: 320 case KEY_RIGHT: |
291 if (!button) { 292 button = 1; /* Indicates "Cancel" button is selected */ 293 print_button(dialog, " OK ", y, x, FALSE); 294 print_button(dialog, "Cancel", y, x+14, TRUE); 295 } 296 else { 297 button = 0; /* Indicates "OK" button is selected */ 298 print_button(dialog, "Cancel", y, x+14, FALSE); 299 print_button(dialog, " OK ", y, x, TRUE); 300 } 301 wrefresh(dialog); 302 break; | 321 button = !button; 322 if (ditems && result) { 323 if (button) { 324 print_button(dialog, ditems[OK_BUTTON].prompt, y, x, 325 ditems[OK_BUTTON].checked ? (*ditems[OK_BUTTON].checked)(&ditems[OK_BUTTON]) : !button); 326 print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, 327 ditems[CANCEL_BUTTON].checked ? (*ditems[CANCEL_BUTTON].checked)(&ditems[CANCEL_BUTTON]) : button); 328 } 329 else { 330 print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, 331 ditems[CANCEL_BUTTON].checked ? (*ditems[CANCEL_BUTTON].checked)(&ditems[CANCEL_BUTTON]) : button); 332 print_button(dialog, ditems[OK_BUTTON].prompt, y, x, 333 ditems[OK_BUTTON].checked ? (*ditems[OK_BUTTON].checked)(&ditems[OK_BUTTON]) : !button); 334 } 335 } 336 else { 337 if (button) { 338 print_button(dialog, " OK ", y, x, !button); 339 print_button(dialog, "Cancel", y, x + 14, button); 340 } 341 else { 342 print_button(dialog, "Cancel", y, x + 14, button); 343 print_button(dialog, " OK ", y, x, !button); 344 } 345 } 346 wrefresh(dialog); 347 break; 348 |
303 case ' ': 304 case '\r': 305 case '\n': | 349 case ' ': 350 case '\r': 351 case '\n': |
306 delwin(dialog); 307 if (!button) | 352 if (!button) { 353 if (ditems && ditems[scroll + choice].fire) { 354 if ((*ditems[scroll + choice].fire)(&ditems[scroll + choice]) == DITEM_FAILURE) 355 continue; 356 } 357 else if (result) |
308 strcpy(result, items[(scroll+choice)*2]); | 358 strcpy(result, items[(scroll+choice)*2]); |
309 return button; | 359 } 360 delwin(dialog); 361 return button; 362 |
310 case ESC: 311 break; | 363 case ESC: 364 break; |
365 |
|
312 case KEY_F(1): 313 case '?': 314 display_helpfile(); 315 break; 316 } | 366 case KEY_F(1): 367 case '?': 368 display_helpfile(); 369 break; 370 } |
371 |
|
317 if (redraw_menu) { 318 for (i = 0; i < max_choice; i++) { 319 print_item(menu, items[(scroll+i)*2], 320 items[(scroll+i)*2 + 1], i, i == choice); 321 } 322 wnoutrefresh(menu); 323 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 324 wrefresh(dialog); 325 redraw_menu = FALSE; 326 } 327 } | 372 if (redraw_menu) { 373 for (i = 0; i < max_choice; i++) { 374 print_item(menu, items[(scroll+i)*2], 375 items[(scroll+i)*2 + 1], i, i == choice); 376 } 377 wnoutrefresh(menu); 378 print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y); 379 wrefresh(dialog); 380 redraw_menu = FALSE; 381 } 382 } |
328 | 383 |
329 delwin(dialog); 330 return -1; /* ESC pressed */ 331} 332/* End of dialog_menu() */ 333 334 335/* 336 * Print menu item --- 22 unchanged lines hidden --- | 384 delwin(dialog); 385 return -1; /* ESC pressed */ 386} 387/* End of dialog_menu() */ 388 389 390/* 391 * Print menu item --- 22 unchanged lines hidden --- |