/* 
 * $Id: x11merge.c,v 1.7 2003/02/16 12:43:37 isizaka Exp isizaka $
 * 
 * This file is part of "Ngraph for X11".
 * 
 * Copyright (C) 2002, Satoshi ISHIZAKA. isizaka@msa.biglobe.ne.jp
 * 
 * "Ngraph for X11" is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * "Ngraph for X11" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

/**
 *
 * $Log: x11merge.c,v $
 * Revision 1.7  2003/02/16 12:43:37  isizaka
 * for release 6.13.18
 *
 * Revision 1.6  2002/07/06 08:57:25  isizaka
 * change to GPL.
 *
 * Revision 1.5  1999/05/08 13:31:30  isizaka
 * for release 6.03.02
 *
 * Revision 1.4  1999/04/15 12:14:26  isizaka
 * for release 6.03.01
 *
 * Revision 1.3  1999/04/11 06:09:20  isizaka
 * *** empty log message ***
 *
 * Revision 1.2  1999/03/20 12:32:54  isizaka
 * minor change
 *
 * Revision 1.1  1999/03/17 13:29:01  isizaka
 * Initial revision
 *
 *
 **/

#include <Xm/XmAll.h>
#include <X11/keysym.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "ngraph.h"
#include "object.h"
#include "nstring.h"
#include "ioutil.h"

#include "x11gui.h"
#include "x11dialg.h"
#include "x11menu.h"
#include "ox11menu.h"
#include "x11file.h"
#include "x11merge.h"
#include "x11commn.h"

void MergeDialogSetupItem(Widget w,struct MergeDialog *d,int file,int id)
{
  if (file) {
    SetTextFromObjField(w,"*file",d->Obj,id,"file");
  }
  SetTextFromObjField(w,"*topmargin",d->Obj,id,"top_margin");
  SetTextFromObjField(w,"*leftmargin",d->Obj,id,"left_margin");
  SetTextFromObjField(w,"*zoom",d->Obj,id,"zoom");
#ifdef JAPANESE
  SetToggleFromObjField(w,"*GreekSymbol",d->Obj,id,"symbol_greek");
#endif
}

void MergeDialogDelete(Widget w,XtPointer client_data,XtPointer call_data)
{
  struct MergeDialog *d;

  d=(struct MergeDialog *)client_data;
  d->ret=IDDELETE;
}

void MergeDialogCopy(Widget w,XtPointer client_data,XtPointer call_data)
{
  struct MergeDialog *d;
  int sel;

  d=(struct MergeDialog *)client_data;
  if ((sel=CopyClick(d->widget,d->Obj,d->Id,FileCB))!=-1) 
    MergeDialogSetupItem(d->widget,d,FALSE,sel);
}

void MergeDialogSetup(Widget w,void *data,int makewidget)
{
  Arg al[20];
  Cardinal ac;
  Widget rc,rc2,button;
  struct MergeDialog *d;
  char title[20];
  XmString xs;
  
  d=(struct MergeDialog *)data;
  sprintf(title,"Merge %d",d->Id);
  xs=XmStringCreateLocalized(title);
  XtVaSetValues(w,XmNdialogTitle,xs,NULL);
  XmStringFree(xs);
  if (makewidget) {
  ac=0;
  XtManageChild(button=XmCreatePushButton(w,"Close",al,ac));
  XtAddCallback(button,XmNdisarmCallback,MergeDialogDelete,d);
  ac=0;
  XtManageChild(button=XmCreatePushButton(w,"Copy",al,ac));
  XtAddCallback(button,XmNdisarmCallback,MergeDialogCopy,d);

  ac=0;
  XtSetArg(al[ac],XmNorientation,XmVERTICAL); ac++;
  XtManageChild(rc=XmCreateRowColumn(w,"rc",al,ac));

  ac=0;
  XtSetArg(al[ac],XmNorientation,XmHORIZONTAL); ac++;
  XtManageChild(rc2=XmCreateRowColumn(rc,"filerc",al,ac));
  ac=0;
  XtManageChild(XmCreateLabel(rc2,"File",al,ac));
  ac=0;
  XtManageChild(XmCreateTextField(rc2,"file",al,ac));

  ac=0;
  XtSetArg(al[ac],XmNorientation,XmHORIZONTAL); ac++;
  XtManageChild(rc2=XmCreateRowColumn(rc,"marginrc",al,ac));
  ac=0;
  XtManageChild(XmCreateLabel(rc2,"TopMargin",al,ac));
  ac=0;
  XtManageChild(XmCreateTextField(rc2,"topmargin",al,ac));
  ac=0;
  XtManageChild(XmCreateLabel(rc2,"LeftMargin",al,ac));
  ac=0;
  XtManageChild(XmCreateTextField(rc2,"leftmargin",al,ac));
  ac=0;
  XtSetArg(al[ac],XmNorientation,XmHORIZONTAL); ac++;
  XtManageChild(rc2=XmCreateRowColumn(rc,"zoomrc",al,ac));
  ac=0;
  XtManageChild(XmCreateLabel(rc2,"Zoom",al,ac));
  ac=0;
  XtManageChild(XmCreateTextField(rc2,"zoom",al,ac));
#ifdef JAPANESE
  ac=0;
  XtManageChild(XmCreateToggleButton(rc2,"GreekSymbol",al,ac));
#endif
  }
  MergeDialogSetupItem(w,d,TRUE,d->Id);
}

