/*
 *	© 1992 by Michael Watzl, compiled with DICE: dcc multibox.c -2.0 -o Multibox
 */


#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <graphics/gfx.h>
#include <graphics/Text.h>
#include <libraries/gadtools.h>
#include <dos/rdargs.h>
#include <string.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/gadtools_protos.h>

#define ACTIVESCREEN	IntuitionBase->ActiveScreen
#define FHEIGHT		ACTIVESCREEN->Font->ta_YSize
#define WHEIGHT		(8*FHEIGHT+2*boxnumber*FHEIGHT+3)
#define GYOFFSET	(FHEIGHT*3.6)
#define GXOFFSET	pixwidth((UBYTE *)"     ")
#define CTOP		WHEIGHT-3*FHEIGHT+3

/*
 *	Protos
 */

VOID	quit( STRPTR errtext, LONG rc);
WORD	pow( WORD base, exp);
VOID	cleanquit( VOID );
VOID	GetIDCMP( VOID );

VOID	usage( VOID );
VOID	calcwidths( VOID );
LONG	pixwidth( STRPTR text );

VOID	exit( LONG rc );

struct IntuitionBase 	*IntuitionBase;
struct GfxBase 		*GfxBase;
struct GadToolsBase 	*GadToolsBase;
struct Window 		*window;
struct IntuiMessage 	*message;
struct Gadget 		*congad;			/* pointer to gadgetcontext (list) */
struct TextExtent	textextent;

struct NewGadget CancelGad= {100,100,40,10,(UBYTE *)"CANCEL!",NULL, 0,PLACETEXT_IN,NULL,NULL};
struct NewGadget OkGad    = {100,100,40,10,(UBYTE *)"OK!"    ,NULL,20,PLACETEXT_IN,NULL,NULL};
struct RDArgs *cliargs;
struct {
        STRPTR  Hail;
        STRPTR	Title;
        STRPTR	*Box;
}	array;
struct IntuiText iText = {1,0,JAM1,0,0,NULL,NULL,NULL};
void	*vi;						/* var for VisualInfo */
char	*boxtext[20];
WORD	boxnumber,textwidth,wwidth,cwidth;		/* number of chackbox-gadgets, max textwidth, width of req-window, width of cancelgadget */

VOID
quit( STRPTR errtxt, LONG rc)				/* print errortext, clean up and put returncode */
{
	if(errtxt) 		PutStr(errtxt);
	if(window) 		CloseWindow(window);
	if(congad) 		FreeGadgets(congad);
	if(vi)			FreeVisualInfo(vi);
	if(GadToolsBase) 	CloseLibrary(GadToolsBase);
	if(GfxBase) 		CloseLibrary(GfxBase);
	if(IntuitionBase) 	CloseLibrary((struct Library*)IntuitionBase);
	if(cliargs)		FreeArgs( cliargs );
	exit(rc);
}

WORD
pow( WORD base, exp )					/* calcualte  a power b */
{
	WORD i=0,po=1;
	for(i=0;i<exp;i++)
		po*=base;
	return(po);
}

VOID
cleanquit( VOID )					/* calculate the returncode (selected/notselected) boxes */
{
	struct Gadget *g;
	LONG i,rc=0;

	g=congad;		/* FirstGadget */
	for(i=0;i<=boxnumber;i++){					/* claculate the RC */
		if( (g->Flags) & GFLG_SELECTED) rc+=pow(2,i-1);
		g=g->NextGadget;
	}
	quit(NULL , rc);
}

VOID
GetIDCMP( VOID )
{
	WORD 	id;
	struct	Gadget *g;
	UBYTE	code;
	ULONG	class=0;

	FOREVER
	{
		Wait(1<<window->UserPort->mp_SigBit);
		while (message=GT_GetIMsg(window->UserPort))
		{
			class=message->Class;
			if(class==IDCMP_CLOSEWINDOW)
				quit(NULL,0);
			if(class==IDCMP_GADGETUP){
				g=(struct Gadget*)message->IAddress;
				id=g->GadgetID;
				if(id==0)  quit(NULL,65536);	/* cancel Gadget */
				if(id==20) cleanquit();		/* ok gadget */
			}
			if(class==IDCMP_VANILLAKEY){
				code=message->Code;
				if(code==13) cleanquit();
			}
			GT_ReplyIMsg(message);
		} /* while message */
	} /* Forever */
}

