#include "BOOPSILib.h"

#define MYLIB_BOOPSI
#define MYLIB_GRAPHICS
#define ROM_VERSION 39

#ifndef INTUITION_IMAGECLASS_H
#include <intuition/imageclass.h>
#endif

#ifndef INTUITION_GADGETCLASS_H
#include <intuition/gadgetclass.h>
#endif

#include "MyLib.h"

#include "StaticSavedsAsmA0A1A2.h"

/****** Frame/--background-- *********************************************
*
*	This class implements frame images to frame gadgets.
*	You add the frame image to your group, and add the
*	gadget to the frame image.
*
*	This is not a gadget, and therefore requires a gadget to
*	take care of its rendering.
*
*	Parent class: frameiclass
*
*************************************************************************/

struct InstanceData
{
  Object *Gadget;
  struct
    {
      unsigned int HSpace:8;
      unsigned int VSpace:8;
      unsigned int Fake:1;		/* pretend that there is a frame, but don't render it */
    } Misc;
  struct IBox FrameBox;
  struct BOOPSILibS_LayoutInfo LayoutInfo;
};

/************************************************************************/

struct IClass *BOOPSILibC_Frame;

/****** Frame/BOOPSILibA_Frame_Fake **************************************
*
*************************************************************************/

/****** Frame/BOOPSILibA_Frame_Space *************************************
*
*    NAME
*	BOOPSILibA_Frame_Space -- spacing around frame
*
*    SYNOPSIS
*	Type:		UWORD
*	Usability:	I..
*	Values:		(HSpace<<8)+VSpace
*
*    FUNCTION
*	Specify whitespace around object. Bascially a framed object
*	looks like this:
*
*	              VSpace
*	         +---------------+
*	HSpace   |    Gadget     |   HSpace
*	         +---------------+
*	              VSpace
*
*	The amount of additional whitespace (HSpace and VSpace) is
*	specified as a percentage value (0-100): if it is 50, then
*	half of the space available for the object is added to the
*	minimum gadget size, the other half is used as whitespace.
*
*************************************************************************/

/****** Frame/BOOPSILibA_Frame_Gadget ************************************
*
*    NAME
*	BOOPSILibA_Frame_Gadget -- the gadget to frame
*
*    SYNOPSIS
*	Type:		Object *
*	Usability:	I.G
*
*************************************************************************/

METHOD(OM_NEW,struct opSet *)

{
  if ((TheObject=(Object *)SUPER_METHOD)!=NULL)
    {
      struct InstanceData *InstanceData;

      InstanceData=INSTANCEDATA;
      if ((InstanceData->Gadget=(Object *)GetTagData(BOOPSILibA_Frame_Gadget,(ULONG)NULL,Message->ops_AttrList))!=NULL)
	{
	  UWORD FrameSpace;

	  FrameSpace=(UWORD)GetTagData(BOOPSILibA_Frame_Space,0,Message->ops_AttrList);
	  InstanceData->Misc.HSpace=FrameSpace>>8;
	  InstanceData->Misc.VSpace=FrameSpace&0xff;
	  SetAttrs(InstanceData->Gadget,BOOPSILibA_Frame,TheObject,TAG_DONE);
	  InstanceData->Misc.Fake=!!GetTagData(BOOPSILibA_Frame_Fake,FALSE,Message->ops_AttrList);
	  return (ULONG)TheObject;
	}
      CoerceMethod(TheClass,TheObject,OM_DISPOSE);
    }
  return (ULONG)NULL;
}

/************************************************************************/

METHOD(OM_DISPOSE,Msg)

{
  DisposeObject(INSTANCEDATA->Gadget);
  return SUPER_METHOD;
}

/************************************************************************/

METHOD(BOOPSILibM_Init,struct BOOPSILibP_Init *)

