/*
** gadget1.c:  Simple example of GadTools gadgets.
**
** (C) Copyright 1990, Commodore-Amiga, Inc.
**
** Executables based on this information may be used in software
** for Commodore Amiga computers.  All other rights reserved.
** This information is provided "as is"; no warranties are made.  All
** use is at your own risk. No liability or responsibility is assumed.
*/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>

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

void printf(STRPTR,...);
void exit(int);

/*------------------------------------------------------------------------*/

void main(void);
void bail_out(int, STRPTR);
BOOL HandleGadgetEvent(struct Window *, struct Gadget *, UWORD);
struct Gadget *CreateAllGadgets(struct Gadget **, void *, UWORD);

/*------------------------------------------------------------------------*/

/* Gadget defines of our choosing, to be used as GadgetID's: */

#define GAD_SLIDER	1
#define GAD_STRING	2
#define GAD_BUTTON	3

/* Range for the slider: */

#define SLIDER_MIN	1
#define SLIDER_MAX	20

/*------------------------------------------------------------------------*/

struct TextAttr Topaz80 =
{
    "topaz.font",	/*  Name */
    8,			/*  YSize */
    0,			/*  Style */
    0,			/*  Flags */
};

extern struct Library *SysBase;
struct GfxBase *GfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *GadToolsBase = NULL;
struct TextFont *font = NULL;
struct Screen *mysc = NULL;
struct Gadget *glist = NULL;
struct Window *mywin = NULL;
void *vi = NULL;

BOOL terminated = FALSE;
WORD slider_level = 5;
struct Gadget *slidergad;

void main(void)
{
    struct IntuiMessage *imsg;
    struct Gadget *gad;
    ULONG imsgClass;
    UWORD imsgCode;
    UWORD topborder;

    /*  Open all libraries: */

    if (!(GfxBase = (struct GfxBase *)
	OpenLibrary("graphics.library", 36L)))
	bail_out(20, "Requires V36 graphics.library");

    if (!(IntuitionBase = (struct IntuitionBase *)
	OpenLibrary("intuition.library", 36L)))
	bail_out(20, "Requires V36 intuition.library");

    if (!(GadToolsBase = OpenLibrary("gadtools.library", 36L)))
	bail_out(20, "Requires V36 gadtools.library");

    /*  Open topaz 8 font, so we can be sure it's openable
	when we later set ng_TextAttr to &Topaz80: */
    if (!(font = OpenFont(&Topaz80)))
	bail_out(20, "Failed to open Topaz 80");

    if (!(mysc = LockPubScreen(NULL)))
	bail_out(20, "Couldn't lock default public screen");

    if (!(vi = GetVisualInfo(mysc,
	TAG_DONE)))
	bail_out(20, "GetVisualInfo() failed");

    /* ZZZ */
    topborder = mysc->WBorTop + (mysc->Font->ta_YSize + 1);

    if (!CreateAllGadgets(&glist, vi, topborder))
    {
	bail_out(20, "CreateAllGadgets() failed");
    }

    if (!(mywin = OpenWindowTags(NULL,
	WA_Width, 400,
	WA_InnerHeight, 100,

	WA_Activate, TRUE,
	WA_DragBar, TRUE,
	WA_DepthGadget, TRUE,
	WA_CloseGadget, TRUE,
	WA_SizeGadget, TRUE,
	WA_SimpleRefresh, TRUE,

	WA_IDCMP, CLOSEWINDOW | REFRESHWINDOW | \
	    SLIDERIDCMP | STRINGIDCMP | BUTTONIDCMP,

	WA_MinWidth, 50,
	WA_MinHeight, 50,
	WA_Title, "GadTools Gadget Demo 1",

	TAG_DONE)))
	bail_out(20, "OpenWindow() failed");

    /*  Add gadgets, refresh them, and call the toolkit refresh function
	too: */
    AddGList(mywin, glist, ((UWORD) -1), ((UWORD) -1), NULL);
    RefreshGList(glist, mywin, NULL, ((UWORD) -1));
    GT_RefreshWindow(mywin, NULL);

    while (!terminated)
    {
	Wait (1 << mywin->UserPort->mp_SigBit);
	/*  GT_GetIMsg() returns a cooked-up IntuiMessage with
	    more friendly information for complex gadget classes.  Use
	    it wherever you get IntuiMessages: */
	while ((!terminated) && (imsg = GT_GetIMsg(mywin->UserPort)))
	{
	    imsgClass = imsg->Class;
	    imsgCode = imsg->Code;
	    /*  Presuming a gadget, of course, but no harm... */
	    gad = (struct Gadget *)imsg->IAddress;
	    /*  Use the toolkit message-replying function here... */
	    GT_ReplyIMsg(imsg);
	    switch (imsgClass)
	    {
		case GADGETUP:
		    printf("GADGETUP.  ");
		    terminated = HandleGadgetEvent(mywin, gad, imsgCode);
		    break;

		case GADGETDOWN:
		    printf("GADGETDOWN.  ");
		    terminated = HandleGadgetEvent(mywin, gad, imsgCode);
		    break;

		case MOUSEMOVE:
		    printf("MOUSEMOVE.  ");
		    terminated = HandleGadgetEvent(mywin, gad, imsgCode);
		    break;

		case CLOSEWINDOW:
		    printf("CLOSEWINDOW.\n");
		    terminated = TRUE;
		    break;

		case REFRESHWINDOW:
		    printf("REFRESHWINDOW.\n");
		    /*  You must use GT_BeginRefresh() where you would
			normally have your first BeginRefresh() */
		    GT_BeginRefresh(mywin);
		    GT_EndRefresh(mywin, TRUE);
		    break;
	    }
	}
    }
    bail_out(0, NULL);
}

