/****************************************************************
/*								*
/*	HackBench - Part 4 of 4 - hbgad.c - Gadgets and Menus	*
/*								*
/*	Copyright (C) 1987 by Bill Kinnersley			*
/*	CS Dept, Washington State Univ, Pullman, WA 99164	*
/*								*
/*	Permission granted to redistribute this program		*
/*	provided the copyright notice remains intact.		*
/*	May not be used as part of any commercial product.	*
/*								*
/****************************************************************/

#include "hb.h"

extern int drawobj(), clearobj(), openobj(), closeobj(), compobj();
extern char *rindex();
extern short debug;
extern struct Window *wbWin, *curWin, *errWin;
extern struct MyWBObject *lastObj;
extern struct List wbObjs, selObjs, utilObjs;

struct MsgPort *DOSPort, *IDCMPPort, *WBPort;
long IDCMPBit, WBBit;
extern void *IconBase;
struct DosLibrary *DosBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct LayersBase *LayersBase;
struct DosInfo *rnInfo;

long sendpkt();
struct Remember *RememberKey=NULL;
char *title = "HackBench release 1.0:                                     ";
char lastErr[60];
BPTR initialDir;

BYTE sbuf[61], undoBuf[61];
struct StringInfo ren_si = {
	sbuf, undoBuf, 0, 60, 0, 0, 1, 60, 0, 0, NULL, 0, NULL
};
struct Gadget ren_gad = {
	NULL, 1, 1, 500, 10, GADGHCOMP, STRINGCENTER | RELVERIFY,
	STRGADGET, NULL, NULL, NULL, 0, (APTR)&ren_si, GID_NAME, NULL
};

struct NewWindow ren_nw = {
	60, 100, 504, 11, 3, 1, NULL, ACTIVATE, &ren_gad,
	NULL, NULL, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
};

/* Used to generate menu items */
struct IntuiText gen_txt = {0, 1, JAM2, 5, 0, NULL, NULL, NULL};

USHORT dm_id[] = {0xfe7f, 0xfe7f, 0xfe7f, 0xce73, 0xf24f, 0xfc3f};
struct Image dm_img = {0, 0, 14, 6, 1, &dm_id[0], 1, 0, NULL};
struct Gadget dm_gad = {
	NULL, -15, -14, 15, 6, GADGIMAGE | GRELRIGHT | GRELBOTTOM,
	GADGIMMEDIATE | RIGHTBORDER, BOOLGADGET,
	(APTR)&dm_img, NULL, NULL, 0, NULL, GID_DOWNSCROLL, NULL
};

USHORT up_id[] = {0xfc3f, 0xf24f, 0xce73, 0xfe7f, 0xfe7f, 0xfe7f};
struct Image up_img = {0, 0, 14, 6, 1, &up_id[0], 1, 0, NULL};
struct Gadget up_gad = {
	&dm_gad, -15, 10, 15, 6, GADGIMAGE | GRELRIGHT,
	GADGIMMEDIATE | RIGHTBORDER, BOOLGADGET,
	(APTR)&up_img, NULL, NULL, 0, NULL, GID_UPSCROLL, NULL
};

USHORT rm_id[] = {
	0xffff, 0xf9f0, 0xfe70, 0xff90,0x0000, 0xff90, 0xfe70, 0xf9f0};
struct Image rm_img = {0, 0, 12, 8, 1, &rm_id[0], 1, 0, NULL};
struct Gadget rm_gad = {
	&up_gad, -26, -8, 12, 8, GADGIMAGE | GRELRIGHT | GRELBOTTOM,
	GADGIMMEDIATE | BOTTOMBORDER, BOOLGADGET,
	(APTR)&rm_img, NULL, NULL, 0, NULL, GID_RIGHTSCROLL, NULL
};

USHORT lm_id[] = {
	0xffff, 0xf3f0, 0xcff0, 0x3ff0, 0x00000, 0x3ff0, 0xcff0, 0xf3f0};
