/*	Demo.c		InovaTools 1 Demo Program         Lattice "C" version

	(c) 1988 Todor Fay

	This is a sample Inovatools 1 program.  It puts up
	a window with gadgets for opening two different
	types of file requester, one displays all files, the other
	displays all files that end with ".c".
	There's a gadget that opens the InovaTools color 
	pallette editor.  And, there are two gadgets to create
	and delete a reentrant window.
 	To keep track of all of the reentrant windows, 
	a list is maintained in the main window.  This list can be
	sized by changing the window size.
	Each reentrant window has an example popup menu, two
	Knob gadgets, and a drag gadget that can be dragged
	to another window, where it stays!
	There is no limit to the number of reentrant windows
 	created, and each is independant of the others.
*/

#include <intuition/intuition.h>
#include <exec/memory.h>
#include <graphics/gfxmacros.h>
#include "itools1.h"

long GfxBase; 
long IntuitionBase;
long MathBase; 
long LayersBase;

/*	We need a list structure to keep track of all of the
	reentrant windows opened.  The ID number is for 
	display purposes only.
*/

struct WindowListItem {
    struct ListItem link;
    struct Window *window;
    short id;
};

void updatelistitem(rp,item,x,y,highlighted)

/*	This is the update routine for a list item in the window
	list.  When you create an InovaTools list, you must provide
	a routine that will display one item in the list,
	given that item, a rastport, x and y positions, and
	a flag that indicates whether it is highlighted.
*/

register struct RastPort *rp;
register struct WindowListItem *item;
register long x,y,highlighted;

{
    static struct IntuiText it = { 0,0,JAM2,0,0,0,0,0};
    static char name[] = "Window #         ";
    if (highlighted) {
	it.FrontPen = 0;
	it.BackPen = 1;
    }
    else {
	it.FrontPen = 1;
	it.BackPen = 0;
    }
    it.IText = name;
    Itoa((long)item->id,&name[8],10l);
    PrintIText(rp,&it,x,y);
}

/*	The ListInfo structure for the window list: */

struct ListInfo windowlist = {
    160,17,100,69,8,   /* Dimensions. */
    10,11,12,13,       /* Gadget ID's. */
    1,0,               /* Draw pens. */
    0,0,0,             /* List pointers. */
    0,                 /* Window. */
    0,0,0,0,           /* The four gadgets. */
    updatelistitem,    /* Draw routine. */
    0,0,0,0,           /* Inovatools stuff. */
};

void knobcode(window,knob)

/*	For a knob, you may provide a routine that is called
	every time the knob is rotated.  This routine is
	passed a pointer to the knob and the window it displays in.
*/

struct Window *window;
register struct Knob *knob;

{
    static struct IntuiText it = { 1,0,JAM2,0,0,0,0,0};
    static char number[] = "    ";
    it.IText = number;
    if (knob->KnobID == 1) {
	Itoa((long)knob->Value,number,10l);
	PrintIText(window->RPort,&it,170,50);
    }
    else {
	it.IText = "      ";
	PrintIText(window->RPort,&it,270l,50l);
	it.IText = number;
	Itoa((long)knob->Value,number,10l);
	PrintIText(window->RPort,&it,270l,50l);
    }
}

/* 	The knob list for the reentrant window.  Copies of
	this list will be made for each window, so
	the knobs can be pointing at different angles.
*/
    
struct Knob firstknob = {
    0,                 /* No next knob. */
    300,30,            /* Center. */
    KNOB_DRAW | KNOB_RANGED | KNOB_CALCVALUE,
    0,100,0,32768,100,20,22,10000,55535,0,2,1,2,0,0,0,0,0,
    knobcode,0
};

struct Knob knoblist = {
    &firstknob,                 /* Next knob. */
    200,30,            /* Center. */
    KNOB_DRAW | KNOB_RANGED | KNOB_CALCVALUE,
    0,10,0,32768,10,20,22,10000,55535,0,3,1,1,0,0,0,0,0,
    knobcode,0
};

/*	The Drag Gadget declaration: */

