/* PowerWindows: Icon.c */

#include <dos/dos.h>
#include <graphics/gfx.h>
#include <intuition/intuition.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <utility/utility.h>

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/timer_lib.h>
#include <clib/alib_protos.h>

#pragma header

#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "PowerWindows.h"
#include "PWDevelopper.h"

/* MakeIcon ============--=======================================================*/

void MakeIcon(struct ActionMsg *MyMsg,WORD x,WORD y)
{
	struct Gadget *gad,*gad2,*gad3,*gad4;
	struct Image *im;
	struct Window *win;
	struct Screen *scr;
	struct DrawInfo *drinfo;
	struct RastPort *rp;
	struct TextExtent MyTextExtent;
	struct ScreenEntry *MySE;
	struct MyButtonData *MyData;
	union  PWMessage ExtMessage;

	STRPTR title;
	ULONG ilock;
	UWORD	 *pens;
	WORD	a,b,c,d,e,xx,yy;
	BOOL	OK;
	
	if (MyMsg->Code!=AM_ICONIFY) return;
	
	MySE=MyMsg->SEntry;
	
/* Calc Icon-Width */

	if (MyConfig.IconWidthFac==IW_WINWIDTH)
	{
		a=MyMsg->win->Width;		
		if (MyConfig.DoIconWidthDiv)
		{
			a/=MyConfig.IconWidthDiv;
		}
	} else {
		if (MyConfig.DoIconWidthDiv)
		{
			if (MyConfig.IconWidthFac==1) c=MyConfig.IconWidthDiv*MyConfig.IconSpaceX; else c=0;
			ilock=GetVPModeID(ViewPortAddress(MyMsg->win));
			if (ilock==INVALID_ID)
			{
				a=MySE->se_NormalWidth;
			} else {
				QueryOverscan(ilock,&MyTextExtent.te_Extent,OSCAN_TEXT);
				a=MyTextExtent.te_Extent.MaxX - MyTextExtent.te_Extent.MinX + 1;
			}

			a=(a-c) * MyConfig.IconWidthFac / MyConfig.IconWidthDiv;

		} else {
			a=MyConfig.IconWidthFac;
		}
	}
	
	if (MyConfig.IconFont)
	{
		b=MyConfig.IconFont->tf_YSize+8;
	} else {
		b=MyMsg->win->WScreen->RastPort.TxHeight+8;
	}
	
	if (ExtIconRenderer)
	{
		ExtMessage.priInitIcon.MethodID=RI_INITICON;
		ExtMessage.priInitIcon.ParentWin=MyMsg->win;
		
		ExtMessage.priInitIcon.IconWidth=a;
		ExtMessage.priInitIcon.IconHeight=b;
		ExtMessage.priInitIcon.WinTask=0;
		ExtMessage.priInitIcon.UserData=0;

		gad=MyMsg->win->FirstGadget;
		while (gad)
		{
			if (IsMyButton(gad))
			{
				if (GetAttr(CGA_Task,(Object *)gad,&ilock))
				{
					ExtMessage.priInitIcon.WinTask=(struct Task *)ilock;
					break;
				}
			}
			gad=gad->NextGadget;
		}
		
		(*MyConfig.IconRenderer)((Msg)&ExtMessage);

		b=ExtMessage.priInitIcon.IconHeight;	/* update Height */
	}
	
/* Calc Icon-Pos */

	ilock=LockIBase(0);
	scr=MyMsg->win->WScreen;
	xx=x;yy=y;
	switch (MyConfig.IconPosition)
	{
		case IP_UPPERLEFT:
			break;	/* use Standard Window Coords */
		
		case IP_UPPERRIGHT:
			xx+=(MyMsg->win->Width-a);
			break;
			
		case IP_LOWERLEFT:
			yy+=(MyMsg->win->Height-b);
			break;
			
		case IP_LOWERRIGHT:
			xx+=(MyMsg->win->Width-a);
			yy+=(MyMsg->win->Height-b);
			break;
			
		case IP_CENTER:
			xx+=((MyMsg->win->Width-a)/2);
			yy+=((MyMsg->win->Height-b)/2);
			break;

		case IP_AUTOBOTTOMLEFT:
		case IP_AUTOBOTTOMRIGHT:
		case IP_AUTOTOPLEFT:
		case IP_AUTOTOPRIGHT:
		case IP_AUTOLEFTTOP:
		case IP_AUTOLEFTBOTTOM:
		case IP_AUTORIGHTTOP:
		case IP_AUTORIGHTBOTTOM:
		
			OK=FALSE;
			switch (MyConfig.IconPosition)
			{
				case IP_AUTOBOTTOMLEFT:
				case IP_AUTOLEFTBOTTOM:
					xx=0;
					yy=MySE->se_NormalHeight-b;
					break;
					
				case IP_AUTOBOTTOMRIGHT:
				case IP_AUTORIGHTBOTTOM:
					xx=MySE->se_NormalWidth-a;
					yy=MySE->se_NormalHeight-b;
					break;
					
				case IP_AUTOTOPLEFT:
				case IP_AUTOLEFTTOP:
					xx=0;
					yy=0;
					break;
				
				case IP_AUTOTOPRIGHT:
				case IP_AUTORIGHTTOP:
					xx=MySE->se_NormalWidth-a;
					yy=0;
					break;
			}

			xx+=MyConfig.IconOffX;
			yy+=MyConfig.IconOffY;

			while (!OK)
			{
				win=scr->FirstWindow;
				OK=TRUE;
				while (win)
				{
					if (win->WLayer) if (win->WLayer->BackFill == &IconLayerHook)
					{
						for (e=1;e<=4;e++)
						{
							switch (e)
							{
								case 1:
									c=xx;d=yy;
									break;
								case 2:
									c=xx+a-1;d=yy;
									break;
								case 3:
									c=xx+a-1;d=yy+b-1;
									break;
								case 4:
									c=xx;d=yy+b-1;
									break;
							}
							if ((c>=win->LeftEdge) && (c<win->LeftEdge+win->Width) &&
							    (d>=win->TopEdge ) && (d<win->TopEdge+win->Height))
							{
								OK=FALSE;
								break;
							}
						}	/* for e=1 to 4 */
					}	/* if Icon-Window */
					if (!OK) break;
					win=win->NextWindow;
				}	/* while win */
				if (OK) break;

				c=MySE->se_NormalWidth-a;
				d=MySE->se_NormalHeight-b;
				
				switch (MyConfig.IconPosition)
				{
					case IP_AUTOBOTTOMLEFT:
						xx+=a+MyConfig.IconSpaceX;
						if (xx>c)
						{
							xx=MyConfig.IconOffX;
							if (yy>=(b+MyConfig.IconSpaceY))
							{
								yy-=(b+MyConfig.IconSpaceY);
							} else OK=TRUE;
						}
						break;
						
					case IP_AUTOLEFTBOTTOM:
						yy-=b+MyConfig.IconSpaceY;
						if (yy<0)
						{
							yy=d+MyConfig.IconOffY;
							if (xx<(c-MyConfig.IconSpaceX))
							{
								xx+=(a+MyConfig.IconSpaceX);
							} else OK=TRUE;
						}
						break;
						
					case IP_AUTOBOTTOMRIGHT:
						xx-=a+MyConfig.IconSpaceX;
						if (xx<0)
						{
							xx=c+MyConfig.IconOffX;
							if (yy>=(b+MyConfig.IconSpaceY))
							{
								yy-=(b+MyConfig.IconSpaceY);
							} else OK=TRUE;
						}
						break;

					case IP_AUTORIGHTBOTTOM:
						yy-=b+MyConfig.IconSpaceY;
						if (yy<0)
						{
							yy=d+MyConfig.IconOffY;
							if (xx>=(a+MyConfig.IconSpaceX))
							{
								xx-=(a+MyConfig.IconSpaceX);
							} else OK=TRUE;
						}
						break;
						
					case IP_AUTOTOPLEFT:
						xx+=a+MyConfig.IconSpaceX;
						if (xx>c)
						{
							xx=MyConfig.IconOffX;
							if (yy<(d-MyConfig.IconSpaceY))
							{
								yy+=(b+MyConfig.IconSpaceY);
							} else OK=TRUE;
						}
						break;
						
					case IP_AUTOLEFTTOP:
						yy+=b+MyConfig.IconSpaceY;
						if (yy>d)
						{
							yy=MyConfig.IconOffY;
							if (xx<(c-MyConfig.IconSpaceX))
							{
								xx+=(a+MyConfig.IconSpaceX);
							} else OK=TRUE;
						}
						break;
					
					case IP_AUTOTOPRIGHT:
						xx-=a+MyConfig.IconSpaceX;
						if (xx<0)
						{
							xx=c+MyConfig.IconOffX;
							if (yy<(d-MyConfig.IconSpaceY))
							{
								yy+=(b+MyConfig.IconSpaceY);
							} else OK=TRUE;
						}
						break;
							
					case IP_AUTORIGHTTOP:
						yy+=b+MyConfig.IconSpaceY;
						if (yy>d)
						{
							yy=MyConfig.IconOffY;
							if (xx>=(a+MyConfig.IconSpaceX))
							{
								xx-=(a+MyConfig.IconSpaceX);
							} else OK=TRUE;
						}
						break;
				}

			}	/* while !ok */
	}
	UnlockIBase(ilock);
/**/

	MinLimit(a,MyConfig.MinIconWidth);
	MaxLimit(a,MySE->se_NormalWidth);
	MaxLimit(b,MySE->se_NormalHeight);
	MaxLimit(xx,MySE->se_NormalWidth-a);
	MaxLimit(yy,MySE->se_NormalHeight-b);
	
	gad3=0;
	
	if (MyConfig.IconCloseGad && (MyMsg->win->Flags&WFLG_CLOSEGADGET))
	{
		gad3=NewObject(MyButtonClass,0,GA_ID,GADGET_ICONCLOSE,
												GA_Left,0,
												GA_Top,0,
												GA_Width,12,
												GA_Height,10,
												GA_SysGType,GTYP_CLOSE,
												GA_RelVerify,TRUE,
												CGA_ParentWindow,MyMsg->win,
												TAG_DONE);
	}
	
	gad2=0;
	if (MyConfig.IconDepth!=ID_ALWAYSFRONT)
	{
		gad2=NewObject(MyButtonClass,0,GA_ID,GADGET_WINDOWDEPTH,
												GA_RelRight,-11,
												GA_Top,0,
												GA_Width,12,
												GA_Height,10,
												GA_SysGType,GTYP_WDEPTH,
												GA_RelVerify,TRUE,
												TAG_DONE);
	}

	gad=NewObject(MyButtonClass,0,GA_ID,GADGET_ICONDRAG,
										  GA_Left,0,
										  GA_Top,0,
										  GA_RelWidth,0,
										  GA_RelHeight,0,
										  GA_SysGType,GTYP_WDRAGGING,
										  CGA_ParentWindow,MyMsg->win,
										  CGA_WindowLeft,x,
										  CGA_WindowTop,y,
										  CGA_WindowTitle,MyMsg->win->Title,
										  CGA_UserDataIcon,ExtMessage.priInitIcon.UserData,
										  gad2 ? GA_Previous : TAG_IGNORE, gad2,
										  TAG_DONE);
	if (!gad)
	{
		if (gad2) DisposeObject(gad2);
		if (gad3) DisposeObject(gad3);
		return;
	}

	Delay(1);

	win=OpenWindowTags(0,WA_CustomScreen,MyMsg->win->WScreen,
							  WA_Left,xx,
							  WA_Top,yy,
							  WA_Width,a,
							  WA_Height,b,
							  WA_BackFill,&IconLayerHook,
							  WA_Flags,WFLG_BORDERLESS|WFLG_RMBTRAP,
							  MyConfig.IconsActivateWin ? TAG_IGNORE : WA_Activate,TRUE,
							  WA_AutoAdjust,TRUE,
							  TAG_DONE);
	if (!win)
	{
		DisposeObject(gad);
		if (gad2) DisposeObject(gad2);
		if (gad3) DisposeObject(gad3);
		return;
	}
	
	if (gad3) AddGadget(win,gad3,-1);
	if (gad2) AddGadget(win,gad2,-1);

	if (MyConfig.NoIconDrag)
	{
		if ((im=NewObject(MyImageClass,0,
			SYSIA_Which,IMAGE_ICONNODRAG,
			CGA_ParentWindow,win,
			IA_Left,0,
			IA_Top,0,
			IA_Width,win->Width,
			IA_Height,win->Height,
			TAG_DONE)))
		{
			if ((gad4=NewObject(MyButtonClass,0,
				GA_ID,GADGET_ICONNODRAG,
				GA_Left,0,
				GA_Top,0,
				GA_RelWidth,0,
				GA_RelHeight,0,
				GA_RelVerify,TRUE,
				GA_Image,im,
				TAG_DONE)))
			{
				AddGadget(win,gad4,-1);
			} else {
				DisposeObject(im);
			}					
		}
	}

	if (gad)  AddGadget(win,gad,-1);

	if (ExtIconRenderer)
	{
		GetAttr(CGA_UserDataIcon,gad,&ilock);
		ExtMessage.priRenderIcon.MethodID=RI_RENDERICON;
		ExtMessage.priRenderIcon.ParentWin=MyMsg->win;
		ExtMessage.priRenderIcon.Icon=win;
		ExtMessage.priRenderIcon.UserData=(APTR)ilock;
		e=(*MyConfig.IconRenderer )((Msg)&ExtMessage);
	}
	if ((!ExtIconRenderer) || (e==0))
	{
		rp=win->RPort;
		if (MyConfig.IconFont)
		{
			SetFont(rp,MyConfig.IconFont);
		} else {
			SetFont(rp,win->WScreen->RastPort.Font);
		}
		SetSoftStyle(rp,MyConfig.IconFontStyle,AskSoftStyle(rp));


		drinfo=GetScreenDrawInfo(win->WScreen);
		if (drinfo)
		{
			pens=drinfo->dri_Pens;
			a=win->Width;
			b=win->Height;
			SetAPen(rp,pens[SHADOWPEN]);
			RectFill(rp,0,0,a-1,b-1);
			SetAPen(rp,pens[SHINEPEN]);
			RectFill(rp,1,1,a-3,b-3);
			SetAPen(rp,pens[BACKGROUNDPEN]);
			RectFill(rp,2,2,a-3,b-3);
			title=MyMsg->win->Title;
			if (title)
			{
				a=rp->TxBaseline+(win->Height - rp->TxHeight + 1) / 2;
				b=TextFit(rp,title,strlen(title),&MyTextExtent,0,1,win->Width-4-4-3-3-20,win->Height);
				
				while (b && (title[b-1]==' ')) b--;
	
				c=(win->Width-TextLength(rp,title,b))/2;
				e=c-8;
	
				SetAPen(rp,pens[SHADOWPEN]);
				SetDrMd(rp,JAM1);
				Move(rp,c+1,a+1);
				Text(rp,title,b);
	
				SetAPen(rp,pens[SHINEPEN]);
				Move(rp,c,a);
				Text(rp,title,b);
				
				SetAPen(rp,pens[SHADOWPEN]);
				for (c=0;c<=rp->TxBaseline+1;c+=2)
				{
					d=c+a-rp->TxBaseline;
					RectFill(rp,4,d,4+e,d);
					RectFill(rp,win->Width-1-4-e,d,win->Width-1-4,d);
				}
			}
			if ((gad2) && (MyConfig.IconDepth!=ID_ALWAYSFRONT))
			{
				SetAPen(rp,pens[BACKGROUNDPEN]);
				RectFill(rp,win->Width-13,2,win->Width-3,10);
				SetAPen(rp,pens[SHADOWPEN]);
				RectFill(rp,win->Width-12,2,win->Width-12,9);
				RectFill(rp,win->Width-12,9,win->Width-3,9);
				RectFill(rp,win->Width-9,3,win->Width-5,6);
				RectFill(rp,win->Width-8,4,win->Width-4,7);
				SetAPen(rp,pens[SHINEPEN]);
				RectFill(rp,win->Width-11,2,win->Width-11,8);
				RectFill(rp,win->Width-7,5,win->Width-5,6);
			}

			if ((gad3) && MyConfig.IconCloseGad)
			{
				SetAPen(rp,pens[BACKGROUNDPEN]);
				RectFill(rp,2,2,12,10);
				SetAPen(rp,pens[SHADOWPEN]);
				RectFill(rp,11,2,11,9);
				RectFill(rp,2,9,11,9);
				RectFill(rp,5,3,7,7);
				SetAPen(rp,pens[SHINEPEN]);
				RectFill(rp,6,4,6,6);
			}

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


	ObtainSemaphore(&IconListSemaphore);
	MyData=INST_DATA(MyButtonClass,gad);
	MyData->ThisWindow=win;
	AddTail(&IconList,(struct Node *)&MyData->node);
	ReleaseSemaphore(&IconListSemaphore);
}
	

/* KillIconWindow ===============================================================*/

void KillIconWindow(struct Window *win, BOOL CloseIt)
{
	struct Gadget *gad;
	struct riExitIcon IconMsg;
	struct MyButtonData *MyData;
	APTR   ud;
	
	if ((gad=FindIconGadget(win)))
	{
		ObtainSemaphore(&IconListSemaphore);
		MyData=INST_DATA(MyButtonClass,gad);
		Remove((struct Node *)&MyData->node);
		ReleaseSemaphore(&IconListSemaphore);	
	}

	if (ExtIconRenderer)
	{
		if ((GetIconUserData(win,&ud)))
		{
			IconMsg.MethodID=RI_EXITICON;
			IconMsg.UserData=ud;
			(*MyConfig.IconRenderer)((Msg)&IconMsg);
		}
	}
	
	KillMyGadgets(win);
	
	if (CloseIt) CloseWindow(win);
}

/* FindIconWindow =============================================================*/

struct Window *FindIconWindow(struct Window *win)
{
	struct Window *iwin,*gwin;
	struct Gadget *gad;

	ULONG	ilock;
	
	ilock=LockIBase(0);
	iwin=win->WScreen->FirstWindow;

	while(iwin)
	{
		if (iwin->WLayer->BackFill == &IconLayerHook)
		{
			gad=iwin->FirstGadget;
			while (gad)
			{
				if (IsMyButton(gad))
				{
					if (GetAttr(CGA_ParentWindow,gad,(ULONG *)&gwin))
					{
						if (gwin==win) break;
					}
				}
				gad=gad->NextGadget;
			}
			if (gad) break;
		}
		iwin=iwin->NextWindow;
	}
	UnlockIBase(ilock);

	return iwin;
}

/* GetIconUserData =============================================================*/

struct Gadget *GetIconUserData(struct Window *win,APTR *v)
{
	struct Gadget *gad;

	if ((gad=FindIconGadget(win)))
	{
		GetAttr(CGA_UserDataIcon,gad,(ULONG *)v);
	}
	return gad;
}

/* RefreshIconFrame =============================================================*/

void RefreshIconFrame(struct Window *win)
{
	struct DrawInfo *di;

	if ((di=GetScreenDrawInfo(win->WScreen)))
	{
		SetAPen(win->RPort,di->dri_Pens[SHADOWPEN]);
		RectFill(win->RPort,0,0,win->Width-1,0);
		RectFill(win->RPort,0,0,0,win->Height-1);
		RectFill(win->RPort,1,win->Height-1,win->Width-1,win->Height-1);
		RectFill(win->RPort,win->Width-1,1,win->Width-1,win->Height-1);
		FreeScreenDrawInfo(win->WScreen,di);
	}
}

/* RefreshIconTitle =============================================================*/

void RefreshIconTitle(struct Window *win,STRPTR title)
{
	struct DrawInfo *di;
	struct RastPort *rp;
	struct TextExtent MyTextExtent;

	WORD a,b,c,d,e;
	
	if ((di=GetScreenDrawInfo(win->WScreen)))
	{
		rp=win->RPort;
		a=rp->TxBaseline+(win->Height - rp->TxHeight + 1) / 2;
		b=TextFit(rp,title,strlen(title),&MyTextExtent,0,1,win->Width-4-4-3-3-20,win->Height);
		
		while (b && (title[b-1]==' ')) b--;

		c=(win->Width-TextLength(rp,title,b))/2;
		e=c-8;

		SetDrMd(rp,JAM1);
		SetAPen(rp,di->dri_Pens[BACKGROUNDPEN]);
		RectFill(rp,4+10,2,win->Width-1-4-10,win->Height-1-2);
		
		SetAPen(rp,di->dri_Pens[SHADOWPEN]);
		Move(rp,c+1,a+1);
		Text(rp,title,b);

		SetAPen(rp,di->dri_Pens[SHINEPEN]);
		Move(rp,c,a);
		Text(rp,title,b);
		
		SetAPen(rp,di->dri_Pens[SHADOWPEN]);
		for (c=0;c<=rp->TxBaseline+1;c+=2)
		{
			d=c+a-rp->TxBaseline;
			RectFill(rp,4+10,d,4+e,d);
			RectFill(rp,win->Width-1-4-e,d,win->Width-1-10-4,d);
		}

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


/* RefreshIconTitleExt ==========================================================*/

void RefreshIconTitleExt(struct Window *win,STRPTR title)
{
	struct riRefreshITitle msg = {RI_REFRESHITITLE,win,0};

	if (GetIconUserData(win,&msg.UserData))
	{
		(*MyConfig.IconRenderer)((Msg)&msg);
	}
}


/* RenderIconFrame ===========================================================*/

void RenderIconFrame(ULONG method,struct Window *win, struct RastPort *rp)
{
	struct DrawInfo *di;

	if ((di=GetScreenDrawInfo(win->WScreen)))
	{
		SetAPen(rp,di->dri_Pens[method == RI_RENDERFRAME ? SHADOWPEN : SHINEPEN]);
		RectFill(rp,0,0,win->Width-1,0);
		RectFill(rp,0,0,0,win->Height-1);
		RectFill(rp,1,win->Height-1,win->Width-1,win->Height-1);
		RectFill(rp,win->Width-1,1,win->Width-1,win->Height-1);
		FreeScreenDrawInfo(win->WScreen,di);
	}
}

/* RenderIconFrameExt ========================================================*/

void RenderIconFrameExt(ULONG method,struct Window *win,struct RastPort *rp)
{
	struct riRenderFrameSel msg = {method,win,rp,0};
	
	if (GetIconUserData(win,&msg.UserData))
	{
		(*MyConfig.IconRenderer)((Msg)&msg);
	}
}


