/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                              P S E F O R M . C                               *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: pseform.c,v 1.4 2003/11/07 11:09:21 jrh Exp $
* $Log: pseform.c,v $
* Revision 1.4  2003/11/07 11:09:21  jrh
* Release 2.4
*
* Revision 1.3  2000/12/10 15:13:58  jrh
* Release 2.3
*
* Revision 1.2  1999/05/24 01:27:01  jrh
* Release 2.2.1
*
* Revision 1.1  1999/02/07 21:54:59  jrh
* Initial revision
*
*
*/
#include<stdlib.h>
#include<X11/Intrinsic.h>
#include<X11/cursorfont.h>
#include<Xm/Xm.h>
#include<Xm/BulletinB.h>
#include<Xm/Form.h>
#include<Xm/Label.h>
#include<Xm/LabelG.h>
#include<Xm/PushB.h>
#include<Xm/PushBG.h>
#include<Xm/RowColumn.h>
#include<Xm/Separator.h>
#include<Xm/Text.h>
#include<Xm/ToggleB.h>
#include<Xm/ToggleBG.h>
#include "viewmol.h"
#include "dialog.h"

extern void drawMolecule(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void MapBox(Widget, caddr_t, XmAnyCallbackStruct *);
extern void CreatePushButtonRow(Widget, struct PushButtonRow *, int);
extern Widget CreateToggleBox(Widget, struct PushButtonRow *, int, int,
                              int, int, int);
extern void setMenuItem(int, int);
extern void undoGeometry(Widget, caddr_t, XmAnyCallbackStruct *);
extern Widget makeMenu(Widget, int, char *, struct MenuItem *);
extern int makeConnectivity(struct MOLECULE *, int, int);
extern struct MOLECULE *initMolecule(int);
extern void *getmem(size_t number, size_t size);
extern void fremem(void **pointer);
extern Widget initShell(Widget, char *, Widget *, Widget *);

void pseDialog(Widget, caddr_t, XmAnyCallbackStruct *);
void pseDialogExit(Widget, caddr_t, XmPushButtonCallbackStruct *);
void newMolecule(Widget, caddr_t, XmAnyCallbackStruct *);
void GetElement(Widget, XtPointer, XmPushButtonCallbackStruct *);
void GetEditMode(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetTorsionDefault(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetBondOrderDefault(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetToggle(Widget, caddr_t, XmToggleButtonCallbackStruct *);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern Widget topShell, undoButton;
extern struct ELEMENT *elements;
extern Pixel stdcol[9];
extern double torsionDefault;
extern int ne, element, nmolecule, nUndo;
extern int modifyMolecule, bondOrderDefault, localGeometry;

static Widget dialog, oldButton;
static Pixel oldBackground;
static struct MOLECULE *mol;
static int nUndoSave, nbAddedSave, nbDeletedSave, *addedSave, *deletedSave;

void pseDialog(Widget w, caddr_t dummy, XmAnyCallbackStruct *data)
{
  Widget widget, board, form, form1, form2, sep;
  Widget radiobox, tors, label1, label2, bo, local;
  static struct PushButtonRow buttons1[] = {
    { "change",  GetEditMode, (XtPointer)NOTHING,      NULL},
    { "add",     GetEditMode, (XtPointer)ADD_ATOM,     NULL },
    { "delete",  GetEditMode, (XtPointer)DELETE_ATOM,  NULL },
    { "replace", GetEditMode, (XtPointer)REPLACE_ATOM, NULL },
    { "create",  GetEditMode, (XtPointer)CREATE_BOND,  NULL },
    { "remove",  GetEditMode, (XtPointer)REMOVE_BOND,  NULL },
    { "order",   GetEditMode, (XtPointer)BOND_ORDER,   NULL },
  };
  static struct PushButtonRow buttons2[] = {
    { "ok",     pseDialogExit, (XtPointer)TRUE, NULL },
    { "undo",   undoGeometry,  NULL, NULL },
    { "cancel", pseDialogExit, (XtPointer)FALSE, NULL },
  };
  static struct MenuItem torsionDefaultsMenu[] = {
    { "trans",   &xmPushButtonGadgetClass, GetTorsionDefault, (XtPointer)180, NULL, NULL },
    { "cis",     &xmPushButtonGadgetClass, GetTorsionDefault, (XtPointer)0, NULL, NULL },
    { "gauche",  &xmPushButtonGadgetClass, GetTorsionDefault, (XtPointer)60, NULL, NULL },
    { "-gauche", &xmPushButtonGadgetClass, GetTorsionDefault, (XtPointer)(-60), NULL, NULL },
    { NULL, NULL, NULL, NULL, NULL, NULL }
  };                                       
  static struct MenuItem bondOrderMenu[] = {
    { "fractional", &xmPushButtonGadgetClass, GetBondOrderDefault, (XtPointer)(-1), NULL, NULL },
    { "single",     &xmPushButtonGadgetClass, GetBondOrderDefault, (XtPointer)1,    NULL, NULL },
    { "double",     &xmPushButtonGadgetClass, GetBondOrderDefault, (XtPointer)2,    NULL, NULL },
    { "triple",     &xmPushButtonGadgetClass, GetBondOrderDefault, (XtPointer)3,    NULL, NULL },
    { NULL, NULL, NULL, NULL, NULL, NULL }
  };                                       
  int left, top;
  register int i;

  /* This function creates the PSE dialog */
 
  setMenuItem(VIEWER1_NEW, False);
  setMenuItem(VIEWER1_BUILD, False);

  nUndoSave=nUndo;
  if (windows[VIEWER].set >= 0)
    mol=&molecules[windows[VIEWER].set];
  else
    mol=&molecules[0];
  nbAddedSave=mol->nbAdded;
  nbDeletedSave=mol->nbDeleted;

  if (nbAddedSave != 0)
  {
    addedSave=(int *)getmem((size_t)nbAddedSave, sizeof(int));
    (void)memcpy(addedSave, mol->addedBonds, nbAddedSave*sizeof(int));
  }
  if (nbDeletedSave != 0)
  {
    deletedSave=(int *)getmem((size_t)nbDeletedSave, sizeof(int));
    (void)memcpy(deletedSave, mol->deletedBonds, nbDeletedSave*sizeof(int));
  }

  dialog=initShell(windows[VIEWER].widget, "pseForm", &board, &form);

  /* Form1 is the form widget which organizes the PSE */
  form1=XtVaCreateWidget("pse", xmFormWidgetClass, form,
                         XmNfractionBase, 359,
                         NULL);

  left=0;
  top=0;
  for (i=0; i<ne; i++)
  {
    if (strcmp(elements[i].symbol, "Uc") && strcmp(elements[i].symbol, "Bd") &&
        strcmp(elements[i].symbol, "Ps") && strcmp(elements[i].symbol, "Ms") &&
	strcmp(elements[i].symbol, "Mp") && strcmp(elements[i].symbol, "??"))
    {
      widget=XtVaCreateManagedWidget(elements[i].symbol, xmPushButtonGadgetClass, form1,
                                     XmNleftAttachment, left ? XmATTACH_POSITION : XmATTACH_FORM,
                                     XmNleftPosition, 20*left,
                                     XmNtopAttachment, top ? XmATTACH_POSITION : XmATTACH_FORM,
                                     XmNtopPosition, 36*top,
                                     XmNrightAttachment, left != 18 ? XmATTACH_POSITION : XmATTACH_FORM,
                                     XmNrightPosition, 20*left+19,
                                     XmNbottomAttachment, XmATTACH_POSITION,
                                     XmNbottomPosition, 36*top+35,
                                     NULL);
      XtAddCallback(widget, XmNactivateCallback, (XtCallbackProc)GetElement, (XtPointer)i);
      if (i == element)
      {
        oldButton=widget;
        XtVaGetValues(widget, XmNbackground, &oldBackground, NULL);
        XtVaSetValues(widget, XmNbackground, stdcol[YELLOW], NULL);
      }
      switch (i)
      {
        case 0:   left+=17;
                  break;
        case 3:  
        case 11:  left+=11;
                  break;
        case 56:  left=3;
                  top=8;
                  break;
        case 70:  left=3;
                  top=5;
                  break;
        case 88:  left=3;
                  top=9;
                  break;
        case 102: left=3;
                  top=6;
                  break;
        default:  left++;
                  break;
      }
      if (left > 17)
      {
          left=0;
        top++;
      }
    }
  }
  sep=XtVaCreateManagedWidget("sep", xmSeparatorWidgetClass, form,
                              XmNorientation, XmHORIZONTAL,
                              XmNtraversalOn, False,
                              NULL);
  /* Form 2 is the Form widget which organizes the operations area */
  form2=XtVaCreateWidget("operations", xmFormWidgetClass, form,
                         XmNfractionBase, 100,
                         NULL);
  if (modifyMolecule == NEW_MOLECULE)
    i=ADD_ATOM;
  else
    i=modifyMolecule;
  radiobox=CreateToggleBox(form2, buttons1, XtNumber(buttons1), XmHORIZONTAL, 3,
                           True, i);
  XtVaSetValues(radiobox, XmNtopAttachment, XmATTACH_FORM,
                          XmNbottomAttachment, XmATTACH_FORM,
                          XmNleftAttachment, XmATTACH_FORM,
                          NULL);

  label1=XtVaCreateManagedWidget("torsionDefault", xmLabelWidgetClass, form2,
                                 XmNtopAttachment, XmATTACH_POSITION,
                                 XmNtopPosition, 10,
                                  XmNleftAttachment, XmATTACH_WIDGET,
                                 XmNleftWidget, radiobox,
                                 NULL);
  tors=makeMenu(form2, XmMENU_OPTION, "torsion", torsionDefaultsMenu);
  XtVaSetValues(tors, XmNtopAttachment, XmATTACH_POSITION,
                      XmNtopPosition, 0,
                      XmNleftAttachment, XmATTACH_POSITION,
                      XmNleftPosition, 85,
                      XmNrightAttachment, XmATTACH_FORM,
                      NULL); 

  label2=XtVaCreateManagedWidget("bondOrderLabel", xmLabelWidgetClass, form2,
                                 XmNtopAttachment, XmATTACH_POSITION,
                                 XmNtopPosition, 43,
                                 XmNleftAttachment, XmATTACH_WIDGET,
                                 XmNleftWidget, radiobox,
                                 NULL);

  bo=makeMenu(form2, XmMENU_OPTION, "bondOrder", bondOrderMenu);
  XtVaSetValues(bo, XmNtopAttachment, XmATTACH_POSITION,
                    XmNtopPosition, 33,
                    XmNleftAttachment, XmATTACH_POSITION,
                    XmNleftPosition, 85,
                    XmNrightAttachment, XmATTACH_FORM,
                    XmNmenuHistory, bondOrderMenu[bondOrderDefault > 0 ? bondOrderDefault : 0].widget,
                    NULL);

  local=XtVaCreateManagedWidget("localGeometry", xmToggleButtonWidgetClass, form2,
                                XmNleftAttachment, XmATTACH_WIDGET,
                                XmNleftWidget, radiobox,
                                XmNbottomAttachment, XmATTACH_FORM,
                                XmNrightAttachment, XmATTACH_FORM,
                                NULL);
  XtAddCallback(local, XmNvalueChangedCallback, (XtCallbackProc)GetToggle, &localGeometry);
  if (localGeometry) XtVaSetValues(local, XmNset, True, NULL);

  sep=XtVaCreateManagedWidget("sep", xmSeparatorWidgetClass, form,
                              XmNorientation, XmHORIZONTAL,
                              XmNtraversalOn, False,
                              NULL);

  CreatePushButtonRow(form, buttons2, XtNumber(buttons2));
  undoButton=buttons2[1].widget;
  if (nUndo == 0) XtVaSetValues(undoButton, XmNsensitive, False, NULL);
  XtAddCallback(dialog, XmNpopupCallback, (XtCallbackProc)MapBox, (XmAnyCallbackStruct *)NULL);
  XtManageChild(form1);
  XtManageChild(tors);
  XtManageChild(bo);
  XtManageChild(form2);
  XtManageChild(form);
  XtManageChild(board);
}

void pseDialogExit(Widget button, caddr_t which, XmPushButtonCallbackStruct *data)
{
  modifyMolecule=NOTHING;
  undoButton=NULL;
  XtDestroyWidget(dialog);
  setMenuItem(VIEWER1_NEW, True);
  if (nmolecule > 0) setMenuItem(VIEWER1_BUILD, True);
  if (!(int)which)
  {
    if (nmolecule > 0)
    {
      if (nUndoSave != 0 && nUndo > nUndoSave)
      {
        nUndo=nUndoSave+1;
        undoGeometry((Widget)0, (caddr_t)0, (XmAnyCallbackStruct *)0);
      }
      if (nbAddedSave != mol->nbAdded)
      {
            mol->nbAdded=nbAddedSave;
        if (nbAddedSave != 0)
        {
          (void)memcpy(mol->addedBonds, addedSave, nbAddedSave*sizeof(int));
          fremem((void **)&addedSave);
        }
        else
          fremem((void **)&mol->addedBonds);
      }
      if (nbDeletedSave != mol->nbDeleted)
      {
          mol->nbDeleted=nbDeletedSave;
        if (nbDeletedSave != 0)
        {
          (void)memcpy(mol->deletedBonds, deletedSave, nbDeletedSave*sizeof(int));
          fremem((void **)&deletedSave);
        }
        else
          fremem((void **)&mol->deletedBonds);
      }
      makeConnectivity(mol, FALSE, TRUE);
    }
  }
}

void newMolecule(Widget w, caddr_t dummy, XmAnyCallbackStruct *data)
{
  if (molecules == NULL)
  {
    XtRemoveAllCallbacks(windows[VIEWER].widget, XmNexposeCallback);
    XtAddCallback(windows[VIEWER].widget, XmNexposeCallback,
		      (XtCallbackProc)drawMolecule, NULL);
    (void)initMolecule(20);
  }
  if (w != NULL)
  {
    modifyMolecule=NEW_MOLECULE;
    pseDialog(w, dummy, data);
  }
}

void GetElement(Widget button, XtPointer which, XmPushButtonCallbackStruct *data)
{
  element=(int)which;
  if (button != oldButton)
  {
    XtVaSetValues(oldButton, XmNbackground, oldBackground, NULL);
    XtVaGetValues(button, XmNbackground, &oldBackground, NULL);
    XtVaSetValues(button, XmNbackground, stdcol[YELLOW], NULL);
    oldButton=button;
  }
}

void GetEditMode(Widget button, caddr_t which,
                 XmToggleButtonCallbackStruct *data)
{
  if (data->set)
    modifyMolecule=(int)which;
}

void GetTorsionDefault(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  int t;

  t=(int)which;
  torsionDefault=(double)t;
} 

void GetBondOrderDefault(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  bondOrderDefault=(int)which;
} 

void GetToggle(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  int *w;

  w=(int *)which;
  *w=!(*w);
}
