/****** cdpanel_gc/--datasheet-- ******************************************

   NAME
	   cdpanel.gadget -- CD front panel

   SUPERCLASS
	   gadgetclass

   DESCRIPTION

   METHODS
	   GM_DOMAIN
	   GM_RENDER
	   GM_HITTEST
	   GM_GOACTIVE
	   GM_GOINACTIVE
	   OM_SET
	   OM_UPDATE
	   OM_GET
	   OM_NEW
	   OM_DISPOSE

	   All other methods are passed to the superclass.

   ATTRIBUTES

   NOTES

   SEE ALSO

******************************************************************************

*/

#include "sysheaders.h"
#include "classdata.h"
#include "cdpanel.h"

static ULONG new_method( Class *cl, Object *o, struct opSet *ops);
static ULONG dispose_method( Class *cl, Object *o, Msg msg);
static ULONG set_method( Class *cl, Object *o, struct opSet *ops);
static ULONG get_method( Class *cl, Object *o, struct opGet *opg);
static ULONG render_method( Class *cl, Object *o, struct gpRender *gpr);
static ULONG domain_method( Class *cl, Object *o, struct gpDomain *gpd);

/* handy macro for handling tag data */
#define SETTAGARG(tag, id, data)	{ tag.ti_Tag = (ULONG)(id);\
					  tag.ti_Data = (ULONG)(data); }

/* prototype for external function from 'gadgetbox.asm' */
extern __stdargs void SetupGadgetIBox(
									 struct Gadget *gadget,
									 struct IBox *domain,
									 struct IBox *box);
										 
/* prototype for LayoutClass */
static ULONG __saveds __asm CDPanelDispatch(
											register __a0 Class * class,
											register __a2 Object * object,
											register __a1 Msg message);

void Sprintf(char *, const char *, ...);

#ifdef __SASC
#pragma msg 181 ign push
static struct ClassLibrary *BevelBase;
#pragma msg 181 pop
#else
static struct ClassLibrary *BevelBase;
#endif

ULONG
SendNotify(Object * o, struct GadgetInfo *gi, ULONG flags, Tag t,...)
{
	return DoMethod(o, OM_NOTIFY, &t, gi, flags);
}

