#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	grphgrab.c (Color Graph Grab Vertex)
 * Purpose:	Get or drop a color graph vertex as per a mouse button event
 * Subroutine:	grab_cgraph_vertex()		returns: void
 * Subroutine:	drop_cgraph_vertex()		returns: int
 * Copyright:	1989 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version		 11 June 1989
 *		{n} <who> -- <does what> -- <when>
 */

#include <X11/Xlib.h>		/* X window stuff */
#include <X11/Xutil.h>		/* X window manager stuff */
#include "hfiles/color.h"	/* color structs */
#include "hfiles/cgraph.h"
#include "hfiles/define.h"	/* YES, NO, MIN, MAX and more */

extern struct cgraphRec cgraph;

#define GRAB_RANGE 8	/* radius in screen pixels within which to grab mark */

/*
 * Subroutine:	grab_cgraph_vertex
 * Purpose:	When a mouse button is pressed, assign a vertex to that button
 */

static void get_color_vertex();

void get_cgraph_vertex ( event )
     XEvent *event;
{

  switch( event->xbutton.button ) {
  case Button1:
    /* note: Sun compiler sometimes muffs these pointers */
    get_color_vertex(event->xbutton.x, event->xbutton.y, &(cgraph.red));
    cgraph.red.active = 1;
    break;
  case Button2:
    get_color_vertex(event->xbutton.x, event->xbutton.y, &(cgraph.green));
    cgraph.green.active = 1;
    break;
  case Button3:
    get_color_vertex(event->xbutton.x, event->xbutton.y, &(cgraph.blue));
    cgraph.blue.active = 1;
    break;
  }
}

/*
 * Subroutine:	drop_cgraph_vertex
 * Purpose:	Delete a vertex if one is under the mouse pointer for drop
 *		event
 * Returns:	1 if a vertex was dropped, else 0
 */

static int drop_color_vertex();

int drop_cgraph_vertex ( event )
     XEvent *event;
{

  switch( event->xbutton.button ) {
  case Button1:
    return( drop_color_vertex(&cgraph.red,
			      event->xbutton.x, event->xbutton.y) );
  case Button2:
    return( drop_color_vertex(&cgraph.green,
			      event->xbutton.x, event->xbutton.y) );
  case Button3:
    return( drop_color_vertex(&cgraph.blue,
			      event->xbutton.x, event->xbutton.y) );
  default:
    return( 0 );
  }
}

/*
 * Subroutine:	get_color_vertex
 * Purpose:	Handle grab vertex event for single color 
 * Method:	Grab old vertex or make new vertex - under mouse pointer
 */

static int grab_old_color_vertex();
static void install_new_color_vertex();

static void get_color_vertex ( x, y, col )
     int x, y;
     struct colgRec *col;
{
  void install_draw_queue_end();

  /* clip against limits */
  if( x < cgraph.graph.xzero )
    x = cgraph.graph.xzero;
  else if( x > cgraph.graph.xmax )
    x = cgraph.graph.xmax;
  if( y < cgraph.graph.yzero )
    y = cgraph.graph.yzero;
  else if( y > cgraph.graph.ymax )
    y = cgraph.graph.ymax;
  if( grab_old_color_vertex(x, y, col) == 0 )
    install_new_color_vertex(x, y, col);
  install_draw_queue_end(col);
}

/*
 * Subroutine:	grab_old_color_vertex
 * Purpose:	Check to see if position is close to an existing hash mark.
 *		If so, set active markers.
 * Returns:	1 if a vertex was grabbed, else 0
 */
static int grab_old_color_vertex ( x, y, col )
     int x, y;
     struct colgRec *col;
{
  int i, match;
  XRectangle *hash;

  hash = col->hash;
  if( col->hash_cnt <= 0 )
    return( 0 );
  /* hash mark positions are upper left corner of hash box */
  x -= HASH_RAY;
  y -= HASH_RAY;
  match = -1;
  /* loop to look for close vertices */
  for( i = 0; i < col->hash_cnt; i++) {
    if( (abs(hash[i].x - x) < GRAB_RANGE) &&
	(abs(hash[i].y - y) < GRAB_RANGE) ) {
      if( match < 0 ) {
	match = i;
      } else if( (SQR(hash[match].x - x) + SQR(hash[match].y - y)) >
		 (SQR(hash[i].x - x) + SQR(hash[i].y - y)) ) {
	/* if not only point within range, compare */
	match = i;
      }
    }
  }
  if( match >= 0 ) {
    col->active_hash = match;
    /* hash marks may be a contiguous subset of vertexes, use offset */
    col->active_vertex = match + col->hash_0;
    return( 1 );
  } else
    return( 0 );
}

/*
 * Subroutine:	install_new_color_vertex
 * Purpose:	Given hash position, install a new vertex, and make active
 */

