
/*	address_gui.c
 *
 *	Functions for the support of our graphics user interface. Responsible
 *	for opening and closing windows, and dealing with gadgets.
 */

#include "address_includes.h"

#define CONTROL_BUTTONS 6

/* Note -
		Defining gadgets, stringinfos and buffers out of a function means
		that they are all set to zeros at the start, rather than being 
		allocated on demand onto the stack, and containing random data. We
		can assume, therefore, that un-initialised fields contain zero. */

/* Gadget Structures */
struct Gadget window_gads[TOTAL_FIELDS+CONTROL_BUTTONS];

/* String info structures for each string gadget */
struct StringInfo string_info[TOTAL_FIELDS];

/* Character entry buffers for string gadgets */
char char_buffers[TOTAL_FIELDS][128];

/* Text strings for button labels */
struct IntuiText gad_text[TOTAL_FIELDS+CONTROL_BUTTONS];

char *control_names[] =
	{
	"Prev", "Next", "Save", "Goto", "Search", "New"
	};

char window_title[128] = "";

/* This is our newwindow structure */
struct NewWindow window_definition =
	{
	0,0,			/* Top left position of window. In this case, 0,0 */
	370,200,		/* Width and height of window. */
	0,1,			/* Block and detail pens. (Ignored if you have 2.04 or above) */
	CLOSEWINDOW |
		GADGETUP,		/* IDCMP flags. We want to know if user selects gadget 
										or clicks on close gadget */
	SMART_REFRESH |
		ACTIVATE |
		WINDOWCLOSE |
		WINDOWDRAG |
		WINDOWDEPTH,		/* Flags. This lot says our window will activate itself on 							opening, have a close gadget, a sizing gadget, be draggable
							and have the standard depth gadgets */
	&window_gads[0],		/* Pointer to first gadget. */
	NULL,		/* Ignore this one */
	(UBYTE *)"Address Book",	/* Window title: Self explanitory I hope! */
	NULL, NULL,
	64,64,				/* Windows minimum size */
	640,200,			/* And maximum */
	WBENCHSCREEN  /* Open on the workbench screen */
	};

/* Border vectors: element 5 & 7 are heights */
UWORD str_border_data[] = 
	{
	0, 0, 260+3, 0, 260+3, 0, 0, 0, 0, 0
	};

UWORD btn_border_data[] =
	{
	0, 0, 50+3, 0, 50+3, 0, 0, 0, 0, 0
	};

/* The border definition for our string & button gadgets */
struct Border str_border =
	{
	-2, -2, 1, 0, JAM1, 5, str_border_data, NULL
	};

struct Border btn_border =
	{
	-2, -2, 1, 0, JAM1, 5, btn_border_data, NULL
	};

/* These are various pointers to structures, including our window and
   any messages we might receive */

struct Screen wb_screen;
struct Window *addr_window = NULL;

/* Definitions we'll need from address_functions.c */
extern int field_lengths[];
extern char *field_names[];
extern long total_records;

/**************************************
 *
 *	BOOL open_window(void);
 *
 *	Attempts to open our window with our gadgets on it. Returns FALSE for
 *	a failure, or TRUE if the window was opened successfully.
 */

BOOL open_window(void)
{
	int loop;
	int bar_height;
	int font_height;
	int	gadget_spacing = 0;
	int window_height = 0;

	/* Fetch some information about the workbench screen: 2.04 has a better way than this */
	if (!(GetScreenData(&wb_screen, sizeof (struct Screen), WBENCHSCREEN, NULL)));

	bar_height = wb_screen.BarHeight;			/* Height of window title */
	font_height = wb_screen.Font->ta_YSize;
	gadget_spacing = font_height+6;

	str_border_data[5] = font_height + 4;
	str_border_data[7] = font_height + 4;
	btn_border_data[5] = font_height + 4;
	btn_border_data[7] = font_height + 4;

	/* Create our gadgets, string gadgets first */
	for (loop = 0; loop < TOTAL_FIELDS; loop ++)
		{
		window_gads[loop].NextGadget 	= &window_gads[loop+1];

		/* Gadget hit-box */
		window_gads[loop].LeftEdge 			= 100;
		window_gads[loop].TopEdge  			=	bar_height + 4 + (loop * gadget_spacing);
		window_gads[loop].Width					= 250;
		window_gads[loop].Height				= font_height;

		/* Gadget flags and rendering information */
		window_gads[loop].Activation		= GACT_RELVERIFY;
		window_gads[loop].GadgetType		=	GTYP_STRGADGET;
		window_gads[loop].GadgetRender	= &str_border;
		window_gads[loop].SelectRender	= NULL;

		init_gadget_text(&gad_text[loop], field_names[loop], TRUE);
		window_gads[loop].GadgetText		= &gad_text[loop];
		window_gads[loop].SpecialInfo 	= &string_info[loop];
		window_gads[loop].GadgetID			= loop;

		/* Set up this gadgets special info structure */
		string_info[loop].Buffer				= &char_buffers[loop][0];
		string_info[loop].MaxChars			= field_lengths[loop];
		}

	for (loop = TOTAL_FIELDS; loop < TOTAL_FIELDS+CONTROL_BUTTONS; loop++)
		{
		window_gads[loop].NextGadget 	= &window_gads[loop+1];

		/* Gadget positioning */
		window_gads[loop].LeftEdge			= 10 + ((loop - TOTAL_FIELDS) * 60);
		window_gads[loop].TopEdge  			=	bar_height + 4 + (TOTAL_FIELDS * gadget_spacing);
		window_gads[loop].Width 				= 50;
		window_gads[loop].Height				= font_height;

		/* Gadget flags and rendering information */
		window_gads[loop].Flags					= GFLG_GADGHCOMP;
		window_gads[loop].Activation		= GACT_RELVERIFY;
		window_gads[loop].GadgetType		=	GTYP_BOOLGADGET;
		window_gads[loop].GadgetRender	= &btn_border;
		window_gads[loop].SelectRender	= NULL;

		init_gadget_text(&gad_text[loop], control_names[loop - TOTAL_FIELDS], FALSE);
		window_gads[loop].GadgetText		= &gad_text[loop];
		window_gads[loop].SpecialInfo 	= NULL;
		window_gads[loop].GadgetID			= loop;

		/* Ensure window height gets set correctly */
		window_height = window_gads[loop].TopEdge + gadget_spacing + 4;
		}

	/* Terminate list of new gadgets */
	window_gads[TOTAL_FIELDS+CONTROL_BUTTONS-1].NextGadget = NULL;

	/* Now open our window */
	window_definition.Height = window_height;
	if (!(addr_window = OpenWindow(&window_definition)))
		return FALSE;					/* OpenWindow failed! */

	/* Activate first string gadget */
	ActivateGadget(&window_gads[0], addr_window, NULL);

	return TRUE;
}

