/*********************/
/*		     */
/* Character editing */
/*		     */
/*********************/

#include "Typeface.h"

ULONG PixelBorder = 1;
extern struct Preferences Prefs;

struct VectorItem LineArrowLeft[] =
  { 10,10,VIF_SCALE,
    SHADOWPEN,0,VIF_DRIPEN,
     2, 5,VIF_MOVE,
     8, 2,VIF_DRAW,
     8, 8,VIF_DRAW,
     2, 5,VIF_DRAW,
     0, 0,VIF_LASTITEM };
struct VectorItem LineArrowRight[] =
  { 10,10,VIF_SCALE,
    SHADOWPEN,0,VIF_DRIPEN,
     8, 5,VIF_MOVE,
     2, 2,VIF_DRAW,
     2, 8,VIF_DRAW,
     8, 5,VIF_DRAW,
     0, 0,VIF_LASTITEM };
struct VectorItem SolidArrowLeft[] =
  { 10,10,VIF_SCALE,
    SHADOWPEN,0,VIF_AOLDRIPEN,
     0, 0,VIF_AREASTART,
     2, 5,VIF_MOVE,
     8, 2,VIF_DRAW,
     8, 8,VIF_DRAW,
     2, 5,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem SolidArrowRight[] =
  { 10,10,VIF_SCALE,
    SHADOWPEN,0,VIF_AOLDRIPEN,
     0, 0,VIF_AREASTART,
     8, 5,VIF_MOVE,
     2, 2,VIF_DRAW,
     2, 8,VIF_DRAW,
     8, 5,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem SolidArrowUp[] =
  { 11,11,VIF_SCALE,
    SHADOWPEN,0,VIF_AOLDRIPEN,
     0, 0,VIF_AREASTART,
     5, 2,VIF_MOVE,
     2, 8,VIF_DRAW,
     8, 8,VIF_DRAW,
     5, 2,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem SolidArrowDown[] =
  { 11,11,VIF_SCALE,
    SHADOWPEN,0,VIF_AOLDRIPEN,
     0, 0,VIF_AREASTART,
     5, 8,VIF_MOVE,
     2, 2,VIF_DRAW,
     8, 2,VIF_DRAW,
     5, 8,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem KernImage[] =
  { 11,11,VIF_SCALE,
    SHINEPEN,0,VIF_AOLDRIPEN,
    SHINEPEN,0,VIF_DRIPEN,
     0, 0,VIF_AREASTART,
     2, 2,VIF_MOVE,
     2, 8,VIF_DRAW,
     5, 8,VIF_DRAW,
     2, 2,VIF_DRAW,
     0, 0,VIF_AREAEND,
    SHADOWPEN,0,VIF_AOLDRIPEN,
    SHADOWPEN,0,VIF_DRIPEN,
     0, 0,VIF_AREASTART,
     5, 2,VIF_MOVE,
     8, 2,VIF_DRAW,
     8, 8,VIF_DRAW,
     5, 2,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem WidthImage[] =
  { 10,10,VIF_SCALE,
    SHINEPEN,0,VIF_DRIPEN,
    SHADOWPEN,0,VIF_AOLDRIPEN,
     0, 0,VIF_AREASTART,
     2, 5,VIF_MOVE,
     8, 2,VIF_DRAW,
     8, 8,VIF_DRAW,
     2, 5,VIF_DRAW,
     0, 0,VIF_AREAEND,
     0, 0,VIF_LASTITEM };
struct VectorItem ZoomInImage[] =
  { 22,10,VIF_SCALE,
    SHADOWPEN,0,VIF_DRIPEN,
     5, 5,VIF_MOVE,
    16, 5,VIF_DRAW,
    10, 2,VIF_MOVE
    10, 8,VIF_DRAW,
    11, 2,VIF_MOVE
    11, 8,VIF_DRAW,
     0, 0,VIF_LASTITEM };
struct VectorItem ZoomOutImage[] =
  { 22,10,VIF_SCALE,
    SHADOWPEN,0,VIF_DRIPEN,
     5, 5,VIF_MOVE,
    16, 5,VIF_DRAW,
     0, 0,VIF_LASTITEM };

struct CharNode *OpenCharWin(ULONG charnum,struct IBox size)
{
extern struct Screen *Screen;
extern struct List *CharWndList;
extern struct MsgPort *WndMsgPort;
extern struct Image *SizeImage, *LeftImage, *RightImage;
extern struct Image *UpImage, *DownImage;
extern Class *EditClass;
extern struct Character CharBuffer[256];
extern BOOL MaxWindow, ShowBLine, DataChanged;
extern ULONG Baseline;
extern struct NewMenu CharMenus[];

struct CharNode *node;
Object *extobj, *toolbar, *toolbarsub, *wingroup;
ULONG gw,gh,top;
UWORD width,height;
static ULONG scroll2edit[] = { GA_ID,EG_Update,TAG_DONE };

  if ((node = CreateNode(sizeof(struct CharNode),CharWndList)) == NULL)
    Quit();
  if ((node->chln_Title = AllocVec(256,MEMF_CLEAR)) == NULL)
    ErrorCode(ALLOCVEC);
  if (charnum > 0)
  {
    if (charnum == 256)
      sprintf(node->chln_Title,GetString(msgBlankTitle));
    else
      sprintf(node->chln_Title,GetString(msgCharTitle),
      (char)charnum,charnum,charnum);
  }
  else sprintf(node->chln_Title,GetString(msgZeroTitle));
  if ((node->chln_Hook = AllocVec(sizeof(struct Hook),MEMF_CLEAR)) == NULL)
    ErrorCode(ALLOCVEC);
  node->chln_Hook->h_Entry = CharHook;
  node->chln_Hook->h_Data = node;
  node->chln_Character = CharBuffer+charnum;
  node->chln_Number = charnum;
  width = (Prefs.PixelX*node->chln_Character->chr_Width)+(2*EG_XOFFSET)+
    (2*SizeX(4))+Screen->WBorLeft+UpImage->Width;
  if (width < size.Width) size.Width = width;
  if (MaxWindow) size.Width = width;
  height = (Prefs.PixelY*node->chln_Character->chr_Height)+(2*EG_YOFFSET)+1+
    (2*SizeY(2))+Screen->WBorTop+Screen->Font->ta_YSize+LeftImage->Height;

  toolbar =
    BGUI_NewObject(BGUI_GROUP_GADGET,GROUP_Spacing,SizeX(4),TAG_DONE);
  if (Prefs.ToolBar & (FTBAR_WIDTHL|FTBAR_WIDTHR))
  {
    toolbarsub = BGUI_NewObject(BGUI_GROUP_GADGET,TAG_DONE);
    if (Prefs.ToolBar & FTBAR_WIDTHL)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,LineArrowLeft,
	  ButtonFrame,
	  GA_ID,ID_WIDTHL,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_WIDTHR)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,LineArrowRight,
	  ButtonFrame,
	  GA_ID,ID_WIDTHR,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    DoMethod(toolbar,GRM_ADDMEMBER,toolbarsub,TAG_DONE);
  }
  if (Prefs.ToolBar & (FTBAR_MOVEL|FTBAR_MOVER|FTBAR_MOVEU|FTBAR_MOVED))
  {
    if (node->chln_ToolBarWidth) node->chln_ToolBarWidth += SizeX(4);
    toolbarsub = BGUI_NewObject(BGUI_GROUP_GADGET,TAG_DONE);
    if (Prefs.ToolBar & FTBAR_MOVEL)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,SolidArrowLeft,
	  ButtonFrame,
	  GA_ID,ID_MOVEL,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_MOVER)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,SolidArrowRight,
	  ButtonFrame,
	  GA_ID,ID_MOVER,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_MOVEU)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,SolidArrowUp,
	  ButtonFrame,
	  GA_ID,ID_MOVEU,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_MOVED)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,SolidArrowDown,
	  ButtonFrame,
	  GA_ID,ID_MOVED,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    DoMethod(toolbar,GRM_ADDMEMBER,toolbarsub,TAG_DONE);
  }
  if (Prefs.ToolBar & (FTBAR_KERN|FTBAR_WIDTH))
  {
    if (node->chln_ToolBarWidth) node->chln_ToolBarWidth += SizeX(4);
    toolbarsub = BGUI_NewObject(BGUI_GROUP_GADGET,TAG_DONE);
    if (Prefs.ToolBar & FTBAR_KERN)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,KernImage,
	  ButtonFrame,
	  GA_ID,ID_KERNING,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_WIDTH)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,WidthImage,
	  ButtonFrame,
	  GA_ID,ID_WIDTHC,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    DoMethod(toolbar,GRM_ADDMEMBER,toolbarsub,TAG_DONE);
  }
  if (Prefs.ToolBar & (FTBAR_ZOOMIN|FTBAR_ZOOMOUT))
  {
    if (node->chln_ToolBarWidth) node->chln_ToolBarWidth += SizeX(4);
    toolbarsub = BGUI_NewObject(BGUI_GROUP_GADGET,TAG_DONE);
    if (Prefs.ToolBar & FTBAR_ZOOMIN)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,ZoomInImage,
	  ButtonFrame,
	  GA_ID,ID_ZOOMIN,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    if (Prefs.ToolBar & FTBAR_ZOOMOUT)
    {
      DoMethod(toolbarsub,GRM_ADDMEMBER,
	ButtonObject,
	  VIT_VectorArray,ZoomOutImage,
	  ButtonFrame,
	  GA_ID,ID_ZOOMOUT,
	EndObject,
	FixWidth(22),FixHeight(Prefs.VecHeight),TAG_DONE);
      node->chln_ToolBarWidth += 22;
    }
    DoMethod(toolbar,GRM_ADDMEMBER,toolbarsub,TAG_DONE);
  }

  if (node->chln_ToolBarWidth > 0)
  {
    height += Prefs.VecHeight+SizeY(2);
    node->chln_ToolBarHeight = Prefs.VecHeight+SizeY(2);
  }
  if (height < size.Height) size.Height = height;
  SetupMenus(CharMenus);

  node->chln_Object = WindowObject,
    WINDOW_Screen,Screen,
    WINDOW_SharedPort,WndMsgPort,
    WINDOW_MenuStrip,CharMenus,
    WINDOW_Title,node->chln_Title,
    WINDOW_Bounds,&size,
    WINDOW_HelpFile,NAME".guide",
    WINDOW_HelpNode,"char",
    WINDOW_IDCMPHook,node->chln_Hook,
    WINDOW_IDCMPHookBits,IDCMP_CHANGEWINDOW,
    WINDOW_SizeRight,TRUE,
    WINDOW_SizeBottom,TRUE,
    WINDOW_CloseOnEsc,TRUE,
    WINDOW_MasterGroup,
      wingroup = VGroupObject,
	HOffset(SizeX(4)),VOffset(SizeY(2)),Spacing(SizeY(2)),
	StartMember,
	  extobj = ExternalObject,
	    EXT_MinWidth,(2*Prefs.PixelX)+(2*EG_XOFFSET)-2,
	    EXT_MinHeight,(2*Prefs.PixelY)+(2*EG_YOFFSET)-2,
	    EXT_Class,EditClass,
	    EXT_NoRebuild,TRUE,
	    EG_PixelX,Prefs.PixelX,
	    EG_PixelY,Prefs.PixelY,
	    EG_CharNode,node,
	    EG_CharStruct,node->chln_Character,
	    EG_PixelBorder,PixelBorder,
	    EG_ShowBaseline,ShowBLine,
	    EG_Baseline,Baseline,
	    EG_ChangePtr,&DataChanged,
	    GA_Disabled,FALSE,
	    GA_ID,ID_EDIT,
	  EndObject,
	EndMember,
      EndObject,
    EndObject;
  if (node->chln_Object == NULL) ErrorCode(NEWWINDOW);
  node->chln_MinPixelX = Prefs.PixelX;
  node->chln_MinPixelY = Prefs.PixelY;
  node->chln_CurPixelX = node->chln_MinPixelX;
  node->chln_CurPixelY = node->chln_MinPixelY;
  if (node->chln_ToolBarHeight > 0)
    DoMethod(wingroup,GRM_INSERTMEMBER,toolbar,NULL,FixMinSize,TAG_DONE);
  if ((node->chln_Window = WindowOpen(node->chln_Object)) == NULL)
    ErrorCode(OPENWINDOW);

  gh = MAX(LeftImage->Height,RightImage->Height);
  gh = MAX(SizeImage->Height,gh);
  gw = MAX(UpImage->Width,DownImage->Width);
  gw = MAX(SizeImage->Width,gw);
  top = Screen->WBorTop+Screen->Font->ta_YSize+1;
  GetAttr(EXT_Object,extobj,&(node->chln_EditGadg));

  if ((node->chln_HorizGadg = CreatePropGadg(FREEHORIZ,
    GA_Left,3,
    GA_RelBottom,3-gh,
    GA_RelWidth,-5-gw-LeftImage->Width-RightImage->Width,
    GA_Height,gh-4,
    GA_BottomBorder,TRUE,
    GA_ID,GADG_HORIZ,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,
    PGA_Total,node->chln_Character->chr_Width,
    PGA_Visible,node->chln_Character->chr_Width,TAG_DONE)) == NULL)
      ErrorCode(NEWPROP);
  if ((node->chln_VertGadg = CreatePropGadg(FREEVERT,
    GA_RelRight,5-gw,
    GA_Top,top+1,
    GA_Width,gw-8,
    GA_RelHeight,-top-SizeImage->Height-UpImage->Height-DownImage->Height-2,
    GA_RightBorder,TRUE,
    GA_Previous,node->chln_HorizGadg,
    GA_ID,GADG_VERT,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,
    PGA_Total,node->chln_Character->chr_Height,
    PGA_Visible,node->chln_Character->chr_Height,TAG_DONE)) == NULL)
      ErrorCode(NEWPROP);

  if ((node->chln_LeftGadg = CreateButtonGadg(LeftImage,
    GA_RelRight,1-LeftImage->Width-RightImage->Width-gw,
    GA_RelBottom,1-LeftImage->Height,
    GA_BottomBorder,TRUE,
    GA_Previous,node->chln_VertGadg,
    GA_ID,GADG_LEFT,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,TAG_DONE)) == NULL) ErrorCode(NEWBUTTON);
  if ((node->chln_RightGadg = CreateButtonGadg(RightImage,
    GA_RelRight,1-RightImage->Width-gw,
    GA_RelBottom,1-RightImage->Height,
    GA_BottomBorder,TRUE,
    GA_Previous,node->chln_LeftGadg,
    GA_ID,GADG_RIGHT,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,TAG_DONE)) == NULL) ErrorCode(NEWBUTTON);
  if ((node->chln_UpGadg = CreateButtonGadg(UpImage,
    GA_RelRight,1-UpImage->Width,
    GA_RelBottom,1-UpImage->Height-DownImage->Height-SizeImage->Height,
    GA_RightBorder,TRUE,
    GA_Previous,node->chln_RightGadg,
    GA_ID,GADG_UP,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,TAG_DONE)) == NULL) ErrorCode(NEWBUTTON);
  if ((node->chln_DownGadg = CreateButtonGadg(DownImage,
    GA_RelRight,1-DownImage->Width,
    GA_RelBottom,1-DownImage->Height-SizeImage->Height,
    GA_RightBorder,TRUE,
    GA_Previous,node->chln_UpGadg,
    GA_ID,GADG_DOWN,
    ICA_TARGET,node->chln_EditGadg,
    ICA_MAP,scroll2edit,TAG_DONE)) == NULL) ErrorCode(NEWBUTTON);

  AddGList(node->chln_Window,node->chln_HorizGadg,-1,-1,NULL);
  SetScrollers(node);
  RefreshGList(node->chln_HorizGadg,node->chln_Window,NULL,-1);
}

