/************************/
/*			*/
/* Gadgets for Typeface */
/*			*/
/************************/

#include "Typeface.h"

extern struct GfxBase *GfxBase;

/* For any gadget */

void Gadg_DrawBevel(struct RastPort *rp,ULONG x,ULONG y,ULONG w,ULONG h,
  UBYTE pen1,UBYTE pen2)
{
  SetAPen(rp,pen1);
  Move(rp,x+w-2,y);
  Draw(rp,x,y);
  Draw(rp,x,y+h-1);
  Move(rp,1+x,y+h-2);
  Draw(rp,1+x,1+y);

  SetAPen(rp,pen2);
  Move(rp,1+x,y+h-1);
  Draw(rp,x+w-1,y+h-1);
  Draw(rp,x+w-1,y);
  Move(rp,x+w-2,1+y);
  Draw(rp,x+w-2,y+h-2);
}

void Gadg_SetTag(struct TagItem *tag,ULONG id, ULONG data)
{
  tag->ti_Tag = id;
  tag->ti_Data = data;
}

/* character selection gadget */

#define CG_XOFFSET 6
#define CG_YOFFSET 3

struct CharGadgData
{
  UWORD cg_CharWidth,cg_CharHeight;
  WORD cg_FirstX,cg_FirstY;
  struct TextFont *cg_TextFont;
  ULONG cg_LastPressed,cg_Pos;
  BOOL cg_Pressed;
};

__geta4 ULONG DispatchCharGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg);
ULONG CharGadg_NEW(Class *cl,Object *o,struct opSet *ops);
ULONG CharGadg_RENDER(Class *cl,struct Gadget *gadg,struct gpRender *gpr);
ULONG CharGadg_GOACTIVE(Class *cl,struct Gadget *gadg,struct gpInput *gpi);
ULONG CharGadg_HANDLEINPUT(Class *cl,struct Gadget *gadg,
  struct gpInput *gpi);
ULONG CharGadg_GOINACTIVE(Class *cl,struct Gadget *gadg,
  struct gpGoInactive *gpgi);
ULONG CharGadg_SET(Class *cl,struct Gadget *gadg,struct opSet *ops);
ULONG CharGadg_GET(Class *cl,Object *o,struct opGet *opg);
void CharGadg_DrawChar(struct RastPort *rp,struct GadgetInfo *gi,
  BOOL selected,ULONG x,ULONG y,ULONG w,ULONG h,char gchar,BOOL lines);
void CharGadg_DrawCurrent(struct GadgetInfo *gi,struct CharGadgData *cgd,
  struct Gadget *gadg);

Class *InitCharGadgClass(void)
{
Class *super, *cl = NULL;

  if (super = BGUI_GetClassPtr(BGUI_BASE_GADGET))
  {
    cl = MakeClass(NULL,NULL,super,sizeof(struct CharGadgData),0);
    if (cl) cl->cl_Dispatcher.h_Entry = DispatchCharGadg;
  }
  return cl;
}

BOOL FreeCharGadgClass(Class *cl)
{
  return FreeClass(cl);
}

ULONG GetCharGadgWidth(void)
{
  return (GfxBase->DefaultFont->tf_XSize+(CG_XOFFSET*2))*8;
}

ULONG GetCharGadgHeight(void)
{
  return (GfxBase->DefaultFont->tf_YSize+(CG_YOFFSET*2))*8;
}

__geta4 ULONG DispatchCharGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg)
{
ULONG retval;

  switch (msg->MethodID)
  {
    case OM_NEW:
      retval = CharGadg_NEW(cl,o,(struct opSet *)msg);
      break;
    case OM_SET:
      retval = CharGadg_SET(cl,(struct Gadget *)o,(struct opSet *)msg);
      break;
    case OM_GET:
      retval = CharGadg_GET(cl,o,(struct opGet *)msg);
      break;
    case GM_RENDER:
      retval = CharGadg_RENDER(cl,(struct Gadget *)o,(struct gpRender *)msg);
      break;
    case GM_GOACTIVE:
      retval = CharGadg_GOACTIVE(cl,(struct Gadget *)o,
	(struct gpInput *)msg);
      break;
    case GM_HANDLEINPUT:
      retval = CharGadg_HANDLEINPUT(cl,(struct Gadget *)o,
	(struct gpInput *)msg);
      break;
    case GM_GOINACTIVE:
      retval = CharGadg_GOINACTIVE(cl,(struct Gadget *)o,
	(struct gpGoInactive *)msg);
      break;
    default:
      retval = DoSuperMethodA(cl,o,(Msg *)msg);
      break;
  }
  return retval;
}

