/*
 * dockwindow.c  V2.0
 *
 * dock edit window handling
 *
 * (c) 1990-1992 Stefan Becker
 */

#include "ToolManagerConf.h"

struct DockNode {
                 struct Node      dn_Node;
                 ULONG            dn_Flags;
                 char            *dn_HotKey;
                 char            *dn_PubScreen;
                 char            *dn_Title;
                 struct TextAttr  dn_Font;
                 char            *dn_FontDesc;
                 LONG             dn_XPos;
                 LONG             dn_YPos;
                 ULONG            dn_Columns;
                 struct List     *dn_ToolsList;
                };

/* Window data */
static struct Gadget *gl;             /* Gadget list */
static struct Window *w;              /* Window */
static struct MsgPort *wp;            /* Window user port */
static UWORD ww,wh;                   /* Window size */
static struct DockNode *CurrentNode;
static struct Gadget *CurrentGadget;
static ULONG CurrentGadgetNum;
static BOOL ReqOpen;
#define WINDOW_IDCMP (IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW|BUTTONIDCMP|\
                      CHECKBOXIDCMP|STRINGIDCMP)

/* Gadget data */
#define GAD_NAME_STR     0 /* Gadgets with labels (left side) */
#define GAD_TITLE_STR    1
#define GAD_HOTKEY_STR   2
#define GAD_XPOS_INT     3
#define GAD_YPOS_INT     4
#define GAD_COLUMNS_INT  5

#define GAD_POSITION     6 /* Cycle gadget */

#define GAD_PSCREEN_BUT  7 /* Gadgets with labels (right side) */
#define GAD_FONT_BUT     8

#define GAD_PSCREEN_STR  9
#define GAD_FONT_TXT    10

#define GAD_TOOLS       11 /* Button gadget */

#define GAD_ACTIVATED   12 /* Checkbox gadgets */
#define GAD_CENTERED    13
#define GAD_FRONTMOST   14
#define GAD_MENU        15
#define GAD_PATTERN     16
#define GAD_POPUP       17
#define GAD_TEXT        18
#define GAD_VERTICAL    19

#define GAD_OK          20 /* Button gadgets */
#define GAD_CANCEL      21
#define GADGETS         22
static struct GadgetData gdata[GADGETS];

/* Gadget tags */
static struct TagItem nametags[]={GTST_String,   NULL,
                                  GTST_MaxChars, 100,
                                  TAG_DONE};

static struct TagItem hotktags[]={GTST_String,   NULL,
                                  GTST_MaxChars, 100,
                                  TAG_DONE};

static struct TagItem pbsctags[]={GTST_String,   NULL,
                                  GTST_MaxChars, 100,
                                  TAG_DONE};

static struct TagItem fonttags[]={GTTX_Text,   NULL,
                                  GTTX_Border, TRUE,
                                  TAG_DONE};

static struct TagItem titletags[]={GTST_String,   NULL,
                                   GTST_MaxChars, 100,
                                   TAG_DONE};

static struct TagItem xpostags[]={GTIN_Number,   0,
                                  GTIN_MaxChars, 10,
                                  TAG_DONE};

static struct TagItem ypostags[]={GTIN_Number,   0,
                                  GTIN_MaxChars, 10,
                                  TAG_DONE};

static char *cyclelabels[3]={NULL, NULL, NULL};
static struct TagItem cycletags[]={GTCY_Labels, cyclelabels,
                                   GTCY_Active, 0,
                                   TAG_DONE};

static struct TagItem colstags[]={GTIN_Number,   0,
                                  GTIN_MaxChars, 10,
                                  TAG_DONE};

static struct TagItem actitags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

static struct TagItem centtags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

static struct TagItem fronttags[]={GTCB_Checked, FALSE,
                                   TAG_DONE};

static struct TagItem menutags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

static struct TagItem patttags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

static struct TagItem popuptags[]={GTCB_Checked, FALSE,
                                   TAG_DONE};

static struct TagItem texttags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

static struct TagItem verttags[]={GTCB_Checked, FALSE,
                                  TAG_DONE};

