/** Functions for drawing GTK graphic on gg_canvas
 *  Transcripted from Motif to GTK+ by P. Vincent to
 *  Replace xutil.c
 * 
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>


#include <cmath.h>
#include "globals.h"
#include "plotone.h"
#include "files.h"
#include "utils.h"
#include "noxprotos.h"

#include "gg_gutil.h"
#include "gg_gtkdrv.h"
#include "gg_protos.h"

/* for gg_graphappwin.c */
#include "gw_list.h"
#include "gg_gtkinc.h"

#include "ng_objects.h"

#define pv5_width  16
#define pv5_height 16

static char pv5_bits[] = {
 0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x00,0x00,0x3f,
 0xfc,0x3f,0xfc,0x00,0x00,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,
 0x80,0x01 };

static char bmask_bits[] = {
 0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xff,
 0xff,0xff,0xff,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,
 0x80,0x01 };



extern GdkDisplay *gg_disp;

extern GdkGC *gg_gc ,*gg_bg_gc;
extern GtkWidget *gg_main_window ,*gg_canvas;

extern GdkWindow *gg_win;  /* replace xwin */

static GdkPixmap *gg_bufpixmap =  NULL;

extern char batchfile[];
extern int inpipe;

extern GdkDisplay *gg_disp;
extern GdkGC *gg_gc ,*gg_gcxor;

extern gint gg_win_h ,gg_win_w;   // win_h ,win_w
extern GtkWidget *gg_loclab;	  /* locator label  loclab */

extern GdkColor gg_colors[MAXCOLORS];  

extern void ge_wait_cursor (int sw);
GdkCursor *wait_cursor;
static GdkCursor *line_cursor;
static GdkCursor *find_cursor;
static GdkCursor *move_cursor;
static GdkCursor *text_cursor;
static GdkCursor *kill_cursor;
static GdkCursor *pv5_cursor;
static int cur_cursor = -1;

/**
 *  Replace set_wait_cursor   xutil.c 85
 */
void gg_set_wait_cursor ()
{
  if (gg_win == NULL) return;
  gdk_window_set_cursor (gg_win, wait_cursor);
  ge_wait_cursor (TRUE);
}

void gg_unset_wait_cursor()
{
  if (gg_win == NULL) return;
  /* With GTK cur_cursor is also <0 */
  gg_set_cursor (cur_cursor);
  ge_wait_cursor (FALSE);
}

/**
 *  Replace  set_cursor      xutil.c   106
 */
void gg_set_cursor (int c)
{
  if (gg_disp == NULL) return;
  cur_cursor = c;
  switch (c) {
  case 0:
    gdk_window_set_cursor (gg_win, line_cursor);
    break;
  case 1:
    gdk_window_set_cursor (gg_win, find_cursor);
    break;
  case 2:
    gdk_window_set_cursor (gg_win, text_cursor);
    break;
  case 3:
    gdk_window_set_cursor (gg_win, kill_cursor);
    break;
  case 4:
    gdk_window_set_cursor (gg_win, move_cursor);
    break;
  case 5:
    gdk_window_set_cursor (gg_win ,pv5_cursor);
    break;
  default:
    cur_cursor = -1;
    gdk_window_set_cursor (gg_win, NULL);
    break;
  }
  gdk_display_flush (gg_disp);
}

/**
 *  Replace  init_cursors     xutils.c   137
 */
void gg_init_cursors (void)
{
  wait_cursor = gdk_cursor_new  (GDK_WATCH);
  line_cursor = gdk_cursor_new  (GDK_CROSSHAIR);
  find_cursor = gdk_cursor_new  (GDK_HAND2);
  text_cursor = gdk_cursor_new  (GDK_XTERM);
  kill_cursor = gdk_cursor_new  (GDK_PIRATE); // display a X cross (?)
  move_cursor = gdk_cursor_new  (GDK_FLEUR);
  cur_cursor = -1;

   GdkPixmap *source, *mask;
   source = gdk_bitmap_create_from_data (NULL ,pv5_bits ,pv5_width ,pv5_height);
   mask = gdk_bitmap_create_from_data (NULL ,(char *)bmask_bits ,pv5_width ,pv5_height);
   pv5_cursor = gdk_cursor_new_from_pixmap (source, mask, &gg_colors[1] ,&gg_colors[0] ,8 ,8);
   gdk_pixmap_unref (source);
   gdk_pixmap_unref (mask);
}