ULONG CharGadg_NEW(Class *cl,Object *o,struct opSet *ops)
{
ULONG retval = 0;
struct CharGadgData *cgd;

  retval = (ULONG)DoSuperMethodA(cl,o,(Msg *)ops);
  if (retval)
  {
    cgd = INST_DATA(cl,retval);
    cgd->cg_TextFont = GfxBase->DefaultFont;
    cgd->cg_CharWidth = cgd->cg_TextFont->tf_XSize+(CG_XOFFSET*2);
    cgd->cg_CharHeight = cgd->cg_TextFont->tf_YSize+(CG_YOFFSET*2);
    cgd->cg_Pressed = FALSE;
    cgd->cg_LastPressed = ~0;
  }
  return retval;
}

ULONG CharGadg_RENDER(Class *cl,struct Gadget *gadg,struct gpRender *gpr)
{
struct RastPort *rp;
struct CharGadgData *cgd = INST_DATA(cl,(Object *)gadg);
struct TextFont *old_tf = NULL;
UWORD i,j;

  rp = gpr->gpr_RPort;
  if (rp->Font != cgd->cg_TextFont)
  {
    old_tf = rp->Font;
    SetFont(rp,cgd->cg_TextFont);
  }
  if ((gpr->gpr_Redraw==GREDRAW_REDRAW)||(gpr->gpr_Redraw==GREDRAW_UPDATE))
  {
    for (i = 0; i < 8; i++)
    {
      for (j = 0; j < 8; j++) CharGadg_DrawChar(rp,gpr->gpr_GInfo,FALSE,
	(j*cgd->cg_CharWidth)+gadg->LeftEdge,
	(i*cgd->cg_CharHeight)+gadg->TopEdge,
	cgd->cg_CharWidth,cgd->cg_CharHeight,(cgd->cg_Pos*64)+(i*8)+j,
	gpr->gpr_Redraw == GREDRAW_REDRAW);
    }
  }
  if (old_tf) SetFont(rp,old_tf);
  return 0;
}

ULONG CharGadg_GOACTIVE(Class *cl,struct Gadget *gadg,struct gpInput *gpi)
{
struct CharGadgData *cgd = INST_DATA(cl,(Object *)gadg);
struct GadgetInfo *gi;
WORD i,j;
ULONG retval = GMR_NOREUSE;

  DoSuperMethodA(cl,(Object *)gadg,(Msg *)gpi);
  cgd->cg_FirstX = -1; cgd->cg_FirstY = -1; cgd->cg_Pressed = TRUE;
  j = gpi->gpi_Mouse.X / cgd->cg_CharWidth;
  i = gpi->gpi_Mouse.Y / cgd->cg_CharHeight;
  if ((i >= 0) && (i < 8) && (j >= 0) && (j < 8))
  {
    cgd->cg_FirstX = j; cgd->cg_FirstY = i;
    gi = gpi->gpi_GInfo;
    CharGadg_DrawCurrent(gi,cgd,gadg);
    retval = GMR_MEACTIVE;
  }
  return retval;
}

