// Please see the README file or the LEGAL NOTES-section in the manual before modifying, compiling or using 'xmrm'
//   Idea: Manfred Kopp
//   Programming: Gerhard Waldhör, Andreas Artmann

#include <forms.h>
#include "morphvec.h"
#include "init.h"
#include "const.h"
#include "io.h"
#include "xmrm.h"
//#include "areas.h"

//static int oneliner = 1;

extern FD_MORPH *fd_MORPH;
extern FD_VEC_MENU *fd_VEC_MENU;

extern Display *disp;

extern int max_x,max_y;
extern ControlClass control;
extern VisualInfoClass vis;
extern WindowClass *s_win, *d_win;
extern MyImageClass *MyImage;
extern GC gc;
extern FL_OBJECT *obj_vs,*obj_vd,*obj_s,*obj_d;

/* Class PictureClass: */
extern PictureClass *s_pic, *d_pic; 

/* Constructor:        */
PictureClass::PictureClass()
{
  pic = NULL;
  pic_x=0; pic_y=0;
}

/* Destructor:        */
PictureClass::~PictureClass()
{
  free (pic);
}

/* Method: InitMem */
int PictureClass::InitMem()
{
  // Allocating or reallocating memory for pictures:
  if (pic == NULL) 
  {
    if ( (pic = (unsigned long *)malloc(pic_x*pic_y*sizeof(unsigned long))) == NULL )
    {
      fl_show_alert("WARNING:","Not enough memory available !","" ,1);
      return -1;
    }
  }
  else 
  {
    if ( (pic = (unsigned long *)fl_realloc(pic, pic_x*pic_y*sizeof(unsigned long))) == NULL )
    {
      fl_show_alert("WARNING:","Not enough memory available !","" ,1);
      return -1;
    }
  }
  
  return 0;
}

/* Method: SetPicSize */
void PictureClass::SetPicSize(int x, int y)
{
  pic_x = x; pic_y = y;
}

/* Method: GetPicSize */
void PictureClass::GetPicSize(int *x, int *y)
{
  *x = pic_x; *y = pic_y;
}

/* Method: GetPicPointer */

unsigned long *PictureClass::GetPicPointer()
{
  return pic;
}

/* Method: SetPicPointer */
void PictureClass::SetPicPointer(unsigned long *pic_ptr)
{
  pic = pic_ptr;
}

/* MyImageClass: */

/* Constructor: */
MyImageClass::MyImageClass()
{
  pic_scal = NULL;
  image = NULL;
}

/* Destructor: */
MyImageClass::~MyImageClass()
{
  if (image != NULL)
  {
//    free(pic_scal);
    XDestroyImage(image);
  }
//  image=NULL;
}  


/* Method InitImage: */
int MyImageClass::InitImage(int x,int y)
{
  if (pic_scal==NULL)
  {
    if ( (pic_scal = (char *)malloc(x*y*(vis.p_fetch/8))) == NULL )
    {
      fl_show_alert("WARNING:","Not enough memory available !","" ,1);
      return -1;
    }
  }  
  else
  {
    if ( (pic_scal = (char *)realloc(pic_scal,x*y*(vis.p_fetch/8))) == NULL )
    {
      fl_show_alert("WARNING:","Not enough memory available !","" ,1);
      return -1;
    }
  }  

  if (x==0) image=NULL;
  else
  /* Create image: */
  if ( (image = XCreateImage(disp,vis.xvis_info->visual,vis.depth,ZPixmap,0,pic_scal,
                                     x,y,32,x*(vis.p_fetch/8))) == NULL)
  {
    fl_show_alert("ERROR:","Cannot create image !","",1);
    return -2;
  }
  
  image_x=x; image_y=y;
  
//  printf ("Mem adress: %d\n",(void *)pic_scal);
  
  return 0;
}

/* Method GetImage: */

XImage *MyImageClass::GetImage()
{
  return image;
}

/* Method ShowImage: */
void MyImageClass::ShowImage(FL_OBJECT *obj,Window win)
{
  XPutImage(disp,win,gc,image,0,0,obj->x,obj->y,obj->w,obj->h);  
}

/* Method MapPicture: */
void MyImageClass::MapPicture(FL_OBJECT *obj, PictureClass *pic_class)
{
  unsigned long i,j,col,adr, rmask,gmask,bmask;
  unsigned long *raster;
  double x,y,dx,dy;
  int px,py, rshift,gshift,bshift;
  
  rmask = (256-(1<<(8-vis.red_len)));
  gmask = (256-(1<<(8-vis.green_len))) << 8;
  bmask = (256-(1<<(8-vis.blue_len))) << 16;
  
  rshift = 24 - (vis.red_beg + vis.red_len);
  gshift = 24 - (vis.green_beg + vis.green_len);
  bshift = 24 - (vis.blue_beg + vis.blue_len);
  
//  printf ("%x  %x  %x   %d %d %d \n",rmask,gmask,bmask,rshift,gshift,bshift);
  
  pic_class->GetPicSize(&px,&py);
  raster = pic_class->GetPicPointer();

  dx = (double) px / obj->w; dy = (double) py / obj->h; 
    
  y=0;
  for (j=0; j<obj->h; j++) 
  {
    x=0;
    for (i=0; i<obj->w; i++)
    {
      adr = (unsigned long)y * px + (unsigned long)x;
      col = raster[adr];
      XPutPixel(image,i,j,   ((col & bmask) >> bshift) 
                          | (((col & gmask) << 8) >> gshift) 
                          | (((col & rmask) << 16) >> rshift) ); 
      // ...this confusing left-right-shifting is necessary to be compatible to different DirectColor modes !

      x+=dx;
    }
    y+=dy;
  }
}

