/**************************************************************************
ibmpc.c         -       Collection of text mode routines for use with
			IBM PC/XT, PC/AT, PS/2.

Programmer      -       Edward James Pugh, FIAP.

Copyright	-	(C) Edward James Pugh, 12-Jan-1990.
***************************************************************************/

#include <stdio.h>
#include <malloc.h>
#include <dos.h>
#include "ibmpc.h"

/* define useful macros */
#define CHKLINE(x)      ((x >= 0) && (x <= *ROWS))
#define CHKCOL(x)	((x >= 0) && (x <= (unsigned char)VIDEO->COLUMNS ))
#define COLSEG40	((VID40) ((0xb800L << 16) + (VIDEO->PAGEOFFSET)))
#define COLSEG80	((VID80) ((0xb800L << 16) + (VIDEO->PAGEOFFSET)))
#define MONOSEG         ((VID80) ((0xb000L << 16) + (VIDEO->PAGEOFFSET)))
#define MONOMODE        (VIDEO->VIDEOMODE == 7)
#define COL40MODE	((VIDEO->VIDEOMODE == 0) || (VIDEO->VIDEOMODE == 1))
#define BIOS_SEG	(0x0040L << 16)
#define INSERTON(s)     (s & 128)
#define ALTHELD(s)      (s & 8)
#define CTRLHELD(s)     (s & 4)
#define LSHIFTHELD(s)   (s & 2)
#define RSHIFTHELD(s)   (s & 1)
#define SHIFTHELD(s)    ((LSHIFTHELD(s)) || (RSHIFTHELD(s)))
#define REV_ATTRIB(x)   ( (x & 0x00FF)|((x & 0x7000)>>4)|((x & 0x0700)<<4) \
|(x & 0x8800) )

typedef unsigned (_far *VID80)[80];
typedef unsigned (_far *VID40)[40];

#pragma pack(1)

typedef struct
	{
	unsigned char   VIDEOMODE;
	unsigned int    COLUMNS;
	unsigned int    SCREENBYTES;
	unsigned int    PAGEOFFSET;
	Curs_t          CURSOR[8];
	unsigned char   ESCAN, SSCAN;
	unsigned char   CURRENTPAGE;
	} video_t;

#pragma pack()

/* declare extern globals */

int MOUSE_SUPPORTED = 0; /* default */
unsigned char SW_BUTTON = 0x07;    // switch button character
unsigned char CW_ICON = '\011';  // close window icon character

Border_t D_BORDER = /* default values */
	{
	0xc9, 0xbb, 0xc8, 0xbc, 0xcd, 0xba, 0xcc, 0xb9, NORMAL
	};

Border_t S_BORDER = /* default values */
	{
	0xda, 0xbf, 0xc0, 0xd9, 0xc4, 0xb3, 0xc3, 0xb4, NORMAL
	};

Screen_t HOST_SCREEN; /* containing maximum screen coordinates */

unsigned SCREEN_MASK = 0xFFFF; /* default */
unsigned ACTIVE_MASK = 0x0800; /* default */

/* declare static variables */
static video_t _far       *VIDEO = ((video_t _far *)(BIOS_SEG + 0x0049));
static unsigned char _far  *ROWS = (unsigned char _far *)(BIOS_SEG + 0x0084);
static unsigned char     CSTART = 6, CEND = 7; /* default cursor
					      characteristics (small) */
static unsigned char DEFAULT_VIDEO_MODE = 0xFF;
static unsigned int STATUS;

/* function prototypes */
static unsigned int GetEquipList(void);
static int ReadChar(unsigned char *attrib);
static unsigned char ResCType(void);
static void SaveCType(void);

/**************************************************************************
InitUI          -       Initialize User Interface

Description     -       Determines the type of video monitor in
			use via GetMonitor(), sets the HOST_SCREEN
			values for use by other modules and sets the
			best video mode.  Ascertains if mouse is
			present, sets MOUSE_SUPPORTED and initializes
			if present.

Parameters      -       InitUI()

Returns         -       NOTHING
**************************************************************************/
int InitUI(int mode)
{
unsigned list;
int ret;

SaveCType();
/* we establish the type of monitor in use by looking at the
equipment's start up video mode */
list = GetEquipList();
list &= 48;
list >>= 4;

if(list == 3) // monochrome mode is start up mode
	{
	SetVidMode(0x07); /* WHITE on BLACK */
	ret = 0x07;
	}
else
	// COLOUR40 == 1 COLOUR80 == 2
	{
	if(mode == 0x07)
		{
		SetVidMode(0x02); // colour burst off
		ret = 0x02;
		}
	else if((mode > -1) && (mode < 4))
		{
		SetVidMode((unsigned char)mode);
		ret = mode;
		}
	else // mode == -1 or invalid mode
		{
		SetVidMode(0x03); /* TEXTCOL80 */
		ret = 0x03;
		}
	}
HOST_SCREEN.TRow = HOST_SCREEN.TCol = (unsigned char)0;
HOST_SCREEN.BCol = (unsigned char)((int)VIDEO->COLUMNS - 1);
HOST_SCREEN.BRow = *ROWS;
if(MOUSE_SUPPORTED = InitMouse())
	{
	SetMouseTCurs(0 /*mode */, 0xFFFF /* & */, 0x7700 /* ^ */);
	ShowMouse();
	}
CursOff();
return(ret);
}

