Listing 1 (cujmenu.c)

/************************************************************
    An implementation of the point and shoot menu system.
    The main function is a simple demonstration routine.
*/

#include <stdio.h>
#include <conio.h>

#define CRET     0x0d            /* key definitions */
#define TAB      0x09
#define BACKTAB  0x0f            /* key scan codes */
#define UPARROW  0x48
#define DNARROW  0x50
#define LTARROW  0x4b
#define RTARROW  0x4d
#define PAGEUP   0x49
#define PAGEDN   0x51
#define HOMEKEY  0x47
#define ENDKEY   0x4f
#define CTRLEND  0x75

/************************************************************
    display one line of menu at the proper location. If
    an X offset is specified then this must be horizontal
    formatted menu.
*/
void show (int x,int y,int xoff,int yoff,char *p,int fore)
{
    if (xoff)                /* if an X offset exist */
       x += xoff;
    else
       y += yoff;

    gotoxy(x,y);
    textcolor(fore|8);       /* use intense color */
    putch(*p++);             /* print the first char */
    textcolor(fore);         /* back to normal color */
    cputs(p);                /* print the rest of it */
}

/************************************************************
    search the p list for a beginning character in the
    menu list that matches c.
*/
int findletter (char c, char *p[], int i)
{
    int j = 0;

    while (*p[j] != NULL)      /* while not at end */
    if (c == *p[j])            /* if we find a match */
       { i = j; break; }      /* record and quit */
    else
       j++;
    
    return(i);                 /* return the new idx */
}

/************************************************************
    initialize certain location variables to allow us
    to write at proper screen location.
*/
int init (char *p[], int horz, int *xoff)
{
    int max = 0, x = 0;

    if (horz)                      /* if horizontal format */
    {
       while (p[max] != NULL)     /* while not at end */
       {
          *xoff++ = x;           /* calc X offsets */
          x += strlen(p[max++]); /* add length of item */
       }
    }

    else                           /* else zero it out */
    {
        while (p[max++] != NULL) *xoff++ = 0;
        max--;
    }

    return(max);                   /* number of items found */
}

/************************************************************
    set the index according to user's response. returns
    the new index value or -1 if the user pressed enter.
*/
int keypress (char *p[], char c, int i, int max)
{
    int done = 0;

    switch(c)                  /* switch on user input */
    {
        case UPARROW:
        case LTARROW:
        case BACKTAB:    i--;         break;
        case DNARROW:
        case RTARROW:
        case TAB:        i++;         break;
        case CRET:       done=1;      break;
        default:         i = findletter(c,p,i);
    }

    if (done) i = -1; else      /* if done, ret -1 */
    if (i < 0) i = max-1; else  /* else do range check */
    if (i == max) i = 0;
    
    return(i);                  /* ret new index */
}

/************************************************************
    display a point and shoot menu. Return the first
    character of the menu option selected.
*/
char menu (char *p[], int horz)
#define MAX_ELEMENTS 12
{
    struct text_info info;      /* holds text screen info */
    int i, j, x = 0, y, fore, back, max, savei;
    int xoff[MAX_ELEMENTS];     /* for use w/ horiz format */
    char c;

    max = init(p,horz,xoff);    /* calc screen positions */
    gettextinfo(&info);         /* get current screen attr */
    fore = info.attribute & 0x0f;/* extract foreground color */
    back = info.attribute >> 4; /* extract background color */
    x = info.curx;              /* establish reference location */
    y = info.cury;
    _setcursortype(_NOCURSOR);  /* turn cursor off */
    for (i=0; i<max; i++)       /* display all menu items */
        show(x,y,xoff[i],i,p[i],fore);
    i = 0;

    do
    {
        textcolor(back);                /* set reverse video mode */
        textbackground(fore);
        show(x,y,xoff[i],i,p[i],back);  /* display selected item*/
        if ((c = toupper(getch())) == 0)/* if 0 is returned */
           c = getch();                /* then get scan code */
        textcolor(fore);                /* set normal video mode */
        textbackground(back);
        show(x,y,xoff[i],i,p[i],fore);  /* redisplay item */
        savei = i;                      /* save prev sel item */
    }

while ((i = keypress(p,c,i,max)) != -1); /* quit when user selects */

_setcursortype(_NORMALCURSOR);      /* turn cursor back on */
return(*p[savei]);                  /* return selection */
}

/************************************************************
    demonstration main function to show use of the point
    and shoot menu.
*/
void main (void)
{
    char *p[] = {"First  ","Second  ","Third",
                 "Quit  ",NULL}, c;
    int format = 0;

    textcolor(LIGHTGRAY);
    textbackground(BLUE);
    clrscr();
    cputs("Display menu in horizontal format? (y/n) >");
    if (toupper(getch()) == 'Y')format = 1;
    gotoxy(10,10);
    while ((c = menu(p,format)) != 'Q')
    {
        gotoxy(10,20);
        cprintf("The selected option is: %c\n\r",c);
        gotoxy(10,10);
    }
}