/************************************************************************/
/* Apfel.c --- Generates an image of the Mandelbrot-set			*/
/*									*/
/* Author:	M. Böhnisch (BillySoft)					*/
/*		Löher Str. 2						*/
/*		D-4790 Paderborn					*/
/*									*/
/*		billy@uni-paderborn.de.pbinfo				*/
/*======================================================================*/
/* 06.11.89	iterative version with fixed box sizes (10 by 10),	*/
/*		adapted a GFA-BASIC program from a german magazine	*/
/*									*/
/* 08.11.89	complete own version with recursive algorithm		*/
/*		(divide & conquer)					*/
/*									*/
/* 10.11.89	added user input of picture size and borders		*/
/*									*/
/* 11.11.89	minor bug fixing					*/
/*									*/
/* 20.11.89	added fix-point arithmetik written in assembler		*/
/*		format:							*/
/*									*/
/*			[sgn|xxx xxxx xxxx xxxx.xxxx xxxx xxxx xxxx]	*/
/*									*/
/*		not accurate enough.					*/
/*									*/
/* 21.11.89	rewrote fix-point format to:				*/
/*									*/
/*			[sgn|xxx xxxx.xxxx xxxx xxxx xxxx xxxx xxxx]	*/
/*									*/
/*		nice! (I'll try to use 26 bit after the point sometime) */
/*									*/
/* 28.11.89	found IFF-Library on Fish #173. save picture option	*/
/*		added.							*/
/*									*/
/* 04.12.89	improved assembly program				*/
/*									*/
/* 07.12.89	slight optimization in recursion scheme			*/
/*									*/
/* 09.12.89	added input requester					*/
/*									*/
/* 21.07.90	review for Aztek-C5.0a					*/
/*									*/
/* 23.09.90	print option added (color printers)			*/
/*									*/
/* 25.09.90	added color requester					*/
/*                                                                      */
/* 27.09.90     optimization of assembly program                        */
/*									*/
/* 15.11.90	review for Lattice-C5.10				*/
/*									*/
/* 19.11.90	added a little retrying in case of an error by closing	*/
/*		screens. Might recover some problems with Amigas short	*/
/*		on memory or when really *BIG* screens are requested.	*/
/*									*/
/* 25.11.90	added s'more source code comments and translated all	*/
/*		strings from german to english				*/
/*									*/
/* 30.01.91	removed a bug causing to save no colormap along with a	*/
/*		picture							*/
/*									*/
/* 01.02.91	removed a bug making strange things while colorcycling	*/
/*		pictures with more than 5 BitPlanes			*/
/*									*/
/* 01.02.91	added configuration facilities				*/
/*									*/
/* 17.04.91	removed a bug preventing the "Multitasking OFF" to work	*/
/*									*/
/* 18.04.91	some cast - operators added in "printersupport.h" to	*/
/*		compile without warnings for Kick 2.0			*/
/*									*/
/* 08.05.91	added 68030/68881 support				*/
/*									*/
/* 09.05.91	replaced lattice fp by fast floating point functions	*/
/************************************************************************/

/* -------------------------------------------------------------------- */
/* Some defininitions to take advantage of Lattice's LSR-code:		*/
/* -------------------------------------------------------------------- */
long	 _stack		= 20000;	/* Stack space for this task 	*/
char	*_procname	= "Apfelkiste";	/* Name of process created	*/
long	 _priority	= 0;		/* Process priority		*/
long	 _BackgroundIO	= 0;		/* No stdio required		*/
/* -------------------------------------------------------------------- */

#define APFEL_VERSION	"27"

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <libraries/iff.h>
#include <libraries/arpbase.h>
#include <libraries/color.h>
#include <printersupport.h>
#include <clib/macros.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mffp.h>
#include <math.h>
#include "Apf0.h"
#include "Apf1.h"
#include "Apf2.h"

/* -------------------------------------------------------------------- */
/* Prototypes for the functions in the other modules			*/
/* -------------------------------------------------------------------- */

void FixPoint(double rmin, double rmax, double imin, double imax, double dx, double dy,
		int maxiter, double divergenz, int gx, int gy, int depth);