struct Image lm_img = {0, 0, 12, 8, 1, &lm_id[0], 1, 0, NULL};
struct Gadget lm_gad = {
	&rm_gad, 2, -8, 12, 8, GADGIMAGE | GRELBOTTOM,
	GADGIMMEDIATE | BOTTOMBORDER,
	BOOLGADGET,
	(APTR)&lm_img, NULL, NULL, 0, NULL, GID_LEFTSCROLL, NULL
};

struct Image knob_img1, knob_img2;

struct PropInfo hs_knob = { FREEHORIZ | AUTOKNOB, 0, 0, MAXBODY, MAXBODY};
struct Gadget hs_gad = {
	&lm_gad, 13, -8, -40, 9, GADGIMAGE | GRELWIDTH | GRELBOTTOM,
	GADGIMMEDIATE | RELVERIFY | BOTTOMBORDER, PROPGADGET,
	(APTR)&knob_img1, NULL, NULL, 0, (APTR)&hs_knob,
	GID_HORIZSCROLL, NULL
};

struct PropInfo vs_knob = {FREEVERT | AUTOKNOB, 0, 0, MAXBODY, MAXBODY};
struct Gadget vs_gad = {
	&hs_gad, -15, 16, 16,-31, GADGIMAGE | GRELHEIGHT | GRELRIGHT,
	GADGIMMEDIATE | RELVERIFY | RIGHTBORDER, PROPGADGET,
	(APTR)&knob_img2, NULL, NULL, 0, (APTR)&vs_knob,
	GID_VERTSCROLL, NULL
};

struct NewWindow nw = {
	0, 0, 640, 200, 0, 1,
	CLOSEWINDOW | GADGETUP | GADGETDOWN | MENUPICK | NEWSIZE |
	    DISKINSERTED | DISKREMOVED | MOUSEBUTTONS | REFRESHWINDOW,
	SMART_REFRESH | REPORTMOUSE | BORDERLESS | ACTIVATE | BACKDROP |
	    WBENCHWINDOW,
	NULL, NULL, "", NULL, NULL, 
	0, 0, 320, 186, WBENCHSCREEN
};

/* Default disk icon */
USHORT disk_icon[] = {
	0x0000, 0x0000, 0x3ffc, 0x3f00, 0x3ffc, 0x3fc0, 0x3ffc, 0x3ff0,
	0x3ffc, 0x3ffc, 0x3fff, 0xfffc, 0x3fff, 0xfffc, 0x3fff, 0xfffc,
	0x3fff, 0xfffc, 0x3fff, 0xfffc, 0x3fff, 0xfffc, 0x3fff, 0xfffc,
	0x3fff, 0xfffc, 0x3fff, 0xfffc, 0x3fff, 0xfffc, 0x0000, 0x0000,

	0xffff, 0xffc0, 0xc0ff, 0xfcf0, 0xc0ff, 0xfc3c, 0xc0ff, 0xfc0f,
	0xc0ff, 0xfc03, 0xc0ff, 0xfc03, 0xc000, 0x0003, 0xc000, 0x0003,
	0xc000, 0x0003, 0xc000, 0x0003, 0xc000, 0x0003, 0xc000, 0x0003,
	0xc000, 0x0003, 0xc000, 0x0003, 0xc000, 0x0003, 0xffff, 0xffff 
};
struct Image disk_img = {0, 0, 32, 16, 2, &disk_icon[0], 3, 0, NULL};

USHORT zz_ptr[] = {
	0x0000, 0x0000, 0x0008, 0x0000, 0x001c, 0x0000, 0x0026, 0x0000,
	0x0013, 0x0060, 0x0009, 0x00f0, 0x0006, 0x01f8,	0x0000, 0x03fc,
	0x0000, 0x07f8, 0x0000, 0x0fe0, 0x0070, 0x1ff0,	0x01f8, 0x3ff8,
	0x030c, 0x7ffc, 0x03dc, 0xf3fc, 0x0bbc, 0x4bfc,	0x030c, 0x03fc,
	0x51f8, 0x51f8, 0x00f0, 0x00f0, 0x2000, 0x2000,	0x2000, 0x2000,
	0x0000, 0x0000, 0x0000, 0x0000
};

