/*
	enter.c		-	Bill Nickerson, 1988

	Functions for defining formulas and associated gadgets.

	Export: FreeGads, InitGads, PickFormula, GetFormula
	Static: none
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include "enter.h"
#include "main.h"

/*
	Imported functions and variables.
*/
extern struct Window *OpenWindow();
extern void CloseWindow();
extern struct IntuiMessage *GetMsg();
extern void Wait();
extern void ReplyMsg();
extern void SetAPen();
extern void DisplayBeep();
extern int ActivateGadget();

extern Formula flist[];
extern struct Gadget *ButtonList;
extern int iswrong;

/*--------------------Parameter input gadget---------------------------------*/

UBYTE InBuf[80];

struct StringInfo StrInfo =
{ InBuf, NULL, 0, 80, 0, 0, 0, 0, 0, 0, NULL, 0L, NULL };

struct Gadget StringG =
{ NULL, 2, 15, 625, 10, SELECTED, 0, STRGADGET,
  NULL, NULL, NULL, NULL, &StrInfo, 0, NULL };

/*--------------------Formula definition gadget------------------------------*/

SHORT ArrowBox[]   = { 0, 0, 0, 10, 10, 10, 10, 0, 0, 0 };
SHORT ArrowUp[]    = { 0, 10, 10, 10, 5, 0, 0, 10 };
SHORT ArrowDown[]  = { 0, 0, 5, 10, 10, 0, 0, 0 };
SHORT ArrowLeft[]  = { 10, 0, 10, 10, 0, 5, 10, 0 };
SHORT ArrowRight[] = { 0, 0, 0, 10, 10, 5, 0, 0 };

struct Border AB   = { 0, 0, 1, 0, JAM1, 5, ArrowBox, NULL };
struct Border AU   = { 0, 0, 1, 0, JAM1, 4, ArrowUp, NULL };
struct Border AD   = { 0, 0, 1, 0, JAM1, 4, ArrowDown, NULL };
struct Border AL   = { 0, 0, 1, 0, JAM1, 4, ArrowLeft, NULL };
struct Border AR   = { 0, 0, 1, 0, JAM1, 4, ArrowRight, NULL };

struct Gadget ABG  = { &StringG, ARROWX, ARROWY, 10, 10, 0, GADGIMMEDIATE,
		       BOOLGADGET, &AB, NULL, NULL, NULL, NULL, ABID, NULL };
struct Gadget AUG  = { &ABG, ARROWX, ARROWY-15, 10, 10, 0, GADGIMMEDIATE,
		       BOOLGADGET, &AU, NULL, NULL, NULL, NULL, AUID, NULL };
struct Gadget ADG  = { &AUG, ARROWX, ARROWY+15, 10, 10, 0, GADGIMMEDIATE,
		       BOOLGADGET, &AD, NULL, NULL, NULL, NULL, ADID, NULL };
struct Gadget ALG  = { &ADG, ARROWX-15, ARROWY, 10, 10, 0, GADGIMMEDIATE,
		       BOOLGADGET, &AL, NULL, NULL, NULL, NULL, ALID, NULL };
struct Gadget ARG  = { &ALG, ARROWX+15, ARROWY, 10, 10, 0, GADGIMMEDIATE,
		       BOOLGADGET, &AR, NULL, NULL, NULL, NULL, ARID, NULL };

/*--------------------Okay/Cancel border gadget------------------------------*/

SHORT BCoords[]	   = { 0, 0, 0, 15, 55, 15, 55, 0, 0, 0 };
struct Border GB   = { 0, 0, 1, 0, JAM1, 5, BCoords, NULL };

/*--------------------Okay gadget--------------------------------------------*/

struct IntuiText OkayT = { 1, 0, JAM1, 11, 4, NULL, "Okay", NULL };

struct Gadget OkayG    = { &ARG, 5, ARROWY+8, 55, 15, 0,
			   GADGIMMEDIATE, BOOLGADGET,
			   &GB, NULL, &OkayT, NULL, NULL, OKAYID, NULL };

/*--------------------Cancel gadget------------------------------------------*/

struct IntuiText CancelT = { 1, 0, JAM1, 4, 4, NULL, "Cancel", NULL };

struct Gadget CancelG	 = { &OkayG, 65, ARROWY+8, 55, 15, 0,
			     GADGIMMEDIATE, BOOLGADGET,
			     &GB, NULL, &CancelT, NULL, NULL, CANCELID, NULL };

/*--------------------Join gadget--------------------------------------------*/

struct IntuiText JoinT   = { 1, 0, JAM1, 11, 4, NULL, "Join", NULL };