/**************************************************************************
GetEquipList    -       Get Equipment List

Description     -       Gets the word code for identifying hardware set up

Parameters      -       GetEquipList(void)

Returns         -       An unsigned int word for interpretation

    &            BIT            Meaning
    ------------------------------------------------------------------------
    1      ...............x     Floppy disk(s) supported
    2      ..............x.     Math Co Processor installed (except PC)
    4      .............x..     PS/2 pointing device installed
   12      ............xx..     System Board RAM for in 16K blocks (64K)
   48      ..........xx....     Initial Video Mode
	   ..........00....     Reserved
	   ..........01....     COLOUR40
	   ..........10....     COLOUR80
	   ..........11....     MONOCHROME
  192      ........xx......     Number of floppy disks - 1
  256      .......x........     0 if DMA chip installed
 3584      ....xxx.........     Number of RS232 ports installed
 4096      ...x............     Game Adaptor installed if 1
 8192      ..x.............     Internal Modem installed if 1
49152      xx..............     Number of printers installed
**************************************************************************/
static unsigned int GetEquipList(void)
{
unsigned int equiplist;

DEFAULT_VIDEO_MODE = VIDEO->VIDEOMODE;
_asm
	{
	int 11h
	mov equiplist, ax
	}
return(equiplist);
}

/*************************************************************************
LeaveUI         -       Leave User Interface

Description     -       Kills all remaining windows and hides the
			mouse if it was present. Resets video mode
			to default.

Parameters      -       LeaveUI();

Returns         -       NOTHING
**************************************************************************/
void LeaveUI(void)
{
if(MOUSE_SUPPORTED)
	HideMouse();
KillAllWindows();
SetVidMode(DEFAULT_VIDEO_MODE);
ResCType();
}

/**************************************************************************
PosnCurs	-	Position Cursor.

Description	-	Positions text cursor at the specified row, col,
			page co-ordinates using current page.

Parameters	-	PosnCurs(row, col,)
			unsigned char  row, col; required coordinates.

Returns 	-	NOTHING.
***************************************************************************/
void	PosnCurs(unsigned char row, unsigned char col)
{
union REGS	inreg, outreg;

inreg.h.ah = 2; /* interrupt 16 function #2 */
inreg.h.dh = row;
inreg.h.dl = col;
inreg.h.bh = VIDEO->CURRENTPAGE;
int86(0x10, &inreg, &outreg);
}

/**************************************************************************
GetCurs 	-	Get Cursor.

Description	-	Obtains the current cursor position setting the
			row and col parameters as appropriate.

Parameters	-	GetCurs(row, col)
			unsigned char *row, *col; where row and col
						  are used to hold
						  information required.

Returns 	-	NOTHING.
***************************************************************************/
void	GetCurs(unsigned char *row, unsigned char *col)
{
union REGS	inreg, outreg;

inreg.h.ah = 3; /* interrupt 16 function #3 */
inreg.h.bh = VIDEO->CURRENTPAGE;
int86(0x10, &inreg, &outreg);
*row = outreg.h.dh;
*col = outreg.h.dl;
}

/**************************************************************************
CursorType	-	Get Cursor Type.

Description	-	Sets the start and end parameters to the current
			cursor scan values.

Parameters	-	CursorType(start, end)
			unsigned char *start, *end; variable pointers for
						    assignment.

Returns 	-	NOTHING.
***************************************************************************/
void	CursorType(unsigned char *start, unsigned char *end)
{
*start = VIDEO->SSCAN;
*end = VIDEO->ESCAN;
}

/**************************************************************************
ScrollScreen    -       Scroll Screen.

Description     -       Used by Scr... and ClearScreen macros.

Parameters      -       ScrollScreen(interrupt, lines, TLine, TCol, BLine,
					BCol)
			unsigned char interrupt; number
			unsigned char lines; to scroll
			unsigned char TLine, TCol, BLine, BCol; coords
			unsigned char attrib;

Returns 	-	NOTHING.
***************************************************************************/
void ScrollScreen(unsigned char inter, unsigned char lines,
	unsigned char TRow, unsigned char TCol, unsigned char
	BRow, unsigned char BCol, unsigned char attrib)
{
if(MOUSE_SUPPORTED)
	HideMouse();
_asm
	{
	mov ah, inter
	mov al, lines
	mov bh, attrib
	mov ch, TRow
	mov cl, TCol
	mov dh, BRow
	mov dl, BCol
	int 10h
	}
if(MOUSE_SUPPORTED)
	ShowMouse();
}

/**************************************************************************
SetCurs 	-	Set Cursor.

Description	-	Sets the starting and ending lines for the blinking
			hardware cursor in text displays.

Parameters	-	SetCurs(SLine, ELine)
			unsigned char SLine, ELine; starting and ending
						    lines.

Returns 	-	NOTHING.
***************************************************************************/
void	 SetCurs(unsigned char SLine, unsigned char ELine)
{
_asm
	{
	mov ah, 1
	mov ch, SLine
	mov cl, ELine
	int 10h
	}
}