/* Method MapArea */
void MyImageClass::MapArea(FL_OBJECT *obj, PictureClass *pic_class, unsigned char *raster)
{
  unsigned long i,j,col,adr, rmask,gmask,bmask;
  double x,y,dx,dy;
  int px,py, rshift,gshift,bshift;
  
  rmask = (256-(1<<(8-vis.red_len)));
  gmask = (256-(1<<(8-vis.green_len))) << 8;
  bmask = (256-(1<<(8-vis.blue_len))) << 16;
  
  rshift = 24 - (vis.red_beg + vis.red_len);
  gshift = 24 - (vis.green_beg + vis.green_len);
  bshift = 24 - (vis.blue_beg + vis.blue_len);
  
//  printf ("%x  %x  %x   %d %d %d \n",rmask,gmask,bmask,rshift,gshift,bshift);
  
  pic_class->GetPicSize(&px,&py);

  dx = (double) px / obj->w; dy = (double) py / obj->h; 
    
  y=0;
  for (j=0; j<obj->h; j++) 
  {
    x=0;
    for (i=0; i<obj->w; i++)
    {
      adr = (unsigned long)y * px + (unsigned long)x;
      col = (unsigned long) raster[adr];

      col = col | (col << 8) | (col << 16);

      XPutPixel(image,i,j,   ((col & bmask) >> bshift) 
                          | (((col & gmask) << 8) >> gshift) 
                          | (((col & rmask) << 16) >> rshift) ); 
      // ...this confusing left-right-shifting is necessary to be compatible to different DirectColor modes !

      x+=dx;
    }
    y+=dy;
  }
}


/* Method RemapPicture: */
unsigned long *MyImageClass::RemapPicture(FL_OBJECT *obj)
{
  unsigned long i,j,adr,col,rmask,gmask,bmask;
  unsigned long *raster;  
  int px,py, rshift,gshift,bshift;

  rmask = vis.xvis_info->red_mask;
  gmask = vis.xvis_info->green_mask;
  bmask = vis.xvis_info->blue_mask;
  
  rshift = 24 - (vis.red_beg + vis.red_len);
  gshift = 24 - (vis.green_beg + vis.green_len);
  bshift = 24 - (vis.blue_beg + vis.blue_len);

  // Get Memory for remapped image:
  if ( (raster=(unsigned long *)malloc(image_x*image_y*sizeof(unsigned long))) == NULL )
  {
    fl_show_alert("WARNING:","Not enough memory available !","" ,1);
    return raster;
  }
  
  adr=0;
  for (j=0; j<image_y; j++)
    for (i=0; i<image_x; i++)  
    {
      col = XGetPixel(image, i,j);
      raster[adr]=   0xff000000 // alpha value
                   | (((col & rmask)<<rshift) >> 16)
                   | (((col & gmask)<<gshift) >> 8)
                   | ((col & bmask)<<bshift) ;
      adr++;
    }
  return raster;
}

/* Class MorphVecClass: */

extern MorphVecClass *s_vec,*d_vec;

/* Constructor: */
MorphVecClass::MorphVecClass()
{
  nr_vec=0;
}

/* Method NewVek: */
int MorphVecClass::NewVec(FL_OBJECT *obj,int nxa,int nya,int nxe,int nye,int con)
{
  double sc_x,sc_y;
  sc_x = (double)max_x / obj->w; sc_y = (double)max_y / obj->h;

  nr_vec++;
  if (nr_vec>=MAX_VEC)
  {
    nr_vec--;
    fl_show_alert("INFORMATION:","Vector limit reached !","",1);
    return -1;
  }
    
  xa[nr_vec]=sc_x*(nxa-obj->x);   ya[nr_vec]=sc_y*(nya-obj->y);   
  xe[nr_vec]=sc_x*(nxe-obj->x);   ye[nr_vec]=sc_y*(nye-obj->y); 
  connect[nr_vec]=con;

  return 0;
}

/* Method DelVec: */
void MorphVecClass::DelVec(int item)
{
  if (item > nr_vec)
  {
    printf("Warning: Wrong vector number, MorphVekClass::DelVek()\n");
    return;
  }

  for (int i=item; i<nr_vec; i++)
  {
    xa[i]=xa[i+1];   ya[i]=ya[i+1];   xe[i]=xe[i+1];   ye[i]=ye[i+1]; connect[i]=connect[i+1];
  }
  connect[item]=0; // no longer connected
  
  nr_vec--; // If nr_vek==0, then no more vector can be selected for DelVek
}