/* Init dock edit window */
void InitDockEditWindow(UWORD left, UWORD fheight)
{
 ULONG llabwidth,lgadwidth,rlabwidth,rgadwidth;
 ULONG cycwidth,cbwidth,butwidth,minstringwidth;
 ULONG strheight=fheight+2;
 ULONG i,tmp,yadd;
 struct GadgetData *gd;

 /* Init strings */
 gdata[GAD_NAME_STR].name    =AppStrings[MSG_WINDOW_NAME_GAD];
 gdata[GAD_TITLE_STR].name   =AppStrings[MSG_DOCKWIN_TITLE_GAD];
 gdata[GAD_HOTKEY_STR].name  =AppStrings[MSG_WINDOW_HOTKEY_GAD];
 gdata[GAD_XPOS_INT].name    =AppStrings[MSG_WINDOW_LEFTEDGE_GAD];
 gdata[GAD_YPOS_INT].name    =AppStrings[MSG_WINDOW_TOPEDGE_GAD];
 gdata[GAD_COLUMNS_INT].name =AppStrings[MSG_DOCKWIN_COLUMNS_GAD];
 cyclelabels[0]              =AppStrings[MSG_WINDOW_POSITION_OPEN_LABEL];
 cyclelabels[1]              =AppStrings[MSG_WINDOW_POSITION_CLOSE_LABEL];
 gdata[GAD_PSCREEN_BUT].name =AppStrings[MSG_WINDOW_PUBSCREEN_GAD];
 gdata[GAD_FONT_BUT].name    =AppStrings[MSG_DOCKWIN_FONT_GAD];
 gdata[GAD_TOOLS].name       =AppStrings[MSG_DOCKWIN_EDITTOOLS_GAD];
 gdata[GAD_ACTIVATED].name   =AppStrings[MSG_DOCKWIN_ACTIVATED_GAD];
 gdata[GAD_CENTERED].name    =AppStrings[MSG_DOCKWIN_CENTERED_GAD];
 gdata[GAD_FRONTMOST].name   =AppStrings[MSG_DOCKWIN_FRONTMOST_GAD];
 gdata[GAD_MENU].name        =AppStrings[MSG_DOCKWIN_MENU_GAD];
 gdata[GAD_PATTERN].name     =AppStrings[MSG_DOCKWIN_PATTERN_GAD];
 gdata[GAD_POPUP].name       =AppStrings[MSG_DOCKWIN_POPUP_GAD];
 gdata[GAD_TEXT].name        =AppStrings[MSG_DOCKWIN_TEXT_GAD];
 gdata[GAD_VERTICAL].name    =AppStrings[MSG_DOCKWIN_VERTICAL_GAD];
 gdata[GAD_OK].name          =AppStrings[MSG_WINDOW_OK_GAD];
 gdata[GAD_CANCEL].name      =AppStrings[MSG_WINDOW_CANCEL_GAD];

 /* Calculate maximum label width (left side) */
 llabwidth=0;
 gd=&gdata[GAD_NAME_STR];
 for (i=GAD_NAME_STR; i<=GAD_COLUMNS_INT; i++, gd++)
  if ((tmp=TextLength(&TmpRastPort,gd->name,strlen(gd->name))) > llabwidth)
   llabwidth=tmp;
 llabwidth+=INTERWIDTH;

 /* Calculate maximum gadget width (left side) */
 minstringwidth=TextLength(&TmpRastPort,AppStrings[MSG_DOCKWIN_NEWNAME],
                           strlen(AppStrings[MSG_DOCKWIN_NEWNAME]))
                +2*INTERWIDTH;
 lgadwidth=minstringwidth;

 /* Calculate maximum cyclegadget width */
 {
  char **s;

  cycwidth=0;
  s=cyclelabels;
  for (i=0; i<=1; i++, s++)
   if ((tmp=TextLength(&TmpRastPort,*s,strlen(*s))) > cycwidth)
    cycwidth=tmp;
  cycwidth+=5*INTERWIDTH;
 }
 if ((llabwidth+lgadwidth+INTERWIDTH) < cycwidth)
  lgadwidth=cycwidth-llabwidth-INTERWIDTH;

 /* Calculate maximum label width (right side) */
 gd=&gdata[GAD_PSCREEN_BUT];
 rlabwidth=TextLength(&TmpRastPort,gd->name,strlen(gd->name))+INTERWIDTH;
 gd++;
 if ((tmp=TextLength(&TmpRastPort,gd->name,strlen(gd->name))+2*INTERWIDTH)
      > rlabwidth)
  rlabwidth=tmp;

 /* Calculate maximum gadget width (right side) */
 rgadwidth=minstringwidth+REQBUTTONWIDTH;

 /* Calculate maximum button gadget width */
 gd=&gdata[GAD_TOOLS];
 butwidth=TextLength(&TmpRastPort,gd->name,strlen(gd->name))+2*INTERWIDTH;
 if ((rlabwidth+rgadwidth+INTERWIDTH) < butwidth)
  rgadwidth=butwidth-rlabwidth-INTERWIDTH;

 /* Calculate maximum checkbox gadget width */
 cbwidth=0;
 gd=&gdata[GAD_ACTIVATED];
 for (i=GAD_ACTIVATED; i<=GAD_VERTICAL; i++, gd++)
  if ((tmp=TextLength(&TmpRastPort,gd->name,strlen(gd->name))) > cbwidth)
   cbwidth=tmp;
 cbwidth+=CHKBOXWIDTH+INTERWIDTH;
 if ((rlabwidth+rgadwidth) < 2*cbwidth)
  rgadwidth=2*cbwidth-rlabwidth;

 /* Calculate minimum window width */
 ww=llabwidth+lgadwidth+rlabwidth+rgadwidth+4*INTERWIDTH;

 /* Calculate button gadgets width */
 gd=&gdata[GAD_OK];
 butwidth=TextLength(&TmpRastPort,gd->name,strlen(gd->name));
 gd++;
 if ((tmp=TextLength(&TmpRastPort,gd->name,strlen(gd->name))) > butwidth)
  butwidth=tmp;
 butwidth+=2*INTERWIDTH;
 if ((tmp=2*(butwidth+INTERWIDTH)) > ww) ww=tmp;

 /* Calculate minimum window height */
 wh=8*fheight+9*INTERHEIGHT+14;

 /* Init gadgets */
 gd=gdata;
 tmp=(ww-llabwidth-lgadwidth-rlabwidth-rgadwidth-4*INTERWIDTH)/2;
 lgadwidth+=tmp; /* String gadget length (left) */
 rgadwidth+=tmp; /* String gadget length (right) */
 llabwidth+=left+INTERWIDTH;
 tmp=WindowTop+INTERHEIGHT;
 yadd=strheight+INTERHEIGHT;

 /* Name string gadget */
 gd->type=STRING_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=nametags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;
 tmp+=yadd;

 /* Title string gadget */
 gd++;
 gd->type=STRING_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=titletags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;
 tmp+=yadd;

 /* HotKey string gadget */
 gd++;
 gd->type=STRING_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=hotktags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;
 tmp+=2*yadd;

 /* LeftEdge integer gadget */
 gd++;
 gd->type=INTEGER_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=xpostags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;
 tmp+=yadd;

 /* TopEdge integer gadget */
 gd++;
 gd->type=INTEGER_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=ypostags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;
 tmp+=yadd;

 /* Columns integer gadget */
 gd++;
 gd->type=INTEGER_KIND;
 gd->flags=PLACETEXT_LEFT;
 gd->tags=colstags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=lgadwidth;
 gd->height=strheight;

 /* Position cycle gadget */
 tmp=WindowTop+3*yadd+INTERHEIGHT;
 gd++;
 gd->type=CYCLE_KIND;
 gd->flags=PLACETEXT_IN;
 gd->tags=cycletags;
 gd->left=left;
 gd->top=tmp;
 gd->width=lgadwidth+llabwidth-left;
 gd->height=strheight;

 /* PubScreen button gadget */
 tmp=WindowTop+INTERHEIGHT;
 llabwidth=ww-rgadwidth-INTERWIDTH+left;
 gd++;
 gd->type=GENERIC_KIND;
 gd->flags=0;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=REQBUTTONWIDTH;
 gd->height=strheight;
 tmp+=yadd;

 /* Font button gadget */
 gd++;
 gd->type=BUTTON_KIND;
 gd->flags=PLACETEXT_IN;
 gd->left=llabwidth-rlabwidth-INTERWIDTH;
 gd->top=tmp;
 gd->width=rlabwidth;
 gd->height=strheight;

 /* PubScreen string gadget */
 tmp=WindowTop+INTERHEIGHT;
 gd++;
 gd->type=STRING_KIND;
 gd->tags=pbsctags;
 gd->left=llabwidth+REQBUTTONWIDTH;
 gd->top=tmp;
 gd->width=rgadwidth-REQBUTTONWIDTH;
 gd->height=strheight;
 tmp+=yadd;

 /* Font text gadget */
 gd++;
 gd->type=TEXT_KIND;
 gd->tags=fonttags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=rgadwidth;
 gd->height=strheight;
 tmp+=yadd;

 /* Tools button gadget */
 llabwidth-=rlabwidth+INTERWIDTH;
 gd++;
 gd->type=BUTTON_KIND;
 gd->flags=PLACETEXT_IN;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=ww-llabwidth-INTERWIDTH+left;
 gd->height=strheight;
 tmp+=yadd+1;

 /* Activated checkbox gadget */
 rlabwidth=(ww-llabwidth-INTERWIDTH+left-2*cbwidth)/3;
 llabwidth+=rlabwidth;
 cbwidth+=llabwidth+rlabwidth;

 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=actitags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;

 /* Centered checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=centtags;
 gd->left=cbwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;
 tmp+=yadd;

 /* Frontmost checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=fronttags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;

 /* Menu checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=menutags;
 gd->left=cbwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;
 tmp+=yadd;

 /* Pattern checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=patttags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;

 /* PopUp checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=popuptags;
 gd->left=cbwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;
 tmp+=yadd;

 /* Text checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=texttags;
 gd->left=llabwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;

 /* Vertical checkbox gadget */
 gd++;
 gd->type=CHECKBOX_KIND;
 gd->flags=PLACETEXT_RIGHT;
 gd->tags=verttags;
 gd->left=cbwidth;
 gd->top=tmp;
 gd->width=CHKBOXWIDTH;
 gd->height=strheight;
 tmp+=yadd-1;

 /* OK button gadget */
 gd++;
 gd->type=BUTTON_KIND;
 gd->flags=PLACETEXT_IN;
 gd->left=left;
 gd->top=tmp;
 gd->width=butwidth;
 gd->height=fheight;

 /* Cancel button gadget */
 gd++;
 gd->type=BUTTON_KIND;
 gd->flags=PLACETEXT_IN;
 gd->left=ww-butwidth-INTERWIDTH+left;
 gd->top=tmp;
 gd->width=butwidth;
 gd->height=fheight;
}