void MergeDialogClose(Widget w,void *data)
{
  struct MergeDialog *d;
  int ret;

  d=(struct MergeDialog *)data;
  if (d->ret!=IDOK) return;
  ret=d->ret;
  d->ret=IDLOOP;
  if (SetObjFieldFromText(w,"*file",d->Obj,d->Id,"file")) return;
  if (SetObjFieldFromText(w,"*topmargin",d->Obj,d->Id,"top_margin")) return;
  if (SetObjFieldFromText(w,"*leftmargin",d->Obj,d->Id,"left_margin")) return;
  if (SetObjFieldFromText(w,"*zoom",d->Obj,d->Id,"zoom")) return;
#ifdef JAPANESE
  if (SetObjFieldFromToggle(w,"*GreekSymbol",
      d->Obj,d->Id,"symbol_greek")) return;
#endif
  d->ret=ret;
}

void MergeDialog(struct MergeDialog *data,
                 struct objlist *obj,int id)
{
  data->SetupWindow=MergeDialogSetup;
  data->CloseWindow=MergeDialogClose;
  data->Obj=obj;
  data->Id=id;
}

void CmMergeOpen()
{
  struct objlist *obj;
  char *name;
  int id,ret;

  if (menulock || globallock) return;
  if ((obj=chkobject("merge"))==NULL) return;
  if (nGetOpenFileName(TopLevel,"Merge open","gra",NULL,NULL,&name,
      "*.gra",TRUE,menulocal.changedirectory)==IDOK) {
    if ((id=newobj(obj))>=0) {
      changefilename(name);
      putobj(obj,"file",id,name);
      MergeDialog(&DlgMerge,obj,id);
      ret=DialogExecute(TopLevel,&DlgMerge);
      if ((ret==IDDELETE) || (ret==IDCANCEL)) {
        delobj(obj,id);
      } else NgraphApp.Changed=TRUE;
    } else free(name);
    MergeWinUpdate(TRUE);
  }
}

void CmMergeClose()
{
  struct narray farray;
  struct objlist *obj;
  int i;
  int num,*array;

  if (menulock || globallock) return;
  if ((obj=chkobject("merge"))==NULL) return;
  if (chkobjlastinst(obj)==-1) return;
  SelectDialog(&DlgSelect,obj,FileCB,(struct narray *)&farray,NULL);
  if (DialogExecute(TopLevel,&DlgSelect)==IDOK) {
    num=arraynum(&farray);
    array=(int *)arraydata(&farray);
    for (i=num-1;i>=0;i--) {
      delobj(obj,array[i]);
      NgraphApp.Changed=TRUE;
    }
    MergeWinUpdate(TRUE);
  }
  arraydel(&farray);
}

void CmMergeUpdate()
{
  struct narray farray;
  struct objlist *obj;
  int i,j,ret;
  int *array,num;

  if (menulock || globallock) return;
  if ((obj=chkobject("merge"))==NULL) return;
  if (chkobjlastinst(obj)==-1) return;
  SelectDialog(&DlgSelect,obj,FileCB,(struct narray *)&farray,NULL);
  if (DialogExecute(TopLevel,&DlgSelect)==IDOK) {
    num=arraynum(&farray);
    array=(int *)arraydata(&farray);
    for (i=0;i<num;i++) {
      MergeDialog(&DlgMerge,obj,array[i]);
      if ((ret=DialogExecute(TopLevel,&DlgMerge))==IDDELETE) {
        delobj(obj,array[i]);
        for (j=i+1;j<num;j++) array[j]--;
      }
      if (ret!=IDCANCEL) NgraphApp.Changed=TRUE;
    }
    MergeWinUpdate(TRUE);
  }
  arraydel(&farray);
}


