/*======== Example Source-Code for an external Icon-Renderer =========

   (C) Copyright 1997 by Georg Steger.
   
       Created with MaxonCPP 4.0 Pro


Description:
ŻŻŻŻŻŻŻŻŻŻŻŻ
The Icons will get the standard Amiga Look


====================================================================*/


/* OS-Includes */

#include <OSIncludes.h>

#pragma header

/* Compiler-Includes */

#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/exec_lib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* Program-Includes */

#include "/PWDevelopper.h"

#define IMTYP_CLOSE 1
#define IMTYP_DEPTH 2

#define ID_Size sizeof(IconData)
#define NUM_Col (sizeof(ColData)/3)


#define ARG_TEMPLATE "FONTNAME=F/K,FONTSIZE=FS/K/N,FONTSTYLE/K/N,FONTYOFFSET=FY/K/N,FONTXOFFSET=FX/K/N,TITLEGAP=TG/K/N,BACKCOL=BC/K,TITLECOL=TC/K,GADGETSGREY=GG/S,BACKGROUNDGREY=BG/S,CENTERTITLE=CT/S,P=PRECISION/K/N"

enum {ARG_FONTNAME,
	   ARG_FONTSIZE,
	   ARG_FONTSTYLE,
	   ARG_FONTYOFFSET,
	   ARG_FONTXOFFSET,
//	   ARG_DEPTHLOOK,
//	   ARG_MINBARWIDTH,
//	   ARG_GADGETGAP,
	   ARG_TITLEGAP,
	   ARG_BACKCOL,
	   ARG_TITLECOL,
	   ARG_GADGETSGREY,
	   ARG_BACKGROUNDGREY,
	   ARG_CENTERTITLE,
	   ARG_PRECISION,
	   NUM_ARGS};


/* Vars */

extern ULONG HookEntry();

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct UtilityBase *UtilityBase;
struct Library *DiskfontBase;
extern struct Library *DOSBase;

static struct Window *IconWin;
static struct RastPort *rp;
static struct DrawInfo *di;
static struct Gadget *gad,*CloseGad,*DepthGad;
static struct IClass *MyImageClass;
static struct Image *im;
static struct SignalSemaphore MemSem;
static struct RDArgs *MyArgs;
static struct TextFont *MyFont;
static struct TextExtent MyTE;
static struct TextAttr MyTextAttr;

static STRPTR title;
static ULONG  l;
static WORD   a,b,c,d,slen,x1,y1,x2,y2;
static WORD	  FontYSize=13,FontXOffset=0,FontYOffset=0,FontStyle=0;
static WORD	  TitleGap=5;
static BOOL	  GadgetsGrey,BackgroundGrey;
static BOOL	  DoCustomBack,DoCustomTitle;
static BOOL	  CenterTitle;

static char	  s[257];
LONG	 *Args[NUM_ARGS];

static WORD	  Precision=PRECISION_EXACT;
static WORD	  DepthTyp=0;

static WORD	  ImageCounter;

APTR	 		  MemPool;

/* GRAUTOENE */

#define COL_BACK 0
#define COL_TITLE 1
#define COL_SELFRAME 2

UBYTE ColData[][3] =
{
	{  0,  0,  0},			// Background
	{  0,  0,  0},			// Bars dark
	{255,  0,  0}		// selected frame
};


struct IconData
{
	struct Window *iwin;
	struct Window *ParentWindow;
	struct ColorMap *cm;
	struct DrawInfo *di;
	WORD BarXStart,BarXEnd;
	WORD Grey[NUM_Col][2];
};

struct MyImageData
{
	WORD typ;
	Object *image;
	struct IconData *id;
};

static void CleanUp(void)
{
	if (MyImageClass) FreeClass(MyImageClass);
	if (MyFont) CloseFont(MyFont);

	if (MemPool) DeletePool(MemPool);
	if (GfxBase) CloseLibrary((struct Library *)GfxBase);
	if (IntuitionBase)
	{
		if (ImageCounter)
		{
			DisplayBeep(IntuitionBase->ActiveScreen);
		}
		CloseLibrary((struct Library *)IntuitionBase);
	}
	if (UtilityBase) CloseLibrary((struct Library *)UtilityBase);
	if (DiskfontBase) CloseLibrary(DiskfontBase);
	if (DOSBase) CloseLibrary(DOSBase);

}

