/*
 *                          DiskSpeed v3.0
 *                                by
 *                           Michael Sinz
 *
 *             Copyright (c) 1989 by MKSoft Development
 *
 *			MKSoft Development
 *			163 Appledore Drive
 *			Downingtown, PA 19335
 *
 * Yes, this is yet another disk speed testing program, but with a few
 * differences.  It was designed to give the most accurate results of the
 * true disk performance in the system.  For this reason many of
 * DiskSpeed's results may look either lower or higher than current disk
 * performance tests.
 *
 * This program was thrown together in a few hours because I needed more
 * accurate and consistent results for disk performance as seen from the
 * application's standpoint.  This program has now served its purpose and
 * I am now giving it to the rest of the Amiga world to play with as long
 * as all of the files remain together in unmodified form.  (That is, the
 * files DiskSpeed, DiskSpeed.info, DiskSpeed.c, DiskSpeedWindow.c,
 * DiskSpeedWindow.h, MakeBoxes.c, MakeBoxes.h, StandardGadgets.c,
 * StandardGadgets.h, RenderInfo.c, RenderInfo.h, DiskSpeed.doc, and
 * MakeFile)
 *
 * Version 2.0 of this program added a few features and cleaned up the
 * user interface.  I hope you like this...
 *
 * Version 3.0 of this program added the performance stress and cleaned up
 * some parts of the older code.  (Fix to RenderInfo.c)
 *
 ******************************************************************************
 *									      *
 *	Reading legal mush can turn your brain into guacamole!		      *
 *									      *
 *		So here is some of that legal mush:			      *
 *									      *
 * Permission is hereby granted to distribute this program's source	      *
 * executable, and documentation for non-commercial purposes, so long as the  *
 * copyright notices are not removed from the sources, executable or	      *
 * documentation.  This program may not be distributed for a profit without   *
 * the express written consent of the author Michael Sinz.		      *
 *									      *
 * This program is not in the public domain.				      *
 *									      *
 * Fred Fish is expressly granted permission to distribute this program's     *
 * source and executable as part of the "Fred Fish freely redistributable     *
 * Amiga software library."						      *
 *									      *
 * Permission is expressly granted for this program and it's source to be     *
 * distributed as part of the Amicus Amiga software disks, and the	      *
 * First Amiga User Group's Hot Mix disks.				      *
 *									      *
 ******************************************************************************
 *
 * This is the window opening and definition code...
 */

#include	<exec/types.h>
#include	<exec/memory.h>
#include	<devices/timer.h>
#include	<intuition/intuition.h>
#include	<graphics/gfxmacros.h>
#include	<graphics/copper.h>
#include	<hardware/custom.h>

#include	<proto/all.h>

#include	<string.h>

#include	"RenderInfo.h"
#include	"StandardGadgets.h"
#include	"MakeBoxes.h"
#include	"DiskSpeedWindow.h"

extern	struct	Custom	__far	custom;

#define	WINDOWTEXT_SIZE	60

static char DiskSpeedTitle[14]="DiskSpeed 3.1";
static char WindowText[WINDOWTEXT_SIZE]="DiskSpeed 3.1 - Copyright (c) 1989,90 by MKSoft Development";
static char CPUstressTask[26]="DiskSpeed CPU Stress Task";
static char Dashes[10]="---------";

static char fontnam[11]="topaz.font";
static struct TextAttr TOPAZ80={fontnam,TOPAZ_EIGHTY,0,0};

#define	TEXT_BUFFER_SIZE	1000L

#define	NUM_COP_INS	12000

#define	WINDOW_WIDTH	531
#define	WINDOW_HEIGHT	177

#define	REQ_X_SIZE	518
#define	REQ_Y_SIZE	152

#define	BOX_OUT	0
#define	BOX_IN	1

struct BoxType
{
	SHORT	x1,y1;
	SHORT	x2,y2;
	SHORT	type;
};

struct Text_Info
{
	SHORT	x,y;
	char	*text;
};

struct Gadget_Info
{
	SHORT	x,y;
	SHORT	size;
	SHORT	flags;
	USHORT	ID;
	char	*text;
};