/*------------------------------------------------------------------------*/

/*/ bail_out()
 *
 * Function to close down or free any opened or allocated stuff, and then
 * exit.
 *
 */

void bail_out(code, error)

int code;
STRPTR error;

{
    if (mywin)
    {
	CloseWindow(mywin);
    }

    /*  None of these two calls mind a NULL parameter, so it's not
	necessary to check for non-NULL before calling.  If we do that,
	we must be certain that the OpenLibrary() of GadTools succeeded,
	or else we would be jumping into outer space: */
    if (GadToolsBase)
    {
	FreeVisualInfo(vi);
	FreeGadgets(glist);
	CloseLibrary(GadToolsBase);
    }

    if (mysc)
    {
	UnlockPubScreen(NULL, mysc);
    }

    if (font)
    {
    	CloseFont(font);
    }

    if (IntuitionBase)
    {
	CloseLibrary(IntuitionBase);
    }

    if (GfxBase)
    {
	CloseLibrary(GfxBase);
    }

    if (error)
    {
	printf("Error: %s\n", error);
    }
    exit(code);
}


/*------------------------------------------------------------------------*/

/*/ HandleGadgetEvent()
 *
 * Function to handle a GADGETUP or GADGETDOWN event.  For toolkit gadgets,
 * it is possible to use this function to handle MOUSEMOVEs as well, with
 * little or no work.
 *
 */

BOOL HandleGadgetEvent(win, gad, code)

struct Window *win;
struct Gadget *gad;
UWORD code;

{
    BOOL terminated = FALSE;

    switch (gad->GadgetID)
    {
	case GAD_SLIDER:
	    /*  Sliders report their level in the IntuiMessage Code
		field: */
	    printf("Slider at level %ld\n", code);
	    slider_level = code;
	    break;

	case GAD_STRING:
	    /*  String gadgets report GADGETUP's */
	    printf("String gadget: '%s'.\n",
		((struct StringInfo *)gad->SpecialInfo)->Buffer);
	    break;

	case GAD_BUTTON:
	    /*  Buttons always report GADGETUP's, nothing
		fancy or different here */
	    printf("Button was pressed.\n");
	    /*  increment the slider, or wrap it around: */
	    if (++slider_level > SLIDER_MAX)
	    {
		slider_level = SLIDER_MIN;
	    }
	    GT_SetGadgetAttrs(slidergad, win, NULL,
		GTSL_Level, slider_level,
		TAG_DONE);
	    break;
    }
    return(terminated);
}


/*------------------------------------------------------------------------*/

/*/ CreateAllGadgets()
 *
 * Here is where all the initialization and creation of toolkit gadgets
 * take place.  This function requires a pointer to a NULL-initialized
 * gadget list pointer.  It returns a pointer to the last created gadget,
 * which can be checked for success/failure.
 *
 */

struct Gadget *CreateAllGadgets(glistptr, vi, topborder)

struct Gadget **glistptr;
void *vi;
UWORD topborder;

{
    struct NewGadget ng;

    struct Gadget *gad;

    /*  All the gadget creation calls accept a pointer to the previous
	gadget, and link the new gadget to that gadget's NextGadget field.
	Also, they exit gracefully, returning NULL, if any previous gadget
	was NULL.  This limits the amount of checking for failure that
	is needed.  You only need to check before you tweak any gadget
	structure or use any of its fields, and finally once at the end,
	before you add the gadgets. */

    /*  We obligingly perform the following operation, required of
	any program that uses the toolkit.  It gives the toolkit a
	place to stuff context data: */
    gad = CreateContext(glistptr);

    /*  Since the NewGadget structure is unmodified by any of the
	CreateGadget() calls, we need only change those fields which
	are different. */

    ng.ng_LeftEdge = 100;
    ng.ng_TopEdge = 20+topborder;
    ng.ng_Width = 200;
    ng.ng_Height = 12;
    ng.ng_GadgetText = "Speed:   ";
    ng.ng_TextAttr = &Topaz80;
    ng.ng_VisualInfo = vi;
    ng.ng_GadgetID = GAD_SLIDER;
    ng.ng_Flags = NG_HIGHLABEL;

    slidergad = gad = CreateGadget(SLIDER_KIND, gad, &ng,
	GTSL_Min, SLIDER_MIN,
	GTSL_Max, SLIDER_MAX,
	GTSL_Level, slider_level,
	GTSL_LevelFormat, "%2ld",
	GTSL_MaxLevelLen, 2,
	TAG_DONE);

    ng.ng_TopEdge = 40+topborder;
    ng.ng_Height = 14;
    ng.ng_GadgetText = "Type Here:";
    ng.ng_GadgetID = GAD_STRING;
    gad = CreateGadget(STRING_KIND, gad, &ng,
	GTST_String, "Hello World!",
	GTIN_MaxChars, 50,
	TAG_DONE);

    ng.ng_LeftEdge += 50;
    ng.ng_TopEdge = 60+topborder;
    ng.ng_Width = 100;
    ng.ng_Height = 12;
    ng.ng_GadgetText = "Click Here";
    ng.ng_GadgetID = GAD_BUTTON;
    ng.ng_Flags = 0;
    gad = CreateGadget(BUTTON_KIND, gad, &ng,
	TAG_DONE);

    return(gad);
}

/*------------------------------------------------------------------------*/