/*USHORT zz_ptr[] = {
	0x0000, 0x0000, 0x0600, 0x0600, 0x0f40, 0x0f40, 0x3fe0, 0x3fe0,
	0x7fe0, 0x7fe0, 0x61f0, 0x7ff0, 0x7bf8, 0x7ff8, 0xf7f8, 0xfff8,
	0x61fc, 0x7ffc, 0x7f0c, 0x7ffc, 0x3fde, 0x3ffe, 0x7fbc, 0x7ffc,
	0x3f0c, 0x3ffc, 0x1ff8, 0x1ff8, 0x07f0, 0x07f0, 0x01c0, 0x01c0,
	0x0700, 0x0700, 0x0fc0, 0x0fc0, 0x0680, 0x0680, 0x0000, 0x0000,
	0x00c0, 0x00c0, 0x00e0, 0x00e0, 0x0040, 0x0040, 0x0000, 0x0000,
	0x0000, 0x0000
};
*/
USHORT x_ptr[] = {
	0x0000, 0x0000, 0x0600, 0x0000, 0x1f80, 0x0000, 0x3fc0, 0x0000,
	0x6660, 0x0000, 0x6060, 0x0000, 0xf0f0, 0x0000, 0xf0f0, 0x0000,
	0x6060, 0x0000, 0x6660, 0x0000, 0x3fc0, 0x0000, 0x1f80, 0x0000,
	0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};

/* Defaults if no Disk.info file is found */
struct DrawerData defDrDat = {
	{1, 13, 379, 123, -1, -1, NULL,
	WBENCHWINDOW | SIZEBRIGHT | SIZEBBOTTOM | SMART_REFRESH |
	WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE,
	NULL, NULL, "", NULL, NULL, 90, 40, -1, -1, WBENCHSCREEN},
	0, 0
};

struct DiskObject defDskObj = {
	0, 1, {
		NULL, 575, 15, 32, 16, GADGIMAGE | GADGHBOX,
		RELVERIFY | GADGIMMEDIATE, BOOLGADGET,
		(APTR)&disk_img, NULL, NULL, 0, NULL, 17, NULL},
	WBDISK, NULL, NULL, 575, 6, &defDrDat, NULL, 0
};

short menuSet = FALSE;
long menuLoc = 30L;
struct Menu *lastMenu = NULL, *menuStrip = NULL;
char *benchNames[] = {"ParkBench", "Open", "Close", "Duplicate",
			"Rename", "Info", "Discard"};
char *diskNames[] = {"Disk", "Empty Trash", "Initialize"};
char *specNames[] = {"Special", "Cleanup", "Last Error", "Redraw",
			"Snapshot", "Version"};
char *debugNames[] = {"Debug", "Trace", "Wbobjs", "SelObjs",
			"UtilObjs", "Children", "Quit"};

makeMenu() {
	addMenu(benchNames, 6, BLACK_FILL);
	addMenu(diskNames, 2, BLACK_FILL);
	addMenu(specNames, 5, BLACK_FILL);
	addMenu(debugNames, 6, BLACK_FILL | ITEMENABLED);
	menuSet = TRUE;
	SetMenuStrip(wbWin, menuStrip);
}

