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

#include "gtlayout_global.h"

VOID __stdargs
LT_SetAttributes(LayoutHandle *handle,LONG id,...)
{
	va_list VarArgs;

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

VOID LIBENT
LT_SetAttributesA(REG(a0) LayoutHandle *handle,REG(d0) LONG id,REG(a1) struct TagItem *TagList)
{
	if(handle && TagList)
	{
		struct Gadget	*Gadget;
		struct TagItem	*ThisTag;
		ObjectNode	*Node;

		if(ThisTag = FindTagItem(LH_AutoActivate,TagList))
			handle -> AutoActivate = ThisTag -> ti_Data;

		if(ThisTag = FindTagItem(LH_UserData,TagList))
			handle -> UserData = (APTR)ThisTag -> ti_Data;

		if(ThisTag = FindTagItem(LH_ExitFlush,TagList))
			handle -> ExitFlush = ThisTag -> ti_Data;

		if(ThisTag = FindTagItem(LH_LocaleHook,TagList))
			handle -> LocaleHook = (struct Hook *)ThisTag -> ti_Data;

		if(ThisTag = FindTagItem(LAPR_Gadget,TagList))
			Gadget = (struct Gadget *)ThisTag -> ti_Data;
		else
			Gadget = NULL;

		if(ThisTag = FindTagItem(LAPR_Object,TagList))
			Node = (ObjectNode *)ThisTag -> ti_Data;
		else
			Node = NULL;

		if(Node)
			Gadget = Node -> Host;
		else
		{
			if(Gadget)
			{
				if(Node = (ObjectNode *)Gadget -> UserData)
				{
					if(Node -> Host != Gadget || Node -> PointBack != Node)
						Node = NULL;
				}
			}
		}

		if(!Gadget)
		{
			if(Gadget = LTP_FindGadget(handle,id))
			{
				if(Node = (ObjectNode *)Gadget -> UserData)
				{
					if(Node -> Host != Gadget || Node -> PointBack != Node)
						Node = NULL;
				}
			}
			else
				Node = LTP_FindNode(handle -> TopGroup,id);
		}

		if(Node)
		{
			STATIC Tag Filter[] = { GA_Disabled,TAG_DONE };

			struct TagItem	*NewTags = NULL;
			ULONG		 Exclude = NULL;

			switch(Node -> Type)
			{
				case STRING_KIND:

					if(ThisTag = FindTagItem(GTST_String,TagList))
					{
						Exclude = GTST_String;

						GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
							GTST_String,ThisTag -> ti_Data,
						TAG_DONE);

						LTP_PutStorage(Node);
					}

					if(ThisTag = FindTagItem(LAST_CursorPosition,TagList))
					{
						struct StringInfo	*StringInfo = Gadget -> SpecialInfo;
						LONG			 Position,Len;

						RemoveGList(handle -> Window,handle -> List,(UWORD)-1);

						Position = (LONG)ThisTag -> ti_Data;

						Len = strlen(StringInfo -> Buffer);

						if(Position == -1)
							Position = Len;
						else
						{
							if(Position < 0)
								Position = 0;
							else
							{
								if(Position > Len)
									Position = Len;
							}
						}

						StringInfo -> BufferPos = Position;

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

					break;

#ifdef DO_LEVEL_KIND
				case LEVEL_KIND:
				{
					BOOLEAN		 ChangeIt	= FALSE;
					LevelExtra	*Special	= &Node -> Special . Level;

					if(ThisTag = FindTagItem(LAVL_Min,TagList))
					{
						Special -> Min = (LONG)ThisTag -> ti_Data;

						ChangeIt = TRUE;
					}

					if(ThisTag = FindTagItem(LAVL_Max,TagList))
					{
						Special -> Max = (LONG)ThisTag -> ti_Data;

						ChangeIt = TRUE;
					}

					if(ThisTag = FindTagItem(LAVL_Level,TagList))
					{
						Special -> Level = (LONG)ThisTag -> ti_Data;

						LTP_PutStorage(Node);

						ChangeIt = TRUE;
					}

					if(Special -> Max < Special -> Min)
						Special -> Max = Special -> Min;

					if(Special -> Level > Special -> Max)
						Special -> Level = Special -> Max;

					if(Special -> Level < Special -> Min)
						Special -> Level = Special -> Min;

					if(ChangeIt && Gadget && handle -> Window)
					{
						LONG Plus = Special -> Plus;

						SetAttrs(Special -> LevelImage,
							LVIA_Current,	Special -> Level	- Plus,
							LVIA_Max,	Special -> Max		- Plus,
						TAG_DONE);

						DrawImageState(&handle -> RPort,Special -> LevelImage,Gadget -> LeftEdge,Gadget -> TopEdge,IDS_NORMAL,handle -> DrawInfo);

						LTP_LevelGadgetDrawLabel(Gadget,FALSE);
					}

					break;
				}
#endif	/* DO_LEVEL_KIND */
				case CHECKBOX_KIND:

					if(ThisTag = FindTagItem(GTCB_Checked,TagList))
					{
						if((Node -> Current && ThisTag -> ti_Data) || (!Node -> Current && !ThisTag -> ti_Data))
							Exclude = GTCB_Checked;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);
						}
					}

					break;

#ifdef DO_TAPEDECK_KIND
				case TAPEDECK_KIND:

					if(ThisTag = FindTagItem(LATD_Pressed,TagList))
					{
						if(Node -> Current != ThisTag -> ti_Data && Node -> Special . TapeDeck . Toggle)
						{
							Node -> Current = ThisTag -> ti_Data;

							if(Gadget)
							{
								RemoveGList(handle -> Window,handle -> List,(UWORD)-1);

								if(Node -> Current)
									Gadget -> Flags |= GFLG_SELECTED;
								else
									Gadget -> Flags &= ~GFLG_SELECTED;

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

					break;
#endif	/* DO_TAPEDECK_KIND */

#ifdef DO_GAUGE_KIND
				case GAUGE_KIND:
				{
					LONG	Percent 	= (LONG)Node -> Current;
					BOOLEAN NeedRefresh	= FALSE;

					if(ThisTag = FindTagItem(LAGA_Percent,TagList))
					{
						Percent = (LONG)ThisTag -> ti_Data;

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

						if(Percent != (LONG)Node -> Current)
							NeedRefresh = TRUE;
					}

					if(ThisTag = FindTagItem(LAGA_InfoText,TagList))
					{
						STRPTR SomeText = (STRPTR)ThisTag -> ti_Data;

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

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

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

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

							NeedRefresh = TRUE;
						}
					}

					if(NeedRefresh && Gadget)
						LTP_DrawGauge(handle,Node,Percent,FALSE);
				}

				return;
#endif
				case LISTVIEW_KIND:

					if(ThisTag = FindTagItem(GTLV_Labels,TagList))
					{
						if(ThisTag -> ti_Data == (ULONG)~0)
							Node -> Min = Node -> Max = -1;
						else
						{
							struct List	*List;
							LONG		 Count = 0;

							if(List = (struct List *)ThisTag -> ti_Data)
							{
								struct Node *Item;

								SCANLIST(List,Item)
								{
									Count++;
								}
							}

							Node -> Min = 0;

							if(Count)
								Node -> Max = Count - 1;
							else
								Node -> Max = 0;
						}

						Node -> Special . List . Labels = (struct List *)ThisTag -> ti_Data;
					}

					if(ThisTag = FindTagItem(GTLV_Selected,TagList))
					{
						struct List *List;

						Node -> Current = (LONG)ThisTag -> ti_Data;

						if(ThisTag = FindTagItem(GTLV_Labels,TagList))
							List = (struct List *)ThisTag -> ti_Data;
						else
							List = NULL;

						if(Gadget)
						{
							Exclude = GTLV_Selected;

							if(Node -> Current < 0)
							{
								GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
									GTLV_Selected,			Node -> Current,
									List ? GTLV_Labels : TAG_IGNORE,List,
								TAG_DONE);
							}
							else
							{
								GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
									GTLV_Selected,			Node -> Current,
									GTLV_Top,			Node -> Current,
									GTLV_MakeVisible,		Node -> Current,

									List ? GTLV_Labels : TAG_IGNORE,List,
								TAG_DONE);
							}
						}

						LTP_PutStorage(Node);
					}

					if(ThisTag = FindTagItem(GA_Disabled,TagList))
					{
						if(!V39)
						{
							if(!(NewTags = CloneTagItems(TagList)))
								return;
							else
								FilterTagItems(NewTags,Filter,TAGFILTER_NOT);
						}
					}

					break;

				case MX_KIND:

					if(ThisTag = FindTagItem(GTMX_Active,TagList))
					{
						if(Node -> Current == ThisTag -> ti_Data)
							Exclude = GTMX_Active;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);

							if(Node -> Special . Radio . AutoPageID != -1)
							{
								LT_SetAttributes(handle,Node -> Special . Radio . AutoPageID,
									LAGR_ActivePage,Node -> Current,
								TAG_DONE);
							}
						}
					}

					if(!V39)
					{
						if(FindTagItem(GA_Disabled,TagList))
						{
							if(!(NewTags = CloneTagItems(TagList)))
								return;
							else
								FilterTagItems(NewTags,Filter,TAGFILTER_NOT);
						}
					}

					break;

				case CYCLE_KIND:

					if(ThisTag = FindTagItem(GTCY_Active,TagList))
					{
						if(Node -> Current == ThisTag -> ti_Data)
							Exclude = GTCY_Active;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);

							if(Node -> Special . Cycle . AutoPageID != -1)
							{
								LT_SetAttributes(handle,Node -> Special . Cycle . AutoPageID,
									LAGR_ActivePage,Node -> Current,
								TAG_DONE);
							}
						}
					}

					if(ThisTag = FindTagItem(GTCY_Labels,TagList))
					{
						STRPTR	*Strings;
						LONG	 Count = 0;

						if(Strings = (STRPTR *)ThisTag -> ti_Data)
						{
							while(Strings[Count])
								Count++;
						}

						if(Count)
							Node -> Max = Count - 1;
						else
							Node -> Max = 0;
					}

					break;

				case PALETTE_KIND:

					if(ThisTag = FindTagItem(GTPA_Color,TagList))
					{
						if(Node -> Current == ThisTag -> ti_Data)
							Exclude = GTPA_Color;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);
						}
					}

					break;

				case INTEGER_KIND:

					if(ThisTag = FindTagItem(GTIN_Number,TagList))
					{
						LONG num = ThisTag -> ti_Data;

						if(num < Node -> Min)
							num = Node -> Min;
						else
						{
							if(num > Node -> Max)
								num = Node -> Max;
						}

						if(Gadget)
						{
#ifdef DO_HEXHOOK
							if(!Node -> Special . Integer . EditHook)
							{
								UBYTE			 buffer[20];
								struct StringInfo	*stringInfo;

								sprintf(buffer,"%ld",num);

								Exclude = GTIN_Number;

								GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
									GTST_String,buffer,
								TAG_DONE);

								stringInfo = (struct StringInfo *)Gadget -> SpecialInfo;

								stringInfo -> LongInt = num;
							}
							else
							{
								UBYTE			 buffer[40];
								struct StringInfo	*stringInfo;
								STRPTR			 Index;
								LONG			 Value,Number = num,
											 Scale,Sign;

								stringInfo = (struct StringInfo *)Gadget -> SpecialInfo;

								Index = stringInfo -> Buffer;

								while(*Index && *Index == ' ')
									Index++;

								switch(Index[0])
								{
									case '$':

										sprintf(buffer,"$%lx",num);
										break;

									case '&':

										if(Number < 0)
										{
											Sign = -1;
											Number = -Number;
										}
										else
											Sign = 1;

										for(Value = 0, Scale = 1 ; Number ; Number /= 8, Scale *= 10)
											Value += (Number & 7) * Scale;

										sprintf(buffer,"&%ld",Sign * Value);
										break;

									case '%':

										if(Number < 0)
										{
											Sign = -1;
											Number = -Number;
										}
										else
											Sign = 1;

										for(Value = 0, Scale = 1 ; Number ; Number /= 2, Scale *= 10)
											Value += (Number & 1) * Scale;

										sprintf(buffer,"%%%ld",Sign * Value);
										break;

									case '0':

										if(Index[1] == 'x')
										{
											sprintf(buffer,"0x%lx",num);
											break;
										}

										// Fall through to...

									default:

										sprintf(buffer,"%ld",num);
										break;
								}

								Exclude = GTIN_Number;

								GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
									GTST_String,buffer,
								TAG_DONE);

								stringInfo -> LongInt = num;
							}