/**************************************************************************
ReadChar	-	Read Character.

Description	-	Reads the character at the current cursor position.

Parameters	-	ReadChar(attrib)
			unsigned char * attrib; pointer to variable to
						hold characters attribute.
						NULL if not required.

Returns 	-	The character read as an int.
***************************************************************************/
static int ReadChar(unsigned char *attrib)
{
union REGS	inregs, outregs;

if(MOUSE_SUPPORTED)
	HideMouse();
inregs.h.ah = 8; /* interrupt function # */
inregs.h.bh = VIDEO->CURRENTPAGE;
int86(0x10, &inregs, &outregs);
if(attrib != NULL)
	*attrib = outregs.h.ah;
if(MOUSE_SUPPORTED)
	ShowMouse();
return((int)outregs.h.al);
}

/***************************************************************************
PutChar 	-	Put Character

Description	-	Writes a character and its specified attribute
			at the current cursor position.

Parameters	-	PutChar(ch, attrib)
			unsigned char ch, attrib; the character and
						  attribute required.

Returns 	-	NOTHING.
***************************************************************************/
void	 PutChar(unsigned char ch, unsigned char attrib)
{
union REGS	inregs, outregs;

if(MOUSE_SUPPORTED)
	HideMouse();
inregs.h.ah = 9; /* interrupt function # */
inregs.h.al = ch;
inregs.h.bh = VIDEO->CURRENTPAGE;
inregs.h.bl = attrib;
inregs.x.cx = 1;
int86(0x10, &inregs, &outregs);
if(MOUSE_SUPPORTED)
	ShowMouse();
}

/**************************************************************************
SaveCType	-	Save Cursor Type.

Description	-	Saves the characteristics of the current cursor
			by using the static CSTART and CEND variables.

Parameters	-	SaveCType()

Returns 	-	NOTHING.
**************************************************************************/
static void SaveCType(void)
{
CursorType(&CSTART, &CEND);
}

/***************************************************************************
ResCType	-	Restore Cursor Type.

Description	-	Restores the saved cursor type.

Parameters	-	ResCType()

Returns 	-	The value of CSTART.  (32 represents a hidden
			cursor, 6 a small cursor and 1 a large cursor).
***************************************************************************/
static unsigned char ResCType(void)
{
SetCurs(CSTART, CEND);
return(CSTART);
}

/**************************************************************************
SaveScreen      -       Save Screen

Description     -       Saves the given screen area to memory.

Parameters      -       SaveScreen(TRow, TCol, BRow, BCol)
			unsigned char TRow, TCol, BRow, BCol; coords

Returns 	-	An unsigned int pointer to the beginning of the
			allocated array.
***************************************************************************/
unsigned int    *SaveScreen(unsigned char TRow, unsigned char TCol,
			unsigned char BRow, unsigned char BCol)
{
VID80		scr80;
VID40		scr40;
unsigned char   col, row;
unsigned        *store, *loc;
size_t          size;

/* create the required storage space */
size = (size_t)((BRow - TRow + 1) * (BCol - TCol + 1));
if(store = (unsigned int *)malloc(size * sizeof(unsigned int)))
	{
	loc = store;
	if(MONOMODE)
		scr80 = MONOSEG;
	else
		if(COL40MODE)
			scr40 = COLSEG40;
		else
			scr80 = COLSEG80;
	if(MOUSE_SUPPORTED)
		HideMouse();
	for(row = TRow; row <= BRow; row ++)
		for(col = TCol; col <= BCol; col ++)
			if(COL40MODE)
				*loc ++ = scr40[row][col];
			else
				*loc ++ = scr80[row][col];
	if(MOUSE_SUPPORTED)
		ShowMouse();
	return(store);
	}
return(NULL);
}

/**************************************************************************
PutArea         -       Put Area

Description	-	Puts a previously saved screen window area to the
			specified window coordinates.

Parameters	-	PutArea(TRow, TCol, BRow, BCol, store)
			unsigned char TRow, TCol, BRow, BCol; coords
			const unsigned int *store; screen data location

Returns 	-	The store parameter as an unsigned int pointer.
***************************************************************************/
unsigned int	*PutArea(unsigned char TRow, unsigned char TCol,
			 unsigned char BRow, unsigned char BCol,
			 unsigned int *store)
{
VID80		scr80;
VID40		scr40;
unsigned char   col, row;
unsigned int    *loc;

if(store)
	{
	loc = store;
	if(MONOMODE)
		scr80 = MONOSEG;
	else
		if(COL40MODE)
			scr40 = COLSEG40;
		else
			scr80 = COLSEG80;
	if(MOUSE_SUPPORTED)
		HideMouse();
	for(row = TRow; row <= BRow; row ++)
		for(col = TCol; col <= BCol; col ++)
			if(COL40MODE)
				scr40[row][col] = *loc ++;
			else
				scr80[row][col] = *loc ++;
	if(MOUSE_SUPPORTED)
		ShowMouse();
	}
return(store);
}

/**************************************************************************
SmallCurs	-	Small Cursor.

Description	-	Sets blinking cursor to bottom of character area.

Parameters	-	SmallCurs()

Returns 	-	NOTHING.
**************************************************************************/
void	SmallCurs(void)
{
if(MONOMODE)
	SetCurs(11, 12);
else
	SetCurs(6, 7);
}

