#include <classes/Libraries/GadTools.h>

#include <exec/libraries.h>

#pragma -
#include <pragma/gadtools_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/layers_lib.h>
#pragma +

extern struct Library *GadToolsBase;

VisualInfoC::VisualInfoC()
{
	vi = NULL;
}

VisualInfoC::VisualInfoC(ScreenC &s)
{
	vi = NULL;
	getInfo(s);
}

VisualInfoC::VisualInfoC(WindowC &w)
{
	vi = NULL;
	getInfo(w);
}

VisualInfoC::VisualInfoC(const VisualInfoC &s)
{
	vi = NULL;
}

VisualInfoC::~VisualInfoC()
{
	freeInfo();
}

VisualInfoC &VisualInfoC::operator= (const VisualInfoC &s)
{
	if (this != &s)
	{
		freeInfo();
		vi = NULL;
	};
	return *this;
}

VOID VisualInfoC::getInfo(ScreenC &s)
{
	freeInfo();
	if (!s.screen())
		throw VisualInfoX();
	if (!(vi = GetVisualInfo(s.screen(),TAG_END)))
		throw VisualInfoX();
}

VOID VisualInfoC::getInfo(WindowC &w)
{
	freeInfo();
	if (!w.window())
		throw VisualInfoX();
	if (!(vi = GetVisualInfo(w.window()->WScreen,TAG_END)))
		throw VisualInfoX();
}

VOID VisualInfoC::freeInfo()
{
	if (vi)
	{
		FreeVisualInfo(vi);
		vi = NULL;
	};
}

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

MenuItemC::MenuItemC(STRPTR name, const MenuEventC *event,
	STRPTR short_key,	BOOL disabled, BOOL checkmark, BOOL checked)
{
	const struct NewMenu n = { NM_ITEM,name,short_key,
		(disabled ? NM_ITEMDISABLED : 0)|(checkmark ? CHECKIT|MENUTOGGLE : 0)|
		(checked ? CHECKED : 0), 0, (APTR) event };
	newmenu = n;
}

VOID MenuItemC::rebuild(gen_arraylist &l)
{
	(struct NewMenu &) l.addTail() = newmenu;
}

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

MenuSeperatorC::MenuSeperatorC()
	: MenuItemC(NM_BARLABEL)
{
}

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

MenuSubtitleC::MenuSubtitleC(STRPTR name, const MenuEventC *event,
	BOOL disabled)
	: MenuItemC(name,event,NULL,disabled)
{
}

VOID MenuSubtitleC::add(MenuItemC &m)
{
	addTail(m);
}

VOID MenuSubtitleC::rebuild(gen_arraylist &l)
{
	MenuItemC::rebuild(l);
	ListCursorC lc(*this);
	while (!lc.isDone()) {
		((MenuItemC *) lc.item())->rebuild(l);
		lc.next();
	};
}

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

MenuTitleC::MenuTitleC(STRPTR name, const MenuEventC *event,
	BOOL disabled)
{
	struct NewMenu n = { NM_TITLE, name, NULL,
		(disabled ? NM_MENUDISABLED : 0), 0, (APTR) event };
	newmenu = n;
}

VOID MenuTitleC::add(MenuItemC &m)
{
	addTail(m);
}

VOID MenuTitleC::rebuild(gen_arraylist &l)
{
	(struct NewMenu &) l.addTail() = newmenu;
	ListCursorC lc(*this);
	while (!lc.isDone()) {
		((MenuItemC *) lc.item())->rebuild(l);
		lc.next();
	};
}

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

MenuC::MenuC(VisualInfoC &vi)
	: newmenu(sizeof(struct NewMenu))
{
	strip = NULL;
	layouted = FALSE;
	visualinfo = &vi;
}

MenuC::~MenuC()
{
	FreeMenus(strip);
}

VOID MenuC::add(MenuTitleC &m)
{
	addTail(m);
}

BOOL MenuC::layout(Tag tag1type, ...)
{
	return layout((struct TagItem *) &tag1type);
}

BOOL MenuC::layout(struct TagItem *tags)
{
	if (visualinfo->visualInfo() != NULL)
	{
		newmenu.clear();
		ListCursorC lc(*this);
		while (!lc.isDone()) {
			((MenuTitleC *) lc.item())->rebuild(newmenu);
			lc.next();
		};
		struct NewMenu n = {NM_END, NULL, NULL, 0, 0, NULL };
		(struct NewMenu &) newmenu.addTail() = n;
		if (!(strip = CreateMenus(&((struct NewMenu &) (newmenu.operator[](0))),
				TAG_MORE, tags)))
			return FALSE;
		return layouted = LayoutMenus(strip,visualinfo->visualInfo(),
			TAG_MORE, tags);
	};
	return FALSE;
}

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

MenuEventHandlerC::MenuEventHandlerC(MenuC &m, ULONG IDCMPclass)
	: IDCMPEventHandlerC(IDCMPclass)
{
	menu = &m;
}

MenuEventHandlerC::~MenuEventHandlerC()
{
}

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