struct DragInfo dragme = {
    0,			  /* Gadget Pointer - to be filled in later. */
    -700,-300,1000,1000,  /* Bounding box. */
    DRAG_OUTLINE | DRAG_MOVEGADGET,	  /* Flags. */
    0,0,
    0,			  /* No user supplied update routine. */
    0
};

/*	The PowerWindows declaration for the reentrant window: */

static USHORT dupeImageData1[] = {
 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x8000,0x0000,0x0000,0x0001,
 0x8000,0x0000,0x0008,0x2001,0x8000,0x0000,0x000C,0x6001,
 0x8000,0x0000,0x000E,0xE3C1,0x8000,0x0000,0x000F,0xE661,
 0x8000,0x0000,0x000D,0x67E1,0x8000,0x0000,0x000C,0x6601,
 0x8000,0x0000,0x000C,0x63C1,0x8000,0x0000,0x0000,0x0001,
 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x0000,0x0000,0x0000,0x0000,
 0x0000,0x0000,0x0000,0x0000,0x0F80,0x0000,0x0008,0x2000,
 0x06C0,0x0000,0x000C,0x6000,0x066E,0xC3C3,0xB00E,0xE3C0,
 0x0667,0x6066,0x600F,0xE660,0x0666,0x61E6,0x600D,0x67E0,
 0x06C6,0x0663,0xC00C,0x6600,0x0F8F,0x03BC,0x600C,0x63C0,
 0x0000,0x0007,0xC000,0x0000,0x0000,0x0000,0x0000,0x0000
};

static struct Image dupeImage1 = {
 0,0,
 64,11,
 2,
 dupeImageData1,
 0x0003,0x0000,
 NULL
};

static struct Gadget dupeGadget1 = {
 NULL,
 24,36,
 64,11,
 GADGHBOX+GADGHIMAGE+GADGIMAGE,
 RELVERIFY+GADGIMMEDIATE,
 BOOLGADGET,
 (APTR)&dupeImage1,
 NULL,
 NULL,
 NULL,
 NULL,
 2,
 NULL
};

static SHORT dupeBorderVectors1[] = {
 0,0,
 99,0,
 99,10,
 0,10,
 0,0
};
static struct Border dupeBorder1 = {
 -2,-1,
 3,0,JAM1,
 5,
 dupeBorderVectors1,
 NULL
};

static struct IntuiText dupeIText1 = {
 3,0,JAM2,
 3,1,
 NULL,
 "Pop Up Menu",
 NULL
};

static struct Gadget dupeGadget2 = {
 &dupeGadget1,
 24,18,
 96,9,
 GADGHBOX+GADGHIMAGE,
 RELVERIFY+GADGIMMEDIATE,
 BOOLGADGET,
 (APTR)&dupeBorder1,
 NULL,
 &dupeIText1,
 NULL,
 NULL,
 1,
 NULL
};

static struct IntuiText dupeIText2 = {
 3,1,COMPLEMENT,
 0,0,
 NULL,
 "Another Menu Item",
 NULL
};

static struct MenuItem dupeMenuItem2 = {
 NULL,
 0,9,
 136,8,
 ITEMTEXT+ITEMENABLED+HIGHCOMP,
 0,
 (APTR)&dupeIText2,
 NULL,
 NULL,
 NULL,
 MENUNULL
};

static USHORT dupeImageData2[] = {
 0x0000,0x0000,0x3FFF,0xF800,0x3FFF,0xF800,0x3FFF,0xF800,
 0x3FFF,0xF800,0x3FFF,0xF800,0x3FFF,0xF800,0x3FFF,0xF800,
 0x3FFF,0xF800,0x3FFF,0xF800,0x0000,0x0000,0xFFFF,0xFE00,
 0xC000,0x0600,0xC000,0x0600,0xC000,0x0600,0xC000,0x0600,
 0xC000,0x0600,0xC000,0x0600,0xC000,0x0600,0xC000,0x0600,
 0xC000,0x0600,0xFFFF,0xFE00
};