/* Method RepVec: */    
void MorphVecClass::RepVec(FL_OBJECT *obj,int rxa,int rya,int rxe,int rye,int item)
{
  double sc_x,sc_y;
  sc_x = (double) max_x / obj->w; sc_y = (double) max_y / obj->h;

  if (item > nr_vec)
  {
    printf("Warning: Wrong vector number, MorphVekClass::RepVek()\n");
    return;
  }
 
  xa[item]=sc_x*(rxa-obj->x);   ya[item]=sc_y*(rya-obj->y);   
  xe[item]=sc_x*(rxe-obj->x);   ye[item]=sc_y*(rye-obj->y); 
}

/* Method NormVec: */
void MorphVecClass::NormVec()
{
  for (int i=1; i<=nr_vec; i++)
  {
    xa[i]=xa[i]/max_x; xe[i]=xe[i]/max_x;
    ya[i]=ya[i]/max_y; ye[i]=ye[i]/max_y;
  }
}

/* Method DeNormVec: */
void MorphVecClass::DeNormVec()
{
  for (int i=1; i<=nr_vec; i++)
  {
    xa[i]=xa[i]*max_x; xe[i]=xe[i]*max_x;
    ya[i]=ya[i]*max_y; ye[i]=ye[i]*max_y;
  }

}
/* Method SearchVec: */
int MorphVecClass::SearchVec(FL_OBJECT *obj,int sx,int sy,int *flag_found)
{
  int i,found;
  double sc_x,sc_y, mx,my, rad, norm, qnorm, PQx,PQy, PXx, PXy, u,v, xx,yy;
  sc_x = (double)max_x / obj->w; sc_y = (double)max_y / obj->h;
  mx = sc_x*(sx-obj->x);   my = sc_y*(sy-obj->y);     

  if (nr_vec == 0) return 0;
  
  rad = Q_SEARCH_RAD;
  i=0; found=0;
  do
  {
    i++;  
  
    PQx = xe[i]-xa[i]; PQy = ye[i]-ya[i];
    PXx = mx-xa[i]; PXy = my-ya[i];
    qnorm = ( PQx*PQx + PQy*PQy );
    u = ( PXx*PQx + PXy*PQy )/qnorm;
    
    if (u<0.0) { xx=PXx*PXx; yy=PXy*PXy; v=xx+yy; }
    else if (u>1.0) { xx=mx-xe[i]; xx*=xx; yy=my-ye[i]; yy*=yy; v=xx+yy; }
      else { v = PXx*(-PQy) + PXy*PQx; v=(v*v)/qnorm; }

    if (v < rad)
    {
      if (u<0.5) *flag_found=1; else *flag_found=2;
      found=i;
      rad=v;
    }
  } while (i<nr_vec);
    
  return found;
}

/* Method DrawVector: */
void MorphVecClass::DrawVector(int xa,int ya, int xe, int ye, int mode, FL_COLOR col)
{
  double norm, vx,vy,nx,ny;
  FL_POINT point[4];
  
  // Calculate points for arrow:
  vx=(double)(xe-xa); vy=(double)(ye-ya);
  norm = sqrt(vx*vx+vy*vy);
  vx=vx/norm; vy=vy/norm;
  nx=-vy; ny=vx;

  // Set arrow points:  
  point[0].x = xe + (int) (ARROW_V*-vx+ARROW_N*nx); point[0].y =  ye + (int) (ARROW_V*-vy+ARROW_N*ny);
  point[1].x = xe + (int) (ARROW_V*-vx-ARROW_N*nx); point[1].y = ye + (int) (ARROW_V*-vy-ARROW_N*ny);
  point[2].x = xe; point[2].y = ye;

  fl_linewidth(0); fl_drawmode(mode); fl_linestyle(LineSolid);
  fl_line(xa,ya,xe,ye,FL_BLACK);
  fl_linestyle(LineOnOffDash); 
  fl_line(xa,ya,xe,ye,col);  
  fl_linestyle(LineSolid); fl_linewidth(1);
  fl_polybound(point,3,col);  
}

/* Method DrawVectorScal */
void MorphVecClass::DrawVectorScal(FL_OBJECT *obj, int item, int mode, FL_COLOR col)
{
  double sc_x,sc_y;
  sc_x = (double) obj->w / max_x; sc_y = (double) obj->h / max_y;
  
  if (item > nr_vec)
  {
    printf("Warning: Wrong vector number ! (MorphVecClass::DrawVectorScal())\n");
    return;
  }
  
  DrawVector(int((sc_x*xa[item])+obj->x),int((sc_y*ya[item])+obj->y),
             int((sc_x*xe[item])+obj->x),int((sc_y*ye[item])+obj->y),mode,col);
  
  fl_linestyle(LineSolid); fl_linewidth(1); fl_drawmode(GXcopy);        
}

/* Method MapVectors: */
void MorphVecClass::MapVectors(FL_OBJECT *obj,int exept1,int exept2)
{
  int i;
  
  for (i=1; i<=nr_vec; i++)
    if (i != exept1 && i!= exept2) DrawVectorScal(obj,i,GXcopy,FL_WHITE);
}

/* Method GetMaxVec: */
int MorphVecClass::GetMaxVec()
{
  return nr_vec;
}

/* Method SetMaxVec: */
void MorphVecClass::SetMaxVec(int items)
{
  nr_vec = items;
}

