 /*
  * Khoros: $Id: run_pixels.c,v 1.2 1992/03/20 22:39:35 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: run_pixels.c,v 1.2 1992/03/20 22:39:35 dkhoros Exp $";
#endif

 /*
  * $Log: run_pixels.c,v $
 * Revision 1.2  1992/03/20  22:39:35  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "editimage.h"
#include "colorspace.h"

static  int    pixel_xpos = 2, pixel_ypos = 2;


/********************************************************
*
*  Routine Name:  run_pixels
*
*       Purpose:  drives the pane 'pixels'
*
*         Input:  form - pointer to the form tree 
*		  pixels_info  - information structure for pane 'pixels'
*        Output:  action of the application program
*
*     Called By:  run_pixels_subform()
*
*   Automatically Generated By:  conductor
*
********************************************************/


run_pixels(form, pixels_info)

xvf_form *form;
pixels_subform_pixels *pixels_info;
{
	Widget	back;


	_xvf_get_pixels(form, pixels_info);

	/*
	 * user clicked on pane toggle 'color_model'
	 */
	if (pixels_info->color_model_selected)
	{
	   pixels->model = pixels_info->color_model_val;
	   switch(pixels_info->color_model_val)
	   {
	      case RGB:
		   back = pixels->rgb_back;
	           break;

	      case CMY:
		   back = pixels->cmy_back;
	           break;

	      case HSV:
		   back = pixels->hsv_back;
	           break;

	      case HLS:
		   back = pixels->hls_back;
	           break;

	      case YIQ:
		   back = pixels->yiq_back;
	           break;

	      case XYZ:
		   back = pixels->xyz_back;
	           break;

	      case UVW:
		   back = pixels->uvw_back;
	           break;

	      case GREY:
		   back = pixels->grey_back;
	           break;
	   }
	   XtMapWidget(back);
	   XRaiseWindow(display, XtWindow(back));
	   refresh_pixels();
	}

	/*
	 * user clicked on live logical "update mode"
	 */
	else if (pixels_info->update_mode_selected)
	{
	    pixels->mode = pixels_info->update_mode;
	    update_pixel_mode();
	}
}



/************************************************************
*
*  MODULE NAME: update_pixel_mode
*
*      PURPOSE: changes the update pixel method to either
*		ButtonPress_Mode or Continuous_Mode.  If the mode
*		is button press then we update the pixel window
*		every time the user button presses in the image
*		window.  If the mode is continous then we update
*		the pixel window as the mouse moves thru the image
*		window.
*
*		A event handler is installed for the desired type
*		and the previous handler is deleted.
*
*	 INPUT: none
*
*       OUTPUT: none
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

update_pixel_mode()

{
        unsigned long mask;


	if (pixels->mode == ButtonPress_Mode)
	{
	   mask = PointerMotionHintMask | PointerMotionMask;
	   XtRemoveEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
				NULL);

	   mask = ButtonPressMask;
	   XtAddEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
			     NULL);
	}
	else if (pixels->mode == Continuous_Mode)
	{
	   mask = ButtonPressMask;
	   XtRemoveEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
				NULL);

	   mask = PointerMotionHintMask | PointerMotionMask;
	   XtAddEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
			     NULL);
	}
}



/************************************************************
*
*  MODULE NAME: redisplay_pixels
*
*      PURPOSE: redisplay_pixels is the event handler that
*		is used to refresh the pixels to the pixel
*		window.  calls refresh_pixels() to do the actual
*		drawing.
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*
*       OUTPUT: none - refresh_pixels() does the actual refreshing
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/


void redisplay_pixels(widget, clientData, event)

Widget	widget;
caddr_t clientData;
XEvent  *event;
{
	PixelStructure *pixels = (PixelStructure *) clientData;

	int         x, y, status;
	Window      root;
	unsigned    long mask;
	unsigned    int width, height, border_width, depth;
	XEvent	    next;


	/*
	 *  Make sure that there is a current image to print pixels with.
	 */
	if (xvdisplay->image == NULL || xvdisplay->ximage == NULL)
	   return;

	if (event->type == Expose && pixels->pixels == widget)
	{
	   /*
	    *  refresh the pixel display, but first eat all the exposure
	    *  events.
	    */
	   do
	   {
	      status = XCheckWindowEvent(display, XtWindow(widget),
					 ExposureMask, &next);
	   } while (status);
	   refresh_pixels();
	}
	else if (event->type == ConfigureNotify)
	{
	   if (!XGetGeometry(XtDisplay(pixels->pixels),XtWindow(pixels->pixels),
			     &root, &x, &y, &width, &height,  &border_width,
			     &depth))
	   {
	      xvf_error_wait("Window does not exist.","redisplay_pixels", NULL);
	      return;
	   }
	}
	else
	{
	   mask = ButtonPressMask;
	   XtRemoveEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
				NULL);
	   mask = PointerMotionHintMask | PointerMotionMask;
	   XtRemoveEventHandler(xvdisplay->raster, mask, FALSE, update_pixels,
				   NULL);
	   if (xvd_check_visibility(widget) == False)
	      return;
	   else
	      update_pixel_mode();

	   refresh_pixels();
	}
}