/** Put a string in the title bar of the window
 *  Replace set_title   xutils.c   121
 */
void gg_set_title (char *ts)
{
  static char *ts_save = NULL;
  static int dstate_save = 0;
  int dstate = is_dirtystate();

  if (!inwin || ts == NULL)  return;

  if (ts_save == NULL || strcmp(ts_save, ts) != 0 || dstate != dstate_save) {
    char *buf1, *buf2;
    ts_save = copy_string(ts_save, ts);
    dstate_save = dstate;
    buf1 = copy_string(NULL, "Grace: ");
    buf1 = concat_strings(buf1, ts);
    buf2 = copy_string(NULL, ts);
    if (dstate) {
      buf2 = concat_strings(buf2, "*");
      buf1 = concat_strings(buf1, " (modified)");
    }
    gtk_window_set_title (GTK_WINDOW(gg_main_window) ,buf1);
    gtk_window_set_icon_name (GTK_WINDOW(gg_main_window) ,buf2);
    xfree(buf1);
    xfree(buf2);
  }
  gtk_window_set_title (GTK_WINDOW(gg_main_window), ts);
}


/*
 *  Auxiliary routines for simultaneous drawing on display and pixmap
 */

/**
 * Replace aux_XDrawLine   xutils.c  181
 */
static void gg_aux_DrawLine (int x1, int y1, int x2, int y2)
{
  gdk_draw_line (gg_win ,gg_gcxor ,x1 ,y1 ,x2 ,y2);
  if (gg_bufpixmap != NULL) {
    gdk_draw_line (gg_bufpixmap ,gg_gcxor ,x1 ,y1 ,x2 ,y2);
  }
}

/**
 * Replace aux_XDrawRectangle  xutils.c  189
 */
static void gg_aux_DrawRectangle (int x1, int y1, int x2, int y2)
{
  gdk_draw_rectangle (gg_win ,gg_gcxor ,FALSE ,x1 ,y1 ,x2 ,y2);
  if (gg_bufpixmap != NULL) {
    gdk_draw_rectangle (gg_bufpixmap ,gg_gcxor ,FALSE ,x1 ,y1 ,x2 ,y2);
  }
}

/**
 * Replace aux_XFillRectangle  xutils.c  197
 */
static void gg_aux_FillRectangle (int x1, int y1, int x2, int y2)
{
  if (gg_win != NULL) {
    gdk_draw_rectangle (gg_win ,gg_gcxor ,TRUE ,x1 ,y1 ,x2 ,y2);
  }
  if (gg_bufpixmap != NULL) {
    gdk_draw_rectangle (gg_bufpixmap ,gg_gcxor ,TRUE ,x1 ,y1 ,x2 ,y2);
  }
}

/**
 *  Replace 
 */
void gg_draw_rect (VPoint vp)
{
  int x, y;
  gg_VPoint2dev (vp, &x, &y);
  gg_aux_FillRectangle (x - 6, y - 6, 12, 12);
}

/** Draw the graph focus indicators
 *  Replace draw_focus  xutils.c 209
 */
void gg_draw_focus(int gno)
{
  int ix1, iy1, ix2, iy2;
  view v;
  VPoint vp;
    
  if (draw_focus_flag == TRUE) {
    get_graph_viewport(gno, &v);
    vp.x = v.xv1;
    vp.y = v.yv1;
    gg_VPoint2dev(vp, &ix1, &iy1);
    vp.x = v.xv2;
    vp.y = v.yv2;
    gg_VPoint2dev(vp, &ix2, &iy2);
    gg_aux_FillRectangle(ix1 - 5, iy1 - 5, 10, 10);
    gg_aux_FillRectangle(ix1 - 5, iy2 - 5, 10, 10);
    gg_aux_FillRectangle(ix2 - 5, iy2 - 5, 10, 10);
    gg_aux_FillRectangle(ix2 - 5, iy1 - 5, 10, 10);
  }
}


/** Rubber band line (optionally erasing previous one)
 *  Replace select_line  xutils.c 233
 */

void gg_select_line (int x1, int y1, int x2, int y2, int erase)
{
  static int x1_old, y1_old, x2_old, y2_old;

  if (erase) {
    gg_aux_DrawLine (x1_old, y1_old, x2_old, y2_old);
  }
  x1_old = x1;
  y1_old = y1;
  x2_old = x2;
  y2_old = y2;
  gg_aux_DrawLine(x1, y1, x2, y2);
}

