/*
 *	(c) Copyright 1991 Sun Microsystems, Inc.  All rights reserved.
 *	See LEGAL_NOTICE file for terms and restrictions.
 */


#ifndef lint
static  char sccsid[] = "@(#)SSM2 drawarea.c 1.11 91/05/06 ";
#endif

/***********************************************************************
 *
 *	implements an area suitable for drawing in virtual coords
 *
 ***********************************************************************/


#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <xview/rect.h>
#include <xview/xv_xrect.h>
#include <xview/win_input.h>
#include <sspkg/drawobj.h>
#include "r_impl.h"
#include "do_impl.h"
#include "drawarea.h"
#include <sspkg/canshell.h>

/*ARGSUSED*/

Pkg_private int
  drawarea_init(parent, drawarea_public, avlist)
Xv_opaque	parent;
Drawarea	drawarea_public;
Attr_avlist	avlist;
{
  Drawarea_info	*dinfo;
  Drawarea_struct	*drawarea_object;
  extern int start_dbl_click();
  void drawarea_paint_proc();

  dinfo = xv_alloc(Drawarea_info);
  dinfo->public_self = drawarea_public;
  dinfo->gc = NULL;
  dinfo->dl_cmds.allocated = 0;
  dinfo->dl_cmds.displayed = 0;
  dinfo->dl_cmds.used = 0;
  dinfo->dl_cmds.cmds = NULL;

  dinfo->dl_transform.upper_y = 0.0;
  dinfo->dl_transform.lower_y = 10000.0;
  dinfo->dl_transform.left_x  = 0.0;
  dinfo->dl_transform.right_x = 10000.0;
  
  drawarea_object = (Drawarea_struct*) drawarea_public;
  drawarea_object->private_data = (Xv_opaque) dinfo;

  xv_set(drawarea_public, 
	 RECTOBJ_PAINT_PROC, drawarea_paint_proc, 
	 RECTOBJ_EVENT_PROC, start_dbl_click,
	 XV_NULL);
  
  return(XV_OK);
}


Pkg_private Xv_opaque
  drawarea_set_avlist(drawarea_public, avlist)
Drawarea		drawarea_public;
register Attr_avlist	avlist;
{
  register Drawarea_attr attr;
  register Drawarea_info *dinfo = DRAWAREA_PRIVATE(drawarea_public);
  register Rectobj_info *rinfo = RECTOBJ_PRIVATE(drawarea_public);

  Rectobj_info *parent_rinfo;

  int value;
  double dvalue;

  if(rinfo->parent)
    parent_rinfo = RECTOBJ_PRIVATE(rinfo->parent);
  else
    parent_rinfo = NULL;

  if(*avlist != XV_END_CREATE) 
    {
      Xv_opaque set_result;
      set_result = 
	xv_super_set_avlist(drawarea_public, &drawarea_pkg, avlist);
      if(set_result != XV_OK) 
	{
	  rectobj_reset_set_info(drawarea_public);
	  return(set_result);
	}
    }

  while (attr = (Drawarea_attr) * avlist++)
    switch (attr) 
      {
      case DRAWAREA_X:
	value = (int) *avlist++;
	if(!rinfo->parent)
	  break;
	xv_set(drawarea_public, 
	       XV_X, xv2X(& parent_rinfo->rect, value),
	       NULL);
	break;

      case DRAWAREA_Y:
	value = (int) *avlist++;
	if(!parent_rinfo)
	  break;
	xv_set(drawarea_public, 
	       XV_Y, yv2X(& parent_rinfo->rect, value),
	       NULL);
	break;

      case DRAWAREA_WIDTH:
	value = (int) *avlist++;
	if(!parent_rinfo)
	  break;

	xv_set(drawarea_public, 
	       XV_WIDTH, wv2X(& parent_rinfo->rect, value),
	       NULL);
	break;

      case DRAWAREA_HEIGHT:
	value = (int) *avlist++;
	if(!parent_rinfo)
	  break;

	xv_set(drawarea_public, 
	       XV_HEIGHT, hv2X(& parent_rinfo->rect, value),
	       NULL);
	break;

      case DRAWAREA_LEFT_X:
	dvalue = * ((double *) *avlist++);

	if(dvalue != dinfo->dl_transform.left_x)
	  {
	    dinfo->dl_transform.left_x = dvalue;
	    rectobj_repaint_rect(drawarea_public,
				 NULL, TRUE);
	  }
	break;

      case DRAWAREA_RIGHT_X:
	dvalue = * ((double *) *avlist++);

	if(dvalue != dinfo->dl_transform.right_x)
	  {
	    dinfo->dl_transform.right_x = dvalue;
	    rectobj_repaint_rect(drawarea_public,
				 NULL, TRUE);
	  }
	break;

      case DRAWAREA_UPPER_Y:
	dvalue = * ((double *) *avlist++);

	if(dvalue != dinfo->dl_transform.upper_y)
	  {
	    dinfo->dl_transform.upper_y = dvalue;
	    rectobj_repaint_rect(drawarea_public,
				 NULL, TRUE);
	  }
	break;

      case DRAWAREA_LOWER_Y:
	dvalue = * ((double *) *avlist++);

	if(dvalue != dinfo->dl_transform.lower_y)
	  {
	    dinfo->dl_transform.lower_y = dvalue;
	    rectobj_repaint_rect(drawarea_public,
				 NULL, TRUE);
	  }

	break;
	
      case RECTOBJ_BACKGROUND_COLOR:
	if(rinfo->shared_info && dinfo->gc)
	  {
	    XSetBackground(rinfo->shared_info->dpy, 
			   dinfo->gc, 
			   rinfo->shared_info->pixels[*avlist]);
	    rectobj_repaint_rect(drawarea_public,
				 NULL, TRUE);
	  }

	avlist++;
	break;

	
      default:
	avlist = attr_skip(attr, avlist);
      }

    rectobj_finish_set(drawarea_public);

    return(XV_SET_DONE);

}


