/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                             S P E C F O R M . C                              *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: specform.c,v 1.6 2003/11/07 11:16:18 jrh Exp $
* $Log: specform.c,v $
* Revision 1.6  2003/11/07 11:16:18  jrh
* Release 2.4
*
* Revision 1.5  2000/12/10 15:16:52  jrh
* Release 2.3
*
* Revision 1.4  1999/05/24 01:27:39  jrh
* Release 2.2.1
*
* Revision 1.3  1999/02/07 21:57:03  jrh
* Release 2.2
*
* Revision 1.2  1998/01/26 00:49:33  jrh
* Release 2.1
*
* Revision 1.1  1996/12/10  18:44:01  jrh
* Initial revision
*
*/
#include<math.h>
#include<stdlib.h>
#include<X11/Intrinsic.h>
#include<Xm/Xm.h>
#include<Xm/BulletinB.h>
#include<Xm/Form.h>
#include<Xm/Label.h>
#include<Xm/LabelG.h>
#include<Xm/PanedW.h>
#include<Xm/PushB.h>
#include<Xm/PushBG.h>
#include<Xm/RowColumn.h>
#include<Xm/Scale.h>
#include<Xm/Separator.h>
#include<Xm/Text.h>
#include<Xm/ToggleB.h>
#include "viewmol.h"
#include "dialog.h"

