/*  GadTools layout toolkit
**
**  Copyright © 1993-1994 by Olaf `Olsen' Barthel
**  Freely distributable.
*/

#include "gtlayout_global.h"

struct Window * __stdargs
LT_Build(LayoutHandle *Handle,...)
{
	struct Window	*Result;
	va_list 	 VarArgs;

	va_start(VarArgs,Handle);
	Result = LT_BuildA(Handle,(struct TagItem *)VarArgs);
	va_end(VarArgs);

	return(Result);
}

struct Window * LIBENT
LT_BuildA(REG(a0) LayoutHandle *handle,REG(a1) struct TagItem *TagParams)
{
	LONG		 left, top, width, height;
	struct IBox	 newBounds;
	struct Menu	*menu;
	struct TagItem	*item;
	LONG		 placeLeft;
	LONG		 placeTop;
	struct IBox	 zoomBox;
	struct IBox	*zoom;
	LONG		 i;
	struct TextFont *font;
	struct TagItem	*NewTags = NULL,*Tags;
	BOOLEAN 	 BlockParent = handle -> BlockParent,
			 SmartZoom = FALSE;
	struct Window	*Parent = handle -> Parent;
	STRPTR		 title		= NULL;
	struct IBox	*bounds 	= NULL;
	LONG		 extraWidth	= 0,
			 extraHeight	= 0;
	ULONG		 IDCMP		= NULL;
	UWORD		 align		= 0;
	WORD		 MinX,
			 MinY,
			 MaxX,
			 MaxY;
	BOOL		 SizeGadget	= FALSE,
			 SizeBRight	= FALSE,
			 SizeBBottom	= FALSE;
	ULONG		 BorderBottom,
			 BorderRight;

	if(!handle)
		return(NULL);

	/* ALWAYS */
	{
		struct TagItem *TagList = (struct TagItem *)TagParams;

		while(item = NextTagItem(&TagList))
		{
			switch((ULONG)item -> ti_Tag)
			{
				case LAWN_TitleText:

					title = (STRPTR)item -> ti_Data;
					break;

				case LAWN_TitleID:

					if(!handle -> LocaleHook)
						return(NULL);
					else
						title = (STRPTR)CallHookPkt(handle -> LocaleHook,handle,(APTR)item -> ti_Data);

					break;

				case LAWN_Bounds:

					bounds = (struct IBox *)item -> ti_Data;
					break;

				case LAWN_ExtraWidth:

					extraWidth = item -> ti_Data;
					break;

				case LAWN_ExtraHeight:

					extraHeight = item -> ti_Data;
					break;

				case LAWN_IDCMP:

					IDCMP = item -> ti_Data;
					break;

				case LAWN_AlignWindow:

					align = item -> ti_Data;
					break;
			}
		}
	}

	if(!bounds)
	{
		LTP_GetDisplayClip(handle -> Screen,&newBounds . Left,&newBounds . Top,&newBounds . Width,&newBounds . Height);

		bounds = &newBounds;
	}

	if(title)
		top = handle -> Screen -> WBorTop + handle -> Screen -> Font -> ta_YSize + 1 + handle -> InterHeight;
	else
		top = handle -> Screen -> WBorTop + handle -> InterHeight;

	left = handle -> Screen -> WBorLeft + handle -> InterWidth;

	BorderRight	= handle -> Screen -> WBorRight;
	BorderBottom	= handle -> Screen -> WBorBottom;

	if(handle -> ResizeView)
	{
		if(handle -> ResizeView -> Special . List . ResizeX)
			BorderRight = LTP_GetSizeWidth(handle);

		if(handle -> ResizeView -> Special . List . ResizeY)
			BorderBottom = LTP_GetSizeHeight(handle);
	}

	LTP_CreateGadgets(handle,bounds,left,top,left + handle -> InterWidth + BorderRight,top + handle -> InterHeight + BorderBottom);

	if(handle -> Failed)
		return(NULL);

	width	= left + handle -> TopGroup -> Width + handle -> InterWidth + BorderRight;
	height	= top + handle -> TopGroup -> Height + handle -> InterHeight + BorderBottom;

	if(handle -> ResizeView)
	{
		MaxX = MinX = width;
		MaxY = MinY = height;

		if(handle -> ResizeView -> Special . List . ResizeX)
			MaxX = handle -> Screen -> Width;

		if(handle -> ResizeView -> Special . List . ResizeY)
		{
			MaxY = handle -> Screen -> Height;

			SizeBBottom = TRUE;
		}
		else
			SizeBRight = TRUE;

		SizeGadget = TRUE;

		if(handle -> ResizeView -> Special . List . MinChars && handle -> ResizeView -> Special . List . MinChars < handle -> ResizeView -> Chars)
			MinX -= handle -> GlyphWidth * (handle -> ResizeView -> Chars - handle -> ResizeView -> Special . List . MinChars);

		if(handle -> ResizeView -> Special . List . MinLines && handle -> ResizeView -> Special . List . MinChars < handle -> ResizeView -> Lines)
			MinY -= handle -> RPort . TxHeight * (handle -> ResizeView -> Lines - handle -> ResizeView -> Special . List . MinLines);
	}
	else
	{
		MaxX = MinX = width;
		MaxY = MinY = height;
	}

	if(align & ALIGNF_LEFT)
		placeLeft = 0;
	else
	{
		if(align & ALIGNF_RIGHT)
			placeLeft = bounds -> Width - (width + extraWidth);
		else
			placeLeft = (bounds -> Width - (width + extraWidth)) / 2;
	}

	if(align & ALIGNF_TOP)
		placeTop = 0;
	else
	{
		if(align & ALIGNF_BOTTOM)
			placeTop = bounds -> Height - (height + extraHeight);
		else
			placeTop = (bounds -> Height - (height + extraHeight)) / 2;
	}

	if(align & ALIGNF_EXTRA_LEFT)
		placeLeft += extraWidth;
	else
	{
		if(!(align & ALIGNF_EXTRA_RIGHT))
			placeLeft += extraWidth / 2;
	}

	if(align & ALIGNF_EXTRA_TOP)
		placeTop += extraHeight;
	else
	{
		if(!(align & ALIGNF_EXTRA_BOTTOM))
			placeTop += extraHeight / 2;
	}

	placeLeft	+= bounds -> Left;
	placeTop	+= bounds -> Top;

	if(placeLeft < 0)
		placeLeft = 0;

	if(placeTop < 0)
		placeTop = 0;

	menu = NULL;
	zoom = NULL;

	handle -> AutoRefresh = TRUE;
#ifdef DO_CLONING
	if(handle -> CloneExtra)
	{
		placeLeft	= 0;
		placeTop	= handle -> CloneExtra -> Screen -> BarHeight + 1;

		zoomBox . Left	= placeLeft;
		zoomBox . Top	= placeTop;
	}
#endif	/* DO_CLONING */

	/* ALWAYS */
	{
		struct TagItem *TagList = (struct TagItem *)TagParams;

		while(item = NextTagItem(&TagList))
		{
			switch((ULONG)item -> ti_Tag)
			{
				case LA_Menu:

					handle -> IDCMP |= IDCMP_MENUPICK;

					menu = (struct Menu *)item -> ti_Data;

					break;

				case LAWN_SmartZoom:

					SmartZoom = item -> ti_Tag;

					if(!SmartZoom)
						break;

				case LAWN_Zoom:

					if(item -> ti_Data)
					{
						if(title && SmartZoom)
						{
							STATIC UWORD WhichTable[3] =
							{
								CLOSEIMAGE,
								ZOOMIMAGE,
								DEPTHIMAGE
							};

							LONG	 Size = 0,i;
							BOOLEAN  GotIt = TRUE;
							UWORD	 SizeType;
							Object	*Image;

							if(handle -> Screen -> Flags & SCREENHIRES)
								SizeType = SYSISIZE_MEDRES;
							else
								SizeType = SYSISIZE_LOWRES;

							for(i = 0 ; i < 3 ; i++)
							{
								if(Image = NewObject(NULL,SYSICLASS,
									SYSIA_Size,	SizeType,
									SYSIA_Which,	WhichTable[i],
									SYSIA_DrawInfo, handle -> DrawInfo,
								TAG_DONE))
								{
									ULONG Width;

									GetAttr(IA_Width,Image,&Width);

									Size += Width;

									DisposeObject(Image);
								}
								else
									GotIt = FALSE;
							}

							if(GotIt)
							{
								Size += 8 + TextLength(&handle -> Screen -> RastPort,title,strlen(title)) + 8;

								zoomBox . Width = Size;
							}
							else
								zoomBox . Width = width;
						}
						else
							zoomBox . Width = width;

						if(V39)
						{
							zoomBox . Left	= -1;
							zoomBox . Top	= -1;
						}
						else
						{
							zoomBox . Left	= placeLeft;
							zoomBox . Top	= placeTop;
						}

						zoomBox . Height = handle -> Screen -> WBorTop + handle -> Screen -> Font -> ta_YSize + 1;

						zoom = &zoomBox;
					}

					break;

				case LAWN_UserPort:

					handle -> MsgPort = (struct MsgPort *)item -> ti_Data;

					break;

				case LAWN_HelpHook:

					handle -> HelpHook = (struct Hook *)item -> ti_Data;

					break;

				case LAWN_Left:

					placeLeft = item -> ti_Data;

					break;

				case LAWN_Top:

					placeTop = item -> ti_Data;

					break;

				case LAWN_Parent:

					Parent = (struct Window *)item -> ti_Data;
					break;

				case LAWN_BlockParent:

					BlockParent = item -> ti_Data;
					break;

				case LAWN_BelowMouse:

					if((placeLeft = handle -> Screen -> MouseX - (width / 2)) < 0)
						placeLeft = 0;

					if((placeTop = handle -> Screen -> MouseY - (height / 2)) < 0)
						placeTop = 0;

					break;

				case LAWN_MaxPen:

					handle -> MaxPen = (LONG)item -> ti_Data;
					break;

				case LAWN_MoveToWindow:

					handle -> MoveToWindow = (LONG)item -> ti_Data;
					break;

				case LAWN_AutoRefresh:

					handle -> AutoRefresh = (LONG)item -> ti_Data;
					break;
			}
		}
	}

	Tags = (struct TagItem *)TagParams;

	if(handle -> BackgroundPen && !V39)
	{
		if(NewTags = CloneTagItems(Tags))
		{
			STATIC Tag Filter[] = { WA_SimpleRefresh,TAG_DONE };

			FilterTagItems(NewTags,Filter,TAGFILTER_NOT);

			Tags = NewTags;
		}
		else
			return(NULL);
	}

	if(Parent)
	{
		WORD	Left,Top,Width,Height,MoveLeft,MoveTop,
			WindowLeft,WindowTop,WindowWidth,WindowHeight;

		WindowLeft	= Parent -> LeftEdge + Parent -> BorderLeft;
		WindowTop	= Parent -> TopEdge + Parent -> BorderTop;
		WindowWidth	= Parent -> Width - (Parent -> BorderLeft + Parent -> BorderRight);
		WindowHeight	= Parent -> Height - (Parent -> BorderTop + Parent -> BorderBottom);

		LTP_GetDisplayClip(Parent -> WScreen,&Left,&Top,&Width,&Height);

		if((MoveLeft = WindowLeft + (WindowWidth - width) / 2) < 0)
			MoveLeft = 0;

		if((MoveTop = WindowTop + (WindowHeight - height) / 2) < 0)
			MoveTop = 0;

		if(MoveLeft < Left || MoveLeft + width > Left + Width)
			MoveLeft = -1;

		if(MoveTop < Top || MoveTop + height > Top + Height)
			MoveTop = -1;

		if(MoveTop != -1 && MoveLeft != -1)
		{
			placeLeft	= MoveLeft;
			placeTop	= MoveTop;
		}
	}

	if(BlockParent && Parent)
	{
		LT_LockWindow(Parent);

		handle -> Parent = Parent;
	}

	if(SizeGadget)
		zoom = NULL;

	if(handle -> Window = OpenWindowTags(NULL,
		WA_Left,		placeLeft,
		WA_Top, 		placeTop,
		WA_Width,		width,
		WA_Height,		height,
		WA_NewLookMenus,	TRUE,
		WA_CustomScreen,	handle -> Screen,
		WA_BackFill,		&handle -> BackfillHook,
		WA_MinWidth,		MinX,
		WA_MinHeight,		MinY,
		WA_MaxWidth,		MaxX,
		WA_MaxHeight,		MaxY,
		WA_SizeGadget,		SizeGadget,
		WA_SizeBBottom,		SizeBBottom,
		WA_SizeBRight,		SizeBRight,

		zoom	? WA_Zoom :			TAG_IGNORE,	zoom,
		!handle -> MsgPort ? WA_IDCMP : 	TAG_IGNORE,	IDCMP_REFRESHWINDOW | IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP | handle -> IDCMP,
		title	? WA_Title :			TAG_IGNORE,	title,
		handle -> AmigaGlyph ? WA_AmigaKey :	TAG_IGNORE,	handle -> AmigaGlyph,
		handle -> CheckGlyph ? WA_Checkmark :	TAG_IGNORE,	handle -> CheckGlyph,
	TAG_MORE,Tags))
	{
		font = handle -> RPort . Font;

		handle -> RPort = *handle -> Window -> RPort;

		LTP_SetFont(handle,font);

		AddGList(handle -> Window,handle -> List,(UWORD)-1,(UWORD)-1,NULL);

		RefreshGList(handle -> List,handle -> Window,NULL,(UWORD)-1);

		if(NewTags)
		{
			FreeTagItems(NewTags);

			NewTags = NULL;
		}

		if(V39)
		{
			if(handle -> MaxPen > 0)
			{
				SetMaxPen(&handle -> RPort,handle -> MaxPen);
				SetMaxPen(handle -> Window -> RPort,handle -> MaxPen);
			}
		}

		GT_RefreshWindow(handle -> Window,NULL);
		LTP_DrawGroup(handle,handle -> TopGroup);

		LTP_MoveToWindow(handle);

		if(handle -> MsgPort)
		{
			handle -> Window -> UserPort = handle -> MsgPort;

			if(!ModifyIDCMP(handle -> Window,IDCMP_REFRESHWINDOW | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP | handle -> IDCMP))
			{
				handle -> Window -> UserPort = NULL;

				return (NULL);
			}
		}

		if(menu)
			SetMenuStrip(handle -> Window,menu);

		handle -> Previous = NULL;

		for(i = 0 ; i < handle -> Count ; i++)
		{
			if(handle -> GadgetArray[i])
			{
				ObjectNode *node;

				if(GETOBJECT(handle -> GadgetArray[i],node))
				{
					if(LIKE_STRING_KIND(node) || (node -> Type == INTEGER_KIND))
					{
						if(!handle -> Previous)
							handle -> Previous = handle -> GadgetArray[i];
					}
				}
			}
		}
#ifdef DO_CLONING
		if(handle -> CloneExtra)
			ScreenToFront(handle -> Window -> WScreen);
#endif
	}
	else
	{
		if(handle -> Parent)
		{
			LT_UnlockWindow(handle -> Parent);

			handle -> Parent = NULL;
		}
	}

	FreeTagItems(NewTags);

	return(handle -> Window);
}


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