void CloseCharWin(struct CharNode *node)
{
extern struct Window *WidthWnd, *KernWnd;
extern struct CharNode *WidthNode, *KernNode;

  ClrWindowClose(&(node->chln_Object),&(node->chln_Window));
  ClrDisposeObject(&(node->chln_Object));
  if (node->chln_Title)
  {
    FreeVec(node->chln_Title);
    node->chln_Title = NULL;
  }
  ClrDisposeObject(&(node->chln_HorizGadg));
  ClrDisposeObject(&(node->chln_VertGadg));
  ClrDisposeObject(&(node->chln_LeftGadg));
  ClrDisposeObject(&(node->chln_RightGadg));
  ClrDisposeObject(&(node->chln_UpGadg));
  ClrDisposeObject(&(node->chln_DownGadg));
  if (node->chln_Hook)
  {
    FreeVec(node->chln_Hook);
    node->chln_Hook = NULL;
  }
  if ((WidthWnd) && (WidthNode == node)) CloseWidthWnd(FALSE);
  if ((KernWnd) && (KernNode == node)) CloseKernWnd(FALSE);
}

Object *CreateSysImage(ULONG which,struct DrawInfo *dri)
{
  return (NewObject(NULL,SYSICLASS,
    SYSIA_DrawInfo,dri,
    SYSIA_Which,which,TAG_DONE));
}

