/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                             A N N O T A T E . C                              *
*                                                                              *
*                  Copyright (c) Joerg-R. Hill, October 2003                   *
*                                                                              *
********************************************************************************
*
* $Id: annotate.c,v 1.5 2003/11/07 10:56:25 jrh Exp $
* $Log: annotate.c,v $
* Revision 1.5  2003/11/07 10:56:25  jrh
* Release 2.4
*
* Revision 1.4  2000/12/10 15:01:05  jrh
* Release 2.3
*
* Revision 1.3  1999/05/24 01:24:31  jrh
* Release 2.2.1
*
* Revision 1.2  1999/02/07 21:43:52  jrh
* Release 2.2
*
* Revision 1.1  1998/01/26 00:33:05  jrh
* Initial revision
*
*/
#include<stdio.h>
#include<string.h>
#include<X11/StringDefs.h>
#include<X11/cursorfont.h>
#include<Xm/Xm.h>
#include<Xm/Text.h>
#include "viewmol.h"

void modifyAnnotation(int, int, int);
void getAnnotation(Widget, caddr_t, caddr_t);
int  makeAnnotation(int, int, float, float, float, int, const GLfloat *, int,
                    int, char *);
void deleteAnnotation(int *);
void moveAnnotation(int, double, double);
void setAnnotation(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
int TextGetBaseline(Widget);

extern void redraw(int);
extern void pixelToWorld(int, double *, double *);
extern void setCursor(Widget, unsigned int);
extern int StringWidth(XFontStruct *, char *);
extern int StringHeight(XFontStruct *);
extern void *getmem(size_t, size_t);
extern void *expmem(void *, size_t, size_t);
extern void fremem(void **);
extern char *getStringResource(Widget, char *);
extern void getScreenCoordinates(double, double, double, double *, double *,
                                 double *);
extern void modifyGeometry(int, char *);
extern PyLabelSpecObject *label_new(void);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern struct ANNOTATION *annotation;
extern int nAnnotations, annotate, imol;
extern Pixel stdcol[9];

void modifyAnnotation(int which, int x, int y)
{
  XmFontListEntry entry;
  XmFontList fontlist;
  XmFontType ret;
  XFontStruct *font;
  Widget text;
  Dimension width, height;
  Pixel bg;
  int l, xs;
  char str[MAXLENLINE], def[]="variable";
  register char *p; 

  if ((which != (-1)) || annotate)
  {
    if ((p=getStringResource(windows[VIEWER].widget, "font")) == NULL) p=def;
    entry=XmFontListEntryLoad(XtDisplay(windows[VIEWER].widget), p, XmFONT_IS_FONT, "TAG");
    fontlist=XmFontListAppendEntry(NULL, entry);
    font=(XFontStruct *)XmFontListEntryGetFont(entry, &ret);
    XmFontListEntryFree(&entry);
    XtVaGetValues(windows[VIEWER].widget, XtNbackground, &bg, NULL);
    text=XtVaCreateWidget("annotation", xmTextWidgetClass, windows[VIEWER].widget,
                          XmNfontList, fontlist,
                          XmNshadowThickness, 0,
                          XmNmarginWidth, 3,
                          XmNmarginHeight, 0,
                          XmNcolumns, 10,
                          XmNresizeWidth, True,
                          XtNbackground, bg,
                          NULL);
/*  Lesstif does not yet have XmTextGetBaseline implemented */
/*  height=XmTextGetBaseline(text); */
    height=TextGetBaseline(text);
    if (which == (-1)) XtVaSetValues(text, XmNx, x-3, XmNy, y-height-1, NULL);
    if (which != (-1))
    {
      annotation[which].widget=text;
      XtVaGetValues(windows[VIEWER].widget, XmNwidth, &width, XmNheight, &height, NULL);
      XtVaSetValues(annotation[which].widget, XmNx, (Position)(0.5*(annotation[which].x+1.0)*(double)width),
                XmNy, height-(Position)(0.5*(annotation[which].y+1.0)*(double)height+TextGetBaseline(annotation[which].widget)),
                NULL);
/*    moveAnnotation(which, 2.0*(double)x/(double)width, 2.0*(double)y/(double)height); */
      xs=(int)(0.5*(annotation[which].x+1.0)*(double)width);
      l=xs;
      p=annotation[which].text;
      while (*p && (l < x))
      {
        strncpy(str, annotation[which].text, p-annotation[which].text+1);
        str[p-annotation[which].text+1]='\0';
        p++;
        l=xs+StringWidth(windows[VIEWER].font, str);
      }
      if (annotation[which].text[0])
      {
        XtVaSetValues(annotation[which].widget, XmNvalue, annotation[which].text,
                      XmNcursorPosition, (XmTextPosition)(p-annotation[which].text-1),
                      XmNcolumns, (int)strlen(annotation[which].text),
                      NULL);
        annotation[which].flags&=~DRAWANN;
      }
    }
    XtManageChild(text);
    XtAddCallback(text, XmNactivateCallback, (XtCallbackProc)getAnnotation, (XmAnyCallbackStruct *)which);
    XmProcessTraversal(text, XmTRAVERSE_CURRENT);
  }
  setCursor(windows[VIEWER].widget, XC_top_left_arrow);
  annotate=FALSE;
}

void getAnnotation(Widget w, caddr_t which, caddr_t call_data)
{
  Dimension h;
  Position x, y;
  const GLfloat black[4] = {0.0, 0.0, 0.0, 0.0};
  double xpix, ypix;
  int i, active;
  char *text;

  active=(int)which;
  text=XmTextGetString(w);
  if (*text != '\0')
  {
    XtVaGetValues(w, XmNx, &x, XmNy, &y, NULL);
    pixelToWorld(VIEWER, &xpix, &ypix);
/*  h=XmTextGetBaseline(w); */
    h=TextGetBaseline(w);

    if (active == (-1))
    {
      x+=3;
      y+=h;
      i=makeAnnotation((-1), COORDINATES, (float)(windows[VIEWER].left+x*xpix),
                       (float)(windows[VIEWER].top-y*ypix), 0.0,
                       stdcol[BLACK], black, EDITABLE | MOVEABLE, (-1), text); 
    }
    else
    {
      if (annotation[active].flags & GEOMETRY)
      {
        molecules[imol].internals[annotation[active].userdata].type=
         (-molecules[imol].internals[annotation[active].userdata].type);
        if (strcmp(annotation[active].text, text))
          modifyGeometry(annotation[active].userdata, text);
        deleteAnnotation(&active);
      }
      else
      {
        strcpy(annotation[active].text, text);
        annotation[active].flags|=DRAWANN;
      }
      active=(-1);
    }
  }
  else
    deleteAnnotation(&active);
  XtFree(text);
  XtDestroyWidget(w);
}

int makeAnnotation(int which, int type, float x, float y, float z, int color,
                   const GLfloat color_rgb[4], int flags, int userdata, char *text)
{
  PyLabelSpecObject *newLabel;
  Dimension width, height;
  double xpix, ypix;
  register int i;

  if (which == (-1))
  {
    nAnnotations++;
    if (annotation == NULL)
      annotation=(struct ANNOTATION *)getmem(1, sizeof(struct ANNOTATION));
    else
      annotation=(struct ANNOTATION *)expmem((void *)annotation, nAnnotations,
                                             sizeof(struct ANNOTATION));
    which=nAnnotations-1;
  }
  if ((newLabel=label_new()) != NULL)
  {
    newLabel->labelID=which;
    annotation[which].pyObject=newLabel;
  }
  annotation[which].widget=NULL;
  if (text != NULL)
    strncpy(annotation[which].text, text, MAXLENLINE-1);
  XtVaGetValues(windows[VIEWER].widget, XtNwidth, &width, XtNheight, &height, NULL);
  pixelToWorld(VIEWER, &xpix, &ypix);
  if (type == CENTERED)
  {
    i=StringHeight(windows[VIEWER].font);
    annotation[which].x=((windows[VIEWER].left+windows[VIEWER].right
                        -xpix*(double)StringWidth(windows[VIEWER].font,
                        annotation[which].text)))/((double)width*xpix);
    annotation[which].y=2.0*(windows[VIEWER].top-2.*(double)y*ypix*(double)i)/((double)height*ypix);
    annotation[which].z=0.0;
  }
  else
  {
    /* x and y are in pixels */
    annotation[which].x=2.0*x/((double)width*xpix);
    annotation[which].y=2.0*y/((double)height*ypix);
    annotation[which].z=z;
  }
  annotation[which].color=color;
  annotation[which].color_rgb[0]=color_rgb[0];
  annotation[which].color_rgb[1]=color_rgb[1];
  annotation[which].color_rgb[2]=color_rgb[2];
  annotation[which].color_rgb[3]=color_rgb[3];
  annotation[which].flags=flags | DRAWANN;
  annotation[which].userdata=userdata;

  return(which);
}

void deleteAnnotation(int *which)
{
  register int i;

  if (*which != (-1))
  {
    Py_DECREF(annotation[*which].pyObject);
    if (annotation[*which].widget)
    {
      XtDestroyWidget(annotation[*which].widget);
      annotation[*which].widget=NULL;
    }
  }
  if (*which > (-1) && *which != nAnnotations-1)
  {
    for (i=(*which)+1; i<nAnnotations; i++)
    {
      (annotation[i-1].pyObject)->labelID=i-1;
      annotation[i-1].widget=annotation[i].widget;
      annotation[i-1].x=annotation[i].x;
      annotation[i-1].y=annotation[i].y;
      annotation[i-1].z=annotation[i].z;
      annotation[i-1].color=annotation[i].color;
      annotation[i-1].color_rgb[0]=annotation[i].color_rgb[0];
      annotation[i-1].color_rgb[1]=annotation[i].color_rgb[1];
      annotation[i-1].color_rgb[2]=annotation[i].color_rgb[2];
      annotation[i-1].color_rgb[3]=annotation[i].color_rgb[3];
      annotation[i-1].flags=annotation[i].flags;
      annotation[i-1].userdata=annotation[i].userdata;
      strcpy(annotation[i-1].text, annotation[i].text);
    }
  }
  if (*which != (-1))
  {
    nAnnotations--;
    if (nAnnotations)
      annotation=(struct ANNOTATION *)expmem((void *)annotation, nAnnotations,
                  sizeof(struct ANNOTATION));
    else
      fremem((void *)&annotation);
    *which=(-1);
  }
}

void scaleAnnotation(float scale)
{
  register int i;

  for (i=0; i<nAnnotations; i++)
  {
    if (annotation[i].flags & MOVEABLE)
    {
      annotation[i].x*=scale;
      annotation[i].y*=scale;
      annotation[i].z*=scale;
    }
  }
}

void moveAnnotation(int which, double x, double y)
{
  Dimension width, height;

  annotation[which].x=x;
  annotation[which].y=y;
  if (annotation[which].widget)
  {
    XtVaGetValues(windows[VIEWER].widget, XmNwidth, &width, XmNheight, &height, NULL);
    XtVaSetValues(annotation[which].widget, XmNx, (Position)(0.5*(double)width*(x+1.0)),
                  XmNy, (Position)(0.5*(double)height*(y+1.0)-TextGetBaseline(annotation[which].widget)),
                  NULL);
  }
}

void setAnnotation(Widget w, caddr_t data, XmDrawingAreaCallbackStruct *dummy)
{
  setCursor(windows[VIEWER].widget, XC_xterm);
  annotate=TRUE;
  redraw(VIEWER);
}

int TextGetBaseline(Widget w)
{
  XmFontList fontlist;
  XmFontContext context;
  XmFontListEntry entry;
  XmFontType ret;
  XFontStruct *font=(XFontStruct *)NULL;
  Dimension margin;

  XtVaGetValues(w, XmNfontList, &fontlist, XmNmarginHeight, &margin, NULL);
  if (!XmFontListInitFontContext(&context, fontlist)) return(0);
  if ((entry=XmFontListNextEntry(context)) != NULL)
    font=(XFontStruct *)XmFontListEntryGetFont(entry, &ret);
  XmFontListFreeFontContext(context);
  return(font->ascent+margin+1);
}