/* Method GetVec: */
void MorphVecClass::GetVec(FL_OBJECT *obj,int *gxa, int *gya, int *gxe, int *gye, int i)
{
  double sc_x,sc_y;
  sc_x = (double) obj->w / max_x; sc_y = (double) obj->h / max_y;
  
  *gxa = (int)((sc_x*xa[i])+obj->x);
  *gya = (int)((sc_y*ya[i])+obj->y);
  *gxe = (int)((sc_x*xe[i])+obj->x);
  *gye = (int)((sc_y*ye[i])+obj->y);
}

/* Method GetVecArray: */
void MorphVecClass::GetVecArray(double **gxa, double **gya, double **gxe, double **gye)
{
  *gxa=&xa[1]; *gya=&ya[1]; *gxe=&xe[1]; *gye=&ye[1];
}

int MorphVecClass::GetCon(int item)
{
  return connect[item];
}

void MorphVecClass::GetConArray(int **con)
{
  *con=&connect[1];
}
  
/* obj_s - objecthandler: Redraws source image */
int obj_s_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  if (event == FL_DRAW)
  {
    s_win->SetWin();

    if (s_pic->GetPicPointer() != NULL)
    {
      if (s_pic->GetPicPointer() == NULL) fl_rectf(obj->x,obj->y,obj->w,obj->h,FL_COL1);

      if (MyImage->InitImage(obj->w,obj->h) != 0) return -1;
      MyImage->MapPicture(obj,s_pic);
      MyImage->ShowImage(obj,s_win->GetWin());
    }
  }
  return 0;
}

/* obj_d - objecthandler: Redraws destination image */
int obj_d_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  if (event == FL_DRAW)
  {
    d_win->SetWin();

    if (d_pic->GetPicPointer() != NULL)
    {
      if (d_pic->GetPicPointer() == NULL) fl_rectf(obj->x,obj->y,obj->w,obj->h,FL_COL1);    

      if (MyImage->InitImage(obj->w,obj->h) != 0) return -1;
      MyImage->MapPicture(obj,d_pic);
      MyImage->ShowImage(obj,d_win->GetWin());
    }
  }
  return 0;
}

