/** simpgad.c
 *
 *   Simple Gadget routines.
 *
**/
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <functions.h>

#include <simpreq.h>
#include "simpdefs.h"

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;

/**
 *
 *
 *    MakeBox(1.0)    ARP Programmers Manual   MakeBox(1.0)
 *
 *
 *    NAME
 *   MakeBox      -- Make a box and shadow Border.
 *
 *    SYNOPSIS
 *   struct Border *MakeBox(pen1, pen2, dm, xo, yo, x1, y1, x2, y2)
 *
 *    FUNCTION
 *   This function is used to create a Border structure to draw a box
 *         and its shadow.
 *
 *    INPUTS
 *   int pen1                  Color for the box pen
 *   int pen2                  Color for the shadow pen
 *   int dm                    Drawing mode
 *   int xo, yo                Offsets for the left upper corner
 *   int x1, y1                left upper corner
 *   int x2, y2                right lower corner
 *
 *    RESULT
 *   Pointer to Border structure, NULL on failure.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
 *
**/
#define BSIZE ((long) sizeof(struct Border))
#define GSIZE ((long) sizeof(struct Gadget))
#define SISIZE ((long) sizeof(struct StringInfo))
#define XYSIZE 20L
	
/*  						pen1, pen2, dm, xo, yo, x1, y1, x2, y2) */
struct Border *MakeBox ( UBYTE pen1, UBYTE pen2, UBYTE dm, WORD xo, WORD yo, WORD x1, WORD y1, WORD x2, WORD y2 )
{
	SHORT *xy1 = NULL, *xy2 = NULL;
	struct Border *b1 = NULL, *b2 = NULL;
	
	b1 = AllocMem(BSIZE, MEMF_CLEAR);
	if (b1 == NULL)
		goto cleanup;
	
	b2 = AllocMem(BSIZE, MEMF_CLEAR);
	if (b2 == NULL)
		goto cleanup;
	
	xy1 = AllocMem(XYSIZE, 0L);
	if (xy1 == NULL)
		goto cleanup;
	
	xy2 = AllocMem(XYSIZE, 0L);
	if (xy2 == NULL)
		goto cleanup;
	
	b1->NextBorder = b2;
	b1->DrawMode   = dm;
	b1->XY         = xy1;
	b1->LeftEdge   = xo;
	b1->TopEdge    = yo;
	b1->Count      = 5;
	b1->FrontPen   = pen1;
	
	if (IntuitionBase->LibNode.lib_Version >= 36) 
	{
		xy1[0] = x2 - 1;
		xy1[1] = y1;
		xy1[2] = x1;
		xy1[3] = y1;
		xy1[4] = x1;
		xy1[5] = y2;
		xy1[6] = x1 + 1;
		xy1[7] = y2 - 1;
		xy1[8] = x1 + 1;
		xy1[9] = y1;
	}
	else
	{
		xy1[0] = x1;
		xy1[1] = y1;
		xy1[2] = x1;
		xy1[3] = y2;
		xy1[4] = x2;
		xy1[5] = y2;
		xy1[6] = x2;
		xy1[7] = y1;
		xy1[8] = x1;
		xy1[9] = y1;
	}
	
	b2->NextBorder = NULL;
	b2->DrawMode   = dm;
	b2->XY         = xy2;
	b2->LeftEdge   = xo;
	b2->TopEdge    = yo;
	b2->Count      = 5;
	b2->FrontPen   = pen2;
	
	if (IntuitionBase->LibNode.lib_Version >= 36) 
	{
		xy2[0] = x1 + 1;
		xy2[1] = y2;
		xy2[2] = x2;
		xy2[3] = y2;
		xy2[4] = x2;
		xy2[5] = y1;
		xy2[6] = x2 - 1;
		xy2[7] = y1 + 1;
		xy2[8] = x2 - 1;
		xy2[9] = y2;
	}
	else
	{
		xy2[0] = x1 + 2;
		xy2[1] = y2 + 1;
		xy2[2] = x2 + 2;
		xy2[3] = y2 + 1;
		xy2[4] = x2 + 2;
		xy2[5] = y1 + 1;
		xy2[6] = x2 + 1;
		xy2[7] = y1 + 1;
		xy2[8] = x2 + 1;
		xy2[9] = y2 + 1;
	}
	return(b1);
	
