/*
** 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");

    /* Here is how we can figure out ahead of time how tall the
     * window's title bar will be:
     */
    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",

	/* Gadgets go here, or in NewWindow.FirstGadget */
	WA_Gadgets, glist,

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

    /* After window is open, we must call this GadTools refresh
     * function.
     */
    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!",
	GTST_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);
}

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