void gg_select_2lines (int x1, int y1, int x2, int y2, int x3, int y3, int erase)
{
  static int x1_old, y1_old, x2_old, y2_old ,x3_old, y3_old;

  if (erase) {
    gg_aux_DrawLine (x1_old, y1_old, x2_old, y2_old);
    gg_aux_DrawLine (x3_old, y3_old, x2_old, y2_old);
  }
  x1_old = x1;
  y1_old = y1;
  x2_old = x2;
  y2_old = y2;
  x3_old = x3;
  y3_old = y3;
  gg_aux_DrawLine(x1, y1, x2, y2);
  gg_aux_DrawLine(x3, y3, x2, y2);
}

/** Draw an xor'ed box (optionally erasing previous one)
 *  Replace select_region  xutils.c 251
 */
void gg_select_region (int x1, int y1, int x2, int y2, int erase)
{
  static int x1_old, y1_old, dx_old, dy_old;
  int dx = x2 - x1;
  int dy = y2 - y1;

  if (dx < 0) {
    iswap(&x1, &x2);
    dx = -dx;
  }
  if (dy < 0) {
    iswap(&y1, &y2);
    dy = -dy;
  }
  if (erase) {
    gg_aux_DrawRectangle (x1_old, y1_old, dx_old, dy_old);
  }
  x1_old = x1;
  y1_old = y1;
  dx_old = dx;
  dy_old = dy;
  gg_aux_DrawRectangle (x1, y1, dx, dy);
}

/**
 *  gg_select_region_scale draw an xor'ed box for scaling objects
 *  must be called 1st time with erase=0 to store static values
 *  
 */
static int anchor_xc, anchor_yc ,dxc ,dyc;

void gg_select_region_scale (int anchor_x ,int anchor_y ,int x2 ,int y2 ,int erase ,int pmask)
{
  int dx ,dy;

  if (pmask & MA_2_HANDLES) {
    gg_select_line (anchor_x ,anchor_y ,x2 ,y2 ,erase);
    anchor_xc = anchor_x;
    anchor_yc = anchor_y;
    dxc = x2 - anchor_x;
    dyc = y2 - anchor_y;
  } else if (pmask & MA_CENTERED) {
    if (erase) {
      gg_aux_DrawRectangle (anchor_xc - dxc ,anchor_yc - dyc ,2*dxc ,2*dyc);
    }
    anchor_xc = anchor_x;
    anchor_yc = anchor_y;
    dxc = abs (x2 - anchor_x);
    dyc = abs (y2 - anchor_y);
    if (pmask & MA_X_EQ_Y) {
      dxc = (dyc > dxc) ? dyc : dxc;
      dyc = dxc;
    }
    gg_aux_DrawRectangle (anchor_xc - dxc ,anchor_yc - dyc ,2*dxc ,2*dyc);
  } else {
    if (erase) {
      gg_aux_DrawRectangle (anchor_xc ,anchor_yc ,dxc ,dyc);
    }
    dx = dxc = x2 - anchor_x;
    dy = dyc = y2 - anchor_y;
    if (dx < 0) {
      iswap (&anchor_x, &x2);
      dxc = -dx;
    }
    if (dy < 0) {
      iswap (&anchor_y, &y2);
      dyc = -dy;
    }
    if (pmask & MA_X_EQ_Y) {
      dxc = (dyc > dxc) ? dyc : dxc;
      dyc = dxc;
    }
    anchor_xc = (dx < 0) ? x2 - dxc : anchor_x;
    anchor_yc = (dy < 0) ? y2 - dyc : anchor_y;
    gg_aux_DrawRectangle (anchor_xc ,anchor_yc ,dxc ,dyc);
  }
}

void gg_get_cur_square (int pmask ,VPoint *vp1 ,VPoint *vp2) 
{
  if (pmask & MA_CENTERED) {
    *vp1 = gg_gtk2VPoint (anchor_xc-dxc ,anchor_yc-dyc);
  } else {
    *vp1 = gg_gtk2VPoint (anchor_xc     ,anchor_yc    );
  }
  *vp2 = gg_gtk2VPoint (anchor_xc+dxc ,anchor_yc+dyc);
}

void gg_select_region_or_line  (Qtype typ ,int x1, int y1, int x2, int y2, int erase)
{
  if (typ == Q_Line || typ == Q_Polyline) {
    gg_select_line (x1 ,y1 ,x2 ,y2 ,erase);
  } else {
    gg_select_region (x1 ,y1 ,x2 ,y2 ,erase);
  }
}