struct Result_Info
{
	SHORT	x,y;
};

static	struct BoxType BoxTypes[NUM_BOXES]=
{
	{0,0,		WINDOW_WIDTH-1,WINDOW_HEIGHT-1,	BOX_OUT},
	{70,20,		249,31,				BOX_IN},
	{70,37,		524,48,				BOX_IN},
	{16,55,		516,102,			BOX_IN},
	{16,106,	265,154,			BOX_IN},
	{274,106,	373,154,			BOX_IN},
	{143,68,	226,98,				BOX_IN},
	{236,68,	319,98,				BOX_IN},
	{329,68,	412,98,				BOX_IN},
	{422,68,	505,98,				BOX_IN},
	{171,110,	254,150,			BOX_IN},
	{282,127,	365,137,			BOX_IN}
};

static	struct Text_Info TextInfo[NUM_TEXT]=
{
	{8,22,		"Device:"},
	{8,39,		"Comment"},
	{265,22,	"Test Intensity:"},
	{24,59,		"Buffer Size"},
	{24,70,		"Bytes/s Create"},
	{24,80,		"Bytes/s Write"},
	{24,90,		"Bytes/s Read"},
	{197,59,	"512"},
	{282,59,	"4096"},
	{367,59,	"32768"},
	{452,59,	"262144"},
	{24,112,	"Files/s Create"},
	{24,122,	"Files/s Open/Close"},
	{24,132,	"Files/s Scan"},
	{24,142,	"Files/s Delete"},
	{288,118,	"Seek/Read"},
	{8,162,		"Performance Stress:"},
	{185,162,	"DMA Contention"},
	{368,162,	"CPU Contention"}
};

static	struct Gadget_Info GadgetInfo[NUM_GADGETS]=
{
	{387,19,	41,	GADGIMMEDIATE|TOGGLESELECT,	GADGET_HIGH,	"High"},
	{435,19,	41,	GADGIMMEDIATE|TOGGLESELECT,	GADGET_MED,	"Med"},
	{483,19,	41,	GADGIMMEDIATE|TOGGLESELECT,	GADGET_LOW,	"Low"},

	{391,107,	116,	RELVERIFY,	GADGET_START,	"Start Test"},
	{391,124,	116,	RELVERIFY,	GADGET_SAVE,	"Save Results"},
	{391,141,	116,	RELVERIFY,	GADGET_PRINT,	"Print Results"},

	{300,159,	41,	TOGGLESELECT,	GADGET_DMA,	"DMA"},
	{483,159,	41,	TOGGLESELECT,	GADGET_CPU,	"CPU"}
};

static	struct Result_Info ResultInfo[NUM_RESULTS]=
{
	{149,70},	{149,80},	{149,90},
	{242,70},	{242,80},	{242,90},
	{335,70},	{335,80},	{335,90},
	{428,70},	{428,80},	{428,90},

	{177,112},	{177,122},	{177,132},	{177,142},

	{288,129}
};

/*
 * This define is for the Write_Results routine...
 */
#define	MYCAT(z,y,x)	for (y=x;*y;*z++=*y++)
#define	MYCATNEWLINE(x)	*x++='\n'
#define	MYCATTAB(x)	*x++='\t'
#define	MYCATSPACE(x)	*x++=' '

/*
 * This routine builds a string of the results and then writes it to
 * the file passed...
 */