/* Free dock node */
void FreeDockNode(struct Node *node)
{
 struct DockNode *dn=node;
 char *s;

 if (s=dn->dn_Node.ln_Name) free(s);
 if (s=dn->dn_HotKey) free(s);
 if (s=dn->dn_PubScreen) free(s);
 if (s=dn->dn_Title) free(s);
 if (s=dn->dn_Font.ta_Name) free(s);
 if (s=dn->dn_FontDesc) free(s);

 /* Free tool list */
 if (dn->dn_ToolsList) FreeToolsList(dn->dn_ToolsList);

 /* Free node */
 FreeMem(dn,sizeof(struct DockNode));
}

/* Build font descriptor string */
static char *BuildFontDesc(struct TextAttr *ta)
{
 char *name;

 if (name=strdup(ta->ta_Name)) {
  ULONG len=strlen(name);
  UWORD size=ta->ta_YSize%10000; /* Safety hack... */
  UWORD div=1000;
  char *s=&name[len-5];
  BOOL InNumber=FALSE;

  /* Overwrite ".font" */
  *s++='/';
  while (div) {
   char c=size/div+'0';

   if ((c!='0') || InNumber) {
    *s++=c;
    InNumber=TRUE;
   }
   size%=div;
   div/=10;
  }
  *s++='\0';
 }
 return(name);
}

