Deleted Added
full compact
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 ---