/**************************************************************************
LargeCurs	-	Large Cursor.

Description	-	Sets blinking cursor to highlight all of the char
			area.

Parameters	-	LargeCurs()

Returns 	-	NOTHING.
***************************************************************************/
void	LargeCurs(void)
{
if(MONOMODE)
	SetCurs(1, 12);
else
	SetCurs(1, 7);
}

/***************************************************************************
CursOff 	-	Cursor Off.

Description	-	Turns the text cursor off.

Parameters	-	CursOff()

Returns 	-	NOTHING.
***************************************************************************/
void		CursOff(void)
{
SetCurs(32,7);
}

/***************************************************************************
PCKey		-	PC Key

Description	-	Reads a character from the AT / normal PC keyboard
			returning its ascii code and scan code.

Parameters	-	PCKey(scan, ascii)
			unsigned char *scan, *ascii;

Returns         -       TRUE if character is extended, else FALSE.
****************************************************************************/
BOOLEAN PCKey(unsigned char *scan, unsigned char *ascii)
{
unsigned char s, a;

_asm
	{
	mov ah, 0
	int 16h
	mov s, ah
	mov a, al
	}
*scan = s;
*ascii = a;
STATUS = KBStatus();
if( (a == 0x00) || (a == 0xe0) )
	return(TRUE);
return(FALSE);
}

/*************************************************************************
SysYear         -       System Year.

Description     -       Gets the current system year held by DOS.

Parameters      -       SysYear()

Returns         -       The year in the form of an int.
**************************************************************************/
int SysYear(void)
{
union REGS inregs, outregs;

inregs.h.ah = 42;
/* interrupt function # */
int86(0x21, &inregs, &outregs);
return((int)outregs.x.cx);
}

/**************************************************************************
SysMonth        -       System Month.

Description     -       Gets the system month as held by DOS.

Parameters      -       SysMonth()

Returns         -       The system month in the form of an integer.
***************************************************************************/
int SysMonth(void)
{
union REGS inregs, outregs;

inregs.h.ah = 42;
/* interrupt function # */
int86(0x21, &inregs, &outregs);
return((int)outregs.h.dh);
}

/**************************************************************************
SysDay          -       System Day.

Description     -       Gets the system day as held by DOS.

Parameters      -       SysDay()

Returns         -       The day number in the form of an int.
***************************************************************************/
int SysDay(void)
{
union REGS inregs, outregs;

inregs.h.ah = 42;
/* interrupt function # */
int86(0x21, &inregs, &outregs);
return((int)outregs.h.dl);
}

/**************************************************************************
KBStatus        -       Key Board Status

Description     -       Obtains details of the current keyboard
			status using int 16H service 02H.

	      128 64 32 16  8  4  2  1

	Bit     7  6  5  4  3  2  1  0
		x  .  .  .  .  .  .  .  Insert State
		.  x  .  .  .  .  .  .  Caps Lock State
		.  .  x  .  .  .  .  .  Number Lock State
		.  .  .  x  .  .  .  .  Scroll Lock State
		.  .  .  .  x  .  .  .  Alt pressed
		.  .  .  .  .  x  .  .  Ctrl pressed
		.  .  .  .  .  .  x  .  Left Shift Pressed
		.  .  .  .  .  .  .  x  Right Shift Pressed

Parameters      -       KBStatus(void)

Returns         -       The resulting AL register byte for evaluation
***************************************************************************/
unsigned int KBStatus(void)
{
unsigned char value;
_asm
	{
	mov ah, 2
	int 16h
	mov value, al
	}
return((unsigned int)value);
}