/* set_vec - objecthandler: Controls vector setting & editing */
int set_vec_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my,int key, void *xev, Window win, int src_dst)
{
  static int old_src_dst=1, flag_clear_vector,i=0,vec_i=0,connect=0,w=0, what_point, what_connect=0;
  static FL_Coord x,y,xa,ya,xo,yo,xa2,ya2,xo2,yo2;
  int allow_setting;
  MorphVecClass *vec;
  FL_COLOR color;
  
  if ((control.flag_set_vector == VEC_SET) && (src_dst != old_src_dst))
    return -1;
  old_src_dst = src_dst;  

  // Choose src/dst vectors to edit
  if (src_dst) vec=s_vec; else vec=d_vec;

  // Check mouse events:
  switch (event)
  {
    case FL_DRAW: // Control drawing events:
      if (control.edit_mode==EDIT_NEW || control.edit_mode==EDIT_LINE) // drawing routines for a NEW vector:
      {
        switch(control.flag_set_vector)
        {
          case VEC_DRAWSTART:
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // Draw first xor-vector
            control.flag_set_vector = VEC_SET; control.edit_change_perm=0; // edit-mode-settings
            break;
    
          case VEC_DRAWEND: // mouse button has been released, vector is defined now,
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // clear xor-vector
            vec->DrawVectorScal(obj, vec->GetMaxVec(),GXcopy,FL_WHITE); // and draw the vector new & fine
            control.flag_set_vector = VEC_NOSET; // edit-mode-settings
            control.edit_change_perm=1; 
            allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // check what cursor to be set
            control.SetCursor(allow_setting,win);
            // maybe the next corresponding vec in src-win has to be shown:
            if (!src_dst) { control.co_vector=CO_SHOW; fl_redraw_object(obj_vs); control.co_vector=CO_OK; }
            break;
  
          case VEC_CLEAR:
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // Clear xor-vector
            fl_set_cursor(win,XC_arrow); // change cursor from X to arrow
            control.flag_set_vector = VEC_NOSET; control.edit_change_perm=1; // edit-mode-settings
            break;
      
          case VEC_SET:
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // Clear old xor-vector
            vec->DrawVector(xa,ya,x,y,GXxor,FL_WHITE); // and draw new xor-vector
            break;
  
          case VEC_NOSET:
            if (src_dst)
            {
              if (control.co_vector == CO_SHOW)
              {
                if (s_vec->GetMaxVec() > d_vec->GetMaxVec())
                  vec->DrawVectorScal(obj,d_vec->GetMaxVec()+1,GXcopy,FL_GREEN); // Draw new corresp. source vec
                if (d_vec->GetMaxVec()>0) 
                  vec->DrawVectorScal(obj,d_vec->GetMaxVec(),GXcopy,FL_WHITE); // Clear old corresp. source vec  
              }
              else if (control.co_vector == CO_HIDE)
              {
                if (s_vec->GetMaxVec() > d_vec->GetMaxVec())
                  vec->DrawVectorScal(obj,d_vec->GetMaxVec()+1,GXcopy,FL_WHITE); // Hide new corresponding source vec
              }
            }
            break;
          default: 
            ;
        }
      }
      else // EDIT_REPLACE:
      {
        if (control.edit_mode == EDIT_REPLACE) color=FL_YELLOW; else color=FL_RED;
      
        // drawing routines for an EDITED vector:
        switch (control.flag_set_vector)
        {
          case VEC_SEARCH: // mouse near a vec -> draw vec YELLOW or RED
            vec->MapVectors(obj,0,0);
            if (vec_i <= vec->GetMaxVec()) 
            {
              vec->DrawVectorScal(obj,vec_i,GXcopy,color);
              if (control.edit_mode == EDIT_REPLACE)
              {
                // end of vector: test if connected
                if (what_connect==1) vec->DrawVectorScal(obj,vec_i-1, GXcopy,color);
                if (what_connect==2) vec->DrawVectorScal(obj,vec_i+1, GXcopy,color);
              }
            }
            break;
      
          case VEC_NOSEARCH: // mouse away from vec -> draw vec WHITE
            //if (vec_i <= vec->GetMaxVec()) vec->DrawVectorScal(obj,vec_i,GXcopy,FL_WHITE);

            color=FL_WHITE;   
            if (vec_i <= vec->GetMaxVec()) 
            {
              vec->DrawVectorScal(obj,vec_i,GXcopy,color);
              if (control.edit_mode == EDIT_REPLACE)
              {
                // end of vector: test if connected
                if (what_connect==1) vec->DrawVectorScal(obj,vec_i-1, GXcopy,color);
                if (what_connect==2) vec->DrawVectorScal(obj,vec_i+1, GXcopy,color);
              }
            }
            control.flag_set_vector = VEC_NOSET;
            break;
  
          case VEC_DRAWSTART:
            if (what_connect==0) vec->MapVectors(obj,vec_i,0);
            if (what_connect==1) vec->MapVectors(obj,vec_i,vec_i-1);
            if (what_connect==2) vec->MapVectors(obj,vec_i,vec_i+1);
              
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE);  // Draw first xor-vector
            
            // connected ?:
            
            if (what_connect!=0)
              vec->DrawVector(xa2,ya2,xo2,yo2,GXxor,FL_WHITE);
            
            control.flag_set_vector = VEC_SET;
            fl_set_cursor_color(XC_arrow,color,FL_BLACK);
            break;
  
          case VEC_DRAWEND: // mouse button has been released, vector is defined now,
            vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE);  // clear xor-vector
            vec->DrawVectorScal(obj, vec_i,GXcopy,FL_WHITE);  // and draw the vector new & fine
            
            if (what_connect != 0)
            {
              vec->DrawVector(xa2,ya2,xo2,yo2,GXxor,FL_WHITE);

              if (what_connect==1)
                vec->DrawVectorScal(obj,vec_i-1,GXcopy,FL_WHITE);
              else
                vec->DrawVectorScal(obj,vec_i+1,GXcopy,FL_WHITE);             
                
              what_connect=0;
            }
            
            control.flag_set_vector = VEC_NOSET;
            control.edit_change_perm=1;
            allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // check what cursor to be set
            control.SetCursor(allow_setting,win);        
//            fl_set_cursor_color(XC_arrow,FL_GREEN,FL_BLACK);
            vec_i=0;
            break;
  
          case VEC_SET:
            if (what_point == 1) // What side of vec can be moved ?
            {
              vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // Clear old xor-vector
              vec->DrawVector(x,y,xo,yo,GXxor,FL_WHITE); // and draw new xor-vector
              
              if (what_connect!=0)
              {
                vec->DrawVector(xa2,ya2,xo2,yo2,GXxor,FL_WHITE); // Clear old xor-vector
                vec->DrawVector(xa2,ya2,x,y,GXxor,FL_WHITE); // and draw new xor-vector
              }
            }
            else
            {
              vec->DrawVector(xa,ya,xo,yo,GXxor,FL_WHITE); // Clear old xor-vector
              vec->DrawVector(xa,ya,x,y,GXxor,FL_WHITE); // and draw new xor-vector
              if (what_connect!=0)
              {
                vec->DrawVector(xa2,ya2,xo2,yo2,GXxor,FL_WHITE); // Clear old xor-vector
                vec->DrawVector(x,y,xo2,yo2,GXxor,FL_WHITE); // and draw new xor-vector
              }
            }        
            break;
  
          case VEC_CLEAR:
            if (vec_i <= d_vec->GetMaxVec())
            {
              if (src_dst) 
                d_vec->DelVec(vec_i);
              else 
                s_vec->DelVec(vec_i);
            }
            vec->DelVec(vec_i);

            control.flag_set_vector = VEC_NOSET;        
            vec_i=0;
            control.edit_change_perm=1;
            fl_set_cursor_color(XC_arrow,FL_GREEN,FL_BLACK);
            
            if (control.edit_mode == EDIT_REPLACE)
            {
              fl_set_cursor(win, XC_hand2);
            }
            else
            {
              fl_set_cursor(win, XC_pirate);
            }
  
            fl_redraw_object(obj_s); fl_redraw_object(obj_d); 
            control.SetDraw(DRAW_SRCVECTORS); fl_redraw_object(obj_vs);
            control.SetDraw(DRAW_DSTVECTORS); fl_redraw_object(obj_vd);
            break;
        
          default:
            ;
        }
      }
      fl_linestyle(LineSolid); 
      fl_linewidth(1);
      fl_drawmode(GXcopy);

    break;
      
    // Mouse enters the object-window:
    case FL_ENTER:
      allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:    
