 /*
  * Khoros: $Id: run_pseudo.c,v 1.1 1991/05/10 15:59:03 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: run_pseudo.c,v 1.1 1991/05/10 15:59:03 khoros Exp $";
#endif

 /*
  * $Log: run_pseudo.c,v $
 * Revision 1.1  1991/05/10  15:59:03  khoros
 * Initial revision
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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 "viewimage.h"
#include "colorspace.h"


/********************************************************
*
*  Routine Name:  run_pseudo
*
*       Purpose:  drives the pane 'pseudo'
*
*         Input:  form - pointer to the form tree 
*		  pseudo_info  - information structure for pane 'pseudo'
*        Output:  action of the application program
*
*     Called By:  run_pseudo_subform()
*
*   Automatically Generated By:  conductor
*
********************************************************/


run_pseudo(form, pseudo_info)

xvf_form *form;
pseudo_subform_pseudo *pseudo_info;
{
	Widget back;


	_xvf_get_pseudo(form, pseudo_info);

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

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

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

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

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

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

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

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

}



/************************************************************
*
*  MODULE NAME: update_palette
*
*      PURPOSE: Allows the user to select a range of pixel values
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*               dispatch   -  flag to see if the event should be propagated
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/

static int modified;

void  update_palette(widget, clientData, event, dispatch)

Widget	widget;
caddr_t	clientData;
XEvent  *event;
Boolean *dispatch;
{
	int index = (int) clientData;
	XImage *ximage = xvdisplay->ximage;

	Arg	  args[2];
	int	  x, y, i;
	Dimension xoffset, yoffset;



	/*
	 *  If index is -1 that means this callback was activated when
	 *  the user button pressed on the raster image.
	 */
	if (index == -1)
	{
	   /*
	    *  Since the user selected a pixel from the image we should
	    *  make sure that the pseudo subform is visible.  If not then
	    *  the event was probably not meant for us.
	    */
	   if (xvd_check_visibility(pseudo->pseudo) == False)
	      return;
	   else
	      *dispatch = False;

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

	   x = event->xbutton.x + xoffset;
	   y = event->xbutton.y + yoffset;
	   index = xvd_query_value(xvdisplay, x, y, NULL, &index, NULL);
	}

	if (index1 == -1 || index2 != -1 || modified == True)
	{
	   index1 = index;
	   index2 = -1;
	   modified = False;
	}
	else
	{
	   index2 = index;
	   push_cstack(xvdisplay->xcolors, index1, index2);
	}
	refresh_pseudo();
}