static ULONG __asm /* no __saveds necessary, this is called through the dispatcher anyway */
tagset(
		  register __a0 Class * cl,
		  register __a2 Object * o,
		  register __a1 struct opSet *ops)
{
	struct CDPanelData *sd = INST_DATA(cl, o);
	register ULONG tidata;
	register BOOL ours;
	BOOL refresh = FALSE;
	struct TagItem *tag;
	struct TagItem *tstate = ops->ops_AttrList;

	if (sd)
	{
		while (tag = NextTagItem(&tstate))
		{
			tidata = tag->ti_Data;
			ours = TRUE;

			switch (tag->ti_Tag)
			{
				case CDPANEL_Artist:
					sd->gad_Data[Artist] = tidata;
					sd->gad_Old[Artist] = ~0;
					break;
					
				case CDPANEL_Title:
					sd->gad_Data[Title] = tidata;
					sd->gad_Old[Title] = ~0;
					break;
					
				case CDPANEL_TrackTitles:
					sd->gad_TrackTitles = (STRPTR *)tidata;
					break;
					
				case CDPANEL_TotalTime:
					sd->gad_Data[TotalTime] = tidata;
					sd->gad_Old[TotalTime] = ~0;
					break;
					
				case CDPANEL_Time:
					sd->gad_Data[Time] = tidata;
					sd->gad_Old[Time] = ~0;
					break;
					
				case CDPANEL_Tracks:
					sd->gad_Data[Tracks] = tidata;
					sd->gad_Old[Tracks] = ~0;
					break;
					
				case CDPANEL_TrackTimes:
					sd->gad_TrackTimes = (ULONG *)tidata;
					break;
					
				case CDPANEL_Track:
					sd->gad_Old[Track] = sd->gad_Data[Track];
					sd->gad_Data[Track] = tidata;
					break;
					
				case CDPANEL_TrackTime:
					sd->gad_Data[TrackTime] = tidata;
					sd->gad_Old[TrackTime] = ~0;
					break;
					
				case CDPANEL_Status:
					if (tidata == CDP_EMPTY || tidata == CDP_EJECTED)
					{
						memset(sd->gad_Data, 0, sizeof(sd->gad_Data));
						memset(sd->gad_Graph, sd->gad_BgPen, 320);
					}
					else
					if (tidata == CDP_STOPPED && sd->gad_Data[Status] != tidata)
					{
						sd->gad_Data[Track] = 0;
						sd->gad_Data[TrackTime] = 0;
						sd->gad_Data[Time] = 0;
						memset(sd->gad_Graph, sd->gad_BgPen, 320);
					}
					sd->gad_Data[Status] = tidata;
				//	sd->gad_Old[Status] = ~0;
					break;
					
				case CDPANEL_BgPen:
					sd->gad_BgPen = (WORD)tidata;
					break;
					
				case CDPANEL_FgPen:
					sd->gad_FgPen = (WORD)tidata;
					break;
					
				case CDPANEL_NoBorder:
					sd->gad_NoBorder = (BOOL)tidata;
					SetAttrs( sd->gad_BevelFrame, BEVEL_Style, sd->gad_NoBorder ? BVS_NONE : BVS_BUTTON, TAG_END );
					break;
					
				case GA_TextAttr:
					if (sd->gad_Font)
						CloseFont(sd->gad_Font);
					sd->gad_Font = OpenFont((struct TextAttr *)tidata);
					break;
					
				default:
					ours = FALSE;
					break;
			}
			if (ours)
				refresh = TRUE;
		}
		
		if (ops->ops_GInfo && refresh && AttemptLockLayerRom( ops->ops_GInfo->gi_Window->WLayer ) )
		{
			struct RastPort *rp;
			
			UnlockLayerRom( ops->ops_GInfo->gi_Window->WLayer );
	
			if (rp = ObtainGIRPort(ops->ops_GInfo))
			{
				DoMethod(o, GM_RENDER, ops->ops_GInfo, rp, GREDRAW_UPDATE);
				ReleaseGIRPort(rp);
				refresh = FALSE;
			}
		}
	}
	return refresh;
}

static void MyFreeBitMap( struct BitMap *bm )
{
	if (!bm)
		return;

	if (GfxBase->LibNode.lib_Version >= 39)
	{
		FreeBitMap( bm );
	}
	else
	{
		if (bm->Planes[0])
			FreeRaster( bm->Planes[0], bm->BytesPerRow<<3, bm->Rows * bm->Depth );
		FreeMem( bm, sizeof(struct BitMap) );
	}
}

static struct BitMap *MyAllocBitMap( UWORD w, UWORD h, UBYTE d, ULONG f, struct BitMap *fr )
{
	if (GfxBase->LibNode.lib_Version >= 39)
	{
		return AllocBitMap( w, h, d, f, fr );
	}
	else
	{
		ULONG s = (((w+15)>>4)<<4);
		UBYTE *r;
		struct BitMap *bm = AllocMem( sizeof(struct BitMap), MEMF_PUBLIC );
		if (!bm)
			return NULL;
		if (r = AllocRaster(s, h*d))
		{
			UBYTE p;
			bm->BytesPerRow = s>>3;
			bm->Rows = h;
			bm->Depth = d;
			bm->Flags = f;
			if (!(f & BMF_INTERLEAVED))
				s *= h;
			for (p = 0; p < d; p++)
			{
				bm->Planes[p] = r;
				r += s;
			}
			return bm;
		}
		bm->Planes[0] = NULL;
		MyFreeBitMap(bm);
		return NULL;
	}
}

static ULONG
new_method(
			  Class * cl,
			  Object * o,
			  struct opSet *ops)
{
	struct CDPanelData *sd;
	Object *object;

	object = (Object *) DoSuperMethodA(cl, o, (Msg) ops);
	if (object)
	{
		sd = INST_DATA(cl, object);

		if (sd->gad_Graph = AllocVec( 640, MEMF_CHIP ))
		{
			sd->gad_BgPen = 1;
			sd->gad_FgPen = ~0;

			memset(sd->gad_Graph, sd->gad_BgPen, 320);

			tagset(cl, object, ops);
		
			if (!sd->gad_Font)
				sd->gad_Font = GfxBase->DefaultFont;

			if (sd->gad_BevelFrame = NewObject( BEVEL_GetClass(), NULL, BEVEL_Style, sd->gad_NoBorder ? BVS_NONE : BVS_BUTTON, TAG_END ))
			{
				return ((ULONG)object);
			}
		}
		CoerceMethod(cl, object, OM_DISPOSE);
	}
	return (0L);
}

