/*
**	GadTools layout toolkit
**
**	Copyright © 1993-1996 by Olaf `Olsen' Barthel
**		Freely distributable.
**
**	:ts=4
*/

#ifndef _GTLAYOUT_GLOBAL_H
#include "gtlayout_global.h"
#endif

#ifdef DO_LEVEL_KIND


/*****************************************************************************/


STATIC VOID
DrawLevelImageLeft(struct RastPort *RPort,UWORD *Pens,LevelImageInfo *Level,struct Image *Image,LONG Left,LONG Top,LONG Width,LONG Height,LONG OffsetX,LONG OffsetY)
{
	LONG	BorderTop	= Level->KnobTop,
			BorderLeft	= Level->KnobWidth;

	Left	+= OffsetX;
	Top		+= OffsetY;

	if(Width > 0)
	{
		LTP_SetAPen(RPort,Pens[SHADOWPEN]);
		LTP_DrawLine(RPort,Left,Top,Left,Top + Height - 1);

		if(Width > 1)
		{
			LTP_DrawLine(RPort,Left + 1,Top,Left + 1,Top + Height - 2);
			LTP_SetAPen(RPort,Pens[SHINEPEN]);

			WritePixel(RPort,Left + 1,Top + Height - 1);

			if(Width > 2)
			{
				LTP_DrawLine(RPort,Left + 2,Top + Height - 1,Left + Width - 1,Top + Height - 1);

				LTP_SetAPen(RPort,Pens[SHADOWPEN]);
				LTP_DrawLine(RPort,Left + 2,Top,Left + Width - 1,Top);

				LTP_SetAPen(RPort,Pens[FILLPEN]);
				RectFill(RPort,Left + 2,Top + 1,Left + Width - 1,Top + Height - 2);
			}
		}

		EraseRect(RPort,Left,Top - BorderTop,Left + Width - 1,Top - 1);
		LTP_EraseBox(RPort,Left,Top + Height,Width,BorderTop);
		EraseRect(RPort,Left - BorderLeft,Top - BorderTop,Left - 1,Top + Height + BorderTop - 1);
	}
	else
	{
		if(Level->Position < BorderLeft && Level->Position > 0)
		{
			Left	= Image->LeftEdge + OffsetX;
			Width	= Level->Position;

			EraseRect(RPort,Left,Top - BorderTop,Left + Width - 1,Top + Height + BorderTop - 1);
		}
	}
}


/*****************************************************************************/


STATIC VOID
DrawLevelImageRight(struct RastPort *RPort,UWORD *Pens,LevelImageInfo *Level,struct Image *Image,LONG Left,LONG Top,LONG Width,LONG Height,LONG OffsetX,LONG OffsetY)
{
	LONG	BorderTop	= Level->KnobTop,
			BorderLeft	= Level->KnobWidth;

	Left	+= OffsetX;
	Top		+= OffsetY;

	if(Width > 0)
	{
		LTP_SetAPen(RPort,Pens[SHINEPEN]);

		LTP_DrawLine(RPort,Left + Width - 1,Top,Left + Width - 1,Top + Height - 1);

		if(Width > 1)
		{
			LTP_DrawLine(RPort,Left + Width - 2,Top + 1,Left + Width - 2,Top + Height - 1);
			LTP_SetAPen(RPort,Pens[SHADOWPEN]);

			WritePixel(RPort,Left + Width - 2,Top);

			if(Width > 2)
			{
				LTP_DrawLine(RPort,Left,Top,Left + Width - 3,Top);

				LTP_SetAPen(RPort,Pens[SHINEPEN]);
				LTP_DrawLine(RPort,Left,Top + Height - 1,Left + Width - 3,Top + Height - 1);

				LTP_SetAPen(RPort,Pens[BACKGROUNDPEN]);
				RectFill(RPort,Left,Top + 1,Left + Width - 3,Top + Height - 2);
			}
		}

		EraseRect(RPort,Left,Top - BorderTop,Left + Width - 1,Top - 1);
		LTP_EraseBox(RPort,Left,Top + Height,Width,BorderTop);
		EraseRect(RPort,Left + Width,Top - BorderTop,Left + Width + BorderLeft - 1,Top + Height + BorderTop - 1);
	}
	else
	{
		Width = Image->Width - (Level->Position + 2 * BorderLeft);

		if(Width > 0)
		{
			Left = Image->LeftEdge + OffsetX + 2 * BorderLeft + Level->Position;

			EraseRect(RPort,Left,Top - BorderTop,Left + Width - 1,Top + Height + BorderTop - 1);
		}
	}
}


/*****************************************************************************/