static void RefreshIFrame(ULONG method,struct Window *win, struct RastPort *rp, struct IconData *id)
{
	struct DrawInfo *dri;

	if ((dri=GetScreenDrawInfo(win->WScreen)))
	{
		SetAPen(rp,method == RI_RENDERFRAME ? dri->dri_Pens[SHINEPEN] : id->Grey[COL_SELFRAME][0]);
	
		RectFill(rp,0,0,0,win->Height-1);
		RectFill(rp,1,0,win->Width-1,0);

		if (method == RI_RENDERFRAME) SetAPen(rp,dri->dri_Pens[SHADOWPEN]);

		RectFill(rp,win->Width-1,1,win->Width-1,win->Height-1);
		RectFill(rp,1,win->Height-1,win->Width-1,win->Height-1);

		FreeScreenDrawInfo(win->WScreen,dri);
	}
}

static void RefreshITitle(struct riRefreshITitle *msg)
{
	struct IconData *id;
	struct DrawInfo *di;
	struct Window *IconWin;
	struct RastPort *rp;
	struct TextExtent MyTE;
	STRPTR title;

	WORD a,b,c,x1,x2;

	id=msg->UserData;
	IconWin=msg->Icon;
	rp=IconWin->RPort;

	x1=id->BarXStart;
	x2=id->BarXEnd;
	
	if ((di=id->di))
	{
		if (DoCustomBack)
		{
			SetAPen(rp,id->Grey[COL_BACK][0]);
		} else {
			SetAPen(rp,di->dri_Pens[BackgroundGrey ? BACKGROUNDPEN : FILLPEN]);
		}
		RectFill(rp,x1,1,x2,IconWin->Height-2);

		title=id->ParentWindow->Title;
		
		a=TextFit(rp,title,strlen(title),&MyTE,0,1,(x2-x1)+1,IconWin->Height);
		while (a && (title[a-1]==' ')) a--;
	
		b=rp->TxBaseline+2;

		if (CenterTitle)
		{
			c=(x1+x2-TextLength(rp,title,a))/2;
		} else {
			c=x1;
		}
		
		Move(rp,c+FontXOffset,b+FontYOffset);
		if (DoCustomTitle)
		{
			SetABPenDrMd(rp,id->Grey[COL_TITLE][0],0,JAM1);
		} else {
			SetABPenDrMd(rp,di->dri_Pens[FILLTEXTPEN],0,JAM1);
		}
		Text(rp,title,a);
	}
}

static LONG MyImageDispatcher(struct IClass *cl,struct Image *im,Msg msg)
{
	struct MyImageData *data;
	struct TagItem *ti;
	struct RastPort *rp;
	ULONG x2,y2;
	WORD x1,y1;
	LONG rc;

	switch(msg->MethodID)
	{
		case OM_NEW:
			rc=0;
			if ((im=(struct Image *)DoSuperMethodA(cl,(Object *)im,msg)))
			{
				ImageCounter++;

				data=INST_DATA(cl,im);
				memset(data,0,sizeof(struct MyImageData));

				if ((ti=FindTagItem(IA_FGPen,((struct opSet *)msg)->ops_AttrList)))
				{
					data->typ=ti->ti_Data;
					ti->ti_Tag=TAG_IGNORE;
				}
				if ((ti=FindTagItem(GA_UserData,((struct opSet *)msg)->ops_AttrList)))
				{
					ti->ti_Tag=TAG_IGNORE;
					data->id=(struct IconData *)ti->ti_Data;
				}
				
				if (!(data->image=NewObject(0,"sysiclass",
													 SYSIA_DrawInfo,data->id->di,
													 SYSIA_Which,data->typ,
													 IA_Height,GetTagData(IA_Height,11,((struct opSet *)msg)->ops_AttrList),
													 TAG_DONE)))
				{
					CoerceMethod(cl,(Object *)im,OM_DISPOSE);
				} else {
					GetAttr(IA_Width,data->image,&x2);
					GetAttr(IA_Height,data->image,&y2);
					SetAttrs(im,IA_Width,x2,
									IA_Height,y2,
									TAG_DONE);

					GetAttr(IA_Left,data->image,&x2);
					GetAttr(IA_Top,data->image,&y2);
					SetAttrs(im,IA_Left,x2,
									IA_Top,y2,
									TAG_DONE);
					SetAttrs(data->image,IA_Left,0,
												IA_Top,0,
												TAG_DONE);

					rc=(LONG)im;
				}


			}
			break;
			
		case OM_DISPOSE:
			data=INST_DATA(cl,(Object *)im);
			if (data->image) DisposeObject(data->image);
			ImageCounter--;
			rc=DoSuperMethodA(cl,(Object *)im,msg);
			break;
			
		case IM_HITTEST:
			data=INST_DATA(cl,(Object *)im);
			rc=DoMethodA(data->image,msg);
			break;
			
		case IM_DRAW:
		case IM_DRAWFRAME:
			data=INST_DATA(cl,im);
			x1=((struct impDraw *)msg)->imp_Offset.X+im->LeftEdge;
			y1=((struct impDraw *)msg)->imp_Offset.Y+im->TopEdge;
			rp=((struct impDraw *)msg)->imp_RPort;
			
			if (((struct impDraw *)msg)->imp_State==IDS_SELECTED)
			{
				DrawImageState(rp,(struct Image *)data->image,x1,y1,GadgetsGrey ? IDS_INACTIVESELECTED : IDS_SELECTED,data->id->di);
			} else {
				DrawImageState(rp,(struct Image *)data->image,x1,y1,GadgetsGrey ? IDS_INACTIVENORMAL : IDS_NORMAL,data->id->di);
			}

			rc=0;
			break;
			
			
		default: rc=DoSuperMethodA(cl,(Object *)im,msg);
	}
	return rc;
}