static struct Image dupeImage2 = {
 19,0,
 23,11,
 2,
 dupeImageData2,
 0x0003,0x0000,
 NULL
};

static struct MenuItem dupeSubItem3 = {
 NULL,
 121,3,
 42,11,
 CHECKIT+ITEMENABLED+HIGHCOMP+CHECKED,
 3,
 (APTR)&dupeImage2,
 NULL,
 NULL,
 NULL,
 MENUNULL
};

static USHORT dupeImageData3[] = {
 0x0000,0x0000,0x01FF,0x0000,0x0FFF,0xE000,0x3F01,0xF800,
 0x7C00,0x7C00,0x7C00,0x7C00,0x7C00,0x7C00,0x3F01,0xF800,
 0x0FFF,0xE000,0x01FF,0x0000,0x0000,0x0000,0x01FF,0x0000,
 0x0FFF,0xE000,0x3F01,0xF800,0x7CFE,0x7C00,0xFBFF,0xBE00,
 0xFBFF,0xBE00,0xFBFF,0xBE00,0x7CFE,0x7C00,0x3F01,0xF800,
 0x0FFF,0xE000,0x01FF,0x0000
};

static struct Image dupeImage3 = {
 19,0,
 23,11,
 2,
 dupeImageData3,
 0x0003,0x0000,
 NULL
};

static struct MenuItem dupeSubItem2 = {
 &dupeSubItem3,
 163,-8,
 42,11,
 CHECKIT+ITEMENABLED+HIGHCOMP,
 5,
 (APTR)&dupeImage3,
 NULL,
 NULL,
 NULL,
 MENUNULL
};

static USHORT dupeImageData4[] = {
 0x03FE,0x0000,0x1FFF,0xC000,0x3FFF,0xE000,0x7BF8,0xF000,
 0xF8FE,0xF800,0xFFFF,0xF800,0xFFFF,0xF800,0x7FFF,0xF000,
 0x3E03,0xE000,0x1FFF,0xC000,0x03FE,0x0000,0x0000,0x0000,
 0x03FE,0x0000,0x1FFF,0xC000,0x3CFF,0xE000,0x7FF9,0xF000,
 0x7FFF,0xF000,0x7FAF,0xF000,0x3FFF,0xE000,0x1FFF,0xC000,
 0x03FE,0x0000,0x0000,0x0000
};

static struct Image dupeImage4 = {
 19,0,
 21,11,
 2,
 dupeImageData4,
 0x0003,0x0000,
 NULL
};

static struct MenuItem dupeSubItem1 = {
 &dupeSubItem2,
 121,-8,
 42,11,
 CHECKIT+ITEMENABLED+HIGHCOMP,
 6,
 (APTR)&dupeImage4,
 NULL,
 NULL,
 NULL,
 MENUNULL
};

static struct IntuiText dupeIText3 = {
 3,1,COMPLEMENT,
 0,0,
 NULL,
 "A Menu Item",
 NULL
};

static struct MenuItem dupeMenuItem1 = {
 &dupeMenuItem2,
 0,0,
 136,8,
 ITEMTEXT+ITEMENABLED+HIGHCOMP,
 0,
 (APTR)&dupeIText3,
 NULL,
 NULL,
 &dupeSubItem1,
 MENUNULL
};

static struct Menu dupeMenu1 = {
 NULL,
 0,0,
 57,0,
 MENUENABLED,
 "PopUp",
 &dupeMenuItem1
};

#define dupeMenuList1 dupeMenu1

static struct NewWindow dupeNewWindowStructure1 = {
 81,28,
 343,62,
 0,1,
 MOUSEBUTTONS+GADGETDOWN+GADGETUP+CLOSEWINDOW+NEWSIZE,
 WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE,
 &dupeGadget2,
 NULL,
 "Duped Window",
 NULL,
 NULL,
 5,5,
 640,200,
 WBENCHSCREEN
};

extern long AllocMem();
extern long FindTask();

void dupewindowcode()

/*	This is the code for a task that opens its own reentrant window.
	All of the structures for the window are created with calls to
	DupeNewWindow, DupeKnobList, and DupeMenu.
*/