/*ARGSUSED*/
Pkg_private Xv_opaque
  drawarea_get_attr(drawarea_public, status, which_attr, avlist)
Drawarea		drawarea_public;
	int		*status;
	register Attr_attribute which_attr;
	Attr_avlist	avlist;
{
  static double return_value;

  Drawarea_info  *dinfo = DRAWAREA_PRIVATE(drawarea_public);
  register Rectobj_info *rinfo = RECTOBJ_PRIVATE(drawarea_public);

  Rectobj_info *parent_rinfo;

  if(rinfo->parent)
    parent_rinfo = RECTOBJ_PRIVATE(rinfo->parent);
  else
    parent_rinfo = NULL;

  switch (which_attr) 
    {
    case DRAWAREA_X:
      if(!parent_rinfo)
	return((Xv_opaque) NULL);
      return((Xv_opaque) xX2v(& parent_rinfo->rect, 
			      xv_get(drawarea_public,
				     XV_X)));
      break;

    case DRAWAREA_Y:
      if(!parent_rinfo)
	return((Xv_opaque) NULL);

      return((Xv_opaque) yX2v(& parent_rinfo->rect, 
			      xv_get(drawarea_public,
				     XV_Y)));
      break;

    case DRAWAREA_WIDTH:
      if(!parent_rinfo)
	return((Xv_opaque) NULL);

      return((Xv_opaque) wX2v(& parent_rinfo->rect, 
			      rinfo->rect.r_width));
      break;

    case DRAWAREA_HEIGHT:
      if(!parent_rinfo)
	return((Xv_opaque) NULL);

      return((Xv_opaque) hX2v(& parent_rinfo->rect, 
			      rinfo->rect.r_height));
      
    case DRAWAREA_LEFT_X:
      return_value = dinfo->dl_transform.left_x;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_RIGHT_X:
      return_value = dinfo->dl_transform.right_x;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_UPPER_Y:
      return_value = dinfo->dl_transform.upper_y;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_LOWER_Y:
      return_value = dinfo->dl_transform.lower_y;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_MIN_X:
      if(dinfo->dl_limits.checked == 0)
	return((Xv_opaque) 0);
      return_value = dinfo->dl_limits.min_x;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_MAX_X:
      if(dinfo->dl_limits.checked == 0)
	return((Xv_opaque) 0);
      return_value = dinfo->dl_limits.max_x;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_MIN_Y:
      if(dinfo->dl_limits.checked == 0)
	return((Xv_opaque) 0);
      return_value = dinfo->dl_limits.min_y;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_MAX_Y:
      if(dinfo->dl_limits.checked == 0)
	return((Xv_opaque) 0);
      return_value = dinfo->dl_limits.max_y;
      return ((Xv_opaque) & return_value);
      break;

    case DRAWAREA_FONT_DIMS:
      {
	Xv_Font font  = (Xv_Font)*avlist;
	char * string = (char *) *avlist;
	int * dims    = (int *)  *avlist;

	if(font == XV_NULL)
	  font = xv_find(XV_NULL, FONT, NULL);
	
	if(get_string_dims(font, string, dims))
	  return((Xv_opaque) 0);
	
	dims[0] = wX2v(& rinfo->rect, dims[0]);
	dims[1] = hX2v(& rinfo->rect, dims[1]);
	dims[2] = hX2v(& rinfo->rect, dims[2]);

	return((Xv_opaque) dims);
	break;
      }
    default:
      *status = XV_ERROR;
      return (Xv_opaque) 0;
    }
}

/*ARGSUSED*/
Pkg_private int
  drawarea_destroy(drawarea_public, status)
Drawarea		drawarea_public;
Destroy_status	status;
{
  Drawarea_info	*dinfo = DRAWAREA_PRIVATE(drawarea_public);
  
  if ((status == DESTROY_CHECKING) || (status == DESTROY_SAVE_YOURSELF))
    return XV_OK;
  
  clear_dl_cmds(& dinfo->dl_cmds);
  free(dinfo);
  return XV_OK;
}


/*ARGSUSED*/
Pkg_private void
  drawarea_paint_proc(drawarea_public, dpy, win, xrects)
Drawarea drawarea_public;
Display *dpy;
Window  win;
Xv_xrectlist *xrects;
{
  Drawarea_info *dinfo = DRAWAREA_PRIVATE(drawarea_public);
  Rectobj_info *rinfo = RECTOBJ_PRIVATE(drawarea_public);
  
  Rect *rect;
  int selected;
  Shared_info *shared_info;
  
  shared_info = rinfo->shared_info;
  
  if(!shared_info)
    return;	/* major snafu */

  traverse_display_list(drawarea_public, 
			dpy, 
			win, 
			xrects, 
			0); /* flag indicates full repaint */

  rectobj_paint_children(drawarea_public, dpy, win, xrects);
}


static int get_string_dims(font, string, dims)
     Xv_Font	font;
     char *	string;
     int dims[3];
{
  XFontStruct *	fontInfo = (XFontStruct *) xv_get(font, FONT_INFO);

  int		direction, ascent, descent;
  XCharStruct	overallReturn;

  if(!fontInfo)
    {
      dims[2] = dims[1] = dims[0] = 0;
      return(-1);
    }

  XTextExtents(fontInfo, string, strlen(string), 
	       &direction, &ascent, &descent,
	       &overallReturn);

  dims[0] = overallReturn.width;
  dims[1] = ascent+descent; 
  dims[2] = descent;

  return(0);
}