/* Copy dock node */
struct Node *CopyDockNode(struct Node *node)
{
 struct DockNode *dn,*orignode=node;

 /* Alloc memory for exec node */
 if (dn=AllocMem(sizeof(struct DockNode),MEMF_PUBLIC|MEMF_CLEAR)) {
  /* Got an old node? */
  if (orignode) {
   /* Yes, copy it */
   if ((!orignode->dn_Node.ln_Name || (dn->dn_Node.ln_Name=
                                        strdup(orignode->dn_Node.ln_Name))) &&
       (!orignode->dn_HotKey || (dn->dn_HotKey=strdup(orignode->dn_HotKey))) &&
       (!orignode->dn_PubScreen || (dn->dn_PubScreen=
                                     strdup(orignode->dn_PubScreen))) &&
       (!orignode->dn_Title || (dn->dn_Title=strdup(orignode->dn_Title))) &&
       (!orignode->dn_Font.ta_Name ||
        ((dn->dn_Font.ta_Name=strdup(orignode->dn_Font.ta_Name)) &&
         (dn->dn_FontDesc=BuildFontDesc(&orignode->dn_Font)))) &&
       (!orignode->dn_ToolsList || (dn->dn_ToolsList=
                                     CopyToolsList(orignode->dn_ToolsList)))) {
    /* Copy flags & numbers */
    dn->dn_XPos=orignode->dn_XPos;
    dn->dn_YPos=orignode->dn_YPos;
    dn->dn_Columns=orignode->dn_Columns;
    dn->dn_Font.ta_YSize=orignode->dn_Font.ta_YSize;
    dn->dn_Font.ta_Style=orignode->dn_Font.ta_Style;
    dn->dn_Font.ta_Flags=orignode->dn_Font.ta_Flags;
    dn->dn_Flags=orignode->dn_Flags;

    /* Return pointer to new node */
    return(dn);
   }
  } else {
   /* No, set defaults */
   if (dn->dn_Node.ln_Name=strdup(AppStrings[MSG_DOCKWIN_NEWNAME])) {
    dn->dn_Columns=1;
    dn->dn_Flags=DOPOF_ACTIVATED;

    /* Return pointer to new node */
    return(dn);
   }
  }

  FreeDockNode((struct Node *) dn);
 }
 /* Call failed */
 return(NULL);
}