/**************************************************************************
ExtCharClass    -       Extended Character Class

Description     -       Returns the character's class and adjusts
			the supplied char for classing to its ASCII
			component or function key number.

Parameters      -       ExtCharClass(ch)
			unsigned char *ch; for classing

Returns         -       The character's class from the ExtClass_s
***************************************************************************/
unsigned int ExtCharClass(unsigned char *ch)
{
unsigned int class = 0;

if(SHIFTHELD(STATUS))
	class |= 1; /* turn on bit 1 */
if(CTRLHELD(STATUS))
	class |= 2; /* turn bit 2 on */
if(ALTHELD(STATUS))
	class |= 4; /* turn bit 3 on */

/* now deal with the character value */
/* VIRGINs */
if((*ch > (unsigned char) 58) && (*ch < (unsigned char) 69))
	*ch -= (unsigned char) 42; /* F1..F10 */
else if((*ch > (unsigned char) 132) && (*ch < (unsigned char) 135))
	*ch -= (unsigned char) 116; /* F11..F12 */
/* SHIFT_EXT */
else if((*ch > (unsigned char) 83) && (*ch < (unsigned char) 94))
	*ch -= (unsigned char) 67; /* Shift F1.. Shift F10 */
else if((*ch > (unsigned char) 134) && (*ch < (unsigned char) 137))
	*ch -= (unsigned char) 118; /* Shift F11..Shift F12 */
/* CTRL_EXT */
else if((*ch > (unsigned char) 93) && (*ch < (unsigned char) 104))
	*ch -= (unsigned char) 77; /* Ctrl F1.. Ctrl F10 */
else if((*ch > (unsigned char) 136) && (*ch < (unsigned char) 139))
	*ch -= (unsigned char) 120; /* Ctrl F11..Ctrl F12 */
/* ALT_EXT */
else if((*ch > (unsigned char) 103) && (*ch < (unsigned char) 114))
	*ch -= (unsigned char) 87; /* Alt F1..Alt F10 */
else if((*ch > (unsigned char) 138) && (*ch < (unsigned char) 141))
	*ch -= (unsigned char) 122; /* Alt F11..Alt F12 */
else if((*ch > (unsigned char) 119) && (*ch < (unsigned char) 132))
	{
	unsigned char *line = "1234567890-=";

	*ch = line[*ch - 120]; /* Alt 1..Alt = */
	}
else if((*ch > (unsigned char) 15) && (*ch < (unsigned char) 26))
	{
	unsigned char *line = "QWERTYUIOP";

	*ch = line[*ch - 16]; /* Alt Q..Alt P */
	}
else if((*ch > (unsigned char) 29) && (*ch < (unsigned char) 39))
	{
	unsigned char *line = "ASDFGHJKL";

	*ch = line[*ch - 30]; /* Alt A.. Alt L */
	}
else if((*ch > (unsigned char) 43) && (*ch < (unsigned char) 51))
	{
	unsigned char *line = "ZXCVBNM";

	*ch = line[*ch - 44]; /* Alt Z..Alt M */
	}
/* so handle direction keys */
else
	{
	class = GREY_KEY;

	if(*ch == (unsigned char) 15)
		*ch = (unsigned char)SHIFT_TAB;
	else if((*ch > (unsigned char) 70) && (*ch < (unsigned char) 74))
		*ch -= (unsigned char) 70; /* HOME..PGUP == 3 */
	else if(*ch == (unsigned char) 75)
		*ch = (unsigned char)LEFT;
	else if(*ch == (unsigned char) 77)
		*ch = (unsigned char)RIGHT;
	else if(*ch == (unsigned char) 79)
		*ch = (unsigned char)END;
	else if((*ch > (unsigned char) 79) && (*ch < (unsigned char) 84))
		*ch = (unsigned char)(*ch - 80 + DOWN);
	else if((*ch > (unsigned char) 113) && (*ch < (unsigned char) 120))
		*ch = (unsigned char)(*ch - 114 + CTRL_PRTSCRN);
	else if(*ch == (unsigned char) 132)
		*ch = (unsigned char)CTRL_PGUP;
	else /* unknown value */
	     class = FAULT;
	}
return(class);
}

/**************************************************************************
InsertOn        -       Insert On

Description     -       Tests the current insert status

Parameters      -       InsertOn()

Returns         -       TRUE if insert is on, else FALSE
**************************************************************************/
BOOLEAN InsertOn(void)
{
unsigned int status;

status = KBStatus();
if(INSERTON(status))
	return(TRUE);
return(FALSE);
}

/*************************************************************************
TransFMickeys   -       Translate From Mickeys

Description     -       Translates mouse mickey co-ordinates into
			screen co-ords depending on the current
			video mode setting

Parameters      -       TransFMickeys(row, col)
			unsigned int *row, *col; mickey co-ords

Returns         -       NOTHING
**************************************************************************/
void TransFMickeys(unsigned int *dx, unsigned int *cx)
{
switch(VIDEO->VIDEOMODE)
	{
	case 0:
	case 1:
		{
		*cx >>= 4; /* div 16 */
		*dx >>= 3; /* div 8 */
		}
	break;
	case 2:
	case 3:
	case 7:
		{
		*cx >>= 3; /* div 8 */
		*dx >>= 3; /* div 8 */
		}
	break;
	case 4:
	case 5:
		{
		*cx >>= 1; /* div 2 */
		}
	break;
	case 6: /* no change necessary */
	case 14:
	case 15:
	case 16:
	default:
	break;
	}
}

/**************************************************************************
TransTMickeys   -       Translate to mickeys

Description     -       Translates the supplied screen
			co-ordinates to Mickeys

Parameters      -       TransTMickeys(row, col)
			unsigned *row, *col;

Returns         -       NOTHING
***************************************************************************/
void TransTMickeys(unsigned *row, unsigned *col)
{
switch(VIDEO->VIDEOMODE)
	{
	case 0:
	case 1:
		{
		*col <<= 4; /* mult 16 */
		*row <<= 3; /* mult 8 */
		}
	break;
	case 2:
	case 3:
	case 7:
		{
		*col <<= 3; /* mult 8 */
		*row <<= 3; /* mult 8 */
		}
	break;
	case 4:
	case 5:
		{
		*col <<= 1; /* mult 2 */
		}
	break;
	case 6: /* no change necessary */
	case 14:
	case 15:
	case 16:
	default:
	break;
	}
}

