source: trunk/ncurses/test/demo_menus.c@ 2787

Last change on this file since 2787 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

File size: 13.2 KB
Line 
1/*
2 * $Id: demo_menus.c,v 1.13 2005/10/01 15:54:31 tom Exp $
3 *
4 * Demonstrate a variety of functions from the menu library.
5 * Thomas Dickey - 2005/4/9
6 */
7/*
8item_description -
9item_init -
10item_opts -
11item_opts_off -
12item_opts_on -
13item_term -
14item_userptr -
15item_visible -
16menu_back -
17menu_fore -
18menu_format -
19menu_grey -
20menu_init -
21menu_mark -
22menu_opts -
23menu_pad -
24menu_pattern -
25menu_request_by_name -
26menu_request_name -
27menu_sub -
28menu_term -
29menu_userptr -
30set_current_item -
31set_item_init -
32set_item_opts -
33set_item_term -
34set_item_userptr -
35set_menu_grey -
36set_menu_init -
37set_menu_items -
38set_menu_opts -
39set_menu_pad -
40set_menu_pattern -
41set_menu_spacing -
42set_menu_term -
43set_menu_userptr -
44set_top_row -
45top_row -
46*/
47
48#include <test.priv.h>
49
50#if USE_LIBMENU
51
52#include <menu.h>
53
54#include <sys/types.h>
55#include <sys/stat.h>
56
57#ifdef NCURSES_VERSION
58#ifdef TRACE
59static unsigned save_trace = TRACE_ORDINARY | TRACE_CALLS;
60extern unsigned _nc_tracing;
61static MENU *mpTrace;
62#endif
63#else
64#undef TRACE
65#endif
66
67typedef enum {
68 eUnknown = -1
69 ,eFile = 0
70 ,eSelect
71#ifdef TRACE
72 ,eTrace
73#endif
74} MenuNo;
75
76#define MENU_Y 1
77
78static MENU *mpBanner;
79static MENU *mpFile;
80static MENU *mpSelect;
81
82#if !HAVE_STRDUP
83#define strdup my_strdup
84static char *
85strdup(char *s)
86{
87 char *p = (char *) malloc(strlen(s) + 1);
88 if (p)
89 strcpy(p, s);
90 return (p);
91}
92#endif /* not HAVE_STRDUP */
93
94/* Common function to allow ^T to toggle trace-mode in the middle of a test
95 * so that trace-files can be made smaller.
96 */
97static int
98wGetchar(WINDOW *win)
99{
100 int c;
101#ifdef TRACE
102 while ((c = wgetch(win)) == CTRL('T')) {
103 if (_nc_tracing) {
104 save_trace = _nc_tracing;
105 _tracef("TOGGLE-TRACING OFF");
106 _nc_tracing = 0;
107 } else {
108 _nc_tracing = save_trace;
109 }
110 trace(_nc_tracing);
111 if (_nc_tracing)
112 _tracef("TOGGLE-TRACING ON");
113 }
114#else
115 c = wgetch(win);
116#endif
117 return c;
118}
119#define Getchar() wGetchar(stdscr)
120
121static int
122menu_virtualize(int c)
123{
124 int result;
125
126 if (c == '\n' || c == KEY_EXIT)
127 result = (MAX_COMMAND + 1);
128 else if (c == 'u')
129 result = (REQ_SCR_ULINE);
130 else if (c == 'd')
131 result = (REQ_SCR_DLINE);
132 else if (c == 'b' || c == KEY_NPAGE)
133 result = (REQ_SCR_UPAGE);
134 else if (c == 'f' || c == KEY_PPAGE)
135 result = (REQ_SCR_DPAGE);
136 else if (c == 'l' || c == KEY_LEFT || c == KEY_BTAB)
137 result = (REQ_LEFT_ITEM);
138 else if (c == 'n' || c == KEY_DOWN)
139 result = (REQ_NEXT_ITEM);
140 else if (c == 'p' || c == KEY_UP)
141 result = (REQ_PREV_ITEM);
142 else if (c == 'r' || c == KEY_RIGHT || c == '\t')
143 result = (REQ_RIGHT_ITEM);
144 else if (c == ' ')
145 result = (REQ_TOGGLE_ITEM);
146 else {
147 if (c != KEY_MOUSE)
148 beep();
149 result = (c);
150 }
151 return result;
152}
153
154static int
155menu_getc(MENU * m)
156{
157 return wGetchar(menu_win(m));
158}
159
160static int
161menu_offset(MenuNo number)
162{
163 int result = 0;
164
165 if ((int) number >= 0) {
166 int spc_desc, spc_rows, spc_cols;
167
168#ifdef NCURSES_VERSION
169 menu_spacing(mpBanner, &spc_desc, &spc_rows, &spc_cols);
170#else
171 spc_rows = 0;
172#endif
173
174 /* FIXME: MENU.itemlen seems the only way to get actual width of items */
175 result = number * (mpBanner->itemlen + spc_rows);
176 }
177 return result;
178}
179
180static MENU *
181menu_create(ITEM ** items, int count, int ncols, MenuNo number)
182{
183 MENU *result;
184 WINDOW *menuwin;
185 int mrows, mcols;
186 int y = ((int) number >= 0) ? MENU_Y : 0;
187 int x = menu_offset(number);
188 int margin = (y == MENU_Y) ? 1 : 0;
189 int maxcol = (ncols + x) < COLS ? ncols : (COLS - x - 1);
190 int maxrow = (count + 1) / ncols;
191
192 if ((maxrow + y) >= (LINES - 4))
193 maxrow = LINES - 4 - y;
194
195 result = new_menu(items);
196
197 if (has_colors()) {
198 set_menu_fore(result, COLOR_PAIR(1));
199 set_menu_back(result, COLOR_PAIR(2));
200 }
201
202 set_menu_format(result, maxrow, maxcol);
203 scale_menu(result, &mrows, &mcols);
204
205 if (mcols + (2 * margin + x) >= COLS)
206 mcols = COLS - (2 * margin + x);
207
208#ifdef TRACE
209 if (number == eTrace)
210 menu_opts_off(result, O_ONEVALUE);
211 else
212 menu_opts_on(result, O_ONEVALUE);
213#endif
214
215 menuwin = newwin(mrows + (2 * margin), mcols + (2 * margin), y, x);
216 set_menu_win(result, menuwin);
217 keypad(menuwin, TRUE);
218 if (margin)
219 box(menuwin, 0, 0);
220
221 set_menu_sub(result, derwin(menuwin, mrows, mcols, margin, margin));
222
223 post_menu(result);
224
225 return result;
226}
227
228static void
229menu_destroy(MENU * m)
230{
231 ITEM **ip;
232 int count;
233
234 if (m != 0) {
235 delwin(menu_win(m));
236
237 ip = menu_items(m);
238 count = item_count(m);
239
240 free_menu(m);
241#if 0
242 if (count > 0) {
243 while (*ip) {
244 _tracef("freeing item %d:%d", ip - menu_items(m), count);
245 free_item(*ip++);
246 }
247 }
248#endif
249 }
250}
251
252/* force the given menu to appear */
253static void
254menu_display(MENU * m)
255{
256 touchwin(menu_win(m));
257 wrefresh(menu_win(m));
258}
259
260/*****************************************************************************/
261
262static void
263build_file_menu(MenuNo number)
264{
265 static const char *labels[] =
266 {
267 "Exit",
268 (char *) 0
269 };
270 static ITEM *items[SIZEOF(labels)];
271
272 ITEM **ip = items;
273 const char **ap;
274
275 for (ap = labels; *ap; ap++)
276 *ip++ = new_item(*ap, "");
277 *ip = (ITEM *) 0;
278
279 mpFile = menu_create(items, SIZEOF(labels) - 1, 1, number);
280}
281
282static int
283perform_file_menu(int cmd)
284{
285 return menu_driver(mpFile, cmd);
286}
287
288/*****************************************************************************/
289
290static void
291build_select_menu(MenuNo number, char *filename)
292{
293 static const char *labels[] =
294 {
295 "Lions",
296 "Tigers",
297 "Bears",
298 "(Oh my!)",
299 "Newts",
300 "Platypi",
301 "Lemurs",
302 "(Oh really?!)",
303 "Leopards",
304 "Panthers",
305 "Pumas",
306 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
307 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
308 (char *) 0
309 };
310 static ITEM **items;
311
312 ITEM **ip;
313 const char **ap = 0;
314 unsigned count = 0;
315
316 if (filename != 0) {
317 struct stat sb;
318 if (stat(filename, &sb) == 0
319 && (sb.st_mode & S_IFMT) == S_IFREG
320 && sb.st_size != 0) {
321 unsigned size = sb.st_size;
322 unsigned j, k;
323 char *blob = malloc(size + 1);
324 const char **list = (const char **) calloc(sizeof(*list), size + 1);
325
326 items = (ITEM **) calloc(sizeof(ITEM *), size + 1);
327 if (blob != 0 && list != 0) {
328 FILE *fp = fopen(filename, "r");
329 if (fp != 0) {
330 if (fread(blob, sizeof(char), size, fp) == size) {
331 bool mark = TRUE;
332 for (j = k = 0; j < size; ++j) {
333 if (mark) {
334 list[k++] = blob + j;
335 mark = FALSE;
336 }
337 if (blob[j] == '\n') {
338 blob[j] = '\0';
339 if (k > 0 && *list[k - 1] == '\0')
340 --k;
341 mark = TRUE;
342 } else if (blob[j] == '\t') {
343 blob[j] = ' '; /* menu items are printable */
344 }
345 }
346 list[k] = 0;
347 count = k;
348 ap = list;
349 }
350 fclose(fp);
351 }
352 }
353 }
354 }
355 if (ap == 0) {
356 count = SIZEOF(labels) - 1;
357 items = (ITEM **) calloc(count + 1, sizeof(*items));
358 ap = labels;
359 }
360
361 ip = items;
362 while (*ap != 0)
363 *ip++ = new_item(*ap++, "");
364 *ip = 0;
365
366 mpSelect = menu_create(items, (int) count, 1, number);
367}
368
369static int
370perform_select_menu(int cmd)
371{
372 return menu_driver(mpSelect, cmd);
373}
374
375/*****************************************************************************/
376
377#ifdef TRACE
378#define T_TBL(name) { #name, name }
379static struct {
380 const char *name;
381 unsigned mask;
382} t_tbl[] = {
383
384 T_TBL(TRACE_DISABLE),
385 T_TBL(TRACE_TIMES),
386 T_TBL(TRACE_TPUTS),
387 T_TBL(TRACE_UPDATE),
388 T_TBL(TRACE_MOVE),
389 T_TBL(TRACE_CHARPUT),
390 T_TBL(TRACE_ORDINARY),
391 T_TBL(TRACE_CALLS),
392 T_TBL(TRACE_VIRTPUT),
393 T_TBL(TRACE_IEVENT),
394 T_TBL(TRACE_BITS),
395 T_TBL(TRACE_ICALLS),
396 T_TBL(TRACE_CCALLS),
397 T_TBL(TRACE_DATABASE),
398 T_TBL(TRACE_ATTRS),
399 T_TBL(TRACE_MAXIMUM),
400 {
401 (char *) 0, 0
402 }
403};
404
405static void
406build_trace_menu(MenuNo number)
407{
408 static ITEM *items[SIZEOF(t_tbl)];
409
410 ITEM **ip = items;
411 int n;
412
413 for (n = 0; t_tbl[n].name != 0; n++)
414 *ip++ = new_item(t_tbl[n].name, "");
415 *ip = (ITEM *) 0;
416
417 mpTrace = menu_create(items, SIZEOF(t_tbl) - 1, 2, number);
418}
419
420static char *
421tracetrace(unsigned tlevel)
422{
423 static char *buf;
424 int n;
425
426 if (buf == 0) {
427 size_t need = 12;
428 for (n = 0; t_tbl[n].name != 0; n++)
429 need += strlen(t_tbl[n].name) + 2;
430 buf = (char *) malloc(need);
431 }
432 sprintf(buf, "0x%02x = {", tlevel);
433 if (tlevel == 0) {
434 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
435 } else {
436 for (n = 1; t_tbl[n].name != 0; n++)
437 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
438 strcat(buf, t_tbl[n].name);
439 strcat(buf, ", ");
440 }
441 }
442 if (buf[strlen(buf) - 2] == ',')
443 buf[strlen(buf) - 2] = '\0';
444 return (strcat(buf, "}"));
445}
446
447/* fake a dynamically reconfigurable menu using the 0th entry to deselect
448 * the others
449 */
450static bool
451update_trace_menu(MENU * m)
452{
453 ITEM **items;
454 ITEM *i, **p;
455 bool changed = FALSE;
456
457 items = menu_items(m);
458 i = current_item(m);
459 if (i == items[0]) {
460 if (item_value(i)) {
461 for (p = items + 1; *p != 0; p++)
462 if (item_value(*p)) {
463 set_item_value(*p, FALSE);
464 changed = TRUE;
465 }
466 }
467 }
468 return changed;
469}
470
471static int
472perform_trace_menu(int cmd)
473/* interactively set the trace level */
474{
475 ITEM **ip;
476 unsigned newtrace;
477 int result;
478
479 for (ip = menu_items(mpTrace); *ip; ip++) {
480 unsigned mask = t_tbl[item_index(*ip)].mask;
481 if (mask == 0)
482 set_item_value(*ip, _nc_tracing == 0);
483 else if ((mask & _nc_tracing) == mask)
484 set_item_value(*ip, TRUE);
485 }
486
487 result = menu_driver(mpTrace, cmd);
488
489 if (result == E_OK) {
490 if (update_trace_menu(mpTrace) || cmd == REQ_TOGGLE_ITEM) {
491 newtrace = 0;
492 for (ip = menu_items(mpTrace); *ip; ip++) {
493 if (item_value(*ip))
494 newtrace |= t_tbl[item_index(*ip)].mask;
495 }
496 trace(newtrace);
497 _tracef("trace level interactively set to %s", tracetrace(_nc_tracing));
498
499 (void) mvprintw(LINES - 2, 0,
500 "Trace level is %s\n", tracetrace(_nc_tracing));
501 refresh();
502 }
503 }
504 return result;
505}
506#endif /* TRACE */
507
508/*****************************************************************************/
509
510static int
511menu_number(void)
512{
513 return item_index(current_item(mpBanner));
514}
515
516static MENU *
517current_menu(void)
518{
519 MENU *result;
520
521 switch (menu_number()) {
522 case eFile:
523 result = mpFile;
524 break;
525 case eSelect:
526 result = mpSelect;
527 break;
528#ifdef TRACE
529 case eTrace:
530 result = mpTrace;
531 break;
532#endif
533 default:
534 result = 0;
535 break;
536 }
537 return result;
538}
539
540static void
541build_menus(char *filename)
542{
543 static const char *labels[] =
544 {
545 "File",
546 "Select",
547#ifdef TRACE
548 "Trace",
549#endif
550 (char *) 0
551 };
552 static ITEM *items[SIZEOF(labels)];
553
554 ITEM **ip = items;
555 const char **ap;
556
557 for (ap = labels; *ap; ap++)
558 *ip++ = new_item(*ap, "");
559 *ip = (ITEM *) 0;
560
561 mpBanner = menu_create(items, SIZEOF(labels) - 1, SIZEOF(labels) - 1, eUnknown);
562 set_menu_mark(mpBanner, ">");
563
564 build_file_menu(eFile);
565 build_select_menu(eSelect, filename);
566#ifdef TRACE
567 build_trace_menu(eTrace);
568#endif
569}
570
571static void
572perform_menus(void)
573{
574 MENU *this_menu;
575 MENU *last_menu = mpFile;
576 int code = E_UNKNOWN_COMMAND, cmd, ch;
577
578#ifdef NCURSES_MOUSE_VERSION
579 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
580#endif
581
582 menu_display(last_menu);
583
584 for (;;) {
585 ch = menu_getc(mpBanner);
586 cmd = menu_virtualize(ch);
587
588 switch (cmd) {
589 /*
590 * The banner menu acts solely to select one of the other menus.
591 * Move between its items, wrapping at the left/right limits.
592 */
593 case REQ_LEFT_ITEM:
594 case REQ_RIGHT_ITEM:
595 code = menu_driver(mpBanner, cmd);
596 if (code == E_REQUEST_DENIED) {
597 if (menu_number() > 0)
598 code = menu_driver(mpBanner, REQ_FIRST_ITEM);
599 else
600 code = menu_driver(mpBanner, REQ_LAST_ITEM);
601 }
602 break;
603 default:
604 switch (menu_number()) {
605 case eFile:
606 code = perform_file_menu(cmd);
607 break;
608 case eSelect:
609 code = perform_select_menu(cmd);
610 break;
611#ifdef TRACE
612 case eTrace:
613 code = perform_trace_menu(cmd);
614 break;
615#endif
616 }
617
618 if ((code == E_REQUEST_DENIED) && (cmd == KEY_MOUSE)) {
619 code = menu_driver(mpBanner, cmd);
620 }
621
622 break;
623 }
624
625 if (code == E_OK) {
626 this_menu = current_menu();
627 if (this_menu != last_menu) {
628 move(1, 0);
629 clrtobot();
630 box(menu_win(this_menu), 0, 0);
631 refresh();
632
633 /* force the current menu to appear */
634 menu_display(this_menu);
635
636 last_menu = this_menu;
637 }
638 }
639 wrefresh(menu_win(last_menu));
640 if (code == E_UNKNOWN_COMMAND
641 || code == E_NOT_POSTED) {
642 if (menu_number() == eFile)
643 break;
644 beep();
645 }
646 if (code == E_REQUEST_DENIED)
647 beep();
648 continue;
649 }
650
651#ifdef NCURSES_MOUSE_VERSION
652 mousemask(0, (mmask_t *) 0);
653#endif
654}
655
656static void
657destroy_menus(void)
658{
659 menu_destroy(mpFile);
660 menu_destroy(mpSelect);
661#ifdef TRACE
662 menu_destroy(mpTrace);
663#endif
664 menu_destroy(mpBanner);
665}
666
667int
668main(int argc, char *argv[])
669{
670 setlocale(LC_ALL, "");
671
672 initscr();
673 noraw();
674 cbreak();
675 noecho();
676
677 if (has_colors()) {
678 start_color();
679 init_pair(1, COLOR_RED, COLOR_BLACK);
680 init_pair(2, COLOR_BLUE, COLOR_WHITE);
681 }
682 build_menus(argc > 1 ? argv[1] : 0);
683 perform_menus();
684 destroy_menus();
685
686 endwin();
687 return EXIT_SUCCESS;
688}
689#else
690int
691main(void)
692{
693 printf("This program requires the curses menu library\n");
694 ExitProgram(EXIT_FAILURE);
695}
696#endif
Note: See TracBrowser for help on using the repository browser.