/* Activate gadget and save pointer to it */
static ActivateAndSetGadget(ULONG num)
{
 CurrentGadget=gdata[num].gadget;
 ActivateGadget(CurrentGadget,w,NULL);
}

/* Open dock edit window */
BOOL OpenDockEditWindow(struct Node *node, struct Window *parent)
{
 /* Copy node */
 if (CurrentNode=CopyDockNode(node)) {
  /* Set tags */
  nametags[0].ti_Data=CurrentNode->dn_Node.ln_Name;
  titletags[0].ti_Data=CurrentNode->dn_Title;
  hotktags[0].ti_Data=CurrentNode->dn_HotKey;
  xpostags[0].ti_Data=CurrentNode->dn_XPos;
  ypostags[0].ti_Data=CurrentNode->dn_YPos;
  colstags[0].ti_Data=CurrentNode->dn_Columns;
  pbsctags[0].ti_Data=CurrentNode->dn_PubScreen;
  fonttags[0].ti_Data=CurrentNode->dn_FontDesc;
  actitags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_ACTIVATED)!=0;
  centtags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_CENTERED)!=0;
  fronttags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_FRONTMOST)!=0;
  menutags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_MENU)!=0;
  patttags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_PATTERN)!=0;
  popuptags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_POPUP)!=0;
  texttags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_TEXT)!=0;
  verttags[0].ti_Data=(CurrentNode->dn_Flags & DOPOF_VERTICAL)!=0;

  /* Create gadgets */
  if (gl=CreateGadgetList(gdata,GADGETS)) {
   /* Open window */
   if (w=OpenWindowTags(NULL,WA_Left,parent->LeftEdge,
                             WA_Top,parent->TopEdge+WindowTop,
                             WA_InnerWidth,ww,
                             WA_InnerHeight,wh,
                             WA_AutoAdjust,TRUE,
                             WA_Title,AppStrings[MSG_DOCKWIN_TITLE],
                             WA_PubScreen,PublicScreen,
                             WA_Flags,WFLG_CLOSEGADGET|WFLG_DRAGBAR|
                                      WFLG_DEPTHGADGET|WFLG_RMBTRAP|
                                      WFLG_ACTIVATE,
                             TAG_DONE)) {
    /* Init requester button gadgets */
    InitReqButtonGadget(gdata[GAD_PSCREEN_BUT].gadget);

    /* Add gadgets to window */
    AddGList(w,gl,(UWORD) -1,(UWORD) -1,NULL);
    RefreshGList(gl,w,NULL,(UWORD) -1);
    GT_RefreshWindow(w,NULL);

    /* Activate name string gadget */
    ActivateAndSetGadget(GAD_NAME_STR);

    /* Set local variables */
    w->UserPort=IDCMPPort;
    w->UserData=HandleDockEditWindowIDCMP;
    ModifyIDCMP(w,WINDOW_IDCMP);
    CurrentWindow=w;
    ReqOpen=FALSE;

    /* All OK. */
    return(TRUE);
   }
   FreeGadgets(gl);
  }
  FreeDockNode((struct Node *) CurrentNode);
 }
 /* Call failed */
 return(FALSE);
}

/* Close dock edit window */
static void CloseDockEditWindow(void)
{
 /* Free resources */
 if (MoveWindowPtr) CloseMoveWindow();
 RemoveGList(w,gl,(UWORD) -1);
 CloseWindowSafely(w);
 FreeGadgets(gl);
}

/* If move window open, move it to new position */
static void MoveMoveWindow(void)
{
 /* Move window open? */
 if (MoveWindowPtr) {
  ULONG x,y;

  /* Read current position */
  x=((struct StringInfo *) gdata[GAD_XPOS_INT].gadget->SpecialInfo)->LongInt;
  y=((struct StringInfo *) gdata[GAD_YPOS_INT].gadget->SpecialInfo)->LongInt;

  /* Move move window */
  MoveWindow(MoveWindowPtr,x-MoveWindowPtr->LeftEdge,y-MoveWindowPtr->TopEdge);
 }
}

