/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                                 Z O O M . C                                  *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: zoom.c,v 1.6 2003/11/07 11:17:44 jrh Exp $
* $Log: zoom.c,v $
* Revision 1.6  2003/11/07 11:17:44  jrh
* Release 2.4
*
* Revision 1.5  2000/12/10 15:19:37  jrh
* Release 2.3
*
* Revision 1.4  1999/05/24 01:28:10  jrh
* Release 2.2.1
*
* Revision 1.3  1999/02/07 22:00:33  jrh
* Release 2.2
*
* Revision 1.2  1998/01/26 00:49:55  jrh
* Release 2.1
*
* Revision 1.1  1996/12/10  18:44:37  jrh
* Initial revision
*
*/
#include<X11/Xlib.h>
#include<X11/Intrinsic.h>
#include<Xm/DrawingA.h>
#include "viewmol.h"

extern void drawSpectrum(Widget, caddr_t, caddr_t);
extern void drawMODiagram(Widget, caddr_t, caddr_t);
extern void setWindowColor(int, Pixel, const float *);
extern void pixelToWorld(int, double *, double *);
extern void *getmem(size_t, size_t);
extern void *expmem(void *, size_t, size_t);
extern void fremem(void **);
extern void setMenuItem(int, int);
extern void redraw(int);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern int swapBuffers, nbasfu;
static int mouseInitX, mouseInitY, window, zoomRec=0;
static struct ZOOM *zoomOld=NULL;

void zoomIn(Widget widget, XmDrawingAreaCallbackStruct *data)
{
/* This subroutine is called when the user wants to zoom
   into the spectrum or into the MO diagram. It is called
   when the middle mouse button is held down and the mouse
   is moved. */

  Dimension width, height;

  swapBuffers=FALSE;
  if (widget == windows[SPECTRUM].widget)
  {
    drawSpectrum((Widget)0, (caddr_t)0, (caddr_t)0);
    window=SPECTRUM;
  }
  else if (widget == windows[MO].widget)
  {
    drawMODiagram((Widget)0, (caddr_t)0, (caddr_t)0);
    window=MO;
  }
  swapBuffers=TRUE;

  XtVaGetValues(windows[window].widget, XmNwidth, &width, XmNheight, &height, NULL);
  glEnable(GL_LINE_STIPPLE);                             /* Dotted lines */
  glLineStipple(1, 0x5555);
  glLineWidth((GLfloat)1.);
  setWindowColor(FOREGROUND, windows[window].foreground, windows[window].foreground_rgb);
  glPushMatrix();
  glLoadIdentity();
  glOrtho(0.0, (double)width, 0.0, (double)height, 0.0, 1.0);
  glBegin(GL_LINE_LOOP);
  glVertex2i(mouseInitX, mouseInitY);
  glVertex2i(mouseInitX, height-data->event->xmotion.y);
  glVertex2i(data->event->xmotion.x, height-data->event->xmotion.y);
  glVertex2i(data->event->xmotion.x, mouseInitY);
  glEnd();
  glDisable(GL_LINE_STIPPLE);
  glXSwapBuffers(XtDisplay(widget), XtWindow(widget));
  glPopMatrix();
}

void initZoom(Widget widget, XmDrawingAreaCallbackStruct *data)
{
  Dimension height;

  XtVaGetValues(widget, XmNheight, &height, NULL);
  mouseInitX=data->event->xbutton.x;
  mouseInitY=height-data->event->xbutton.y;
}

void saveZoom(int window)
{
  if (zoomOld == NULL)
    zoomOld=(struct ZOOM *)getmem(zoomRec+1, sizeof(struct ZOOM));
  else
    zoomOld=(struct ZOOM *)expmem((void *)zoomOld, zoomRec+1, sizeof(struct ZOOM));

  zoomOld[zoomRec].window=window;
  zoomOld[zoomRec].left=windows[window].left;
  zoomOld[zoomRec].right=windows[window].right;
  zoomOld[zoomRec].bottom=windows[window].bottom;
  zoomOld[zoomRec++].top=windows[window].top;
}