void __regargs	Apfel_Alert(long number);
void __regargs	Activate_Gadget(struct Window *w, USHORT ID);
void __regargs	Apfel_FLOAT(int x1, int y1, int x2, int y2);
long 		Iter_FLOAT(double r, double i);

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

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct IFFBase		*IFFBase;
struct ArpBase		*ArpBase;
struct ColorBase	*ColorBase;
struct Screen		*s;
struct Window		*w, *u, *v;
struct RastPort		*rp, *up;
struct ViewPort		*vp;
short			 cycle, task = TRUE;
APTR			 IFFfile = NULL;
struct FileRequester	*FReq;
union printerIO		*request;
struct MsgPort		*printerPort;

int			 gx, gy, xsize, ysize, depth, hide;
short			 maxcol;
int			 maxiter;
double			 divergenz, rmin, rmax, imin, imax, dx, dy;

/* -------------------------------------------------------------------- */
/* All the stuff needed to comfortably get IntuitionMessages		*/
/* -------------------------------------------------------------------- */

#define GAD_ID (((struct Gadget *)ADDR)->GadgetID)

ULONG			 CLASS, CODE;
APTR			 ADDR;
struct IntuiMessage	*Message	= NULL;

ULONG GetMessage(struct Window *MW)
{
	CLASS = CODE = 0;
	ADDR = NULL;
	if ( Message = (struct IntuiMessage *) GetMsg(MW->UserPort) ) {
		CLASS	= Message->Class;
		CODE	= Message->Code;
		ADDR	= Message->IAddress;
		ReplyMsg((struct Message *) Message);
	}
	return(CLASS);
}

/* -------------------------------------------------------------------- */
/* Simple routine to draw a rectangular shape. Used for the Mouse Opt	*/
/* -------------------------------------------------------------------- */

void DrawRect(struct RastPort *rp, short x1, short y1, short x2, short y2)
{
	Move(rp, x1, y1);
	Draw(rp, x2, y1);
	Draw(rp, x2, y2);
	Draw(rp, x1, y2);
	Draw(rp, x1, y1);
}

/* -------------------------------------------------------------------- */
/* Pre-initialized structures for main screen and window		*/
/* -------------------------------------------------------------------- */

struct NewScreen NS = {
	0, 0,				/* screen XY origin relative to View */
	0, 0,				/* screen width and height */
	0,				/* screen depth (number of bitplanes) */
	0, 1,				/* detail and block pens */
	NULL,				/* display modes for this screen */
	CUSTOMSCREEN | SCREENQUIET,	/* screen type */
	NULL,				/* pointer to default screen font */
	NULL,				/* screen title */
	NULL,				/* first in list of custom screen gadgets */
	NULL				/* pointer to custom BitMap structure */
};

struct NewWindow NW = {
	0, 0,		/* window XY origin relative to TopLeft of screen */
	0, 0,		/* window width and height */
	0, 1,		/* detail and block pens */
	NULL,		/* IDCMP flags */
	SMART_REFRESH |
	ACTIVATE      |
	BORDERLESS,	/* other window flags */
	NULL,		/* first gadget in gadget list */
	NULL,		/* custom CHECKMARK imagery */
	NULL,		/* window title */
	NULL,		/* custom screen pointer */
	NULL,		/* custom bitmap */
	5, 5,		/* minimum width and height */
	-1, -1,		/* maximum width and height */
	CUSTOMSCREEN	/* destination screen type */
};

/* -------------------------------------------------------------------- */
/* Default palette. Change this if you don't like the colors provided	*/
/* by me. Versions 25 and higher are supporting a custom default file.	*/
/* -------------------------------------------------------------------- */

USHORT Palette[128] = {
	0x0000,	/* color #0 */
	0x0F90,	/* color #1 */
	0x0F20,	/* color #2 */
	0x0840,	/* color #3 */
	0x0580,	/* color #4 */
	0x0589,	/* color #5 */
	0x055F,	/* color #6 */
	0x0A0F,	/* color #7 */
	0x0F08,	/* color #8 */
	0x0777,	/* color #9 */
	0x0080,	/* color #10 */
	0x00A0,	/* color #11 */
	0x00C0,	/* color #12 */
	0x00E0,	/* color #13 */
	0x08E0,	/* color #14 */
	0x0FF0,	/* color #15 */
	0x0000,	/* color #16 */
	0x0F90,	/* color #17 */
	0x0F20,	/* color #18 */
	0x0840,	/* color #19 */
	0x0580,	/* color #20 */
	0x0589,	/* color #21 */
	0x055F,	/* color #22 */
	0x0A0F,	/* color #23 */
	0x0F08,	/* color #24 */
	0x0777,	/* color #25 */
	0x0080,	/* color #26 */
	0x00A0,	/* color #27 */
	0x00C0,	/* color #28 */
	0x00E0,	/* color #29 */
	0x08E0,	/* color #30 */
	0x0FF0	/* color #31 */
#define PaletteColorCount 32
};

