 Area: BC&Pasca 
  Msg#: 119                                          Date: 04-03-96  18:50
  From: Matthew Probert                              Read: Yes    Replied: No 
    To: All                                          Mark:                     
  Subj: Dynamic Menu

             Non-Destructive Menu Selection From An Array

                            Matthew Probert

                           Servile  Software



This code provides a "pop-up" moving bar, scrolling window selection 
menu from an array of strings. The main function MENU() accepts as 
parameters the coordinates of the window, the number of items and the 
array. Colour information is defined in two global variables. The 
screen is saved on entry to the function MENU() and restored on exit. 
The screen save and restore functions take into consideration the 
currently displayed screen page.

The array supplied to the MENU() function is a dynamic array of 
pointers, so the entries for each item can be defined before or after 
compilation - for example a directory listing can be read in to the 
array and passed for file selection. Or hard coded menu items can be 
programmed in prior to compilation.


------------------------------cut here--------------------------------

/*
    A moving bar selection window with defineable screen
    coordinates, colour attributes and selection text

    written for use with Borland C

    Matthew Probert
*/

#include <stdio.h>
#include <alloc.h>
#include <conio.h>
#include <mem.h>
#include <dos.h>

int mc;            /* Normal display attribute */
int hi;            /* Highlight display attribute */
int start;         /* Index of first item in window */
int row;           /* Index of current item relative to window  */
int last_item;     /* Number of items in the menu */
int wm;            /* Length of the window in items */

void DOWN(char **);
void HILITE(char **);
int MENU(int,int,int,int,int,char **);
void RESTORESCREEN(char *);
void SAVESCREEN(char *);
void SHOW_LIST(char **);
void UNLITE(char **);
void UP(char **);

void SHOW_LIST(char **list)
{
    /*
        Display a window of menu options from the array 'list[]'
        Starting at item 'start'
    */

    int n;

    if (start + wm > last_item)
        start = last_item - wm;

    for(n = 0; n <= wm; n++)
    {
        gotoxy(2,n + 1);
        cprintf("%s",list[start + n]);
        clreol();
    }
}

void HILITE(char **list)
{
    /*
        Highlight the current row
    */

    textattr(hi);
    gotoxy(2,row + 1);
    cprintf("%s",list[start + row]);
    textattr(mc);
}

void UNLITE(char **list)
{
    /*
        Dehighlight the current row
    */
    textattr(mc);
    gotoxy(2,row + 1);
    cprintf("%s",list[start + row]);
}

void SAVESCREEN(char *p)
{
    /*
        Save screen display to 'p'
    */

    union REGS inreg,outreg;
    unsigned char far *video;
    unsigned far *video_port;
    int page;

    /*
        Get current display page
    */
    inreg.h.ah = 0x0f;
    int86(0x10,&inreg,&outreg);
    page = outreg.h.bh;

    /*
        Determine type of video card, mono or colour
    */
    video_port = MK_FP(0x40,0x63);
    if (*video_port == 0x3B4)
    {
        video = MK_FP(0xB000,4096 * page);
    }
    else
    {
        video = MK_FP(0xB800,4096 * page);
    }

    _fmemcpy(p,video,4096);
}

void RESTORESCREEN(char *p)
{
    /*
        Restore screen display to 'p'
    */

    union REGS inreg,outreg;
    unsigned char far *video;
    unsigned far *video_port;
    int page;

    /*
        Get current display page
    */
    inreg.h.ah = 0x0f;
    int86(0x10,&inreg,&outreg);
    page = outreg.h.bh;

    /*
        Determine type of video card, mono or colour
    */
    video_port = MK_FP(0x40,0x63);
    if (*video_port == 0x3B4)
    {
        video = MK_FP(0xB000,4096 * page);
    }
    else
    {
        video = MK_FP(0xB800,4096 * page);
    }

    _fmemcpy(video,p,4096);
}

int MENU(int left,int top,int right,int bottom,int number,char **list)
{
    /*
        A moving bar and scrolling window menu of options in 'list'
        Returns the index of the selected item if RETURN is pressed,
        otherwise -1 if ESC is pressed.
        Responds to the Up and Down cursor arrow keys
                        Page Up and Page Down
                        Home and End

        Parameters:
            left    Left column of selection window
            top        Top row of selection window
            right    Right column of selection window
            bottom    Bottom row of selection window
            number    Number of items in the array
            list    The array of display items
    */

    int k;
    char *screen;

    screen = malloc(4096);

    start = 0;
    last_item = number - 1;
    wm = bottom - top;
    window (left,top,right,bottom);
    textattr(mc);

    SAVESCREEN(screen);

    SHOW_LIST(list);

    do
    {
        HILITE(list);

        if ((k = getch()) == 0)
        {
            k = getch();
            switch(k)
            {
                case 72:UP(list);
                        break;

                case 80:DOWN(list);
                        break;

                case 73:if (start > wm)
                            start -= wm;
                        else
                            start = 0;
                        SHOW_LIST(list);
                        break;

                case 81:if (start < last_item - wm)
                        {
                            start += wm;
                            if (start + row > last_item)
                                row = last_item - start;
                            SHOW_LIST(list);
                        }
                        break;

                case 71:row = 0;
                        start = 0;
                        SHOW_LIST(list);
                        break;

                case 79:row = wm;
                        start = last_item - wm;
                        if (row > last_item)
                            row = last_item;
                        if (start < 0)
                            start = 0;
                        SHOW_LIST(list);
                        break;
            }
        }
    }
    while (k != 27 && k != 13);

    RESTORESCREEN(screen);
    free(screen);
    if (k == 13)
        return start + row;
    return -1;
}

void UP(char **list)
{
    /*
        Previous item in menu
    */
    if (row > 0)
    {
        UNLITE(list);
        row--;
    }
    else
    if (start > 0)
    {
        start--;
        SHOW_LIST(list);
    }
}

void DOWN(char **list)
{
    /*
        Next item in menu
    */
    if ((row < wm) && (row < last_item - start))
    {
        UNLITE(list);
        row++;
    }
    else
    if (start < last_item - wm)
    {
        start++;
        SHOW_LIST(list);
    }
}



/*
    Demonstration code follows
*/

void main()
{
    char *desc[50];
    int n;

    for(n = 0; n < 30; n++)
    {
        desc[n] = malloc(30);
        sprintf(desc[n],"Option #%d",n);
    }

    clrscr();

    mc = 30;    /* Unselected item attribute */
    hi = 79;    /* Highlighted item attribute */


    MENU(20,10,31,20,30,desc);
}

------------------------------cut here--------------------------------




... [Servile Info Journal]
___ Blue Wave/QWK v2.12