{
    register struct Window *window;
    register struct IntuiMessage *message;
    register long class, code;
    register struct Gadget *gadget;
    static short globalid = 1;
    short startx, starty;
    struct Window *otherwindow;
    struct NewWindow *newwindow;
    struct Knob *knob;
    struct Menu *menu;
    struct WindowListItem *windowlistitem, *otheritem;
    Forbid();
    newwindow = DupeNewWindow(&dupeNewWindowStructure1);
    if (!newwindow) {
	Permit();
	DeleteTask(FindTask((long)0));
    }
    knob = DupeKnobList(&knoblist);
    if (!knob) {
	Permit();
	DeleteNewWindow(newwindow);
	DeleteTask(FindTask((long)0));
    }
    menu = DupeMenu(&dupeMenuList1);
    if (!menu) {
	Permit();
	DeleteNewWindow(newwindow);
	DeleteKnobList(knob);
	DeleteTask(FindTask((long)0));
    }
    window = FlashyOpenWindow(newwindow);
    if (window) {

/*	Create a list item that points at this window and stick it in
	the list in the main window. */

	windowlistitem = (struct WindowListItem *) 
	    AllocMem((long)sizeof(struct WindowListItem),MEMF_PUBLIC | MEMF_CLEAR);
	if (windowlistitem) {
	    windowlistitem->window = window;
	    windowlistitem->id = globalid++;
	    InsertListItem(&windowlist,(struct ListItem *)windowlistitem);
	}

/*	Install the knobs and call their display routines. */

	DrawKnobs(window,knob);
	knobcode(window,knob);
	knobcode(window,knob->NextKnob);
	Permit();

/*	Main loop.  process messages and break with a CLOSEWINDOW. */

	for (;;) {

/*	Read an IntuiMessage and grab pertinent data before replying. */

	    message = GetIntuiMessage(window);
	    class = message->Class;
	    code = message->Code;
	    gadget = (struct Gadget *) message->IAddress;
	    ReplyMsg(message);
	    if (class == CLOSEWINDOW) break;

/*	If window was resized, redraw knobs. */

	    else if (class == NEWSIZE) 	DrawKnobs(window,knob);

/*	If mouse was clicked, it may have been a knob, process it. */

	    else if ((class == MOUSEBUTTONS) && (code == SELECTDOWN)) {
		KnobGadgets(window,knob);
	    }
	    else if (class == GADGETDOWN) {
		switch(gadget->GadgetID) {
		    case 1 :	/* PopUp menu selected. */
			PopUpMenu(window,menu);
			break;
		    case 2 : 	/* Drag gadget selected. */
			startx = gadget->LeftEdge;
			starty = gadget->TopEdge;
			dragme.Gadget = gadget;
			DragGadget(window,&dragme);
			otherwindow = 
			    WhichWindow(window,(long)dragme.XPos,
				(long)dragme.YPos);

/*	If the gadget ended in another window, find it in the list. If
	it is in the list and it isn't this window, stick the gadget
	in that window.
*/
			if (otherwindow != window) {
			    Forbid();
			    otheritem = 
				(struct WindowListItem *) windowlist.TopItem;
			    for (;otheritem;) {
				if (otheritem->window == otherwindow) break;
				otheritem = (struct WindowListItem *)
				    otheritem->link.Next;
			    }
			    if (otheritem) {
				RemoveGadget(window,gadget);
				gadget->LeftEdge = window->LeftEdge + 
				    gadget->LeftEdge - otherwindow->LeftEdge;
				gadget->TopEdge = window->TopEdge + 
				    gadget->TopEdge - otherwindow->TopEdge;
				gadget->NextGadget = 0;
				AddGadget(otherwindow,gadget,(long)-1);
				RefreshGadgets(otherwindow->FirstGadget,
				    otherwindow,0);
			    }
			    else {
				gadget->LeftEdge = startx;
				gadget->TopEdge = starty;
				RefreshGadgets(window->FirstGadget,window,0);
			    }
			    Permit();
			}
			break;
	 	}
	    }
	}

/*	Done.  Pull out of the list in the main window.  */

	if (windowlistitem) {
	    windowlist.ActiveItem = (struct ListItem *) windowlistitem;
	    RemoveListItem(&windowlist);
	    FreeMem(windowlistitem,(long)sizeof(*windowlistitem));
	}
	FlashyCloseWindow(window);
    }
    else Permit();
    DeleteNewWindow(newwindow);
    DeleteKnobList(knob);
    DeleteMenu(menu);
    DeleteTask(FindTask(0l));
}