/************************************************************
*
*  MODULE NAME: refresh_pseudo
*
*      PURPOSE: Once a range has been selected, sets the scroll
*		bars to the current value
*
*        INPUT: Uses the global pseudo structure
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/

refresh_pseudo()
{
	int	 i;
	Pixel	 pixel;
	Arg	 args[10];

	XColor	 color;
	ScrollStruct *scroll;
	double	 val[3], value;


	if (index1 != -1)
	{
	   XtMapWidget(pseudo->color1);
	   pixel = xvdisplay->xcolors[index1].pixel;

	   i = 0;
	   XtSetArg(args[i], XtNforeground, pixel);	i++;
	   XtSetArg(args[i], XtNbackground, pixel);	i++;
	   XtSetValues(pseudo->color1, args, i);
	}
	else
	   XtUnmapWidget(pseudo->color1);


	if (index2 != -1)
	{
	   XtMapWidget(pseudo->color2);
	   pixel = xvdisplay->xcolors[index2].pixel;

	   i = 0;
	   XtSetArg(args[i], XtNforeground, pixel);	i++;
	   XtSetArg(args[i], XtNbackground, pixel);	i++;
	   XtSetValues(pseudo->color2, args, i);
	}
	else
	   XtUnmapWidget(pseudo->color2);


	if (index1 == -1)
	   return;
	else
	   color = xvdisplay->xcolors[index1];

	switch(pseudo->model)
	{
	   case RGB:
		val[0] = color.red;
		val[1] = color.green;
		val[2] = color.blue;
		scroll = pseudo->rgb;
		break;

	   case CMY:
		RGB_to_CMY(color, color);
		val[0] = color.red;
		val[1] = color.green;
		val[2] = color.blue;
		scroll = pseudo->cmy;
		break;

	   case HSV:
		RGB_to_HSV(color, val[0], val[1], val[2]);
		scroll = pseudo->hsv;
		break;

	   case HLS:
		RGB_to_HLS(color, val[0], val[1], val[2]);
		scroll = pseudo->hls;
		break;

	   case YIQ:
		RGB_to_YIQ(color, val[0], val[1], val[2]);
		scroll = pseudo->yiq;
		break;

	   case UVW:
		RGB_to_UVW(color, val[0], val[1], val[2]);
		scroll = pseudo->uvw;
		break;

	   case XYZ:
		RGB_to_XYZ(color, val[0], val[1], val[2]);
		scroll = pseudo->xyz;
		break;

	   case GREY:
		val[0] = (color.red + color.green + color.blue)/3;
		scroll = pseudo->grey;
		break;
	}

	if (pseudo->model == RGB || pseudo->model == CMY)
	{
	   for (i = 0; i < 3; i++)
	   {
	       sprintf(scroll[i].string, "%d", ((int) val[i]/MAX_PIXELS));
	       XtSetArg(args[0], XtNstring, scroll[i].string);
	       XtSetValues(scroll[i].value, args, 1);

	       value = (1.0 - (val[i]/MAX_INTEN));
	       XawScrollbarSetThumb(scroll[i].scrollbar, value, 1.0);
	   }
	}
	else if (pseudo->model == GREY)
	{
	   sprintf(scroll[0].string, "%d", ((int) val[0]/MAX_PIXELS));
	   XtSetArg(args[0], XtNstring, scroll[0].string);
	   XtSetValues(scroll[0].value, args, 1);

	   value = (1.0 - (val[0]/MAX_INTEN));
	   XawScrollbarSetThumb(scroll[0].scrollbar, value, 1.0);
	}
	else
	{
	   for (i = 0; i < 3; i++)
	   {
	       sprintf(scroll[i].string, "%0.3f", val[i]);
	       XtSetArg(args[0], XtNstring, scroll[i].string);
	       XtSetValues(scroll[i].value, args, 1);

	       value = (1.0 - val[i]);
	       XawScrollbarSetThumb(scroll[i].scrollbar, value, 1.0);
	   }
	}
}



/************************************************************
*
*  MODULE NAME: update_pseudo_cont
*
*      PURPOSE: Updates the colors of the pixel boxes in the
*		palette of the selected range as the user moves
*		the slider on the red, green or blue scroll bars
*		(called when the slider is used continuously)
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


void  update_pseudo_cont(widget, clientData, callData)

Widget	widget;
caddr_t	clientData, callData;
{
        ScrollStruct *scroll = (ScrollStruct *) clientData;
	float	*number = (float *) callData;
	double  value;


	if (!check_pseudo_index())
	   return;

	if (pseudo->model == RGB || pseudo->model == CMY ||
	    pseudo->model == GREY)
	{
	   value = ((int) ((1.0 - *number) * MAX_INTEN));
	   sprintf(scroll->string, "%d", ((int) value/MAX_PIXELS));
	}
	else
	{
	   value = 1.0 - *number;
	   sprintf(scroll->string, "%0.3f", value);
	}
	update_pseudo(scroll, value, True);
}



/************************************************************
*
*  MODULE NAME: update_pseudo_incr
*
*      PURPOSE: Updates the colors of the pixel boxes in the
*		palette of the selected range as the user moves
*		the slider on the red, green or blue scroll bars
*		(called when the slider is used incrementally)
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/

void  update_pseudo_incr(widget, clientData, callData)

Widget	widget;
caddr_t	clientData, callData;
{
	int	direction = (int) callData;
        ScrollStruct *scroll = (ScrollStruct *) clientData;
	double  value;


	if (!check_pseudo_index())
	   return;

	if (pseudo->model == RGB || pseudo->model == CMY ||
	    pseudo->model == GREY)
	{
	   if (direction > 0)
	      value = 1000.0;
	   else
	      value = -1000.0;
	}
	else
	{
	   if (direction > 0)
	      value = 0.1;
	   else
	      value = -0.1;
	}
	update_pseudo(scroll, value, False);
}



/************************************************************
*
*  MODULE NAME: update_pseudo
*
*      PURPOSE: Really updates the colors of the pixel boxes in the
*		palette of the selected range.
*
*        INPUT: scroll	   - the scroll structure to update.
*               value      - the value to update
*               set        - set or increment the value
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


update_pseudo(scroll, value, set)

ScrollStruct *scroll;
double	     value;
int	     set;
{
	int	i, num, index;

	XColor  color, *xcolors = xvdisplay->xcolors;
	double  val1, val2, val3;


	if (!check_pseudo_index())
	   return;

	/*
	 *  We allow the user to pseudo color a single pixel or a range
	 *  of pixels.  If index2 is -1 then this means that the user is
	 *  pseudo coloring a single pixel otherwise they are pseudo
	 *  coloring a range of pixels.
	 */
	if (index2 != -1)
	{
	   index = MIN(index1, index2);
	   num   = abs(index1 - index2) +1;
	}
	else
	{
	   index = index1;
	   num   = 1;
	}

	for (i = index; i < index+num; i++)
	{
	   switch(pseudo->model)
	   {
	       case RGB:
		    if (set) assign_color(scroll->num, value, &xcolors[i]);
		    else update_color(scroll->num, value, &xcolors[i]);
		    break;

	       case CMY:
		    RGB_to_CMY(xcolors[i], color);
		    if (set) assign_color(scroll->num, value, &color);
		    else update_color(scroll->num, value, &color);
		    CMY_to_RGB(color, xcolors[i]);
		    break;

	       case HSV:
		    RGB_to_HSV(xcolors[i], val1, val2, val3);
		    if (set) assign_value(scroll->num, value,&val1,&val2,&val3);
		    else update_value(scroll->num, value, &val1, &val2, &val3);
		    HSV_to_RGB(val1, val2, val3, xcolors[i]);
		    break;

	       case HLS:
		    RGB_to_HLS(xcolors[i], val1, val2, val3);
		    if (set) assign_value(scroll->num, value,&val1,&val2,&val3);
		    else update_value(scroll->num, value, &val1, &val2, &val3);
		    HLS_to_RGB(val1, val2, val3, xcolors[i]);
		    break;

	       case YIQ:
		    RGB_to_YIQ(xcolors[i], val1, val2, val3);
		    if (set) assign_value(scroll->num, value,&val1,&val2,&val3);
		    else update_value(scroll->num, value, &val1, &val2, &val3);
		    YIQ_to_RGB(val1, val2, val3, xcolors[i]);
		    break;

	       case UVW:
		    RGB_to_UVW(xcolors[i], val1, val2, val3);
		    if (set) assign_value(scroll->num, value,&val1,&val2,&val3);
		    else update_value(scroll->num, value, &val1, &val2, &val3);
		    UVW_to_RGB(val1, val2, val3, xcolors[i]);
		    break;

	       case XYZ:
		    RGB_to_XYZ(xcolors[i], val1, val2, val3);
		    if (set) assign_value(scroll->num, value,&val1,&val2,&val3);
		    else update_value(scroll->num, value, &val1, &val2, &val3);
		    XYZ_to_RGB(val1, val2, val3, xcolors[i]);
		    break;

	       case GREY:
		    if (set)
		    {
		       xcolors[i].red   = (short) value;
		       xcolors[i].green = (short) value;
		       xcolors[i].blue  = (short) value;
		    }
		    else
		    {
		       xcolors[i].red   += (short) value;
		       xcolors[i].green += (short) value;
		       xcolors[i].blue  += (short) value;
		    }
		    break;
	   }

	   if (xvdisplay->active[i] > 0)
	      xcolors[i].flags = DoRed | DoGreen | DoBlue;
	   else
	      xcolors[i].flags = 0;
	}
	store_colors(xcolors, index, num);
	modified = True;
}