/**************************************************************************
PutAttrib       -       Put Attribute

Description     -       Changes the screen attributes in the specified
			block by ANDing with mask1 and XORing with
			mask2.

			A further call to this function with the same
			parameters therefore restores the original
			attributes.

Parameters      -       PutAttrib(TRow, TCol, BRow, BCol, mask1, mask2)
			unsigned char TRow, TCol, BRow, BCol; coords
			unsigned int mask1, mask2; required

Returns         -       NOTHING
***************************************************************************/
void PutAttrib(unsigned char TRow, unsigned char TCol, unsigned char BRow,
		unsigned char BCol, unsigned int mask1, unsigned int mask2)
{
VID80           scr80;
VID40           scr40;
unsigned char   col, row;

if(MONOMODE)
	scr80 = MONOSEG;
else
	if(COL40MODE)
		scr40 = COLSEG40;
	else
		scr80 = COLSEG80;
if(MOUSE_SUPPORTED)
	HideMouse();
for(row = TRow; row <= BRow; row ++)
	for(col = TCol; col <= BCol; col ++)
		if(COL40MODE)
		    scr40[row][col] = ANDXOR(scr40[row][col], mask1, mask2);
		else
		    scr80[row][col] = ANDXOR(scr80[row][col], mask1, mask2);
if(MOUSE_SUPPORTED)
	ShowMouse();
}

/*************************************************************************
RevScrBlock     -       Reverse Screen Block

Description     -       Reverses the attributes of the given screen
			area.

Parameters      -       RevScrBlock(TRow, TCol, BRow, BCol)
			unsigned char TRow, TCol, BRow, BCol; coords

Returns         -       NOTHING
**************************************************************************/
void RevScrBlock(unsigned char TRow, unsigned char TCol, unsigned char BRow,
		unsigned char BCol)
{
VID80           scr80;
VID40           scr40;
unsigned char   col, row;

if(MONOMODE)
	scr80 = MONOSEG;
else
	if(COL40MODE)
		scr40 = COLSEG40;
	else
		scr80 = COLSEG80;
if(MOUSE_SUPPORTED)
	HideMouse();
for(row = TRow; row <= BRow; row ++)
	for(col = TCol; col <= BCol; col ++)
		if(COL40MODE)
		    scr40[row][col] = REV_ATTRIB(scr40[row][col]);
		else
		    scr80[row][col] = REV_ATTRIB(scr80[row][col]);
if(MOUSE_SUPPORTED)
	ShowMouse();
}

/*************************************************************************
FlipArea        -       Flip Area

Description     -       Flips the area attributes to make it appear
			inactive if active, and active if inactive.

Parameters      -       FlipTitle(area)
			Screen_t *area

Returns         -       NOTHING
**************************************************************************/
void FlipArea(Screen_t *area)
{
PutAttrib(area->TRow, area->TCol, area->BRow, area->BCol,
	SCREEN_MASK, ACTIVE_MASK);
}

/*************************************************************************
ShowGhostW      -       Show Ghost Window

Description     -       Puts the supplied area into video reverse.

Parameters      -       ShowGhostW(bounds)
			Screen_t *bounds;

Returns         -       NOTHING
**************************************************************************/
void ShowGhostW(Screen_t *bounds)
{
RevScrBlock(bounds->TRow, bounds->TCol, bounds->BRow, bounds->BCol);
}

/**************************************************************************
ShowLine        -       Show Line

Description     -       Reverses the video attributes in the supplied
			line.

			A second call to this function with the same
			parameters puts the original attribute back.

Parameters      -       ShowLine(window, line)
			Window_t *window;
			int line; 0 is first in window

Returns         -       NOTHING
***************************************************************************/
void ShowLine(Window_t *window, int line)
{
unsigned char tline;

tline = (unsigned char)(window->Bounds.TRow + line);
RevScrBlock(tline, window->Bounds.TCol, tline, window->Bounds.BCol);
}

/*************************************************************************
ShowSBChar      -       Show Switch Box Character

Description     -       Changes the character within the switch
			brackets or check box square brackets
			to the character given

Parameters      -       ShowSBChar(window, line, ch)
			Window_t *window;
			int line;
			char ch;

Returns         -       NOTHING
**************************************************************************/
void ShowSBChar(Window_t *window, int line, unsigned char ch)
{
unsigned char col = (unsigned char)(window->Bounds.BCol - 1);
unsigned char row = (unsigned char)(window->Bounds.TRow + line);
int store = (window->Attrib << 8) | ch;

PutArea(row, col, row, col, &store);
}

/*************************************************************************
AdjBounds       -       Adjust Boundaries

Description     -       Adjusts the supplied boundaries to a new location
			based on the supplied horizontal and vertical
			movements to take place

Parameters      -       AdjBounds(bounds, hmove, vmove)
			Screen_t *bounds;
			int hmove, vmove;

Returns         -       NOTHING
**************************************************************************/
void AdjBounds(Screen_t *bounds, int hmove, int vmove)
{
Screen_t screen = HOST_SCREEN;
Screen_t temp = *bounds;

/* adjust the host screen boundaries */
screen.TRow = 1;

/* now implement the requested moves on temp */
temp.TRow = (unsigned char)((int)temp.TRow + vmove);
temp.BRow = (unsigned char)((int)temp.BRow + vmove);
temp.TCol = (unsigned char)((int)temp.TCol + hmove);
temp.BCol = (unsigned char)((int)temp.BCol + hmove);

/* clip both temp diagonals in relation to screen */
if(B1inB2(&temp, &screen))
	/* ok to incorporate the move */
	*bounds = temp;
}