MenuPickHandlerC::MenuPickHandlerC(MenuC &m)
	: MenuEventHandlerC(m,IDCMP_MENUPICK)
{
	_exit = FALSE;
}

MenuPickHandlerC::~MenuPickHandlerC()
{
}

BOOL MenuPickHandlerC::_handle(IntuiMessageC &msg)
{
	UWORD menuNumber = msg.Code;
	while (menuNumber != MENUNULL)
	{
		struct MenuItem *item = ItemAddress(menu->menu(),menuNumber);
		MenuEventC *event = (MenuEventC *) (GTMENUITEM_USERDATA(item));
		if (event)
		{
			if (event->pick((WindowC *) msg.IDCMPWindow->UserData,menu,&msg))
			{
				_exit = TRUE;
				return TRUE;
			};
		};
		menuNumber = item->NextSelect;
	};
	return TRUE;
}

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

MenuHelpHandlerC::MenuHelpHandlerC(MenuC &m)
	: MenuEventHandlerC(m,IDCMP_MENUHELP)
{
}

MenuHelpHandlerC::~MenuHelpHandlerC()
{
}

static struct Menu *MenuAddress(struct Menu *strip, UWORD number)
{
	UWORD menunum = MENUNUM(number);
	if (menunum == NOMENU)
		return NULL;
	UWORD i = 0;
	while ((strip != NULL) && (i < menunum))
	{
		i++;
		strip = strip->NextMenu;
	};
	return strip;
}

BOOL MenuHelpHandlerC::_handle(IntuiMessageC &msg)
{
	int menuNumber = msg.Code;
	MenuEventC *event = NULL;
	if (ITEMNUM(menuNumber) != NOITEM)
	{
		struct MenuItem *item = ItemAddress(menu->menu(),menuNumber);
		if (item)
			event = (MenuEventC *) GTMENUITEM_USERDATA(item);
	}
	else if (MENUNUM(menuNumber) != NOMENU)
	{
		struct Menu *menutitle = MenuAddress(menu->menu(),menuNumber);
		if (menutitle)
			event = (MenuEventC *) (GTMENU_USERDATA(menutitle));
	};
	if (event)
	{
		event->help((WindowC *) msg.IDCMPWindow->UserData,menu,&msg);
	};
	return TRUE;
}

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

BOOL GTIDCMPortC::handle(ULONG)
{
	if (port())
	{
		MessageC *msg;
		while (msg = (MessageC *) GT_GetIMsg(port()))
		{
			if (handleMsg(*msg))
				return TRUE;
		};
	};
	return FALSE;
}

BOOL GTIDCMPortC::handleMsg(MessageC &msg)
{
	ListCursorC lc(*this);
	BOOL r = FALSE;
	imsg = (IntuiMessageC &) msg;
	if ((imsg.Class & (IDCMP_SIZEVERIFY|IDCMP_MENUVERIFY|IDCMP_REQVERIFY)) == 0)
		GT_ReplyIMsg((struct IntuiMessage *) &msg);
	while (!lc.isDone()) {
		MessageHandlerC *h = (MessageHandlerC *) lc.item();
		if (h->forMe(imsg))
		{
			if (h->handle(imsg))
			{
				BOOL b = h->exit();
				r = r | b;
			};
		};
		lc.next();
	};
	if ((imsg.Class & (IDCMP_SIZEVERIFY|IDCMP_MENUVERIFY|IDCMP_REQVERIFY)) != 0)
		GT_ReplyIMsg((struct IntuiMessage *) &msg);
	return r;
}

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

GTWindowC::GTWindowC(GTIDCMPortC &p, Tag tag1Type, ...)
	: WindowC(p,(struct TagItem *) &tag1Type)
{
}

GTWindowC::GTWindowC(GTIDCMPortC &p, struct TagItem *tags)
	: WindowC(p,tags)
{
}

GTWindowC::~GTWindowC()
{
}

VOID GTWindowC::open(struct TagItem *tagList)
{
	WindowC::open(tagList);
	GT_RefreshWindow(window(),NULL);
}

VOID GTWindowC::refreshGadgets()
{
	WindowC::refreshGadgets();
	if (window())
		GT_RefreshWindow(window(),NULL);
}

VOID GTWindowC::beginRefresh()
{
	if (window())
		GT_BeginRefresh(window());
}

VOID GTWindowC::endRefresh(BOOL Complete)
{
	if (window())
		GT_EndRefresh(window(),Complete);
}

VOID GTWindowC::refreshFrame()
{
	WindowC::refreshFrame();
	if (window())
		GT_RefreshWindow(window(),NULL);
}

VOID GTWindowC::freeIDCMP()
{
	Forbid();
	MsgPort *idcmport = window()->UserPort;
	struct IntuiMessage *msg;
	struct Node *succ;
	if (idcmport)
	{
		msg = (struct IntuiMessage *) idcmport->mp_MsgList.lh_Head;
		while (succ = msg->ExecMessage.mn_Node.ln_Succ)
		{
			if (msg->IDCMPWindow == window())
			{
				Remove((struct Node *) msg);
				ReplyMsg((struct Message *) msg);
			}
			msg = (IntuiMessage *) succ;
		};
	};
	window()->UserPort = NULL;
	ModifyIDCMP(window(),0);
	Permit();
}