ULONG CharGadg_HANDLEINPUT(Class *cl,struct Gadget *gadg,struct gpInput *gpi)
{
struct GadgetInfo *gi = gpi->gpi_GInfo;
struct InputEvent *ie = gpi->gpi_IEvent;
struct CharGadgData *cgd = INST_DATA(cl,(Object *)gadg);
ULONG retval = GMR_MEACTIVE;
WORD i,j;

  if (gi->gi_Window)
  {
    if ((gi->gi_Window->Flags & WFLG_WINDOWACTIVE) == 0) return GMR_NOREUSE;
  }
  while (ie && (retval == GMR_MEACTIVE))
  {
    if (ie->ie_Class == IECLASS_RAWMOUSE)
    {
      if (ie->ie_Code != SELECTUP)
      {
	j = gpi->gpi_Mouse.X / cgd->cg_CharWidth;
	i = gpi->gpi_Mouse.Y / cgd->cg_CharHeight;
	if ((i == cgd->cg_FirstY) && (j == cgd->cg_FirstX))
	{
	  if (cgd->cg_Pressed == FALSE)
	  {
	    cgd->cg_Pressed = TRUE;
	    CharGadg_DrawCurrent(gi,cgd,gadg);
	  }
	}
	else
	{
	  if (cgd->cg_Pressed == TRUE)
	  {
	    cgd->cg_Pressed = FALSE;
	    CharGadg_DrawCurrent(gi,cgd,gadg);
	  }
	}
      }
      else retval = GMR_NOREUSE|GMR_VERIFY;
    }
    ie = ie->ie_NextEvent;
  }
  return retval;
}

ULONG CharGadg_GOINACTIVE(Class *cl,struct Gadget *gadg,
  struct gpGoInactive *gpgi)
{
struct CharGadgData *cgd = INST_DATA(cl,(Object *)gadg);
struct GadgetInfo *gi;
struct RastPort *rp;
struct TextFont *old_tf = NULL;
struct TagItem inactive;
ULONG retval;

  retval = DoSuperMethodA(cl,(Object *)gadg,(Msg *)gpgi);
  if ((cgd->cg_FirstX != -1) && (cgd->cg_FirstY != -1))
  {
    gi = gpgi->gpgi_GInfo;
    if (cgd->cg_Pressed == TRUE)
    {
      if (rp = ObtainGIRPort(gi))
      {
	if (rp->Font != cgd->cg_TextFont)
	{
	  old_tf = rp->Font;
	  SetFont(rp,cgd->cg_TextFont);
	}
	CharGadg_DrawChar(rp,gi,FALSE,
	  (cgd->cg_FirstX*cgd->cg_CharWidth)+gadg->LeftEdge,
	  (cgd->cg_FirstY*cgd->cg_CharHeight)+gadg->TopEdge,
	  cgd->cg_CharWidth,cgd->cg_CharHeight,
	  (cgd->cg_Pos*64)+(cgd->cg_FirstY*8)+cgd->cg_FirstX,TRUE);
	if (old_tf) SetFont(rp,old_tf);
	ReleaseGIRPort(rp);
      }
      cgd->cg_LastPressed =
	(cgd->cg_Pos*64)+(cgd->cg_FirstY*8)+cgd->cg_FirstX;
      Gadg_SetTag(&inactive,TAG_DONE,0);
      DoMethod(gadg,OM_NOTIFY,&inactive,gi,0);
    }
  }
  return retval;
}

ULONG CharGadg_SET(Class *cl,struct Gadget *gadg,struct opSet *ops)
{
struct TagItem *tags, *tag;
ULONG retval;
struct CharGadgData *cgd = INST_DATA(cl,(Object *)gadg);
struct RastPort *rp;

  retval = DoSuperMethodA(cl,(Object *)gadg,(Msg *)ops);
  tags = ops->ops_AttrList;
  if (tags)
  {
    if (tag = FindTagItem(CG_Pos,tags))
    {
      if ((tag->ti_Data >= 0) && (tag->ti_Data < 4))
      {
	if (cgd->cg_Pos != tag->ti_Data)
	{
	  cgd->cg_Pos = tag->ti_Data;
	  if (rp = ObtainGIRPort(ops->ops_GInfo))
	  {
	    DoMethod(gadg,GM_RENDER,ops->ops_GInfo,rp,GREDRAW_UPDATE);
	    ReleaseGIRPort(rp);
	  }
	}
      }
    }
    if (tag = FindTagItem(CG_Pressed,tags))
      cgd->cg_LastPressed = tag->ti_Data;
  }
  return retval;
}