/**************************************************************************
ExpBounds       -       Expand Boundaries

Description     -       Expands the supplied boundaries to include
			the supplied movements

Parameters      -       ExpBounds(bounds, min, hmove, vmove, loc)
			Screen_t *bounds;
			Screen_t *min;
			int hmove, vmove;
			int loc; location at which expansion takes place

				1 == top left
				2 == top right
				3 == bottom left
				4 == bottom right

Returns         -       NOTHING
***************************************************************************/
void ExpBounds(Screen_t *bounds, Screen_t *min, int hmove, int vmove, int loc)
{
Screen_t temp = *bounds;
Screen_t new = *bounds;

/* adjust temp to its maximum height and adjust new to incorporate
the required moves */
switch(loc)
	{
	case 1: // top left
		{
		new.TRow = (unsigned char)((int)new.TRow + vmove);
		new.TCol = (unsigned char)((int)new.TCol + hmove);
		temp.TRow = 1;
		temp.TCol = 0;
		}
	break;
	case 2: // top right
		{
		new.TRow = (unsigned char)((int)new.TRow + vmove);
		new.BCol = (unsigned char)((int)new.BCol + hmove);
		temp.TRow = 1;
		temp.BCol = (unsigned char)(VIDEO->COLUMNS - 1);
		}
	break;
	case 3: // bottom left
		{
		new.BRow = (unsigned char)((int)new.BRow + vmove);
		new.TCol = (unsigned char)((int)new.TCol + hmove);
		temp.BRow = (unsigned char)*ROWS;
		temp.TCol = 0;
		}
	break;
	case 4: // bottom right
		{
		new.BRow = (unsigned char)((int)new.BRow + vmove);
		new.BCol = (unsigned char)((int)new.BCol + hmove);
		temp.BRow = (unsigned char)*ROWS;
		temp.BCol = (unsigned char)(VIDEO->COLUMNS - 1);
		}
	break;
	}
/* are the new boundaries fully contained in temp ? */
/* and are the min boundaries fully contained in the new ? */
if(B1inB2(&new, &temp) && B1inB2(min, &new))
	*bounds = new;
}

/*************************************************************************
BestSizingPosn  -       Best Sizing Position

Description     -       Locates the best postion for undertaking
			window sizing based on the current boundary positions
			provided.

Parameters      -       BestSizingPosn(window, row, col)
			Window_t *window;
			int *row, *col;

Returns         -       An int representing a location number

			1 == top left
			2 == top right
			3 == bottom left
			4 == bottom right

			top left is chosen as default if no other
			location betters it.
**************************************************************************/
int BestSizingPosn(Window_t *window, int *row, int *col)
{
int moves[4], n, best = 4;

/* assign available areas */
moves[0] = (int)( (window->MinBounds.TRow - 1) * window->MinBounds.TCol );
moves[1] = (int)( (window->MinBounds.TRow - 1) *
		  ((VIDEO->COLUMNS - 1) - window->MinBounds.BCol) );
moves[2] = (int)( (*ROWS - window->MinBounds.BRow) * window->MinBounds.TCol );
moves[3] = (int)( (*ROWS - window->MinBounds.BRow) *
		  ((VIDEO->COLUMNS - 1) - window->MinBounds.BCol) );
for(best = n = 0; n < 4; n++)
	{
	if(moves[n] > moves[best])
		best = n;
	}
++best;
if(window->Border)
	IncBounds(&window->Bounds);
switch(best)
	{
	case 1:
		{
		*row = window->Bounds.TRow;
		*col = window->Bounds.TCol;
		}
	break;
	case 2:
		{
		*row = window->Bounds.TRow;
		*col = window->Bounds.BCol;
		}
	break;
	case 3:
		{
		*row = window->Bounds.BRow;
		*col = window->Bounds.TCol;
		}
	break;
	case 4:
		{
		*row = window->Bounds.BRow;
		*col = window->Bounds.BCol;
		}
	break;
	}
if(window->Border)
	DecBounds(&window->Bounds);
return(best);
}

/***************************************************************************
InitMouse        -      Initialize mouse

Description      -      Checks that a mouse is installed and resets it
			if present.  Sets cursor visible in centre of
			screen.

Parameters      -       InitMouse()

Returns         -       0 if mouse not present, else number of buttons
			supported
***************************************************************************/
int InitMouse(void)
{
union REGS      inregs, outregs;

inregs.x.ax = 0; /* interrupt function #0 */
int86(0x33, &inregs, &outregs);
if(outregs.x.ax)
	return(outregs.x.bx);
else
	return(0);
}

/**************************************************************************
ShowMouse       -       Show Mouse Cursor

Description     -       Displays the mouse cursor

Parameters      -       ShowMouse()

Returns         -       NOTHING
**************************************************************************/

void ShowMouse(void)
{
union REGS      inregs, outregs;

inregs.x.ax = 1; /* interrupt function #1 */
int86(0x33, &inregs, &outregs);
}

