#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"

/****** Button/--background-- ********************************************
*
*	This class implements the button gadget type for BOOPSILib.
*
*	Parent class: gadgetclass
*
*************************************************************************/

struct InstanceData
{
  struct BOOPSILibS_LayoutInfo LayoutInfo;
  struct TextFont *Font;
  WORD StringWidth;
  UBYTE Keyboard;
  UBYTE ControlChar;
};

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

struct IClass *BOOPSILibC_Button;

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

METHOD(OM_NEW,struct opSet *)

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

      InstanceData=INSTANCEDATA;
      InstanceData->Keyboard=0;
      InstanceData->LayoutInfo.Weight=(WORD)GetTagData(BOOPSILibA_Weight,100,Message->ops_AttrList);
      InstanceData->ControlChar=(char)GetTagData(BOOPSILibA_ControlChar,'\0',Message->ops_AttrList);
      ((struct ExtGadget *)TheObject)->GadgetText=(struct IntuiText *)GetTagData(GA_Text,(ULONG)"",Message->ops_AttrList);
      ((struct ExtGadget *)TheObject)->Flags|=GFLG_TABCYCLE;
      ((struct ExtGadget *)TheObject)->Activation|=GACT_RELVERIFY;
    }
  return (ULONG)TheObject;
}

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

METHOD(BOOPSILibM_Init,const struct BOOPSILibP_Init *)

{
  struct InstanceData *InstanceData;
  struct RastPort RastPort;

  DoMethod(Message->Root,BOOPSILibM_Root_AddGadget,(struct Gadget *)TheObject);
  InstanceData=INSTANCEDATA;
  if (InstanceData->ControlChar!=0)
    {
      DoMethod(Message->Root,BOOPSILibM_Root_RequestKey,TheObject,InstanceData->ControlChar);
    }
  InstanceData->Font=Message->Font;
  InitRastPort(&RastPort);
  SetFont(&RastPort,Message->Font);
  InstanceData->StringWidth=LabelText(&RastPort,(char *)((struct ExtGadget *)TheObject)->GadgetText,FALSE);
  InstanceData->LayoutInfo.Width.Min=InstanceData->StringWidth;
  InstanceData->LayoutInfo.Width.Max=0x7fff;
  InstanceData->LayoutInfo.Height.Min=InstanceData->LayoutInfo.Height.Max=InstanceData->Font->tf_YSize;
  return (ULONG)&InstanceData->LayoutInfo;
}

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

METHOD(BOOPSILibM_Layout,const struct BOOPSILibP_Layout *)

{
  *(struct IBox *)&((struct ExtGadget *)TheObject)->LeftEdge=Message->Position;
  return 0;
}

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

METHOD(OM_GET,struct opGet *)

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

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

METHOD(GM_RENDER,const struct gpRender *)