ULONG CharGadg_GET(Class *cl,Object *o,struct opGet *opg)
{
struct CharGadgData *cgd = INST_DATA(cl,o);
ULONG retval = TRUE;

  switch (opg->opg_AttrID)
  {
    case CG_Pos:
      *(opg->opg_Storage) = cgd->cg_Pos;
      break;
    case CG_Pressed:
      *(opg->opg_Storage) = cgd->cg_LastPressed;
      break;
    default:
      retval = DoSuperMethodA(cl,o,(Msg *)opg);
      break;
  }
  return retval;
}

void CharGadg_DrawChar(struct RastPort *rp,struct GadgetInfo *gi,
  BOOL selected,ULONG x,ULONG y,ULONG w,ULONG h,char gchar, BOOL lines)
{
struct DrawInfo *dri = gi->gi_DrInfo;
UBYTE pen1,pen2,pen3,pen4;

  if (selected)
  {
    pen1 = dri->dri_Pens[SHADOWPEN];
    pen2 = dri->dri_Pens[SHINEPEN];
    pen3 = dri->dri_Pens[FILLTEXTPEN];
    pen4 = dri->dri_Pens[FILLPEN];
  }
  else
  {
    pen1 = dri->dri_Pens[SHINEPEN];
    pen2 = dri->dri_Pens[SHADOWPEN];
    pen3 = dri->dri_Pens[TEXTPEN];
    pen4 = dri->dri_Pens[BACKGROUNDPEN];
  }
  SetAPen(rp,pen4);
  if (lines)
  {
    RectFill(rp,x,y,x+w-1,y+h-1);
    Gadg_DrawBevel(rp,x,y,w,h,pen1,pen2);
  }
  else RectFill(rp,x+2,y+1,x+w-5,y+h-3);
  SetAPen(rp,pen3);
  SetBPen(rp,pen4);
  SetDrMd(rp,JAM2);
  Move(rp,x+CG_XOFFSET,y+CG_YOFFSET+rp->Font->tf_Baseline);
  Text(rp,&gchar,1);
}

void CharGadg_DrawCurrent(struct GadgetInfo *gi,struct CharGadgData *cgd,
  struct Gadget *gadg)
{
struct RastPort *rp;
struct TextFont *old_tf = NULL;

  if (rp = ObtainGIRPort(gi))
  {
    if (rp->Font != cgd->cg_TextFont)
    {
      old_tf = rp->Font;
      SetFont(rp,cgd->cg_TextFont);
    }
    CharGadg_DrawChar(rp,gi,cgd->cg_Pressed,
      (cgd->cg_FirstX*cgd->cg_CharWidth)+gadg->LeftEdge,
      (cgd->cg_FirstY*cgd->cg_CharHeight)+gadg->TopEdge,
      cgd->cg_CharWidth,cgd->cg_CharHeight,
      (cgd->cg_Pos*64)+(cgd->cg_FirstY*8)+cgd->cg_FirstX,TRUE);
    if (old_tf) SetFont(rp,old_tf);
    ReleaseGIRPort(rp);
  }
}

/* character editing gadget */

struct EditGadgData
{
  UWORD eg_PixelX,eg_PixelY;
  struct Character *eg_Char;
  UWORD eg_XOffset,eg_YOffset;
  struct CharNode *eg_Node;
  UWORD eg_Button, eg_PixelBorder;
};

__geta4 ULONG DispatchEditGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg);
ULONG EditGadg_NEW(Class *cl,Object *o,struct opSet *ops);
ULONG EditGadg_GET(Class *cl,Object *o,struct opGet *opg);
ULONG EditGadg_SET(Class *cl,struct Gadget *gadg,struct opSet *ops);
ULONG EditGadg_RENDER(Class *cl,struct Gadget *gadg,struct gpRender *gpr);
ULONG EditGadg_GOACTIVE(Class *cl,struct Gadget *gadg,struct gpInput *gpi);

Class *InitEditGadgClass(void)
{
Class *super, *cl = NULL;

  if (super = BGUI_GetClassPtr(BGUI_BASE_GADGET))
  {
    cl = MakeClass(NULL,NULL,super,sizeof(struct EditGadgData),0);
    if (cl) cl->cl_Dispatcher.h_Entry = DispatchEditGadg;
  }
  return cl;
}

