/*
	mouseg.c
*/
#include <dos.h>
#include <stdio.h>
#include <malloc.h>

#define LEFT_BUTTON 0
#define RIGHT_BUTTON 1
#define BUTTON_DOWN  0
#define BUTTON_UP    1
#define MAX_ITEM 10

extern int Font[128][25];
extern int ScreenXs,ScreenYs;
unsigned char MouseBuffer[100];
unsigned char BarBuffer[17][640];
unsigned char *MenuBuffer[160];
int MouseMove;
struct menu_item
{
	char *item,ret,status;
};
struct menu
{
	char *bar,bar_return,status;
	int num_entry;
	struct menu_item menu[MAX_ITEM];
};

int mouse_initialize(int sensitivity);
void mouse_show_cursor(void);
void mouse_hide_cursor(void);
void mouse_information(int *right,int *left,int *row,int *col);
void mouse_move_cursor(int row,int col);
void mouse_times_pressed(int mouse_button,int *num_times,int *row,int *col);
void mouse_times_released(int mouse_button,int *num_times,int *row,int *col);
void mouse_horizontal_range(int left,int right);
void mouse_vertical_range(int top,int bottom);

void mouse_get_button(int *right,int *left);
int mouse_get_point(int *right,int *left,int *row,int *col,int button_up);
char mouse_menu(struct menu *m,int back_color,int off_color,int on_color,
		int ret_inactive,
		int ret_left,int ret_right,int ret_top,int ret_bottom,
		int ret_row,int ret_col,int *start_row,int *start_col,
		int ret_mousemove,int cursor,int button_up);

/********************************************************************
**
**
**
********************************************************************* */

int mouse_limit_area(int *x,int *y,int *xsize,int *ysize,int *speed,
		int maxbox,int iop,unsigned char *buffer)

{
	char ans;
	int size=0,xo,yo,menu=1;
	int spd=*speed;
	int dir=1;
	int row,col,right,left,times;
	int pushed=0;

	if(*xsize>ScreenXs)
		*xsize=ScreenXs;
	if(*x+*xsize>=ScreenXs)
		*x=ScreenXs-*xsize;
	if(*ysize>ScreenYs)
		*ysize=ScreenYs;
	if(*y+*ysize>=ScreenYs)
		*y=ScreenYs-*ysize;
	col=xo=*x;
	row=yo=*y;
	tbox(3,*x,*y,*xsize,*ysize,buffer); /* plot 1st box on overlay */
	mouse_times_released(LEFT_BUTTON,&times,&row,&col);
	mouse_move_cursor(*y,*x);
	do
	{
		mouse_information(&right,&left,&row,&col);
		if(left!=0)
			pushed=1;
		if(right==0)
		{
			*y=row;
			*x=col;
		}
		else
		{
			unbox(3,xo,yo,*xsize,*ysize,buffer); /* remove old box */
			return(27);
		}
		if(xo!=*x||yo!=*y)
		{
			unbox(3,xo,yo,*xsize,*ysize,buffer); /* remove old box */
			if(*x<0)*x=0;							/* make sure all is on screen */
			if(*y<0)*y=0;
			if(*x+*xsize>(ScreenXs-1))*x=(ScreenXs-1)-*xsize;
			if(*y+*ysize>(ScreenYs-1))*y=(ScreenYs-1)-*ysize;
			tbox(3,*x,*y,*xsize,*ysize,buffer);  /* plot new box on overlay */	
			xo=*x;									/* set old location */
			yo=*y;
		}
		mouse_times_released(LEFT_BUTTON,&times,&row,&col);
	}while(times==0||pushed==0);
	unbox(3,xo,yo,*xsize,*ysize,buffer); /* remove old box */
	return(1);
}





/***********************************************************************
**
**
**
**
************************************************************************/

void mouse_get_button(int *right,int *left)

{
	int row,col;
	int val,left_down,right_down;

	mouse_information(right,left,&row,&col);
	for(;;)
	{
		mouse_information(right,left,&row,&col);
		if(*left>0||*right>0)
		{
			do
			{
				mouse_information(&right_down,&left_down,&row,&col);
				if(right_down>0)
					*right=right_down;
				if(left_down>0)
					*left=left_down;
			}while(right_down!=0||left_down!=0);
			return;
		}
	}
}



/***********************************************************************
**
**
**
**
************************************************************************/

int mouse_get_point(int *right,int *left,int *row,int *col,int button_up)