/************************************************************
*
*  MODULE NAME: update_pixels
*
*      PURPOSE: Updates the pixels on the screen.  This routine
*		does not do the actual refreshing of the pixels,
*		but rather queries the position of the mouse in
*		the screen, clips the position to make sure the
*		all the pixels fit, and then calls refresh_pixels().
*
*	 INPUT: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       OUTPUT: calls refresh_pixels() to print the pixels.
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/


void update_pixels(widget, clientData, event)

Widget	widget;
caddr_t clientData;
XEvent  *event;
{
	Arg	  args[2];
	int	  x, y, i;
	Dimension xoffset, yoffset;

	XImage	  *ximage = xvdisplay->ximage;


	/*
	 *  Make sure that there is a current image to print pixels with.
	 */
	if (xvdisplay->image == NULL || xvdisplay->ximage == NULL)
	   return;

	if (event->type == MotionNotify)
	{
	   if (xvd_query_position(widget, &x, &y, True))
	      return;
	}
	else if (event->type == ButtonPress)
	{
	   x = event->xbutton.x;
	   y = event->xbutton.y;
	}
	else
	{
	   return;
	}

	i = 0;
        XtSetArg(args[i], XtNxoffset, &xoffset);             i++;
        XtSetArg(args[i], XtNyoffset, &yoffset);             i++;
        XtGetValues(xvdisplay->raster, args, i);

	x += xoffset;
	y += yoffset;

	if (x < 2)
	   x = 2;
	if ((x + 2) >= ximage->width)
	   x = ximage->width - 3;

	if (y < 2)
	   y = 2;
	if ((y + 2) >= ximage->height)
	   y = ximage->height - 3;

	/*
	 *  Assign global pixel position for x & y.  This is used when
	 *  refreshing the pixel widget.
	 */
	pixel_xpos = x;
	pixel_ypos = y;

	refresh_pixels();
}