/* -------------------------------------------------------------------- */
/* Close everything opened at runtime					*/
/* -------------------------------------------------------------------- */

void CleanUp(void)
{
	if ( request )		DeleteExtIO((struct IORequest *) request);
	if ( printerPort )	DeletePort(printerPort);
	if ( IFFfile )		CloseIFF(IFFfile);
	if ( w )		CloseWindow(w);
	if ( u )		CloseWindow(u);
	if ( s )		CloseScreen(s);
	if ( ColorBase )	CloseLibrary(ColorBase);
	if ( ArpBase )		CloseLibrary((struct Library *) ArpBase);
	if ( IFFBase )		CloseLibrary(IFFBase);
	if ( GfxBase )		CloseLibrary(GfxBase);
	if ( IntuitionBase )	CloseLibrary(IntuitionBase);
	exit(0);
}

/* -------------------------------------------------------------------- */
/* Open all used libraries, ports, etc. If this routine fails you are	*/
/* probably not up-to-date with one or several of the shared libraries	*/
/* used by me. Copy the provided libraries to your LIBS: directory,	*/
/* reboot (!) and try again.						*/
/* -------------------------------------------------------------------- */

void OpenLibs(void)
{
	IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L);
	if ( ! IntuitionBase ) {
		Apfel_Alert(1);
		CleanUp();
	}

	GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L);
	if ( ! GfxBase ) {
		Apfel_Alert(2);
		CleanUp();
	}

	IFFBase = (struct IFFBase *) OpenLibrary(IFFNAME, IFFVERSION);
	if ( ! IFFBase ) {
		Apfel_Alert(3);
		CleanUp();
	}

	ArpBase = (struct ArpBase *) OpenLibrary(ArpName, ArpVersion);
	if ( ! ArpBase ) {
		Apfel_Alert(4);
		CleanUp();
	}

	ColorBase = (struct ColorBase *) OpenLibrary(COLORNAME, COLORVERSION);
	if ( ! ColorBase ) {
		Apfel_Alert(5);
		CleanUp();
	}

	FReq = ArpAllocFreq();	/* Wird durch CloseLibrary(ArpBase) freigegeben */
	if ( ! FReq ) {
		Apfel_Alert(6);
		CleanUp();
	}

	printerPort = CreatePort("Apfel-01.port",0L);
	if ( ! printerPort ) {
		Apfel_Alert(7);
		CleanUp();
	}

	request = (union printerIO *) CreateExtIO(printerPort, sizeof(union printerIO));
	if ( ! request ) {
		Apfel_Alert(8);
		CleanUp();
	}
}

/* -------------------------------------------------------------------- */
/* Open the control window and set gadget texts to appropriate values	*/
/* -------------------------------------------------------------------- */

void OpenRW(void)
{
	NW2.Screen = s;
	if ( ! s ) {
		NW2.Type = WBENCHSCREEN;
	}
	else {
		NW2.Type = CUSTOMSCREEN;
	}

	if ( task ) {
		strcpy((char *) IText4.IText, " ON ");
		IText4.LeftEdge = 6;
	}
	else {
		strcpy((char *) IText4.IText, "OFF");
		IText4.LeftEdge = 10;
	}

	if ( cycle ) {
		strcpy((char *) IText3.IText, " ON ");
		IText3.LeftEdge = 6;
	}
	else {
		strcpy((char *) IText3.IText, "OFF");
		IText3.LeftEdge = 10;
	}

	u = OpenWindow(&NW2);		/* open control window 		*/
	if ( ! u ) {			/* if something goes wrong...	*/
		Apfel_Alert(9);		/* give message.		*/
		if ( s ) {		/* is the screen open, then ?	*/
			CloseScreen(s);	/* close it...			*/
			s = NULL;
			OpenRW();	/* and retry on WB Screen...	*/
		}
		else {			/* No screen, no hope...	*/
			CleanUp();	/* exiting...			*/
		}
	}

	up = u->RPort;
	PrintIText(up, &IntuiTextList1, 0L, 0L);
}