addMenu (itemNames, numItems, flag)
char *itemNames[]; short numItems; long flag; {
	short i;
	long l, height=0L, width=0L;
	struct Menu *menu;
	struct MenuItem *firstItem, *lastItem, *menuItem;
	struct IntuiText *menuText;

	menu = (struct Menu *) AllocRemember(&RememberKey,
		(long)sizeof(struct Menu), MEMF_CPC);
	menu->Flags = MENUENABLED;
	menu->MenuName = itemNames[0];
	menu->Width = 10*strlen(itemNames[0]);
	menu->LeftEdge = menuLoc;
	menuLoc += (long)menu->Width + 30L;
	if (lastMenu) lastMenu->NextMenu = menu;
	else menuStrip = menu;
	lastMenu = menu;
	for (i=1; i<=numItems; i++)
		width = MAX(width, strlen(itemNames[i]));
	/*{l = strlen(itemNames[i+1]);if  (l>width) width = l;}*/
	width = 8L*width + 8L;
	lastItem = NULL;
	for (i=0; i<numItems; i++) {
		menuItem = (struct MenuItem *)AllocRemember(&RememberKey,
			(long)sizeof(struct MenuItem), MEMF_CPC);
		if (lastItem) lastItem->NextItem = menuItem;
		else menu->FirstItem = menuItem;
		lastItem = menuItem;
		menuItem->TopEdge = 10L * i;
		menuItem->Height = 8L;
		menuItem->Flags = flag;
		menuItem->Width = width;
		menuItem->MutualExclude = (~(1L<<i));
		menuText = (struct IntuiText *)AllocRemember(&RememberKey,
			(long)sizeof(struct IntuiText), MEMF_CPC);
/*stc*/		*menuText = gen_txt;
		menuText->IText = itemNames[i+1];
		menuItem->ItemFill = (APTR)menuText;
		height += 10L;
	}
	menu->Height = height;
}