static ULONG
dispose_method(
				  Class * cl,
				  Object * o,
				  Msg message)
{
	struct CDPanelData *sd = INST_DATA(cl, o);

	if (sd->gad_Font != GfxBase->DefaultFont)
		CloseFont( sd->gad_Font );
		
	DisposeObject(sd->gad_BevelFrame);
	
	if (sd->gad_Graph)
		FreeVec(sd->gad_Graph);
		
	MyFreeBitMap(sd->gad_TempBitMap);

	return DoSuperMethodA(cl, o, message);
}

static ULONG
set_method(
			  Class * cl,
			  Object * o,
			  struct opSet *ops)
{
	register struct TagItem *tstate = ops->ops_AttrList;

	if (tstate)
		tagset(cl, o, ops);

	DoSuperMethodA(cl, o, (Msg) ops);
	return 0;
}

static ULONG
get_method(
			  Class * cl,
			  Object * o,
			  struct opGet *opg)
{
	ULONG retval = TRUE;
	struct CDPanelData *sd = INST_DATA(cl, o);
	
	switch (opg->opg_AttrID)
	 {
	 case CDPANEL_Status:
	 	*opg->opg_Storage = sd->gad_Data[Status];
	 	break;
	 
	 case CDPANEL_Track:
	 	*opg->opg_Storage = sd->gad_Data[Track];
	 	break;
	 	
	 default:
		 retval = DoSuperMethodA(cl, o, (Msg) opg);
		 break;
	 }
	return (retval);
}

static ULONG
domain_method(
				 Class * cl,
				 Object * o,
				 struct gpDomain *gpd)
{
	struct CDPanelData *sd = INST_DATA(cl, o);
	ULONG t;
	
	/* GM_DOMAIN is a V42 method for asking a gadget how much space it
	 * needs/prefers.
	 * This is a fixed size gadget, so we'll always return the same thing.
	 */

	gpd->gpd_Domain.Left = gpd->gpd_Domain.Top = 0;
	gpd->gpd_Domain.Width = 26 * (sd->gad_Font->tf_XSize) + 2*(2 + 1);
	gpd->gpd_Domain.Height = 3 * (sd->gad_Font->tf_YSize + 1) + 8 + 2*(2 + 1);

//	if (!sd->gad_NoBorder)
//	{
		SetAttrs( sd->gad_BevelFrame, 
					IA_Width, gpd->gpd_Domain.Width, 
					IA_Height, gpd->gpd_Domain.Height,
					TAG_END );
		
		GetAttr( BEVEL_InnerWidth, sd->gad_BevelFrame, &t );
		gpd->gpd_Domain.Width += gpd->gpd_Domain.Width - t;
		GetAttr( BEVEL_InnerHeight, sd->gad_BevelFrame, &t );
		gpd->gpd_Domain.Height += gpd->gpd_Domain.Height - t;
//	}
	
	return (0);
}

UBYTE IconPlaying[8] =	{ 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x00 };
UBYTE IconStopped[8] =	{ 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00 };
UBYTE IconEjected[8] =	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
UBYTE IconPaused[8]  =	{ 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00 };
UBYTE IconEmpty[8]   =	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
UBYTE IconSeeking[8] =	{ 0x38, 0x38, 0x38, 0xfe, 0x7c, 0x38, 0x10, 0x00 };

static void
DrawStatusIcon( struct RastPort *rp, UBYTE *icon, UWORD x, UWORD y )
{
	UWORD i,j;
	
	for (j = 0 ; j < 8 ; j++)
	{
		for (i = 0 ; i < 8 ; i++)
		{
			if (icon[j] & (1 << i))
				WritePixel( rp, x+7-i, y+j);
		}
	}
}