/* Handle dock edit window IDCMP events */
void *HandleDockEditWindowIDCMP(struct IntuiMessage *msg)
{
 struct Node *NewNode=NULL;

 /* Which IDCMP class? */
 switch (msg->Class) {
  case IDCMP_CLOSEWINDOW:   NewNode=(struct Node *) -1;
                            FreeDockNode((struct Node *) CurrentNode);
                            break;
  case IDCMP_REFRESHWINDOW: GT_BeginRefresh(w);
                            GT_EndRefresh(w,TRUE);
                            break;
  case IDCMP_GADGETUP:
   switch (((struct Gadget *) msg->IAddress)->GadgetID) {
    case GAD_NAME_STR:    ActivateAndSetGadget(GAD_TITLE_STR);
                          break;
    case GAD_TITLE_STR:   ActivateAndSetGadget(GAD_HOTKEY_STR);
                          break;
    case GAD_HOTKEY_STR:  ActivateAndSetGadget(GAD_XPOS_INT);
                          break;
    case GAD_XPOS_INT:    MoveMoveWindow();
                          ActivateAndSetGadget(GAD_YPOS_INT);
                          break;
    case GAD_YPOS_INT:    MoveMoveWindow();
                          ActivateAndSetGadget(GAD_COLUMNS_INT);
                          break;
    case GAD_COLUMNS_INT: ActivateAndSetGadget(GAD_PSCREEN_STR);
                          break;
    case GAD_POSITION:    /* Move window open? */
                          if (MoveWindowPtr)
                           /* Yes, close move window */
                           CloseMoveWindow();
                          else {
                           /* No. Open it! */
                           MoveWindowOffX=0;
                           MoveWindowOffY=0;

                           /* Open move window */
                           OpenMoveWindow(w,gdata[GAD_XPOS_INT].gadget,
                                            gdata[GAD_YPOS_INT].gadget);
                          }

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_PSCREEN_BUT: if (!ReqOpen) {
                           /* Save current gadget number */
                           CurrentGadgetNum=GAD_PSCREEN_BUT;

                           /* Open list requester */
                           if (OpenListRequester(LISTREQ_PUBSC,w)) {
                            /* Disable window */
                            DisableWindow(w);

                            /* Set update function */
                            UpdateWindow=UpdateDockEditWindow;
                            ReqOpen=TRUE;
                           } else
                            ActivateGadget(CurrentGadget,w,NULL);
                          }
                          break;
    case GAD_FONT_BUT:    {
                           struct TextAttr *newta;

                           /* Set old font */
                           newta=(CurrentNode->dn_FontDesc) ?
                                  &CurrentNode->dn_Font : NULL;

                           /* Open font requester */
                           if (newta=OpenFontRequester(w,newta)) {

                            /* Font specified? */
                            if (newta->ta_Name) {
                             char *fontdesc;

                             /* Build font descriptor */
                             if (fontdesc=BuildFontDesc(newta)) {
                              /* All OK. Set new font */
                              GT_SetGadgetAttrs(gdata[GAD_FONT_TXT].gadget,w,
                                                NULL,GTTX_Text,fontdesc,
                                                     TAG_DONE);

                              /* Throw away old font */
                              if (CurrentNode->dn_FontDesc) {
                               free(CurrentNode->dn_Font.ta_Name);
                               free(CurrentNode->dn_FontDesc);
                              }

                              /* Set new font */
                              CurrentNode->dn_Font=*(newta);
                              CurrentNode->dn_FontDesc=fontdesc;
                             }
                            } else
                             /* User selected NO font, delete old one */
                             if (CurrentNode->dn_FontDesc) {
                              GT_SetGadgetAttrs(gdata[GAD_FONT_TXT].gadget,w,
                                                NULL,GTTX_Text,NULL,
                                                     TAG_DONE);
                              /* Free strings */
                              free(CurrentNode->dn_Font.ta_Name);
                              CurrentNode->dn_Font.ta_Name=NULL;
                              free(CurrentNode->dn_FontDesc);
                              CurrentNode->dn_FontDesc=NULL;
                             }
                           }

                           ActivateGadget(CurrentGadget,w,NULL);
                          }
                          break;
    case GAD_PSCREEN_STR: ActivateAndSetGadget(GAD_NAME_STR);
                          break;
    case GAD_FONT_TXT:
                          break;
    case GAD_ACTIVATED:   /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_ACTIVATED;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_CENTERED:    /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_CENTERED;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_FRONTMOST:   /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_FRONTMOST;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_MENU:        /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_MENU;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_PATTERN:     /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_PATTERN;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_POPUP:       /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_POPUP;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_TEXT:        /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_TEXT;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_VERTICAL:    /* Toggle flag */
                          CurrentNode->dn_Flags^=DOPOF_VERTICAL;

                          /* Activate old string gadget */
                          ActivateGadget(CurrentGadget,w,NULL);
                          break;
    case GAD_TOOLS:       if (!ReqOpen) {
                           /* Save current gadget number */
                           CurrentGadgetNum=GAD_TOOLS;

                           /* Open edit window */
                           if (OpenDockListEditWindow(CurrentNode->dn_ToolsList,
                                                      w)) {
                            /* Disable window */
                            DisableWindow(w);

                            /* Set update function */
                            UpdateWindow=UpdateDockEditWindow;
                            ReqOpen=TRUE;
                           } else
                            DisplayBeep(NULL);
                          }
                          break;
    case GAD_OK: {
     char *s;

     /* Free old string */
     if (s=CurrentNode->dn_Node.ln_Name) free(s);
     if (s=CurrentNode->dn_HotKey) free(s);
     if (s=CurrentNode->dn_PubScreen) free(s);
     if (s=CurrentNode->dn_Title) free(s);

     /* Duplicate new string */
     if (((CurrentNode->dn_Node.ln_Name=
           DuplicateBuffer(gdata[GAD_NAME_STR].gadget)) != (char *) -1) &&
         ((CurrentNode->dn_HotKey=
            DuplicateBuffer(gdata[GAD_HOTKEY_STR].gadget)) != (char *) -1) &&
         ((CurrentNode->dn_PubScreen=
            DuplicateBuffer(gdata[GAD_PSCREEN_STR].gadget)) != (char *) -1) &&
         ((CurrentNode->dn_Title=
            DuplicateBuffer(gdata[GAD_TITLE_STR].gadget)) != (char *) -1)) {
      /* Copy integer gadget values */
      CurrentNode->dn_XPos=
       ((struct StringInfo *) gdata[GAD_XPOS_INT].gadget->SpecialInfo)->LongInt;
      CurrentNode->dn_YPos=
       ((struct StringInfo *) gdata[GAD_YPOS_INT].gadget->SpecialInfo)->LongInt;
      CurrentNode->dn_Columns=
       ((struct StringInfo *) gdata[GAD_COLUMNS_INT].gadget->SpecialInfo)
        ->LongInt;

      NewNode=CurrentNode;
     } else {
      /* Couldn't copy strings */
      NewNode=(struct Node *) -1;
      CurrentNode->dn_Node.ln_Name=NULL;
      CurrentNode->dn_HotKey=NULL;
      CurrentNode->dn_PubScreen=NULL;
      CurrentNode->dn_Title=NULL;
      FreeDockNode((struct Node *) CurrentNode);
     }
    }
    break;
    case GAD_CANCEL:      NewNode=(struct Node *) -1;
                          FreeDockNode((struct Node *) CurrentNode);
                          break;
   }
   break;
 }

 /* Close window? */
 if (NewNode) {
  /* Yes. But first reply message!!! */
  GT_ReplyIMsg(msg);
  CloseDockEditWindow();
 }

 return(NewNode);
}