/************************************************************
*
*  MODULE NAME: refresh_pixels
*
*      PURPOSE: refreshes the pixels to the pixel window
*		by printing the pixel values using XDrawImageString()
*
*	 INPUT: none - uses the global "pixel_xpos" & "pixel_ypos"
*		       as the x and y position offset.
*
*       OUTPUT: prints the pixel values to the window
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

refresh_pixels()
{
	XColor	  *xcolors = xvdisplay->xcolors;

	XColor	  color;
	char	  buf[10];
	Widget	  *widgets;
	double	  value, val1, val2, val3, light;
	int	  x, y, xpos, ypos, i, j, index, rgbindex[3];


	/*
	 *  Make sure that there is a current image to print pixels with.
	 */
	if (xvdisplay->image == NULL || xvdisplay->ximage == NULL)
	   return;

	y = pixel_ypos - 2;
	ypos = 0;
	for (i = 0; i < 5; i++)
	{
	   x = pixel_xpos - 2;
	   ypos += pixels->height;
	   xpos  = 0;
	   for (j = 0; j < 5; j++)
	   {
	       if (xvd_truecolor_image(xvdisplay->image) == False)
	       {
	          xvd_query_value(xvdisplay, x, y, NULL, &index, NULL);
	          XSetBackground(display, pixels->gc, xcolors[index].pixel);
		  color = xcolors[index];
	       }
	       else
	       {
	          xvd_query_rgbvalue(xvdisplay, x, y, NULL, rgbindex, NULL);
		  color.red     = xcolors[rgbindex[0]].red;
		  color.green   = xcolors[rgbindex[1]].green;
		  color.blue    = xcolors[rgbindex[2]].blue;
	          color.pixel = XGetPixel(xvdisplay->ximage, (int) x, (int) y);
	          XSetBackground(display, pixels->gc, color.pixel);
	       }

	       RGB_to_HLS(color, val1, light, val3);
	       if (light >= 0.5)
		  XSetForeground(display, pixels->gc, black);
	       else
		  XSetForeground(display, pixels->gc, white);


	       switch (pixels->model)
	       {
		  case RGB:
		       widgets = pixels->rgb;
		       break;

		  case CMY:
		       widgets = pixels->cmy;
		       RGB_to_CMY(color, color);
		       break;

		  case HSV:
		       widgets = pixels->hsv;
		       RGB_to_HSV(color, val1, val2, val3);
		       break;

		  case HLS:
		       widgets = pixels->hls;
		       RGB_to_HLS(color, val1, val2, val3);
		       break;

		  case YIQ:
		       widgets = pixels->yiq;
		       RGB_to_YIQ(color, val1, val2, val3);
		       break;

		  case UVW:
		       widgets = pixels->uvw;
		       RGB_to_UVW(color, val1, val2, val3);
		       break;

		  case XYZ:
		       widgets = pixels->xyz;
		       RGB_to_XYZ(color, val1, val2, val3);
		       break;

		  case GREY:
		       value = ((color.red + color.green + color.blue)/3) >> 8;
		       widgets = pixels->grey;
		       break;
	       }

	       if (pixels->model == RGB || pixels->model == CMY)
	       {
	          sprintf(buf, " %3d ", color.red/256);
	          XDrawImageString(display, XtWindow(widgets[0]),
			      pixels->gc, xpos, ypos, buf, 5);

	          sprintf(buf, " %3d ", color.green/256);
	          XDrawImageString(display, XtWindow(widgets[1]),
			      pixels->gc, xpos, ypos, buf, 5);

	          sprintf(buf, " %3d ", color.blue/256);
	          XDrawImageString(display, XtWindow(widgets[2]),
			      pixels->gc, xpos, ypos, buf, 5);
	       }
	       else if (pixels->model == GREY)
	       {
	          sprintf(buf, " %3g ", value);
	          XDrawImageString(display, XtWindow(widgets[0]),
			      pixels->gc, xpos, ypos, buf, 5);
	       }
	       else
	       {
	          sprintf(buf, "%0.3f", val1);
	          XDrawImageString(display, XtWindow(widgets[0]),
			      pixels->gc, xpos, ypos, buf, 5);

	          sprintf(buf, "%0.3f", val2);
	          XDrawImageString(display, XtWindow(widgets[1]),
			      pixels->gc, xpos, ypos, buf, 5);

	          sprintf(buf, "%0.3f", val3);
	          XDrawImageString(display, XtWindow(widgets[2]),
			      pixels->gc, xpos, ypos, buf, 5);
	       }
	       x++;
	       xpos += pixels->width;
	   }
	   y++;
	}
}