void GetMode(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetAnimate(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetType(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetSlider(Widget, struct SLIDER *, XmScrollBarCallbackStruct *);
void GetAmplitude(Widget, struct SLIDER *, XmScrollBarCallbackStruct *);
void GetScale(Widget, struct SLIDER *, XmScrollBarCallbackStruct *);
void spectrumDialogExit(Widget, caddr_t, XmPushButtonCallbackStruct *);
void GetIns(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetInsWeight(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetDouble(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetOption(Widget, caddr_t, XmToggleButtonCallbackStruct *);
void GetLineWidth(Widget, caddr_t, XmToggleButtonCallbackStruct *);

extern void MapBox(Widget, caddr_t, XmAnyCallbackStruct *);
extern Widget CreateToggleBox(Widget, struct PushButtonRow *, int, int,
                              int, int, int);
extern char *getStringResource(Widget, char *);
extern void CreatePushButtonRow(Widget, struct PushButtonRow *, int);
extern void setWindowTitle(Widget, char *);
extern void redraw(int);
extern void drawSpectrum(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void setAnimation(int);
extern void restoreGeometry(struct SAVE *, int);
extern void distortGeometry(double);
extern void setMenuItem(int, int);
extern int  makeAnnotation(int, int, float, float, float, int, const GLfloat *,
                           int, int, char *);
extern void deleteAnnotation(int *);
extern Widget initShell(Widget, char *, Widget *, Widget *);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern int animate, lines, setins, xIsTop, showGrid;
extern int setinsAnnotation;
extern double weight, temp, amplitude, wnScale, spectrumLineWidth;
extern Widget topShell;
extern Pixel stdcol[9];

static Widget dialog, insweight;
static int mode_save, animate_save, lines_save, setins_save, xIsTop_save, showGrid_save;
static double weight_save, temp_save, amplitude_save, wnScale_save, lineWidth_save;

void spectrumDialog(Widget widget, caddr_t dummy, XmAnyCallbackStruct *data)
{
  Widget board, form, form1, form2, form3, form4, form5;
  Widget radiobox1, radiobox2, radiobox3;
  Widget ins, slider1, slider2, slider3, temperature, ampl, scale;
  Widget axisTop, lineWidthLabel, lineWidthWidget, showGridWidget;
  Widget sep1, sep2, sep3, sep4, sep5, sep6;
  static struct SLIDER tempSlider, amplitudeSlider, scaleSlider;
  short decimals;
  char str[20];
  static struct PushButtonRow buttons[] = {
    { "ok", spectrumDialogExit, (XtPointer)TRUE, NULL },
    { "cancel", spectrumDialogExit, (XtPointer)FALSE, NULL }
  };
  static struct PushButtonRow radiobox1_buttons[] = {
    { "all_modes", GetMode, (XtPointer)SPECTRUM_ALL, NULL },
    { "ir_modes", GetMode, (XtPointer)SPECTRUM_IR, NULL },
    { "raman_modes", GetMode, (XtPointer)SPECTRUM_RAMAN, NULL },
    { "ins_modes", GetMode, (XtPointer)SPECTRUM_INS, NULL }
  };
  static struct PushButtonRow radiobox2_buttons[] = {
    { "animate", GetAnimate, (XtPointer)ANIMATE, NULL },
    { "draw_arrows", GetAnimate, (XtPointer)ARROWS, NULL },
    { "distort", GetAnimate, (XtPointer)DISTORT, NULL }
  };
  static struct PushButtonRow radiobox3_buttons[] = {
    { "line_spectrum", GetType, (XtPointer)TRUE, NULL },
    { "gaussian_spectrum", GetType, (XtPointer)FALSE, NULL }
  };

  /* This function creates the dialog for the spectrum window */
 
  setMenuItem(SPECTRUM_SETTINGS, False);

  mode_save=windows[SPECTRUM].mode;
  animate_save=animate;
  lines_save=lines;
  setins_save=setins;
  weight_save=weight;
  temp_save=temp;
  amplitude_save=amplitude;
  wnScale_save=wnScale;
  xIsTop_save=xIsTop;
  showGrid_save=showGrid;
  lineWidth_save=spectrumLineWidth;

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

  /* Form1 is the row/column widget which organizes the toggle button boxes
     at the left and the sliders at the right */
  form1=XtVaCreateWidget("controlarea1", xmRowColumnWidgetClass, form,
                         XmNorientation, XmHORIZONTAL,
                         NULL);

  /* Form2 is the container for the toggle button boxes */
  form2=XtVaCreateWidget("controlarea2", xmFormWidgetClass, form1, NULL);
  sep1=XtVaCreateManagedWidget("sep1", xmSeparatorWidgetClass, form1,
                               XmNorientation, XmVERTICAL,
                               XmNtraversalOn, False,
                               XmNtopAttachment, XmATTACH_FORM,
                               XmNbottomAttachment, XmATTACH_FORM,
                               XmNleftAttachment, XmATTACH_WIDGET,
                               XmNleftWidget, form2,
                               NULL);
  /* Form3 is the container for the sliders */
  form3=XtVaCreateWidget("controlarea3", xmFormWidgetClass, form1, NULL);

  radiobox1=CreateToggleBox(form2, radiobox1_buttons, XtNumber(radiobox1_buttons),
                            XmVERTICAL, 1, True, windows[SPECTRUM].mode-1);
  XtVaSetValues(radiobox1, XmNleftAttachment, XmATTACH_FORM,
                           XmNtopAttachment, XmATTACH_FORM,
                           XmNrightAttachment, XmATTACH_FORM,
                           NULL);
  sep2=XtVaCreateManagedWidget("sep2", xmSeparatorWidgetClass, form2,
                               XmNtraversalOn, False,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, radiobox1,
                               XmNrightAttachment, XmATTACH_FORM,
                               NULL);

  radiobox2=CreateToggleBox(form2, radiobox2_buttons, XtNumber(radiobox2_buttons),
                            XmVERTICAL, 1, True, animate-1);
  XtVaSetValues(radiobox2, XmNleftAttachment, XmATTACH_FORM,
                           XmNtopAttachment, XmATTACH_WIDGET,
                           XmNtopWidget, sep2,
                           XmNrightAttachment, XmATTACH_FORM,
                           NULL);
  sep3=XtVaCreateManagedWidget("sep3", xmSeparatorWidgetClass, form2,
                               XmNtraversalOn, False,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, radiobox2,
                               XmNrightAttachment, XmATTACH_FORM,
                               NULL);

  radiobox3=CreateToggleBox(form2, radiobox3_buttons, XtNumber(radiobox3_buttons),
                            XmVERTICAL, 1, True, lines ? 0 : 1);
  XtVaSetValues(radiobox3, XmNtopAttachment, XmATTACH_WIDGET,
                           XmNtopWidget, sep3,
                           XmNleftAttachment, XmATTACH_FORM,
                           XmNrightAttachment, XmATTACH_FORM,
                           NULL); 

  temperature=XtVaCreateManagedWidget("temperature", xmLabelWidgetClass, form3,
                                      XmNleftAttachment, XmATTACH_FORM,
                                      XmNtopAttachment, XmATTACH_FORM,
                                      NULL);
  slider1=XtVaCreateManagedWidget("temperatureSlider", xmScaleWidgetClass, form3,
                                  XmNorientation, XmVERTICAL,
                                  XmNprocessingDirection, XmMAX_ON_BOTTOM,
                                  XmNvalue, (int)(temp),
                                  XmNminimum, 0,
                                  XmNmaximum, 1000,
                                  XmNshowValue, True,
                                  XmNsensitive, True,
                                  XmNleftAttachment, XmATTACH_FORM,
                                  XmNtopAttachment, XmATTACH_WIDGET,
                                  XmNtopWidget, temperature,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  NULL);
  tempSlider.number=&temp;
  tempSlider.decimals=0;
  tempSlider.draw=(void (*)())drawSpectrum;
  XtAddCallback(slider1, XmNvalueChangedCallback, (XtCallbackProc)GetSlider, &tempSlider);
  XtAddCallback(slider1, XmNdragCallback, (XtCallbackProc)GetSlider, &tempSlider);

  ampl=XtVaCreateManagedWidget("amplitude", xmLabelWidgetClass, form3,
                               XmNleftAttachment, XmATTACH_WIDGET,
                               XmNleftWidget, temperature,
                               XmNtopAttachment, XmATTACH_FORM,
                               NULL);
  slider2=XtVaCreateManagedWidget("amplitudeSlider", xmScaleWidgetClass, form3,
                                  XmNorientation, XmVERTICAL,
                                  XmNprocessingDirection, XmMAX_ON_BOTTOM,
                                  XmNshowValue, True,
                                  XmNsensitive, True,
                                  XmNleftAttachment, XmATTACH_WIDGET,
                                  XmNleftWidget, temperature,
                                  XmNtopAttachment, XmATTACH_WIDGET,
                                  XmNtopWidget, ampl,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  NULL);
  XtVaGetValues(slider2, XmNdecimalPoints, &decimals, NULL);
  XtVaSetValues(slider2, XmNvalue, (int)(amplitude*pow((double)10.0,
		    (double)decimals)/windows[VIEWER].top), NULL);
  amplitudeSlider.number=&amplitude;
  amplitudeSlider.decimals=decimals;
  amplitudeSlider.draw=NULL;
  XtAddCallback(slider2, XmNvalueChangedCallback, (XtCallbackProc)GetAmplitude,
		    &amplitudeSlider);
  XtAddCallback(slider2, XmNdragCallback, (XtCallbackProc)GetAmplitude,
		    &amplitudeSlider);

  scale=XtVaCreateManagedWidget("scale", xmLabelWidgetClass, form3,
                                XmNleftAttachment, XmATTACH_WIDGET,
                                XmNleftWidget, ampl,
                                XmNtopAttachment, XmATTACH_FORM,
                                XmNrightAttachment, XmATTACH_FORM,
                                NULL);
  slider3=XtVaCreateManagedWidget("scaleSlider", xmScaleWidgetClass, form3,
                                  XmNorientation, XmVERTICAL,
                                  XmNprocessingDirection, XmMAX_ON_BOTTOM,
                                  XmNshowValue, True,
                                  XmNsensitive, True,
                                  XmNleftAttachment, XmATTACH_WIDGET,
                                  XmNleftWidget, ampl,
                                  XmNtopAttachment, XmATTACH_WIDGET,
                                  XmNtopWidget, scale,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  NULL);
  XtVaGetValues(slider3, XmNdecimalPoints, &decimals, NULL);
  XtVaSetValues(slider3, XmNvalue, (int)(wnScale*pow((double)10.0,
		    (double)decimals)), NULL);
  scaleSlider.number=&wnScale;
  scaleSlider.decimals=decimals;
  scaleSlider.draw=NULL;
  XtAddCallback(slider3, XmNvalueChangedCallback, (XtCallbackProc)GetScale, &scaleSlider);
  XtAddCallback(slider3, XmNdragCallback, (XtCallbackProc)GetScale, &scaleSlider);

  sep4=XtVaCreateManagedWidget("sep4", xmSeparatorWidgetClass, form,
                               XmNtraversalOn, False,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, form1,
                               XmNrightAttachment, XmATTACH_FORM,
                               NULL);

  form4=XtVaCreateWidget("controlarea4", xmFormWidgetClass, form, NULL);
  ins=XtVaCreateManagedWidget("setins", xmToggleButtonWidgetClass, form4,
                              XmNleftAttachment, XmATTACH_FORM,
                              XmNtopAttachment, XmATTACH_FORM,
                              XmNbottomAttachment, XmATTACH_FORM,
                              NULL);
  if (setins) XtVaSetValues(ins, XmNset, True, NULL);
  XtAddCallback(ins, XmNvalueChangedCallback, (XtCallbackProc)GetIns, &setins);
  sprintf(str, "%f", weight);
  insweight=XtVaCreateManagedWidget("insweight", xmTextWidgetClass, form4,
                                    XmNvalue, str,
                                    XmNcolumns, 8,
                                    XmNleftAttachment, XmATTACH_WIDGET,
                                    XmNleftWidget, ins,
                                    XmNtopAttachment, XmATTACH_FORM,
                                    XmNrightAttachment, XmATTACH_FORM,
                                    XmNbottomAttachment, XmATTACH_FORM,
                                    NULL);
  XtAddCallback(insweight, XmNvalueChangedCallback, (XtCallbackProc)GetInsWeight,
                NULL);
  if (!setins) XtVaSetValues(insweight, XmNsensitive, False, NULL);

  sep5=XtVaCreateManagedWidget("sep5", xmSeparatorWidgetClass, form,
                               XmNtraversalOn, False,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, insweight,
                               XmNrightAttachment, XmATTACH_FORM,
                               NULL);

  form5=XtVaCreateWidget("controlarea5", xmFormWidgetClass, form, NULL);
  axisTop=XtVaCreateManagedWidget("axisTop", xmToggleButtonWidgetClass, form5,
                                  XmNleftAttachment, XmATTACH_FORM,
                                  XmNtopAttachment, XmATTACH_FORM,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  NULL);
  if (xIsTop) XtVaSetValues(axisTop, XmNset, True, NULL);
  XtAddCallback(axisTop, XmNvalueChangedCallback, (XtCallbackProc)GetOption, &xIsTop);
  showGridWidget=XtVaCreateManagedWidget("showGrid", xmToggleButtonWidgetClass, form5,
                                         XmNleftAttachment, XmATTACH_WIDGET,
                                         XmNleftWidget, axisTop,
                                         XmNtopAttachment, XmATTACH_FORM,
                                         XmNbottomAttachment, XmATTACH_FORM,
                                         NULL);
  if (showGrid) XtVaSetValues(showGridWidget, XmNset, True, NULL);
  XtAddCallback(showGridWidget, XmNvalueChangedCallback, (XtCallbackProc)GetOption, &showGrid);
  sprintf(str, "%f", spectrumLineWidth);
  lineWidthWidget=XtVaCreateManagedWidget("lineWidth", xmTextWidgetClass, form5,
                                          XmNvalue, str,
                                          XmNcolumns, 4,
                                          XmNtopAttachment, XmATTACH_FORM,
                                          XmNrightAttachment, XmATTACH_FORM,
                                          XmNbottomAttachment, XmATTACH_FORM,
                                          NULL);
  XtAddCallback(lineWidthWidget, XmNvalueChangedCallback, (XtCallbackProc)GetLineWidth,
                NULL);
  lineWidthLabel=XtVaCreateManagedWidget("lineWidthLabel", xmLabelWidgetClass, form5,
                                         XmNrightAttachment, XmATTACH_WIDGET,
			                       XmNrightWidget, lineWidthWidget,
                                         XmNtopAttachment, XmATTACH_FORM,
                                         XmNbottomAttachment, XmATTACH_FORM,
                                         NULL);

  sep6=XtVaCreateManagedWidget("sep6", xmSeparatorWidgetClass, form,
                               XmNtraversalOn, False,
                               XmNleftAttachment, XmATTACH_FORM,
                               XmNtopAttachment, XmATTACH_WIDGET,
                               XmNtopWidget, axisTop,
                               XmNrightAttachment, XmATTACH_FORM,
                               NULL);
  XtManageChild(form1);
  XtManageChild(form2);
  XtManageChild(form3);
  XtManageChild(form4);
  XtManageChild(form5);

  CreatePushButtonRow(form, buttons, 2);
  XtAddCallback(dialog, XmNpopupCallback, (XtCallbackProc)MapBox, (XmAnyCallbackStruct *)NULL);
  XtManageChild(form);
  XtManageChild(board);
}

void GetMode(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  struct MOLECULE *mol;
  char t[7], *string, line[MAXLENLINE];

  if (data->set)
  {
    windows[SPECTRUM].mode=(int)which;
    mol=&molecules[windows[SPECTRUM].set];
    sprintf(t, "title%.1d", windows[SPECTRUM].mode);
    string=getStringResource(XtParent(windows[SPECTRUM].widget), t);
    sprintf(line, string, mol->title);
    setWindowTitle(windows[SPECTRUM].widget, line);
    if (mol->mode != -1)
    {
      if ((windows[SPECTRUM].mode == SPECTRUM_IR &&
           mol->normal_modes[mol->mode].ir_intensity == 0.0) ||
          (windows[SPECTRUM].mode == SPECTRUM_RAMAN &&
           mol->normal_modes[mol->mode].raman_intensity == 0.0))
      {
        mol->mode=(-1);
        if (animate == ANIMATE) setAnimation(FALSE);
        else                    restoreGeometry(mol->coord, windows[SPECTRUM].set);
        redraw(VIEWER);
      }
    }
    drawSpectrum((Widget)0, (caddr_t)0, (XmDrawingAreaCallbackStruct *)0);
  }
}

void GetAnimate(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  if (data->set)
  {
    animate=(int)which;
    if (animate == ANIMATE) setAnimation(animate);
    else
    {
      setAnimation(FALSE);
      if (animate == DISTORT)
        distortGeometry(amplitude);
    }
    redraw(VIEWER);
  }
}

void GetType(Widget button, caddr_t which, XmToggleButtonCallbackStruct *data)
{
  if (data->set)
  {
    if ((int)which)
      lines=TRUE;
    else
      lines=FALSE;
    drawSpectrum((Widget)0, (caddr_t)0, (XmDrawingAreaCallbackStruct *)0);
  }
}

void GetAmplitude(Widget button, struct SLIDER *slider,
			XmScrollBarCallbackStruct *data)
{
  *(slider->number)=(double)(data->value)*windows[VIEWER].top/pow((double)10.0,
                    (double)slider->decimals);
  restoreGeometry(molecules[windows[SPECTRUM].set].coord, windows[SPECTRUM].set);
  if (animate == DISTORT) distortGeometry(amplitude);
  redraw(VIEWER);
}

void GetScale(Widget button, struct SLIDER *slider,
		  XmScrollBarCallbackStruct *data)
{
  *(slider->number)=(double)(data->value)/pow((double)10.0,
			  (double)slider->decimals);
  redraw(SPECTRUM);
  redraw(VIEWER);
}

void GetIns(Widget button, caddr_t dest, XmToggleButtonCallbackStruct *data)
{
  const GLfloat black[4] = {0.0, 0.0, 0.0, 0.0};
  char line[MAXLENLINE], *word;

  if (data->set)
  {
    *(int *)dest=TRUE;
    XtVaSetValues(insweight, XmNsensitive, True,  NULL);
    word=getStringResource(topShell, "selectINSTitle");
    sprintf(line, word, weight);
    setinsAnnotation=makeAnnotation(setinsAnnotation, CENTERED, 0.0, 1.0,
                                    0.0, stdcol[BLACK], black, 0, 0, line);
  }
  else
  {
    *(int *)dest=FALSE;
    XtVaSetValues(insweight, XmNsensitive, False, NULL);
    deleteAnnotation(&setinsAnnotation);
  }
  redraw(VIEWER);
}

void GetInsWeight(Widget button, caddr_t dummy, XmToggleButtonCallbackStruct *data)
{
  const GLfloat black[4] = {0.0, 0.0, 0.0, 0.0};
  char line[MAXLENLINE], *word;

  GetDouble(button, (caddr_t)&weight, data);
  word=getStringResource(topShell, "selectINSTitle");
  sprintf(line, word, weight);
  setinsAnnotation=makeAnnotation(setinsAnnotation, CENTERED, 0.0, 1.0,
                                  0.0, stdcol[BLACK], black, 0, 0, line);
  redraw(VIEWER);
}

void GetOption(Widget button, caddr_t dest, XmToggleButtonCallbackStruct *data)
{
  if (data->set)
    *(int *)dest=TRUE;
  else
    *(int *)dest=FALSE;
  redraw(SPECTRUM);
}

void GetLineWidth(Widget field, caddr_t dummy, XmToggleButtonCallbackStruct *data)
{
  GetDouble(field, (caddr_t)&spectrumLineWidth, data);
  redraw(SPECTRUM);
}

void GetDouble(Widget button, caddr_t dest, XmToggleButtonCallbackStruct *data)
{
  char *str;

  str=XmTextGetString(button);
  *(double *)dest=atof(str);
}

void spectrumDialogExit(Widget button, caddr_t which, XmPushButtonCallbackStruct *data)
{
  char t[7], *string, line[MAXLENLINE];

  if (!(int)which)
  {
    windows[SPECTRUM].mode=mode_save;
    animate=animate_save;
    lines=lines_save;
    setins=setins_save;
    weight=weight_save;
    temp=temp_save;
    amplitude=amplitude_save;
    wnScale=wnScale_save;
    xIsTop=xIsTop_save;
    showGrid=showGrid_save;
    spectrumLineWidth=lineWidth_save;
    deleteAnnotation(&setinsAnnotation);
    restoreGeometry(molecules[windows[SPECTRUM].set].coord, windows[SPECTRUM].set);
    sprintf(t, "title%.1d", windows[SPECTRUM].mode);
    string=getStringResource(XtParent(windows[SPECTRUM].widget), t);
    sprintf(line, string, molecules[windows[SPECTRUM].set].title);
    setWindowTitle(windows[SPECTRUM].widget, line);
  }
  XtDestroyWidget(dialog);
  setMenuItem(SPECTRUM_SETTINGS, True);
  redraw(SPECTRUM);
  redraw(VIEWER);
}