// ***********************************************************
GTWindowRefreshHandlerChainC::GTWindowRefreshHandlerChainC(GTWindowC &w)
		: WindowRefreshHandlerChainC(w)
{
	gtwindow = &w;
}

BOOL GTWindowRefreshHandlerChainC::handle(MessageC &msg)
{
	LockLayerInfo(&window()->window()->WScreen->LayerInfo);
	gtwindow->beginRefresh();
	WindowEventHandlerChainC::handle(msg);
	gtwindow->endRefresh(TRUE);
	UnlockLayerInfo(&window()->window()->WScreen->LayerInfo);
	return TRUE;
}

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

#define PLACETEXT_MASK (PLACETEXT_LEFT|PLACETEXT_RIGHT|PLACETEXT_ABOVE|PLACETEXT_BELOW|PLACETEXT_IN)

GTGadgetC::GTGadgetC(GadgetEventC *ev, ULONG kind,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, ULONG defaultplace,
		const TextAttrC *tattr, UWORD id, struct TagItem *taglist)
	: GadgetC(ev), tags(taglist)
{
	gadgetkind = kind;
	ngadget.ng_LeftEdge = LeftEdge;
	ngadget.ng_TopEdge = TopEdge;
	ngadget.ng_Width = Width;
	ngadget.ng_Height = Height;
	ngadget.ng_GadgetText = label;
	if (!(flags & PLACETEXT_MASK))
		flags |= defaultplace;
	ngadget.ng_Flags = flags;
	ngadget.ng_TextAttr = (struct TextAttr *) tattr;
	ngadget.ng_GadgetID = id;
	ngadget.ng_UserData = (APTR) (GadgetC *) this;
	leftB = 0;
	rightB = 0;
	topB = 0;
	bottomB = 0;
	labelWidth = 0;
	privtattr = tattr != NULL;
	if (!tags.find(GT_Underscore))
	{
		tags.append(GT_Underscore,'_',TAG_END);
	};
}

GTGadgetC::GTGadgetC(GadgetEventC *ev, ULONG kind,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, ULONG defaultplace,
		const TextAttrC *tattr, UWORD id, Tag tag1type, ...)
	: GadgetC(ev), tags((struct TagItem *) &tag1type)
{
	gadgetkind = kind;
	ngadget.ng_LeftEdge = LeftEdge;
	ngadget.ng_TopEdge = TopEdge;
	ngadget.ng_Width = Width;
	ngadget.ng_Height = Height;
	ngadget.ng_GadgetText = label;
	if (!(flags & PLACETEXT_MASK))
		flags |= defaultplace;
	ngadget.ng_Flags = flags;
	ngadget.ng_TextAttr = (struct TextAttr *) tattr;
	ngadget.ng_GadgetID = id;
	ngadget.ng_UserData = (APTR) (GadgetC *) this;
	leftB = 0;
	rightB = 0;
	topB = 0;
	bottomB = 0;
	labelWidth = 0;
	privtattr = tattr != NULL;
	if (!tags.find(GT_Underscore))
	{
		tags.append(GT_Underscore,'_',TAG_END);
	};
}

GTGadgetC::~GTGadgetC()
{
}

struct Gadget *GTGadgetC::rebuild(struct Gadget *prev)
{
	if (!prev)
		return NULL;
	if (!vi->isValid())
		return NULL;
	ngadget.ng_VisualInfo = vi->visualInfo();
	return gadget_ob = CreateGadgetA(gadgetkind,prev,&ngadget,tags.tags());
}

VOID GTGadgetC::erase(WindowC *w)
{
	if (w && gadget_ob)
	{
		if (w->rastPort())
			EraseRect(w->rastPort(),
				ngadget.ng_LeftEdge-leftB,
				ngadget.ng_TopEdge-topB,
				ngadget.ng_LeftEdge+ngadget.ng_Width+rightB-1,
				ngadget.ng_TopEdge+ngadget.ng_Height+bottomB-1)
	};
}

VOID GTGadgetC::setLeft(WORD left)
{
	ngadget.ng_LeftEdge = left;
}

VOID GTGadgetC::setTop(WORD top)
{
	ngadget.ng_TopEdge = top;
}

VOID GTGadgetC::setWidth(WORD width)
{
	ngadget.ng_Width = width;
	leftB = 0;
	rightB = 0;
	if (label() && textAttr())
	{
		if (labelWidth <= 0)
		{
			IntuiText l;
			l.ITextFont = (struct TextAttr *) textAttr();
			l.IText = label();
			labelWidth = IntuiTextLength(&l);
		};
		if (ngadget.ng_Flags & PLACETEXT_LEFT)
			leftB = labelWidth + 8;
		if (ngadget.ng_Flags & PLACETEXT_RIGHT)
			rightB = labelWidth + 7;
		if (ngadget.ng_Flags & (PLACETEXT_ABOVE|PLACETEXT_BELOW))
		{
			/* register */ WORD db = labelWidth-ngadget.ng_Width-leftB-rightB;
			if (db > 0)
			{
				leftB += (db+1) >> 1;
				rightB += db >> 1;
			};
		};
	};
}