/**
 *  Slide an xor'ed bbox, (and optionally a center mark)
 *  optionally erasing previous one(s)
 *  Replace slide_region  xutils.c  278
 */
void gg_slide_region (view bb, int shift_x, int shift_y, int erase ,int center)
{
    int x1, x2;
    int y1, y2;
    VPoint vp;
    static int xc ,yc;

    vp.x = bb.xv1;
    vp.y = bb.yv1;
    gg_VPoint2dev (vp, &x1, &y1);
    x1 += shift_x;
    y1 += shift_y;
    
    vp.x = bb.xv2;
    vp.y = bb.yv2;
    gg_VPoint2dev (vp, &x2, &y2);
    x2 += shift_x;
    y2 += shift_y;
    
    gg_select_region (x1, y1, x2, y2, erase);
    
    if (center) {
      if (erase) gg_aux_DrawRectangle (xc-3 ,yc-3 ,6 ,6);
      xc = (x1 + x2) / 2;
      yc = (y1 + y2) / 2;
      gg_aux_DrawRectangle (xc-3, yc-3, 6 ,6);
    }
}

static int crosshair_erase = FALSE;

void gg_reset_crosshair (void)
{
  crosshair_erase = FALSE;
}

/** Draw a crosshair cursor
 *  Replace crosshair_motion     xutil.c  309
 */
void gg_crosshair_motion (int x, int y)
{
    static int cursor_oldx, cursor_oldy;
    
    /* Erase the previous crosshair */
    if (crosshair_erase == TRUE) {
        gg_aux_DrawLine (0, cursor_oldy, gg_win_w, cursor_oldy);
        gg_aux_DrawLine (cursor_oldx, 0, cursor_oldx, gg_win_h);
    }

    /* Draw the new crosshair */
    gg_aux_DrawLine (0, y, gg_win_w, y);
    gg_aux_DrawLine (x, 0, x, gg_win_h);
    crosshair_erase = TRUE;
    cursor_oldx = x;
    cursor_oldy = y;
}


/** Callback for "expose-event" emitted by gg_canvas
 *  Replace expose_resize
 */
gboolean gg_expose_resize_CB (GtkWidget *w ,GdkEventExpose *event, gpointer data)
{
  static int inc = 0;

   if (!inc) {
     /* The first time, we initialize the drawing area */
     inwin = TRUE;
     inc++;
     if (batchfile[0]) getparms (batchfile);
     if (inpipe == TRUE) {
       getdata (get_cg (), "stdin", SOURCE_DISK, LOAD_SINGLE);
       inpipe = FALSE;
     }

     /* gg_gc is initialized here since I don't how to do in gg_init
      * Seems logical if "expose_event" is connected to gg_canvas
      */
     gg_gc = gdk_gc_new (GDK_DRAWABLE(gg_canvas->window));

     gg_update_all ();
     gg_drawgraph();
     return TRUE;
   }

   /* After the "expose_event", redraw the area exposed
    * Replace the call to xlibredraw in xutil.c 367
    */
   gg_redraw (gg_canvas
	   ,event->area.x
	   ,event->area.y
	   ,event->area.width
	   ,event->area.height
	   );
   return TRUE;
}

/** Draw graph if iwin && auto_redraw
 *  Replace xdrawgraph    xutil.c 384
 */
void gg_drawgraph (void)
{
  if (inwin && (auto_redraw) ) {
    gg_set_wait_cursor();
    clear_all_handles ();
    drawgraph();
    gg_unset_wait_cursor();
  }
}

/**
 *  Replace xlibredraw
 */
void gg_redraw (GtkWidget *gg_canvas ,int x ,int y ,int width ,int height)
{
  if (inwin == TRUE && gg_bufpixmap !=  NULL) {
    gdk_draw_drawable (GDK_DRAWABLE(gg_canvas->window) ,gg_gc ,gg_bufpixmap
		       ,x ,y ,x ,y ,width, height);
  }
}

/** Resize the gg_displaybuff
 *  Replace resize_bufpixmap          xutil.c 401
 */