/* Update dock edit window */
void UpdateDockEditWindow(void *data)
{
 /* Which data? */
 switch (CurrentGadgetNum) {
  case GAD_PSCREEN_BUT: /* Got data? */
                        if (data != LREQRET_CANCEL) {
                         char *new;

                         /* Selected something? */
                         new=(data == LREQRET_NOSELECT) ?
                              NULL : ((struct Node *) data)->ln_Name;

                         /* set new public screen name */
                         GT_SetGadgetAttrs(gdata[GAD_PSCREEN_STR].gadget,w,
                                           NULL,GTST_String,new,TAG_DONE);
                        }
                        break;
  case GAD_TOOLS:       /* Got data? */
                        if (data != (void *) -1) {
                         /* Free old tools list */
                         if (CurrentNode->dn_ToolsList)
                          FreeToolsList(CurrentNode->dn_ToolsList);

                         /* Set new tools list */
                         CurrentNode->dn_ToolsList=data;
                        }
                        break;
 }

 /* Activate old string gadget */
 ActivateGadget(CurrentGadget,w,NULL);

 /* Enable window */
 EnableWindow(w,WINDOW_IDCMP);

 /* Restore update function pointer */
 UpdateWindow=UpdateMainWindow;
 CurrentWindow=w;
 ReqOpen=FALSE;
}

/* Read TMDO IFF chunk into Dock node */
struct Node *ReadDockNode(UBYTE *buf)
{
 struct DockNode *dn;