static ULONG
render_method(
				 Class * cl,
				 Object * o,
				 struct gpRender *gpr)
{
	struct CDPanelData *sd = INST_DATA(cl, o);
	struct RastPort rpfg = *gpr->gpr_RPort, rpbg = *gpr->gpr_RPort;
	UBYTE line[6];
	ULONG X, Y;
	ULONG *data = sd->gad_Data, *old = sd->gad_Old;
	ULONG baseline = sd->gad_Font->tf_Baseline;

	SetAPen( &rpbg, sd->gad_BgPen );
	SetDrMd( &rpbg, JAM2 );
	
	if (gpr->gpr_Redraw == GREDRAW_REDRAW)
	{
		ULONG W, H;
//		struct impDraw id;

		SetupGadgetIBox((struct Gadget *) o, &gpr->gpr_GInfo->gi_Domain, &sd->gad_Container);

		if (!sd->gad_NoBorder)
		{
#if 0
			id.MethodID = IM_DRAWFRAME;
			id.imp_RPort = &rpfg;
			id.imp_Offset.X = sd->gad_Container.Left;
			id.imp_Offset.Y = sd->gad_Container.Top;
			id.imp_State = IDS_SELECTED;
			id.imp_DrInfo = gpr->gpr_GInfo->gi_DrInfo;
			id.imp_Dimensions.Width = sd->gad_Container.Width;
			id.imp_Dimensions.Height = sd->gad_Container.Height;
			DoMethodA( sd->gad_BevelFrame, (Msg)&id );
#else
			SetAttrs( sd->gad_BevelFrame, 
					IA_Left, 0, IA_Top, 0,
					IA_Width, sd->gad_Container.Width, IA_Height, sd->gad_Container.Height,
					TAG_END );
			DrawImageState( &rpfg, (struct Image *)sd->gad_BevelFrame, sd->gad_Container.Left, sd->gad_Container.Top, IDS_SELECTED, gpr->gpr_GInfo->gi_DrInfo );
#endif
			
			GetAttr( BEVEL_InnerLeft, sd->gad_BevelFrame, &X );
			GetAttr( BEVEL_InnerTop, sd->gad_BevelFrame, &Y );
			GetAttr( BEVEL_InnerWidth, sd->gad_BevelFrame, &W );
			GetAttr( BEVEL_InnerHeight, sd->gad_BevelFrame, &H );
		}
		else
		{
			X = 0;
			Y = 0;
			W = sd->gad_Container.Width;
			H = sd->gad_Container.Height;
		}
		
		X += sd->gad_Container.Left + 1;
		Y += sd->gad_Container.Top + 1;
		W -= 2;
		H -= 2;
		RectFill( &rpbg, X, Y, X + W - 1, Y + H - 1 );

		sd->gad_GraphLen = W - 13;
		
		if (sd->gad_GraphLen > 320)
			sd->gad_GraphLen = 320;
		
		MyFreeBitMap( sd->gad_TempBitMap );
		sd->gad_TempBitMap = MyAllocBitMap( sd->gad_GraphLen, 1, 8, 0, NULL );

		memset(old, ~0, DATA_MAX * sizeof(ULONG));
	}
	else
	{
//		if (sd->gad_NoBorder)
//		{
//			X = Y = 0;
//		}
//		else
//		{
			GetAttr( BEVEL_InnerLeft, sd->gad_BevelFrame, &X );
			GetAttr( BEVEL_InnerTop, sd->gad_BevelFrame, &Y );
//		}
		
		X += sd->gad_Container.Left + 1;
		Y += sd->gad_Container.Top + 1;
	}
	
	SetAPen( &rpfg, sd->gad_FgPen );
	SetBPen( &rpfg, sd->gad_BgPen );
	SetDrMd( &rpfg, JAM2 );
	SetFont( &rpfg, sd->gad_Font );
	
	X += 2;
	Y += 2;
	
	if (data[Track] != old[Track] || data[Tracks] != old[Tracks])
	{
		/* track count */
		Sprintf( line, "%02.2ld", data[Status] == CDP_STOPPED ? data[Tracks] : data[Track] );
		Move( &rpfg, X, Y + baseline );
		RectFill( &rpbg, X, Y, X + 2 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, line, 2 /* constant length string */ );
	}
	
