v17i062: menubar - C Menubar function, Part01/01

J.E. King jek5036 at ultb.isc.rit.edu
Fri Mar 22 07:08:26 AEST 1991


Submitted-by: J.E. King <jek5036 at 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 at 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 at 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 at 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 at uunet.uu.net.



More information about the Comp.sources.misc mailing list