/*
菜单演示程序
《C高级实用程序设计》 王士元编著 清华大学出版社 p304 - p320
TC3.0 下编译通过.对源代码略有修改。
2005-5-21 1:11
*/
#include<graphics.h>
#include<alloc.h>
#include<process.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<dos.h>
#include<bios.h>
#include<conio.h>
#include<ctype.h>
#define INSERT 0x5200
#define ESC 0x001b
#define TAB 0x0f09
#define RETURN 0x000d
#define RIGHT 0x4d00
#define LEFT 0x4b00
#define UP 0x4800
#define DOWN 0x5000
#define BS 0x0e08
#define HOME 0x4700
#define END 0x4f00
#define PGUP 0x4900
#define PGDN 0x5100
#define DEL 0x5300
#define F1 0x3b00
#define F2 0x3c00
#define F3 0x3d00
#define F4 0x3e00
#define F5 0x3f00
#define F6 0x4000
#define F7 0x4100
#define F8 0x4200
#define F9 0x4300
#define F10 0x4400
#define MenuInGround 1
#define MenuActiveGround 2
#define MenuActiveItem 3
#define MenuInItem 4
#define MenuEdge 5
#define WindowEdge 6
#define WindowGround 7
#define PopWindow 8
#define WindowMinX 1
#define WindowMinY 25
#define WindowMaxX 638
#define WindowMaxY 478
void getitemcount(char **,int *,int *,int *);
void InitialGraphics(void);
void LoadMainMenu(void);
void LoadSubMenu(char **name,int ord);
int ManageSubMenu(void);
void ManageMainMenu(void);
void DisplayMainMenu(void);
int DisplaySubMenu(int ord);
void FuncProc(int ID);
void GoodBye(char *pcInf1,char *pcInf2);
void In_ActiveMainMenuItem(int select,char In_Active);
void In_ActiveSubMenuItem(int ord,int select,char In_Active);
int GetKey(void);
void MessageBox(char *Message);
void About(void);
void MoveText(void);
void Draw(void);
void GoodBye(char *pcInf1,char *pcInf2);
void ExitMenu(int ord);
int DisplaySubMenu(int ord);
void Help_page_show(void){return;};
unsigned char AllColors[20]={0,CYAN,LIGHTRED,YELLOW,BLACK,WHITE,LIGHTRED,BLUE,CYAN,9,10,11,12,13,14,15};
#define INUM 10 /* maximum 10 items in each MENU */
typedef struct _menu
{
int coor[4]; /* The menu's area */
int itemcoor[4*INUM]; /* max 10 item,each with x1,y1,x2,y2 */
int itemdispxy[2*INUM]; /* Actually disp item name's X coor */
char select; /* selected item's ord */
char itemnum; /* The number of items in this menu */
char **itemname; /* item's name(point to static data) */
int COMMAND_ID[INUM]; /* Key number */
}MENUTYPE;
MENUTYPE MainMenu,SubMenu[INUM];
static char *MainMenuItem[]={"File","Menu1","Menu2","Menu3","Menu4","Quit",0};
static char *SubMenuItem1[]=
{
"Item11",
"Item12",
"Item13",
"Item14",
"Item15",
"Item16",
"Quit",
0
};
static char *SubMenuItem2[]=
{
"Item21",
"Draw",
"Item23",
"Item24",
"Item25",
"Item26",
"Item27",
"Item28",
0
};
static char *SubMenuItem3[]=
{
"Item31...",
"Item32...",
"Item add......",
"Item33",
0
};
static char *SubMenuItem4[]=
{
"Item41...",
"Item42...",
"Moving Text",
"Item44",
"Item45",
"iteme**",
0
};
static char *SubMenuItem5[]=
{
"Item51...",
"About...",
"Item53",
0
};
static char *SubMenuItem6[]=
{
0
};
int maxx,texth,textw;
void * MenuImageBuf;
void main( )
{
InitialGraphics();
maxx=getmaxx();
texth=textheight("text");
textw=textwidth("t");
LoadMainMenu();
LoadSubMenu(SubMenuItem1,0);
LoadSubMenu(SubMenuItem2,1);
LoadSubMenu(SubMenuItem3,2);
LoadSubMenu(SubMenuItem4,3);
LoadSubMenu(SubMenuItem5,4);
LoadSubMenu(SubMenuItem6,5);
ManageMainMenu();
}
/*checked 2005年5月20日 23:58:03 */
void ManageMainMenu(void)
{
unsigned key;
int ID;
DisplayMainMenu();
for(key=0;;)
{
key=GetKey();
switch(key)
{
case LEFT:
In_ActiveMainMenuItem(MainMenu.select,0);
if(MainMenu.select<1) /*Already leftest item in mainmenu */
MainMenu.select=MainMenu.itemnum-1;
else
MainMenu.select--;
In_ActiveMainMenuItem(MainMenu.select,1);/* checked 2005年5月20日 23:58:03*/
break;
case RIGHT:
In_ActiveMainMenuItem(MainMenu.select,0);
if(MainMenu.select>MainMenu.itemnum-2) /*already rightest */
MainMenu.select=0;
else
MainMenu.select++;
In_ActiveMainMenuItem(MainMenu.select,1);
break;
case DOWN:
case RETURN:
switch(MainMenu.COMMAND_ID[MainMenu.select])
{
case 5: /* Exit to DOS */
if(key==DOWN)
break;
closegraph();
GoodBye("Goodbye from","the MENU DEMO in graphics mode.");
break;
default:
ID=ManageSubMenu();
if(ID>=0)
FuncProc(ID);
break;
}
}
}
}
void FuncProc(int ID)
{
switch(ID)
{
case 6: /* 006 File|Quit */
closegraph();
GoodBye("GoodBye from","the MENU DEMO in graphics mode.");
break;
case 101:
Draw();
break;
case 302:
MoveText();
break;
case 401:
About();
break;
default:
/* Clear window */
setfillstyle(SOLID_FILL,AllColors[WindowGround]);
bar(WindowMinX,WindowMinY,WindowMaxX,WindowMaxY);
/* dynamic show item text 2005年5月21日 1:07:50*/
MessageBox(*(SubMenu[MainMenu.select].itemname + SubMenu[MainMenu.select].select));
/* MessageBox("This is an example!");*/
break;
}
}
/* 2005年5月21日 0:26:12*/
/* ManageSubMenu() return an int value that is */
/* ==-2:If there is a error */
/* ==-1:Return to main menu,nothing to do */
/* ==0 or >0:the COMMAND_ID of a menu item */
int ManageSubMenu(void)
{
MENUTYPE * mn=&SubMenu[MainMenu.select];
unsigned key;
if(DisplaySubMenu(MainMenu.select)) /*Out of memery */
return -2;
for(key=0;;)
{
key=GetKey();
switch(key)
{
case ESC: /* return to MainMenu */
ExitMenu(MainMenu.select);
return -1;
case UP:
In_ActiveSubMenuItem(MainMenu.select,mn->select,0);
if(mn->select>0)
mn->select--;
else
mn->select=mn->itemnum-1;
In_ActiveSubMenuItem(MainMenu.select,mn->select,1);
break;
case DOWN:
In_ActiveSubMenuItem(MainMenu.select,mn->select,0);
if(mn->select<mn->itemnum-1)
mn->select++;
else
mn->select=0;
In_ActiveSubMenuItem(MainMenu.select,mn->select,1);
break;
case LEFT:
ExitMenu(MainMenu.select);
In_ActiveMainMenuItem(MainMenu.select,0); /*2005年5月21日 0:25:04*/
if(MainMenu.select<1) /*Already leftest item in mainmenu */
MainMenu.select=(MainMenu.itemnum-1);
else
MainMenu.select--;
In_ActiveMainMenuItem(MainMenu.select,1); /*Light bar */
if(DisplaySubMenu(MainMenu.select)) /*Out of memory */
return -2;
mn=&SubMenu[MainMenu.select];
break;
case RIGHT:
ExitMenu(MainMenu.select);
In_ActiveMainMenuItem(MainMenu.select,0);
if(MainMenu.select>MainMenu.itemnum-2) /*already rightest */
MainMenu.select=0;
else
MainMenu.select++;
In_ActiveMainMenuItem(MainMenu.select,1);
if(DisplaySubMenu(MainMenu.select)) /* Out of memory */
return -2;
mn=&SubMenu[MainMenu.select];
break;
case RETURN:
ExitMenu(MainMenu.select);
return mn->COMMAND_ID[mn->select];
}
}
}
/* Checked 2005年5月20日 21:36:47 */
void LoadMainMenu()
{
int count,totallen,maxlen,i,j=1;
/*主菜单的两条对角线坐标*/
MainMenu.coor[0]=0;
MainMenu.coor[1]=0;
MainMenu.coor[2]=maxx;
MainMenu.coor[3]=3*texth;
getitemcount(MainMenuItem,&count,&totallen,&maxlen);
MainMenu.itemnum=count;
maxlen=(maxx/textw-totallen)/count; /*length(char)between 2 items(horiz.) */
for(i=0,j=0;i<count;i++)
{
MainMenu.itemcoor[i*4]=j*textw; /* x1 */
MainMenu.itemcoor[i*4+1]=MainMenu.coor[1]; /* y1 */
MainMenu.itemcoor[i*4+2]=textw*(j+maxlen+strlen(MainMenuItem[i]));
/* x2 */
MainMenu.itemcoor[i*4+3]=MainMenu.coor[3];
MainMenu.itemdispxy[i*2]=textw*(j+0.5*maxlen); /* actuall disp X */
MainMenu.itemdispxy[i*2+1]=texth; /* actuall disp Y */
MainMenu.COMMAND_ID[i]=i;
j+=maxlen+strlen(MainMenuItem[i]);
}
MainMenu.itemname=MainMenuItem;
}
void LoadSubMenu(char **name,int ord)
{
int count,i,j,maxlen;
getitemcount(name,&count,&i,&maxlen);
SubMenu[ord].itemname=name;
SubMenu[ord].itemnum=count;
j=textw*(maxlen+2);
if(j+MainMenu.itemcoor[4*ord]<maxx) /* left text justification is OK */
{
SubMenu[ord].coor[0]=MainMenu.itemcoor[4*ord]; /* item's x1 */
SubMenu[ord].coor[2]=SubMenu[ord].coor[0]+j;
}
else /* Use right justification because of space */
{
SubMenu[ord].coor[2]=maxx; /* left just use X2 */
SubMenu[ord].coor[0]=SubMenu[ord].coor[2]-j;
}
SubMenu[ord].coor[1]=MainMenu.itemcoor[4*ord+3]; /* The item's y2 */
SubMenu[ord].coor[3]=SubMenu[ord].coor[1]+count*(texth+6);
/* 6-pixel between items of vert.menu */
for(i=0;i<count;i++)
{
SubMenu[ord].itemcoor[i*4]=SubMenu[ord].coor[0];
SubMenu[ord].itemcoor[i*4+1]=SubMenu[ord].coor[1]+i*(6+texth);
SubMenu[ord].itemcoor[i*4+2]=SubMenu[ord].coor[2];
SubMenu[ord].itemcoor[i*4+3]=SubMenu[ord].itemcoor[i*4+1]+texth+6;
SubMenu[ord].itemdispxy[i*2]=SubMenu[ord].itemcoor[i*4]+textw;
SubMenu[ord].itemdispxy[i*2+1]=SubMenu[ord].itemcoor[i*4+1]+3;
SubMenu[ord].COMMAND_ID[i]=ord*100+i;
}
}
/* checked in 2005年5月20日 23:39:02 */
void DisplayMainMenu(void) /* Display main menu. */
{
unsigned i;
setcolor(AllColors[WindowEdge]);
rectangle(0,0,getmaxx(),getmaxy());
setcolor(AllColors[MenuEdge]);
setfillstyle(SOLID_FILL,AllColors[MenuInGround]);
bar3d(MainMenu.coor[0],MainMenu.coor[1],MainMenu.coor[2],MainMenu.coor[3],0,0);
setcolor(AllColors[2]);
MainMenu.select = 0 ;
for(i=0;i<MainMenu.itemnum;i++) /* */
{
if(MainMenu.select==i)
In_ActiveMainMenuItem(i,1);
else
setcolor(AllColors[MenuInItem]);
outtextxy((MainMenu.itemdispxy[i*2]),MainMenu.itemdispxy[i*2+1],MainMenu.itemname[i]);
}
}
int DisplaySubMenu(int ord) /* Display submenu */
{
unsigned size,i;
MENUTYPE *mn=&SubMenu[ord];
size=imagesize(mn->coor[0],mn->coor[1],mn->coor[2],mn->coor[3]);
/*
Changed farmalloc to malloc and also changed farfree to free in function ExitMenu().
Or else it will cause CPU error!
2005年5月21日 0:30:48
*/
if(NULL==(MenuImageBuf=(unsigned char *)malloc(size*2)))
{
clearviewport();
outtextxy(100,100,"Out of memory!");
outtextxy(100,110,"Press any key..");
getch();
return 1;
}
getimage(mn->coor[0],mn->coor[1],mn->coor[2],mn->coor[3],MenuImageBuf);
setfillstyle(SOLID_FILL,AllColors[MenuInGround]);
setcolor(AllColors[MenuEdge]);
bar3d(mn->coor[0],mn->coor[1],mn->coor[2],mn->coor[3],0,0);
for(i=0;i<mn->itemnum;i++)
{
if(i==mn->select)
In_ActiveSubMenuItem(ord,i,1);
else
{
setcolor(AllColors[MenuInItem]);
outtextxy(mn->itemdispxy[i*2],mn->itemdispxy[i*2+1],mn->itemname[i]);
}
}
return 0;
}
void ExitMenu(int ord)
{
MENUTYPE *mn=&SubMenu[ord];
if(MenuImageBuf)
{
putimage(mn->coor[0],mn->coor[1],MenuImageBuf,COPY_PUT);
free(MenuImageBuf);
}
}
void In_ActiveMainMenuItem(int select,char In_Active)
{
MENUTYPE *tp=&MainMenu;
int start,end,bot,top;
start=tp->itemcoor[select*4]+8;
top=tp->itemcoor[select*4+1]+2;
end=tp->itemcoor[select*4+2]-8;
bot=tp->itemcoor[select*4+3]-2;
if(In_Active==0) /* off */
{
setfillstyle(SOLID_FILL,AllColors[MenuInGround]);
bar(start,top,end,bot);
setcolor(AllColors[MenuInItem]);
outtextxy(tp->itemdispxy[select*2],tp->itemdispxy[select*2+1],tp->itemname[select]);
}
else
{
setfillstyle(SOLID_FILL,AllColors[MenuActiveGround]);
bar(start,top,end,bot);
setcolor(AllColors[MenuActiveItem]);
outtextxy(tp->itemdispxy[select*2],tp->itemdispxy[select*2+1],tp->itemname[select]);
}
}
/* 2005年5月21日 0:21:25*/
void In_ActiveSubMenuItem(int ord,int select,char In_Active)
{
MENUTYPE *tp=&SubMenu[ord];
int start,end,bot,top;
start=tp->itemcoor[select*4]+2;
top=tp->itemcoor[select*4+1]+1;
end=tp->itemcoor[select*4+2]-2;
bot=tp->itemcoor[select*4+3]-1;
if(In_Active==0) /* off */
{
setfillstyle(SOLID_FILL,AllColors[MenuInGround]);
bar(start,top,end,bot);
setcolor(AllColors[MenuInItem]);
outtextxy(tp->itemdispxy[select*2],tp->itemdispxy[select*2+1],tp->itemname[select]);
}
else
{
setfillstyle(SOLID_FILL,AllColors[MenuActiveGround]);/*updated 2005年5月21日 0:20:56*/
bar(start,top,end,bot);
setcolor(AllColors[MenuActiveItem]);/*0:21:09*/
outtextxy(tp->itemdispxy[select*2],tp->itemdispxy[select*2+1],tp->itemname[select]);
}
}
void InitialGraphics(void)
{
int driver=DETECT,mode=0;
int errorcode;
initgraph(&driver,&mode,"C://TC//BGI");
/* read result of initialization */
errorcode=graphresult();
if(errorcode!=grOk) /* an error occurred */
{
printf("Graphics error:%s/n",grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
GoodBye("Graphics error.","Try again!");
}
}
int GetKey(void)/* */
{
int key;
key=bioskey(0);
if(key==F1)
Help_page_show();
else if(key<<8)
{
key=key&0x00ff; /* Get ASCII code */
if(isalpha(key))
key=toupper(key);
}
return key;
}
static void getitemcount(char **s,int *count,int *len,int *maxlen) /* */
{
int i,j;
for((*maxlen)=0,(*len)=0,i=0;s[i]!=NULL;i++)
{
j=strlen(s[i]);
(*len)+=j;
if(j>(*maxlen))(*maxlen)=j;
}
(*count)=i;
}
void Draw(void)
{
int x,x1,x2,y1,y2,ch;
randomize();
do
{
x1=random(WindowMaxX-WindowMinX)+WindowMinX;
y1=random(WindowMaxY-WindowMinY)+WindowMinY;
x2=random(WindowMaxX-WindowMinX)+WindowMinX;
y2=random(WindowMaxY-WindowMinY)+WindowMinY;
ch=random(16);
setfillstyle(SOLID_FILL,ch);
if(x1>x2)
{
x=x1;
x1=x2;
x2=x;
}
if(y1>y2)
{
x=y1;
y1=y2;
y2=x;
}
bar(x1,y1,x2,y2);
delay(100);
}while(!bioskey(1));
}
/* modified on 2005年5月21日 9:10:37*/
void About(void)
{
int MidX,MidY,x1,y1,x2,y2,size;
void *Buffer;
MidX=(WindowMaxX-WindowMinX)/2;
MidY=(WindowMaxY-WindowMinY)/2;
x1=MidX-90;
x2=MidX+90;
y1=MidY-100;
y2=MidY+100;
size=imagesize(x1,y1,x2,y2);
/* Clear window */
setfillstyle(SOLID_FILL,AllColors[WindowGround]);
bar(WindowMinX,WindowMinY,WindowMaxX-1,WindowMaxY-1);
if((Buffer=malloc(size))==NULL)
{
outtextxy(100,100,"Out of memory!Press any key to continue.");
getch();
}
else
{
getimage(x1,y1,x2,y2,Buffer);
setfillstyle(SOLID_FILL,AllColors[PopWindow]);
bar(x1,y1,x2-9,y2-9);
setfillstyle(SOLID_FILL,BLACK);
bar(x1+8,y2-8,x2,y2);
bar(x2-8,y1+8,x2,y2);
setcolor(MAGENTA);
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy(MidX-4,MidY-40,"MENU EXAMPLE");
outtextxy(MidX-4,MidY-20,"IN GRAPHICS MODE");
outtextxy(MidX-4,MidY+25,"10-2005 by");
outtextxy(MidX-4,MidY+45,"XXX studio");
getch();
putimage(x1,y1,Buffer,COPY_PUT);
free(Buffer);
settextjustify(LEFT_TEXT,TOP_TEXT);
}
}
/* modified by meteor135
2005年5月21日 0:56:55*/
void MessageBox(char *Message)
{
int MidX,MidY,x1,y1,x2,y2,size,Len;
void *Buffer;
MidX=(WindowMaxX-WindowMinX)/2;
MidY=(WindowMaxY-WindowMinY)/2;
Len=8*(strlen(Message)+1)/2;
x1=MidX-Len-5*8;
x2=MidX+Len+5*8;
y1=MidY-50;
y2=MidY+50;
size=imagesize(x1,y1,x2,y2);
if((Buffer=malloc(size))==NULL)
{
outtextxy(100,100,"Out of memorry! Press any key to continue.");
getch();
}
else
{
getimage(x1,y1,x2,y2,Buffer);
setcolor(AllColors[MenuEdge]);
rectangle(x1,y1,x2-13,y2-13);
setfillstyle(SOLID_FILL,AllColors[PopWindow]);
bar(x1+1,y1+1,x2-14,y2-14); //2005年5月21日 0:51:14
setfillstyle(SOLID_FILL,DARKGRAY);//2005年5月21日 0:56:37
bar(x1+12,y2-12,x2,y2);
bar(x2-12,y1+12,x2,y2);
setcolor(MAGENTA);//2005年5月21日 0:56:26
settextjustify(CENTER_TEXT,CENTER_TEXT);
outtextxy(MidX,MidY-20,Message);
setfillstyle(SOLID_FILL,LIGHTRED);
bar(MidX-3*8,MidY+16,MidX+3*8,MidY+34);
setcolor(YELLOW);
outtextxy(MidX,MidY+26,"OK");
getch();
putimage(x1,y1,Buffer,COPY_PUT);
free(Buffer);
settextjustify(LEFT_TEXT,TOP_TEXT);
}
}
void MoveText(void)
{
int i;
/* Clear window */
setfillstyle(SOLID_FILL,BLUE);
bar(WindowMinX,WindowMinY,WindowMaxX,WindowMaxY);
setcolor(YELLOW);
for(i=300;i>1;i-=2)
{
outtextxy(i,100,"Menu example!");
delay(50);
bar(i,100,i+104,108);
}
}
void GoodBye(char *pcInf1,char *pcInf2)
{
int f;
clrscr();
window(1,1,80,1);
textbackground(LIGHTBLUE);
clrscr();
highvideo();
textcolor(WHITE);
cprintf(pcInf1);
textcolor(YELLOW);
cprintf(pcInf2);
window(1,1,80,25);
printf("/n");
for(f=400;f<800;f+=100)
{
sound(f);
delay(100);
}
for(f=400;f>=200;f-=100)
{
sound(f);
delay(200);
}
sound(1000);
delay(1000);
nosound();
exit(0);
}