/*
 *	File:					ListviewReqester.h
 *	Version:			1.0 (21.02.95)
 *	Description:	Let the user select an item from a listview-requester.
 *
 *	(C) 1994,1995 Ketil Hunn
 *
 */

#ifndef	LISTVIEWREQUESTER_H
#define	LISTVIEWREQUESTER_H

/*** DEFINES *************************************************************************/
#define every_node					node=list->lh_Head;node->ln_Succ;node=node->ln_Succ
#define	GTLV_Visible				MR_Window
#define	ID_LVREQ_LISTVIEW		65535
#define	ID_LVREQ_CANCEL			0

/*** PROTOTYPES **********************************************************************/
UWORD mrHandleListviewRequest(struct ListviewRequester *req,
															varWORD *posarray,
															varWORD *sizearray);
struct Node *mrGetNode(struct List *list, UWORD select);

/*** FUNCTIONS ***********************************************************************/
__asm BYTE TextToList(register __a0 struct List *list,
											register __a1 UBYTE				*text,
											register __d0 UWORD				width)
{
	register BYTE success=FALSE;

#ifdef MYDEBUG_H
	DebugOut("TextToList");
#endif

	if(list && text)
	{
		register UBYTE	*start=text,
										cc,
										*laststop=NULL;

		/* subtract border width */
		width-=25;
		while(*text!='\0')
		{
			while(*text!='\n' && *text!=' ' && *text!='\0')
				text++;

			cc=*text;
			*text='\0';
			if(cc==' ' && TextLength(&eg->RPort, start, text-start)>width)
			{
				if(laststop)
				{
					register UBYTE lcc=*laststop;

					*laststop='\0';
					AddNode(list, NULL, start);
					*laststop=lcc;
					*text=cc;
					text=laststop;
					cc=~0;
					laststop=NULL;
				}
				else
					AddNode(list, NULL, start);
				start=text+1;
			}
			else if(cc=='\n' | cc=='\0')
			{
				if(laststop && TextLength(&eg->RPort, start, text-start)>width)
				{
					register UBYTE lcc=*laststop;

					*laststop='\0';
					AddNode(list, NULL, start);
					*laststop=lcc;
					*text=cc;
					text=laststop;
					cc=~0;
					laststop=NULL;
				}
				else
					AddNode(list, NULL, start);
				start=text+1;
			}
			else
				laststop=text;
			if(cc!=~0)
				*text=cc;
			if(*text!='\0')
				*text++;
		}
		success=TRUE;
	}
	return success;
}