VOID
usage( VOID )
{
	PutStr("Usage: multibox [\"Hailstring\"] TITLE \"TitleString\" BOXES Box1|Box2|...\n");
	PutStr("[33m© 1992 by Michael Watzl [31m\n");
	PutStr("\nThe returncode inicates which gadgets have been selected.\n");
	PutStr("Example:\n The first an third gadged have been selected\n => You'll get the rc: 1*2^0 + 0*2^1 + 1*2^2 = 5\n");
	exit(5);
}

main(WORD argc, STRPTR *argv)
{
	WORD	i=0;
	struct	Gadget *gad;
	struct	TagItem CheckGadTags[2] = {GTCB_Checked,FALSE,TAG_DONE,0};
	STRPTR	template = "HAIL/K,TITLE/K/A,BOXES/F/A", arg;
	const	STRPTR  ws ="|";
	struct	NewGadget **ng;

       	if(!( cliargs=ReadArgs( template , &array, NULL))){
		FreeArgs(cliargs);
		usage();
	}

	for( arg = strtok( array.Box , ws ) ; arg ; arg=strtok(NULL,ws) ) boxtext[i++]=arg;
	boxnumber=i;

	if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37L)))
		quit("Clould not open intuition.library V37!\n",10);
	if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37L)))
		quit("Clould not open graphics.library V37!\n",10);
	if(!(GadToolsBase=(struct GadToolsBase *)OpenLibrary("gadtools.library",0L)))
		quit("Clould not open gadtools.library!\n",10);
	if(!(vi=(void *)GetVisualInfoA(ACTIVESCREEN,NULL)))
		quit("Can't get visual info!\n",10);
	if(!(gad=(struct Gadget *)CreateContext((struct Gadget **)&congad)))
		quit("Can't create context!\n",10);

	calcwidths();					/* calc width of window, gadgets */

	if(!( ng[0] = AllocMem( sizeof( struct NewGadget ) * boxnumber , MEMF_PUBLIC | MEMF_CLEAR ))) quit("Can't allocate enough memory!\n",10);
	for(i=0;i<boxnumber;i++)
	{
		ng[i]->ng_LeftEdge   = GXOFFSET;
		ng[i]->ng_TopEdge    = GYOFFSET+ (2*i+1)*FHEIGHT;
		ng[i]->ng_GadgetText = boxtext[i];
		ng[i]->ng_TextAttr   = ACTIVESCREEN->Font;
		ng[i]->ng_GadgetID   = i+1;
		ng[i]->ng_Flags      = PLACETEXT_RIGHT;
		ng[i]->ng_VisualInfo = vi;

		if(boxtext[i][strlen(boxtext[i])-1]=='_')
		{
			boxtext[i][strlen(boxtext[i])-1]='\0';			/* Kill last char */
			CheckGadTags[0].ti_Data=TRUE;
		} else  CheckGadTags[0].ti_Data=FALSE;
		if(!(gad = CreateGadgetA( CHECKBOX_KIND , gad , ng[i] , CheckGadTags ))){
				FreeMem( ng , sizeof( struct NewGadget ) * boxnumber );
				quit("Can't create gadget!\n",10);
		}
	}
	FreeMem( ng[0] , sizeof( struct NewGadget ) * boxnumber );

	CancelGad.ng_LeftEdge=wwidth-cwidth-15;
	CancelGad.ng_TopEdge=CTOP;
	CancelGad.ng_Width =cwidth-3;
	CancelGad.ng_Height=FHEIGHT*2;
	CancelGad.ng_VisualInfo=vi;
	CancelGad.ng_TextAttr=ACTIVESCREEN->Font;

	OkGad.ng_LeftEdge=15;
	OkGad.ng_TopEdge=CTOP;
	OkGad.ng_Width =cwidth-3;			/* Width minus  BevelBoxSize */
	OkGad.ng_Height=FHEIGHT*2;
	OkGad.ng_VisualInfo=vi;
	OkGad.ng_TextAttr=ACTIVESCREEN->Font;

	if(!(gad=CreateGadget(BUTTON_KIND,gad,&CancelGad,GA_RelVerify,TRUE,TAG_DONE,0)))
			quit("Can't create cancel gadget!\n",10);
	if(!(gad=CreateGadget(BUTTON_KIND,gad,&OkGad,GA_RelVerify,TRUE,TAG_DONE,0)))
			quit("Can't create ok gadget!\n",10);

	if(!(window=(struct Window *)OpenWindowTags(NULL,
		WA_Top		,ACTIVESCREEN->MouseY-((boxnumber+2)*FHEIGHT+50)/2,
		WA_Left		,ACTIVESCREEN->MouseX-(textwidth+200)/2,
		WA_Width	,wwidth,
		WA_Height	,WHEIGHT+5,
		WA_Flags	,WFLG_DRAGBAR|WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_ACTIVATE,
		WA_IDCMP	,IDCMP_CLOSEWINDOW|IDCMP_GADGETUP|IDCMP_VANILLAKEY,
		WA_Gadgets	,congad,
		WA_Title	,array.Hail,
		WA_CustomScreen	,ACTIVESCREEN,
		TAG_DONE	,0)))
			quit("Could not open window!\n",10);

	DrawBevelBox(window->RPort,15-3              ,CTOP-2,cwidth+3,FHEIGHT*2+4,GT_VisualInfo,vi,TAG_DONE,0);
	DrawBevelBox(window->RPort,wwidth-cwidth-15-3,CTOP-2,cwidth+3,FHEIGHT*2+4,GTBB_Recessed,TRUE,GT_VisualInfo,vi,TAG_DONE,0);

	iText.IText=array.Title;		/* Outlined looks much better! */
	iText.ITextFont=ACTIVESCREEN->Font;
	iText.FrontPen=1;
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2-1,2+2*FHEIGHT-1);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2  ,2+2*FHEIGHT-1);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2+1,2+2*FHEIGHT-1);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2-1,2+2*FHEIGHT);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2+1,2+2*FHEIGHT);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2-1,2+2*FHEIGHT+1);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2  ,2+2*FHEIGHT+1);
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2+1,2+2*FHEIGHT+1);
	iText.FrontPen=3;
	PrintIText(window->RPort,&iText,(wwidth-pixwidth(array.Title))/2,2+2*FHEIGHT);
	DrawBevelBox(window->RPort,(wwidth-pixwidth(array.Title))/2-5,2+2*FHEIGHT-5,pixwidth(array.Title)+10,FHEIGHT+10,GT_VisualInfo,vi,TAG_DONE,0);

	GetIDCMP();
}

VOID
calcwidths( VOID )
{

	WORD i,len;

	cwidth = pixwidth( "CANCEL!"  ) + 20;
	len    = pixwidth( boxtext[0] );
	for( i=1 ; i<boxnumber ; i++ )					/* find longest string */
		if( len < pixwidth( boxtext[i] ) ) len = pixwidth( boxtext[i] );
	if( pixwidth( array.Title ) > len) len=pixwidth( array.Title );
	textwidth = len + 20;
	wwidth    = GXOFFSET + 30 + textwidth;
	if( 2*cwidth+40>wwidth ) wwidth = 2*cwidth+40;
}

LONG
pixwidth( STRPTR text)					/* calc width of text */
{
        TextExtent( &(ACTIVESCREEN->RastPort) , text , strlen(text) , &textextent );
	return( textextent.te_Width );
}