GdkPixmap *gg_resize_bufpixmap (int w ,int h)
{
    static  int pixmap_w = 0, pixmap_h = 0;
    
    if (w == 0 || h == 0) {
        return (gg_bufpixmap);
    }
    if (gg_bufpixmap == NULL) { 
      gg_bufpixmap = gdk_pixmap_new (GDK_DRAWABLE(gg_canvas->window)
				  ,(gint)w ,(gint)h ,-1);
      g_object_ref (gg_bufpixmap);        //<<<<<<<<<<< inutile ?
      /* Draw the background of the pixmap  */
      gg_bg_gc = gg_canvas->style->bg_gc[GTK_STATE_NORMAL];
    } else if (pixmap_w != w || pixmap_h != h) {
      g_object_unref (gg_bufpixmap);       //<<<<<<<<<<< inutile ?
      gg_bufpixmap = gdk_pixmap_new (GDK_DRAWABLE (gg_canvas->window) ,(gint)w ,(gint)h ,-1);
      /* Draw the background of the pixmap  */
      gg_bg_gc = gg_canvas->style->bg_gc[GTK_STATE_NORMAL];
    }
    
    if (gg_bufpixmap == NULL) {
        g_error ("Can't allocate buffer pixmap");
        pixmap_w = 0;
        pixmap_h = 0;
        return (NULL);
    } else {
        pixmap_w = w;
        pixmap_h = h;
        return (gg_bufpixmap);
    }
}


/**
 *  Replace xunregister_rti     xutil.c   437
 */
void gg_unregister_rti (GIOChannel *channel)
{
  if (gg_disp !=NULL) {
    g_io_channel_unref (channel);
  }
}

/** Callback for pipes events **/

/**
 *  Replace xmonitor_rti    xutil.c  428
 */
gboolean gg_monitor_rti (GIOChannel *channel ,GIOCondition condition ,gpointer pib)
{
  gg_set_wait_cursor ();
  monitor_input ((Input_buffer *) pib, 1, 1);
  gg_unset_wait_cursor ();
  return TRUE;  // ???????????????? dans xmonitor_rti, le type est void
}



/**
 *  Replace xregister_rti     xutil.c   445
 */
void gg_Xregister_rti (Input_buffer *ib)
{
  if (gg_disp !=NULL) {
    ib->channel = g_io_channel_unix_new (ib->fd);
    g_io_add_watch (ib->channel ,G_IO_IN ,gg_monitor_rti ,ib);   // xmonitor_rti
  }
}

/**
 *  Makes a table with "nx" rows" and "ny" columns.
 *  Use this one into a "gg_frame" because xx and yy (gg_frame_attach)
 *    are not compatible with a new table 
 */
GtkWidget *gg_tableau (GtkWidget *parent ,gchar *label
		       ,GdkColor *couleur ,int nx ,int ny)
{
  GtkWidget *event ,*frame ,*table;
  event = gtk_event_box_new ();  
  gtk_box_pack_start (GTK_BOX (parent) ,event , TRUE , FALSE , 5);
  gtk_widget_modify_bg (GTK_WIDGET(event), GTK_STATE_NORMAL ,couleur);
  frame = gtk_frame_new (label);
  gtk_container_add (GTK_CONTAINER (event) ,frame);
  table = gtk_table_new (nx ,ny ,FALSE);
  gtk_container_add (GTK_CONTAINER (frame) ,table);
  return (table);
}

/*
 * set format string for locator
 */
static char *typestr[6] = {"World (X,Y)"
			   ,"DX, DY"
			   ,"Distance"
			   ,"Phi, Rho"
			   ,"Viewport (X,Y)"
			   ,"Pixels (X,Y)"};

/**
 *  LOCATOR on MAIN_PANEL
 *   Replace getpoints   815
 */