	cleanup:
	if (b1)
		FreeMem(b1, BSIZE);
	if (b2)
		FreeMem(b2, BSIZE);
	if (xy1)
		FreeMem(xy1, XYSIZE);
	if (xy2)
		FreeMem(xy2, XYSIZE);
	
	return(NULL);
}

/**
 *
 *
 *    FreeBox(1.0)    ARP Programmers Manual   FreeBox(1.0)
 *
 *
 *    NAME
 *   FreeBox      -- Free an IntuiText structure.
 *
 *    SYNOPSIS
 *   struct Border *FreeBox(b)
 *
 *    FUNCTION
 *   This function is used to free a list of Border structures.
 *
 *    INPUTS
 *   struct Border *b First in a linked list of Borders to be
 *    freed.
 *
 *    RESULT
 *   Guaranteed NULL.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
 *
**/
struct Border *FreeBox( struct Border *b )
{
	struct Border *b1 = NULL;
	
	while (b) 
	{
		b1 = b->NextBorder;
		
		if (b->XY)
			FreeMem(b->XY, XYSIZE);
		FreeMem(b, BSIZE);
		b = b1;
	}
	
	return(NULL);
}


/**
 *
 *
 *    MakeSIText(1.0)    ARP Programmers Manual   MakeSIText(1.0)
 *
 *
 *    NAME
 *   MakeSIText      -- Make a linked list of IntuiText structures.
 *
 *    SYNOPSIS
 *   struct IntuiText *MakeSIText(pen1, pen2, dm, xo, yo, text)
 *
 *    FUNCTION
 *   This function is used to create a IntuiText structures given some
 *         text.
 *
 *    INPUTS
 *   int pen1                  Color for the front pen
 *   int pen2                  Color for the back pen
 *   int dm                    Drawing mode
 *   int xo, yo                Offsets for the left upper corner
 *   UBYTE *text               The actual text.
 *
 *    RESULT
 *   Pointer to IntuitText structure, NULL on failure.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *   If there are embedded linefeeds in the string, multiple IntuiText
 *   structures will be created and added to the list. The individual
 *   IntuiText's will be spaced vertically.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
 *
**/
#define ISIZE ((long) sizeof(struct IntuiText))
	
struct IntuiText *MakeSIText( UBYTE pen1, UBYTE pen2, UBYTE dm, WORD xo, WORD yo, UBYTE *text)
{
	struct IntuiText *i1 = NULL, *i2 = NULL, *it = NULL;
	UBYTE *t1 = NULL, *t2 = NULL;
	ULONG *foo;
	unsigned int n = 0;
	int l = 0;
	
	t1 = text;
	while (t1) 
	{
		t2 = strchr(t1, '\n');
		
		if (t2)
			n = t2 - t1;
		else
			n = strlen(t1);
		
		i2 = AllocMem(ISIZE, MEMF_CLEAR);
		if (i2 == NULL)
			goto cleanup;
		
		if (i1) 
		{
			i1->NextText = i2;
			i1 = i2;
		}
		else
		{
			it = i1 = i2;
		}
		
		i1->FrontPen   = pen1;
		i1->BackPen    = pen2;
		i1->DrawMode   = dm;
		i1->LeftEdge   = xo;
		i1->TopEdge    = yo + LINEHEIGHT * l;
		i1->ITextFont  = Topaz80Equiv();
		i1->NextText   = NULL;
		
//		i1->IText      =  malloc( n + 1 );
	
		foo            = (ULONG *) AllocMem( (ULONG) (n + 5), MEMF_CLEAR );
		*foo++         = (ULONG) (n + 5);
		i1->IText      = (UBYTE *) foo;
		if (i1->IText == NULL)
			goto cleanup;
		strncpy(i1->IText, t1, (size_t) n);
		i1->IText[n] = '\0';
		
		if (t2 == NULL)
			break;
		t1 = t2;
		t1++;
		l++;
	}
	