void endZoom(Widget widget, int x, int y)
{
  Dimension height;
  double xpix, ypix, save;

/* Copy final values and be careful that these are not
   equal to the start values. */

  pixelToWorld(window, &xpix, &ypix);
  XtVaGetValues(widget, XmNheight, &height, NULL);

  saveZoom(window);

  if (window == SPECTRUM)
  {
    save=windows[window].left;
    if (mouseInitX < x)
    {
      windows[window].left=(mouseInitX-windows[window].horizontalMargin)*xpix+save;
      windows[window].right=(x-windows[window].horizontalMargin)*xpix+save;
    }
    else if (mouseInitX == x)
    {
      windows[window].left=(mouseInitX-windows[window].horizontalMargin)*xpix+save;
      windows[window].right=(mouseInitX-windows[window].horizontalMargin+1)*xpix+save;
    }
    else
    {
      windows[window].left=(x-windows[window].horizontalMargin)*xpix+save;
      windows[window].right=(mouseInitX-windows[window].horizontalMargin)*xpix+save;
    }
  }
  y=height-y;
  save=windows[window].bottom;
  if (mouseInitY < y)
  {
    windows[window].top=(y-windows[window].verticalMargin)*ypix+save;
    windows[window].bottom=(mouseInitY-windows[window].verticalMargin)*ypix+save;
  }
  else if (mouseInitY == y)
  {
    windows[window].top=(mouseInitY-windows[window].verticalMargin+1)*ypix+save;
    windows[window].bottom=(mouseInitY-windows[window].verticalMargin)*ypix+save;
  }
  else
  {
    windows[window].top=(mouseInitY-windows[window].verticalMargin)*ypix+save;
    windows[window].bottom=(y-windows[window].verticalMargin)*ypix+save;
  }

  if (window == SPECTRUM)
  {
    drawSpectrum((Widget)0, (caddr_t)0, (caddr_t)0);
    setMenuItem(SPECTRUM_ZOOMOUT, True);
  }
  else if (window == MO)
  {
    drawMODiagram((Widget)0, (caddr_t)0, (caddr_t)0);
    setMenuItem(MO_ZOOMOUT, True);
  }
}

void zoomOut(Widget widget, caddr_t window, XmDrawingAreaCallbackStruct *data)
{
  register int i, j, w;

  w=(int)window;
  for (i=zoomRec-1; i>=0; i--)
  {
    if (zoomOld[i].window == w)
    {
      windows[w].left=zoomOld[i].left;
      windows[w].right=zoomOld[i].right;
      windows[w].bottom=zoomOld[i].bottom;
      windows[w].top=zoomOld[i].top;
      for (j=i+1; j<zoomRec; j++)
      {
        zoomOld[i].window=zoomOld[j].window;
        zoomOld[i].left=zoomOld[j].left;
        zoomOld[i].right=zoomOld[j].right;
        zoomOld[i].bottom=zoomOld[j].bottom;
        zoomOld[i].top=zoomOld[j].top;
        i++;
      }
      zoomRec--;
      if (zoomRec == 0)
      {
        fremem((void **)&zoomOld);
        switch (w)
        {
          case SPECTRUM: setMenuItem(SPECTRUM_ZOOMOUT, False);
                         break;
          case MO:       setMenuItem(MO_ZOOMOUT, False);
                         break;
        }
      }
      else
        zoomOld=(struct ZOOM *)expmem((void *)zoomOld, zoomRec, sizeof(struct ZOOM));
      break;
    }
  }
  redraw(w);
}

int checkZoom(int window)
{
  struct MOLECULE *mol;
  register int i, found=FALSE;

  if (zoomRec == 0) return(FALSE);

  for (i=0; i<zoomRec; i++)
  {
    if (zoomOld[i].window == window)
    {
	if (window == MO)
	{
	  mol=&molecules[windows[MO].set];
        zoomOld[i].bottom=1.05*mol->orbitals[0].energy;
        zoomOld[i].top=1.05*mol->orbitals[mol->nbasfu-1].energy;
      }
	found=TRUE;
      break;
    }
  }
  return(found);
}