{
  struct InstanceData *InstanceData;
  WORD t;

  InstanceData=INSTANCEDATA;

  {
    struct IBox ContentsBox;

    ContentsBox.Left=0;
    ContentsBox.Top=0;
    ContentsBox.Width=0;
    ContentsBox.Height=0;
    DoMethod(TheObject,IM_FRAMEBOX,&ContentsBox,&InstanceData->FrameBox,Message->DrawInfo,0);
  }

  InstanceData->LayoutInfo=*(struct BOOPSILibS_LayoutInfo *)DoMethodA(InstanceData->Gadget,Message);

  InstanceData->LayoutInfo.Width.Min+=InstanceData->FrameBox.Width;
  t=InstanceData->LayoutInfo.Width.Max+((InstanceData->LayoutInfo.Width.Max-InstanceData->LayoutInfo.Width.Min)*(100-InstanceData->Misc.HSpace))/100+InstanceData->FrameBox.Width;
  if (t>MAX_WORD || t<0)
    {
      t=MAX_WORD;
    }
  InstanceData->LayoutInfo.Width.Max=t;

  InstanceData->LayoutInfo.Height.Max+=((InstanceData->LayoutInfo.Height.Max-InstanceData->LayoutInfo.Height.Min)*(100-InstanceData->Misc.VSpace))/100;
  InstanceData->LayoutInfo.Height.Min+=InstanceData->FrameBox.Height;
  if ((InstanceData->LayoutInfo.Height.Max+=InstanceData->FrameBox.Height)<0)
    {
      InstanceData->LayoutInfo.Height.Max=0x7fff;
    }

  return (ULONG)&InstanceData->LayoutInfo;
}

/************************************************************************/

METHOD(BOOPSILibM_Layout,const struct BOOPSILibP_Layout *)

{
  const struct InstanceData *InstanceData;
  struct IBox GadgetBox;
  WORD FrameSpace;

  InstanceData=INSTANCEDATA;
  GadgetBox=Message->Position;
  SetAttrs(InstanceData->Gadget,GA_Bounds,&GadgetBox,TAG_DONE);
  FrameSpace=((GadgetBox.Width-InstanceData->LayoutInfo.Width.Min)*InstanceData->Misc.HSpace)/100;
  GadgetBox.Width-=FrameSpace;
  GadgetBox.Left+=FrameSpace/2;
  FrameSpace=((GadgetBox.Height-InstanceData->LayoutInfo.Height.Min)*InstanceData->Misc.VSpace)/100;
  GadgetBox.Height-=FrameSpace;
  GadgetBox.Top+=FrameSpace/2;

  SetAttrs(TheObject,
	   IA_Left, InstanceData->FrameBox.Left,
	   IA_Top, InstanceData->FrameBox.Top,
	   IA_Width, GadgetBox.Width,
	   IA_Height, GadgetBox.Height,
	   TAG_DONE);

  GadgetBox.Left-=InstanceData->FrameBox.Left;
  GadgetBox.Top-=InstanceData->FrameBox.Top;
  GadgetBox.Width-=InstanceData->FrameBox.Width;
  GadgetBox.Height-=InstanceData->FrameBox.Height;

  return DoMethod(InstanceData->Gadget,BOOPSILibM_Layout,Message->Root,GadgetBox,Message->GadgetInfo);
}

/************************************************************************/

METHOD(OM_GET,struct opGet *)

{
  switch (Message->opg_AttrID)
    {
    case BOOPSILibA_LayoutInfo:
      *Message->opg_Storage=(ULONG)&INSTANCEDATA->LayoutInfo;
      return TRUE;

    case BOOPSILibA_Frame_Gadget:
      *Message->opg_Storage=(ULONG)INSTANCEDATA->Gadget;
      return TRUE;
    }
  return SUPER_METHOD;
}

/************************************************************************/

METHOD(IM_DRAW,struct impDraw *)

{
  return INSTANCEDATA->Misc.Fake ? 0 : SUPER_METHOD;
}

/************************************************************************/

STATIC_SAVEDS_ASM_A0A1A2(ULONG,Dispatcher,struct IClass *,TheClass,Msg,Message,Object *,TheObject)

{
  switch(Message->MethodID)
    {
      METHOD_DISP(OM_NEW,struct opSet *);
      METHOD_DISP(OM_GET,struct opGet *);
      METHOD_DISP(OM_DISPOSE,Msg);
      METHOD_DISP(BOOPSILibM_Init,struct BOOPSILibP_Init *);
      METHOD_DISP(BOOPSILibM_Layout,struct BOOPSILibP_Layout *);
      METHOD_DISP(IM_DRAW,struct impDraw *);
    }
  return SUPER_METHOD;
}

/************************************************************************/

struct IClass *CreateBOOPSILibC_Frame(void)

{
  if ((BOOPSILibC_Frame=MakeClass(NULL,BOOPSI_frameiclass,NULL,sizeof(struct InstanceData),0))!=NULL)
    {
      BOOPSILibC_Frame->cl_Dispatcher.h_Entry=Dispatcher;
    }
  return BOOPSILibC_Frame;
}