	return(it);
	
	cleanup:
	FreeSIText(it);
	
	return(NULL);
}


/**
 *
 *
 *    FreeSIText(1.0)    ARP Programmers Manual   FreeSIText(1.0)
 *
 *
 *    NAME
 *   FreeSIText      -- Free an IntuiText structure.
 *
 *    SYNOPSIS
 *   struct IntuiText *FreeSIText(it)
 *
 *    FUNCTION
 *   This function is used to free a list of IntuiText structures.
 *
 *    INPUTS
 *   struct IntuiText *it First in a linked list of IntuiText's to be
 *    freed.
 *
 *    RESULT
 *   Guaranteed NULL.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
 *
**/
struct IntuiText *FreeSIText( struct IntuiText *it )
{
	struct IntuiText *it1 = NULL;
	ULONG			 *foo = NULL;
	
	while (it) 
	{
		if (it->IText)
		{
			foo = (ULONG *) it->IText;
			foo--;
			FreeMem( foo, *foo );
		}
		
		it1 = it->NextText;
		FreeMem(it, ISIZE);
		it = it1;
	}
	return(NULL);
}


/**
 *
 *
 *    SITextLength(1.0)    ARP Programmers Manual   SITextLength(1.0)
 *
 *
 *    NAME
 *   SITextLength      -- Determine width of list of IntuiText structures.
 *
 *    SYNOPSIS
 *   int SITextLength(it)
 *
 *    FUNCTION
 *   This function is used to find the horizontal size of the
 *   enclosing box of a list of IntuiText structures.
 *
 *    INPUTS
 *   struct IntuiText *it First in a linked list of IntuiText's to be
 *    measured.
 *
 *    RESULT
 *   Horizontal size.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
 *
**/
WORD SITextLength( struct IntuiText *it )
{
	WORD hsize = 0, temp = 0;
	
	while (it) 
	{
		if ((temp = it->LeftEdge + (strlen(it->IText) << 3)) > hsize)
			hsize = temp;
		it = it->NextText;
	}
	return(hsize);
}


/**
 *
 *
 *    SITextHeight(1.0)    ARP Programmers Manual   SITextHeight(1.0)
 *
 *
 *    NAME
 *   SITextHeight      -- Determine height of list of IntuiText structures.
 *
 *    SYNOPSIS
 *   int SITextHeight(it)
 *
 *    FUNCTION
 *   This function is used to determine the height of a limked list of
 *   IntuiText structures
 *
 *    INPUTS
 *   struct IntuiText *it First in a linked list of IntuiText's to be
 *    freed.
 *
 *    RESULT
 *   Height.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *   Also, it assumes all text is in the positive direction.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
**/
WORD SITextHeight( struct IntuiText *it )
{
	WORD vsize = 0, temp = 0;
	
	while (it) 
	{
		if ((temp = it->TopEdge + it->ITextFont->ta_YSize) > vsize)
			vsize = temp;
		it = it->NextText;
	}
	return(vsize);
}


/**
 *    MakeSStrGad(1.0)    ARP Programmers Manual   MakeSStrGad(1.0)
 *
 *
 *    NAME
 *   MakeSStrGad   -- Make a simple string gadget
 *
 *    SYNOPSIS
 *   StrGadget = MakeSStrGad(s, p1, p2, x, y, width, id, ec)
 *
 *    FUNCTION
 *   This function creates asimple string gadget. You still need to add
 *   it to the window and refresh it.
 *
 *    INPUTS
 *   char *s     Pointer to a string for the string gadget
 *   int p1     Pen number for the gadget border
 *   int p2     Pen number for the gadget border's shadow
 *   int x      Top left x coordinate of gadget
 *   int y      Top left y coordinate of gadget
 *   int width     Width of gadget
 *   int id     Gadget id
 *
 *    OUTPUTS
 *   int *ec     Error code
 *
 *    RESULT
 *   struct Gadget *StrGadget   A pointer to the Gadget structure.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *   Use FreeSimpGad() to deallocate all allocated structures.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
**/
struct Gadget *MakeSStrGad(UBYTE *s, UBYTE p1, UBYTE p2, WORD x, WORD y, WORD width, WORD id, ULONG *ec)
{
	UBYTE *undobuffer = NULL, *SREQSIBuff = NULL;
	struct Gadget *SREQString = NULL;
	struct StringInfo *SREQSInfo = NULL;
	WORD wd, xoff, yoff, vsize, tht;
	