void CmMergeMenu(Widget w,XtPointer client_data,XtPointer call_data)
{
  switch ((int )client_data) {
  case 0: 
    CmMergeOpen();
    break;
  case 1: 
    CmMergeUpdate();
    break;
  case 2: 
    CmMergeClose();
    break;
  }
}

void MergeWinMergeOpen()
{
  CmMergeOpen();
}

void MergeWinMergeDelete()
{
  int sel;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    delobj(d->obj,sel);
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinMergeCopy()
{
  int sel;
  int j,id,perm,type;
  char *field;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    if ((id=newobj(d->obj))>=0) {
      for (j=0;j<chkobjfieldnum(d->obj);j++) {
        field=chkobjfieldname(d->obj,j);
        perm=chkobjperm(d->obj,field);
        type=chkobjfieldtype(d->obj,field);
        if ((strcmp2(field,"name")!=0)
          && ((perm&NREAD)!=0) && ((perm&NWRITE)!=0) && (type<NVFUNC))
          copyobj(d->obj,field,id,sel);
      }
      d->filenum++;
      NgraphApp.Changed=TRUE;
    }
    d->select=sel;
    MergeWinUpdate(FALSE);
  }
}

void MergeWinMergeTop()
{
  int sel;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    movetopobj(d->obj,sel);
    d->select=0;
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinMergeLast()
{
  int sel;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    movelastobj(d->obj,sel);
    d->select=d->filenum;
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinMergeUp()
{
  int sel;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=1) && (sel<=d->filenum)) {
    moveupobj(d->obj,sel);
    d->select=sel-1;
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinMergeDown()
{
  int sel;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum-1)) {
    movedownobj(d->obj,sel);
    d->select=sel+1;
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinMergeUpdate()
{
  int sel,ret;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    MergeDialog(&DlgMerge,d->obj,sel);
    if ((ret=DialogExecute(TopLevel,&DlgMerge))==IDDELETE) {
      delobj(d->obj,sel);
      d->select=-1;
    }
    if (ret!=IDCANCEL) NgraphApp.Changed=TRUE;
    MergeWinUpdate(FALSE);
  }
}

void MergeWinMergeHidden()
{
  int sel;
  int hidden;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (menulock || globallock) return;
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    getobj(d->obj,"hidden",sel,0,NULL,&hidden);
    hidden=hidden?FALSE:TRUE;
    putobj(d->obj,"hidden",sel,&hidden);
    MergeWinUpdate(FALSE);
    NgraphApp.Changed=TRUE;
  }
}

void MergeWinChangeFileNum()
{
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (d->text==NULL) return;
  XtVaSetValues(d->text,XmNheight,(d->filenum+3)*FHeight,NULL);
}

void MergeWinUpdate(int clear)
{
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  d->filenum=chkobjlastinst(d->obj);
  MergeWinChangeFileNum();
  if (d->text==NULL) return;
  XClearArea(XtDisplay(d->text),XtWindow(d->text),0,0,0,0,TRUE);
}