struct Gadget JoinG	 = { &CancelG, 35, ARROWY-10, 55, 15, GADGHCOMP,
			     GADGIMMEDIATE | TOGGLESELECT, BOOLGADGET,
			     &GB, NULL, &JoinT, NULL, NULL, JOINID, NULL };

/*--------------------NewWindow for "enter" window---------------------------*/

struct NewWindow SNW = { 5, 10, 630, 75, 0, 1, GADGETDOWN,
			 ACTIVATE, &JoinG, NULL, "Enter", NULL, NULL,
			 0, 0, 0, 0, WBENCHSCREEN };

/*--------------------NewWindow for "select" window--------------------------*/

struct NewWindow SELNW = { 5, 10, 630, 140, 0, 1, GADGETDOWN,
			   ACTIVATE, NULL, NULL, "Select", NULL, NULL,
			   0, 0, 0, 0, WBENCHSCREEN };

SHORT SelXY[]		= { 0, 0, 0, 5, 10, 5, 10, 0, 0, 0 };
struct Border SelB	= { 0, 0, 1, 0, JAM1, 5, SelXY, NULL };
struct Gadget SelG	= { NULL, 5, 0, 10, 5, GADGHCOMP, GADGIMMEDIATE | TOGGLESELECT,
			    BOOLGADGET, &SelB, NULL, NULL, NULL, NULL,
			    0, NULL };
struct Gadget SelOkayG	= { NULL, 5, 120, 55, 15, 0, GADGIMMEDIATE,
			    BOOLGADGET, &GB, NULL, &OkayT, NULL, NULL,
			    OKAYID, NULL };
struct Gadget SelCancelG= { &SelOkayG, 65, 120, 55, 15, 0, GADGIMMEDIATE,
			    BOOLGADGET, &GB, NULL, &CancelT, NULL, NULL,
			    CANCELID, NULL };

/*---------------------------------------------------------------------------*/

struct Gadget *ButtonList;

/*
	Deallocate all memory allocated to button gadget list.
	ButtonList is changed.
*/
void FreeGads()
{
	struct Gadget *tgad;

	while (ButtonList != NULL)
	{
		tgad = ButtonList;
		ButtonList = ButtonList->NextGadget;
		free(tgad);
	}
}

/*
	Make a button gadget list for use when entering/choosing
	formulas.
	ButtonList is changed.
*/
int InitGads()
{
	struct Gadget *tgad;
	int i;

	/*
		Allocate memory for buttons used to choose formulas.
		Stop if no memory is available.
	*/
	for (i = 0; i < MAXFORMULAS; i++)
		if ((tgad = (struct Gadget *)malloc(sizeof(struct Gadget))) == NULL)
		{
			FreeGads();
			return(0);
		}
		else
		{
			*tgad = SelG;
			tgad->TopEdge = 15 + i*10;
			tgad->GadgetID = i;
			tgad->NextGadget = ButtonList;
			ButtonList = tgad;
		}
	return(1);
}

/*
	howmany	- GIMMEONE (just 1 formula), GIMMESOME (>1 formula).

	Choose just one formula or a selection from a list of formulas.
	Returns -1 if CANCEL, or a choice. If GIMMESOME, 0 is returned
	and the chosen formulas have their "selected" flags set.
*/
int PickFormula( howmany )
int howmany;
{
	struct Window *Win;
	struct IntuiMessage *msg;
	struct Gadget *gi;
	ULONG class;
	int i, len, choice = -2;

	/*
		Deselect all gadgets.
	*/
	for (gi = ButtonList; gi != NULL; gi = gi->NextGadget)
		gi->Flags &= ~SELECTED;
	/*
		If we want to choose for than one formula, put "Okay" and
		"Cancel" gadgets on the window.
	*/
	if (howmany == GIMMESOME)
	{
		SelOkayG.NextGadget = ButtonList;
		SELNW.FirstGadget = &SelCancelG;
	}
	else	SELNW.FirstGadget = ButtonList;

	if ((Win = OpenWindow(&SELNW)) == NULL)
		return(-1);

	SetAPen(Win->RPort, 1L);

	/*
		Put all formulas beside their buttons.
	*/
	for (i = 0; i < MAXFORMULAS; i++)
	{
		if ((len = strlen(flist[i].form)) > 70)
			len = 70;
		Move(Win->RPort, 20, 15 + i*10 + Win->RPort->TxBaseline);
		Text(Win->RPort, flist[i].form, len);
	}

	/*
		Keep looping until we have either CANCEL or a choice.
	*/
	while (choice == -2)
	{
		Wait(1<<Win->UserPort->mp_SigBit);
		while (msg = GetMsg(Win->UserPort))
		{
			class = msg->Class;
			ReplyMsg(msg);

			if (class == GADGETDOWN)
			{
				gi = (struct Gadget *)(msg->IAddress);
				switch (gi->GadgetID)
				{
				case OKAYID:
					choice = 0;
					break;
				case CANCELID:
					choice = -1;
					break;
				default:
					if (howmany == GIMMEONE)
						choice = gi->GadgetID;
					else	flist[gi->GadgetID].selected ^= FSELECT;
				}
			}
		}
	}
	CloseWindow(Win);
	return(choice);
}