VOID GTGadgetC::setHeight(WORD height)
{
	ngadget.ng_Height = height;
	topB = 0;
	bottomB = 0;
	if (textAttr() && label())
	{
		WORD lheight = ((struct TextAttr *) textAttr())->ta_YSize;
		if (ngadget.ng_Flags & PLACETEXT_ABOVE)
			topB = lheight + 4;
		if (ngadget.ng_Flags & PLACETEXT_BELOW)
			bottomB = lheight + 4;
		if (ngadget.ng_Flags & (PLACETEXT_LEFT|PLACETEXT_RIGHT))
		{
			/* register */ WORD db = lheight-ngadget.ng_Height - topB - bottomB;
			if (db > 0)
			{
				topB += (db + 1) >> 1;
				bottomB += db >> 1;
			};
		};
	};
}

BOOL GTGadgetC::disable(BOOL value)
{
	setAttrs(GA_Disabled,value,TAG_END);
	return TRUE;
}

BOOL GTGadgetC::isDisabled()
{
	if (gadget_ob)
		return (gadget_ob->Flags & GFLG_DISABLED) != 0;
	return FALSE;
}

VOID GTGadgetC::setTextAttr(const TextAttrC *tattr)
{
	ngadget.ng_TextAttr = (struct TextAttr *) tattr;
	privtattr = tattr != NULL;
	labelWidth = 0;
	calcBorders();
};

VOID GTGadgetC::setDefTextAttr(const TextAttrC *tattr)
{
	if ((!ngadget.ng_TextAttr) || (!privtattr))
	{
		ngadget.ng_TextAttr = (struct TextAttr *) tattr;
	};
	labelWidth = 0;
	calcBorders();
};

VOID GTGadgetC::setAttrs(struct TagItem *taglist)
{
	if (gadget_ob && window && window->window())
		GT_SetGadgetAttrsA(gadget_ob,window->window(),NULL,taglist);
	tags.set(taglist);
}

VOID GTGadgetC::setAttrs(Tag tag1Type, ...)
{
	if (gadget_ob && window && window->window())
		GT_SetGadgetAttrsA(gadget_ob,window->window(),
			NULL,(struct TagItem *) &tag1Type);
	tags.set((struct TagItem *) &tag1Type);
}

LONG GTGadgetC::getAttrs(struct TagItem *taglist)
{
	if (GadToolsBase->lib_Version >= 39)
	{
		if (gadget_ob && window && window->window())
			return GT_GetGadgetAttrsA(gadget_ob,window->window(),NULL,taglist);
	};
	LONG tagcounter = 0;
	while (taglist != NULL)
	{
		ULONG *toData = (ULONG *) taglist->ti_Data;
		if (toData)
		{
			struct TagItem *tag = FindTagItem(taglist->ti_Tag,tags.tags());
			if (tag)
			{
				*toData = tag->ti_Data;
				tagcounter++;
			};
		};
		taglist++;
	};
	return tagcounter;
}

LONG GTGadgetC::getAttrs(Tag tag1type, ...)
{
	return getAttrs((struct TagItem *) &tag1type);
}

ULONG GTGadgetC::labelPlace()
{
	return ngadget.ng_Flags & PLACETEXT_MASK;
}

VOID GTGadgetC::calcBorders()
{
	ULONG place = ngadget.ng_Flags & PLACETEXT_MASK;
	leftB = 0;
	rightB = 0;
	topB = 0;
	bottomB = 0;
	if (label() && textAttr())
	{
		if (labelWidth <= 0)
		{
			IntuiText l;
			l.ITextFont = (struct TextAttr *) textAttr();
			l.IText = label();
			labelWidth = IntuiTextLength(&l);
		};
		WORD lheight = ((struct TextAttr *) textAttr())->ta_YSize;
		if (place & PLACETEXT_LEFT)
			leftB = labelWidth+8;
		if (place & PLACETEXT_RIGHT)
			rightB = labelWidth+7;
		if (place & PLACETEXT_ABOVE)
			topB = lheight+4;
		if (place & PLACETEXT_BELOW)
			bottomB = lheight+4;
		if (place & (PLACETEXT_LEFT|PLACETEXT_RIGHT))
		{
			/* register */ WORD db = lheight-ngadget.ng_Height-topB-bottomB;
			if (db > 0)
			{
				topB += (db+1) >> 1;
				bottomB += db >> 1;
			};
		};
		if (place & (PLACETEXT_ABOVE|PLACETEXT_BELOW))
		{
			/* register */ WORD db = labelWidth-ngadget.ng_Width-leftB-rightB;
			if (db > 0)
			{
				leftB += (db+1) >> 1;
				rightB += db >> 1;
			};
		};
	};
}

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