void MergeWinExpose(Widget wi,XtPointer client_data,XtPointer call_data)
{
  XmDrawingAreaCallbackStruct *dd;
  XExposeEvent *e;
  Display *disp;
  Window win;
  GC gc;
  int i;
  char buf[256];
  char *file,*bfile;
  XRectangle rect;
  int h,w,x,y,len,cx;
  int hidden;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (d->text==NULL) return;
  dd=(XmDrawingAreaCallbackStruct *)call_data;
  e=(XExposeEvent *)(dd->event);
  disp=e->display;
  win=e->window;
  gc=XCreateGC(disp,win,0,0);
  if (globallock) return;
  d->filenum=chkobjlastinst(d->obj);
  h=FHeight;
  w=FWidth;
  XSetForeground(disp,gc,gray);
  XFillRectangle(disp,win,gc,0,0,47*w+2*w,h);
  x=FWidth;
  y=FAscent;
  XSetForeground(disp,gc,black);
  rect.y=y-FAscent;
  rect.height=h;
  rect.x=x;
  rect.width=6*w;
  len=sprintf(buf,"#");
  ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
  x+=6*w;
  rect.x=x;
  rect.width=13*w;
  len=sprintf(buf,"file");
  ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
  x+=13*w;
  rect.x=x;
  rect.width=6*w;
  len=sprintf(buf,"    tm");
  ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
  x+=6*w;
  rect.x=x;
  rect.width=6*w;
  len=sprintf(buf,"    lm");
  ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
  x+=6*w;
  rect.x=x;
  rect.width=6*w;
  len=sprintf(buf,"    zm");
  ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
  x+=6*w;
  rect.x=x+w;
  rect.width=7*w;
  len=sprintf(buf,"^#");
  ExtTextOut(disp,win,gc,x+w,y,&rect,buf,len);

  for (i=0;i<=d->filenum;i++) {
      x=w;
      y=(i+1)*h+FAscent;
      rect.y=y-FAscent;
      rect.height=h;

      getobj(d->obj,"hidden",i,0,NULL,&hidden);
      if (hidden) XSetForeground(disp,gc,gray);
      else XSetForeground(disp,gc,black);
      if (i==d->select) {
        XSetForeground(disp,gc,black);
        XFillRectangle(disp,win,gc,0,rect.y,74*w+h+w,rect.height);
        XSetForeground(disp,gc,white);
      }

      getobj(d->obj,"id",i,0,NULL,&cx);
      rect.x=x;
      rect.width=6*w;
      len=sprintf(buf,"%d",cx);
      ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
      x+=6*w;

      getobj(d->obj,"file",i,0,NULL,&file);
      bfile=getbasename(file);
      rect.x=x;
      rect.width=12*w;
      if (bfile!=NULL) {
        ExtTextOut(disp,win,gc,x,y,&rect,bfile,strlen(bfile));
        memfree(bfile);
      } else
        ExtTextOut(disp,win,gc,x,y,&rect,"....................",20);
      x+=13*w;

      getobj(d->obj,"top_margin",i,0,NULL,&cx);
      rect.x=x;
      rect.width=6*w;
      len=sprintf(buf,"%6d",cx);
      ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
      x+=6*w;

      getobj(d->obj,"left_margin",i,0,NULL,&cx);
      rect.x=x;
      rect.width=6*w;
      len=sprintf(buf,"%6d",cx);
      ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
      x+=6*w;

      getobj(d->obj,"zoom",i,0,NULL,&cx);
      rect.x=x;
      rect.width=6*w;
      len=sprintf(buf,"%6d",cx);
      ExtTextOut(disp,win,gc,x,y,&rect,buf,len);
      x+=6*w;

      getobj(d->obj,"oid",i,0,NULL,&cx);
      rect.x=x+w;
      rect.width=7*w;
      len=sprintf(buf,"^%d",cx);
      ExtTextOut(disp,win,gc,x+w,y,&rect,buf,len);
      x+=8*w;
    }
  XFreeGC(disp,gc);
}

void MergeWinEvLButtonDown(unsigned int state,TPoint point,struct MergeWin *d)
{
  int sel;

  if (menulock || globallock) return;
  sel=point.y/FHeight-1;
  if (sel!=d->select) {
    MergeWinUpdate(FALSE);
    d->select=sel;
  }
}

void MergeWinEvLButtonDblClk(unsigned int state,TPoint point,struct MergeWin *d)
{
  if (menulock || globallock) return;
  MergeWinMergeUpdate();
}

void MergeWinEvRButtonDown(unsigned int state,TPoint point,struct MergeWin *d,
                          XButtonPressedEvent *event)
{
  int sel;

  if (menulock || globallock) return;
  sel=point.y/FHeight-1;
  if (sel!=d->select) {
    MergeWinUpdate(TRUE);
    d->select=sel;
  }
  sel=d->select;
  if ((sel>=0) && (sel<=d->filenum)) {
    XtSetSensitive(XtNameToWidget(d->popup,"button_0"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_1"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_2"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_3"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_4"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_5"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_6"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_7"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_8"),True);
  } else {
    XtSetSensitive(XtNameToWidget(d->popup,"button_0"),True);
    XtSetSensitive(XtNameToWidget(d->popup,"button_1"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_2"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_3"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_4"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_5"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_6"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_7"),False);
    XtSetSensitive(XtNameToWidget(d->popup,"button_8"),False);
  }
  XmMenuPosition(d->popup,event);
  XtManageChild(d->popup);
}

Time MergeWinTime=0;
TPoint MergeWinPoint;

