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

#include "gtlayout_global.h"

VOID __stdargs
LT_Add(LayoutHandle *Handle,UBYTE Type,STRPTR Label,LONG ID,...)
{
	va_list VarArgs;

	va_start(VarArgs,ID);
	LT_AddA(Handle,Type,Label,ID,(struct TagItem *)VarArgs);
	va_end(VarArgs);
}

VOID LIBENT
LT_AddA(REG(a0) LayoutHandle *Handle,REG(d0) UBYTE Type,REG(d1) STRPTR Label,REG(d2) LONG ID,REG(a1) struct TagItem *TagList)
{
	struct TagItem *TagItem;

	if(!Handle || Handle -> Failed)
		return;

	if(Type == VERTICAL_KIND || Type == HORIZONTAL_KIND || Handle -> TopGroup)
	{
		ObjectNode *Node;

		switch(Type)
		{
			case BUTTON_KIND:

				Handle -> IDCMP |= BUTTONIDCMP;
				break;

			case CHECKBOX_KIND:

				Handle -> IDCMP |= CHECKBOXIDCMP;
				break;

			case LISTVIEW_KIND:

				Handle -> IDCMP |= LISTVIEWIDCMP;
				break;

			case MX_KIND:

				Handle -> IDCMP |= MXIDCMP;
				break;

			case CYCLE_KIND:

				Handle -> IDCMP |= CYCLEIDCMP;
				break;

			case PALETTE_KIND:

				Handle -> IDCMP |= PALETTEIDCMP;
				break;

			case SLIDER_KIND:

				Handle -> IDCMP |= SLIDERIDCMP;
				break;

			case SCROLLER_KIND:

				Handle -> IDCMP |= SCROLLERIDCMP | ARROWIDCMP;
				break;

			case INTEGER_KIND:

				Handle -> IDCMP |= STRINGIDCMP | IDCMP_GADGETDOWN | IDCMP_INTUITICKS;
				break;

			case STRING_KIND:
			case FRACTION_KIND:
			case PASSWORD_KIND:

				Handle -> IDCMP |= STRINGIDCMP | IDCMP_GADGETDOWN;
				break;
#ifdef DO_LEVEL_KIND
			case LEVEL_KIND:

				Handle -> IDCMP |= IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_GADGETUP;
				break;
#endif	/* DO_LEVEL_KIND */
			case END_KIND:

				Handle -> CurrentGroup = Handle -> CurrentGroup -> Special . Group . ParentGroup;
				return;
		}

		if(Node = LTP_CreateObjectNode(Handle,Type,ID,Label))
		{
			struct MinList	*ParentList;
			LONG		 FirstLabel	= -1;
			LONG		 LastLabel	= -1;
			LONG		*LabelTable	= NULL;

			Type = Node -> Type;

			if(Type == GROUP_KIND)
			{
				Node -> LabelPlace			= PLACE_IN;
				Node -> Special . Group . ParentGroup	= Handle -> CurrentGroup;

				if(!Handle -> TopGroup)
				{
					Handle -> TopGroup = Node;

					ParentList = NULL;
				}
				else
					ParentList = &Handle -> CurrentGroup -> Special . Group . ObjectList;

				Handle -> CurrentGroup = Node;

				NewList(&Node -> Special . Group . ObjectList);
			}
			else
				ParentList = &Handle -> CurrentGroup -> Special . Group . ObjectList;

			if(Label && !Node -> NoKey)
			{
				ULONG Len;

				Len = 0;

				while(Label[Len])
				{
					if(Label[Len] == '_')
					{
						Node -> Key = ToLower(Label[Len + 1]);

						break;
					}

					Len++;
				}
			}

			if(TagList)
			{
				struct TagItem *TempList = TagList;

				while(!Handle -> Failed && (TagItem = NextTagItem(&TempList)))
				{
					switch(TagItem -> ti_Tag)
					{
						case LA_BYTE:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_BYTE;

							LTP_GetStorage(Node);

							break;

						case LA_UBYTE:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_UBYTE;

							LTP_GetStorage(Node);

							break;

						case LA_WORD:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_WORD;

							LTP_GetStorage(Node);

							break;

						case LA_UWORD:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_UWORD;

							LTP_GetStorage(Node);

							break;

						case LA_LONG:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_LONG;

							LTP_GetStorage(Node);

							break;

						case LA_ULONG:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_ULONG;

							LTP_GetStorage(Node);

							break;

						case LA_STRPTR:

							Node -> Storage 	= (APTR)TagItem -> ti_Data;
							Node -> StorageType	= STORAGE_STRPTR;

							LTP_GetStorage(Node);

							break;

						case LAXB_FullSize:

							if(Type == XBAR_KIND || Type == YBAR_KIND)
								Node -> Special . Bar . FullSize = TagItem -> ti_Data;

							break;

						case LA_LabelTable:

							LabelTable = (LONG *)TagItem -> ti_Data;
							break;

						case LA_FirstLabel:

							FirstLabel = TagItem -> ti_Data;
							break;

						case LA_LastLabel:

							LastLabel = TagItem -> ti_Data;
							break;

						case LA_LastGadget:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . LastGadget = TagItem -> ti_Data;
							else
							{
								if(Type == FRACTION_KIND || Type == STRING_KIND || Type == PASSWORD_KIND)
									Node -> Special . String . LastGadget = TagItem -> ti_Data;
							}

							break;

						case LA_LabelChars:

							Node -> LabelChars = TagItem -> ti_Data;

							break;

						case LA_HistoryLines:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . MaxHistoryLines = TagItem -> ti_Data;
							else
							{
								if(Type == FRACTION_KIND || Type == STRING_KIND || Type == PASSWORD_KIND)
									Node -> Special . String . MaxHistoryLines = TagItem -> ti_Data;
							}

							break;

						case LA_HistoryHook:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . HistoryHook = (struct Hook *)TagItem -> ti_Data;
							else
							{
								if(Type == FRACTION_KIND || Type == STRING_KIND)
									Node -> Special . String . HistoryHook = (struct Hook *)TagItem -> ti_Data;
							}

							break;

						case LAIN_IncrementerHook:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . IncrementerHook = (struct Hook *)TagItem -> ti_Data;

							break;

						case LA_Min:

							Node -> Min = TagItem -> ti_Data;

							break;

						case LA_Max:

							Node -> Max = TagItem -> ti_Data;

							break;

						case LABX_ReserveSpace:

							if(Type == BOX_KIND)
								Node -> Special . Box . ReserveSpace = TagItem -> ti_Data;

							break;

						case LA_Chars:

							Node -> Chars = TagItem -> ti_Data;

							break;

						case LA_LabelPlace:

							Node -> LabelPlace = TagItem -> ti_Data;

							if(Type == MX_KIND)
							{
								if(TagItem -> ti_Data == PLACE_RIGHT)
									Node -> LabelPlace = PLACE_RIGHT;
								else
									Node -> LabelPlace = PLACE_LEFT;
							}

							break;

						case LA_ExtraSpace:

							Node -> ExtraSpace = (WORD)TagItem -> ti_Data;

							if(Node -> ExtraSpace == 1)
								Node -> ExtraSpace = 3;

							break;

						case LA_PageSelector:

							Node -> PageSelector = TagItem -> ti_Data;
							break;

						case LABT_ExtraFat:

							if(Node -> Type == BUTTON_KIND)
								Node -> Special . Button . ExtraFat = TagItem -> ti_Data;

							break;
#ifdef DO_PICKSHORTCUTS
						case LA_NoKey:

							Node -> NoKey = TagItem -> ti_Data;
							break;
#endif
						case LA_HighLabel:

							Node -> HighLabel = TagItem -> ti_Data;
							break;

						case LAPA_SmallPalette:

							if(Type == PALETTE_KIND)
								Node -> Special . Palette . SmallPalette = TagItem -> ti_Data;

							break;

						case LA_Lines:

							if(Type == BOX_KIND)
							{
								LONG Count = TagItem -> ti_Data;

								if(Node -> Lines != Count)
								{
									if(Node -> Special . Box . Lines)
									{
										LTP_Free(Handle,Node -> Special . Box . Lines,sizeof(STRPTR) * Node -> Lines);

										Node -> Special . Box . Lines = NULL;
									}
								}

								if(!Node -> Special . Box . Lines)
								{
									if(Node -> Special . Box . Lines = (STRPTR *)LTP_Alloc(Handle,sizeof(STRPTR) * Count))
									{
										LONG i;

										for(i = 0 ; i < Count ; i++)
											Node -> Special . Box . Lines[i] = "";
									}
									else
										Handle -> Failed = TRUE;
								}
							}

							Node -> Lines = TagItem -> ti_Data;

							break;

						case LA_Picker:

							if(Type == TEXT_KIND)
								Node -> Special . Text . UsePicker = TagItem -> ti_Data;

							if(Type == STRING_KIND)
								Node -> Special . String . UsePicker = TagItem -> ti_Data;

							break;

						case LACY_AutoPageID:

							if(Type == CYCLE_KIND)
								Node -> Special . Cycle . AutoPageID = (LONG)TagItem -> ti_Data;

							if(Type == MX_KIND)
								Node -> Special . Radio . AutoPageID = (LONG)TagItem -> ti_Data;

							break;

						case LAGR_Spread:

							if(Type == GROUP_KIND)
								Node -> Special . Group . Spread = TagItem -> ti_Data;

							break;

						case LAGR_Frame:

							if(Type == GROUP_KIND)
								Node -> Special . Group . Frame = TagItem -> ti_Data;

							break;

						case LAGR_SameSize:

							if(Type == GROUP_KIND)
								Node -> Special . Group . SameSize = TagItem -> ti_Data;

							break;

						case LAGR_LastAttributes:

							if(Type == GROUP_KIND)
								Node -> Special . Group . LastAttributes = TagItem -> ti_Data;

							break;

						case LAGR_ActivePage:

							if(Type == GROUP_KIND)
							{
								Node -> Special . Group . ActivePage	= TagItem -> ti_Data;
								Node -> Special . Group . Paging	= TRUE;
							}

							break;

						case LABT_ReturnKey:

							if(Type == BUTTON_KIND)
								Node -> Special . Button . ReturnKey = TagItem -> ti_Data;

							break;

						case LABT_EscKey:

							if(Type == BUTTON_KIND)
								Node -> Special . Button . EscKey = TagItem -> ti_Data;

							break;

						case LALV_CursorKey:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . CursorKey = TagItem -> ti_Data;

							break;

						case LALV_LockSize:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . LockSize = TagItem -> ti_Data;

							break;

						case LALV_MaxGrowX:

							if(Type == LISTVIEW_KIND)
							{
								Handle -> GrowView = Node;

								Node -> Special . List . MaxGrowX = TagItem -> ti_Data;
							}

							break;

						case LALV_MaxGrowY:

							if(Type == LISTVIEW_KIND)
							{
								Handle -> GrowView = Node;

								Node -> Special . List . MaxGrowY = TagItem -> ti_Data;
							}

							break;

						case LALV_ResizeX:

							if(Type == LISTVIEW_KIND)
							{
								Handle -> ResizeView = Node;

								Handle -> IDCMP |= IDCMP_SIZEVERIFY | IDCMP_NEWSIZE;

								Node -> Special . List . ResizeX = TagItem -> ti_Data;
							}

							break;

						case LALV_ResizeY:

							if(Type == LISTVIEW_KIND)
							{
								Handle -> ResizeView = Node;

								Handle -> IDCMP |= IDCMP_SIZEVERIFY | IDCMP_NEWSIZE;

								Node -> Special . List . ResizeY = TagItem -> ti_Data;
							}

							break;

						case LALV_MinChars:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . MinChars = TagItem -> ti_Data;

							break;

						case LALV_MinLines:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . MinLines = TagItem -> ti_Data;

							break;

						case LALV_FlushLabelLeft:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . FlushLabelLeft = TagItem -> ti_Data;

							break;

						case LALV_Labels:

							if(Type == LISTVIEW_KIND)
							{
								STRPTR *Labels = (STRPTR *)TagItem -> ti_Data;

								if(*Labels)
								{
									struct List *SomeList;

									if(SomeList = LTP_Alloc(Handle,sizeof(struct List)))
									{
										struct Node *SomeNode;

										NewList(SomeList);

										Node -> Special . List . Labels = SomeList;

										while(*Labels)
										{
											if(SomeNode = LTP_Alloc(Handle,sizeof(struct Node) + strlen(*Labels) + 1))
											{
												SomeNode -> ln_Name = (STRPTR)(SomeNode + 1);

												strcpy(SomeNode -> ln_Name,*Labels++);

												AddTail(SomeList,SomeNode);
											}
										}
									}
								}
							}

							break;

						case LA_Link:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . LinkID = TagItem -> ti_Data;

							if(Type == STRING_KIND || Type == FRACTION_KIND)
								Node -> Special . String . LinkID = TagItem -> ti_Data;

							break;

#ifdef DO_TAPEDECK_KIND
						case LATD_ButtonType:

							if(Type == TAPEDECK_KIND)
								Node -> Special . TapeDeck . ButtonType = TagItem -> ti_Data;

							break;

						case LATD_Toggle:

							if(Type == TAPEDECK_KIND)
								Node -> Special . TapeDeck . Toggle = TagItem -> ti_Data;

							break;

						case LATD_Pressed:

							if(Type == TAPEDECK_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case LATD_Smaller:

							if(Type == TAPEDECK_KIND)
								Node -> Special . TapeDeck . Smaller = TagItem -> ti_Data;

							break;
#endif	/* DO_TAPEDECK_KIND */

#ifdef DO_GAUGE_KIND
						case LAGA_Percent:

							if(Type == GAUGE_KIND)
							{
								LONG Percent = (LONG)TagItem -> ti_Data;

								if(Percent <= 0)
									Node -> Current = 0;
								else
								{
									if(Percent > 100)
										Node -> Current = 100;
									else
										Node -> Current = Percent;
								}
							}

							break;

						case LAGA_InfoLength:

							if(Type == GAUGE_KIND)
							{
								LONG Length = (LONG)TagItem -> ti_Data;

								if(Length > Node -> Special . Gauge . InfoLength)
								{
									STRPTR NewText;

									if(NewText = (STRPTR)AsmAllocPooled(Handle -> Pool,Length + 1,SysBase))
									{
										if(Node -> Special . Gauge . InfoText)
										{
											strcpy(NewText,Node -> Special . Gauge . InfoText);

											AsmFreePooled(Handle -> Pool,Node -> Special . Gauge . InfoText,Node -> Special . Gauge . InfoLength + 1,SysBase);
										}

										NewText[0] = 0;

										Node -> Special . Gauge . InfoText	= NewText;
										Node -> Special . Gauge . InfoLength	= Length;
									}
									else
										Handle -> Failed = TRUE;
								}
							}

							break;

						case LAGA_InfoText:

							if(Type == GAUGE_KIND)
							{
								STRPTR	SomeText	= (STRPTR)TagItem -> ti_Data;
								LONG	Len		= strlen(SomeText);

								if(!Node -> Special . Gauge . InfoLength)
								{
									if(Node -> Special . Gauge . InfoText = (STRPTR)AsmAllocPooled(Handle -> Pool,Len + 1,SysBase))
										Node -> Special . Gauge . InfoLength = Len;
									else
										Handle -> Failed = TRUE;
								}

								if(Node -> Special . Gauge . InfoLength)
								{
									if(Len > Node -> Special . Gauge . InfoLength)
										Len = Node -> Special . Gauge . InfoLength;

									CopyMem(SomeText,Node -> Special . Gauge . InfoText,Len);

									Node -> Special . Gauge . InfoText[Len] = 0;
								}
							}

							break;
#endif
						case LALV_ExtraLabels:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . ExtraLabels = (STRPTR *)TagItem -> ti_Data;

							break;

						case LACY_TabKey:

							if(Type == CYCLE_KIND)
								Node -> Special . Cycle . TabKey = TagItem -> ti_Data;

							if(Type == MX_KIND)
								Node -> Special . Radio . TabKey = TagItem -> ti_Data;

							break;

						case LAFR_RefreshHook:

							if(Type == FRAME_KIND)
								Node -> Special . Frame . RefreshHook = (struct Hook *)TagItem -> ti_Data;

							break;

						case LAFR_InnerWidth:

							if(Type == FRAME_KIND)
								Node -> Special . Frame . InnerWidth = TagItem -> ti_Data;

							break;

						case LAFR_InnerHeight:

							if(Type == FRAME_KIND)
								Node -> Special . Frame . InnerHeight = TagItem -> ti_Data;

							break;

						case LA_DrawBox:

							if(Type == FRAME_KIND)
								Node -> Special . Frame . DrawBox = TagItem -> ti_Data;

							if(Type == BOX_KIND)
								Node -> Special . Box . DrawBox = TagItem -> ti_Data;

							break;

						case LABX_AlignText:

							if(Type == BOX_KIND)
								Node -> Special . Box . AlignText = TagItem -> ti_Data;

							break;

						case LABX_Labels:

							if(Type == BOX_KIND)
							{
								STRPTR	*Labels = (STRPTR *)TagItem -> ti_Data;
								LONG	 Count	= 0;

								while(Labels[Count])
									Count++;

								if(Node -> Lines != Count)
								{
									if(Node -> Special . Box . Lines)
									{
										LTP_Free(Handle,Node -> Special . Box . Lines,sizeof(STRPTR) * Node -> Lines);

										Node -> Special . Box . Lines = NULL;
									}
								}

								if(Count)
								{
									if(!Node -> Special . Box . Lines)
									{
										if(Node -> Special . Box . Lines = LTP_Alloc(Handle,sizeof(STRPTR) * Count))
										{
											LONG i;

											for(i = 0 ; i < Count ; i++)
												Node -> Special . Box . Lines[i] = "";
										}
									}
								}

								Node -> Lines = Count;

								Node -> Special . Box . Labels = Labels;
							}

							break;

						case LABX_Lines:

							if(Type == BOX_KIND)
							{
								STRPTR	*Lines = (STRPTR *)TagItem -> ti_Data;
								LONG	 Count = 0;

								while(Lines[Count])
									Count++;

								if(Node -> Lines && Count > Node -> Lines)
									Count = Node -> Lines;

								if(Count)
								{
									if(!Node -> Special . Box . Lines)
										Node -> Special . Box . Lines = LTP_Alloc(Handle,sizeof(STRPTR) * Count);

									if(Node -> Special . Box . Lines)
									{
										LONG i;

										for(i = 0 ; i < Count ; i++)
											Node -> Special . Box . Lines[i] = Lines[i];
									}
								}

								Node -> Lines = Count;
							}

							break;

						case GA_Disabled:

							Node -> Disabled = TagItem -> ti_Data;
							break;

						case GTCB_Checked:

							if(Type == CHECKBOX_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTLV_Labels:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . Labels = (struct List *)TagItem -> ti_Data;

							break;

						case GTLV_ReadOnly:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . ReadOnly = TagItem -> ti_Data;

							break;

						case GTLV_MakeVisible:
						case GTLV_Selected:

							if(Type == LISTVIEW_KIND)
								Node -> Current = (LONG)TagItem -> ti_Data;

							break;

						case GTLV_CallBack:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . CallBack = (struct Hook *)TagItem -> ti_Data;

							break;

						case GTLV_MaxPen:

							if(Type == LISTVIEW_KIND)
								Node -> Special . List . MaxPen = TagItem -> ti_Data;

							break;

						case GTMX_Labels:

							if(Type == MX_KIND)
								Node -> Special . Radio . Choices = (STRPTR *)TagItem -> ti_Data;

							break;

						case GTMX_Active:

							if(Type == MX_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTMX_TitlePlace:

							if(Type == MX_KIND && Label)
							{
								if(TagItem -> ti_Data == PLACE_RIGHT)
									Node -> Special . Radio . TitlePlace = PLACETEXT_RIGHT;
								else
									Node -> Special . Radio . TitlePlace = PLACETEXT_LEFT;
							}

							break;

						case GTTX_Text:

							if(Type == TEXT_KIND)
								Node -> Special . Text . Text = (STRPTR)TagItem -> ti_Data;

							break;

						case GTTX_CopyText:

							if(Type == TEXT_KIND)
								Node -> Special . Text . CopyText = TagItem -> ti_Data;

							break;

						case GTTX_Border:

							if(Type == TEXT_KIND)
								Node -> Special . Text . Border = TagItem -> ti_Data;

							break;

						case GTNM_Number:

							if(Type == NUMBER_KIND)
								Node -> Special . Number . Number = TagItem -> ti_Data;

							break;

						case GTNM_Border:

							if(Type == NUMBER_KIND)
								Node -> Special . Number . Border = TagItem -> ti_Data;

							break;

						case GTTX_Justification:

							if(Type == NUMBER_KIND)
								Node -> Special . Number . Justification = TagItem -> ti_Data;

							if(Type == TEXT_KIND)
								Node -> Special . Text . Justification = TagItem -> ti_Data;

							break;

						case GTCY_Labels:

							if(Type == CYCLE_KIND)
								Node -> Special . Cycle . Choices = (STRPTR *)TagItem -> ti_Data;

							break;

						case GTCY_Active:

							if(Type == CYCLE_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTPA_Depth:

							if(Type == PALETTE_KIND)
							{
								Node -> Special . Palette . Depth = TagItem -> ti_Data;

								if(Handle -> MaxPen < (1L << Node -> Special . Palette . Depth) - 1)
									Handle -> MaxPen = (1L << Node -> Special . Palette . Depth) - 1;
							}

							break;

						case GTPA_Color:

							if(Type == PALETTE_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTPA_ColorOffset:

							if(Type == PALETTE_KIND)
								Node -> Min = TagItem -> ti_Data;

							break;

						case GTPA_NumColors:

							if(Type == PALETTE_KIND)
							{
								Node -> Special . Palette . NumColours = TagItem -> ti_Data;

								if(Node -> Special . Palette . ColourTable)
								{
									LONG i;

									for(i = 0 ; i < Node -> Special . Palette . NumColours ; i++)
									{
										if(Node -> Special . Palette . ColourTable[i] > Handle -> MaxPen)
											Handle -> MaxPen = Node -> Special . Palette . ColourTable[i];
									}
								}
							}

							break;

						case GTPA_ColorTable:

							if(Type == PALETTE_KIND)
							{
								Node -> Special . Palette . ColourTable = (UBYTE *)TagItem -> ti_Data;

								if(Node -> Special . Palette . NumColours)
								{
									LONG i;

									for(i = 0 ; i < Node -> Special . Palette . NumColours ; i++)
									{
										if(Node -> Special . Palette . ColourTable[i] > Handle -> MaxPen)
											Handle -> MaxPen = Node -> Special . Palette . ColourTable[i];
									}
								}
							}

							break;

						case GTSC_Top:

							if(Type == SCROLLER_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTSC_Total:

							if(Type == SCROLLER_KIND)
								Node -> Max = TagItem -> ti_Data;

							break;

						case GTSC_Visible:

							if(Type == SCROLLER_KIND)
								Node -> Special . Scroller . Visible = TagItem -> ti_Data;

							break;

						case GTSC_Arrows:

							if(Type == SCROLLER_KIND)
								Node -> Special . Scroller . Arrows = (TagItem -> ti_Data != 0);

							break;

						case LASC_Thin:

							if(Type == SCROLLER_KIND)
								Node -> Special . Scroller . Thin = TagItem -> ti_Data;

							break;

						case PGA_Freedom:

							if(Type == SCROLLER_KIND)
								Node -> Special . Scroller . Vertical = (TagItem -> ti_Data == LORIENT_VERT);

							break;

						case GTSL_Min:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . Min = (LONG)TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
								Node -> Min = TagItem -> ti_Data;

							break;

						case GTSL_Max:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . Max = (LONG)TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
								Node -> Max = TagItem -> ti_Data;

							break;

						case GTSL_Level:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . Level = (LONG)TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;

						case GTSL_LevelFormat:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . LevelFormat = (STRPTR)TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
								Node -> Special . Slider . LevelFormat = (STRPTR)TagItem -> ti_Data;

							break;

						case GTSL_LevelPlace:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
							{
								if(TagItem -> ti_Data == PLACE_RIGHT)
									Node -> Special . Level . LevelPlace = PLACETEXT_RIGHT;
								else
									Node -> Special . Level . LevelPlace = PLACETEXT_LEFT;
							}
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
							{
								if(TagItem -> ti_Data == PLACE_RIGHT)
									Node -> Special . Slider . LevelPlace = PLACETEXT_RIGHT;
								else
									Node -> Special . Slider . LevelPlace = PLACETEXT_LEFT;
							}

							break;

						case GTSL_DispFunc:

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . DispFunc = (DISPFUNC)TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							if(Type == SLIDER_KIND)
								Node -> Special . Slider . DispFunc = (DISPFUNC)TagItem -> ti_Data;

							break;

						case LASL_FullCheck:

							if(Type == SLIDER_KIND)
								Node -> Special . Slider . FullLevelCheck = TagItem -> ti_Data;

#ifdef DO_LEVEL_KIND
							if(Type == LEVEL_KIND)
								Node -> Special . Level . FullLevelCheck = TagItem -> ti_Data;
#endif	/* DO_LEVEL_KIND */
							break;

						case GTST_String:

							if(Type == STRING_KIND || Type == PASSWORD_KIND)
								Node -> Special . String . String = (STRPTR)TagItem -> ti_Data;

							break;

						case GTST_MaxChars:

							if(Type == STRING_KIND || Type == PASSWORD_KIND)
								Node -> Special . String . MaxChars = TagItem -> ti_Data;

							break;

						case GTST_EditHook:

							if(Type == STRING_KIND)
								Node -> Special . String . EditHook = (struct Hook *)TagItem -> ti_Data;
							else
							{
								if(Type == INTEGER_KIND)
									Node -> Special . Integer . EditHook = (struct Hook *)TagItem -> ti_Data;
							}

							break;

						case STRINGA_Justification:

							if(Type == STRING_KIND || Type == FRACTION_KIND || Type == PASSWORD_KIND)
								Node -> Special . String . Justification = TagItem -> ti_Data;
							else
							{
								if(Type == INTEGER_KIND)
									Node -> Special . Integer . Justification = TagItem -> ti_Data;
							}

							break;
#ifdef DO_FRACTION_KIND
						case LAFC_MaxChars:

							if(Type == FRACTION_KIND)
								Node -> Special . String . MaxChars = TagItem -> ti_Data;

							break;

						case LAFC_Number:

							if(Type == FRACTION_KIND)
								Node -> Current = TagItem -> ti_Data;

							break;
#endif
						case LAIN_UseIncrementers:

							if(Type == INTEGER_KIND)
							{
								if(Node -> Special . Integer . UseIncrementers = TagItem -> ti_Data)
									Handle -> IDCMP |= IDCMP_INTUITICKS;
							}

							break;

						case GTIN_Number:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . Number = TagItem -> ti_Data;

							break;

						case GTIN_MaxChars:

							if(Type == INTEGER_KIND)
								Node -> Special . Integer . MaxChars = TagItem -> ti_Data;

							break;
					}
				}
			}

			if(Handle -> Failed)
				return;

			if((Type == FRACTION_KIND || Type == STRING_KIND || Type == INTEGER_KIND) && Node -> Special . String . MaxHistoryLines)
			{
				if(!Node -> Special . Integer . HistoryHook)
				{
					struct Hook *Hook;

					if(Hook = (struct Hook *)LTP_Alloc(Handle,sizeof(struct Hook) + sizeof(struct MinList)))
					{
						struct MinList *List;

						List = Hook -> h_Data = (APTR)(Hook + 1);

						NewList((struct List *)List);

						Hook -> h_Entry = (HOOKFUNC)LTP_DefaultHistoryHook;

						Node -> Special . Integer . HistoryHook = Hook;
					}
				}

				if(Node -> Special . Integer . HistoryHook)
				{
					struct Node	*TextNode;
					struct MinList	*List = (struct List *)Node -> Special . Integer . HistoryHook -> h_Data;

					Node -> Special . Integer . LayoutHandle	= Handle;
					Node -> Special . Integer . NumHistoryLines	= 0;

					TextNode = (struct Node *)List -> mlh_Head;

					while(TextNode -> ln_Succ)
					{
						Node -> Special . Integer . NumHistoryLines++;

						TextNode = TextNode -> ln_Succ;
					}
				}
			}

			if(Type == TEXT_KIND && Node -> Special . Text . CopyText && Node -> Special . Text . Text)
			{
				LONG	len;
				STRPTR	text;

				len = strlen(Node -> Special . Text . Text);

				if(text = LTP_Alloc(Handle,len + 1))
				{
					strcpy(text,Node -> Special . Text . Text);

					Node -> Special . Text . Text = text;
				}
			}

			if((FirstLabel != -1 && LastLabel != -1) || LabelTable)
			{
				if(Type == MX_KIND || Type == CYCLE_KIND || Type == LISTVIEW_KIND || Type == BOX_KIND)
				{
					if(!Handle -> LocaleHook)
						Handle -> Failed = TRUE;
					else
					{
						if(Type == LISTVIEW_KIND)
						{
							struct List *SomeList;

							if(SomeList = (struct List *)LTP_Alloc(Handle,sizeof(struct List)))
							{
								struct Node	*SomeNode;
								LONG		 Count = (LastLabel - FirstLabel + 1),i;

								NewList(SomeList);

								Node -> Special . List . Labels = SomeList;

								if(LabelTable)
								{
									while(*LabelTable != -1)
									{
										if(SomeNode = LTP_Alloc(Handle,sizeof(struct Node)))
										{
											SomeNode -> ln_Name = (STRPTR)CallHookPkt(Handle -> LocaleHook,Handle,(APTR)(*LabelTable++));

											AddTail(SomeList,SomeNode);
										}
									}
								}
								else
								{
									for(i = 0 ; i < Count ; i++)
									{
										if(SomeNode = LTP_Alloc(Handle,sizeof(struct Node)))
										{
											SomeNode -> ln_Name = (STRPTR)CallHookPkt(Handle -> LocaleHook,Handle,(APTR)(FirstLabel + i));

											AddTail(SomeList,SomeNode);
										}
									}
								}
							}
						}
						else
						{
							STRPTR	*Labels;
							LONG	 Count = (LastLabel - FirstLabel + 1),i;

							if(LabelTable)
							{
								register LONG *Index = LabelTable;

								for(Count = 0 ; *Index != -1 ; Count++, Index++);
							}

							if(Labels = LTP_Alloc(Handle,sizeof(STRPTR) * (Count + 1)))
							{
								if(LabelTable)
								{
									for(i = 0 ; i < Count ; i++)
										Labels[i] = (STRPTR)CallHookPkt(Handle -> LocaleHook,Handle,(APTR)(*LabelTable++));
								}
								else
								{
									for(i = 0 ; i < Count ; i++)
										Labels[i] = (STRPTR)CallHookPkt(Handle -> LocaleHook,Handle,(APTR)(FirstLabel + i));
								}

								Labels[i] = NULL;

								if(Type == MX_KIND)
									Node -> Special . Radio . Choices = Labels;
								else
								{
									if(Type == CYCLE_KIND)
										Node -> Special . Cycle . Choices = Labels;
									else
									{
										if(Type == BOX_KIND)
										{
											if(!Node -> Special . Box . Lines)
											{
												if(Node -> Special . Box . Lines = LTP_Alloc(Handle,sizeof(STRPTR) * Count))
												{
													LONG i;

													for(i = 0 ; i < Count ; i++)
														Node -> Special . Box . Lines[i] = "";
												}
											}

											Node -> Lines = Count;

											Node -> Special . Box . Labels = Labels;
										}
									}
								}
							}
						}
					}
				}
			}

			if(Type == BOX_KIND && Node -> Special . Box . ReserveSpace)
			{
				LONG	Size;
				STRPTR	Buffer;

				if(!Node -> Special . Box . Lines)
				{
					if(Node -> Special . Box . Lines = LTP_Alloc(Handle,sizeof(STRPTR) * Node -> Lines))
					{
						LONG i;

						for(i = 0 ; i < Node -> Lines ; i++)
							Node -> Special . Box . Lines[i] = "";
					}
				}

				if(!Node -> Chars)
					Size = 10;
				else
					Size = Node -> Chars;

				Node -> Special . Box . MaxSize = Size;

				if(Buffer = (STRPTR)LTP_Alloc(Handle,(Size + 1) * Node -> Lines))
				{
					LONG i,Len;

					for(i = 0 ; i < Node -> Lines ; i++)
					{
						if(Node -> Special . Box . Lines[i])
						{
							Len = strlen(Node -> Special . Box . Lines[i]);

							if(Len > Size)
								Len = Size;

							CopyMem(Node -> Special . Box . Lines[i],Buffer,Len);

							Buffer[Len] = 0;
						}
						else
							Buffer[0] = 0;

						Node -> Special . Box . Lines[i] = Buffer;

						Buffer += Size + 1;
					}
				}
			}

			if(Handle -> Failed)
				return;

			if(ParentList)
			{
#ifdef DO_PASSWORD_KIND
				if(Type == PASSWORD_KIND)
				{
					STRPTR Buffer;

					if(!(Buffer = LTP_Alloc(Handle,2 * (Node -> Special . String . MaxChars + 1))))
						return;

					Node -> Special . String . RealString	= Buffer;
					Node -> Special . String . Original	= Buffer + Node -> Special . String . MaxChars + 1;

					if(Node -> Special . String . String)
					{
						strcpy(Node -> Special . String . RealString,	Node -> Special . String . String);
						strcpy(Node -> Special . String . Original,	Node -> Special . String . String);
					}
				}
#endif
				AddTail((struct List *)ParentList,(struct Node *)Node);

				if(Type == XBAR_KIND || Type == YBAR_KIND)
					Node -> Special . Bar . Parent = Handle -> CurrentGroup;
			}
		}
	}
}


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


VOID __stdargs
LT_AddL(LayoutHandle *handle,UBYTE type,ULONG labelID,LONG id,...)
{
	if(handle)
	{
		struct TagItem	*tagList;
		va_list 	 varArg;

		va_start(varArg,id);

		tagList = (struct TagItem *)varArg;

		if(handle -> LocaleHook)
		{
			STRPTR label;

			label = (STRPTR)CallHookPkt(handle -> LocaleHook,handle,(APTR)labelID);

			LT_AddA(handle,type,label,id,tagList);
		}
		else
			handle -> Failed = TRUE;

		va_end(varArgs);
	}
}


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


VOID __stdargs
LT_New(LayoutHandle *handle,...)
{
	va_list VarArgs;

	va_start(VarArgs,handle);
	LT_NewA(handle,(struct TagItem *)VarArgs);
	va_end(VarArgs);
}

VOID LIBENT
LT_NewA(REG(a0) LayoutHandle *handle,REG(a1) struct TagItem *tagList)
{
	if(handle)
	{
		struct TagItem	*tag;
		UBYTE		 type;
		STRPTR		 label;
		ULONG		 id;

		if(tag = FindTagItem(LA_Type,tagList))
		{
			type = tag -> ti_Data;

			if(type == END_KIND)
			{
				handle -> CurrentGroup = handle -> CurrentGroup -> Special . Group . ParentGroup;

				return;
			}

			if(tag = FindTagItem(LA_ID,tagList))
				id = tag -> ti_Data;

			if(tag = FindTagItem(LA_LabelID,tagList))
			{
				if(handle -> LocaleHook)
					label = (STRPTR)CallHookPkt(handle -> LocaleHook,handle,(APTR)tag -> ti_Data);
				else
					handle -> Failed = TRUE;
			}
			else
				label = (STRPTR)GetTagData(LA_LabelText,NULL,tagList);

			LT_AddA(handle,type,label,id,tagList);
		}
		else
			handle -> Failed = TRUE;
	}
}


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


VOID LIBENT
LT_EndGroup(REG(a0) LayoutHandle *handle)
{
	LT_AddA(handle,END_KIND,NULL,0,NULL);
}
