jek5036@ultb.isc.rit.edu (J.E. King) (03/22/91)
Submitted-by: J.E. King <jek5036@ultb.isc.rit.edu> Posting-number: Volume 17, Issue 62 Archive-name: menubar/part01 Since I rely on curses heavily for my programs, I have began to write some functions for my programs. I found this one so useful that I decided to put it up on comp.sources.misc. It is a menu routine, which will adjust to the size of a 2d char array and will draw a nice box around the menu which is either numerically driven or arrow-key driven. I hope someone finds it useful. Jim King <jek5036@ultb.isc.rit.edu> -- cut here -- cut here -- cut here -- cut here -- cut here -- cut here -- #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./Makefile` then echo "writing ./Makefile" cat > ./Makefile << '\End\Of\Shar\' CFLAGS = -O all: test test: menubar.o test.o cc test.o menubar.o -o test -g -lcurses -ltermcap test.o: test.c menubar.o: menubar.c \End\Of\Shar\ else echo "will not over write ./Makefile" fi if `test ! -s ./README` then echo "writing ./README" cat > ./README << '\End\Of\Shar\' Hi! MenuBar is something I cooked up whilst bored at work. You can use it for just about any program which prompts the user for menu choices. I am planning on installing it in my next version of Chemtab, the chemistry database released on comp.sources.unix not too long ago. Here's how you would go about using menubar(): 1) Set up a 2d array of char in your program, such as: char *first_menu[] = { "This is menu option number 1", "This is menu option number 2", "This will return a three", "Exit the program", 0 }; 2) Call the function like this: menubar(y, x, first_menu, boxflag, title); where: y = the y position on the screen - upper left hand corner x = the x position on the screen - upper left hand corner first_menu = the char 2d array like above boxflag = (1, 0) if 1, will put an ascii box around the menu title = char string - centered in the first line of the menu if you don't want a title, use NULL 3) The fuctions will return the number of the option, for example in the above menu if I pressed return on "This will return a three" I would get back a three because it was the third choice.. Have fun with it. \End\Of\Shar\ else echo "will not over write ./README" fi if `test ! -s ./menubar.c` then echo "writing ./menubar.c" cat > ./menubar.c << '\End\Of\Shar\' /* * Menubar - curses driven menu bar display * menubar will run a menu-bar display on screen for you. * This type of package is useful for databases, etc.. */ /* Menubar V1.0 by Jim King (jek5036@ultb.isc.rit.edu) */ #include <stdio.h> #include <curses.h> #include <signal.h> #ifdef SYSV # include <string.h> #else # include <strings.h> #endif #define MAXNAMELEN 70 #define UP 'A' #define DN 'B' #define LT 'C' #define RT 'D' #define ESC '\033' #define RET '\015' #define LF '\012' struct mbar { char menu_choice[MAXNAMELEN]; int menu_number; struct mbar *next; } *m; WINDOW *MENU; #define NEW(XXX) (struct XXX *)malloc(sizeof(struct XXX)) int Stopflag = 0; /* interrupt flag */ void (*oldsig)(); /* old signal catch */ /* * signal calls this on an interrupt like ^C */ menuclean() { wclear(MENU); wrefresh(MENU); delwin(MENU); refresh(); printf("<<< Press return to continue >>>"); fflush(stdout); signal(SIGINT, oldsig); /* reset signal handler */ ++Stopflag; return(-1); /* return to loop */ } /* * converts information in menu to a linked-list */ mkmenubar(num, menu) int *num; char *menu[]; { int i = 0; /* counter for num */ struct mbar *tmp; /* tmp pointer to list */ m = NEW(mbar); /* initialize menubar */ tmp = m; /* set tmp to head */ do { strcpy(tmp->menu_choice, menu[i]); tmp->menu_number = i+1; /* move values into tmp */ tmp->next = NEW(mbar); tmp = tmp->next; /* set up next link */ ++i; } while (menu[i] != NULL); *num = i; /* 'return' the maxnum of choices */ tmp = NULL; /* lop off the end */ } /* * determine optimal size for menu bar. */ sizemenubar(len, wid, title) int *len, *wid; char *title; { int sz = 0, i = 0; /* tmp counter */ struct mbar *tmp; /* tmp placeholder */ *len = 0; *wid = 0; tmp = m; for (tmp = m; tmp != NULL; tmp = tmp->next) { ++i; sz = strlen(tmp->menu_choice); if (sz > *wid) /* as wide as longest line */ *wid = sz; } if (title != NULL) if (strlen(title) > *wid) *wid = strlen(title); *wid += 8; /* extras like #] and . */ *len = i+1; } /* * sets up the menu on MENU window */ dispmenu(boxflag, title, width, length) int boxflag, width, length; char *title; { struct mbar *tmp; if (boxflag) { box(MENU, '|', '-'); mvwaddch(MENU, 0, 0, '/'); mvwaddch(MENU, 0, width-1, '\\'); mvwaddch(MENU, length-1, 0, '\\'); mvwaddch(MENU, length-1, width-1, '/'); } if (title != NULL) { wstandout(MENU); mvwaddstr(MENU, 0, (width / 2) - (strlen(title) / 2), title); wstandend(MENU); } for (tmp = m; tmp != NULL; tmp = tmp->next) { if (tmp->menu_number == 0) continue; wmove(MENU, tmp->menu_number, 1); wprintw(MENU, "%d] %s. ", tmp->menu_number, tmp->menu_choice); } wrefresh(MENU); } /* * un-hilight old selection at num */ delight(num) int num; { struct mbar *tmp; for (tmp = m; tmp != NULL; tmp = tmp->next) { if (num == tmp->menu_number) { wmove(MENU, tmp->menu_number, 1); wprintw(MENU, "%d] %s. ", tmp->menu_number, tmp->menu_choice); } } wrefresh(MENU); } /* * hilight selection at num */ hilight(num) int num; { struct mbar *tmp; for (tmp = m; tmp != NULL; tmp = tmp->next) { if (num == tmp->menu_number) { wstandout(MENU); /* highlight */ wmove(MENU, tmp->menu_number, 1); wprintw(MENU, "%d> %s. ", tmp->menu_number, tmp->menu_choice); wstandend(MENU); } } wrefresh(MENU); } /* * main function call * menubar(y, x, menu) where * y = starting line of menu * x = starting column of menu * menu is of type *menu[] in which are stored the items for be chosen */ menubar(y, x, menu, boxflag, title) int y, x, boxflag; char *menu[], *title; { int cur = 1, old = 1, l, w, num; char c; mkmenubar(&num, menu); sizemenubar(&l, &w, title); initscr(); MENU = newwin(l, w, y, x); /* start (x, y) to (x+w, y+l) */ dispmenu(boxflag, title, w, l); oldsig = signal(SIGINT, menuclean); noecho(); crmode(); for (;;) { delight(old); hilight(cur); if (Stopflag) { cur = -1; goto end; } c = wgetch(MENU); switch(c) { case ESC: wgetch(MENU); switch(wgetch(MENU)) { case UP: case RT: old = cur--; if (Stopflag) { cur = -1; goto end; } break; case DN: case LT: old = cur++; if (Stopflag) { cur = -1; goto end; } break; default: if (Stopflag) { cur = -1; goto end; } break; } break; case LF: case RET: if (Stopflag) { cur = -1; goto end; } end: wclear(MENU); wrefresh(MENU); delwin(MENU); refresh(); echo(); crmode(); return(cur); break; default: if (Stopflag) { cur = -1; goto end; } if (c > '0' || c <= '9') { old = cur; cur = c - '0'; if (cur > num) cur = num; if (cur < 1) cur = 1; } break; } if (cur > num) cur = 1; if (cur < 1) cur = num; } } \End\Of\Shar\ else echo "will not over write ./menubar.c" fi if `test ! -s ./test.c` then echo "writing ./test.c" cat > ./test.c << '\End\Of\Shar\' #include <stdio.h> /* * declare your menus like this: */ char *menu[40] = { "This is menu option 1", "This is menu option 2", "This is menu option 3", "This is menu option 4", 0 }; char title[80] = "THIS IS THE MenuBar"; /* * don't forget this */ extern int menubar(); main() { /* * call menubar like this * it returns the number of choice (good to use as a switch statement) * or a -1 if the person hit return */ printf("\n\nAnd the number is: %d\n", menubar(5, 20, menu, 1, title)); exit(1); } \End\Of\Shar\ else echo "will not over write ./test.c" fi echo "Finished archive 1 of 1" exit exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.