//      fl_set_cursor_color(XC_arrow,FL_GREEN,FL_BLACK);
      control.SetCursor(allow_setting,win);
      XFlush(fl_get_display());
      // When entering the dest-win, show the corresponding vector from the src-win:
      if (!src_dst) 
      {
        control.co_vector=CO_SHOW;
        fl_redraw_object(obj_vs); 
        control.co_vector=CO_OK;
      }
      break;
      
    case FL_LEAVE:
      // Set default cursor:
      fl_reset_cursor(win);
//      fl_set_cursor_color(XC_arrow,FL_BLACK,FL_WHITE);        

      // When leaving the dest-win, hide the corresponding vector from the src-win:
      if (!src_dst)
      {
        control.co_vector=CO_HIDE;
        fl_redraw_object(obj_vs); 
        control.co_vector=CO_OK;
      }
      break;

    case FL_PUSH:
      // right mouse-button pressed:

      if ( (key==3) && (control.edit_change_perm == 0) && (control.edit_mode == EDIT_LINE) )
      {
        control.flag_set_vector = VEC_CLEAR;
        fl_redraw_object(obj);
      }

      if ( (key==3) && (control.edit_change_perm == 1) )
      {
        if (control.edit_mode==EDIT_REPLACE || control.edit_mode==EDIT_DELETE)
        {
          control.flag_set_vector = VEC_NOSEARCH; fl_redraw_object(obj_vs);
          control.flag_set_vector = VEC_NOSEARCH; fl_redraw_object(obj_vd);
        }
        
        // change edit mode:          
        control.edit_mode=(control.edit_mode+1)%4;
        
        // draw new wintitle and change buttons in vector-menu:
        switch ( control.edit_mode )
        {
          case EDIT_NEW:
            fl_wintitle(fd_MORPH->MORPH->window,"SET VECTOR");
            fl_set_button(fd_VEC_MENU->BT_SetVec,1);
            fl_set_button(fd_VEC_MENU->BT_EditVec,0);
            fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
            fl_set_button(fd_VEC_MENU->BT_SetLines,0);
            break;
          case EDIT_REPLACE:
            fl_wintitle(fd_MORPH->MORPH->window,"EDIT VECTOR");
            fl_set_button(fd_VEC_MENU->BT_SetVec,0);
            fl_set_button(fd_VEC_MENU->BT_EditVec,1);
            fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
            fl_set_button(fd_VEC_MENU->BT_SetLines,0);
            break;
          case EDIT_DELETE:
            fl_wintitle(fd_MORPH->MORPH->window,"DELETE VECTOR");
            fl_set_button(fd_VEC_MENU->BT_SetVec,0);
            fl_set_button(fd_VEC_MENU->BT_EditVec,0);
            fl_set_button(fd_VEC_MENU->BT_DeleteVec,1);            
            fl_set_button(fd_VEC_MENU->BT_SetLines,0);
            break;
          case EDIT_LINE:
            fl_wintitle(fd_MORPH->MORPH->window,"SET LINE");
            fl_set_button(fd_VEC_MENU->BT_SetVec,0);
            fl_set_button(fd_VEC_MENU->BT_EditVec,0);
            fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
            fl_set_button(fd_VEC_MENU->BT_SetLines,1);
            break;
          default:
            fl_wintitle(fd_MORPH->MORPH->window,"ERROR: NO MODE !!!");
        }
        
        allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:    
        control.SetCursor(allow_setting,win);        
        vec_i=0;
        control.flag_set_vector = VEC_NOSET;
        
        if ( !src_dst && (control.edit_mode==EDIT_NEW || control.edit_mode==EDIT_LINE) ) 
        {
          control.co_vector=CO_SHOW;
          fl_redraw_object(obj_vs); 
          control.co_vector=CO_OK;
        }
        fl_redraw_object(obj);
        break;
      }

      // left mouse-button pressed:
      if (key==1)
      {
        if (control.edit_mode==EDIT_NEW) // || control.edit_mode==EDIT_LINE) // WOIDL+-
        {
          switch (control.flag_set_vector)
          {
            case VEC_NOSET:
              allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:         
              if (allow_setting)
              {
                xa=mx; ya=my;
                xo=mx; yo=my;
                control.flag_set_vector=VEC_DRAWSTART; connect=0;
                fl_redraw_object(obj);
              } 
              break;
          }
        }
        else  // EDIT_REPLACE:
        if (control.edit_mode==EDIT_REPLACE)
        {
          switch(control.flag_set_vector) 
          {
          case VEC_SEARCH:
            vec->GetVec(obj,&xa,&ya,&xo,&yo,vec_i);
            
            if (what_connect==1) vec->GetVec(obj,&xa2,&ya2,&xo2,&yo2,vec_i-1);
            if (what_connect==2) vec->GetVec(obj,&xa2,&ya2,&xo2,&yo2,vec_i+1);            

            if (what_point == 1) 
            { 
              xa=mx; ya=my; 
              xo2=mx; yo2=my;
            }
            else 
            { 
              xo=mx; yo=my; 
              xa2=mx; ya2=my;
            }
            control.flag_set_vector=VEC_DRAWSTART;

            control.edit_change_perm=0;
            
            if (src_dst) fl_redraw_object(obj_s);
            else fl_redraw_object(obj_d);            
            fl_redraw_object(obj);       
            break;
          }
        }
        else
        if (control.edit_mode==EDIT_DELETE)        
        {
          switch(control.flag_set_vector) 
          {
          case VEC_SEARCH:
            control.flag_set_vector=VEC_CLEAR;
            control.edit_change_perm=0;
            fl_redraw_object(obj);       

            break;
          }
        }
        
        // all vectors deleted:            
        if (s_vec->GetMaxVec() == 0) 
          control.vec_changed=0;
        else 
          control.vec_changed=1;
      }
      break;    

    case FL_RELEASE:
      if (key == 1)
      {
        switch (control.flag_set_vector)
        {
          case VEC_SET:
            if (flag_clear_vector)
            {
              control.flag_set_vector=VEC_CLEAR;

              if (what_connect != 0)
              {
                if (what_connect==1) 
                  vec->RepVec(obj,xa2,ya2,xo2,yo2,vec_i-1);
                else 
                  vec->RepVec(obj,xa2,ya2,xo2,yo2,vec_i+1);                
              }

              fl_redraw_object(obj); 

              // all vectors deleted:            
              if (s_vec->GetMaxVec() == 0) 
                control.vec_changed=0;
              else 
                control.vec_changed=1;
            }
            else
            {
              if (control.edit_mode==EDIT_NEW)
                vec->NewVec(obj,xa,ya,x,y,0);
              else if (control.edit_mode==EDIT_LINE)
                vec->NewVec(obj,xa,ya,x,y,connect); 
              else if (control.edit_mode==EDIT_REPLACE)
              {
                vec->RepVec(obj,xa,ya,xo,yo,vec_i);
                
                if (what_connect != 0)
                {
                  if (what_connect==1) 
                    vec->RepVec(obj,xa2,ya2,xo2,yo2,vec_i-1);
                  else 
                    vec->RepVec(obj,xa2,ya2,xo2,yo2,vec_i+1);                
                }
              }

              control.flag_set_vector=VEC_DRAWEND;
              fl_redraw_object(obj);

              if (control.edit_mode==EDIT_LINE)
              {
                allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:         
                if (allow_setting)
                {
                  xa=mx; ya=my;
                  xo=mx; yo=my;
                  control.flag_set_vector=VEC_DRAWSTART; connect=1;
                  fl_redraw_object(obj);
                } 
              }
            }
            break;

// WOIDL+
          case VEC_NOSET:            
            if (control.edit_mode==EDIT_LINE)
            {
              allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:         
              if (allow_setting)
              {
                xa=mx; ya=my;
                xo=mx; yo=my;
                control.flag_set_vector=VEC_DRAWSTART; connect=0;
                fl_redraw_object(obj);
              } 
            }
// WOIDL-          
          
            break;
        }
      }
      break;    

    case FL_MOUSE:
      if (control.edit_mode==EDIT_NEW || control.edit_mode==EDIT_LINE) //***
      {
        switch(control.flag_set_vector)
        {
          case VEC_SET:
            double distx,disty;
            distx=(double)(mx-xa); distx*=distx;
            disty=(double)(my-ya); disty*=disty;
            if ( sqrt(distx+disty) <= (double)CIRC_RAD ) 
            {
              flag_clear_vector = 1;
              fl_set_cursor(win, XC_X_cursor);
            }
            else
            {
              flag_clear_vector = 0;
              fl_set_cursor(win, XC_arrow);
            }
            // Get mouse coordinates:
            x=mx; y=my;
            // Check borders:
            if (x < obj->x) x=obj->x; if (x >= obj->x+obj->w) x=obj->x+obj->w-1;
            if (y < obj->y) y=obj->y; if (y >= obj->y+obj->h) y=obj->y+obj->h-1;
            // Draw vector:
            fl_redraw_object(obj);
            // Store old coordinates:
            xo=x; yo=y;
            break;
        }
      }
      else if (control.edit_mode != EDIT_LINE)
      {
        switch(control.flag_set_vector)
        {
          case VEC_SET:
            double distx,disty;
          
            if (what_point == 2) 
            {
              distx=(double)(mx-xa); distx*=distx;
              disty=(double)(my-ya); disty*=disty;
            }
            else
            {
              distx=(double)(mx-xo); distx*=distx;
              disty=(double)(my-yo); disty*=disty;
            }          
          
            if ( sqrt(distx+disty) <= (double)CIRC_RAD ) 
            {
              flag_clear_vector = 1;
              fl_set_cursor(win, XC_X_cursor);              
            }
            else
            {
              flag_clear_vector = 0;
              fl_set_cursor(win, XC_arrow);
            }
  
            x=mx; y=my;
            // Check borders:
            if (x < obj->x) x=obj->x; if (x >= obj->x+obj->w) x=obj->x+obj->w-1;
            if (y < obj->y) y=obj->y; if (y >= obj->y+obj->h) y=obj->y+obj->h-1;
            // Draw vector:
            fl_redraw_object(obj);
            // Store old coordinates:            
            if (what_point == 1) 
            { 
              xa=x; ya=y; 
              if (what_connect !=0) 
                xo2=x; yo2=y;
            } 
            else 
            { 
              xo=x; yo=y; 
              if (what_connect !=0) 
                xa2=x; ya2=y;
            }
            break;
        }
      }
      break;
    
    case FL_MOTION:
      if (control.edit_mode==EDIT_LINE)
      {
        switch(control.flag_set_vector)
        {
          case VEC_SET:
            double distx,disty;
            distx=(double)(mx-xa); distx*=distx;
            disty=(double)(my-ya); disty*=disty;
            if ( sqrt(distx+disty) <= (double)CIRC_RAD ) 
            {
              flag_clear_vector = 1;
              fl_set_cursor(win, XC_X_cursor);
            }
            else
            {
              flag_clear_vector = 0;
              fl_set_cursor(win, XC_arrow);
            }
            // Get mouse coordinates:
            x=mx; y=my;
            // Check borders:
            if (x < obj->x) x=obj->x; if (x >= obj->x+obj->w) x=obj->x+obj->w-1;
            if (y < obj->y) y=obj->y; if (y >= obj->y+obj->h) y=obj->y+obj->h-1;
            // Draw vector:
            fl_redraw_object(obj);
            // Store old coordinates:
            xo=x; yo=y;
            break;
        }
      }
      else
      if (control.edit_mode==EDIT_NEW) //||(control.edit_mode==EDIT_LINE)
      {
        switch(control.flag_set_vector)
        {
          case VEC_NOSET:
            allow_setting = src_dst || (s_vec->GetMaxVec()>d_vec->GetMaxVec()); // Check if edit vectors OK:                       if ( (!src_dst) && (allow_setting) && (control.co_vector==CO_SHOW) )
            {
              fl_redraw_object(obj_vs);
            }
            break;
        }
      }
      else // EDIT_REPLACE:
      {
        if (i=vec->SearchVec(obj,mx,my,&w))
        {
          if ( (i != vec_i) || (i==vec_i && w!=what_point))
          {
            vec_i=i; what_point=w;
            
            what_connect=0;
            if (what_point==1)
            {
              if (vec->GetCon(vec_i)) what_connect=1;
            }
            else
            {
              if (vec_i+1 <= vec->GetMaxVec())
                if (vec->GetCon(vec_i+1)) what_connect=2;
            }    
            control.flag_set_vector = VEC_SEARCH;
            fl_redraw_object(obj_vs);
            fl_redraw_object(obj_vd);
          }
        }
        else
        {
          if (control.flag_set_vector == VEC_SEARCH)        
          {
            control.flag_set_vector = VEC_NOSEARCH;
            fl_redraw_object(obj_vs);
            control.flag_set_vector = VEC_NOSEARCH;
            fl_redraw_object(obj_vd);            
            vec_i=0;
          }
        }
      }
      break;
      
    default:
      ;
  }
  return 0;
}