Object *CreatePropGadg(ULONG freedom,Tag tag1,...)
{
  return (NewObject(NULL,PROPGCLASS,
    PGA_Freedom,freedom,
    PGA_NewLook,TRUE,
    PGA_Borderless,TRUE,
    TAG_MORE,&tag1));
}

Object *CreateButtonGadg(Object *image,Tag tag1,...)
{
  return (NewObject(NULL,BUTTONGCLASS,
    GA_Image,image,
    TAG_MORE,&tag1));
}

__geta4 void CharHook(__a0 struct Hook *hook, __a2 Object *o,
  __a1 struct IntuiMessage *msg)
{
  if ((msg->Class == IDCMP_CHANGEWINDOW) && (msg->Code == CWCODE_MOVESIZE))
    ForceResizeChar(hook->h_Data);
}

void ForceResizeChar(struct CharNode *node)
{
struct Character *chr;
LONG l,t,w,h;

  chr = node->chln_Character;
  GetAttr(EG_XOffset,node->chln_EditGadg,&l);
  GetAttr(EG_YOffset,node->chln_EditGadg,&t);
  GetAttr(EG_Width,node->chln_EditGadg,&w);
  GetAttr(EG_Height,node->chln_EditGadg,&h);
  if (chr->chr_Width - l < w) l = chr->chr_Width - w;
  if (l < 0) l = 0;
  if (chr->chr_Height - t < h) t = chr->chr_Height - h;
  if (t < 0) t = 0;
  SetGadgetAttrs(node->chln_EditGadg,node->chln_Window,NULL,
    EG_XOffset,l,EG_YOffset,t,TAG_DONE);
  SetScrollers(node);
}