BOOL FreeEditGadgClass(Class *cl)
{
  return FreeClass(cl);
}

void EditGadg_GetSize(struct EditGadgData *egd,UWORD w,UWORD h,
  UWORD *ew_ptr, UWORD *eh_ptr)
{
struct Character *chr;

  *ew_ptr = (w-(2*EG_XOFFSET))/(egd->eg_PixelX);
  *eh_ptr = (h-(2*EG_YOFFSET))/(egd->eg_PixelY);
  if (chr = egd->eg_Char)
  {
    if (*ew_ptr > chr->chr_Width) *ew_ptr = chr->chr_Width;
    if (*eh_ptr > chr->chr_Height) *eh_ptr = chr->chr_Height;
  }
}

void EditGadg_Draw(Object *o, struct GadgetInfo *gi,ULONG draw)
{
struct RastPort *rp;

  if (rp = ObtainGIRPort(gi))
  {
    DoMethod(o,GM_RENDER,gi,rp,draw);
    ReleaseGIRPort(rp);
  }
}

__geta4 ULONG DispatchEditGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg)
{
ULONG retval;

  switch (msg->MethodID)
  {
    case OM_NEW:
      retval = EditGadg_NEW(cl,o,(struct opSet *)msg);
      break;
    case OM_GET:
      retval = EditGadg_GET(cl,o,(struct opGet *)msg);
      break;
    case OM_SET:
    case OM_UPDATE:
      retval = EditGadg_SET(cl,(struct Gadget *)o,(struct opSet *)msg);
      break;
    case GM_RENDER:
      retval = EditGadg_RENDER(cl,(struct Gadget *)o,(struct gpRender *)msg);
      break;
    case GM_GOACTIVE:
      retval = EditGadg_GOACTIVE(cl,(struct Gadget *)o,
	(struct gpInput *)msg);
      break;
    default:
      retval = DoSuperMethodA(cl,o,(Msg *)msg);
      break;
  }
  return retval;
}

ULONG EditGadg_NEW(Class *cl,Object *o,struct opSet *ops)
{
ULONG retval = 0;
struct EditGadgData *egd;

  retval = (ULONG)DoSuperMethodA(cl,o,(Msg *)ops);
  if (retval)
  {
    egd = INST_DATA(cl,retval);
    egd->eg_PixelX = GetTagData(EG_PixelX,32,ops->ops_AttrList);
    egd->eg_PixelY = GetTagData(EG_PixelY,16,ops->ops_AttrList);
    egd->eg_Char = (struct Character *)
      GetTagData(EG_CharStruct,0,ops->ops_AttrList);
    egd->eg_XOffset = 0;
    egd->eg_YOffset = 0;
    egd->eg_Node = (struct CharNode *)
      GetTagData(EG_CharNode,0,ops->ops_AttrList);
    egd->eg_Button = 0;
    egd->eg_PixelBorder = GetTagData(EG_PixelBorder,1,ops->ops_AttrList);
  }
  return retval;
}