{
	int rowo,colo,ro,co;
	int val,left_down,right_down;

	mouse_information(right,left,row,col);
	rowo=*row;
	colo=*col;
	tcursor(0,*col,*row,5,MouseBuffer);
	for(;;)
	{
		mouse_information(right,left,row,col);
		if(*row!=rowo||*col!=colo)
		{
			uncursor(0,colo,rowo,5,MouseBuffer);
			tcursor(0,*col,*row,5,MouseBuffer);
			colo=*col;
			rowo=*row;
		}
		if(*left>0||*right>0)
		{
			uncursor(0,colo,rowo,5,MouseBuffer);
			val=getpt(0,*col,*row);
			if(button_up==1)
			{
				do
				{
					mouse_information(&right_down,&left_down,row,col);
					if(right_down>0)
						*right=right_down;
					if(left_down>0)
						*left=left_down;
				}while(right_down!=0||left_down!=0);
			}
			return(val);
		}
	}
}

/***********************************************************************
**  ret_mousemove is the sensitivity setting to return to
**     cursor = 0  cursor off
**              else cursor on
**  button_up = 1 returns only when all buttons are up
**              else returns with buttons down
**
**      ret_* = settings before returning
**    start_* = settings to start and where ended
**
************************************************************************/

char mouse_menu(struct menu *m,int back_color,int off_color,int on_color,
		int inactive_color,
		int ret_left,int ret_right,int ret_top,int ret_bottom,
		int ret_row,int ret_col,int *start_row,int *start_col,
		int ret_mousemove,int cursor,int button_up)