/**************************************
 *
 *	void close_window(void);
 *
 *	Closes our window if it was opened, freeing any resources that came
 *	with it. If the window is not open, this routine does nothing.
 */

void close_window(void)
{
	/* Close window if it was opened */
	if (addr_window)	CloseWindow(addr_window);

	return;
}

/**************************************
 *
 *	void init_gadget_text(struct IntuiText *itext, char *string, BOOL str);
 *
 *	Sets up the supplied intui-text structure to point to the named
 *	string. If the str paramter is true, then the string is placed neatly
 *	to the left of a gadget (ie, titling string gadgets)
 */

void init_gadget_text(struct IntuiText *itext, char *string, BOOL str)
{
	itext->FrontPen 	= 1;
	itext->BackPen 		= 0;
	itext->DrawMode		= JAM1;
	itext->LeftEdge		= 0;
	itext->TopEdge		= 0;
	itext->ITextFont	= NULL;
	itext->IText 			= string;
	itext->NextText		= 0;

	/* If this is a string gadget, place text to left */
	if (str)
		itext->LeftEdge = -90;

	return;
}

/**************************************
 *
 *	BOOL show_current_record(char *record_data, long record_id);
 *
 *	Reads the named record and attempts to display it in the gadgets on
 *	screen, updating the window title accordingly. Returns FALSE for a
 *	failure.
 *
 *	If passed -1 as a record ID, it clears the gadgets and shows the
 *	"Creating new record" message in the window title instead.
 */

BOOL show_current_record(char *record_data, long record_id)
{
	char 	*field_offset;
	int		loop;

	/* Attempt to read the named record */
	if (record_id == CREATE_NEW || record_id == CREATE_SEARCH)
		{
		/* Special case, so clear the record */
		memset(record_data, 0, RECORD_LENGTH);
		}
	else
		{
		/* Read a record in */
		if (!(read_record_data(record_data, record_id)))	return FALSE;
		}

	/*
	**	Before we alter the gadgets, we must remove them
	*/
	RemoveGList(addr_window, window_gads, -1);

	/*
	**	Now go through record, copying fields to string gadgets.
	*/
	field_offset = record_data;

	for (loop = 0; loop < TOTAL_FIELDS; loop ++)
		{
		strcpy(((struct StringInfo *)(window_gads[loop].SpecialInfo))->Buffer, field_offset);
		
		field_offset = field_offset + field_lengths[loop];
		}

	/*
	**	Now they are updated, we can add them back and refresh the window
	*/
	AddGList(addr_window, window_gads, -1, -1, NULL);
	RefreshGList(window_gads, addr_window, NULL, -1);

	/*
	**	Now show something sensible on our window title
	*/
	switch(record_id)
		{
		case CREATE_NEW:
			sprintf(window_title, "Create new record...");
			break;
		case CREATE_SEARCH:
			sprintf(window_title, "Enter search data...");
			break;
		default:
			sprintf(window_title, "Record %ld of %ld", record_id+1, total_records);
			break;
		}

	SetWindowTitles(addr_window, window_title, (UBYTE *)~0);

	return TRUE;
}

/**************************************
 *
 *	BOOL YesOrNo(char *body_text, char *ok_text, char *cancel_text)
 *
 *	Shows a requester and returns TRUE if the OK button was pressed, and
 *	FALSE if the CANCEL button was pressed.
 */

BOOL YesOrNo(char *body_text, char *ok_text, char *cancel_text)
{
	struct 	IntuiText texts[3];
	struct	IntuiText *postext;
	int		loop;

	/* Knock up our IntuiText structures */
	for (loop = 0; loop < 3; loop ++)
		{
		texts[loop].FrontPen 		= 1;
		texts[loop].BackPen			= 0;
		texts[loop].DrawMode		= JAM1;
		texts[loop].LeftEdge		= 10;
		texts[loop].TopEdge			= 5;
		texts[loop].ITextFont		= NULL;

		switch(loop)
			{
			case 0:
				texts[loop].IText = body_text;
				break;
			case 1:				/* Deal with the OK button and allow it to be blank */
				if (ok_text)
					{
					texts[loop].IText = ok_text;
					postext = &texts[loop];
					}
				else
					postext = NULL;					
				break;
			case 2:
				texts[loop].IText = cancel_text;
				break;
			}
		
		texts[loop].NextText 		= NULL;
		}

	return (AutoRequest(addr_window, &texts[0], postext, &texts[2], 0, 0, 320, 60));
}