ULONG EditGadg_RENDER(Class *cl,struct Gadget *gadg,struct gpRender *gpr)
{
struct RastPort *rp;
struct EditGadgData *egd = INST_DATA(cl,(Object *)gadg);
struct DrawInfo *dri = gpr->gpr_GInfo->gi_DrInfo;
struct Character *chr;
UBYTE pen1,pen2,pen3;
UWORD ew,eh,i,j,x,y,w,h,p;

  rp = gpr->gpr_RPort;
  if ((gpr->gpr_Redraw==GREDRAW_REDRAW)||(gpr->gpr_Redraw==GREDRAW_UPDATE))
  {
    if ((chr = egd->eg_Char) == NULL) return 0;
    pen1 = dri->dri_Pens[SHINEPEN];
    pen2 = dri->dri_Pens[SHADOWPEN];
    pen3 = dri->dri_Pens[BACKGROUNDPEN];
    SetAfPt(rp,NULL,0);
    x = gadg->LeftEdge; y = gadg->TopEdge;
    w = gadg->Width; h = gadg->Height;
    if (gpr->gpr_Redraw == GREDRAW_REDRAW)
    {
      SetAPen(rp,pen3);
      RectFill(rp,x,y,x+w-1,y+h-1);
    }
    EditGadg_GetSize(egd,w,h,&ew,&eh);
    w = (ew*(egd->eg_PixelX))+(2*EG_XOFFSET);
    h = (eh*(egd->eg_PixelY))+(2*EG_YOFFSET);
    p = (egd->eg_PixelBorder != 0) ? 2 : 1;
    Gadg_DrawBevel(rp,x,y,w,h,pen1,pen2);
    if (chr->chr_Data)
    {
      for (i = 0; i < ew; i++)
      {
	for (j = 0; j < eh; j++)
	{
	  SetAPen(rp,(*(chr->chr_Data+((j+egd->eg_YOffset)*chr->chr_Width)+
	    i+egd->eg_XOffset) != 0) ? pen2 : pen3);
	  RectFill(rp,(i*egd->eg_PixelX)+x+EG_XOFFSET,
	    (j*egd->eg_PixelY)+y+EG_YOFFSET,
	    ((i+1)*egd->eg_PixelX)+x+EG_XOFFSET-p,
	    ((j+1)*egd->eg_PixelY)+y+EG_YOFFSET-p);
	}
      }
    }
  }
  return 0;
}

ULONG EditGadg_GET(Class *cl,Object *o,struct opGet *opg)
{
struct EditGadgData *egd = INST_DATA(cl,o);
ULONG retval = TRUE;
UWORD ew,eh;

  switch (opg->opg_AttrID)
  {
    case EG_Width:
      EditGadg_GetSize(egd,((struct Gadget *)o)->Width,
	((struct Gadget *)o)->Height,&ew,&eh);
      *(opg->opg_Storage) = ew;
      break;
    case EG_Height:
      EditGadg_GetSize(egd,((struct Gadget *)o)->Width,
	((struct Gadget *)o)->Height,&ew,&eh);
      *(opg->opg_Storage) = eh;
      break;
    case EG_XOffset:
      *(opg->opg_Storage) = egd->eg_XOffset;
      break;
    case EG_YOffset:
      *(opg->opg_Storage) = egd->eg_YOffset;
      break;
    default:
      retval = DoSuperMethodA(cl,o,(Msg *)opg);
      break;
  }
  return retval;
}