void gg_getpoints (VPoint *vpp)
{
  static VPoint vp = {0.0, 0.0};
  int cg = get_cg();
  double wx ,wy ,xtmp ,ytmp;
  int x ,y;
  double dsx = 0.0 ,dsy = 0.0;
  char buf[256] ,bufx[64] ,bufy[64] ,*s;
  GLocator locator;
    
  if (vpp != NULL) {
    vp = *vpp;
  }
    
  view2world (vp.x ,vp.y ,&wx ,&wy);
  if (get_graph_locator(cg ,&locator) != RETURN_SUCCESS) {
    gtk_label_set_text (GTK_LABEL(gg_loclab) ,"[No graphs]");
    return;
  }
    
  if (locator.pointset) {
    dsx = locator.dsx;
    dsy = locator.dsy;
  }
    
    switch (locator.pt_type) {
    case 0:
        if (get_graph_type(cg) == GRAPH_POLAR) {
            polar2xy (wx ,wy ,&xtmp ,&ytmp);
        } else {
            xtmp = wx;
            ytmp = wy;
        }
        break;
    case 1:
        xtmp = wx - dsx;
        ytmp = wy - dsy;
        break;
    case 2:
        if (get_graph_type(cg) == GRAPH_POLAR) {
            polar2xy (wx ,wy ,&xtmp ,&ytmp);
        } else {
            xtmp = wx;
            ytmp = wy;
        }
        xtmp = hypot (dsx - xtmp ,dsy - ytmp);
        ytmp = 0.0;
        break;
    case 3:
        if (dsx - wx != 0.0 || dsy - wy != 0.0) {
            xy2polar(wx - dsx ,wy - dsy ,&xtmp ,&ytmp);
        } else {
            xtmp = 0.0;
            ytmp = 0.0;
        }
        break;
    case 4:
        xtmp = vp.x;
        ytmp = vp.y;
        break;
    case 5:
        gg_VPoint2dev(vp ,&x ,&y);
        xtmp = x;
        ytmp = y;
        break;
    default:
        return;
    }
    s = create_fstring (locator.fx ,locator.px ,xtmp ,LFORMAT_TYPE_PLAIN);
    strcpy (bufx ,s);
    s = create_fstring (locator.fy ,locator.py ,ytmp ,LFORMAT_TYPE_PLAIN);
    strcpy (bufy ,s);
    if (locator.pt_type < 4) {
      sprintf (buf ,"G%1d: %s = [%s, %s]" ,cg ,typestr[locator.pt_type] ,bufx ,bufy);
    } else {
      sprintf (buf ,"%s = [%s, %s]" ,typestr[locator.pt_type] ,bufx ,bufy);

    }
    gtk_label_set_text (GTK_LABEL(gg_loclab) ,buf);
    
}


/**
 *  Replace switch_current_graph  events.c  1268
 */
void gg_switch_current_graph (int gno)
{
  GtkWidget *graph_list;
  int saveg = get_cg();
  if (!is_valid_gno (gno)) return;
  if (gno == get_cg ())    return;

  if (is_graph_hidden(gno) == FALSE) {
    select_graph (gno);
    gg_draw_focus (saveg);
    gg_draw_focus (gno);
    gg_update_all();

    if ( (graph_list = gg_get_fileswin_graph_list ()) != NULL) {
      gw_list_unselect_all (GW_LIST(graph_list));
      gw_list_select       (GW_LIST(graph_list) ,gno);
    }
    gg_getpoints (NULL);
    gg_drawgraph ();
    gg_update_bt_graph ();
  }
}

void gg_switch_current_set (int gno ,int setno)
{
  if (is_graph_hidden(gno) == FALSE) {
    gg_switch_current_graph (gno);
  }
}

/**
********************* Handles management ****************
*/

/**
 *  gg_handles:  low level function to  draw/clear nh  (i.e. 2 or 4) handles
 *               and optionally draw the center 
 *  Based on a XORed GC by calling gg_aux_FillRectangle
 */
void gg_handles (view v ,int nh ,int center)
{
  int ix1, iy1, ix2, iy2;
  VPoint vp;
    
  vp.x = v.xv1;
  vp.y = v.yv1;
  gg_VPoint2dev (vp, &ix1, &iy1);
  vp.x = v.xv2;
  vp.y = v.yv2;
  gg_VPoint2dev (vp, &ix2, &iy2);
  gg_aux_FillRectangle (ix1 - 3, iy1 - 3, 6, 6);
  gg_aux_FillRectangle (ix2 - 3, iy2 - 3, 6, 6);
  if (nh == 4) {
    gg_aux_FillRectangle (ix1 - 3, iy2 - 3, 6, 6);
    gg_aux_FillRectangle (ix2 - 3, iy1 - 3, 6, 6);
  }
  if (center) {
    vp.x = 0.5 * (v.xv1 + v.xv2);
    vp.y = 0.5 * (v.yv1 + v.yv2);
    gg_VPoint2dev (vp, &ix1, &iy1);
    gg_aux_DrawRectangle (ix1 - 3, iy1 - 3, 6, 6);
  }
}

void gg_one_handle (VPoint vp)
{
  int ix, iy;
  gg_VPoint2dev (vp, &ix, &iy);
  gg_aux_FillRectangle (ix - 3, iy - 3, 6, 6);
}