void mrRenderListviewRequest(	struct ListviewRequester *req,
															varWORD *posarray,
															varWORD *sizearray)
{
	struct Gadget		*gad;
	struct NewGadget	ng;
	BYTE lowkick=(IntuitionBase->LibNode.lib_Version<39),
				dropdown=req->dropdown,
				readonly=req->readonly;
	WORD	wborleft	=req->window->BorderLeft,
				wbortop		=req->window->BorderTop,
				wborright	=req->window->BorderRight,
				wborbottom=req->window->BorderBottom,
				butheight	=req->textattr->ta_YSize+MR_GadVInside;
	register ULONG i;

#ifdef MYDEBUG_H
	DebugOut("RenderListviewRequest");
#endif

			gad=CreateContext(&(req->glist));

			ng.ng_TextAttr		=req->textattr;
			ng.ng_VisualInfo	=req->visualinfo;
			ng.ng_Flags				=0;
			ng.ng_Height			=butheight;

		if(req->numgads)
		{
			if(dropdown)
			{
				mrSpreadGadgets((WORD *)posarray->val, (WORD *)sizearray->val, 0, req->window->Width, req->numgads, !dropdown);
				ng.ng_TopEdge			=req->window->Height-butheight;
			}
			else
			{
				mrSpreadGadgets((WORD *)posarray->val, (WORD *)sizearray->val, wborleft+MR_LeftMargin,
													req->window->Width-MR_RightMargin-wborright, req->numgads, !dropdown);
				ng.ng_TopEdge			=req->window->Height-butheight-MR_BottomMargin-wborbottom;
			}

			for(i=0; i<req->numgads; i++)
			{
				ng.ng_LeftEdge		=posarray->val[i];
				ng.ng_Width				=sizearray->val[i];
				ng.ng_GadgetText	=req->gadgettexts->text[i];
				ng.ng_GadgetID		=i+1;
				req->gadgets->gad[i]=gad=CreateGadget(BUTTON_KIND, gad, &ng,
//				gad=CreateGadget(BUTTON_KIND, gad, &ng,
													GT_Underscore,		MR_Underscorechar,
													TAG_END);
			}
			if(req->numgads>1)
				gad->GadgetID=0;
		}

			if(dropdown)
			{
				ng.ng_LeftEdge		=ng.ng_TopEdge=0;
				ng.ng_Width				=req->window->Width;
				ng.ng_Height			=req->window->Height-(req->numgads ? butheight:0);
			}
			else
			{
				ng.ng_LeftEdge		=wborleft+MR_LeftMargin;
				ng.ng_TopEdge			=wbortop+MR_TopMargin;
				ng.ng_Width				=req->window->Width-wborleft-MR_LeftMargin-wborright-MR_RightMargin;
				ng.ng_Height			=req->window->Height-(req->numgads ? butheight:0)-wbortop-MR_TopMargin-wborbottom-MR_BottomMargin-INTERHEIGHT;
			}
			ng.ng_GadgetText	=NULL;
			ng.ng_GadgetID		=ID_LVREQ_LISTVIEW;
			req->listview=CreateGadget(LISTVIEW_KIND, gad, &ng,
												GTLV_Labels,				req->list,
												GTLV_Selected,			req->selectednum,
												(readonly | lowkick ? TAG_IGNORE : GTLV_ShowSelected),	NULL,
												(IntuitionBase->LibNode.lib_Version>38 ? GTLV_MakeVisible:GTLV_Top),	req->selectednum,
												GTLV_MakeVisible,		req->selectednum,
												GTLV_ReadOnly,			readonly,
												TAG_END);
			AddGList(req->window, req->glist, -1, -1, NULL);

			if(dropdown)
				EraseRect(req->window->RPort, 0, 0, req->window->Width, req->window->Height);
			else
				EraseRect(req->window->RPort, wborleft, wbortop,
									req->window->Width-wborright-1,
									req->window->Height-wborbottom-1);
			RefreshGList(req->glist, req->window, NULL, -1);
			GT_RefreshWindow(req->window, NULL);

			req->scrollrows=(H(req->listview)/req->textattr->ta_YSize)-1;
			req->selectednode=mrGetNode(req->list, req->selectednum);
}