void MergeWinEvButtonDown(Widget w,XtPointer client_data,XEvent *event,
                         Boolean *dispatch)
{
  struct MergeWin *d;
  XButtonEvent *e;
  TPoint point;
  int dbl;

  d=(struct MergeWin *)client_data;
  e=(XButtonEvent *)event;
  point.x=e->x;
  point.y=e->y;
  if (((e->time-MergeWinTime)<menulocal.mouseclick)
  && (MergeWinPoint.x==point.x) && (MergeWinPoint.y==point.y)) dbl=TRUE;
  else dbl=FALSE;
  MergeWinTime=e->time;
  MergeWinPoint.x=point.x;
  MergeWinPoint.y=point.y;
  if (e->button==Button1) {
    if (dbl) MergeWinEvLButtonDblClk(e->state,point,d);
    else MergeWinEvLButtonDown(e->state,point,d);
  } else if (e->button==Button2) {
    MergeWinEvLButtonDown(e->state,point,d);
    MergeWinEvLButtonDblClk(e->state,point,d);
  } else if (e->button==Button3) MergeWinEvRButtonDown(e->state,point,d,e);
}

void MergeWinPopupMenu(Widget w,XtPointer client_data,XtPointer call_data)
{
  switch ((int )client_data) {
  case 0:
    MergeWinMergeOpen(); 
    break;
  case 1: 
    MergeWinMergeUpdate(); 
    break;
  case 2: 
    MergeWinMergeDelete(); 
    break;
  case 3: 
    MergeWinMergeTop(); 
    break;
  case 4: 
    MergeWinMergeUp(); 
    break;
  case 5: 
    MergeWinMergeDown(); 
    break;
  case 6: 
    MergeWinMergeLast(); 
    break;
  case 7: 
    MergeWinMergeCopy(); 
    break;
  case 8: 
    MergeWinMergeHidden(); 
    break;
  }
}

void MergeWinEvKeyDown(Widget w,XtPointer client_data,XEvent *event,
                     Boolean *dispatch)
{
  struct MergeWin *d;
  XKeyEvent *e;
  KeySym sym;
  int sel;

  if (menulock || globallock) return;
  d=(struct MergeWin *)client_data;
  e=(XKeyEvent *)event;
  sym=XKeycodeToKeysym(e->display,e->keycode,0);
  sel=d->select;
  switch (sym) {
  case XK_Down:
    if (e->state & ShiftMask) MergeWinMergeDown();
    else {
      if ((sel==-1) && (d->filenum>=0)) sel=0;
      else if (sel<d->filenum) sel++;
      if (sel!=d->select) {
        d->select=sel;
        MergeWinUpdate(TRUE);
      }
    }
    break;
  case XK_Up:
    if (e->state & ShiftMask) MergeWinMergeUp();
    else {
      if ((sel==-1) && (d->filenum>=0)) sel=d->filenum;
      else if (sel>0) sel--;
      if (sel!=d->select) {
        d->select=sel;
        MergeWinUpdate(TRUE);
      }
    }
    break;
  case XK_Delete:
    MergeWinMergeDelete();
    break;
  case XK_Insert:
    MergeWinMergeCopy();
    break;
  case XK_Home:
    if (e->state & ShiftMask) MergeWinMergeTop();
    break;
  case XK_End:
    if (e->state & ShiftMask) MergeWinMergeLast();
    break;
  case XK_Return:
    MergeWinMergeUpdate();
    break;
  case XK_BackSpace:
    MergeWinMergeHidden();
    break;
  }
}

void MergeWindowUnmap(Widget w,XtPointer client_data,XtPointer call_data)
{
  struct MergeWin *d;
  Position x,y,x0,y0;
  Dimension w0,h0;

  d=&(NgraphApp.MergeWin);
  if (d->Win!=NULL) {
    XtVaGetValues(d->Win,XmNx,&x,XmNy,&y,
                         XmNwidth,&w0,XmNheight,&h0,NULL);
    menulocal.mergewidth=w0;
    menulocal.mergeheight=h0;
    XtTranslateCoords(TopLevel,0,0,&x0,&y0);
    menulocal.mergex=x-x0;
    menulocal.mergey=y-y0;
    XtDestroyWidget(d->Win);
    d->Win=NULL;
    d->text=NULL;
    XmToggleButtonSetState(XtNameToWidget(TopLevel,"*windowmenu.button_3"),
                           False,False);
  }
}