struct Window * __stdargs
LT_Layout(LayoutHandle *handle, STRPTR title,struct IBox *bounds,LONG extraWidth, LONG extraHeight,ULONG IDCMP, UBYTE align, ...)
{
	struct Window	*Result;
	va_list 	 VarArgs;

	va_start(VarArgs,align);

	Result = LT_Build(handle,
		LAWN_Title,		title,
		LAWN_Bounds,		bounds,
		LAWN_ExtraWidth,	extraWidth,
		LAWN_ExtraHeight,	extraHeight,
		LAWN_IDCMP,		IDCMP,
		LAWN_AlignWindow,	align,
	TAG_MORE,(struct TagItem *)VarArgs);

	va_end(VarArgs);

	return(Result);
}

struct Window * LIBENT
LT_LayoutA(REG(a0) LayoutHandle *handle, REG(a1) STRPTR title,REG(a2) struct IBox *bounds,REG(d0) LONG extraWidth, REG(d1) LONG extraHeight,REG(d2) ULONG IDCMP, REG(d3) UBYTE align, REG(a3) struct TagItem *TagParams)
{
	return(LT_Build(handle,
		LAWN_Title,		title,
		LAWN_Bounds,		bounds,
		LAWN_ExtraWidth,	extraWidth,
		LAWN_ExtraHeight,	extraHeight,
		LAWN_IDCMP,		IDCMP,
		LAWN_AlignWindow,	align,
	TAG_MORE,TagParams));
}