	if (data[TrackTime] != old[TrackTime])
	{
		/* playing time on this track */
		Sprintf( line, "%02.2ld:%02.2ld", data[TrackTime]/60, data[TrackTime]%60 );
		Move( &rpfg, X + 3 * (sd->gad_Font->tf_XSize), Y + baseline );
		RectFill( &rpbg, X + 3 * (sd->gad_Font->tf_XSize), Y, X + 8 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, line, 5 /* constant length string */ );
	}
	
	if (data[Time] != old[Time])
	{
		ULONG time = data[TrackTime];
		
		if (sd->gad_TrackTimes && data[Track])
			time = sd->gad_TrackTimes[data[Track]] - data[Time];
		
		/* remaining time on this track */
		Sprintf( line, "%02.2ld:%02.2ld", time/60, time%60 );
		Move( &rpfg, X + 9 * (sd->gad_Font->tf_XSize), Y + baseline );
		RectFill( &rpbg, X + 9 * (sd->gad_Font->tf_XSize), Y, X + 14 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, line, 5 /* constant length string */ );

		/* playing time from the start of the CD */
		Sprintf( line, "%02.2ld:%02.2ld", data[Time]/60, data[Time]%60 );
		Move( &rpfg, X + 15 * (sd->gad_Font->tf_XSize), Y + baseline );
		RectFill( &rpbg, X + 15 * (sd->gad_Font->tf_XSize), Y, X + 20 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, line, 5 /* constant length string */ );
	}
	
	if (data[TotalTime] != old[TotalTime])
	{
		/* total length of the CD */
		Sprintf( line, "%02.2ld:%02.2ld", data[TotalTime]/60, data[TotalTime]%60 );
		Move( &rpfg, X + 21 * (sd->gad_Font->tf_XSize), Y + baseline );
		RectFill( &rpbg, X + 21 * (sd->gad_Font->tf_XSize), Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, line, 5 /* constant length string */ );
	}
	
	Y += sd->gad_Font->tf_YSize + 1;
	if (data[Artist] != old[Artist])
	{
		/* show artist name */
		ULONG len;
		if (!data[Artist])
			data[Artist] = (ULONG)"CompactPlayer";
		len = strlen((STRPTR)data[Artist]);
		Move( &rpfg, X, Y + baseline );
		RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, (STRPTR)data[Artist], len > 26 ? 26 : len );
	}
	
	/* title */
	Y += sd->gad_Font->tf_YSize + 1;
	if (sd->gad_TrackTitles && data[Track] && data[Track] != old[Track])
	{
		/* show track title */
		ULONG len = strlen(sd->gad_TrackTitles[data[Track]-1]);
		Move( &rpfg, X, Y + baseline );
		RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, sd->gad_TrackTitles[data[Track]-1], len > 26 ? 26 : len );
	}
	else
	if (data[Title] != old[Title] || data[Track] != old[Track])
	{	
		/* show disc title */
		ULONG len;
		if (!data[Title])
			data[Title] = (ULONG)"By Osma Ahvenlampi";
		len = strlen((STRPTR)data[Title]);
		Move( &rpfg, X, Y + baseline );
		RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
		Text( &rpfg, (STRPTR)data[Title], len > 26 ? 26 : len );
	}

	/* track graph */
	Y += sd->gad_Font->tf_YSize + 1;
	
	if (data[Tracks] != old[Tracks])
	{
		ULONG x = X + /*sd->gad_GraphLen*/ data[TotalTime] * sd->gad_GraphLen / (80*60);
		/* draw the disc time line */
		RectFill( &rpbg, X, Y, X + sd->gad_GraphLen, Y + 6 );
		Move( &rpfg, X, Y + 3 );
		Draw( &rpfg, X, Y + 6 );
		Move( &rpfg, X, Y + 5 );
		Draw( &rpfg, x, Y + 5 );
		Move( &rpfg, x, Y + 3 );
		Draw( &rpfg, x, Y + 6 );
	
		if (sd->gad_TrackTimes)
		{
			/* mark the track limits */
			ULONG i = 0;
			while (i < data[Tracks])
			{	
				x = X + sd->gad_TrackTimes[i++] * sd->gad_GraphLen / (80*60) /*data[TotalTime]*/;
				Move( &rpfg, x, Y + 4 );
				Draw( &rpfg, x, Y + 6 );
			}
		}
	}

	if (data[Status] != old[Status])
	{
		/* draw the icon */
		ULONG x = X + sd->gad_GraphLen + 1;
		UBYTE *i;
		RectFill( &rpbg, x, Y, x + 7, Y + 7 );
		
		switch (data[Status])
		{
		case CDP_EMPTY:
			i = IconEmpty;
			break;
		case CDP_PLAYING:
			i = IconPlaying;
			break;
		case CDP_PAUSED:
			i = IconPaused;
			break;
		case CDP_STOPPED:
			i = IconStopped;
			break;
		case CDP_SEEKING:
			i = IconSeeking;
			break;
		case CDP_EJECTED:
			i = IconEjected;
			break;
		}
		DrawStatusIcon( &rpfg, i, x, Y );
	}
	
	if (data[Time] != old[Time] && sd->gad_TempBitMap)
	{
		/* draw the line at current track position */
		ULONG x = data[Time] * sd->gad_GraphLen / (80*60)/*data[TotalTime]*/;
		struct RastPort rp = rpfg;
		
		rp.Layer = NULL;
		rp.BitMap = sd->gad_TempBitMap;

		if (data[Status] == CDP_PLAYING || data[Status] == CDP_SEEKING)
		{
			if (data[Track] != old[Track] || data[Time] < old[Time])
				memset(sd->gad_Graph + x, sd->gad_BgPen, sd->gad_TrackTimes[data[Track]] * sd->gad_GraphLen / (80*60) - x);

			sd->gad_Graph[x&0xfffe] = sd->gad_FgPen;
		}
		
		memcpy(sd->gad_Graph + 320, sd->gad_Graph, 320);
		WritePixelLine8(&rpfg, X, Y+2, sd->gad_GraphLen, sd->gad_Graph, &rp);
		memcpy(sd->gad_Graph, sd->gad_Graph + 320, 320);
	}
	
	memcpy(old, data, DATA_MAX * sizeof(ULONG));
	
	return (0);
}

