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

#include "gtlayout_global.h"

VOID __regargs
LTP_LayoutGadgets(LayoutHandle *Handle,ObjectNode *Group)
{
	if(!Handle -> Failed)
	{
		STATIC struct TagItem NoUnderscoreVanillaTags[] =
		{
			{TAG_DONE}
		};

		STATIC struct TagItem VanillaTags[] =
		{
			{GT_Underscore, '_'},
			{TAG_DONE}
		};

		STATIC struct TagItem DisabledTags[] =
		{
			{GT_Underscore, '_' },
			{GA_Disabled,	TRUE},
			{TAG_DONE}
		};

		STATIC struct TagItem NoUnderscoreDisabledTags[] =
		{
			{GA_Disabled,	TRUE},
			{TAG_DONE}
		};

		struct NewGadget	 NewGadget;

		struct Gadget		*Gadget,
					*Extra;
		struct TagItem		*Tags;
		ULONG			 page;
		ObjectNode		*Node;

		if(!Handle -> List)
		{
			if(!(Handle -> Previous = CreateContext(&Handle -> List)))
			{
				Handle -> Failed = TRUE;

				return;
			}
		}

		NewGadget . ng_TextAttr   = Handle -> TextAttr;
		NewGadget . ng_VisualInfo = Handle -> VisualInfo;

		Group -> Special . Group . Visible = TRUE;

		SCANPAGE(Group,Node,page)
		{
			if(Node -> Type != FRAME_KIND && Node -> Type != BOX_KIND && Node -> Type != XBAR_KIND && Node -> Type != YBAR_KIND)
			{
				Extra = NULL;

				if(Node -> GroupIndent)
				{
					NewGadget . ng_LeftEdge = Node -> Left + 4;
					NewGadget . ng_TopEdge	= Node -> Top + 2;
					NewGadget . ng_Width	= Node -> Width - (4 + 4);
					NewGadget . ng_Height	= Node -> Height - (2 + 2);
				}
				else
				{
					NewGadget . ng_LeftEdge = Node -> Left;
					NewGadget . ng_TopEdge	= Node -> Top;
					NewGadget . ng_Width	= Node -> Width;
					NewGadget . ng_Height	= Node -> Height;
				}

				NewGadget . ng_GadgetText	= Node -> Label ? Node -> Label : (STRPTR)"";
				NewGadget . ng_GadgetID 	= Node -> ID;
				NewGadget . ng_UserData 	= Node;

				if(Node -> NoKey)
				{
					if(Node -> Disabled)
					{
						if(!V39 && (Node -> Type == MX_KIND || Node -> Type == LISTVIEW_KIND))
							Tags = NoUnderscoreVanillaTags;
						else
							Tags = NoUnderscoreDisabledTags;
					}
					else
						Tags = NoUnderscoreVanillaTags;
				}
				else
				{
					if(Node -> Disabled)
					{
						if(!V39 && (Node -> Type == MX_KIND || Node -> Type == LISTVIEW_KIND))
							Tags = VanillaTags;
						else
							Tags = DisabledTags;
					}
					else
						Tags = VanillaTags;
				}

				switch(Node -> LabelPlace)
				{
					case PLACE_LEFT:

						NewGadget . ng_Flags = PLACETEXT_LEFT;
						break;

					case PLACE_RIGHT:

						NewGadget . ng_Flags = PLACETEXT_RIGHT;
						break;

					case PLACE_ABOVE:

						NewGadget . ng_Flags = PLACETEXT_ABOVE;
						break;

					case PLACE_BELOW:

						NewGadget . ng_Flags = PLACETEXT_BELOW;
						break;

					case PLACE_IN:

						NewGadget . ng_Flags = PLACETEXT_IN;
						break;

					default:

						NewGadget . ng_Flags = NULL;
						break;
				}

				if(Node -> HighLabel)
					NewGadget . ng_Flags |= NG_HIGHLABEL;

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

						if(Node -> Special . Level . LevelImage = NewObject(LTP_LevelClass,NULL,
							IA_Width,	Node -> Width,
							IA_Height,	Node -> Height,
							IA_Left,	0,
							IA_Top, 	0,
							LVIA_DrawInfo,	Handle -> DrawInfo,
							LVIA_FontWidth, Handle -> GlyphWidth,
							LVIA_Max,	Node -> Special . Level . Max	- Node -> Special . Level . Plus,
							LVIA_Current,	Node -> Special . Level . Level - Node -> Special . Level . Plus,
						TAG_DONE))
						{
							NewGadget . ng_GadgetText	= "";
							NewGadget . ng_Flags		= NULL;

							if(Gadget = CreateGadgetA(GENERIC_KIND,Handle -> Previous,&NewGadget,NULL))
							{
								Gadget -> GadgetType	|= GTYP_CUSTOMGADGET;

								Gadget -> Flags 	= GFLG_GADGIMAGE | GFLG_GADGHIMAGE;
								Gadget -> Activation	= GACT_RELVERIFY | GACT_IMMEDIATE | GACT_FOLLOWMOUSE;
								Gadget -> MutualExclude = (ULONG)&Node -> Special . Level . CustomHook;
								Gadget -> GadgetRender	= Node -> Special . Level . LevelImage;
								Gadget -> SelectRender	= Node -> Special . Level . LevelImage;
								Gadget -> SpecialInfo	= &Node -> Special . Level;

								if(Node -> Disabled)
									Gadget -> Flags |= GFLG_DISABLED;
							}
						}

						break;
#endif	/* DO_LEVEL_KIND */
					case BUTTON_KIND:

						Gadget = CreateGadgetA(BUTTON_KIND,Handle -> Previous,&NewGadget,Tags);

						break;

					case GROUP_KIND:

						LTP_LayoutGadgets(Handle,Node);

						continue;

					case CHECKBOX_KIND:

						Gadget = CreateGadget(CHECKBOX_KIND,Handle -> Previous,&NewGadget,
							GTCB_Checked,	Node -> Current,
							GTCB_Scaled,	TRUE,
						TAG_MORE,Tags);

						break;

					case LISTVIEW_KIND:

						if(!Node -> Special . List . ReadOnly && Node -> Special . List . LinkID != -1 && Node -> Special . List . LinkID != NIL_LINK)
							Gadget = Node -> Special . List . Link = LTP_FindGadget(Handle,Node -> Special . List . LinkID);
						else
							Gadget = NULL;

						if((NewGadget . ng_Flags & PLACETEXT_ABOVE) && Node -> Label && Node -> Special . List . FlushLabelLeft)
							NewGadget . ng_GadgetText = "";

						Gadget = CreateGadget(LISTVIEW_KIND,Handle -> Previous,&NewGadget,
							GTLV_Selected,		Node -> Current,
							GTLV_ReadOnly,		Node -> Special . List . ReadOnly,
							GTLV_ScrollWidth,	2 + 2 * Handle -> GlyphWidth + 2,

							Node -> Current >= 0 ?			GTLV_Top:		TAG_IGNORE,Node -> Current,
							Node -> Current >= 0 ?			GTLV_MakeVisible:	TAG_IGNORE,Node -> Current,
							Node -> Special . List . Labels ?	GTLV_Labels:		TAG_IGNORE,Node -> Special . List . Labels,
							Node -> Special . List . LinkID != -1 ? GTLV_ShowSelected:	TAG_IGNORE,Gadget,
							Node -> Special . List . CallBack ?	GTLV_CallBack:		TAG_IGNORE,Node -> Special . List . CallBack,
							Node -> Special . List . MaxPen ?	GTLV_MaxPen:		TAG_IGNORE,Node -> Special . List . MaxPen,
						TAG_MORE,Tags);

						break;

					case MX_KIND:

						NewGadget . ng_Height = Handle -> RPort . TxHeight;

						Gadget = CreateGadget(MX_KIND,Handle -> Previous,&NewGadget,
							GTMX_Labels,	Node -> Special . Radio . Choices,
							GTMX_Active,	Node -> Current,
							GTMX_Spacing,	Handle -> InterHeight,
							GTMX_Scaled,	TRUE,

							Node -> Label ? GTMX_TitlePlace : TAG_IGNORE,  Node -> Special . Radio . TitlePlace,
						TAG_MORE,Tags);

						break;

					case TEXT_KIND:

						if(Node -> Special . Text . UsePicker)
							NewGadget . ng_Width -= (4 + (((6 * Handle -> GlyphWidth) / 4) & ~1) + 1 + 4);

						if(Gadget = CreateGadget(TEXT_KIND,Handle -> Previous,&NewGadget,
							GTTX_Border,		Node -> Special . Text . Border,
							GTTX_Justification,	Node -> Special . Text . Justification,

							Node -> Special . Text . Text ? GTTX_Text : TAG_IGNORE,Node -> Special . Text . Text,
						TAG_MORE,Tags))
						{
							if(Node -> Special . Text . UsePicker)
							{
								Extra = LTP_CreatePicker(Handle,Node,Gadget,&NewGadget);

								if(!Extra)
									Gadget = NULL;

								Node -> Special . Text . Picker = Extra;
							}
						}

						break;
#ifdef DO_GAUGE_KIND
					case GAUGE_KIND:

						NewGadget . ng_Height -= Handle -> InterHeight + Handle -> RPort . TxHeight + 2;

						Gadget = CreateGadgetA(TEXT_KIND,Handle -> Previous,&NewGadget,NULL);

						break;
#endif

#ifdef DO_TAPEDECK_KIND
					case TAPEDECK_KIND:

						if(Node -> Special . TapeDeck . ButtonType >= TDBT_BACKWARD && Node -> Special . TapeDeck . ButtonType < TDBTLAST)
						{
							LONG	ImageType;
							UWORD	Activation,
								Flags;

							if(Node -> Special . TapeDeck . Toggle)
								Activation = GACT_TOGGLESELECT | GACT_IMMEDIATE;
							else
								Activation = GACT_RELVERIFY;

							if(Node -> Current)
								Flags = GFLG_GADGIMAGE | GFLG_GADGHIMAGE | GFLG_SELECTED;
							else
								Flags = GFLG_GADGIMAGE | GFLG_GADGHIMAGE;

							switch(Node -> Special . TapeDeck . ButtonType)
							{
								case TDBT_BACKWARD:

									ImageType = IMAGECLASS_BACKWARD;
									break;

								case TDBT_FORWARD:

									ImageType = IMAGECLASS_FORWARD;
									break;

								case TDBT_PREVIOUS:

									ImageType = IMAGECLASS_PREVIOUS;
									break;

								case TDBT_NEXT:

									ImageType = IMAGECLASS_NEXT;
									break;

								case TDBT_RECORD:

									ImageType = IMAGECLASS_RECORD;
									break;

								case TDBT_PLAY:

									ImageType = IMAGECLASS_PLAY;
									break;

								case TDBT_STOP:

									ImageType = IMAGECLASS_STOP;
									break;

								case TDBT_PAUSE:

									ImageType = IMAGECLASS_PAUSE;
									break;

								case TDBT_REWIND:

									ImageType = IMAGECLASS_REWIND;
									break;

								case TDBT_EJECT:

									ImageType = IMAGECLASS_EJECT;
									break;
							}

							if(Node -> Special . TapeDeck . ButtonImage = NewObject(LTP_ImageClass,NULL,
								IIA_ImageType,	ImageType,
								IIA_GlyphWidth, Node -> Special . TapeDeck . ButtonWidth,
								IIA_GlyphHeight,Node -> Special . TapeDeck . ButtonHeight,
								IA_Width,	NewGadget . ng_Width,
								IA_Height,	NewGadget . ng_Height,
							TAG_DONE))
							{
								NewGadget . ng_GadgetText	= "";
								NewGadget . ng_Flags		= NULL;

								if(Gadget = CreateGadgetA(GENERIC_KIND,Handle -> Previous,&NewGadget,NULL))
								{
									Gadget -> GadgetType	|= GTYP_BOOLGADGET;
									Gadget -> Flags 	|= Flags;
									Gadget -> Activation	|= Activation;

									Gadget -> GadgetRender	 = Node -> Special . TapeDeck . ButtonImage;
									Gadget -> SelectRender	 = Node -> Special . TapeDeck . ButtonImage;

									if(Node -> Disabled)
										Gadget -> Flags |= GFLG_DISABLED;
								}
							}
						}

						break;
#endif	/* DO_TAPEDECK_KIND */
					case NUMBER_KIND:

						Gadget = CreateGadget(NUMBER_KIND,Handle -> Previous,&NewGadget,
							GTNM_Number,		Node -> Special . Number . Number,
							GTNM_Border,		Node -> Special . Number . Border,
							GTNM_Justification,	Node -> Special . Number . Justification,
							GTNM_Border,		Node -> Special . Number . Border,
							GTNM_Justification,	Node -> Special . Number . Justification,
						TAG_MORE,Tags);

						break;

					case CYCLE_KIND:

						Gadget = CreateGadget(CYCLE_KIND,Handle -> Previous,&NewGadget,
							GTCY_Labels,		Node -> Special . Cycle . Choices,
							GTCY_Active,		Node -> Current,
						TAG_MORE,Tags);

						break;

					case PALETTE_KIND:

						Gadget = CreateGadget(PALETTE_KIND,Handle -> Previous,&NewGadget,
							GTPA_Depth,		Node -> Special . Palette . Depth,
							GTPA_Color,		Node -> Current,
							GTPA_ColorOffset,	Node -> Min,
							GTPA_IndicatorWidth,	MAX(10,Node -> Width / (Node -> Max - Node -> Min + 1)),
							GTPA_IndicatorHeight,	Node -> Height,

							Node -> Special . Palette . ColourTable ? GTPA_ColorTable : TAG_IGNORE,Node -> Special . Palette . ColourTable,
						TAG_MORE,Tags);

						break;

					case SLIDER_KIND:

						Gadget = CreateGadget(SLIDER_KIND,Handle -> Previous,&NewGadget,
							GTSL_Min,		Node -> Min,
							GTSL_Max,		Node -> Max,
							GTSL_Level,		Node -> Current,
							GTSL_MaxLevelLen,	Node -> Special . Slider . MaxLevelLen,
							GTSL_LevelPlace,	Node -> Special . Slider . LevelPlace,
							GTSL_LevelFormat,	Node -> Special . Slider . LevelFormat ? Node -> Special . Slider . LevelFormat : (STRPTR)"%ld",
							GA_RelVerify,		TRUE,

							V40 ? GTSL_MaxPixelLen : TAG_IGNORE,	Node -> Special . Slider . LevelWidth,
							V40 ? GTSL_Justification : TAG_IGNORE,	GTJ_RIGHT,
							Node -> Special . Slider . DispFunc ? GTSL_DispFunc : TAG_IGNORE,Node -> Special . Slider . DispFunc,
						TAG_MORE,Tags);

						break;

					case SCROLLER_KIND:

						Gadget = CreateGadget(SCROLLER_KIND,Handle -> Previous,&NewGadget,
							GA_RelVerify,	Node -> Special . Scroller . RelVerify,
							GA_Immediate,	Node -> Special . Scroller . Immediate,
							GTSC_Top,	Node -> Current,
							GTSC_Total,	Node -> Max,
							GTSC_Visible,	Node -> Special . Scroller . Visible,
							PGA_Freedom,	Node -> Special . Scroller . Vertical ? LORIENT_VERT : LORIENT_HORIZ,

							Node -> Special . Scroller . Arrows ? GTSC_Arrows : TAG_IGNORE,Node -> Special . Scroller . ArrowSize,
						TAG_MORE,Tags);

						break;

					case STRING_KIND:

						if(Node -> Special . String . LinkID != -1)
						{
							ObjectNode *ListView = LTP_FindNode(Handle -> TopGroup,Node -> Special . String . LinkID);

							if(ListView)
							{
								NewGadget . ng_LeftEdge = ListView -> Left;
								NewGadget . ng_TopEdge	= ListView -> Top + ListView -> Height;
								NewGadget . ng_Width	= ListView -> Width;
							}
						}

						if(Node -> Special . String . UsePicker)
							NewGadget . ng_Width -= (4 + (((6 * Handle -> GlyphWidth) / 4) & ~1) + 1 + 4);

						if(Gadget = CreateGadget(STRING_KIND,Handle -> Previous,&NewGadget,
							GTST_String,		Node -> Special . String . String,
							GTST_MaxChars,		Node -> Special . String . MaxChars,
							GTST_EditHook,		Node -> Special . String . EditHook ? Node -> Special . String . EditHook : Handle -> StandardEditHook,
							GA_Immediate,		TRUE,
							STRINGA_Justification,	Node -> Special . String . Justification,
							STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
						TAG_MORE,Tags))
						{
							if(!V39)
								Gadget -> Activation |= GACT_IMMEDIATE;

							if(Node -> Special . String . UsePicker)
							{
								Extra = LTP_CreatePicker(Handle,Node,Gadget,&NewGadget);

								if(!Extra)
									Gadget = NULL;

								Node -> Special . String . Picker = Extra;
							}
						}

						break;
#ifdef DO_FRACTION_KIND
					case FRACTION_KIND:

						if(Node -> Special . String . LinkID != -1)
						{
							ObjectNode *ListView = LTP_FindNode(Handle -> TopGroup,Node -> Special . String . LinkID);

							if(ListView)
							{
								NewGadget . ng_LeftEdge = ListView -> Left;
								NewGadget . ng_TopEdge	  = ListView -> Top + ListView -> Height;
								NewGadget . ng_Width	  = ListView -> Width;
							}
						}

						/* ALWAYS */
						{
							UBYTE LocalBuffer[20];

							sprintf(LocalBuffer,"%ld%lc%ld",Node -> Current / FIXED_UNITY,LTP_Locale ? LTP_Locale -> loc_DecimalPoint[0] : '.',Node -> Current % FIXED_UNITY);

							if(Gadget = CreateGadget(STRING_KIND,Handle -> Previous,&NewGadget,
								GTST_String,		LocalBuffer,
								GTST_MaxChars,		Node -> Special . String . MaxChars > 12 ? 12 : Node -> Special . String . MaxChars,
								GTST_EditHook,		&Handle -> FracEditHook,
								GA_Immediate,		TRUE,
								STRINGA_Justification,	Node -> Special . String . Justification,
								STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
							TAG_MORE,Tags))
							{
								if(!V39)
									Gadget -> Activation |= GACT_IMMEDIATE;
							}
						}

						break;
#endif

#ifdef DO_PASSWORD_KIND
					case PASSWORD_KIND:
					{
						WORD Len;

						if(Len = strlen(Node -> Special . String . Original))
							memset(Node -> Special . String . Original,'·',Len);

						if(Gadget = CreateGadget(STRING_KIND,Handle -> Previous,&NewGadget,
							GTST_String,		Node -> Special . String . Original,
							GTST_MaxChars,		Node -> Special . String . MaxChars,
							GTST_EditHook,		&Handle -> PasswordEditHook,
							GA_Immediate,		TRUE,
							STRINGA_Justification,	Node -> Special . String . Justification,
							STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
						TAG_MORE,Tags))
						{
							if(!V39)
								Gadget -> Activation |= GACT_IMMEDIATE;
						}

						if(Len)
							strcpy(Node -> Special . String . Original,Node -> Special . String . RealString);

						break;
					}
#endif

					case INTEGER_KIND:

						if(Node -> Special . Integer . UseIncrementers)
						{
							NewGadget . ng_Width -= 4 + Handle -> GlyphWidth + 4;
							NewGadget . ng_Width -= 4 + Handle -> GlyphWidth + 4;

							if(Node -> Special . Integer . IncrementerHook)
							{
								LONG Value;

								Value = (LONG)CallHookPkt(Node -> Special . Integer . IncrementerHook,(APTR)Node -> Special . Integer . Number,(APTR)INCREMENTERMSG_INITIAL);

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

								Node -> Special . Integer . Number = Value;
							}
						}

#ifndef DO_HEXHOOK
						Gadget = CreateGadget(INTEGER_KIND,Handle -> Previous,&NewGadget,
							GTIN_Number,		Node -> Special . Integer . Number,
							GTIN_MaxChars,		Node -> Special . Integer . MaxChars,
							GTIN_EditHook,		Node -> Special . Integer . EditHook ? Node -> Special . Integer . EditHook : Handle -> StandardEditHook,
							GA_Immediate,		TRUE,
							STRINGA_Justification,	Node -> Special . Integer . Justification,
							STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
						TAG_MORE,Tags);
#else
						if(Node -> Special . Integer . EditHook)
						{
							Gadget = CreateGadget(INTEGER_KIND,Handle -> Previous,&NewGadget,
								GTIN_Number,		Node -> Special . Integer . Number,
								GTIN_MaxChars,		Node -> Special . Integer . MaxChars,
								GTIN_EditHook,		Node -> Special . Integer . EditHook,
								GA_Immediate,		TRUE,
								STRINGA_Justification,	Node -> Special . Integer . Justification,
								STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
							TAG_MORE,Tags);
						}
						else
						{
							UBYTE LocalBuffer[20];

							sprintf(LocalBuffer,"%ld",Node -> Special . Integer . Number);

							Gadget = CreateGadget(STRING_KIND,Handle -> Previous,&NewGadget,
								GTST_String,		LocalBuffer,
								GTST_MaxChars,		Node -> Special . Integer . MaxChars,
								GTST_EditHook,		&Handle -> HexEditHook,
								GA_Immediate,		TRUE,
								STRINGA_Justification,	Node -> Special . Integer . Justification,
								STRINGA_ExitHelp,	Handle -> HelpHook != NULL,
							TAG_MORE,Tags);
						}

						if(Gadget)
						{
							struct StringInfo *StringInfo = (struct StringInfo *)Gadget -> SpecialInfo;

							StringInfo -> LongInt = Node -> Special . Integer . Number;
						}
#endif

						if(Gadget)
						{
							if(!V39)
								Gadget -> Activation |= GACT_IMMEDIATE;

							if(Node -> Special . Integer . UseIncrementers)
							{
								Handle -> Previous = Gadget;

								if(Node -> Special . Integer . LeftIncrementer = LTP_CreateIncrementer(Handle,Node,Gadget,&NewGadget,TRUE,-1))
								{
									Handle -> Previous = Node -> Special . Integer . LeftIncrementer;

									if(Node -> Special . Integer . RightIncrementer = LTP_CreateIncrementer(Handle,Node,Gadget,&NewGadget,FALSE,1))
										Extra = Node -> Special . Integer . RightIncrementer;
									else
										Gadget = NULL;
								}
								else
									Gadget = NULL;
							}
						}

						break;
				}

				if(Gadget)
				{
					Handle -> GadgetArray[Handle -> Index++] = Gadget;

					if(Extra)
						Handle -> Previous = Extra;
					else
						Handle -> Previous = Gadget;

					Node -> Host = Gadget;
				}
				else
				{
					Handle -> Failed = TRUE;

					return;
				}
			}
		}
	}
}