ULONG EditGadg_SET(Class *cl,struct Gadget *gadg,struct opSet *ops)
{
struct TagItem *tags, *tag;
ULONG retval,pos;
UWORD ew,eh;
struct EditGadgData *egd = INST_DATA(cl,(Object *)gadg);

  retval = DoSuperMethodA(cl,(Object *)gadg,(Msg *)ops);
  EditGadg_GetSize(egd,gadg->Width,gadg->Height,&ew,&eh);
  tags = ops->ops_AttrList;
  if (tags)
  {
    if (tag = FindTagItem(EG_Update,tags))
    {
      switch (tag->ti_Data)
      {
	case GADG_HORIZ:
	  if (egd->eg_Node)
	  {
	    GetAttr(PGA_Top,egd->eg_Node->chln_HorizGadg,&pos);
	    if (egd->eg_XOffset != pos)
	    {
	      egd->eg_XOffset = pos;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	    }
	  }
	  break;
	case GADG_VERT:
	  if (egd->eg_Node)
	  {
	    GetAttr(PGA_Top,egd->eg_Node->chln_VertGadg,&pos);
	    if (egd->eg_YOffset != pos)
	    {
	      egd->eg_YOffset = pos;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	    }
	  }
	  break;
	case GADG_LEFT:
	  if (egd->eg_XOffset > 0)
	  {
	    if ((egd->eg_Button = 1-egd->eg_Button) == 0)
	    {
	      egd->eg_XOffset--;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	      SetGadgetAttrs(egd->eg_Node->chln_HorizGadg,
		egd->eg_Node->chln_Window,NULL,PGA_Top,egd->eg_XOffset,
		TAG_DONE);
	    }
	  }
	  break;
	case GADG_RIGHT:
	  if (egd->eg_XOffset + ew < egd->eg_Char->chr_Width)
	  {
	    if ((egd->eg_Button = 1-egd->eg_Button) == 0)
	    {
	      egd->eg_XOffset++;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	      SetGadgetAttrs(egd->eg_Node->chln_HorizGadg,
		egd->eg_Node->chln_Window,NULL,PGA_Top,egd->eg_XOffset,
		TAG_DONE);
	    }
	  }
	  break;
	case GADG_UP:
	  if (egd->eg_YOffset > 0)
	  {
	    if ((egd->eg_Button = 1-egd->eg_Button) == 0)
	    {
	      egd->eg_YOffset--;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	      SetGadgetAttrs(egd->eg_Node->chln_VertGadg,
		egd->eg_Node->chln_Window,NULL,PGA_Top,egd->eg_YOffset,
		TAG_DONE);
	    }
	  }
	  break;
	case GADG_DOWN:
	  if (egd->eg_YOffset + eh < egd->eg_Char->chr_Height)
	  {
	    if ((egd->eg_Button = 1-egd->eg_Button) == 0)
	    {
	      egd->eg_YOffset++;
	      EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
	      SetGadgetAttrs(egd->eg_Node->chln_VertGadg,
		egd->eg_Node->chln_Window,NULL,PGA_Top,egd->eg_YOffset,
		TAG_DONE);
	    }
	  }
	  break;
	case GADG_NONE:
	  egd->eg_XOffset = 0;
	  egd->eg_YOffset = 0;
	  EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_REDRAW);
	  break;
      }
    }
    if (tag = FindTagItem(EG_XOffset,tags))
    {
      if (egd->eg_XOffset != tag->ti_Data)
      {
	egd->eg_XOffset = tag->ti_Data;
	EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
      }
    }
    if (tag = FindTagItem(EG_YOffset,tags))
    {
      if (egd->eg_YOffset != tag->ti_Data)
      {
	egd->eg_YOffset = tag->ti_Data;
	EditGadg_Draw(gadg,ops->ops_GInfo,GREDRAW_UPDATE);
      }
    }
  }
  return retval;
}

ULONG EditGadg_GOACTIVE(Class *cl,struct Gadget *gadg,struct gpInput *gpi)
{
struct EditGadgData *egd = INST_DATA(cl,(Object *)gadg);
struct DrawInfo *dri = gpi->gpi_GInfo->gi_DrInfo;
struct RastPort *rp;
struct Character *chr;
UBYTE *pixel;
WORD i,j;
UWORD ew,eh,p;
UBYTE pen1,pen2;

  DoSuperMethodA(cl,(Object *)gadg,(Msg *)gpi);
  EditGadg_GetSize(egd,gadg->Width,gadg->Height,&ew,&eh);
  i = (gpi->gpi_Mouse.X - EG_XOFFSET) / egd->eg_PixelX;
  j = (gpi->gpi_Mouse.Y - EG_YOFFSET) / egd->eg_PixelY;
  if ((i >= 0) && (i < ew) && (j >= 0) && (j < eh))
  {
    if ((chr = egd->eg_Char) == NULL) return GMR_NOREUSE;
    if (chr->chr_Data == NULL)
    {
      if ((chr->chr_Data = AllocVec(chr->chr_Width*chr->chr_Height,
	MEMF_CLEAR)) == NULL) return GMR_NOREUSE;
    }
    pixel =
      chr->chr_Data+((j+egd->eg_YOffset)*chr->chr_Width)+i+egd->eg_XOffset;
    if (rp = ObtainGIRPort(gpi->gpi_GInfo))
    {
      pen1 = dri->dri_Pens[SHADOWPEN];
      pen2 = dri->dri_Pens[BACKGROUNDPEN];
      p = (egd->eg_PixelBorder != 0) ? 2 : 1;
      SetAfPt(rp,NULL,0);
      *pixel = 1-(*pixel);
      SetAPen(rp,*pixel == 1 ? pen1 : pen2);
      RectFill(rp,(i*egd->eg_PixelX)+gadg->LeftEdge+EG_XOFFSET,
	(j*egd->eg_PixelY)+gadg->TopEdge+EG_YOFFSET,
	((i+1)*egd->eg_PixelX)+gadg->LeftEdge+EG_XOFFSET-p,
	((j+1)*egd->eg_PixelY)+gadg->TopEdge+EG_YOFFSET-p);
      ReleaseGIRPort(rp);
    }
  }
  return GMR_NOREUSE;
}