UWORD mrLVRequestA(struct ListviewRequester *req, struct TagItem *taglist)
{
	register WORD minwidth, minheight, butheight, butwidth, allbutwidth=0;
	register BOOL	dropdown, ok=FALSE;
	register varWORD	*posarray=NULL, *sizearray=NULL;
	UWORD retvalue;

#ifdef MYDEBUG_H
	DebugOut("mrLVRequestA");
#endif

	if(req==NULL)
		return 0;

	mrGetTags(MR_ListviewRequest, (APTR)req, taglist);
	dropdown=req->dropdown;

	req->glist=NULL;

	if(req->numgads)
	{
		if(sizearray=AllocVec(sizeof(varWORD)+sizeof(WORD)*(req->numgads+1), MEMF_CLEAR))
			if(posarray=AllocVec(sizeof(varWORD)+sizeof(WORD)*(req->numgads+1), MEMF_CLEAR))
				ok=TRUE;
	}
	else
		ok=TRUE;

	if(ok)
	{
		register ULONG i;

		if(req->numgads)
		{
			if(req->samegadgetwidth)
			{
				butwidth=mrMaxLenA(&req->rp, req->gadgettexts->text)+MR_GadHInside;
				for(i=0; i<req->numgads; i++)
				{
					sizearray->val[i]=butwidth;
					allbutwidth+=sizearray->val[i];
				}
			}
			else
				for(i=0; i<req->numgads; i++)
				{
					sizearray->val[i]=MR_GadHInside+mrTextWidth(&req->rp, req->gadgettexts->text[i]);
					allbutwidth+=sizearray->val[i];
				}
		}
		mrInitialPercent(req);
		minwidth=allbutwidth+MR_RightMargin+MR_LeftMargin*req->numgads;
		butheight=(req->numgads>0 ? req->textattr->ta_YSize+MR_GadVInside : 0);
		minheight=butheight*4+INTERHEIGHT;

		req->Width	=MAX(minwidth, req->Width);
		req->Height	=MAX(minheight, req->Height);

		if(dropdown==TRUE)
		{
			register WORD rows;

			rows=(req->Height-butheight-4)/req->textattr->ta_YSize;
			req->Height=rows*req->textattr->ta_YSize+butheight+4;

			if(allbutwidth<req->Width & req->numgads>0)
			{
				register WORD addwidth=(req->Width-allbutwidth)/req->numgads;

				for(i=0; i<req->numgads; i++)
					sizearray->val[i]+=addwidth;
				sizearray->val[i-1]+=req->Width-allbutwidth-addwidth*req->numgads;
			}
		}

		mrInitialCentre(req);
		if(req->sleepwindow==TRUE & req->pwindow!=NULL)
			req->sleepreq=mrLockWindow(req->pwindow);
		else
			req->sleepreq=NULL;

		if(req->window=OpenWindowTags(NULL,
								(dropdown ? TAG_IGNORE : WA_Title),					req->titletext,
								WA_Left,					req->LeftEdge,
								WA_Top,						req->TopEdge,
								WA_InnerWidth,		req->Width,
								WA_InnerHeight,		req->Height,
								WA_Flags,					WFLG_ACTIVATE|
																	WFLG_RMBTRAP,
								(dropdown ? TAG_IGNORE : WA_DragBar),				TRUE,
								(dropdown ? TAG_IGNORE : WA_DepthGadget),		TRUE,
								(dropdown ? TAG_IGNORE : WA_CloseGadget),		req->closegadget,
								(dropdown ? TAG_IGNORE : WA_SizeGadget),		req->sizegadget,
								(dropdown ? TAG_IGNORE : WA_SizeBBottom),		TRUE,
								(dropdown ? WA_Borderless : TAG_IGNORE),		TRUE,
								WA_SimpleRefresh,	req->simplerefresh,
								WA_CustomScreen,	req->screen,
								TAG_END))
		{
			register BOOL	portcreated=FALSE;

			if(req->privateidcmp==FALSE & req->pwindow!=NULL)
				req->port=req->window->UserPort=req->pwindow->UserPort;
			else
			{
				req->port=req->window->UserPort=CreateMsgPort();
				portcreated=TRUE;
			}

			if(req->port)
			{
				ModifyIDCMP(req->window,	IDCMP_VANILLAKEY|
																	IDCMP_RAWKEY|
																	IDCMP_NEWSIZE|
																	IDCMP_SIZEVERIFY|
																	IDCMP_REFRESHWINDOW|
																	IDCMP_CLOSEWINDOW|
																	ARROWIDCMP|
																	SCROLLERIDCMP);
				{
					register struct Node	*node=req->list->lh_Head;
					register i=0;

					for(;node->ln_Succ;node=node->ln_Succ)
						++i;
					req->count=i;
				}

				if(req->gadgets=AllocVec(sizeof(varGADGET)+sizeof(struct Gadget *)*(req->numgads+1), MEMF_CLEAR))
				{
					mrRenderListviewRequest(req, posarray, sizearray);

					WindowLimits(	req->window,
												minwidth+req->window->BorderLeft+req->window->BorderRight,
												minheight+req->window->BorderTop+req->window->BorderBottom,
												~0,~0);

					ScreenToFront(req->screen);
					req->status=STATUS_OPEN;
					while(req->status==STATUS_OPEN)
					{
						Wait(1L<<req->window->UserPort->mp_SigBit);
						retvalue=mrHandleListviewRequest(req, posarray, sizearray);
					}
					if(portcreated)
						DeleteMsgPort(req->port);
					req->privateidcmp=FALSE;

					FreeVec(req->gadgets);
					req->gadgets=NULL;
				}
			}
		}

		if(req->sleepreq!=NULL)
			mrUnlockWindow(req->pwindow, req->sleepreq);
	}

	if(posarray)
				FreeVec(posarray);
	if(sizearray)
		FreeVec(sizearray);

	return retvalue;
}