/*	PowerWindow declarations for main window. */

static SHORT demoBorderVectors2[] = {
 0,0,
 123,0,
 123,11,
 0,11,
 0,0
};
static struct Border demoBorder2 = {
 -2,-1,
 3,0,JAM1,
 5,
 demoBorderVectors2,
 NULL
};

static struct IntuiText demoIText4 = {
 3,0,JAM2,
 16,1,
 NULL,
 "Kill Window",
 NULL
};

static struct Gadget demoGadget7 = {
 NULL,
 23,77,
 120,10,
 NULL,
 RELVERIFY,
 BOOLGADGET,
 (APTR)&demoBorder2,
 NULL,
 &demoIText4,
 NULL,
 NULL,
 5,
 NULL
};

static SHORT demoBorderVectors3[] = {
 0,0,
 123,0,
 123,11,
 0,11,
 0,0
};
static struct Border demoBorder3 = {
 -2,-1,
 3,0,JAM1,
 5,
 demoBorderVectors3,
 NULL
};

static struct IntuiText demoIText5 = {
 3,0,JAM2,
 20,1,
 NULL,
 "New Window",
 NULL
};

static struct Gadget demoGadget6 = {
 &demoGadget7,
 23,62,
 120,10,
 NULL,
 RELVERIFY,
 BOOLGADGET,
 (APTR)&demoBorder3,
 NULL,
 &demoIText5,
 NULL,
 NULL,
 4,
 NULL
};

static SHORT demoBorderVectors4[] = {
 0,0,
 123,0,
 123,11,
 0,11,
 0,0
};
static struct Border demoBorder4 = {
 -2,-1,
 3,0,JAM1,
 5,
 demoBorderVectors4,
 NULL
};

static struct IntuiText demoIText6 = {
 3,0,JAM2,
 24,1,
 NULL,
 "'C' Files",
 NULL
};

static struct Gadget demoGadget5 = {
 &demoGadget6,
 23,32,
 120,10,
 NULL,
 RELVERIFY,
 BOOLGADGET,
 (APTR)&demoBorder4,
 NULL,
 &demoIText6,
 NULL,
 NULL,
 2,
 NULL
};

static SHORT demoBorderVectors5[] = {
 0,0,
 123,0,
 123,11,
 0,11,
 0,0
};
static struct Border demoBorder5 = {
 -2,-1,
 3,0,JAM1,
 5,
 demoBorderVectors5,
 NULL
};

static struct IntuiText demoIText7 = {
 3,0,JAM2,
 5,1,
 NULL,
 "Color Pallette",
 NULL
};

static struct Gadget demoGadget4 = {
 &demoGadget5,
 23,47,
 120,10,
 NULL,
 RELVERIFY,
 BOOLGADGET,
 (APTR)&demoBorder5,
 NULL,
 &demoIText7,
 NULL,
 NULL,
 3,
 NULL
};

static SHORT demoBorderVectors6[] = {
 0,0,
 123,0,
 123,11,
 0,11,
 0,0
};
static struct Border demoBorder6 = {
 -2,-1,
 3,0,JAM1,
 5,
 demoBorderVectors6,
 NULL
};

static struct IntuiText demoIText8 = {
 3,0,JAM2,
 24,1,
 NULL,
 "All Files",
 NULL
};

static struct Gadget demoGadget3 = {
 &demoGadget4,
 23,17,
 120,10,
 NULL,
 RELVERIFY,
 BOOLGADGET,
 (APTR)&demoBorder6,
 NULL,
 &demoIText8,
 NULL,
 NULL,
 1,
 NULL
};