/* -------------------------------------------------------------------- */
/* Open screen & window for graphics rendition trying to evaluate a	*/
/* "best match" for the view modes for both PAL and NTSC. Maybe this	*/
/* needs a little work for optimal results on NTSC machines.		*/
/* I plan to rework this completely after CBM pops out Kick 2.0 for	*/
/* the A2000 in an official version.					*/
/* -------------------------------------------------------------------- */

void OpenAll(void)
{
	USHORT Modes = 0;

	NS.Width	= xsize;
	NS.Height	= ysize;
	NS.Depth	= depth;
	maxcol		= 1 << depth;

	if ( xsize > 368 )		Modes  = HIRES;
	if ( ! Modes && depth == 6 )	Modes  = EXTRA_HALFBRITE;
	if ( ysize > 282 )		Modes |= LACE;

	NS.ViewModes = Modes;

	s = OpenScreen(&NS);
	if ( ! s ) {
		Apfel_Alert(10);
	}
	else {
		NW.Screen	= s;
		NW.Width	= gx;
		NW.Height	= gy;
		NW.LeftEdge	= (xsize - gx) / 2;
		NW.TopEdge	= (ysize - gy) / 2;
		w = OpenWindow(&NW);
		if ( ! w ) {
			Apfel_Alert(9);
		}
		else {
			rp = w->RPort;
			vp = &(s->ViewPort);
			LoadRGB4(vp, Palette, PaletteColorCount);
		}
	}
}

/* -------------------------------------------------------------------- */
/* Load an IFF ILBM file and get it displayed on the graphics screen.	*/
/* I have not put too much work into this, e.g. there is no chunk for	*/
/* the data needed to re-calculate the loaded Mandelbrot image.		*/
/* Comments and help are welcome, just send me a message to my E-Mail	*/
/* adress.								*/
/* -------------------------------------------------------------------- */

BOOL LoadFile(char *Name)
{
	struct BitMapHeader *bmhd;
	ULONG cnt;

	IFFfile = OpenIFF(Name);
	if ( ! IFFfile ) {
		Apfel_Alert(12);
	}
	else {
		bmhd = GetBMHD(IFFfile);
		if ( ! bmhd ) {
			Apfel_Alert(13);
		}
		else {
			NS.Width	= gx	= xsize	= bmhd->w;
			NS.Height	= gy	= ysize	= bmhd->h;
			NS.Depth	= depth	= bmhd->nPlanes;
			maxcol		= 1 << depth;
			NS.ViewModes	= GetViewModes(IFFfile);
			s		= OpenScreen(&NS);
			if ( ! s ) {
				Apfel_Alert(10);
			}
			else {
				vp		= &(s->ViewPort);
				cnt		= GetColorTab(IFFfile, (WORD *) Palette);
				NW.Screen	= s;
				NW.Width	= gx;
				NW.Height	= gy;
				w		= OpenWindow(&NW);
				if ( ! w ) {
					Apfel_Alert(9);
					CloseScreen(s);
					s = NULL;
				}
				else {
					rp		= w->RPort;
					LoadRGB4(vp, Palette, cnt);
					if ( ! DecodePic(IFFfile, rp->BitMap) ) {
						Apfel_Alert(14);
						CloseWindow(w);
						w = NULL;
						CloseScreen(s);
						s = NULL;
					}
				}
			}
		}
		CloseIFF(IFFfile);
		IFFfile		= NULL;
	}
	return ( w != NULL );		/* All OK if window still open */
}

/* -------------------------------------------------------------------- */
/* Set default values for the control window. Load the default image to	*/
/* comfortably get zoomed into this wonderful world of chaos.		*/
/* -------------------------------------------------------------------- */