openAll() {
	struct Process *me;
	struct Screen *sc;
	struct RootNode *dlRoot;

	if (!(DosBase = (struct DosLibrary *) OpenLibrary(DOSNAME,33L)))
		closeAll("Requires V1.2 DOS Library");
	if (!(GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library", 33L)))
		closeAll("Requires V1.2 Graphics Library");
	if (!(LayersBase = (struct LayersBase *)
		OpenLibrary("layers.library", 33L)))
		closeAll("Requires V1.2 Layers Library");
	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library", 33L)))
		closeAll("Requires V1.2 Intuition Library");
	if (!(IconBase = OpenLibrary("icon.library", 31L)))
		closeAll("I give up, where's the icon library?\n");

	/* Make sure the backdrop fills the screen */
	for (sc=IntuitionBase->FirstScreen; sc; sc=sc->NextScreen)
	    if (sc->Flags & WBENCHSCREEN) {
		nw.Height = sc->Height; nw.Width = sc->Width;
		break;
	    }
	if (!(wbWin = OpenWindow(&nw)))
		closeAll("Couldn't open the backdrop window\n");
	if (!(WBPort = CreatePort(NULL, NULL)))
		closeAll("Couldn't create the WB port\n");

	WBBit = 1L << WBPort->mp_SigBit;
	IDCMPPort = wbWin->UserPort;
	IDCMPBit = 1L << wbWin->UserPort->mp_SigBit;
	me = (struct Process *)FindTask(NULL);
	initialDir = me->pr_CurrentDir;
	DOSPort = &me->pr_MsgPort;
	dlRoot = (struct RootNode *) DosBase->dl_Root;
	rnInfo = (struct DosInfo *) BADDR(dlRoot->rn_Info);

	NewList(&wbObjs);
	NewList(&selObjs);
}

doMenu(menuNum) USHORT menuNum; {
	if (menuNum==MENUNULL) return;
	switch ((long)menuNum) {
	case OPEN: doOpen();
		OffMenu(wbWin, OPEN); OnMenu(wbWin, CLOZE);
		break;
	case CLOZE: doList(&selObjs, SEL, closeobj);
		clearSel();
		break;
	case DUP: error("Not implemented"); break;
	case RENAME: ren(lastObj); break;
	case INFO:
	case DISCARD:

	case EMPTY:
	case INIT:

	case CLEANUP: error("Not implemented"); break;
	case ERROR: error(lastErr); break;
	case REDRAW: break;
	case SNAP: error("Not implemented"); break;
	case VERS: error(" (C) 1987 by Bill Kinnersley"); break;

	case TRACE: debug = ~debug; break;
	case WBOBJS:  dumplist(&wbObjs, MAST); break;
	case SELOBJS: dumplist(&selObjs, SEL); break;
	case UTILOBJS: dumplist(&utilObjs, UTIL); break;
	case CHILDREN: if (!lastObj) error("No object selected");
		else if (lastObj->wo_DrawerData)
		dumplist(&lastObj->wo_DrawerData->dd_Children, CHILD);
		break;
	case QUIT: closeAll(""); break;
	}
}

/* Rename an object */
ren(obj) struct MyWBObject *obj; {
	struct IntuiMessage *msg;
	struct IntuiMessage saveMsg;
	USHORT gid;
	char buf1[80], *buffer;
	struct Window *renWin;
	ULONG saveIDCMP;
	struct MsgPort *handid;
	long arg[1];

	if (!obj) {error("No icon selected"); return;}
	if (!(buffer = AllocMem(50L, MEMF_CPC))) /* Must be aligned */
		{printf("Couldn't allocate buffer"); return;}
	strcpy(sbuf, obj->wo_Name); strcpy(buf1, obj->wo_Name);
	if (!(renWin = OpenWindow(&ren_nw)))
		closeAll("Can't open rename window");
	renWin->UserPort = IDCMPPort;
	saveIDCMP = wbWin->IDCMPFlags;
	ModifyIDCMP(renWin, ACTIVEWINDOW | GADGETUP);
	ActivateGadget(&ren_gad, renWin, NULL);
	curWin = renWin;
	error("Enter the new name");
	for (;;) {
	    WaitPort(IDCMPPort);
	    while (msg = GetMsg(IDCMPPort)) {
/*stc*/		saveMsg = *msg;
		ReplyMsg(msg);
		if (saveMsg.IDCMPWindow!=renWin) {
		    /* If user clicks somewhere else, ignore him */
		    SetPointer(saveMsg.IDCMPWindow, zz_ptr,
			19L, 16L, -7L, -8L);
		    continue;
		}
		gid = ((struct Gadget *)saveMsg.IAddress)->GadgetID;
		switch (saveMsg.Class) {
		case GADGETUP:
		    if (gid!=GID_NAME) break;
		    if (obj->wo_Type==WBDISK) {
			if (strcmp(sbuf, obj->wo_Name)==0) goto rencln;
			cs2bs(buffer, sbuf);
			arg[0] = ((long)buffer)>>2;
			if (!(handid = DeviceProc(obj->wo_Name))) {
			    printf("Couldn't get handler\n");
			    goto rencln;
			}
			if (!sendpkt(handid, ACTION_RENAME_DISK,
			    arg, 1L)) {
			    error("Couldn't rename the disk");
			    /* User probably cancelled a requester */
			    goto rencln;
			}
		    }
		    else {
			if (debug) printf("I should rename <%s> to <%s>\n",
				obj->wo_Name, sbuf);
			strcat(buf1, ".info"); strcat(sbuf, ".info");
			if (debug) printf("and <%s> to <%s>\n", buf1, sbuf);
			if (rename(buf1, sbuf)==-1)
				{error("Can't rename"); goto rencln;}
			*rindex(buf1,'.') = 0; *rindex(sbuf,'.') = 0;
			rename(buf1, sbuf);
			/* Ignore error this time--if the real file does
			not exist, at least the .info has been renamed */
		    }
		    goto renok;
		case GADGETDOWN:
		    if (gid==GID_NAME) ClearPointer(renWin);
		    break;
		default: SetPointer(curWin, zz_ptr,  19L, 16L, -7L, -8L);
		}
	    }
	}
renok:	strcpy(obj->wo_Name, sbuf);
	obj->wo_NameXOffset = (obj->wo_Gadget.Width/2) - 4*strlen(sbuf);
	clearSel();
rencln: renWin->UserPort = NULL;
	CloseWindow(renWin);
	ModifyIDCMP(wbWin, saveIDCMP);
	FreeMem(buffer, 50L);
	ClearPointer(curWin = wbWin);
}

avail() {
	if (errWin) return;
	sprintf(title+25, "%ld free memory", AvailMem(MEMF_PUBLIC));
	SetWindowTitles(curWin, -1L, title);
}

error(s) char *s; {
	strcpy(lastErr, s);
	DisplayBeep(wbWin->WScreen);
	SetWindowTitles(curWin, -1L, s);
	OnMenu(wbWin, ERROR);
	errWin = curWin;
}

closeAll(s) char *s; {
	struct MyWBObject *obj;
	struct MyDrawerData *dd;
	struct Region *reg;
	printf(s);
	if (debug) printf("Closing things\n");
	while (obj = (struct MyWBObject *)RemHead(&wbObjs)) {
		if (debug) printf("Removing %lx <%s>\n", obj, obj->wo_Name);
		if (dd = obj->wo_DrawerData) {
			if (dd->dd_DrawerWin) {
				if (debug) printf("   (it was open)\n");
				reg = InstallClipRegion(dd->dd_DrawerWin->
					WLayer, NULL);
				DisposeRegion(reg);
				closeWinSafely(dd->dd_DrawerWin);
			}
			if (dd->dd_Lock) {
			    if (debug) printf("Unlocking dd_Lock %lx\n",
				dd->dd_Lock);
			    UnLock(dd->dd_Lock);
			}
		}
		if (obj->wo_Lock) {
			if (debug) printf("Unlocking wo_Lock %lx\n",
				obj->wo_Lock);
			UnLock(obj->wo_Lock);
		}
		FreeFreeList(&obj->wo_FreeList);
		FreeMem(obj, (long)sizeof(struct MyWBObject));
	}
	if (menuSet) ClearMenuStrip(wbWin, menuStrip);
	FreeRemember(&RememberKey, TRUE);
	if (wbWin) CloseWindow(wbWin);
	if (WBPort) DeletePort(WBPort);
	if (IconBase) CloseLibrary(IconBase);
	CurrentDir(initialDir);
	exit(0);
}

closeWinSafely(win) struct Window *win; {
/* This and the next courtesy Neil Katin */
	Forbid();
	stripIntuiMessages(win->UserPort, win);
	win->UserPort = NULL;
	ModifyIDCMP(win, 0L);
	win->MenuStrip = NULL;
	Permit();
	CloseWindow(win);
}

stripIntuiMessages(mp, win) struct MsgPort *mp; struct Window *win; {
	struct IntuiMessage *msg, *succ;

	msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
	while (succ = (struct IntuiMessage *)
		msg->ExecMessage.mn_Node.ln_Succ) {
		if (msg->IDCMPWindow==win) {
			Remove(msg);
			ReplyMsg(msg);
		}
		msg = succ;
	}
}

long sendpkt(pid, action, args, nargs)
struct MsgPort *pid; long action, args[], nargs; {
	struct StandardPacket *packet;
	long count, *pargs, res1, error;

	if (!(packet = ALLOC(StandardPacket)))
		{printf("Can't allocate packet\n"); return;}
	packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt);
	packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
	packet->sp_Pkt.dp_Port         = DOSPort;
	packet->sp_Pkt.dp_Type         = action;
	pargs = &(packet->sp_Pkt.dp_Arg1);
	for (count=0; count<nargs; count++) pargs[count] = args[count];
	PutMsg(pid, packet);
	WaitPort(DOSPort);
	GetMsg(DOSPort);
	res1 = packet->sp_Pkt.dp_Res1;
	FreeMem(packet, (long)sizeof(struct StandardPacket));
	if (!res1) printf("DOS error: %ld action=%ld\n",
		packet->sp_Pkt.dp_Res2, packet->sp_Pkt.dp_Type);
	return res1;
}