/* Program */

LONG RenderIcon(Msg msg)
{
	struct IconData *id;
	struct Gadget *gad;
	struct Image *im;
	WORD i;
	
	switch (msg->MethodID)
	{

 /*==========  RI_INIT  ===========================================*/

		case RI_INIT:
			GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",39);
			IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",39);
			UtilityBase=(struct UtilityBase *)OpenLibrary("utility.library",39);
			DiskfontBase=OpenLibrary("diskfont.library",39);
			DOSBase=OpenLibrary("dos.library",39);
			
			MyImageClass=MakeClass(0,IMAGECLASS,0,sizeof(MyImageData),0);
			MemPool=CreatePool(MEMF_PUBLIC|MEMF_CLEAR,2000,2000);
			InitSemaphore(&MemSem);

			if ((!GfxBase) || (!IntuitionBase) || (!UtilityBase) || (!DOSBase) || (!MyImageClass) || (!MemPool))
			{
				CleanUp();
				return RIR_FAIL;
			} else {
				MyImageClass->cl_Dispatcher.h_Entry=HookEntry;
				MyImageClass->cl_Dispatcher.h_SubEntry=(HOOKFUNC)MyImageDispatcher;
				
				if (RIINIT_Msg->Parameters && (RIINIT_Msg->PWVersion>=0))
				{
					if ((MyArgs=AllocDosObject(DOS_RDARGS,0)))
					{
						strncpy(s,RIINIT_Msg->Parameters,254);
						strcat(s,"\n");
						MyArgs->RDA_Source.CS_Buffer=s;
						MyArgs->RDA_Source.CS_Length=strlen(s);
						MyArgs->RDA_Source.CS_CurChr=0;
						
						if (ReadArgs(ARG_TEMPLATE,(LONG *)Args,MyArgs))
						{
							if (Args[ARG_FONTSIZE]) FontYSize= *Args[ARG_FONTSIZE];
							if (Args[ARG_FONTSTYLE]) FontStyle= *Args[ARG_FONTSTYLE];
							if (Args[ARG_FONTXOFFSET]) FontXOffset= *Args[ARG_FONTXOFFSET];
							if (Args[ARG_FONTYOFFSET]) FontYOffset= *Args[ARG_FONTYOFFSET];
//							if (Args[ARG_MINBARWIDTH]) MinBarWidth= *Args[ARG_MINBARWIDTH];
//							if (Args[ARG_GADGETGAP]) GadgetGap= *Args[ARG_GADGETGAP];
							if (Args[ARG_TITLEGAP]) TitleGap= *Args[ARG_TITLEGAP];
							if (Args[ARG_GADGETSGREY]) GadgetsGrey=TRUE;
							if (Args[ARG_BACKGROUNDGREY]) BackgroundGrey=TRUE;
							if (Args[ARG_BACKCOL])
							{
								l=strtol((STRPTR)Args[ARG_BACKCOL],0,0);
								ColData[COL_BACK][0]=(l&0xFF0000)>>16;
								ColData[COL_BACK][1]=(l&0xFF00)>>8;
								ColData[COL_BACK][2]=(l&0xFF);
								DoCustomBack=TRUE;
							}
							if (Args[ARG_TITLECOL])
							{
								l=strtol((STRPTR)Args[ARG_TITLECOL],0,0);
								ColData[COL_TITLE][0]=(l&0xFF0000)>>16;
								ColData[COL_TITLE][1]=(l&0xFF00)>>8;
								ColData[COL_TITLE][2]=(l&0xFF);
								DoCustomTitle=TRUE;
							}
							if (Args[ARG_CENTERTITLE]) CenterTitle=TRUE;
							if (Args[ARG_PRECISION]) Precision= *Args[ARG_PRECISION];

							if (Args[ARG_FONTNAME])
							{
								MyTextAttr.ta_Name=(STRPTR)Args[ARG_FONTNAME];
								MyTextAttr.ta_YSize=FontYSize;
								
								MyFont=OpenDiskFont(&MyTextAttr);
							}
							FreeArgs(MyArgs);
						}
						FreeDosObject(DOS_RDARGS,MyArgs);
					}
				}
				
			}
			return RIR_OK;

/*==========  RI_EXIT  ===========================================*/

		case RI_EXIT:
			CleanUp();
			return RIR_OK;

/*==========  RI_INITICON  =======================================*/

		case RI_INITICON:
			ObtainSemaphore(&MemSem);
			if ((RIINITICON_Msg->UserData=AllocPooled(MemPool,ID_Size)))
			{
				id=(struct IconData *)RIINITICON_Msg->UserData;
				id->cm=ViewPortAddress(RIINITICON_Msg->ParentWin)->ColorMap;
				id->ParentWindow=RIINITICON_Msg->ParentWin;
				id->di=GetScreenDrawInfo(id->ParentWindow->WScreen);

				id->Grey[COL_BACK][1]=DoCustomBack ? 0 : -1;
				id->Grey[COL_TITLE][1]=DoCustomTitle ? 0 : -1;
				for (i=0;i<NUM_Col;i++)
				{
					if (id->Grey[i][1]!= -1)
					{
						id->Grey[i][1]=ObtainBestPen(id->cm,
											ColData[i][0]<<24,
											ColData[i][1]<<24,
											ColData[i][2]<<24,
											OBP_Precision,Precision,
											OBP_FailIfBad,FALSE,
											TAG_DONE);
						if (id->Grey[i][1]>=0)
						{
							id->Grey[i][0]=id->Grey[i][1];
						} else {
							id->Grey[i][0]=FindColor(id->cm,
											ColData[i][0]<<24,
											ColData[i][1]<<24,
											ColData[i][2]<<24,
											~0);
						}
					}
				}
				if (MyFont)
				{
					RIINITICON_Msg->IconHeight=3+MyFont->tf_YSize;
				} else {
					RIINITICON_Msg->IconHeight=3+RIINITICON_Msg->ParentWin->WScreen->RastPort.TxHeight;
				}
				
			}
			ReleaseSemaphore(&MemSem);

			return RIR_OK;

/*==========  RI_EXITICON  =======================================*/

		case RI_EXITICON:
			if (RIEXITICON_Msg->UserData)
			{
				id=(struct IconData *)RIEXITICON_Msg->UserData;
				gad=id->iwin->FirstGadget;
				while (gad)
				{
					if (gad->Flags&GFLG_GADGIMAGE)
					{
						if ((im=(struct Image *)gad->GadgetRender))
						{
							if (im->Depth==CUSTOMIMAGEDEPTH)
							{
								if (OCLASS(im)==MyImageClass)
								{
									SetGadgetAttrs(gad,id->iwin,0,
										GA_Image,0,
										TAG_DONE);
									DisposeObject(im);
								}
							}
						}
					}
					gad=gad->NextGadget;
				}
				for (i=0;i<NUM_Col;i++)
				{
					if (id->Grey[i][1]>=0)
					{
						ReleasePen(id->cm,id->Grey[i][0]);
					}
				}

				if (id->di) FreeScreenDrawInfo(id->iwin->WScreen,id->di);

				ObtainSemaphore(&MemSem);
				FreePooled(MemPool,RIEXITICON_Msg->UserData,ID_Size);
				ReleaseSemaphore(&MemSem);
			}
			return RIR_OK;
			
/*==========  RI_RENDERICON  =====================================*/

		case RI_RENDERICON:
			id=(struct IconData *)RIRENDERICON_Msg->UserData;
			if (!id) return RIR_FAIL;

			IconWin=RIRENDERICON_Msg->Icon;
			id->iwin=IconWin;
			id->BarXStart=TitleGap;
			id->BarXEnd=IconWin->Width-1-TitleGap;

			rp=IconWin->RPort;

			if (MyFont)
			{
				SetFont(rp,MyFont);
			} else {
				SetFont(rp,IconWin->WScreen->RastPort.Font);
			}
			if (FontStyle) SetSoftStyle(rp,FontStyle,AskSoftStyle(rp));

			di=id->di;
			if (!di) return RIR_FAIL;

			gad=IconWin->FirstGadget;
			CloseGad=0;DepthGad=0;
			while (gad)
			{
				if ((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_WDEPTH)
				{
					DepthGad=gad;
				} else if ((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_CLOSE)
				{
					CloseGad=gad;
				} else if (gad->GadgetID==GID_WDEPTH)
				{
					DepthGad=gad;
				}
				gad=gad->NextGadget;
			}

			SetAPen(rp,di->dri_Pens[SHINEPEN]);
			Move(rp,0,IconWin->Height-1);
			Draw(rp,0,0);
			Draw(rp,IconWin->Width-1,0);
			SetAPen(rp,di->dri_Pens[SHADOWPEN]);
			Move(rp,IconWin->Width-1,1);
			Draw(rp,IconWin->Width-1,IconWin->Height-1);
			Draw(rp,1,IconWin->Height-1);

			if (DoCustomBack)
			{
				SetAPen(rp,id->Grey[COL_BACK][0]);
			} else {
				SetAPen(rp,di->dri_Pens[BackgroundGrey ? BACKGROUNDPEN : FILLPEN]);
			}
			RectFill(rp,1,1,IconWin->Width-2,IconWin->Height-2);

//			SetAPen(rp,id->Grey[COL_BACK][0]);

			if (CloseGad)
			{
				if ((im=NewObject(MyImageClass,0,
					IA_FGPen,CLOSEIMAGE,
					IA_Height,IconWin->Height,
					GA_UserData,id,
					TAG_DONE)))
				{
					SetGadgetAttrs(CloseGad,IconWin,0,
						GA_Left,0,
						GA_Top,0,
						GA_Width,im->Width,
						GA_Height,im->Height,
						GA_Image,im,
						TAG_DONE);

					RefreshGList(CloseGad,IconWin,0,1);
					id->BarXStart+=im->Width;
				}
			}
			if (DepthGad)
			{
				if ((im=NewObject(MyImageClass,0,
					IA_FGPen,DEPTHIMAGE,
					IA_Height,IconWin->Height,
					GA_UserData,id,
					TAG_DONE)))
				{
					SetGadgetAttrs(DepthGad,IconWin,0,
						GA_RelRight,1-im->Width-im->LeftEdge,
						GA_Top,0,
						GA_Width,im->Width,
						GA_Height,im->Height,
						GA_Image,im,
						TAG_DONE);

					RefreshGList(DepthGad,IconWin,0,1);
					id->BarXEnd-=im->Width;

				}
			}

			title=RIRENDERICON_Msg->ParentWin->Title;
			a=TextFit(rp,title,strlen(title),&MyTE,0,1,(id->BarXEnd-id->BarXStart+1),IconWin->Height);
			while (a && (title[a-1]==' ')) a--;

			b=rp->TxBaseline+2;
			if (CenterTitle)
			{
				c=(id->BarXStart+id->BarXEnd-TextLength(rp,title,a))/2;
			} else {
				c=id->BarXStart;
			}

			
			Move(rp,c+FontXOffset,b+FontYOffset);
			if (DoCustomTitle)
			{
				SetABPenDrMd(rp,id->Grey[COL_TITLE][0],0,JAM1);
			} else {
				SetABPenDrMd(rp,di->dri_Pens[FILLTEXTPEN],0,JAM1);
			}
			Text(rp,title,a);

			return RIR_OK;

/*==========  RI_REFRESHIFRAME ===================================*/

		case RI_REFRESHIFRAME:
			RefreshIFrame(RI_RENDERFRAME,
							  RIREFRESHIFRAME_Msg->Icon,
							  RIREFRESHIFRAME_Msg->Icon->RPort,
							  (struct IconData *)RIREFRESHIFRAME_Msg->UserData);
			return RIR_OK;
			return RIR_OK;

/*==========  RI_REFRESHIFRAME ===================================*/

		case RI_REFRESHITITLE:
			RefreshITitle((struct riRefreshITitle *)msg);
			return RIR_OK;

/*==========  RI_RENDERFRAME    ==================================*/

		case RI_RENDERFRAME:
			RefreshIFrame(RI_RENDERFRAME,
							  RIRENDERFRAME_Msg->Icon,
							  RIRENDERFRAME_Msg->rp,
							  (struct IconData *)RIRENDERFRAME_Msg->UserData);
			break;

/*==========  RI_RENDERFRAMESEL ==================================*/

		case RI_RENDERFRAMESEL:
			RefreshIFrame(RI_RENDERFRAMESEL,
								RIRENDERFRAMESEL_Msg->Icon,
								RIRENDERFRAMESEL_Msg->rp,
								(struct IconData *)RIRENDERFRAMESEL_Msg->UserData);
			break;

		default:
			return RIR_FAIL;
	}
}