VOID Write_Results(struct MyWindow *MyWindow,BPTR TheFile)
{
register	char	*t;
register	char	*h;
register	char	*Buffer;
register struct	Gadget	*gad;
register	short	flag=FALSE;

	if (t=Buffer=AllocMem(TEXT_BUFFER_SIZE,MEMF_PUBLIC|MEMF_CLEAR))
	{

/* Title and device name */
		MYCATNEWLINE(t);
		MYCAT(t,h,WindowText);
		MYCATNEWLINE(t);
		MYCATNEWLINE(t);
		MYCAT(t,h,TextInfo[0].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->DeviceName);
		MYCATNEWLINE(t);
		MYCATNEWLINE(t);
		if (MyWindow->Comment[0])
		{
			MYCAT(t,h,TextInfo[1].text);
			MYCATTAB(t);
			MYCAT(t,h,MyWindow->Comment);
			MYCATNEWLINE(t);
			MYCATNEWLINE(t);
		}

/* Tell of the test intensity... */
		MYCAT(t,h,TextInfo[2].text);
		MYCATSPACE(t);
		switch(MyWindow->TestFlag)
		{
		case GADGET_HIGH:	MYCAT(t,h,GadgetInfo[0].text);
					break;
		case GADGET_MED:	MYCAT(t,h,GadgetInfo[1].text);
					MYCATSPACE(t);
					break;
		case GADGET_LOW:	MYCAT(t,h,GadgetInfo[2].text);
					MYCATSPACE(t);
					break;
		}

/* Show the DMA and CPU settings... */
		MYCATSPACE(t);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[16].text);

		gad=MyWindow->Window->FirstGadget;
		while (gad)
		{
			if (gad->Flags & SELECTED)
			{
				if (GADGET_DMA==gad->GadgetID)
				{
					MYCATSPACE(t);
					if (flag)
					{
						*t++='&';
						MYCATSPACE(t);
					}
					MYCAT(t,h,TextInfo[17].text);
					flag=TRUE;
				}
				else if (GADGET_CPU==gad->GadgetID)
				{
					MYCATSPACE(t);
					if (flag)
					{
						*t++='&';
						MYCATSPACE(t);
					}
					MYCAT(t,h,TextInfo[18].text);
					flag=TRUE;
				}
			}
			gad=gad->NextGadget;
		}
		if (!flag) MYCAT(t,h," None");
		MYCATNEWLINE(t);
		MYCATNEWLINE(t);

/* File Create */
		MYCAT(t,h,MyWindow->MyResults[RESULTS_CREATE].text);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[11].text);
		MYCATNEWLINE(t);

/* File Open/Close */
		MYCAT(t,h,MyWindow->MyResults[RESULTS_OPEN_CLOSE].text);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[12].text);
		MYCATNEWLINE(t);

/* File Scan */
		MYCAT(t,h,MyWindow->MyResults[RESULTS_DIR_SCAN].text);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[13].text);
		MYCATNEWLINE(t);

/* File Delete */
		MYCAT(t,h,MyWindow->MyResults[RESULTS_DELETE].text);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[14].text);
		MYCATNEWLINE(t);

		MYCATNEWLINE(t);

/* Seek and Read */
		MYCAT(t,h,MyWindow->MyResults[RESULTS_SEEK_READ].text);
		MYCATSPACE(t);
		MYCAT(t,h,TextInfo[15].text);
		MYCATNEWLINE(t);

		MYCATNEWLINE(t);

/* Titles... */
		MYCAT(t,h,TextInfo[3].text);
		MYCATTAB(t);
		MYCAT(t,h,TextInfo[7].text);
		MYCATTAB(t);
		MYCATTAB(t);
		MYCAT(t,h,TextInfo[8].text);
		MYCATTAB(t);
		MYCATTAB(t);
		MYCAT(t,h,TextInfo[9].text);
		MYCATTAB(t);
		MYCATTAB(t);
		MYCAT(t,h,TextInfo[10].text);
		MYCATNEWLINE(t);
/* Dash it all...  :-) */
		MYCAT(t,h,Dashes);
		MYCATTAB(t);
		MYCAT(t,h,Dashes);
		MYCATTAB(t);
		MYCAT(t,h,Dashes);
		MYCATTAB(t);
		MYCAT(t,h,Dashes);
		MYCATTAB(t);
		MYCAT(t,h,Dashes);
		MYCATNEWLINE(t);

/* Create Speed */
		MYCAT(t,h,TextInfo[4].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_512_CREATE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_4096_CREATE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_32768_CREATE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_262144_CREATE].text);
		MYCATNEWLINE(t);

/* Write Speed */
		MYCAT(t,h,TextInfo[5].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_512_WRITE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_4096_WRITE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_32768_WRITE].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_262144_WRITE].text);
		MYCATNEWLINE(t);