/**************************************************************************
HideMouse       -       Hide mouse cursor

Description     -       Hides the mouse cursor

Parameters      -       HideMouse()

Returns         -       NOTHING
**************************************************************************/

void HideMouse(void)
{
union REGS      inregs, outregs;

inregs.x.ax = 2; /* interrrupt function #2 */
int86(0x33, &inregs, &outregs);
}

/**************************************************************************
GetMPosn        -       Get mouse position

Description     -       Gets the mouse position and button status

Parameters      -       GetMPosn(row, col)
			unsigned int *row, *col; coords

Returns         -       The result of the bx reg; 1 == LEFT, 2 == RIGHT,
			4 == MIDDLE; and combinations.
**************************************************************************/
int GetMPosn(unsigned int *row, unsigned int *col)
{
union REGS inregs, outregs;

inregs.x.ax = 3; /* interrupt function #3 */
int86(0x33, &inregs, &outregs);
*col = outregs.x.cx;
*row = outregs.x.dx;
TransFMickeys(row, col);
return(outregs.x.bx);
}

/**************************************************************************
PutMouse        -       Put Mouse Cursor

Description     -       Puts the mouse cursor at position given

Parameters      -       PutMouse(x, y)
			unsigned int x, y; coords

Returns         -       NOTHING
**************************************************************************/
void PutMouse(unsigned row, unsigned col)
{
union REGS inregs, outregs;

TransTMickeys(&row, &col);
inregs.x.ax = 4; /* interrupt function #4 */
inregs.x.cx = col;
inregs.x.dx = row;
int86(0x33, &inregs, &outregs);
}

/**************************************************************************
GetMPress       -       Get Mouse Press

Description     -       Obtains mouse button press information

Parameters      -       GetMPress(button, row, col, status)
			unsigned int button; required
			unsigned int *row, *col; coords
			unsigned *status;

Returns         -       The number of Button presses
**************************************************************************/
int GetMPress(unsigned button,
	unsigned *row, unsigned *col, unsigned *status)
{
union REGS      inregs, outregs;

inregs.x.ax = 5; /* interrupt function #5 */
inregs.x.bx = button;
int86(0x33, &inregs, &outregs);
*col = outregs.x.cx;
*row = outregs.x.dx;
TransFMickeys(row, col);
*status = outregs.x.ax;
return(outregs.x.bx);
}

/**************************************************************************
SetMouseTCurs   -       Set Mouse Text Cursor

Description     -       Sets the required mouse cursor type in text mode.
			Two types of cursor are supported in text mode
			- the normal hardware cursor via the video
			controller and software. If the hardware option
			is selected then the first and last scan lines
			of the cursor need to be defined. This is hardware
			dependant, but for IBM monochrome it is 0 and 7,
			for CGA 0 and 14 etc. The software cursor is
			controlled by two 16 bit values - the screen mask
			which determines which of the current attributes
			are retained (AND function) and the cursor mask
			which determines which characteristics are to be
			modified (XOR function). The format for both is
			as follows:-

				Bit 15  -  1==blinking; 0==non-blinking
				14-12   -  background colour
				11      -  1==high intensity; 0==normal
				10-8    -  foreground colour
				7-0     -  ASCII character code

Parameters      -       SetMouseTCurs(type, CX, DX)
			unsigned int type; 1== hardware, 0==software
			MText_t CX; screen mask or scan line start
			MText_t DX; cursor mask or scan line finish

Returns         -       NOTHING
**************************************************************************/
void SetMouseTCurs(unsigned int type, unsigned int CX, unsigned int DX)
{
union REGS      inregs, outregs;

inregs.x.ax = 10; /* interrupt function #10 */
inregs.x.bx = type;
inregs.x.cx = CX;
inregs.x.dx = DX;
int86(0x33, &inregs, &outregs);
}


/*************************************************************************
SetVidMode      -       Set Video Mode

Description     -       Sets the IBMPC video mode

Parameters      -       SetVidMode(mode)
			unsigned char mode;

Returns         -       NOTHING
**************************************************************************/
void SetVidMode(unsigned char mode)
{
_asm
	{
	mov     ah, 00h
	mov     al, mode
	int 10h
	}
}

/**************************************************************************
GetVidMode      -       Get Video Mode

Description     -       Gets the current video mode setting

Parameters      -       GetVidMode()

Returns         -       The mode as an unsigned char
***************************************************************************/
unsigned char GetVidMode(void)
{
return(VIDEO->VIDEOMODE);
}

/*************************************************************************
ResVidMode      -       Restore Video Mode

Description     -       Restores the original video mode

Parameters      -       ResVidMode()

Returns         -       NOTHING
**************************************************************************/
void ResVidMode(void)
{
SetVidMode(DEFAULT_VIDEO_MODE);
}

/**************************************************************************
ValidAttrib     -       Validate Attribute

Description     -       Validates the passed attribute for consistancy
			with the in use

Parameters      -       ValidAttrib(attrib)
			unsigned char attrib;

Returns         -       The valid attrib setting as unsigned char
**************************************************************************/
unsigned char ValidAttrib(unsigned char attrib)
{
if(MONOMODE)
	return(NORMAL); /* white on black */
else
	return(attrib);
}