	if (width > 0) 
	{
		wd    = width;
		xoff  = -2;
		yoff  = -1;
		vsize =  9;
		tht   =  8;
	}
	else
	{
		wd    = -width - 4;
		x    += 4;
		xoff  = -4;
		y    -= 1;
		yoff  = -2;
		vsize = 11;
		tht   = 10;
	}
	/*
	 *   Get the string gadget structure.
	 */
	SREQString = (struct Gadget *) AllocMem(GSIZE, MEMF_CLEAR);
	if (SREQString == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(NULL);
	}
	/*
	 *   Get a StringInfo structure
	 */
	SREQSInfo = (struct StringInfo *) AllocMem(SISIZE, MEMF_CLEAR);
	if (SREQSInfo == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(FreeSimpGad(SREQString));
	}
	SREQString->SpecialInfo = (APTR) SREQSInfo;
	/*
	 *   Give it an UndoBuffer
	 */
	undobuffer = (UBYTE *) AllocMem(BUFLEN, MEMF_CLEAR);
	if (undobuffer == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(FreeSimpGad(SREQString));
	}
	SREQSInfo->UndoBuffer = undobuffer;
	/*
	 *   Give it a string buffer and copy the default string into it.
	 */
	SREQSIBuff = (UBYTE *) AllocMem(BUFLEN, MEMF_CLEAR);
	if (SREQSIBuff == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(FreeSimpGad(SREQString));
	}
	SREQSInfo->Buffer   = SREQSIBuff;
	SREQSInfo->MaxChars = BUFLEN;
	
	strcpy(SREQSIBuff, s);
	
	SREQString->LeftEdge     = x;
	SREQString->TopEdge      = y;
	SREQString->Width        = wd;
	SREQString->Height       = tht;
	SREQString->Activation   = RELVERIFY;
	SREQString->GadgetType   = STRGADGET;
	SREQString->GadgetID     = id;
	/*
	 *   Give it the "look and feel"...
	 */
	if (IntuitionBase->LibNode.lib_Version >= 36) 
	{
		SREQString->GadgetRender = ( APTR )	/* ( struct Border * ) */
		MakeBox ( p2, p1, (int) JAM1, xoff, yoff, 0, 0, wd + 3, vsize );
		if (  SREQString->GadgetRender == NULL) 
		{
			*ec = SR_OUTOFMEMORY;
			return(FreeSimpGad(SREQString));
		}
		if (width < 0) 
		{
			if (((  (struct Border *) SREQString->GadgetRender)->
				NextBorder->NextBorder = ( APTR )
			MakeBox(p1, p2, (int) JAM1, -6, -3, 0, 0, wd + 7, 13)) == NULL) 
			{
				*ec = SR_OUTOFMEMORY;
				return(FreeSimpGad(SREQString));
			}
		}
	}
	else
	{
		SREQString->GadgetRender =
		(APTR) MakeBox(p1, p2, (int) JAM1, -2, -2, 0, 0, wd + 3, 11);
		if (SREQString->GadgetRender == NULL) 
		{
			*ec = SR_OUTOFMEMORY;
			return(FreeSimpGad(SREQString));
		}
	}
	
	return(SREQString);
}

/**
 *    FreeSimpGad(1.0)    ARP Programmers Manual   FreeSimpGad(1.0)
 *
 *
 *    NAME
 *   FreeSimpGad   -- Free a simple gadget
 *
 *    SYNOPSIS
 *   result = FreeSimpGad(Gadget)
 *
 *    FUNCTION
 *   This function frees a simple gadget safely.
 *
 *    INPUTS
 *   struct Gadget *Gadget   A pointer to the Gadget structure.
 *
 *    RESULT
 *   struct Gadget *result      Guaranteed NULL.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *   This function HAS to be used after calling MakeSStrGad or
 *   MakeSBoolGad to free up the storage allocated.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
**/
struct Gadget *FreeSimpGad( struct Gadget *g )
{
	register struct StringInfo *SREQSInfo;
	