STATIC VOID
DrawLevelImageComplete(struct Image *Image,struct RastPort *RPort,UWORD *Pens,LevelImageInfo *Level,LONG OffsetX,LONG OffsetY,BOOL Selected)
{
	LONG	BorderTop	= Level->KnobTop,
			BorderLeft	= Level->KnobWidth,
			Left,Top,
			Width,Height;
	LONG	Position;

	Left	= Image->LeftEdge + BorderLeft;
	Top		= Image->TopEdge + BorderTop;
	Width	= Image->Width - 2 * BorderLeft;
	Height	= Image->Height - 2 * BorderTop;

	Position = Level->Position + Left;

	DrawLevelImageLeft(RPort,Pens,Level,Image,Left,Top,Position - BorderLeft - Left,Height,OffsetX,OffsetY);
	DrawLevelImageRight(RPort,Pens,Level,Image,Position + BorderLeft,Top,Left + Width - (Position + BorderLeft),Height,OffsetX,OffsetY);

	BltBitMapRastPort(Level->Knob[Selected ? 1: 0],0,0,RPort,Left + OffsetX + Level->Position - Level->KnobWidth,Image->TopEdge + OffsetY,Level->KnobWidth * 2,Image->Height,0xC0);
}


/*****************************************************************************/


STATIC ULONG
LevelClassDraw(struct Image *Image,struct impDraw *DrawMsg,LevelImageInfo *Level)
{
	struct RastPort *RPort = DrawMsg->imp_RPort;

	SetAfPt(RPort,NULL,0);

	DrawLevelImageComplete(Image,RPort,Level->Pens,Level,DrawMsg->imp_Offset.X,DrawMsg->imp_Offset.Y,DrawMsg->imp_State == IDS_SELECTED);

	if(DrawMsg->imp_State == IDS_DISABLED)
	{
		ULONG	Ghosting	= 0x44441111;

		LONG	Left		= Image->LeftEdge	+ DrawMsg->imp_Offset.X,
				Top			= Image->TopEdge	+ DrawMsg->imp_Offset.Y;

		LTP_SetPens(RPort,Level->Pens[SHADOWPEN],0,JAM1);

		SetAfPt(RPort,(UWORD *)&Ghosting,1);
		LTP_FillBox(RPort,Left,Top,Image->Width,Image->Height);
		SetAfPt(RPort,NULL,0);
	}

	return(TRUE);
}


/*****************************************************************************/


STATIC VOID
LevelClassSet(Class *class,struct Image *Image,struct opSet *SetMsg)
{
	LevelImageInfo	*Level = (LevelImageInfo *)INST_DATA(class,Image);
	struct TagItem	*Item,*List,*PositionItem = NULL;
	LONG			 Width = Image->Width - 2 * Level->KnobWidth;

	List = SetMsg->ops_AttrList;

	while(Item = NextTagItem(&List))
	{
		switch(Item->ti_Tag)
		{
			case LVIA_Current:
				Level->Current = Item->ti_Data;
				break;

			case LVIA_Max:
				Level->Max = Item->ti_Data;
				break;

			case LVIA_Position:
				PositionItem = Item;
				break;
		}
	}

	if(PositionItem)
	{
		LONG Position = (LONG)PositionItem->ti_Data;

		if(Position < 0 || !Level->Max)
			Position = 0;
		else
		{
			if(Position > Width)
				Position = Width;
		}

		Level->Position = Position;
	}
	else
	{
		if(Level->Max)
			Level->Position = (Width * Level->Current) / Level->Max;
		else
			Level->Position = 0;
	}
}


/*****************************************************************************/


STATIC BOOL
LevelClassGet(Class *class,struct Image *Image,struct opGet *GetMsg)
{
	LevelImageInfo *Level = (LevelImageInfo *)INST_DATA(class,Image);

	switch(GetMsg->opg_AttrID)
	{
		case LVIA_Current:
			*GetMsg->opg_Storage = Level->Current;
			return(TRUE);

		case LVIA_Max:
			*GetMsg->opg_Storage = Level->Max;
			return(TRUE);

		case LVIA_Position:
			*GetMsg->opg_Storage = Level->Position;
			return(TRUE);

		case LVIA_KnobWidth:
			*GetMsg->opg_Storage = Level->KnobWidth;
			return(TRUE);

		case IA_SupportsDisable:
			*GetMsg->opg_Storage = TRUE;
			return(TRUE);
	}

	return(FALSE);
}


/*****************************************************************************/