#define demoGadgetList2 demoGadget3

static struct NewWindow demoNewWindowStructure2 = {
 222,96,
 314,95,
 0,1,
 GADGETDOWN+GADGETUP+CLOSEWINDOW+NEWSIZE,
 WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE,
 &demoGadget3,
 NULL,
 "InovaTools Demo",
 NULL,
 NULL,
 314,95,
 314,200,
 WBENCHSCREEN
};


/*	Only ROM resident libraries are needed: */

extern long OpenLibrary();

void main()

/*	The main program.  Open the window and install the list.
	There is no need to duplicate structures, since this is
	not a reentrant window. 
*/

{
    register struct Window *window;
    register struct IntuiMessage *message;
    register long class, code;
    register struct Gadget *gadget;
    struct WindowListItem *windowlistitem;
    char blankstring[100];
    LayersBase = OpenLibrary("layers.library",0l);
    GfxBase = OpenLibrary("graphics.library",0l);
    IntuitionBase = OpenLibrary("intuition.library",0l);
    MathBase = OpenLibrary("mathffp.library",0l);
    window = (struct Window *) FlashyOpenWindow(&demoNewWindowStructure2);
    if (window) {
	windowlist.Window = window;
	InitListInfo(&windowlist);
	for (;;) {
	    message = GetIntuiMessage(window);
	    class = message->Class;
	    code = message->Code;
	    gadget = (struct Gadget *) message->IAddress;
	    ReplyMsg(message);
	    if (class == CLOSEWINDOW) break;

/*	If the window size changes, redraw the list so it fits. */

	    else if (class == NEWSIZE) {
		windowlist.Height = window->Height - 26;
		SizeList(&windowlist);
	    }
	    else if (class == GADGETDOWN) {
		switch(gadget->GadgetID) {
		    case 12 :	/* Up arrow clicked in list. */
		    case 13 :	/* Down arrow clicked in list. */
			ClickList(&windowlist,(long)gadget->GadgetID);
			break;
		}
	    }
	    else if (class == GADGETUP) {
		switch(gadget->GadgetID) {
		    case 1 :	/* All files requester. */
			FileName(blankstring,"All Files:",0l,0l,(long)
			    FILES_DELETE | FILES_OPEN | FILES_TEST,0l,0l);
			break;
		    case 2 :	/* C files requester. */
			FileName(blankstring,"C Files:","c",0l,(long)
			    FILES_DELETE | FILES_OPEN | FILES_TEST,0l,0l);
			break;
		    case 3 :	/* Pallette Editor. */
			EditColors(0l,10l,10l,80l);
			break;
		    case 4 :	/* Create a window. */
			CreateTask("Duplicate Window Handler",(long)0,
			    dupewindowcode,(long)4000);
			Delay((long)30);
			break;
		    case 5 :	/* Delete currently activated window. */
			if (windowlist.ActiveItem) {
			    windowlistitem = (struct WindowListItem *) 
				windowlist.ActiveItem;
			    SendCloseWindow(windowlistitem->window);
			    Delay((long)30);
			}
			break;
		    case 10 :	/* List scroll bar. */
			ScrollList(&windowlist);
			break;
		    case 11 :	/* List box was clicked. */
			GetListItem(&windowlist);
			break;
		}
	    }
	}

/*	Tell all windows to close down.  SendCloseWindow sends
	and Intuition CLOSEWINDOW event to the window, tricking it
	into thinking the use shut it down.
*/

	for (;windowlist.TopItem;) {
	    windowlistitem = (struct WindowListItem *) windowlist.TopItem;
	    SendCloseWindow(windowlistitem->window);
	    Delay((long)20);
	}
	RemoveListInfo(&windowlist);
	FlashyCloseWindow(window);
    }

/*	Get rid of all duplicated structures that weren't freed.
	And, get rid of the memory backup of file names. 
*/

    DeleteAll();
    ReleaseFiles();
    CloseLibrary(MathBase);
    CloseLibrary(IntuitionBase);
    CloseLibrary(GfxBase);
}