void SetScrollers(struct CharNode *node)
{
ULONG l,t,w,h;

  GetAttr(EG_XOffset,node->chln_EditGadg,&l);
  GetAttr(EG_YOffset,node->chln_EditGadg,&t);
  GetAttr(EG_Width,node->chln_EditGadg,&w);
  GetAttr(EG_Height,node->chln_EditGadg,&h);
  SetGadgetAttrs(node->chln_HorizGadg,node->chln_Window,NULL,
    PGA_Top,l,PGA_Visible,w,TAG_DONE);
  SetGadgetAttrs(node->chln_VertGadg,node->chln_Window,NULL,
    PGA_Top,t,PGA_Visible,h,TAG_DONE);
}

void RedrawEdit(struct CharNode *node)
{
  SetGadgetAttrs(node->chln_HorizGadg,node->chln_Window,NULL,
    PGA_Total,node->chln_Character->chr_Width,TAG_DONE);
  SetGadgetAttrs(node->chln_VertGadg,node->chln_Window,NULL,
    PGA_Total,node->chln_Character->chr_Height,TAG_DONE);
  SetGadgetAttrs(node->chln_EditGadg,node->chln_Window,NULL,
    EG_Baseline,Baseline,
    EG_Update,GADG_NONE,TAG_DONE);
  ForceResizeChar(node);
}