int check_pseudo_index()
{
	static int in_use = False;


	/*
	 *  Check to see if we have been called before.  If so then
	 *  return False.
	 */
	if (in_use) return(False);

	/*
	 *  Make sure at least one pixel range has been selected.
	 */
	if (index1 == -1 && index2 == -1)
	{
	   in_use = True;
	   xvf_error_wait("Please select a pixel or a range of pixels before \
using pseudo color bars!", "Pseudo", NULL);
	   in_use = False;
	   return(False);
	}
	return(True);
}

assign_value(num, value, val1, val2, val3)

int   num;
double value, *val1, *val2, *val3;
{
	if (value < 0.0) value = 0.0;
	else if (value > 1.0) value = 1.0;

	if (num == 0)
	   *val1 = value;
	else if (num == 1)
	   *val2 = value;
	else if (num == 2)
	   *val3 = value;
}

assign_color(num, value, color)

int    num;
double  value;
XColor *color;
{
	if (value < 0.0) value = 0.0;
	else if (value > MAX_INTEN) value = MAX_INTEN;

	if (num == 0)
	   color->red = (short) value;
	else if (num == 1)
	   color->green = (short) value;
	else if (num == 2)
	   color->blue = (short) value;
}
update_value(num, value, val1, val2, val3)

int   num;
double value, *val1, *val2, *val3;
{
	if (num == 0)
	   *val1 += value;
	else if (num == 1)
	   *val2 += value;
	else if (num == 2)
	   *val3 += value;
}

update_color(num, value, color)

int    num;
double  value;
XColor *color;
{
	if (num == 0)
	   color->red += (short) value;
	else if (num == 1)
	   color->green += (short) value;
	else if (num == 2)
	   color->blue += (short) value;
}