{
  struct InstanceData *InstanceData;
  const struct ExtGadget *Gadget;

  InstanceData=INSTANCEDATA;
  Gadget=(struct ExtGadget *)TheObject;
  DrawImageState(Message->gpr_RPort,Gadget->GadgetRender,Gadget->LeftEdge,Gadget->TopEdge,
		 (Gadget->Flags & GFLG_SELECTED) ? IDS_SELECTED : IDS_NORMAL,Message->gpr_GInfo->gi_DrInfo);
  SetDrMd(Message->gpr_RPort,JAM1);
  if (InstanceData->Keyboard==0xff)
    {
      SetAPen(Message->gpr_RPort,Message->gpr_GInfo->gi_DrInfo->dri_Pens[FILLPEN]);
      RectFill(Message->gpr_RPort,
	       Gadget->LeftEdge, Gadget->TopEdge,
	       Gadget->LeftEdge+Gadget->Width-1, Gadget->TopEdge+Gadget->Height-1);
    }
  SetAPen(Message->gpr_RPort,Message->gpr_GInfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  Move(Message->gpr_RPort,
       Gadget->LeftEdge+(Gadget->Width-InstanceData->StringWidth)/2,
       Gadget->TopEdge+InstanceData->Font->tf_Baseline);
  LabelText(Message->gpr_RPort,(char *)Gadget->GadgetText,TRUE);
  return 0;
}

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

static void RedrawGadget(Object *TheObject, struct GadgetInfo *GadgetInfo)

{
  struct RastPort *RastPort;

  if ((RastPort=ObtainGIRPort(GadgetInfo))!=NULL)
    {
      DoMethod(TheObject,GM_RENDER,GadgetInfo,RastPort,GREDRAW_UPDATE);
      ReleaseGIRPort(RastPort);
    }
}

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

METHOD(GM_GOACTIVE,struct gpInput *)

{
  struct InstanceData *InstanceData;

  InstanceData=INSTANCEDATA;
  if (InstanceData->Keyboard!=0)
    {
      if (Message->gpi_IEvent!=NULL)
	{
	  return GMR_REUSE;
	}
    }
  else
    {
      if (Message->gpi_IEvent==NULL)
	{
	  InstanceData->Keyboard=0xff;
	  SetAttrs(((struct ExtGadget *)TheObject)->GadgetRender,IA_EdgesOnly,TRUE,TAG_DONE);
	  RedrawGadget(TheObject,Message->gpi_GInfo);
	}
    }
  return GMR_MEACTIVE;
}

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

METHOD(GM_HANDLEINPUT,struct gpInput *)

{
  ULONG RC;
  UWORD Selected;
  UBYTE Keyboard;

  RC=GMR_MEACTIVE;
  Selected=~0;
  Keyboard=INSTANCEDATA->Keyboard;
  if (Keyboard!=0)
    {
      switch (Message->gpi_IEvent->ie_Class)
	{
	case IECLASS_RAWMOUSE:
	  if (Message->gpi_IEvent->ie_Code!=IECODE_NOBUTTON)
	    {
	      RC=GMR_REUSE;
	    }
	  break;

	case IECLASS_RAWKEY:
	  {
	    if (Message->gpi_IEvent->ie_Code==Keyboard || Message->gpi_IEvent->ie_Code==(IECODE_UP_PREFIX | 0x40))
	      {
		if ((Message->gpi_IEvent->ie_Qualifier&(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
		  {
		    RC=GMR_NOREUSE;
		  }
		else
		  {
		    *Message->gpi_Termination=((struct ExtGadget *)TheObject)->GadgetID;
		    RC=GMR_NOREUSE | GMR_VERIFY;
		  }
	      }
	    else if (Keyboard==0xff && Message->gpi_IEvent->ie_Code==0x40)
	      {
		Selected=GFLG_SELECTED;
	      }
	    else if (Message->gpi_IEvent->ie_Code==0x42)
	      {
		if ((Message->gpi_IEvent->ie_Qualifier&(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
		  {
		    RC=GMR_PREVACTIVE;
		  }
		else
		  {
		    RC=GMR_NEXTACTIVE;
		  }
	      }
	  }
	  break;
	}
    }
  else
    {
      if (Message->gpi_IEvent->ie_Class==IECLASS_RAWMOUSE)
	{
	  if (DoMethod((Object *)((struct ExtGadget *)TheObject)->GadgetRender,IM_HITTEST,Message->gpi_Mouse))
	    {
	      Selected=GFLG_SELECTED;
	    }
	  else
	    {
	      Selected=0;
	    }
	  if (Message->gpi_IEvent->ie_Code==SELECTUP)
	    {
	      if (Selected)
		{
		  *Message->gpi_Termination=((struct ExtGadget *)TheObject)->GadgetID;
		  Selected=0;
		  RC=GMR_NOREUSE | GMR_VERIFY;
		}
	      else
		{
		  RC=GMR_NOREUSE;
		}
	    }
	}
    }
  if (Selected!=~0 && (((struct ExtGadget *)TheObject)->Flags & GFLG_SELECTED)!=Selected)
    {
      ((struct ExtGadget *)TheObject)->Flags^=GFLG_SELECTED;
      RedrawGadget(TheObject,Message->gpi_GInfo);
    }
  return RC;
}

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

METHOD(GM_GOINACTIVE,struct gpGoInactive *)

{
  struct InstanceData *InstanceData;

  InstanceData=INSTANCEDATA;
  if ((((struct ExtGadget *)TheObject)->Flags & GFLG_SELECTED) || InstanceData->Keyboard)
    {
      SetAttrs(((struct ExtGadget *)TheObject)->GadgetRender,IA_EdgesOnly,FALSE,TAG_DONE);
      ((struct ExtGadget *)TheObject)->Flags&=~GFLG_SELECTED;
      InstanceData->Keyboard=0;
      RedrawGadget(TheObject,Message->gpgi_GInfo);
    }
  return 0;
}

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

METHOD(OM_SET,struct opSet *)

{
  struct TagItem *Tags;
  const struct TagItem *Tag;

  Tags=Message->ops_AttrList;
  while ((Tag=NextTagItem(&Tags))!=NULL)
    {
      switch (Tag->ti_Tag)
	{
	case BOOPSILibA_Frame:
	  ((struct ExtGadget *)TheObject)->GadgetRender=(Object *)Tag->ti_Data;
	  break;
	}
    }
  return SUPER_METHOD;
}

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

METHOD(BOOPSILibM_ControlChar,const struct BOOPSILibP_ControlChar *)

{
  if (!(Message->Code&IECODE_UP_PREFIX))
    {
      struct InstanceData *InstanceData;

      InstanceData=INSTANCEDATA;
      InstanceData->Keyboard=Message->Code|IECODE_UP_PREFIX;
      if (ActivateGadget((struct Gadget *)TheObject,Message->GadgetInfo->gi_Window,NULL))
	{
	  ((struct ExtGadget *)TheObject)->Flags|=GFLG_SELECTED;
	  RedrawGadget(TheObject,Message->GadgetInfo);
	}
      else
	{
	  InstanceData->Keyboard=0;
	}
    }
  return 0;
}

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

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_SET,struct opSet *);
      METHOD_DISP(OM_GET,struct opGet *);
      METHOD_DISP(BOOPSILibM_Init,struct BOOPSILibP_Init *);
      METHOD_DISP(BOOPSILibM_Layout,struct BOOPSILibP_Layout *);
      METHOD_DISP(GM_RENDER,struct gpRender *);
      METHOD_DISP(GM_GOACTIVE,struct gpInput *);
      METHOD_DISP(GM_GOINACTIVE,struct gpGoInactive *);
      METHOD_DISP(GM_HANDLEINPUT,struct gpInput *);
      METHOD_DISP(BOOPSILibM_ControlChar,struct BOOPSILibP_ControlChar *);
    }
  return SUPER_METHOD;
}

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

struct IClass *CreateBOOPSILibC_Button(void)

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