void SetDefault(void)
{
	FILE	*fp;
	char	 defpic[FMSIZE];
	int	 i;
	int	 omt;

	omt = task;

	fp = fopen("Apfelkiste.config", "r");
	if ( ! fp ) fopen("DEVS:Apfelkiste.config", "r");
	if ( ! fp ) fopen("S:Apfelkiste.config", "r");
	if ( ! fp ) {
		Apfel_Alert(11);
		strcpy(defpic, "Apfel0.IFF");
		rmin		= -2.3;
		imin		= -1.25;
		rmax		=  0.825;
		imax		=  1.25;
		maxiter		= 30;
		divergenz	=  6.0;
		cycle		= FALSE;
		task		= TRUE;
	}
	else {
		fscanf(fp, "FNAME=%s", defpic);
		fscanf(fp, "RMIN=%lf", &rmin);
		fscanf(fp, "RMAX=%lf", &rmax);
		fscanf(fp, "IMIN=%lf", &imin);
		fscanf(fp, "IMAX=%lf", &imax);
		fscanf(fp, "MAXITER=%d", &maxiter);
		fscanf(fp, "DIVERGENZ=%lf", &divergenz);
		fscanf(fp, "TASK=%hd", &task);
		fscanf(fp, "CYCLE=%hd", &cycle);
		for ( i = 0; i < PaletteColorCount; i++ ) {
			fscanf(fp, "COLOR=%hx", &(Palette[i]));
		}
		fclose(fp);
	}

	if ( ! LoadFile("Apfel0.IFF") ) {
		xsize	= gx	= 320;
		ysize	= gy	= 200;
		depth	= 2;
		maxcol	= 1 << depth;
	}

	dx = (rmax - rmin) / (double) gx;
	dy = (imax - imin) / (double) gy;

	sprintf((char *) Gadget1SIBuff, "%lf", rmin);
	sprintf((char *) Gadget2SIBuff, "%lf", rmax);
	sprintf((char *) Gadget3SIBuff, "%lf", imin);
	sprintf((char *) Gadget4SIBuff, "%lf", imax);
	sprintf((char *) Gadget5SIBuff, "%d",  maxiter);
	sprintf((char *) Gadget6SIBuff, "%lf", divergenz);
	sprintf((char *) Gadget7SIBuff, "%d",  gx);
	sprintf((char *) Gadget8SIBuff, "%d",  gy);
	sprintf((char *) Gadget9SIBuff, "%d",  depth);

	if ( omt != task ) {
		if ( task ) {
			Permit();
		}
		else {
			Forbid();
		}
	}
}

/* -------------------------------------------------------------------- */
/* Used by load/save routines to get filenames.	Thanks to all the guys	*/
/* who put sweat and blood into the creation of ARP.			*/
/* -------------------------------------------------------------------- */

BOOL GetFileName(char *Name, char *Hail)
{
	FReq->fr_Hail		= Hail;
	FReq->fr_Window		= w;
	FReq->fr_LeftEdge	= 1;
	FReq->fr_TopEdge	= 1;

	if ( FileRequest(FReq) ) {
		strcpy(Name, FReq->fr_Dir);
		TackOn(Name, FReq->fr_File);
		return TRUE;
	}
	else {
		return FALSE;
	}
}

/************************************************************************/
/* The main() function, at last...					*/
/* Contains the handling to react on gadget activation and manage the	*/
/* call of the diverse subroutines.					*/
/* Not commented at all, but shouldn't be too difficult to read anyway.	*/
/************************************************************************/