UWORD mrLVRequest(struct ListviewRequester *req, Tag tag1, ...)
{
	return mrLVRequestA(req, (struct TagItem *)&tag1);
}

struct Node *mrGetNode(struct List *list, UWORD select)
{
	register struct Node *node;
	register UWORD i=0;

#ifdef MYDEBUG_H
	DebugOut("mrGetNode");
#endif

	for(every_node)
		if(i++==select)
			return node;
	return NULL;
}

UWORD mrHandleListviewRequest(struct ListviewRequester *req,
															varWORD *posarray,
															varWORD *sizearray)
{
	struct IntuiMessage *msg;
	UWORD								retvalue=0;

#ifdef MYDEBUG_H
	DebugOut("HandleListviewRequest");
#endif

  while((req->status==STATUS_OPEN) &&
					(NULL!=(msg=GT_GetIMsg(req->window->UserPort))))
	{
		if(msg->IDCMPWindow!=req->window)
		{
			switch(msg->Class)
			{
				case IDCMP_CLOSEWINDOW:
				case IDCMP_SIZEVERIFY:
				case IDCMP_NEWSIZE:
				case IDCMP_MOUSEBUTTONS:
				case IDCMP_CHANGEWINDOW:
				case IDCMP_GADGETUP:
					req->status=STATUS_CLOSED;
					retvalue=0;
					break;
/*				default:
					if(mrCallHook(req, msg)==0)
					{
						req->status=STATUS_CLOSED;
						retvalue=0;
					}
					break;
*/
			}
		}
		else
		{
			switch(msg->Class)
			{
				case IDCMP_REFRESHWINDOW:
					GT_BeginRefresh(req->window);
					GT_EndRefresh(req->window, TRUE);
					break;
				case IDCMP_SIZEVERIFY:
					RemoveGList(req->window, req->glist, -1);
					FreeGadgets(req->glist);
					req->glist=NULL;
					break;
				case IDCMP_NEWSIZE:
					if(req->glist!=NULL)
					{
						RemoveGList(req->window, req->glist, -1);
						FreeGadgets(req->glist);
					}
					RefreshWindowFrame(req->window);
					mrRenderListviewRequest(req, posarray, sizearray);
					break;
				case IDCMP_CLOSEWINDOW:
					req->status=STATUS_CLOSED;
					retvalue=0;
					break;
				case IDCMP_RAWKEY:
					{
						ULONG top;
						BYTE highkick=(IntuitionBase->LibNode.lib_Version>38);

						if(msg->Code!=CURSORUP & msg->Code!=CURSORDOWN & msg->Code!=95)
							break;

						if(highkick)
							GT_GetGadgetAttrs(req->listview, req->window, NULL,
																GTLV_Top,	&top,
																TAG_DONE);

						switch(msg->Code)
						{
							case 95:		// help key
								if(mrCallHook(req, msg)==0)
								{
									req->status=STATUS_CLOSED;
									retvalue=0;
								}
								break;
							case CURSORUP:
								if(CTRLPRESSED(msg) | ALTPRESSED(msg))
								{
									req->selectednum=0;
//									req->top=0;
								}
								else if(SHIFTPRESSED(msg))
								{
									if(req->readonly)
										req->selectednum=MIN(0, req->selectednum-req->scrollrows-1);
									else
									{
										if(highkick==TRUE & req->selectednum>top)
											req->selectednum=(UWORD)top;
										else
										{
											req->selectednum=MAX(0, req->selectednum-req->scrollrows);
//											req->top=(req->selectednum<req->top-req->scrollrows ? req->selectednum:req->top);
										}
									}
								}
								else
								{
									if(req->readonly)
										req->selectednum=MAX(0, req->selectednum-1);
									else
									{
										req->selectednum=MAX(0, req->selectednum-1);
//										req->top=(req->selectednum<req->top ? req->top-(req->top-req->selectednum): req->top);
									}
								}
								break;
							case CURSORDOWN:
								if(CTRLPRESSED(msg) | ALTPRESSED(msg))
								{
									req->selectednum=req->count-1;
//									req->top=req->count;
								}
								else if(SHIFTPRESSED(msg))
								{
									if(req->readonly)
										req->selectednum=MIN(req->count-1, req->selectednum+req->scrollrows-1);
									else
									{
										if(highkick==TRUE & req->selectednum!=top+req->scrollrows)
											req->selectednum=MIN(req->count-1, (UWORD)top+req->scrollrows);
										else
										{
											req->selectednum=MIN(req->count-1, req->selectednum+req->scrollrows);
//											req->top=MIN(req->count-1, req->top+req->scrollrows-1);
										}
									}
								}
								else
								{
									if(req->readonly)
										req->selectednum=MIN(req->count-1, req->selectednum+1);
									else
									{
										req->selectednum=MIN(req->count-1, req->selectednum+1);
//										req->top=(req->selectednum>req->top+req->scrollrows ? req->top+1: req->top);
									}
								}
								break;
						}

						GT_SetGadgetAttrs(req->listview, req->window, NULL,
												GTLV_Selected,		req->selectednum,
												(req->readonly ? TAG_IGNORE: GTLV_MakeVisible),	req->selectednum,
//												(req->readonly ? GTLV_Top : TAG_IGNORE),				req->top,
												(highkick ? TAG_IGNORE : GTLV_Top), req->selectednum,
												TAG_DONE);
					}
					break;
				case IDCMP_VANILLAKEY:
					switch(msg->Code)
					{
						case 13:		// return key
							retvalue=1;
							req->status=STATUS_CLOSED;
							if(req->numgads>0)
								mrHandleButtonKey(req->window, req->gadgets->gad[0]);
							break;
						case 27:		// esc key
							retvalue=0;
							req->status=STATUS_CLOSED;
							if(req->numgads)
								mrHandleButtonKey(req->window, req->gadgets->gad[req->numgads-1]);
							break;
						default:
							retvalue=mrMatchVanillaKeyA((int)msg->Code, req->gadgettexts->text);
							if(retvalue)
							{
								req->status=STATUS_CLOSED;
						
								if(req->numgads)
									mrHandleButtonKey(req->window, req->gadgets->gad[retvalue-1]);

								if(retvalue==req->numgads & req->numgads>1)
									retvalue=0;
							}
							break;
					}
					break;
				case MOUSEMOVE:
				case IDCMP_GADGETUP:
					{
						register UWORD id=((struct Gadget *)msg->IAddress)->GadgetID;

						if(id==ID_LVREQ_LISTVIEW)
						{
							req->selectednum	=msg->Code;
							if(DoubleClick(	req->seconds, req->micros,
															msg->Seconds, msg->Micros)
															& req->selectednum==req->lastselected)
							{
								if(req->numgads)
									mrHandleButtonKey(req->window, req->gadgets->gad[0]);
								req->status=STATUS_CLOSED;
								retvalue=1;
							}
							else
							{
								req->seconds			=msg->Seconds;
								req->micros				=msg->Micros;
								req->lastselected	=msg->Code;
							}
						}
						else if(id==ID_LVREQ_CANCEL)
						{
							req->status=STATUS_CLOSED;
							retvalue=0;
						}
						else
						{
							req->status=STATUS_CLOSED;
							retvalue=id;
						}
					}
					break;
			}
		}
		GT_ReplyIMsg(msg);
	}
	if(req->status==STATUS_CLOSED)
	{
		mrCloseRequester(req);
		req->selectednode	=mrGetNode(req->list, req->selectednum);
	}

	return retvalue;
}

#endif