{
	int i,j,k;
	int ix1,ix2,iy1,iy2,inum;
	char ret=0,ans;
	int io=-1,times,jo=-1;
	int row,col,right,left;
	int rowo=-1,colo=-1;
	int size=2,high=32/size,wide=ScreenXs/8,num=0;
	int maxnum=8,color;

	for(i=0;i<160;i++)
	{
		MenuBuffer[i]=(unsigned char *)malloc(100);
		if(MenuBuffer[i]==NULL)
		{
			SetVideoMode(0);
			printf("i = %d   malloc failed\n\n",i);
			exit(0);
		}
	}
	MouseMove=1;
	for(i=0;i<maxnum;i++)
	{
		if(m[i].bar[0]>0&&m[i].bar[0]!='*')
			num=i+1;
		else
			break;
	}
	if(num<1||num>MAX_ITEM)
	{
		MouseMove=ret_mousemove;
		for(i=0;i<160;i++)
			free(MenuBuffer[i]);
		return(27);
	}
	mouse_vertical_range(0,15);
	mouse_horizontal_range(0,num*wide-1);
	mouse_move_cursor(*start_row,*start_col);
	for(k=0;k<high;k++)
		getrow(0,0,ScreenXs-1,k,BarBuffer[k]);
	paint_box(0,back_color,BarBuffer[16],0,0,num*wide,16);
	for(i=0;i<num;i++)
	{
		box(0,i*wide,0,off_color,wide,high-1);
		if(m[i].num_entry>0)
			plotln(0,i*wide,high-2,(i+1)*wide-1,high-2,off_color);
		color=(m[i].status>0)?off_color:inactive_color;
		plot_font_h(color,i*wide+2,2,m[i].bar,size,Font);
	}
	mouse_times_released(LEFT_BUTTON,&times,&row,&col);
	mouse_information(&right,&left,&row,&col);
	if(cursor!=0)
		tcursor(0,col,row,5,MouseBuffer);
	colo=col;
	rowo=row;	
	do
	{
		mouse_information(&right,&left,&row,&col);
		if(row!=rowo||col!=colo)
		{
			if(cursor!=0)
			{
				uncursor(0,colo,rowo,5,MouseBuffer);
				tcursor(0,col,row,5,MouseBuffer);
			}
			colo=col;
			rowo=row;
		}
		i=col/wide;
		if(i!=io)
		{
			ans=m[i].bar_return;
			if(cursor!=0)
				uncursor(0,colo,rowo,5,MouseBuffer);
			color=(m[io].status>0)?off_color:inactive_color;
			if(io>=0)
				plot_font_h(color,io*wide+2,2,m[io].bar,size,Font);
			color=(m[i].status>0)?on_color:off_color;
			plot_font_h(color,i*wide+2,2,m[i].bar,size,Font);
			box(0,io*wide,0,off_color,wide,high-1);
			if(m[io].num_entry>0)
				plotln(0,io*wide,high-2,(io+1)*wide-1,high-2,off_color);
			box(0,i*wide,0,on_color,wide,high-1);
			if(m[i].num_entry>0)
				plotln(0,i*wide,high-2,(i+1)*wide-1,high-2,on_color);
			if(cursor!=0)
				tcursor(0,colo,rowo,5,MouseBuffer);
			io=i;
		}
		if(left!=0||(m[i].num_entry>0&&row==high-1))
		{
			if(m[i].num_entry==0&&m[i].status>0)
				ret=1;
			else
			{
				if(cursor!=0)
					uncursor(0,colo,rowo,5,MouseBuffer);
				ix1=i*wide;
				ix2=(i+1)*wide-1;
				iy1=high;
				inum=m[i].num_entry;
				iy2=high*(inum+1)-1;
				for(k=iy1;k<=iy2;k++)
					getrow(0,ix1,ix2,k,MenuBuffer[k-iy1]);
				color=(m[io].status>0)?off_color:inactive_color;
				plot_font_h(color,io*wide+2,2,m[io].bar,size,Font);
				color=(m[i].status>0)?on_color:off_color;
				plot_font_h(color,i*wide+2,2,m[i].bar,size,Font);
				box(0,i*wide,0,off_color,wide,high-1);
				if(m[i].num_entry>0)
				plotln(0,i*wide,high-2,(i+1)*wide-1,high-2,off_color);
				paint_box(0,back_color,BarBuffer[16],ix1,iy1,wide,high*inum);
				box(0,ix1,iy1,off_color,wide-1,high*inum-1);
				for(j=0;j<inum;j++)
				{
					color=(m[i].menu[j].status>0)?off_color:inactive_color;
					plot_font_h(color,ix1+2,iy1+j*high+2,
						m[i].menu[j].item,size,Font);
				}
				mouse_vertical_range(iy1,iy2);
				mouse_horizontal_range(ix1,ix2);
				row=rowo=iy1+high/2;
				col=colo=(ix1+ix2)/2;
				mouse_move_cursor(row,col);
				if(cursor!=0)
					tcursor(0,colo,rowo,5,MouseBuffer);
				jo=-1;
				do
				{
					mouse_information(&right,&left,&row,&col);
					if(left>0&&m[i].menu[j].status>0)
					{
						ret=1;
						ans=m[i].menu[j].ret;
					}
					if(row!=rowo||col!=colo)
					{
						if(cursor!=0)
						{
							uncursor(0,colo,rowo,5,MouseBuffer);
							tcursor(0,col,row,5,MouseBuffer);
						}
						colo=col;
						rowo=row;
					}
					j=row/high-1;
					if(j!=jo)
					{
						if(cursor!=0)
							uncursor(0,colo,rowo,5,MouseBuffer);
						color=(m[i].menu[jo].status>0)?off_color:inactive_color;
						if(jo>=0)
							plot_font_h(color,ix1+2,iy1+jo*high+2,
								m[i].menu[jo].item,size,Font);
						color=(m[i].menu[j].status>0)?on_color:off_color;
						plot_font_h(color,ix1+2,iy1+j*high+2,
							m[i].menu[j].item,size,Font);
						jo=j;
						if(cursor!=0)
							tcursor(0,col,row,5,MouseBuffer);
					}
				}while(row!=iy1&&ret==0);
				if(cursor!=0)
					uncursor(0,colo,rowo,5,MouseBuffer);
				mouse_vertical_range(0,15);
				mouse_horizontal_range(0,num*wide-1);
				col=colo;
				row=rowo=7;
				mouse_move_cursor(row,col);
				for(k=iy1;k<=iy2;k++)
					plotrow(0,ix1,ix2,k,MenuBuffer[k-iy1]);
				if(cursor!=0)
					tcursor(0,col,row,5,MouseBuffer);
			}
		}
		if(ret==1)
		{
			if(cursor!=0)
				uncursor(0,colo,rowo,5,MouseBuffer);
			for(k=0;k<high;k++)
				plotrow(0,0,ScreenXs-1,k,BarBuffer[k]);
			if(button_up==1)
				do
				{
					mouse_times_released(LEFT_BUTTON,&times,&row,&col);
				}while(times==0);
			MouseMove=ret_mousemove;
			mouse_vertical_range(ret_top,ret_bottom);
			mouse_horizontal_range(ret_left,ret_right);
			*start_row=row;
			*start_col=col;
			mouse_move_cursor(ret_row,ret_col);
			for(i=0;i<160;i++)
				free(MenuBuffer[i]);
			return(ans);
		}
	}while(right==0);
	if(cursor!=0)
		uncursor(0,colo,rowo,5,MouseBuffer);
	for(k=0;k<high;k++)
		plotrow(0,0,ScreenXs-1,k,BarBuffer[k]);
	if(button_up==1)
		do
		{
			mouse_times_released(RIGHT_BUTTON,&times,&row,&col);
		}while(times==0);
	MouseMove=ret_mousemove;
	mouse_vertical_range(ret_top,ret_bottom);
	mouse_horizontal_range(ret_left,ret_right);
	*start_row=row;
	*start_col=col;
	mouse_move_cursor(ret_row,ret_col);
	for(i=0;i<160;i++)
		free(MenuBuffer[i]);
	return(27);
}