GTGadgetListC::GTGadgetListC(
	const TextAttrC &tattr, VisualInfoC &vinfo, GTWindowC &w)
{
	textattr = (TextAttrC *) &tattr;
	vi = &vinfo;
	window = &w;
	lastGadget = NULL;
}

GTGadgetListC::~GTGadgetListC()
{
	if (lastGadget)
		lastGadget->NextGadget = NULL;
	FreeGadgets(gadget_ob);
}

VOID GTGadgetListC::add(GTGadgetC &g)
{
	g.vi = vi;
	g.window = window;
	g.setDefTextAttr(textattr);
	GadgetListC::add(g);
}

struct Gadget *GTGadgetListC::rebuild(struct Gadget *prev)
{
	ListCursorC lc(*this);
	lc.last();
	while (!lc.isDone()) {
		((GadgetC *) lc.item())->free();
		lc.prev();
	};
	if (lastGadget)
		lastGadget->NextGadget = NULL;
	FreeGadgets(gadget_ob);
	lastGadget = NULL;
	gadget_ob = NULL;
	if (!prev)
		return NULL;
	struct Gadget *p = CreateContext(&gadget_ob);
	if (p)
	{
		prev->NextGadget = gadget_ob;
		prev = p;
		lc.last();
		while (!lc.isDone()) {
			if (!((GadgetC *) lc.item())->textAttr())
				((GadgetC *) lc.item())->setDefTextAttr(textattr);
			if (!(prev = ((GadgetC *) lc.item())->rebuild(prev)))
			{
				FreeGadgets(gadget_ob);
				gadget_ob = NULL;
				return NULL;
			};
			lc.prev();
		};
		lastGadget = prev;
		return prev;
	};
	return NULL;
}

VOID GTGadgetListC::setTextAttr(const TextAttrC *tattr)
{
	if (tattr)
	{
		textattr = (TextAttrC *) tattr;
		ListCursorC lc(*this);
		while (!lc.isDone())
		{
			((GadgetC *) lc.item())->setDefTextAttr(textattr);
			lc.next();
		};
	};
}

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

GTAnchorGadgetListC::GTAnchorGadgetListC(const TextAttrC &t,
		VisualInfoC &v, GTWindowC &w)
	: GTGadgetListC(t,v,w)
{
}

GTAnchorGadgetListC::~GTAnchorGadgetListC()
{
}

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

GTRootGadgetListC::GTRootGadgetListC(GTWindowC &w,
	const TextAttrC &tattr, VisualInfoC &vinfo)
	: glist(tattr,vinfo,w)
{
	window = &w;
	w.setGadgetList(glist);
}

GTRootGadgetListC::~GTRootGadgetListC()
{
	window->clearGadgetList();
}

VOID GTRootGadgetListC::add(GTGadgetC &g)
{
	glist.add(g);
}

VOID GTRootGadgetListC::rebuild(BOOL refresh)
{
	window->clearGadgetList(FALSE,FALSE);
	struct Gadget first;
	glist.rebuild(&first);
	window->addIDCMP(glist.idcmp());
	window->resetGadgetList(refresh);
}

VOID GTRootGadgetListC::erase()
{
	window->clearGadgetList();
	glist.erase(window);
}

VOID GTRootGadgetListC::refresh()
{
	glist.refresh(window);
}

VOID GTRootGadgetListC::setTextAttr(const TextAttrC *tattr)
{
	glist.setTextAttr(tattr);
}

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

GTButtonC::GTButtonC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,BUTTON_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_IN,tattr,id,taglist),
	  GButtonC()
{
}

GTButtonC::GTButtonC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,BUTTON_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_IN,tattr,id,
		(struct TagItem *) &tag1Type),
	  GButtonC()
{
}

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

GTStringC::GTStringC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,STRING_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GStringC()
{
}

GTStringC::GTStringC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,STRING_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GStringC()
{
}

VOID GTStringC::free()
{
	if (gadget_ob)
	{
		str = get();
		taglist()->set(GTST_String,(STRPTR) str,TAG_END);
	};
}

VOID GTStringC::set(STRPTR s)
{
	setAttrs(GTST_String,s,TAG_END);
}

STRPTR GTStringC::get()
{
	if (gadget_ob)
		return (STRPTR) ((struct StringInfo *) gadget_ob->SpecialInfo)->Buffer;
	return NULL;
}

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

GTIntegerC::GTIntegerC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,INTEGER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GIntegerC()
{
}

GTIntegerC::GTIntegerC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,INTEGER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GIntegerC()
{
}

VOID GTIntegerC::free()
{
	if (gadget_ob)
		taglist()->set(GTIN_Number,get(),TAG_END);
}

VOID GTIntegerC::set(LONG integer)
{
	setAttrs(GTIN_Number,integer,TAG_END);
}

LONG GTIntegerC::get()
{
	if (gadget_ob)
		return ((struct StringInfo *) gadget_ob->SpecialInfo)->LongInt;
}

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