static ULONG __saveds __asm
CDPanelDispatch(
						register __a0 Class * cl,
						register __a2 Object * o,
						register __a1 Msg message)
{
	ULONG retval;
	
	switch (message->MethodID)
	 {
	 case GM_DOMAIN:
		 retval = domain_method(cl, o, (struct gpDomain *) message);
		 break;

	 case GM_RENDER:
		 retval = render_method(cl, o, (struct gpRender *) message);
		 break;

	 case GM_HITTEST:
		 retval = 0;
		 break;

	 case GM_HANDLEINPUT:
	 case GM_GOINACTIVE:
	 case GM_GOACTIVE:
		 retval = GMR_NOREUSE;
		 break;

	 case OM_SET:
	 case OM_UPDATE:
		 retval = set_method(cl, o, (struct opSet *) message);
		 break;

	 case OM_NEW:
		 retval = new_method(cl, o, (struct opSet *) message);
		 break;

	 case OM_DISPOSE:
		 retval = dispose_method(cl, o, message);
		 break;

	 case OM_GET:
		 retval = get_method(cl, o, (struct opGet *) message);
		 break;
		 
	 default:
		 retval = DoSuperMethodA(cl, o, message);
		 break;
	 }

	return (retval);
}

/* function to create/initialize our CLASS */
Class *
CreateCDPanelClass(void)
{
	Class *cl;

	if (cl = MakeClass( NULL, "gadgetclass", NULL, sizeof(struct CDPanelData), 0))
	{
		cl->cl_Dispatcher.h_Entry = (unsigned long (*)())CDPanelDispatch;
		cl->cl_Dispatcher.h_SubEntry = NULL;

		BevelBase = (struct ClassLibrary *) OpenLibrary("images/bevel.image", 0L);
		if (BevelBase)
		{
			return (cl);
		}
		FreeClass( cl );
	}
	return (0);
}

void
DestroyCDPanelClass(struct Class * cl)
{
	if (BevelBase)
	{
		CloseLibrary((struct Library *)BevelBase);
		BevelBase = NULL;
	}
	if (cl)
	{
		FreeClass((struct IClass *)cl);
	}
}