/**************************************************************************
**
**
**
************************************************************************* */

int mouse_initialize(int sensitivity)

{
	union REGS in_regs,out_regs;

	in_regs.x.ax=0;
	int86(0x33,&in_regs,&out_regs);
	MouseMove=sensitivity;
	return(out_regs.x.ax);
}


/**************************************************************************
**
**
**
************************************************************************* */

void mouse_show_cursor(void)

{
	union REGS in_regs,out_regs;

	in_regs.x.ax=1;
	int86(0x33,&in_regs,&out_regs);
}



/**************************************************************************
**
**
**
************************************************************************* */

void mouse_hide_cursor(void)

{
	union REGS in_regs,out_regs;

	in_regs.x.ax=2;
	int86(0x33,&in_regs,&out_regs);
}

/**************************************************************************
**
**
**
************************************************************************* */

void mouse_information(int *right,int *left,int *row,int *col)

{
	union REGS in_regs,out_regs;

	in_regs.x.ax=3;
	int86(0x33,&in_regs,&out_regs);
	*right=*left=0;
	switch(out_regs.x.bx)
	{
		case 1:
			*left=1;
			break;
		case 2:
			*right=1;
			break;
		case 3:
			*left=1;
			*right=1;
	}
	*row=out_regs.x.dx/MouseMove;
	*col=out_regs.x.cx/MouseMove;
}


/**************************************************************************
**
**
**
************************************************************************* */

void mouse_move_cursor(int row,int col)

{
	union REGS in_regs,out_regs;

	in_regs.x.dx=row*MouseMove;
	in_regs.x.cx=col*MouseMove;
	in_regs.x.ax=4;
	int86(0x33,&in_regs,&out_regs);
}


/**************************************************************************
**
**
**
************************************************************************* */


void mouse_horizontal_range(int left,int right)

{
	union REGS in_regs,out_regs;

	in_regs.x.cx=right*MouseMove;
	in_regs.x.dx=left*MouseMove;
	in_regs.x.ax=7;
	int86(0x33,&in_regs,&out_regs);
}






/**************************************************************************
**
**
**
************************************************************************* */

void mouse_vertical_range(int top,int bottom)

{
	union REGS in_regs,out_regs;

	in_regs.x.dx=top*MouseMove;
	in_regs.x.cx=bottom*MouseMove;
	in_regs.x.ax=8;
	int86(0x33,&in_regs,&out_regs);
}



/**************************************************************************
**
**
**	   0 -- left
**    1 -- right
**
**
************************************************************************* */

void mouse_times_pressed(int mouse_button,int *num_times,int *row,int *col)

{
	union REGS in_regs,out_regs;

	in_regs.x.bx=mouse_button;
	in_regs.x.ax=5;
	int86(0x33,&in_regs,&out_regs);
	*num_times=out_regs.x.bx;
	*row=out_regs.x.dx/MouseMove;
	*col=out_regs.x.cx/MouseMove;
}

/**************************************************************************
**
**
**	   0 -- left
**    1 -- right
**
**
************************************************************************* */

void mouse_times_released(int mouse_button,int *num_times,int *row,int *col)

{
	union REGS in_regs,out_regs;

	in_regs.x.bx=mouse_button;
	in_regs.x.ax=6;
	int86(0x33,&in_regs,&out_regs);
	*num_times=out_regs.x.bx;
	*row=out_regs.x.dx/MouseMove;
	*col=out_regs.x.cx/MouseMove;
}

                                   