GTCheckboxC::GTCheckboxC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,CHECKBOX_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GCheckboxC()
{
}

GTCheckboxC::GTCheckboxC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,CHECKBOX_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GCheckboxC()
{
}

VOID GTCheckboxC::free()
{
	if (gadget_ob)
		taglist()->set(GTCB_Checked,checked(),TAG_END);
}

VOID GTCheckboxC::check(BOOL value)
{
	setAttrs(GTCB_Checked,value,TAG_END);
}

BOOL GTCheckboxC::checked()
{
	if (gadget_ob)
		return (gadget_ob->Flags & GFLG_SELECTED) != 0;
	return FALSE;
}

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

VOID GTRadioEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((struct GTRadioC *) g)->setAttrs(GTMX_Active,msg->Code,TAG_END);
}

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

GTRadioC::GTRadioC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		stringarray &buttonLabels,
		STRPTR label, ULONG flags, ULONG place, const TextAttrC *tattr,
		UWORD id, struct TagItem *tags)
	: GTGadgetC(event,MX_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags & (~PLACETEXT_MASK),0,tattr,id,tags),
	  GRadioC(),
	  labels(buttonLabels)
{
	labelsplace = place & (PLACETEXT_LEFT|PLACETEXT_RIGHT);
	if (!labelsplace)
		labelsplace = PLACETEXT_LEFT;
	struct TagItem *l = taglist()->find(GTMX_Labels);
	if (l)
		l->ti_Data = (ULONG) labels.strings()
	else
		taglist()->append(GTMX_Labels,(ULONG) labels.strings(),TAG_END);
}

GTRadioC::GTRadioC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		stringarray &buttonLabels,
		STRPTR label, ULONG flags, ULONG place, const TextAttrC *tattr,
		UWORD id, Tag tag1Type, ...)
	: GTGadgetC(event,MX_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags & (~PLACETEXT_MASK),0,tattr,id,
		(struct TagItem *) &tag1Type),
	  GRadioC(),
	  labels(buttonLabels)
{
	labelsplace = place & (PLACETEXT_LEFT|PLACETEXT_RIGHT);
	if (!labelsplace)
		labelsplace = PLACETEXT_LEFT;
	struct TagItem *l = taglist()->find(GTMX_Labels);
	if (l)
		l->ti_Data = (ULONG) labels.strings()
	else
		taglist()->append(GTMX_Labels,(ULONG) labels.strings(),TAG_END);
}

VOID GTRadioC::free()
{
	if (gadget_ob)
		taglist()->set(GTMX_Active,selected(),TAG_END);
}

struct Gadget *GTRadioC::rebuild(struct Gadget *prev)
{
	if (!prev)
		return NULL;
	if (!vinfo()->isValid())
		return NULL;
	NewGadget ng = *newgadget();
	ng.ng_Height = ((struct TextAttr *) textAttr())->ta_YSize+1;
	ng.ng_Flags = (ng.ng_Flags & (~PLACETEXT_MASK)) | labelsplace;
	ng.ng_VisualInfo = vinfo()->visualInfo();
	return gadget_ob = CreateGadgetA(MX_KIND,prev,&ng,taglist()->tags());
}

VOID GTRadioC::calcBorders()
{
	GTGadgetC::calcBorders();
	WORD lwidth = 0;
	STRPTR *labels = (STRPTR *) taglist()->getData(GTMX_Labels,NULL);
	if (labels && textAttr())
	{
		IntuiText l;
		l.ITextFont = (struct TextAttr *) textAttr();
		while (*labels) {
			l.IText = *labels;
			/* register */ WORD lw = IntuiTextLength(&l);
			if (lw > lwidth)
				lwidth = lw;
			labels++;
		};
	};
	if (labelsplace & PLACETEXT_LEFT)
	{
		if (lwidth + 8 > leftB)
			leftB = lwidth + 8;
	};
	if (labelsplace & PLACETEXT_RIGHT)
	{
		if (lwidth + 7 > rightB)
			rightB = lwidth + 7;
	};
}

VOID GTRadioC::select(ULONG active)
{
	setAttrs(GTMX_Active,(ULONG) active, TAG_END);
}

ULONG GTRadioC::selected()
{
	ULONG retval = ~0;
	getAttrs(GTMX_Active,&retval,TAG_END);
	return retval;
}

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

VOID GTCycleEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((struct GTCycleC *) g)->setAttrs(GTCY_Active,msg->Code,TAG_END);
}

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