void MoveLeft(struct CharNode *node,struct Character *chr)
{
ULONG i,j;

  if (node != NULL) chr = node->chln_Character;
  if ((chr->chr_Data) && (chr->chr_Width > 0))
  {
    for (j = 0; j < chr->chr_Height; j++)
    {
      for (i = 0; i < chr->chr_Width-1; i++) DATA(i,j) = DATA(i+1,j);
      DATA(chr->chr_Width-1,j) = 0;
    }
    if (node != NULL) RedrawEdit(node);
  }
}

void MoveRight(struct CharNode *node,struct Character *chr)
{
ULONG i,j;

  if (node != NULL) chr = node->chln_Character;
  if ((chr->chr_Data) && (chr->chr_Width > 0))
  {
    for (j = 0; j < chr->chr_Height; j++)
    {
      for (i = chr->chr_Width-1; i > 0; i--) DATA(i,j) = DATA(i-1,j);
      DATA(0,j) = 0;
    }
    if (node != NULL) RedrawEdit(node);
  }
}

void MoveUp(struct CharNode *node,struct Character *chr)
{
ULONG i,j;

  if (node != NULL) chr = node->chln_Character;
  if ((chr->chr_Data) && (chr->chr_Height > 0))
  {
    for (i = 0; i < chr->chr_Width; i++)
    {
      for (j = 0; j < chr->chr_Height-1; j++) DATA(i,j) = DATA(i,j+1);
      DATA(i,chr->chr_Height-1) = 0;
    }
    if (node != NULL) RedrawEdit(node);
  }
}