/* obj_vs - objecthandler: Redraws source vectors */
int obj_vs_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  static int x_old,y_old,w_old,h_old,win_changed;
  int x,y,w,h;

  // If size of object changes, redraw object
  fl_get_win_geometry(s_win->GetWin(),&x,&y,&w,&h);
  if ( (x_old != x) || (y_old != y) || (w_old != w) || (h_old != h) ||
       (win_changed) || (control.GetDraw() == DRAW_SRCVECTORS) )
  {
    s_vec->MapVectors(obj_vs,0,0);
    x_old=x; y_old=y; w_old=w; h_old=h; win_changed=0;
    control.SetDraw(DRAW_NOTHING);     
  }

  if (event == FL_OTHER) win_changed=1;

  // Call handler for editing vectors:
  set_vec_handler(obj,event,mx,my,key,xev,s_win->GetWin(),1);

  return 0;
}

/* obj_vd - objecthandler: Redraws destination vectors */
int obj_vd_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev)
{
  static int x_old,y_old,w_old,h_old,win_changed;
  int x,y,w,h;

  // If size of object changes, redraw object
  fl_get_win_geometry(d_win->GetWin(),&x,&y,&w,&h);
  if ( (x_old != x) || (y_old != y) || (w_old != w) || (h_old != h) ||
       (win_changed) || (control.GetDraw() == DRAW_DSTVECTORS) )
  {
    d_vec->MapVectors(obj,0,0);
    x_old=x; y_old=y; w_old=w; h_old=h; win_changed=0;
    control.SetDraw(DRAW_NOTHING);        
  }

  if (event == FL_OTHER) win_changed=1;

  // Call handler for editing vectors:
  set_vec_handler(obj,event,mx,my,key,xev,d_win->GetWin(),0);
 
  return 0;
}