GTCycleC::GTCycleC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		stringarray &cyclelabels,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *tags)
	: GTGadgetC(event,CYCLE_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,tags),
	  GCycleC(),
	  labels(cyclelabels)
{
	struct TagItem *l = taglist()->find(GTCY_Labels);
	if (l)
		l->ti_Data = (ULONG) labels.strings()
	else
		taglist()->append(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
}

GTCycleC::GTCycleC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		stringarray &cyclelabels,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,CYCLE_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GCycleC(),
	  labels(cyclelabels)
{
	struct TagItem *l = taglist()->find(GTCY_Labels);
	if (l)
		l->ti_Data = (ULONG) labels.strings()
	else
		taglist()->append(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
}

VOID GTCycleC::free()
{
	if (gadget_ob)
		taglist()->set(GTCY_Active,selected(),TAG_END);
}

struct Gadget *GTCycleC::rebuild(struct Gadget *prev)
{
	if (!prev)
		return NULL;
	if (!vinfo()->isValid())
		return NULL;
	newgadget()->ng_VisualInfo = vinfo()->visualInfo();
	gadget_ob = CreateGadgetA(CYCLE_KIND,prev,newgadget(),taglist()->tags());
	return gadget_ob;
}

VOID GTCycleC::setLabels(STRPTR *l)
{
	labels = stringarray(l);
	setAttrs(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
}

VOID GTCycleC::setLabels(STRPTR label1, ...)
{
	labels = stringarray(&label1);
	setAttrs(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
}

STRPTR *GTCycleC::getLabels()
{
	return labels.strings();
}

ULONG GTCycleC::labelsCount()
{
	return labels.length();
}

UWORD GTCycleC::addLabel(STRPTR label)
{
	if (!label)
		return ~0;
	UWORD retval = (UWORD) labels.length();
	labels.addTail(label);
	setAttrs(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
	return retval;
}

VOID GTCycleC::remLabel(UWORD count)
{
	if (count != ~0)
	{
		labels.remove(count);
		setAttrs(GTCY_Labels,(ULONG) labels.strings(),TAG_END);
	};
}

VOID GTCycleC::select(ULONG active)
{
	setAttrs(GTCY_Active,active,TAG_END);
}

ULONG GTCycleC::selected()
{
	ULONG retval = ~0;
	getAttrs(GTCY_Active,&retval,TAG_END);
	return retval;
}

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

VOID GTSliderEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((struct GTSliderC *) g)->setAttrs(GTSL_Level,msg->Code,TAG_END);
}

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

GTSliderC::GTSliderC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,SLIDER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GSliderC()
{
}

GTSliderC::GTSliderC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,SLIDER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GSliderC()
{
}

VOID GTSliderC::free()
{
	if (gadget_ob)
		taglist()->set(GTSL_Level,level(),TAG_END);
}

VOID GTSliderC::calcBorders()
{
	GTGadgetC::calcBorders();
	UWORD maxlevellen = taglist()->getData(GTSL_MaxLevelLen,0);
	if (maxlevellen > 0 && textAttr())
	{
		IntuiText l;
		l.ITextFont = (struct TextAttr *) textAttr();
		l.IText = "0";
		ULONG levelwidth = IntuiTextLength(&l)*maxlevellen;
		ULONG levelheight = ((struct TextAttr *) textAttr())->ta_YSize;
		ULONG lplace = taglist()->getData(GTSL_LevelPlace,PLACETEXT_LEFT);
		if (lplace & PLACETEXT_LEFT)
		{
			if (levelwidth+8 > leftB)
				leftB = levelwidth+8;
		};
		if (lplace & PLACETEXT_RIGHT)
		{
			if (levelwidth+7 > rightB)
				rightB = levelwidth+7;
		};
		if (lplace & PLACETEXT_ABOVE)
		{
			if (levelheight > topB)
				topB = levelheight;
		};
		if (lplace & PLACETEXT_BELOW)
		{
			if (levelheight > bottomB)
				bottomB = levelheight;
		};
		if (lplace & (PLACETEXT_LEFT|PLACETEXT_RIGHT|PLACETEXT_IN))
		{
			LONG db = levelheight-height()-topB-bottomB;
			if (db > 0)
			{
				topB += (db+1) >> 1;
				bottomB += db >> 1;
			};
		};
		if (lplace & (PLACETEXT_ABOVE|PLACETEXT_BELOW|PLACETEXT_IN))
		{
			LONG db = levelwidth-width()-leftB-rightB;
			if (db > 0)
			{
				leftB += (db+1) >> 1;
				rightB += db >> 1;
			};
		};
	};
}

VOID GTSliderC::setMin(UWORD min)
{
	setAttrs(GTSL_Min,min,TAG_END);
}

UWORD GTSliderC::min()
{
	LONG retval = 0;
	getAttrs(GTSL_Min,&retval,TAG_END);
	return retval;
}

VOID GTSliderC::setMax(UWORD max)
{
	setAttrs(GTSL_Max,max,TAG_END);
}

UWORD GTSliderC::max()
{
	LONG retval = 0;
	getAttrs(GTSL_Max,&retval,TAG_END);
	return retval;
}

VOID GTSliderC::setLevel(UWORD level)
{
	setAttrs(GTSL_Level,level,TAG_END);
}

UWORD GTSliderC::level()
{
	LONG retval = 0;
	getAttrs(GTSL_Level,&retval,TAG_END);
	return retval;
}

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

VOID GTScrollerEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((GTScrollerC *) g)->setAttrs(GTSC_Top,msg->Code,TAG_END);
}

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

GTScrollerC::GTScrollerC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,SCROLLER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GScrollerC()
{
}

GTScrollerC::GTScrollerC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,SCROLLER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GScrollerC()
{
}

VOID GTScrollerC::free()
{
	if (gadget_ob)
		taglist()->set(GTSC_Top,pot(),TAG_END);
}

VOID GTScrollerC::setPot(UWORD top)
{
	setAttrs(GTSC_Top,top,TAG_END);
}

UWORD GTScrollerC::pot()
{
	LONG retval = 0;
	getAttrs(GTSC_Top,&retval,TAG_END);
	return retval;
}

VOID GTScrollerC::setTotal(UWORD total)
{
	setAttrs(GTSC_Total,total,TAG_END);
}

UWORD GTScrollerC::total()
{
	LONG retval = 0;
	getAttrs(GTSC_Total,&retval,TAG_END);
	return retval;
}

VOID GTScrollerC::setVisible(UWORD visible)
{
	setAttrs(GTSC_Visible,visible,TAG_END);
}

UWORD GTScrollerC::visible()
{
	LONG retval = 0;
	getAttrs(GTSC_Visible,&retval,TAG_END);
	return retval;
}

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

VOID GTListviewEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((GTListviewC *) g)->setAttrs(GTLV_Selected,msg->Code,TAG_END);
}

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

GTListviewC::GTListviewC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *tags)
	: GTGadgetC(event,LISTVIEW_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_ABOVE,tattr,id,tags),
	  GListviewC()
{
	list = (EListC *) taglist()->getData(GTLV_Labels,NULL);
}

GTListviewC::GTListviewC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,LISTVIEW_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_ABOVE,tattr,id,
		(struct TagItem *) &tag1Type),
	  GListviewC()
{
	list = (EListC *) taglist()->getData(GTLV_Labels,NULL);
}