STATIC ULONG
LevelClassNew(Class *class,Object *object,struct opSet *SetMsg)
{
	LONG			 Width		= 0,
					 Height 	= 0;
	LONG			 FontWidth	= 0;
	LONG			 Current	= 0,
					 Max		= 0;
	struct DrawInfo *DrawInfo	= NULL;
	struct Screen	*Screen		= NULL;
	struct TagItem	*List,
					*Item;

	List = SetMsg->ops_AttrList;

	while(Item = NextTagItem(&List))
	{
		switch(Item->ti_Tag)
		{
			case LVIA_Current:
				Current = (LONG)Item->ti_Data;
				break;

			case LVIA_Max:
				Max = (LONG)Item->ti_Data;
				break;

			case LVIA_DrawInfo:
				DrawInfo = (struct DrawInfo *)Item->ti_Data;
				break;

			case LVIA_FontWidth:
				FontWidth = Item->ti_Data;
				break;

			case LVIA_Screen:
				Screen = (struct Screen *)Item->ti_Data;
				break;

			case IA_Width:
				Width = Item->ti_Data;
				break;

			case IA_Height:
				Height = Item->ti_Data;
				break;
		}
	}

	if(Width && Height >= 4 && DrawInfo && Screen)
	{
		struct Image *Image;

		if(Image = (struct Image *)DoSuperMethodA(class,object,(Msg)SetMsg))
		{
			struct RastPort __aligned	 RastPort;
			struct RastPort				*RPort;
			LevelImageInfo				*Level = (LevelImageInfo *)INST_DATA(class,Image);
			LONG						 QuarterWidth,
										 KnobWidth,
										 LevelHeight,
										 i;
			LONG						 Depth;
			struct BitMap				*Friend;
			LONG						 Shine,Shadow,Back,Fill;
			UWORD						*Pens;

			memset(Level,0,sizeof(LevelImageInfo));

			QuarterWidth	= (FontWidth + 3) / 4,
			KnobWidth		= 3 * QuarterWidth,
			LevelHeight		= 2 + (2 * QuarterWidth * DrawInfo->dri_Resolution.X) / DrawInfo->dri_Resolution.Y;

			if(LevelHeight >= Height)
				LevelHeight = Height / 4;

			if(LevelHeight < 2)
			{
				if(Height > 2)
					LevelHeight = 2;
				else
					LevelHeight = Height;
			}

			Level->KnobWidth	= KnobWidth;
			Level->KnobTop		= (Height - LevelHeight) / 2;
			Level->LevelHeight	= LevelHeight;
			Level->Max			= Max;
			Level->Current		= Current;
			Level->Pens			= DrawInfo->dri_Pens;

			if(Max)
				Level->Position = ((Width - 2 * KnobWidth) * Current) / Max;
			else
				Level->Position = 0;

			Friend = Screen->RastPort.BitMap;

			Depth = LTP_GetDepth(Friend);

			Width = Level->KnobWidth * 2;

			for(i = 0 ; i < 2 ; i++)
			{
				if(!(Level->Knob[i] = LTP_CreateBitMap(Width,Height,Depth,Friend,FALSE)))
				{
					CoerceMethod(class,object,OM_DISPOSE);

					return(NULL);
				}
			}

			InitRastPort(RPort = &RastPort);

			Pens = Level->Pens;

			Back = Pens[BACKGROUNDPEN];

			for(i = 0 ; i < 2 ; i++)
			{
				RPort->BitMap = Level->Knob[i];

				Fill	= Pens[i ? FILLPEN : BACKGROUNDPEN];
				Shine	= Pens[SHINEPEN];
				Shadow	= Pens[SHADOWPEN];

				SetRast(RPort,Fill);

				LTP_RenderBevel(RPort,Pens,0,0,Width,Height,FALSE,2);

				if(Fill == Shine || Fill == Shadow)
					Shine = Shadow = Back;

				LTP_SetAPen(RPort,Shine);
				LTP_DrawLine(RPort,Width / 2,2,Width / 2,Height - 3);

				LTP_SetAPen(RPort,Shadow);
				LTP_DrawLine(RPort,Width / 2 - 1,2,Width / 2 - 1,Height - 3);
			}

			return((ULONG)Image);
		}
	}

	return(NULL);
}


STATIC VOID
LevelClassDispose(Class *class,Object *object,Msg msg)
{
	LevelImageInfo	*Level = (LevelImageInfo *)INST_DATA(class,object);
	LONG			 i;

	for(i = 0 ; i < 2 ; i++)
	{
		if(Level->Knob[i])
		{
			WaitBlit();

			break;
		}
	}

	for(i = 0 ; i < 2 ; i++)
		LTP_DeleteBitMap(Level->Knob[i],FALSE);
}

/*****************************************************************************/


ULONG __saveds __asm
LTP_LevelClassDispatcher(REG(a0) Class *class,REG(a2) Object *object,REG(a1) Msg msg)
{
	switch(msg->MethodID)
	{
		case IM_DRAW:
			return(LevelClassDraw((struct Image *)object,(struct impDraw *)msg,(LevelImageInfo *)INST_DATA(class,object)));

		case OM_SET:
			LevelClassSet(class,(struct Image *)object,(struct opSet *)msg);
			break;

		case OM_GET:
			if(LevelClassGet(class,(struct Image *)object,(struct opGet *)msg))
				return(TRUE);
			else
				break;

		case OM_NEW:
			return(LevelClassNew(class,object,(struct opSet *)msg));

		case OM_DISPOSE:
			LevelClassDispose(class,object,msg);

			// Falls down through to the default case...
	}

	return(DoSuperMethodA(class,object,msg));
}
#endif	/* DO_LEVEL_KIND */