/*
	w	- window to receive information.
	f	- pointer to structure containing formula string.
	bnds	- pointer to array defining graph bounds.

	Display the given formula and bounds.
	Returns nothing.
*/
void DrawInfo( w, f, bnds )
struct Window *w;
char *f;
double bnds[];
{
	int len;
	char tmp[20];

	Move(w->RPort, 200, 33 + w->RPort->TxBaseline);
	Text(w->RPort, "                                             ", 45);
	if ((len = strlen(f)) > 40)
	{
		len = 40;
		Move(w->RPort, 200 + w->RPort->TxWidth*40, 33 + w->RPort->TxBaseline);
		Text(w->RPort, " ....", 5);
	}
	Move(w->RPort, 200, 33 + w->RPort->TxBaseline);
	Text(w->RPort, f, len);

	sprintf(tmp, "Y lo = %-6.3e", bnds[1]);
	Move(w->RPort, 200, 46 + w->RPort->TxBaseline);
	Text(w->RPort, tmp, strlen(tmp));
	sprintf(tmp, "Y hi = %-6.3e", bnds[0]);
	Move(w->RPort, 200 + w->RPort->TxWidth*20, 46 + w->RPort->TxBaseline);
	Text(w->RPort, tmp, strlen(tmp));
	sprintf(tmp, "X lo = %-6.3e", bnds[2]);
	Move(w->RPort, 200, 59 + w->RPort->TxBaseline);
	Text(w->RPort, tmp, strlen(tmp));
	sprintf(tmp, "X hi = %-6.3e", bnds[3]);
	Move(w->RPort, 200 + w->RPort->TxWidth*20, 59 + w->RPort->TxBaseline);
	Text(w->RPort, tmp, strlen(tmp));
}

/*
	f	- pointer to structure containing formula string.
	bnds	- pointer to array defining graph bounds.

	Allow the given formula or bounds to be changed.
	Returns 1 if anything was changed, 0 if changes were cancelled.
*/
int GetFormula( f, bnds )
Formula *f;
double bnds[];
{
	struct Window *Win;
	struct IntuiMessage *msg;
	struct Gadget *gi;
	ULONG class;
	char tform[80];
	double bnd, tbnd[4];
	int tselected, i;

	strcpy(InBuf, f->form);
	strcpy(tform, f->form);
	tselected = f->selected;
	for (i = 0; i < 4; i++)
		tbnd[i] = bnds[i];

	/*
		Set formula's initial "join dots" state.
	*/
	if (f->selected & FJOIN)
		JoinG.Flags |= SELECTED;
	else	JoinG.Flags &= ~SELECTED;

	if ((Win = OpenWindow(&SNW)) == NULL)
		return(0);

	ActivateGadget(&StringG, Win, NULL);
	SetAPen(Win->RPort, 1L);
	DrawInfo(Win, tform, tbnd);

	while (1)
	{
		Wait(1<<Win->UserPort->mp_SigBit);
		while (msg = GetMsg(Win->UserPort))
		{
			class = msg->Class;
			ReplyMsg(msg);

			if (class == GADGETDOWN)
			{
				gi = (struct Gadget *)(msg->IAddress);
				switch (gi->GadgetID)
				{
				case ABID:
					parse(InBuf, NULL);
					if (!iswrong)
					{
						strcpy(tform, InBuf);
						DrawInfo(Win, tform, tbnd);
					}
					else	DisplayBeep(Win->WScreen);
					break;
				case AUID:
				case ADID:
				case ALID:
				case ARID:
					if (sscanf(InBuf, "%lf", &bnd) == 1)
					{
						tbnd[gi->GadgetID-1] = bnd;
						DrawInfo(Win, tform, tbnd);
					}
					else	DisplayBeep(Win->WScreen);
					break;
				case JOINID:
					tselected ^= FJOIN;
					break;
				case OKAYID:
					strcpy(f->form, tform);
					f->selected = tselected;
					for (i = 0; i < 4; i++)
						bnds[i] = tbnd[i];
					CloseWindow(Win);
					return(1);
				case CANCELID:
					CloseWindow(Win);
					return(0);
				default:
					break;
				}
			}
		}
	}
}

