/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by Olaf 'Olsen' Barthel & MXM
 *
 *	Name .....: Serial.c
 *	Created ..: Saturday 02-Mar-91 18:30
 *	Revision .: 0
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	02-Mar-91       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#include "termGlobal.h"

	/* RasterMarkArea(WORD Column,WORD Line,WORD Length):
	 *
	 *	Mark an area in the term Buffer window.
	 */

VOID
RasterMarkArea(WORD Column,WORD Line,WORD Length)
{
	STATIC WORD OldColumn = -1,OldLine = -1,OldLength = -1;

	if(OldColumn != Column || OldLine != Line || OldLength != Length)
	{
		if(OldColumn != -1)
			ClipBlit(RPort,0,0,RPort,OldColumn << 3,OldLine << 3,OldLength << 3,8,0x50);

		ClipBlit(RPort,0,0,RPort,Column << 3,Line << 3,Length << 3,8,0x50);
	}

	OldColumn	= Column;
	OldLine		= Line;
	OldLength	= Length;
}

	/* RasterClip():
	 *
	 *	Put a character raster portion into the clipboard.
	 */

VOID
RasterClip(BYTE SingleChar,BYTE Xerox)
{
	struct IntuiMessage	*Massage;
	ULONG			 Code,Class;
	BYTE			 SkipLoop = FALSE;
	LONG			 ThisLine,ThisColumn,MyColumn,SomeColumn;
	UBYTE			*TheLine;

		/* Remember initial mouse position. */

	ThisColumn	= Window -> MouseX >> 3;
	ThisLine	= Window -> MouseY >> 3;

	if(ThisColumn <= LastColumn && ThisLine <= LastLine)
	{
		RasterMarkArea(-1,-1,-1);

			/* Find the approriate line and its length. */

		TheLine = &Raster[RasterWidth * ThisLine];

		if(SingleChar)
		{
			if(TheLine[ThisColumn] && TheLine[ThisColumn] != ' ')
			{
				SerWrite(&TheLine[ThisColumn],1);

				if(Xerox)
				{
					switch(Config . SendCR)
					{
						case CR_IGNORE:	break;

						case CR_ASCR:	SerWrite("\r",1);
								break;

						case CR_ASCRLF:	SerWrite("\r\n",2);
								break;
					}
				}
			}

			return;
		}

			/* Resonable dimensions? */

		if(ThisColumn <= LastColumn)
		{
			MyColumn = ThisColumn;

				/* Loop until left mouse button is release. */

			while(!SkipLoop)
			{
				WaitPort(Window -> UserPort);

				while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
				{
					Class	= Massage -> Class;
					Code	= Massage -> Code;

					ReplyMsg(Massage);

						/* We're finished! */

					if(Class == IDCMP_MOUSEBUTTONS && Code == SELECTUP)
					{
						SkipLoop = TRUE;

							/* Did we get a reasonable mouse
							 * position?
							 */

						if(MyColumn != ThisColumn)
						{
								/* Preserve right order of
								 * numbers.
								 */

							if(MyColumn < ThisColumn)
							{
								LONG Help;

								Help		= ThisColumn;
								ThisColumn	= MyColumn;
								MyColumn	= Help;
							}

							RasterMarkArea(-1,-1,-1);

								/* Clip the contents of the line to
								 * the clipboard.
								 */

							SaveClip(&TheLine[ThisColumn],MyColumn - ThisColumn);

							if(Xerox)
							{
								SerWrite(&TheLine[ThisColumn],MyColumn - ThisColumn);

								switch(Config . SendCR)
								{
									case CR_IGNORE:	break;

									case CR_ASCR:	SerWrite("\r",1);
											break;

									case CR_ASCRLF:	SerWrite("\r\n",2);
											break;
								}
							}
						}

						break;
					}

						/* The mouse has moved. */

					if(Class == IDCMP_MOUSEMOVE)
					{
						STATIC LONG OldColumn = ~0;

							/* Determine new mouse position. */

						SomeColumn = MyColumn;

						MyColumn = Massage -> MouseX >> 3;

						if((Massage -> MouseY >> 3) < ThisLine)
							MyColumn = 0;

						if((Massage -> MouseY >> 3) > ThisLine)
							MyColumn = LastColumn + 1;

							/* Don't redraw the line if nothing
							 * has changed.
							 */

						if(OldColumn != MyColumn)
						{
							OldColumn = MyColumn;

								/* Reasonable position? */

							if(MyColumn <= LastColumn + 1)
							{
								if(MyColumn >= 0)
								{
										/* Highlight the selected
										 * area (invert).
										 */

									if(MyColumn != ThisColumn)
									{
										if(MyColumn < ThisColumn)
											RasterMarkArea(MyColumn,ThisLine,ThisColumn - MyColumn);
										else
											RasterMarkArea(ThisColumn,ThisLine,MyColumn - ThisColumn);
									}
								}
							}
							else
								MyColumn = SomeColumn;
						}
					}
				}
			}
		}
	}
}

	/* DeleteRaster():
	 *
	 *	Free the contents of the character raster.
	 */