void CmMergeWindow(Widget w,XtPointer client_data,XtPointer call_data)
{
  Arg al[20];
  Cardinal ac;
  Widget dlg,scw,clip;
  int width,height;
  Position x,y;
  struct MergeWin *d;

  d=&(NgraphApp.MergeWin);
  if (d->Win!=NULL) {
    XtUnmanageChild(d->Win);
  } else {
    if (menulocal.mergewidth==CW_USEDEFAULT) width=FWidth*47+2*FWidth;
    else width=menulocal.mergewidth;
    if (menulocal.mergeheight==CW_USEDEFAULT) height=FHeight*10;
    else height=menulocal.mergeheight;
    ac=0;
    XtSetArg(al[ac],XmNborderWidth,1);ac++;
    XtSetArg(al[ac],XmNdialogStyle,XmDIALOG_MODELESS); ac++;
    XtSetArg(al[ac],XmNautoUnmanage,FALSE); ac++;
    XtSetArg(al[ac],XmNwidth,width); ac++;
    XtSetArg(al[ac],XmNheight,height); ac++;
    if ((menulocal.mergex!=CW_USEDEFAULT)
    && (menulocal.mergey!=CW_USEDEFAULT)) {
      XtTranslateCoords(TopLevel,menulocal.mergex,menulocal.mergey,&x,&y);
      x-=menulocal.framex;
      y-=menulocal.framey;
      if (x<0) x=0;
      if (y<0) y=0;
      XtSetArg(al[ac],XmNdefaultPosition,False); ac++;
      XtSetArg(al[ac],XmNx,x); ac++;
      XtSetArg(al[ac],XmNy,y); ac++;
    } else {
      XtSetArg(al[ac],XmNdefaultPosition,True); ac++;
    }
    XtManageChild(dlg=XmCreateFormDialog(TopLevel,"mergewindow",al,ac));
    d->Win=dlg;
    XtAddCallback(dlg,XmNunmapCallback,MergeWindowUnmap,NULL);
    ac=0;
    XtSetArg(al[ac],XmNtopAttachment,XmATTACH_FORM); ac++;
    XtSetArg(al[ac],XmNbottomAttachment,XmATTACH_FORM); ac++;
    XtSetArg(al[ac],XmNleftAttachment,XmATTACH_FORM); ac++;
    XtSetArg(al[ac],XmNrightAttachment,XmATTACH_FORM); ac++;
    XtSetArg(al[ac],XmNalignment,XmALIGNMENT_BEGINNING); ac++; 
    XtSetArg(al[ac],XmNscrollingPolicy,XmAUTOMATIC); ac++;
    XtSetArg(al[ac],XmNscrollBarDisplayPolicy,XmSTATIC); ac++;
    XtSetArg(al[ac],XmNwidth,width); ac++;
    XtSetArg(al[ac],XmNheight,height); ac++;
    XtSetArg(al[ac],XmNborderWidth,0);ac++;
    XtManageChild(scw=XmCreateScrolledWindow(dlg,NULL,al,ac));
    ac=0;
    XtSetArg(al[ac],XmNwidth,FWidth*47+2*FWidth); ac++;
    XtSetArg(al[ac],XmNheight,height); ac++;
    XtSetArg(al[ac],XmNbackground,WhitePixel(XtDisplay(TopLevel),0)); ac++;
    XtManageChild(d->text=XmCreateDrawingArea(scw,NULL,al,ac));
    XtVaGetValues(scw,XmNclipWindow,&clip,NULL);
    XtVaSetValues(clip,XmNbackground,WhitePixel(XtDisplay(TopLevel),0),NULL);
    XtAddCallback(d->text,XmNexposeCallback,MergeWinExpose,NULL); 
    XtAddEventHandler(d->text,ButtonPressMask,False,MergeWinEvButtonDown,d);
    d->obj=chkobject("merge");
    d->filenum=chkobjlastinst(d->obj);
    MergeWinChangeFileNum();
    d->select=-1;
    d->popup=XmVaCreateSimplePopupMenu(d->text,"mergepopup",MergeWinPopupMenu,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    XmVaPUSHBUTTON,NULL,NULL,NULL,NULL,
    NULL);
    XtAddEventHandler(d->text,KeyPressMask,False,MergeWinEvKeyDown,d);
    XmToggleButtonSetState(XtNameToWidget(TopLevel,"*windowmenu.button_3"),
                           True,False);
  }
}
