1 /****************************************************************************
2 * Copyright (c) 2005-2013,2014 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 * $Id: demo_menus.c,v 1.54 2014/09/05 08:34:06 tom Exp $
31 * Demonstrate a variety of functions from the menu library.
32 * Thomas Dickey - 2005/4/9
49 menu_request_by_name -
66 #include <test.priv.h>
72 #include <sys/types.h>
75 #ifdef NCURSES_VERSION
77 static unsigned save_trace
= TRACE_ORDINARY
| TRACE_CALLS
;
78 extern unsigned _nc_tracing
;
95 #define okMenuNo(n) (((n) > eBanner) && ((n) < eMAX))
100 NCURSES_CONST
char *name
;
105 static void call_files(int);
107 static MENU
*mpBanner
;
109 static MENU
*mpSelect
;
111 static WINDOW
*status
;
113 static bool loaded_file
= FALSE
;
115 static char empty
[1];
117 /* Common function to allow ^T to toggle trace-mode in the middle of a test
118 * so that trace-files can be made smaller.
121 wGetchar(WINDOW
*win
)
125 while ((c
= wgetch(win
)) == CTRL('T')) {
127 save_trace
= _nc_tracing
;
128 Trace(("TOGGLE-TRACING OFF"));
131 _nc_tracing
= save_trace
;
135 Trace(("TOGGLE-TRACING ON"));
142 #define Getchar() wGetchar(stdscr)
145 menu_virtualize(int c
)
149 if (c
== '\n' || c
== KEY_EXIT
)
150 result
= (MAX_COMMAND
+ 1);
152 result
= (REQ_SCR_ULINE
);
154 result
= (REQ_SCR_DLINE
);
155 else if (c
== 'b' || c
== KEY_NPAGE
)
156 result
= (REQ_SCR_UPAGE
);
157 else if (c
== 'f' || c
== KEY_PPAGE
)
158 result
= (REQ_SCR_DPAGE
);
159 else if (c
== 'l' || c
== KEY_LEFT
|| c
== KEY_BTAB
)
160 result
= (REQ_LEFT_ITEM
);
161 else if (c
== 'n' || c
== KEY_DOWN
)
162 result
= (REQ_NEXT_ITEM
);
163 else if (c
== 'p' || c
== KEY_UP
)
164 result
= (REQ_PREV_ITEM
);
165 else if (c
== 'r' || c
== KEY_RIGHT
|| c
== '\t')
166 result
= (REQ_RIGHT_ITEM
);
168 result
= (REQ_TOGGLE_ITEM
);
180 return wGetchar(menu_win(m
));
184 menu_offset(MenuNo number
)
188 if (okMenuNo(number
)) {
189 int spc_desc
, spc_rows
, spc_cols
;
191 #ifdef NCURSES_VERSION
192 menu_spacing(mpBanner
, &spc_desc
, &spc_rows
, &spc_cols
);
197 /* FIXME: MENU.itemlen seems the only way to get actual width of items */
198 result
= (number
- (eBanner
+ 1)) * (menu_itemwidth(mpBanner
) + spc_rows
);
204 my_menu_init(MENU
* menu
)
206 Trace(("called MenuHook my_menu_init"));
207 mvwprintw(status
, 2, 0, "menu_init %p", (void *) menu
);
213 my_menu_term(MENU
* menu
)
215 Trace(("called MenuHook my_menu_term"));
216 mvwprintw(status
, 2, 0, "menu_term %p", (void *) menu
);
222 my_item_init(MENU
* menu
)
224 ITEM
*item
= current_item(menu
);
225 const char *name
= item_name(item
);
227 Trace(("called MenuHook my_item_init (%s)", name
));
228 mvwprintw(status
, 2, 0, "item_init %s", name
);
234 my_item_term(MENU
* menu
)
236 ITEM
*item
= current_item(menu
);
237 const char *name
= item_name(item
);
239 Trace(("called MenuHook my_item_term (%s)", name
));
240 mvwprintw(status
, 2, 0, "item_term %s", name
);
246 menu_create(ITEM
** items
, int count
, int ncols
, MenuNo number
)
251 int y
= okMenuNo(number
) ? MENU_Y
: 0;
252 int x
= menu_offset(number
);
253 int margin
= (y
== MENU_Y
) ? 1 : 0;
254 int maxcol
= (ncols
+ x
) < COLS
? ncols
: (COLS
- x
- 1);
255 int maxrow
= (count
+ 1) / ncols
;
257 if ((maxrow
+ y
) >= (LINES
- 4))
258 maxrow
= LINES
- 4 - y
;
260 result
= new_menu(items
);
263 set_menu_fore(result
, (chtype
) COLOR_PAIR(1));
264 set_menu_back(result
, (chtype
) COLOR_PAIR(2));
267 set_menu_format(result
, maxrow
, maxcol
);
268 scale_menu(result
, &mrows
, &mcols
);
270 if (mcols
+ (2 * margin
+ x
) >= COLS
)
271 mcols
= COLS
- (2 * margin
+ x
);
274 if (number
== eTrace
)
275 menu_opts_off(result
, O_ONEVALUE
);
277 menu_opts_on(result
, O_ONEVALUE
);
280 menuwin
= newwin(mrows
+ (2 * margin
), mcols
+ (2 * margin
), y
, x
);
281 set_menu_win(result
, menuwin
);
282 keypad(menuwin
, TRUE
);
286 set_menu_sub(result
, derwin(menuwin
, mrows
, mcols
, margin
, margin
));
290 set_menu_init(result
, my_menu_init
);
291 set_menu_term(result
, my_menu_term
);
292 set_item_init(result
, my_item_init
);
293 set_item_term(result
, my_item_term
);
298 menu_destroy(MENU
* m
)
302 Trace(("menu_destroy %p", (void *) m
));
304 ITEM
**items
= menu_items(m
);
305 const char *blob
= 0;
307 count
= item_count(m
);
308 Trace(("menu_destroy %p count %d", (void *) m
, count
));
309 if ((count
> 0) && (m
== mpSelect
)) {
310 blob
= item_name(*items
);
316 /* free the extra data allocated in build_select_menu() */
317 if ((count
> 0) && (m
== mpSelect
)) {
318 if (blob
&& loaded_file
) {
319 Trace(("freeing blob %p", blob
));
326 if ((count
> 0) && (m
== mpTrace
)) {
337 /* force the given menu to appear */
339 menu_display(MENU
* m
)
341 touchwin(menu_win(m
));
342 wrefresh(menu_win(m
));
345 /*****************************************************************************/
348 build_file_menu(MenuNo number
)
350 static MENU_DATA table
[] =
352 {"Exit", call_files
, 0},
355 static ITEM
*items
[SIZEOF(table
)];
360 for (n
= 0; table
[n
].name
!= 0; ++n
) {
361 *ip
= new_item(table
[n
].name
, empty
);
362 set_item_userptr(*ip
, (void *) &table
[n
]);
367 mpFile
= menu_create(items
, SIZEOF(table
) - 1, 1, number
);
371 perform_file_menu(int cmd
)
373 return menu_driver(mpFile
, cmd
);
376 /*****************************************************************************/
379 call_select(int code
)
382 Trace(("Selected item %d", code
));
386 build_select_menu(MenuNo number
, char *filename
)
388 #define MY_DATA(name) { name, call_select, 0 }
389 static MENU_DATA table
[] =
398 MY_DATA("(Oh really?!)"),
402 MY_DATA("Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs"),
403 MY_DATA("Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs"),
410 MENU_DATA
*myList
= 0;
416 if (stat(filename
, &sb
) == 0
417 && (sb
.st_mode
& S_IFMT
) == S_IFREG
418 && sb
.st_size
!= 0) {
419 size_t size
= (size_t) sb
.st_size
;
421 char *blob
= typeMalloc(char, size
+ 1);
422 MENU_DATA
*list
= typeCalloc(MENU_DATA
, size
+ 1);
424 items
= typeCalloc(ITEM
*, size
+ 1);
425 Trace(("build_select_menu blob=%p, items=%p",
428 if (blob
!= 0 && list
!= 0) {
429 FILE *fp
= fopen(filename
, "r");
431 if (fread(blob
, sizeof(char), size
, fp
) == size
) {
433 for (j
= k
= 0; j
< size
; ++j
) {
435 list
[k
++].name
= blob
+ j
;
438 if (blob
[j
] == '\n') {
440 if (k
> 0 && *list
[k
- 1].name
== '\0')
443 } else if (blob
[j
] == '\t') {
444 blob
[j
] = ' '; /* menu items are printable */
460 count
= SIZEOF(table
) - 1;
461 items
= typeCalloc(ITEM
*, count
+ 1);
466 for (i
= 0; ap
[i
].name
!= 0; ++i
) {
467 ap
[i
].func
= call_select
;
468 ap
[i
].mask
= (unsigned) i
;
469 *ip
= new_item(ap
[i
].name
, empty
);
470 set_item_userptr(*ip
, (void *) &table
[i
]);
475 mpSelect
= menu_create(items
, (int) count
, 1, number
);
481 perform_select_menu(int cmd
)
483 return menu_driver(mpSelect
, cmd
);
486 /*****************************************************************************/
494 Trace(("Updating trace mask %d", code
));
497 #define T_TBL(name) { #name, call_trace, name }
498 static MENU_DATA t_tbl
[] =
501 T_TBL(TRACE_DISABLE
),
506 T_TBL(TRACE_CHARPUT
),
507 T_TBL(TRACE_ORDINARY
),
509 T_TBL(TRACE_VIRTPUT
),
514 T_TBL(TRACE_DATABASE
),
516 T_TBL(TRACE_MAXIMUM
),
523 build_trace_menu(MenuNo number
)
525 static ITEM
*items
[SIZEOF(t_tbl
)];
530 for (n
= 0; t_tbl
[n
].name
!= 0; n
++) {
531 *ip
= new_item(t_tbl
[n
].name
, empty
);
532 set_item_userptr(*ip
, (void *) &t_tbl
[n
]);
537 mpTrace
= menu_create(items
, SIZEOF(t_tbl
) - 1, 2, number
);
541 tracetrace(unsigned tlevel
)
548 for (n
= 0; t_tbl
[n
].name
!= 0; n
++)
549 need
+= strlen(t_tbl
[n
].name
) + 2;
550 buf
= typeMalloc(char, need
);
552 sprintf(buf
, "0x%02x = {", tlevel
);
554 sprintf(buf
+ strlen(buf
), "%s, ", t_tbl
[0].name
);
556 for (n
= 1; t_tbl
[n
].name
!= 0; n
++)
557 if ((tlevel
& t_tbl
[n
].mask
) == t_tbl
[n
].mask
) {
558 strcat(buf
, t_tbl
[n
].name
);
562 if (buf
[strlen(buf
) - 2] == ',')
563 buf
[strlen(buf
) - 2] = '\0';
564 return (strcat(buf
, "}"));
567 /* fake a dynamically reconfigurable menu using the 0th entry to deselect
571 update_trace_menu(MENU
* m
)
575 bool changed
= FALSE
;
577 items
= menu_items(m
);
581 for (p
= items
+ 1; *p
!= 0; p
++)
582 if (item_value(*p
)) {
583 set_item_value(*p
, FALSE
);
592 perform_trace_menu(int cmd
)
593 /* interactively set the trace level */
599 for (ip
= menu_items(mpTrace
); *ip
; ip
++) {
600 MENU_DATA
*td
= (MENU_DATA
*) item_userptr(*ip
);
601 unsigned mask
= td
->mask
;
603 set_item_value(*ip
, _nc_tracing
== 0);
604 else if ((mask
& _nc_tracing
) == mask
)
605 set_item_value(*ip
, TRUE
);
608 result
= menu_driver(mpTrace
, cmd
);
610 if (result
== E_OK
) {
611 if (update_trace_menu(mpTrace
) || cmd
== REQ_TOGGLE_ITEM
) {
613 for (ip
= menu_items(mpTrace
); *ip
; ip
++) {
614 if (item_value(*ip
)) {
615 MENU_DATA
*td
= (MENU_DATA
*) item_userptr(*ip
);
616 newtrace
|= td
->mask
;
620 Trace(("trace level interactively set to %s", tracetrace(_nc_tracing
)));
622 MvWPrintw(status
, 1, 0,
623 "Trace level is %s\n", tracetrace(_nc_tracing
));
631 /*****************************************************************************/
636 return item_index(current_item(mpBanner
)) - (eBanner
+ 1);
644 switch (menu_number()) {
667 Trace(("Activated menu %d\n", code
));
671 build_menus(char *filename
)
673 static MENU_DATA table
[] =
675 {"File", call_menus
, 0},
676 {"Select", call_menus
, 1},
678 {"Trace", call_menus
, 2},
682 static ITEM
*items
[SIZEOF(table
)];
687 for (n
= 0; table
[n
].name
!= 0; ++n
) {
688 *ip
= new_item(table
[n
].name
, empty
);
689 set_item_userptr(*ip
, (void *) &table
[n
]);
694 mpBanner
= menu_create(items
, SIZEOF(table
) - 1, SIZEOF(table
) - 1, eBanner
);
695 set_menu_mark(mpBanner
, ">");
697 build_file_menu(eFile
);
698 build_select_menu(eSelect
, filename
);
700 build_trace_menu(eTrace
);
705 move_menu(MENU
* menu
, MENU
* current
, int by_y
, int by_x
)
707 WINDOW
*top_win
= menu_win(menu
);
708 WINDOW
*sub_win
= menu_sub(menu
);
713 getbegyx(top_win
, y0
, x0
);
717 getbegyx(sub_win
, y1
, x1
);
721 if ((result
= mvwin(top_win
, y0
, x0
)) != ERR
) {
722 #if defined(NCURSES_VERSION_PATCH) && (NCURSES_VERSION_PATCH < 20060218)
726 mvwin(sub_win
, y1
, x1
);
728 if (menu
== current
) {
730 wnoutrefresh(top_win
);
737 * Move the menus around on the screen, to test mvwin().
740 move_menus(MENU
* current
, int by_y
, int by_x
)
742 if (move_menu(mpBanner
, current
, by_y
, by_x
) != ERR
) {
744 wnoutrefresh(stdscr
);
745 move_menu(mpFile
, current
, by_y
, by_x
);
746 move_menu(mpSelect
, current
, by_y
, by_x
);
748 move_menu(mpTrace
, current
, by_y
, by_x
);
755 show_status(int ch
, MENU
* menu
)
758 wprintw(status
, "key %s, menu %d, mark %s, match %s",
771 MENU
*last_menu
= mpFile
;
772 int code
= E_UNKNOWN_COMMAND
;
776 #ifdef NCURSES_MOUSE_VERSION
777 mousemask(ALL_MOUSE_EVENTS
, (mmask_t
*) 0);
780 menu_display(last_menu
);
785 show_status(ch
, last_menu
);
787 ch
= menu_getc(mpBanner
);
790 * Provide for moving the menu around in the screen using shifted
795 move_menus(last_menu
, 1, 0);
798 move_menus(last_menu
, -1, 0);
801 move_menus(last_menu
, 0, -1);
804 move_menus(last_menu
, 0, 1);
807 cmd
= menu_virtualize(ch
);
811 * The banner menu acts solely to select one of the other menus.
812 * Move between its items, wrapping at the left/right limits.
816 code
= menu_driver(mpBanner
, cmd
);
817 if (code
== E_REQUEST_DENIED
) {
818 if (menu_number() > 0)
819 code
= menu_driver(mpBanner
, REQ_FIRST_ITEM
);
821 code
= menu_driver(mpBanner
, REQ_LAST_ITEM
);
825 switch (menu_number()) {
827 code
= perform_file_menu(cmd
);
830 code
= perform_select_menu(cmd
);
834 code
= perform_trace_menu(cmd
);
839 if ((code
== E_REQUEST_DENIED
) && (cmd
== KEY_MOUSE
)) {
840 code
= menu_driver(mpBanner
, cmd
);
847 this_menu
= current_menu();
848 if (this_menu
!= last_menu
) {
851 box(menu_win(this_menu
), 0, 0);
854 /* force the current menu to appear */
855 menu_display(this_menu
);
857 last_menu
= this_menu
;
860 wrefresh(menu_win(last_menu
));
861 if (code
== E_UNKNOWN_COMMAND
862 || code
== E_NOT_POSTED
) {
863 ITEM
*item
= current_item(last_menu
);
864 MENU_DATA
*td
= (MENU_DATA
*) item_userptr(item
);
865 td
->func((int) td
->mask
);
867 if (code
== E_REQUEST_DENIED
)
872 #ifdef NCURSES_MOUSE_VERSION
873 mousemask(0, (mmask_t
*) 0);
880 menu_destroy(mpFile
);
881 menu_destroy(mpSelect
);
883 menu_destroy(mpTrace
);
885 menu_destroy(mpBanner
);
890 rip_footer(WINDOW
*win
, int cols
)
892 wbkgd(win
, A_REVERSE
);
895 wprintw(win
, "footer: %d columns", cols
);
901 rip_header(WINDOW
*win
, int cols
)
903 wbkgd(win
, A_REVERSE
);
906 wprintw(win
, "header: %d columns", cols
);
910 #endif /* HAVE_RIPOFFLINE */
920 ExitProgram(EXIT_SUCCESS
);
927 static const char *const tbl
[] =
929 "Usage: demo_menus [options] [menu-file]"
933 ," -f rip-off footer line (can repeat)"
934 ," -h rip-off header line (can repeat)"
937 ," -t mask specify default trace-level (may toggle with ^T)"
941 for (n
= 0; n
< SIZEOF(tbl
); n
++)
942 fprintf(stderr
, "%s\n", tbl
[n
]);
943 ExitProgram(EXIT_FAILURE
);
947 main(int argc
, char *argv
[])
951 setlocale(LC_ALL
, "");
953 while ((c
= getopt(argc
, argv
, "a:de:fhmp:s:t:")) != -1) {
957 ripoffline(-1, rip_footer
);
960 ripoffline(1, rip_header
);
962 #endif /* HAVE_RIPOFFLINE */
965 trace((unsigned) strtoul(optarg
, 0, 0));
980 init_pair(1, COLOR_RED
, COLOR_BLACK
);
981 init_pair(2, COLOR_BLUE
, COLOR_WHITE
);
983 status
= newwin(3, COLS
, LINES
- 3, 0);
984 build_menus(argc
> 1 ? argv
[1] : 0);
989 ExitProgram(EXIT_SUCCESS
);
995 printf("This program requires the curses menu library\n");
996 ExitProgram(EXIT_FAILURE
);