void main(int argc, char *argv[])
{
	char	fname[80];
	int	i, x, y;
	double	help;
	int	mx1, my1, mx2, my2;
	UWORD	c_palette[128];

	OpenLibs();
	SetDefault();
	OpenRW();

	do {
		Wait(1L << u -> UserPort -> mp_SigBit);
		GetMessage(u);
		switch ( CLASS ) {
		case GADGETUP:
			switch ( GAD_ID ) {
			case GAD_FLOAT:
			case GAD_FXP:
				sscanf((char *) Gadget1SIBuff, "%lf", &rmin);
				sscanf((char *) Gadget2SIBuff, "%lf", &rmax);
				sscanf((char *) Gadget3SIBuff, "%lf", &imin);
				sscanf((char *) Gadget4SIBuff, "%lf", &imax);
				sscanf((char *) Gadget5SIBuff, "%d",  &maxiter);
				sscanf((char *) Gadget6SIBuff, "%lf", &divergenz);
				sscanf((char *) Gadget7SIBuff, "%d",  &gx);
				sscanf((char *) Gadget8SIBuff, "%d",  &gy);
				sscanf((char *) Gadget9SIBuff, "%d",  &depth);

				xsize = gx;
				if ( gx <= 736 ) xsize = 736;	/* Max. Overscan Hires	*/
				if ( gx <= 640 ) xsize = 640;	/* Nor. Size Hires	*/
				if ( gx <= 368 ) xsize = 368;	/* Max. Overscan Lores	*/
				if ( gx <= 320 ) xsize = 320;	/* Nor. Size Lores	*/

				ysize = gy;
				if ( gy <= 564 ) ysize = 564;	/* Max. Overscan Lace   PAL	*/
				if ( gy <= 512 ) ysize = 512;	/* Nor. Size Lace       PAL	*/
				if ( gy <= 400 ) ysize = 400;	/* Nor. Size Lace       NTSC	*/
				if ( gy <= 282 ) ysize = 282;	/* Max. Overscan NoLace PAL	*/
				if ( gy <= 256 ) ysize = 256;	/* Nor. Size NoLace	PAL	*/ 
				if ( gy <= 200 ) ysize = 200;	/* Nor. Size NoLace     NTSC	*/
				if ( w ) CloseWindow(w);
				w = NULL;
				if ( u ) CloseWindow(u);
				u = NULL;
				if ( s ) CloseScreen(s);
				s = NULL;
				OpenAll();
				if (  w && s ) {
					dx   = (rmax - rmin) / (double) gx;
					dy   = (imax - imin) / (double) gy;

					switch ( GAD_ID ) {
					case GAD_FLOAT:
						help = rmin;
						for ( x = 0; x < gx; x++ ) {
							SetAPen(rp, Iter_FLOAT(help, imin));
							WritePixel(rp, x, 0);
							SetAPen(rp, Iter_FLOAT(help, imax));
							WritePixel(rp, x, gy-1);
							help += dx;
						}

						help = imin;
						for ( y = 0; y < gy; y++ ) {
							SetAPen(rp, Iter_FLOAT(rmin, help));
							WritePixel(rp, 0, y);
							SetAPen(rp, Iter_FLOAT(rmax, help));
							WritePixel(rp, gx-1, y);
							help += dy;
						}

						Apfel_FLOAT(0, 0, gx - 1, gy - 1);
						break;
					case GAD_FXP:
 						FixPoint(rmin, rmax, imin, imax, dx, dy,
							 maxiter, divergenz,
							 gx, gy, depth);
						break;
					}
				}
				else {
					if ( s ) {
						CloseScreen(s);
					}
				}
				OpenRW();
				break;
			case GAD_QUIT:
				CleanUp();
				break;
			case GAD_SAVE:
				if ( u ) CloseWindow(u);
				u = NULL;
				if ( GetFileName(fname, "Save Picture") ) {
					SaveBitMap(fname, &(s->BitMap), Palette, 0x1L);
				}
				OpenRW();
				break;
			case GAD_LOAD:
				if ( u ) CloseWindow(u);
				u = NULL;
				if ( GetFileName(fname, "Load Picture") ) {
					if ( w ) CloseWindow(w);
					w = NULL;
					if ( s ) CloseScreen(s);
					s = NULL;
					if ( ! LoadFile(fname) ) {;}
				}
				OpenRW();
				break;
			case GAD_REAL0:
				Activate_Gadget(u, GAD_REAL1);
				break;
			case GAD_REAL1:
				Activate_Gadget(u, GAD_IMAG0);
				break;
			case GAD_IMAG0:
				Activate_Gadget(u, GAD_IMAG1);
				break;
			case GAD_IMAG1:
				Activate_Gadget(u, GAD_MAXITER);
				break;
			case GAD_MAXITER:
				Activate_Gadget(u, GAD_DIV);
				break;
			case GAD_DIV:
				Activate_Gadget(u, GAD_XSIZE);
				break;
			case GAD_XSIZE:
				Activate_Gadget(u, GAD_YSIZE);
				break;
			case GAD_YSIZE:
				Activate_Gadget(u, GAD_DEPTH);
				break;
			case GAD_DEPTH:
				Activate_Gadget(u, GAD_REAL0);
				break;
			case GAD_MOUSE:
				if ( s && w ) {
					if ( u ) CloseWindow(u);
					u = NULL;
					ModifyIDCMP(w, MOUSEBUTTONS | INTUITICKS);
					do {
						Wait(1L << w->UserPort->mp_SigBit);
						GetMessage(w);
					} while ( CLASS != MOUSEBUTTONS || CODE != SELECTDOWN );

					mx2 = mx1 = w->MouseX;
					my2 = my1 = w->MouseY;
					SetDrMd(rp, JAM2 | COMPLEMENT);
					SetAPen(rp, 1L);
					DrawRect(rp, mx1, my1, mx2, my2);

					do {
						if ( mx2 != w->MouseX || my2 != w->MouseY ) {
							DrawRect(rp, mx1, my1, mx2, my2);
							mx2 = w->MouseX;
							my2 = w->MouseY;
							DrawRect(rp, mx1, my1, mx2, my2);
						}
						Wait(1L << w->UserPort->mp_SigBit);
						GetMessage(w);
					} while ( CLASS != MOUSEBUTTONS || CODE != SELECTUP );

					DrawRect(rp, mx1, my1, mx2, my2);
					if ( mx1 > mx2 ) {
						i	= mx1;
						mx1	= mx2;
						mx2	= i;
					}
					if ( my1 > my2 ) {
						i	= my1;
						my1	= my2;
						my2	= i;
					}
					ModifyIDCMP(w, NULL);

					sprintf((char *) Gadget1SIBuff, "%lf", mx1*dx+rmin);
					sprintf((char *) Gadget2SIBuff, "%lf", mx2*dx+rmin);
					sprintf((char *) Gadget3SIBuff, "%lf", my1*dy+imin);
					sprintf((char *) Gadget4SIBuff, "%lf", my2*dy+imin);
					OpenRW();
				}
				break;
			case GAD_VIEW:
				if ( s && w ) {
					if ( u ) CloseWindow(u);
					u = NULL;
					memcpy(c_palette, Palette, sizeof(UWORD) * MIN(32, maxcol));
					ModifyIDCMP(w, MOUSEBUTTONS | INTUITICKS);
					while ( GetMessage(w) != MOUSEBUTTONS ) {
						if ( cycle ) {
							i = c_palette[MIN(31, maxcol-1)];
							movmem(c_palette, c_palette+1, sizeof(UWORD) * MIN(31, maxcol-1 ));
							c_palette[0] = i;
							LoadRGB4(vp, c_palette, MIN(32, maxcol));
							Delay(10L);
						}
						Wait(1L << w->UserPort->mp_SigBit);
					}
					ModifyIDCMP(w, NULL);
					LoadRGB4(vp, Palette, MIN(32,maxcol));
					OpenRW();
				}
				break;
			case GAD_PRINT:
				if ( s && w ) {
					if ( ! OpenPrinter(request) ) {
						DumpRPort(request, rp, vp->ColorMap,
						vp->Modes, 0, 0, s->Width, s->Height, 0, 0,
						SPECIAL_FULLCOLS | SPECIAL_ASPECT);
						ClosePrinter(request);
					}
				}
				break;
			case GAD_CYCLE:
				cycle = ! cycle;
				if ( cycle ) {
					strcpy((char *) IText3.IText, " ON ");
					IText3.LeftEdge = 6;
				}
				else {
					strcpy((char *) IText3.IText, "OFF");
					IText3.LeftEdge = 10;
				}
				RefreshGadgets(u->FirstGadget, u, NULL);
				break;
			case GAD_DEFAULT:
				if ( w ) CloseWindow(w);
				w = NULL;
				if ( u ) CloseWindow(u);
				u = NULL;
				if ( s ) CloseScreen(s);
				s = NULL;
				SetDefault();
				OpenRW();
				break;
			case GAD_TASK:
				task = ! task;
				if ( task ) {
					strcpy((char *) IText4.IText, " ON ");
					IText4.LeftEdge = 6;
					Permit();
				}
				else {
					strcpy((char *) IText4.IText, "OFF");
					IText4.LeftEdge = 10;
					Forbid();
				}
				RefreshGadgets(u->FirstGadget, u, NULL);
				break;
			case GAD_ABOUT:
				if ( u ) CloseWindow(u);
				u = NULL;
				NW3.Screen = s;
				if ( ! s )	NW3.Type = WBENCHSCREEN;
				else		NW3.Type = CUSTOMSCREEN;
				if ( v = OpenWindow(&NW3) ) {
					PrintIText(v->RPort, &IntuiTextList2, 0L, 0L);
					Wait(1L << v->UserPort->mp_SigBit);
					CloseWindow(v);
					v = NULL;
				}
				OpenRW();
				break;
			case GAD_COLOR:
				if ( s ) {
					if ( u ) CloseWindow(u);
					u = NULL;
					if ( ! DoColor(Palette, s) ) {
						for ( i = 0; i < MIN(32, maxcol); i++ ) {
							Palette[i] = GetRGB4(vp->ColorMap, i);
						}
					}
					OpenRW();
				}
				break;
			}
		}
	} while ( TRUE );
}