void MoveDown(struct CharNode *node,struct Character *chr)
{
ULONG i,j;

  if (node != NULL) chr = node->chln_Character;
  if ((chr->chr_Data) && (chr->chr_Height > 0))
  {
    for (i = 0; i < chr->chr_Width; i++)
    {
      for (j = chr->chr_Height-1; j > 0; j--) DATA(i,j) = DATA(i,j-1);
      DATA(i,0) = 0;
    }
    if (node != NULL) RedrawEdit(node);
  }
}

void MoveAll(void (*MoveFunction)())
{
struct Character *chr;
ULONG i;

  for (i = 0; i < 257; i++)
  {
    chr = CharBuffer+i;
    MoveFunction(NULL,chr);
  }
  RedrawAll();
}

void RedrawAll()
{
struct CharNode *node;

  node = CharWndList->lh_Head;
  while (node->chln_Node.ln_Succ)
  {
    RedrawEdit(node);
    CheckWidthKern(node->chln_Character);
    node = node->chln_Node.ln_Succ;
  }
}

void ZoomIn(struct CharNode *node)
{
ULONG x,y,max_x,max_y;

  GetAttr(EG_PixelX,node->chln_EditGadg,&x);
  GetAttr(EG_PixelY,node->chln_EditGadg,&y);

  max_x = node->chln_Window->Width-(2*EG_XOFFSET)-(2*SizeX(4))-
    Screen->WBorLeft-UpImage->Width;
  max_y = node->chln_Window->Height-(2*EG_YOFFSET)-1-(2*SizeY(2))-
    Screen->WBorTop-Screen->Font->ta_YSize-LeftImage->Height-
    node->chln_ToolBarHeight;

  if ((x*4 <= max_x) && (y*4 <= max_y))
  {
    SetGadgetAttrs(node->chln_EditGadg,node->chln_Window,NULL,
      EG_PixelX,x*2,
      EG_PixelY,y*2,
      EG_Update,GADG_NONE,TAG_DONE);
    SetScrollers(node);
    SetMinWindowSize(node,x);
  }
  else DisplayBeep(node->chln_Window->WScreen);
}

void ZoomOut(struct CharNode *node)
{
ULONG x,y;

  GetAttr(EG_PixelX,node->chln_EditGadg,&x);
  GetAttr(EG_PixelY,node->chln_EditGadg,&y);

  if ((x/2 >= 2) && (y/2 >= 2))
  {
    SetGadgetAttrs(node->chln_EditGadg,node->chln_Window,NULL,
      EG_PixelX,x/2,
      EG_PixelY,y/2,
      EG_Update,GADG_NONE,TAG_DONE);
    SetScrollers(node);
    SetMinWindowSize(node,x);
  }
  else DisplayBeep(node->chln_Window->WScreen);
}

void SetMinWindowSize(struct CharNode *node, ULONG oldx)
{
ULONG x,y;

  GetAttr(EG_PixelX,node->chln_EditGadg,&x);
  GetAttr(EG_PixelY,node->chln_EditGadg,&y);

  if (2*(oldx+EG_XOFFSET) < node->chln_ToolBarWidth)
  {
    if (2*(x+EG_XOFFSET) > node->chln_ToolBarWidth)
    {
      node->chln_Window->MinWidth -= node->chln_ToolBarWidth;
      node->chln_Window->MinWidth += 2*(x+EG_XOFFSET);
    }
  }
  else
  {
    if (2*(x+EG_XOFFSET) < node->chln_ToolBarWidth)
    {
      node->chln_Window->MinWidth += node->chln_ToolBarWidth;
      node->chln_Window->MinWidth -= 2*(node->chln_CurPixelX+EG_XOFFSET);
    }
    else
    {
      node->chln_Window->MinWidth += 2*MAX(x,node->chln_MinPixelX);
      node->chln_Window->MinWidth -= 2*node->chln_CurPixelX;
    }
  }
  node->chln_CurPixelX = MAX(x,node->chln_MinPixelX);

  node->chln_Window->MinHeight += 2*MAX(y,node->chln_MinPixelY);
  node->chln_Window->MinHeight -= 2*node->chln_CurPixelY;
  node->chln_CurPixelY = MAX(y,node->chln_MinPixelY);
}