VOID GTListviewC::free()
{
	if (gadget_ob)
		taglist()->set(GTLV_Selected,selected(),TAG_END);
}

VOID GTListviewC::setList(EListC *header)
{
	list = header;
	setAttrs(GTLV_Labels,list,TAG_END);
}

EListC *GTListviewC::getList()
{
	return list;
}

VOID GTListviewC::detachList()
{
	setAttrs(GTLV_Labels,~0,TAG_END);
}

VOID GTListviewC::attachList()
{
	setAttrs(GTLV_Labels,list,TAG_END);
}

VOID GTListviewC::select(ULONG selected)
{
	setAttrs(GTLV_Selected,selected,TAG_END);
}

ULONG GTListviewC::selected()
{
	LONG retval = ~0;
	getAttrs(GTLV_Selected,&retval,TAG_END);
	return retval;
}

VOID GTListviewC::clearSelection()
{
	setAttrs(GTLV_Selected,~0,TAG_END);
}

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

VOID GTPaletteEventC::up(WindowC *, GadgetC *g, IntuiMessageC *msg)
{
	((GTPaletteC *) g)->setAttrs(GTPA_Color,msg->Code,TAG_END);
}

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

GTPaletteC::GTPaletteC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,PALETTE_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GPaletteC()
{
}

GTPaletteC::GTPaletteC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,PALETTE_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GPaletteC()
{
}

VOID GTPaletteC::free()
{
	if (gadget_ob)
		taglist()->set(GTPA_Color,selected(),TAG_END);
}

VOID GTPaletteC::select(ULONG color)
{
	setAttrs(GTPA_Color,color,TAG_END);
}

ULONG GTPaletteC::selected()
{
	LONG retval = ~0;
	getAttrs(GTPA_Color,&retval,TAG_END);
	return retval;
}

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

GTTextC::GTTextC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,TEXT_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GTextC()
{
}

GTTextC::GTTextC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,TEXT_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GTextC()
{
}

VOID GTTextC::set(STRPTR text)
{
	setAttrs(GTTX_Text,text,TAG_END);
}

STRPTR GTTextC::get()
{
	STRPTR retval = NULL;
	getAttrs(GTTX_Text,&retval,TAG_END);
	return retval;
}

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

GTNumberC::GTNumberC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		struct TagItem *taglist)
	: GTGadgetC(event,NUMBER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,taglist),
	  GNumberC()
{
}

GTNumberC::GTNumberC(GadgetEventC *event,
		WORD LeftEdge, WORD TopEdge, WORD Width, WORD Height,
		STRPTR label, ULONG flags, const TextAttrC *tattr, UWORD id,
		Tag tag1Type, ...)
	: GTGadgetC(event,NUMBER_KIND,LeftEdge,TopEdge,
		Width,Height,label,flags,PLACETEXT_LEFT,tattr,id,
		(struct TagItem *) &tag1Type),
	  GNumberC()
{
}

VOID GTNumberC::set(LONG number)
{
	setAttrs(GTNM_Number,number,TAG_END);
}

LONG GTNumberC::get()
{
	LONG retval = 0;
	getAttrs(GTNM_Number,&retval,TAG_END);
	return retval;
}

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