static void add_color_vertex(), add_color_vertex_hash();

static void install_new_color_vertex ( x, y, col )
     int x, y;			/* i: position of ULcorner of new hash mark */
     struct colgRec *col;	/* i: color info structure for one color */
{
  double intensity, cell_level;
  int match;
  int select_best_hash_position();

  col->active_hash = select_best_hash_position(x, y, col->hash, col->hash_cnt,
					       &match, cgraph.vertical);
  col->active_vertex = col->active_hash + col->hash_0;
  if( match >= 0 ) {
    /* new vertex must have same level as an existing one */
    cell_level = col->table->cell_level[match + col->hash_0];
  } else {
    if( cgraph.vertical )
      cell_level = (cgraph.hash.Ymax - (double)(y - HASH_RAY)) /
	cgraph.hash.Yheight;
    else
      cell_level = ((double)(x - HASH_RAY) - cgraph.hash.Xzero) /
	cgraph.hash.Xwidth;
    if( cell_level > 1.0 )
      cell_level = 1.0;
    else if( cell_level < 0.0 )
      cell_level = 0.0;
  }
  if( cgraph.vertical )
    intensity = ((double)(x - HASH_RAY) - cgraph.hash.Xzero) /
      cgraph.hash.Xwidth;
  else
    intensity = (cgraph.hash.Ymax - (double)(y - HASH_RAY)) /
      cgraph.hash.Yheight;
  if( intensity > 1.0 )
    intensity = 1.0;
  else if( intensity < 0.0 )
    intensity = 0.0;
  add_color_vertex(col->table, col->active_vertex, cell_level, intensity);
  add_color_vertex_hash(col, col->active_hash, x, y);
  col->unset = 1;
}

/*
 * Subroutine:	add_color_vertex
 * Purpose:	Install new vertex in a color subtableRec.
 */
static void add_color_vertex ( table, index, new_cell_level, new_intensity )
     struct subtableRec *table;	/* i/o: table structure for one color */
     int index;			/* i: index of new vertex */
     double new_cell_level;	/* i: cell_level and intensity of new vertex */
     double new_intensity;
{
  register int i, j;
  int count = table->vertex_cnt;
  double *cell_level = table->cell_level;
  double *base_level = table->base_level;
  double *intensity = table->intensity;

  /* make room for the new entry */
  for( i = count, j=i-1; i > index; i=j, j-- ) {
    cell_level[i] = cell_level[j];
    base_level[i] = base_level[j];
    intensity[i] = intensity[j];
  }
  /* install the new entry */
  cell_level[i] = new_cell_level;
  base_level[i] = (new_cell_level - table->bias) / table->contrast;
  intensity[i] = new_intensity;
  ++(table->vertex_cnt);
}

/*
 * Subroutine:	add_color_vertex_hash
 * Purpose:	Add a new hash mark
 */
static void add_color_vertex_hash ( col, index, x, y )
     struct colgRec *col;
     int index;
     int x, y;
{
  register int i, j;
  XRectangle *hash;
  int hash_cnt;

  hash_cnt = col->hash_cnt;
  hash = col->hash;
  for( i = hash_cnt, j = i - 1; i > index; i = j, j-- ) {
    hash[i].x = hash[j].x;
    hash[i].y = hash[j].y;
  }
  hash[i].x = x - HASH_RAY;
  hash[i].y = y - HASH_RAY;
  ++(col->hash_cnt);
}

/*
 * Subroutine:	drop_color_vertex
 * Purpose:	Delete a color table vertex if one is under the mouse position
 * Returns:	1 if vertex was dropped, else 0
 */

  static int grab_old_color_vertex();

static int drop_color_vertex ( col, x, y )
     struct colgRec *col;
     int x, y;
{

  /* hash mark positions are upper left corner of hash box */
  x -= HASH_RAY;
  y -= HASH_RAY;
  if( grab_old_color_vertex(x, y, col)  ) {
    register int i, j;
    {
      int count = col->table->vertex_cnt;
      double *cell_level = col->table->cell_level;
      double *base_level = col->table->base_level;
      double *intensity = col->table->intensity;
      for( i = col->active_vertex, j=i+1; j < count; i=j, j++ ) {
	cell_level[i] = cell_level[j];
	base_level[i] = base_level[j];
	intensity[i] = intensity[j];
      }
      --(col->table->vertex_cnt);
    }
    {
      int count = col->hash_cnt;
      XRectangle *hash = col->hash;
      for( i = col->active_hash, j=i+1; j < count; i=j, j++ ) {
	hash[i].x = hash[j].x;
	hash[i].y = hash[j].y;
      }
      --(col->hash_cnt);
    }
    col->unset = 1;
    return( 1 );
  } else
    return( 0 );
}


syntax highlighted by Code2HTML, v. 0.9.1