/* Read Speed */
		MYCAT(t,h,TextInfo[6].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_512_READ].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_4096_READ].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_32768_READ].text);
		MYCATTAB(t);
		MYCAT(t,h,MyWindow->MyResults[RESULTS_262144_READ].text);
		MYCATNEWLINE(t);

		MYCATNEWLINE(t);
		MYCATNEWLINE(t);

/* Now, all we have to do is write the sucker... */
		Write(TheFile,Buffer,t-Buffer);

		FreeMem(Buffer,TEXT_BUFFER_SIZE);
	}
}

VOID __saveds CPU_Stress_Code(VOID)
{
char	test1[WINDOWTEXT_SIZE];
char	test2[WINDOWTEXT_SIZE];

	for(;;)
	{
		strcpy(test1,WindowText);
		strcpy(test2,test1);
	}
}

VOID CreateCopper(struct MyWindow *MyWin)
{
register		SHORT		loop;
register		SHORT		colour;
register	struct	ViewPort	*vp;
register	struct	UCopList	*ucop;
register		ULONG		mask;

	vp=ViewPortAddress(MyWin->Window);
	colour=GetRGB4(vp->ColorMap,0);

	if (ucop=AllocMem(sizeof(struct UCopList),MEMF_PUBLIC|MEMF_CLEAR))
	{
		MyWin->DMAstress=ucop;
		CINIT(ucop,NUM_COP_INS+2);
		CWAIT(ucop,12,0);
		mask=0x04044004;
		for (loop=0;loop<NUM_COP_INS;loop++)
		{
			colour^=(0xFFF & mask);
			mask=(mask << 4) | (mask >> 28);
			CMOVE(ucop,custom.color[0],colour);
		}
		CEND(ucop);
		Forbid();
		vp->UCopIns=ucop;
		Permit();
		RethinkDisplay();
	}
}

VOID Stress_On(struct MyWindow *MyWin)
{
register	struct	Gadget	*gad;

	gad=MyWin->Window->FirstGadget;
	while (gad)
	{
		if (gad->Flags & SELECTED)
		{
			if (GADGET_DMA==gad->GadgetID)
			{
				CreateCopper(MyWin);
			}
			else if (GADGET_CPU==gad->GadgetID)
			{
				MyWin->CPUstress=CreateTask(CPUstressTask,0L,CPU_Stress_Code,1000L);
			}
		}
		gad=gad->NextGadget;
	}
}

VOID Stress_Off(struct MyWindow *MyWin)
{
	if (MyWin->CPUstress)
	{
		Forbid();	/* This is a work-around for a bug in EXEC... */
		RemTask(MyWin->CPUstress);	/* RemTask in 1.3 and earlier */
		Permit();	/* has a problem of reusing memory after free */
		MyWin->CPUstress=NULL;
	}
	if (MyWin->DMAstress)
	{
		FreeVPortCopLists(ViewPortAddress(MyWin->Window));
		RemakeDisplay();
		MyWin->DMAstress=NULL;
	}
}

VOID CloseMyWindow(struct MyWindow *MyWin)
{
	if (MyWin)
	{
		if (MyWin->Window)
		{
			if (MyWin->DragGadget) RemDragGadget(MyWin->DragGadget);
			if (MyWin->FrontBackGadget) RemFrontBackGadget(MyWin->FrontBackGadget);
			if (MyWin->CloseGadget) RemCloseGadget(MyWin->CloseGadget);
			CloseWindow(MyWin->Window);
		}
		FreeMem(MyWin,sizeof(struct MyWindow));
	}
}

struct MyWindow *OpenMyWindow(struct RenderInfo *ri)
{
register		SHORT		loop;
register	struct	MyWindow	*MyWin;
register	struct	Border		*MyBorder;
register	struct	IntuiText	*itext;
register	struct	Gadget		*gad;
		struct	NewWindow	nw;