VOID
DeleteRaster()
{
	if(Raster)
	{
		FreeVec(Raster);

		Raster = NULL;
	}

	if(RasterAttr)
	{
		FreeVec(RasterAttr);

		RasterAttr = NULL;
	}
}

	/* CreateRaster():
	 *
	 *	Create the character raster.
	 */

BYTE
CreateRaster()
{
		/* Width of the screen * 2 (in characters).
		 * extra for Double width
		 */

	RasterWidth	= Window -> Width >> 2;

		/* Height of the character raster. */

	RasterHeight	= Window -> Height >> 3;

		/* Allocate the raster. */

	if(!(Raster = (UBYTE *)AllocVec(RasterWidth * RasterHeight * 2,MEMF_PUBLIC|MEMF_CLEAR)))
		return(FALSE);

		/* Allocate the raster attributes. */

	if(!(RasterAttr = (UBYTE *)AllocVec(RasterHeight * 2,MEMF_PUBLIC|MEMF_CLEAR)))
	{
		FreeVec(Raster);

		Raster = NULL;

		return(FALSE);
	}

	return(TRUE);
}

	/* RasterEraseScreen(BYTE Mode):
	 *
	 *	Erase parts of the screen.
	 */

VOID
RasterEraseScreen(BYTE Mode)
{
	WORD First,Last;

	switch(Mode)
	{
		case 1:	First	= 0;
			Last	= CursorY * RasterWidth + CursorX; 
			memset(&RasterAttr[0],SCALE_NORMAL,CursorY + 1);
			break;

		case 2:	First	= 0;
			Last	= (RasterHeight + 1) * RasterWidth - 1;
			memset(&RasterAttr[0],SCALE_NORMAL,RasterHeight + 1);
			break;

		default:First	= CursorY * RasterWidth;
			Last	= (RasterHeight + 1) * RasterWidth - 1;
			memset(&RasterAttr[CursorY],SCALE_NORMAL,RasterHeight - CursorY + 1);
			break;
	}

	memset(&Raster[First],' ',Last - First);
}

	/* RasterEraseLine(BYTE Mode):
	 *
	 *	Erase parts of the current cursor line.
	 */

VOID
RasterEraseLine(BYTE Mode)
{
	WORD First,Last;

	switch(Mode)
	{
		case 1:	First	= CursorY * RasterWidth;
			Last	= First + CursorX;
			break;

		case 2:	First	= CursorY * RasterWidth;
			Last	= First + RasterWidth - 1;
			break;

		default:First	= CursorY * RasterWidth + CursorX;
			Last	= (CursorY + 1) * RasterWidth - 1;
			break;
	}

	memset(&Raster[First],' ',Last - First);
}

	/* RasterEraseCharacters(WORD Chars):
	 *
	 *	Erase a number of characters in the current cursor
	 *	line.
	 */

VOID
RasterEraseCharacters(WORD Chars)
{
	WORD i,First,Diff = RasterWidth - CursorX;
	UBYTE *FirstPtr,*LastPtr;

	First = CursorY * RasterWidth + CursorX;

	FirstPtr = &Raster[First];
	LastPtr = &Raster[First + Chars];

	i = 0;

	while(i++ < Diff)
	{
		*FirstPtr++ = *LastPtr;

		*LastPtr++ = ' ';
	}
}

	/* RasterClearLine(WORD Lines):
	 *
	 *	Clear the current line.
	 */

VOID
RasterClearLine(WORD Lines)
{
	if(CursorY + Lines >= RasterHeight)
		RasterEraseScreen(0);
	else
	{
		WORD	 Max = (RasterHeight - (CursorY + Lines)) * RasterWidth,First,Last;
		UBYTE	*From,*To;

		From	= &Raster[(CursorY + Lines)	* RasterWidth];
		To	= &Raster[ CursorY		* RasterWidth];

		while(Max--)
			*To++ = *From++;

		First	= (RasterHeight - Lines) * RasterWidth;
		Last	= (RasterHeight + 1) * RasterWidth - 1;

		memset(&RasterAttr[RasterHeight - Lines],SCALE_NORMAL,Lines);

		memset(&Raster[First],' ',Last - First);
	}
}

	/* RasterInsertLine(WORD Lines):
	 *
	 *	Insert a number of lines at the current cursor line.
	 */