/* slider gadget subclass */

struct SlideGadgData
{
  ULONG sg_Total,sg_Visible;
};

__geta4 ULONG DispatchSlideGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg);
ULONG SlideGadg_NOTIFY(Class *cl,Object *o,struct opUpdate *opu);
ULONG SlideGadg_NEW(Class *cl,Object *o,struct opSet *ops);
ULONG SlideGadg_SET(Class *cl,Object *o,struct opSet *ops);

Class *InitSlideGadgClass(void)
{
Class *super, *cl = NULL;

  if (super = BGUI_GetClassPtr(BGUI_PROP_GADGET))
  {
    cl = MakeClass(NULL,NULL,super,0,0);
    if (cl) cl->cl_Dispatcher.h_Entry = DispatchSlideGadg;
  }
  return cl;
}

BOOL FreeSlideGadgClass(Class *cl)
{
  return FreeClass(cl);
}

__geta4 ULONG DispatchSlideGadg(__a0 Class *cl,__a2 Object *o,__a1 Msg msg)
{
ULONG retval;

  switch (msg->MethodID)
  {
    case OM_NEW:
      retval = SlideGadg_NEW(cl,o,(struct opSet *)msg);
      break;
    case OM_SET:
    case OM_UPDATE:
      retval = SlideGadg_SET(cl,o,(struct opSet *)msg);
      break;
    case OM_NOTIFY:
      retval = SlideGadg_NOTIFY(cl,o,(struct opUpdate *)msg);
      break;
    default:
      retval = DoSuperMethodA(cl,o,(Msg *)msg);
      break;
  }
  return retval;
}

ULONG SlideGadg_NEW(Class *cl,Object *o,struct opSet *ops)
{
ULONG retval = 0;
struct SlideGadgData *sgd;

  retval = (ULONG)DoSuperMethodA(cl,o,(Msg *)ops);
  if (retval)
  {
    sgd = INST_DATA(cl,retval);
    sgd->sg_Total = GetTagData(PGA_Total,0,ops->ops_AttrList);
    sgd->sg_Visible = GetTagData(PGA_Visible,0,ops->ops_AttrList);
  }
  return retval;
}

ULONG SlideGadg_SET(Class *cl,Object *o,struct opSet *ops)
{
struct SlideGadgData *sgd = INST_DATA(cl,o);
struct GadgetInfo *gi = ops->ops_GInfo;
struct TagItem *tags, *tag;
struct TagItem inactive;
ULONG retval;

  retval = DoSuperMethodA(cl,o,(Msg *)ops);
  tags = ops->ops_AttrList;
  if (tags)
  {
    if (tag = FindTagItem(PGA_Total,tags)) sgd->sg_Total = tag->ti_Data;
    if (tag = FindTagItem(PGA_Visible,tags)) sgd->sg_Visible = tag->ti_Data;
    Gadg_SetTag(&inactive,TAG_DONE,0);
    DoMethod((struct Gadget *)o,OM_NOTIFY,&inactive,gi,0);
  }
  return retval;
}

ULONG SlideGadg_NOTIFY(Class *cl,Object *o,struct opUpdate *opu)
{
struct SlideGadgData *sgd = INST_DATA(cl,o);
struct TagItem tags[3];
ULONG pos = 0;

  GetAttr(PGA_Top,o,&pos);
  Gadg_SetTag(&tags[0],GA_ID,((struct Gadget *)o)->GadgetID);
  Gadg_SetTag(&tags[1],SCRL_Right,sgd->sg_Total-sgd->sg_Visible-pos);
  if (opu->opu_AttrList == NULL)
    Gadg_SetTag(&tags[2],TAG_DONE,0);
  else
    Gadg_SetTag(&tags[2],TAG_MORE,(ULONG)opu->opu_AttrList);
  return DoSuperMethod(cl,o,OM_NOTIFY,tags,opu->opu_GInfo,opu->opu_Flags);
}