	if (g) 
	{
		FreeBox(g->GadgetRender);
		FreeSIText(g->GadgetText);
		
		if (g->GadgetType == STRGADGET) 
		{
			SREQSInfo = (struct StringInfo *) g->SpecialInfo;
			if (SREQSInfo) 
			{
				if (SREQSInfo->Buffer)
					FreeMem(SREQSInfo->Buffer,     BUFLEN);
				if (SREQSInfo->UndoBuffer)
					FreeMem(SREQSInfo->UndoBuffer, BUFLEN);
				
				FreeMem(SREQSInfo, SISIZE);
			}
		}
		
		FreeMem(g, GSIZE);
	}
	return(NULL);
}



/**
 *    MakeSBoolGad(1.0)    ARP Programmers Manual   MakeSBoolGad(1.0)
 *
 *
 *    NAME
 *   MakeSBoolGad   -- Make  a simple boolean gadget
 *
 *    SYNOPSIS
 *   BoolGadget = MakeSBoolGad(s, p1, p2, p3, x, y, hslop, vslop,
 *                            id, ec)
 *
 *    FUNCTION
 *   This function creates a simple boolean gadget. You still need to add
 *   it to the window and refresh it.
 *
 *    INPUTS
 *   char *s     Pointer to a string for the gadget text
 *   int p1     Pen number for the gadget border
 *   int p2     Pen number for the gadget border's shadow
 *   int p3     Pen number for the gadget text
 *   int x      Top left x coordinate of gadget
 *   int y      Top left y coordinate of gadget
 *   int hslop     Extra room before and after text of gadget
 *   int vslop     Extra room above and below gadget
 *   int id     Gadget id
 *
 *    OUTPUTS
 *   int *ec     Error code
 *
 *    RESULT
 *   struct Gadget *BoolGadget   A pointer to the Gadget structure.
 *
 *    ADDITIONAL CONSIDERATIONS
 *   This routine assumes the necessary libraries to be open.
 *   Use FreeSimpGad() to free all allocated structures.
 *
 *    BUGS
 *   None reported sofar.
 *
 *    AUTHOR
 *   W.G.J. Langeveld (WGL)
 *
 *
**/
struct Gadget *MakeSBoolGad(UBYTE *s, UBYTE p1, UBYTE p2, UBYTE p3, WORD x, WORD y, WORD hslop, WORD vslop, WORD id, ULONG *ec)
{
	struct Gadget *SREQGadget;
	int width, height;
	
	*ec = 0;
	
	SREQGadget = (struct Gadget *) AllocMem(GSIZE, MEMF_CLEAR);
	if (SREQGadget == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(NULL);
	}
	/*
	 *   Add the text
	 */
	SREQGadget->GadgetText = MakeSIText(p3, 0, (int) JAM1, hslop, vslop, s);
	
	width  = SITextLength(SREQGadget->GadgetText) + hslop;
	height = SITextHeight(SREQGadget->GadgetText) + vslop;
	
	SREQGadget->LeftEdge     = x;
	SREQGadget->TopEdge      = y;
	SREQGadget->Width        = width;
	SREQGadget->Height       = height;
	SREQGadget->Activation   = RELVERIFY;
	SREQGadget->GadgetType   = BOOLGADGET;
	SREQGadget->GadgetID     = id;
	/*
	 *   Give it the "look and feel"...
	 */
	SREQGadget->GadgetRender =
	(APTR) MakeBox(p1, p2, (int) JAM1, -2, -1, 0, 0, width + 3, height + 1);
	
	if (SREQGadget->GadgetRender == NULL) 
	{
		*ec = SR_OUTOFMEMORY;
		return(FreeSimpGad(SREQGadget));
	}
	/*
	 *   All done, add the gadget
	 */
	return(SREQGadget);
}