	if (MyWin=AllocMem(sizeof(struct MyWindow),MEMF_PUBLIC|MEMF_CLEAR))
	{

/* First, set up the requester structures... */
		MyWin->Req.LeftEdge=7;
		MyWin->Req.TopEdge=19;
		MyWin->Req.Width=REQ_X_SIZE;
		MyWin->Req.Height=REQ_Y_SIZE;
		MyWin->Req.BackFill=ri->BackPen;
		MyWin->Req.ReqGadget=&(MyWin->ReqGadget);

		MyWin->ReqGadget.Width=REQ_X_SIZE;
		MyWin->ReqGadget.Height=REQ_Y_SIZE;
		MyWin->ReqGadget.Flags=GADGHIMAGE;
		MyWin->ReqGadget.Activation=RELVERIFY;
		MyWin->ReqGadget.GadgetType=BOOLGADGET|REQGADGET;
		MyWin->ReqGadget.GadgetRender=(APTR)&(MyWin->ReqBorders[0]);
		MyWin->ReqGadget.SelectRender=(APTR)&(MyWin->ReqBorders[2]);
		MyWin->ReqGadget.GadgetText=&(MyWin->ReqIText);
		MyWin->ReqGadget.GadgetID=GADGET_REQ;

		MyWin->ReqBorders[0].NextBorder=&(MyWin->ReqBorders[1]);
		MyWin->ReqBorders[2].NextBorder=&(MyWin->ReqBorders[3]);
		MyWin->ReqBorders[0].XY=MyWin->ReqBorders[2].XY=MyWin->ReqVector1;
		MyWin->ReqBorders[1].XY=MyWin->ReqBorders[3].XY=MyWin->ReqVector2;
		for (loop=0;loop<4;loop++)
		{
			MyWin->ReqBorders[loop].Count=8;
			MyWin->ReqBorders[loop].DrawMode=JAM1;
		}
		MyWin->ReqBorders[0].FrontPen=MyWin->ReqBorders[3].FrontPen=ri->Highlight;
		MyWin->ReqBorders[1].FrontPen=MyWin->ReqBorders[2].FrontPen=ri->Shadow;
		FillTopLeftDouble_Border(&(MyWin->ReqBorders[0]),REQ_X_SIZE,REQ_Y_SIZE);
		FillBottomRightDouble_Border(&(MyWin->ReqBorders[1]),REQ_X_SIZE,REQ_Y_SIZE);

		MyWin->ReqIText.FrontPen=ri->TextPen;
		MyWin->ReqIText.DrawMode=JAM1;
		MyWin->ReqIText.TopEdge=(REQ_Y_SIZE>>1)-8;
		MyWin->ReqIText.ITextFont=&TOPAZ80;

/* Now for the window gadgets... */
		gad=&(MyWin->Detail);
		gad->Flags=GADGHNONE;
		gad->GadgetType=BOOLGADGET;

		nw.LeftEdge=20;
		nw.TopEdge=11;
		nw.Width=WINDOW_WIDTH;
		nw.Height=WINDOW_HEIGHT;
		nw.DetailPen=-1;
		nw.BlockPen=-1;
		nw.IDCMPFlags=GADGETDOWN|GADGETUP|CLOSEWINDOW|ACTIVEWINDOW;
		nw.Flags=SIMPLE_REFRESH|BORDERLESS|ACTIVATE|NOCAREREFRESH|RMBTRAP;
		nw.FirstGadget=gad;
		nw.CheckMark=NULL;
		nw.Title=NULL;
		nw.Type=WBENCHSCREEN;

		MyBorder=NULL;
		for (loop=0;loop<(NUM_BOXES*2);loop++)
		{
			MyWin->Details[loop].Border.NextBorder=MyBorder;
			MyBorder=&(MyWin->Details[loop].Border);
			MyBorder->XY=MyWin->Details[loop].Vectors;
			MyBorder->FrontPen=ri->Highlight;
			MyBorder->DrawMode=JAM1;
			MyBorder->Count=5;
		}
		gad->GadgetRender=(APTR)MyBorder;

		for (loop=0;loop<NUM_BOXES;loop++)
		{
			MyWin->Details[loop*2].Border.LeftEdge=BoxTypes[loop].x1;
			MyWin->Details[loop*2].Border.TopEdge=BoxTypes[loop].y1;
			FillTopLeft_Border(&(MyWin->Details[loop*2].Border),
					BoxTypes[loop].x2-BoxTypes[loop].x1+1,
					BoxTypes[loop].y2-BoxTypes[loop].y1+1);
			if (BOX_IN==BoxTypes[loop].type) MyWin->Details[loop*2].Border.FrontPen=ri->Shadow;

			MyWin->Details[loop*2+1].Border.LeftEdge=BoxTypes[loop].x1;
			MyWin->Details[loop*2+1].Border.TopEdge=BoxTypes[loop].y1;
			FillBottomRight_Border(&(MyWin->Details[loop*2+1].Border),
					BoxTypes[loop].x2-BoxTypes[loop].x1+1,
					BoxTypes[loop].y2-BoxTypes[loop].y1+1);
			if (BOX_OUT==BoxTypes[loop].type) MyWin->Details[loop*2+1].Border.FrontPen=ri->Shadow;
		}

		itext=NULL;

		for (loop=NUM_RESULTS-1;loop>=0;loop--)
		{
			MyWin->MyResults[loop].IntuiText.NextText=itext;
			itext=&(MyWin->MyResults[loop].IntuiText);
			itext->FrontPen=ri->TextPen;
			itext->BackPen=ri->BackPen;
			itext->DrawMode=JAM2;
			itext->LeftEdge=ResultInfo[loop].x;
			itext->TopEdge=ResultInfo[loop].y;
			itext->ITextFont=&TOPAZ80;
			itext->IText=MyWin->MyResults[loop].text;
		}
		for (loop=0;loop<NUM_TEXT;loop++)
		{
			MyWin->TextDetails[loop].NextText=itext;
			itext=&(MyWin->TextDetails[loop]);
			itext->FrontPen=ri->TextPen;
			itext->DrawMode=JAM1;
			itext->LeftEdge=TextInfo[loop].x;
			itext->TopEdge=TextInfo[loop].y;
			itext->ITextFont=&TOPAZ80;
			itext->IText=TextInfo[loop].text;
		}
		gad->GadgetText=itext;

		for (loop=0;loop<NUM_GADGETS;loop++)
		{
			gad->NextGadget=&(MyWin->MyGadgets[loop].Gadget);
			gad=gad->NextGadget;

			gad->LeftEdge=GadgetInfo[loop].x;
			gad->TopEdge=GadgetInfo[loop].y;
			gad->Width=GadgetInfo[loop].size;
			gad->Height=14;
			gad->Flags=GADGHIMAGE;
			gad->Activation=GadgetInfo[loop].flags;
			gad->GadgetType=BOOLGADGET;
			gad->GadgetRender=(APTR)&(MyWin->MyGadgets[loop].Borders[0]);
			gad->SelectRender=(APTR)&(MyWin->MyGadgets[loop].Borders[2]);
			gad->GadgetText=&(MyWin->MyGadgets[loop].IntuiText);
			gad->GadgetID=GadgetInfo[loop].ID;
			if (GadgetInfo[loop].ID==GADGET_MED)
			{
				gad->Flags|=SELECTED;
				MyWin->TestFlag=GadgetInfo[loop].ID;
			}

			MyWin->MyGadgets[loop].Borders[0].NextBorder=&(MyWin->MyGadgets[loop].Borders[1]);
			MyWin->MyGadgets[loop].Borders[2].NextBorder=&(MyWin->MyGadgets[loop].Borders[3]);

			MyWin->MyGadgets[loop].Borders[0].DrawMode=JAM1;
			MyWin->MyGadgets[loop].Borders[1].DrawMode=JAM1;
			MyWin->MyGadgets[loop].Borders[2].DrawMode=JAM1;
			MyWin->MyGadgets[loop].Borders[3].DrawMode=JAM1;

			MyWin->MyGadgets[loop].Borders[0].FrontPen=ri->Highlight;
			MyWin->MyGadgets[loop].Borders[1].FrontPen=ri->Shadow;
			MyWin->MyGadgets[loop].Borders[2].FrontPen=ri->Shadow;
			MyWin->MyGadgets[loop].Borders[3].FrontPen=ri->Highlight;

			MyWin->MyGadgets[loop].Borders[0].XY=MyWin->MyGadgets[loop].Vectors1;
			MyWin->MyGadgets[loop].Borders[1].XY=MyWin->MyGadgets[loop].Vectors2;
			MyWin->MyGadgets[loop].Borders[2].XY=MyWin->MyGadgets[loop].Vectors1;
			MyWin->MyGadgets[loop].Borders[3].XY=MyWin->MyGadgets[loop].Vectors2;

			MyWin->MyGadgets[loop].Borders[0].Count=8;
			MyWin->MyGadgets[loop].Borders[1].Count=8;
			MyWin->MyGadgets[loop].Borders[2].Count=8;
			MyWin->MyGadgets[loop].Borders[3].Count=8;

			FillTopLeftDouble_Border(&(MyWin->MyGadgets[loop].Borders[0]),GadgetInfo[loop].size,14);
			FillBottomRightDouble_Border(&(MyWin->MyGadgets[loop].Borders[1]),GadgetInfo[loop].size,14);

			MyWin->MyGadgets[loop].IntuiText.TopEdge=3;
			MyWin->MyGadgets[loop].IntuiText.FrontPen=ri->TextPen;
			MyWin->MyGadgets[loop].IntuiText.DrawMode=JAM1;
			MyWin->MyGadgets[loop].IntuiText.ITextFont=&TOPAZ80;
			MyWin->MyGadgets[loop].IntuiText.IText=GadgetInfo[loop].text;
			MyWin->MyGadgets[loop].IntuiText.LeftEdge=
				(GadgetInfo[loop].size-IntuiTextLength(&(MyWin->MyGadgets[loop].IntuiText))) >> 1;
		}

		gad->NextGadget=&(MyWin->DeviceGadget);
		gad=gad->NextGadget;
		gad->LeftEdge=72;
		gad->TopEdge=22;
		gad->Width=176;
		gad->Height=9;
		gad->Activation=RELVERIFY;
		gad->GadgetType=STRGADGET;
		gad->SpecialInfo=(APTR)&(MyWin->DeviceGadgetInfo);
		gad->GadgetID=GADGET_STRING;
		gad->UserData=(APTR)&(MyWin->CommentGadget);
		MyWin->DeviceGadgetInfo.Buffer=MyWin->DeviceName;
		MyWin->DeviceGadgetInfo.MaxChars=32;

		gad->NextGadget=&(MyWin->CommentGadget);
		gad=gad->NextGadget;
		gad->LeftEdge=72;
		gad->TopEdge=39;
		gad->Width=451;
		gad->Height=9;
		gad->Activation=RELVERIFY;
		gad->GadgetType=STRGADGET;
		gad->SpecialInfo=(APTR)&(MyWin->CommentGadgetInfo);
		gad->GadgetID=GADGET_STRING;
		gad->UserData=(APTR)&(MyWin->DeviceGadget);
		MyWin->CommentGadgetInfo.Buffer=MyWin->Comment;
		MyWin->CommentGadgetInfo.MaxChars=80;

		gad->NextGadget=&(MyWin->Background);
		gad=gad->NextGadget;
		gad->Flags=GADGHNONE|GADGIMAGE;
		gad->GadgetType=BOOLGADGET;
		gad->GadgetRender=(APTR)&(MyWin->Image_Background);
		MyWin->Image_Background.Width=WINDOW_WIDTH;
		MyWin->Image_Background.Height=WINDOW_HEIGHT;
		MyWin->Image_Background.PlaneOnOff=ri->BackPen;

		loop=FALSE;
		if (MyWin->Window=OpenWindow(&nw))
		 if (MyWin->CloseGadget=AddCloseGadget(MyWin->Window,ri,7,3))
		  if (MyWin->FrontBackGadget=AddFrontBackGadget(MyWin->Window,ri,473,3))
		   if (MyWin->DragGadget=AddDragGadget(MyWin->Window,ri,DiskSpeedTitle,33,3,438))
		   {
			loop=TRUE;
		   }

		if (!loop)
		{
			CloseMyWindow(MyWin);
			MyWin=NULL;
		}
		else SetWindowTitles(MyWin->Window,(UBYTE *)-1L,WindowText);
	}
	return(MyWin);
}