 /* Allocate memory for node */
 if (dn=AllocMem(sizeof(struct DockNode),MEMF_PUBLIC|MEMF_CLEAR)) {
  struct DockPrefsObject *dpo=buf;
  ULONG sbits=dpo->dpo_StringBits;
  UBYTE *ptr=dpo+1;
  struct List *toolslist;

  if ((!(sbits & DOPO_NAME) || (dn->dn_Node.ln_Name=GetConfigStr(&ptr))) &&
      (!(sbits & DOPO_HOTKEY) || (dn->dn_HotKey=GetConfigStr(&ptr))) &&
      (!(sbits & DOPO_PSCREEN) || (dn->dn_PubScreen=GetConfigStr(&ptr))) &&
      (!(sbits & DOPO_TITLE) || (dn->dn_Title=GetConfigStr(&ptr))) &&
      (!(sbits & DOPO_FONTNAME) || (dn->dn_Font.ta_Name=GetConfigStr(&ptr))) &&
      (toolslist=malloc(sizeof(struct List)))) {
   LONG tools=0;
   UBYTE tlflags;

   /* Init list */
   NewList(toolslist);
   dn->dn_ToolsList=toolslist;

   /* Get tools */
   while ((tlflags=*ptr++) & DOPOT_CONTINUE) {
    struct ToolNode *tn;

    if (tn=AllocMem(sizeof(struct ToolNode),MEMF_PUBLIC|MEMF_CLEAR))
     if ((!(tlflags & DOPOT_EXEC) || (tn->tn_Node.ln_Name=
                                       GetConfigStr(&ptr))) &&
         (!(tlflags & DOPOT_IMAGE) || (tn->tn_Image=GetConfigStr(&ptr))) &&
         (!(tlflags & DOPOT_SOUND) || (tn->tn_Sound=GetConfigStr(&ptr)))) {
      /* Add tool to list */
      AddTail(toolslist,(struct Node *) tn);

      /* All OK. */
      tools++;
     } else {
      /* Error */
      tools=-1;
      break;
     }
    else {
     /* No memory. */
     tools=-1;
     break;
    }
   }

   /* Error? */
   if (tools!=-1) {
    /* Got tools? */
    if (tools==0) {
     /* No, free list structure */
     free(toolslist);
     dn->dn_ToolsList=NULL;
    }

    /* Copy flags & values */
    dn->dn_Flags=dpo->dpo_Flags;
    dn->dn_XPos=dpo->dpo_XPos;
    dn->dn_YPos=dpo->dpo_YPos;
    dn->dn_Columns=dpo->dpo_Columns;
    dn->dn_Font.ta_YSize=dpo->dpo_Font.ta_YSize;
    dn->dn_Font.ta_Style=dpo->dpo_Font.ta_Style;
    dn->dn_Font.ta_Flags=dpo->dpo_Font.ta_Flags;

    /* All OK. */
    return(dn);
   }
  }

  /* Call failed */
  FreeDockNode((struct Node *) dn);
 }
 return(NULL);
}

/* Write Dock node to TMDO IFF chunk */
BOOL WriteDockNode(struct IFFHandle *iff, UBYTE *buf, struct Node *node)
{
 struct DockNode *dn=node;
 struct DockPrefsObject *dpo=buf;
 ULONG sbits=0;
 UBYTE *ptr=dpo+1;

 /* Copy strings */
 if (PutConfigStr(dn->dn_Node.ln_Name,&ptr)) sbits|=DOPO_NAME;
 if (PutConfigStr(dn->dn_HotKey,&ptr)) sbits|=DOPO_HOTKEY;
 if (PutConfigStr(dn->dn_PubScreen,&ptr)) sbits|=DOPO_PSCREEN;
 if (PutConfigStr(dn->dn_Title,&ptr)) sbits|=DOPO_TITLE;
 if (PutConfigStr(dn->dn_Font.ta_Name,&ptr)) sbits|=DOPO_FONTNAME;

 /* set string bits */
 dpo->dpo_StringBits=sbits;

 /* Write tool list */
 if (dn->dn_ToolsList) {
  struct ToolNode *tn=GetHead(dn->dn_ToolsList);

  while (tn) {
   UBYTE *flptr=ptr++;
   UBYTE tfl=DOPOT_CONTINUE;

   if (PutConfigStr(tn->tn_Node.ln_Name,&ptr)) tfl|=DOPOT_EXEC;
   if (PutConfigStr(tn->tn_Image,&ptr)) tfl|=DOPOT_IMAGE;
   if (PutConfigStr(tn->tn_Sound,&ptr)) tfl|=DOPOT_SOUND;

   /* Put flags */
   *flptr=tfl;

   /* Get next node */
   tn=GetSucc(tn);
  }
 }

 /* Append terminator */
 *ptr++=0;

 /* Copy flags & values */
 dpo->dpo_Flags=dn->dn_Flags;
 dpo->dpo_XPos=dn->dn_XPos;
 dpo->dpo_YPos=dn->dn_YPos;
 dpo->dpo_Columns=dn->dn_Columns;
 dpo->dpo_Font.ta_YSize=dn->dn_Font.ta_YSize;
 dpo->dpo_Font.ta_Style=dn->dn_Font.ta_Style;
 dpo->dpo_Font.ta_Flags=dn->dn_Font.ta_Flags;

 /* calculate length */
 sbits=ptr-buf;

 DEBUG_PRINTF("chunk size %ld\n",sbits);

 /* Open chunk */
 if (PushChunk(iff,0,ID_TMDO,sbits)) return(FALSE);

 /* Write chunk */
 if (WriteChunkBytes(iff,buf,sbits)!=sbits) return(FALSE);

 /* Close chunk */
 if (PopChunk(iff)) return(FALSE);

 /* All OK. */
 return(TRUE);
}