#else
							GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
								GTIN_Number,num,
							TAG_DONE);
#endif
						}

						Node -> Special . Integer . Number = num;

						LTP_PutStorage(Node);
					}

					break;

				case SLIDER_KIND:

					if(ThisTag = FindTagItem(GTSL_Level,TagList))
					{
						if(Node -> Current == ThisTag -> ti_Data)
							Exclude = GTSL_Level;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);
						}
					}

					if(ThisTag = FindTagItem(GTSL_Min,TagList))
					{
						Node -> Min = ThisTag -> ti_Data;

						if(Node -> Current < Node -> Min)
						{
							Node -> Current = Node -> Min;

							LTP_PutStorage(Node);
						}
					}

					if(ThisTag = FindTagItem(GTSL_Max,TagList))
					{
						Node -> Max = ThisTag -> ti_Data;

						if(Node -> Current > Node -> Max)
						{
							Node -> Current = Node -> Max;

							LTP_PutStorage(Node);
						}
					}

					break;

				case SCROLLER_KIND:

					if(ThisTag = FindTagItem(GTSC_Top,TagList))
					{
						if(Node -> Current == ThisTag -> ti_Data)
							Exclude = GTSC_Top;
						else
						{
							Node -> Current = ThisTag -> ti_Data;

							LTP_PutStorage(Node);
						}
					}

					if(ThisTag = FindTagItem(GTSC_Total,TagList))
					{
						Node -> Max = ThisTag -> ti_Data;

						if(Node -> Current > Node -> Max)
						{
							Node -> Current = Node -> Max;

							LTP_PutStorage(Node);
						}
					}

					if(ThisTag = FindTagItem(GTSC_Visible,TagList))
						Node -> Special . Scroller . Visible = ThisTag -> ti_Data;

					break;

				case BOX_KIND:
				{
					BOOLEAN Visible = Node -> Special . Box . Parent -> Special . Group . Visible;

					if(ThisTag = FindTagItem(LABX_Index,TagList))
					{
						LONG Index = ThisTag -> ti_Data;

						if(Index >= 0 && Index < Node -> Lines)
						{
							if(ThisTag = FindTagItem(LABX_Text,TagList))
							{
								if(Node -> Special . Box . ReserveSpace)
								{
									STRPTR	Text = (STRPTR)ThisTag -> ti_Data;
									WORD	Len = strlen(Text);

									if(Len > Node -> Special . Box . MaxSize)
										Len = Node -> Special . Box . MaxSize;

									CopyMem(Text,Node -> Special . Box . Lines[Index],Len);

									Node -> Special . Box . Lines[Index][Len] = 0;
								}
								else
									Node -> Special . Box . Lines[Index] = (STRPTR)ThisTag -> ti_Data;

								if(Visible)
									LTP_PrintBoxLine(handle,Node,Index);
							}
						}
					}

					if(ThisTag = FindTagItem(LABX_Lines,TagList))
					{
						STRPTR	*Lines = (STRPTR *)ThisTag -> ti_Data;
						LONG	 i;

						if(Node -> Special . Box . ReserveSpace)
						{
							WORD Len;

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

									if(Len > Node -> Special . Box . MaxSize)
										Len = Node -> Special . Box . MaxSize;

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

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

									if(Visible)
										LTP_PrintBoxLine(handle,Node,i);
								}
								else
									break;
							}
						}
						else
						{
							for(i = 0 ; i < Node -> Lines ; i++)
							{
								if(Lines[i])
								{
									Node -> Special . Box . Lines[i] = Lines[i];

									if(Visible)
										LTP_PrintBoxLine(handle,Node,i);
								}
								else
									break;
							}
						}
					}

					break;
				}

				case TEXT_KIND:

					if(ThisTag = FindTagItem(GTTX_Text,TagList))
					{
						STRPTR text = (STRPTR)ThisTag -> ti_Data;

						if(!text)
							text = "";

						if(Node -> Special . Text . CopyText)
						{
							LONG len;

							if(Node -> Special . Text . Text)
								len = strlen(Node -> Special . Text . Text) + 1;
							else
								len = 0;

							if(len)
								LTP_Free(handle,Node -> Special . Text . Text,len);

							len = strlen(text);

							if(Node -> Special . Text . Text = LTP_Alloc(handle,len + 1))
								strcpy(Node -> Special . Text . Text,text);
						}
						else
							Node -> Special . Text . Text = text;
					}

					break;

				case GROUP_KIND:

					if(Node -> Special . Group . Paging)
					{
						if(ThisTag = FindTagItem(LAGR_ActivePage,TagList))
						{
							ObjectNode *node;

							node = Node;

//							if(node = LTP_FindNode(handle -> TopGroup,id))
							{
								if(node -> Type == GROUP_KIND)
								{
									if(node -> Special . Group . ActivePage != ThisTag -> ti_Data)
									{
										WORD	Left	= node -> Left,
											Top	= node -> Top,
											Width	= node -> Width,
											Height	= node -> Height;

										if(node -> Label || node -> Special . Group . Frame)
										{
											Left	+= 4 + handle -> GlyphWidth;
											Width	-= 2 * (4 + handle -> GlyphWidth);

											if(node -> Label)
											{
												Top	+= handle -> RPort . TxHeight;
												Height	-= handle -> RPort . TxHeight + 3;
											}
											else
											{
												Top	+= 2;
												Height	-= 5;
											}
										}

										node -> Special . Group . ActivePage = ThisTag -> ti_Data;

										LT_LockWindow(handle -> Window);

										EraseRect(&handle -> RPort,Left,Top,Left + Width - 1,Top + Height - 1);

										LT_RebuildTagList(handle,FALSE,NULL);

										LT_UnlockWindow(handle -> Window);
									}
								}
							}
						}
					}

					break;
			}

			if(ThisTag = FindTagItem(LA_LabelText,TagList))
				Node -> Label = (STRPTR)ThisTag -> ti_Data;

			if(ThisTag = FindTagItem(LA_LabelID,TagList))
			{
				if(handle -> LocaleHook)
					Node -> Label = (STRPTR)CallHookPkt(handle -> LocaleHook,handle,(APTR)ThisTag -> ti_Data);
			}

			if(ThisTag = FindTagItem(GA_Disabled,TagList))
			{
				if((Node -> Disabled && ThisTag -> ti_Data) || (!Node -> Disabled && !ThisTag -> ti_Data))
				{
					if(NewTags = CloneTagItems(TagList))
						FilterTagItems(NewTags,Filter,TAGFILTER_NOT);
				}
				else
				{
					Node -> Disabled = ThisTag -> ti_Data;

					if(Gadget)
					{
						struct Gadget *gad;

						switch(Node -> Type)
						{
#ifdef DO_LEVEL_KIND
							case LEVEL_KIND:

								gad = Gadget;
								break;
#endif	/* DO_LEVEL_KIND */
							case TEXT_KIND:

								gad = Node -> Special . Text . Picker;
								break;

							case STRING_KIND:

								gad = Node -> Special . String . Picker;
								break;

							case INTEGER_KIND:

								if(gad = Node -> Special . Integer . LeftIncrementer)
								{
									RemoveGList(handle -> Window,handle -> List,(UWORD)-1);

									if(Node -> Disabled)
										gad -> Flags |= GFLG_DISABLED;
									else
										gad -> Flags &= ~GFLG_DISABLED;

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

								gad = Node -> Special . Integer . RightIncrementer;
								break;

							case TAPEDECK_KIND:

								gad = Node -> Host;

								Gadget = NULL;

								break;

							default:

								gad = NULL;
								break;
						}

						if(gad)
						{
							RemoveGList(handle -> Window,handle -> List,(UWORD)-1);

							if(Node -> Disabled)
								gad -> Flags |= GFLG_DISABLED;
							else
								gad -> Flags &= ~GFLG_DISABLED;

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

			if(Exclude)
			{
				ULONG Filter[2];

				Filter[0] = Exclude;
				Filter[1] = TAG_DONE;

				if(!NewTags)
					NewTags = CloneTagItems(TagList);

				if(NewTags)
					FilterTagItems(NewTags,Filter,TAGFILTER_NOT);
			}

			if(Gadget)
			{
				struct TagItem *tags = TagList;

				if(NewTags)
					tags = NewTags;

				if(!V39 && Node -> Disabled && Node -> Type == SLIDER_KIND)
				{
					GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
						GA_Disabled,	FALSE,
					TAG_MORE,tags);

					GT_SetGadgetAttrs(Gadget,handle -> Window,NULL,
						GA_Disabled,	TRUE,
					TAG_DONE);
				}
				else
					GT_SetGadgetAttrsA(Gadget,handle -> Window,NULL,tags);

				if(Node -> Type == STRING_KIND || Node -> Type == FRACTION_KIND || Node -> Type == PASSWORD_KIND)
					LTP_PutStorage(Node);
			}

			FreeTagItems(NewTags);
		}
	}
}