VOID
RasterInsertLine(WORD Lines)
{
	if(CursorY + Lines > RasterHeight)
		RasterEraseScreen(0);
	else
	{
		WORD	 From,To,
			 Max;
		UBYTE	*FromPtr,
			*ToPtr;

		Max	= (LastLine + 1 - Lines - CursorY) * RasterWidth;

		From	= RasterWidth * (LastLine + 1 - Lines) - 1;
		To	= RasterWidth * (LastLine + 1)         - 1;

		FromPtr	= &Raster[From];
		ToPtr	= &Raster[To];

		while(Max--)
			*ToPtr-- = *FromPtr--;

		memset(&Raster[CursorY * RasterWidth],' ',Lines * RasterWidth);
	}
}

	/* RasterScrollRegion(WORD Direction,WORD RasterTop,WORD RasterBottom,WORD RasterLines):
	 *
	 *	Scroll the contents of the character raster up/down.
	 */

VOID
RasterScrollRegion(WORD Direction,WORD RasterTop,WORD RasterBottom,WORD RasterLines)
{
	WORD First,Last,i,Max,Dir;
	UBYTE *FirstPtr,*LastPtr;

	Max = RasterLines * RasterWidth;
	Dir = Direction < 0 ? -Direction : Direction;
	
	if(Dir > RasterLines)
	{
			/* All that is needed is to delete the lines. */
	
		memset(&Raster[RasterTop * RasterWidth],' ',Max);
	}
	else
	{
		if(Dir)
			Max -= (Dir - 1) * RasterWidth;
		
		if(Direction < 0)
		{
			First	= (RasterTop + RasterLines	) * RasterWidth - 1;
			Last	= (RasterTop + RasterLines + Dir) * RasterWidth - 1;
	
			FirstPtr = &Raster[First];
			LastPtr = &Raster[Last];
	
			i = 0;
	
			while(i++ < Max)
				*LastPtr-- = *FirstPtr--;

			for(i = RasterBottom ; i >= (RasterTop + Dir) ; i--)
				RasterAttr[i] = RasterAttr[i - Dir];

			memset(&Raster[RasterTop * RasterWidth],' ',RasterWidth * Dir);

			memset(&RasterAttr[RasterTop],SCALE_NORMAL,Dir);
		}
		else
		{
			First	= RasterTop * RasterWidth + RasterWidth * Dir;
			Last	= RasterTop * RasterWidth;
	
			FirstPtr = &Raster[First];
			LastPtr = &Raster[Last];
	
			i = 0;
	
			while(i++ < Max)
				*LastPtr++ = *FirstPtr++;
	
			for(i = RasterTop ; i <= (RasterBottom - Dir) ; i++)
				RasterAttr[i] = RasterAttr[i + Dir];

			memset(&Raster[(RasterLines - Dir + 1) * RasterWidth],' ',RasterWidth * Dir);

			memset(&RasterAttr[RasterBottom - Dir],SCALE_NORMAL,Dir);
		}
	}
}

	/* RasterShiftChar(WORD Size):
	 *
	 *	Shift the characters following the current cursor
	 *	position Size characters to the right.
	 */

VOID
RasterShiftChar(WORD Size)
{
	WORD i,First;
	UBYTE *FirstPtr,*LastPtr;

	First = CursorY * RasterWidth + RasterWidth - 1;

	FirstPtr = &Raster[First];
	LastPtr = &Raster[First - Size];

	i = RasterWidth - Size;

	while(i-- > CursorX)
		*FirstPtr-- = *LastPtr--;
}

	/* RasterPutString(UBYTE *String,WORD Length):
	 *
	 *	Put a string into the character raster.
	 */

VOID
RasterPutString(UBYTE *String,WORD Length)
{
	if(Length == 1)
	{
		if(CursorX + 1 < RasterWidth)
			Raster[CursorY * RasterWidth + CursorX] = String[0];
	}
	else
	{
		if(CursorX + Length >= RasterWidth)
			Length = RasterWidth - CursorX;

		CopyMem(String,&Raster[CursorY * RasterWidth + CursorX],Length);
	}
}
