 /*
  * Khoros: $Id: run_thres.c,v 1.1 1991/05/10 15:58:30 khoros Exp $
  */

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

 /*
  * $Log: run_thres.c,v $
 * Revision 1.1  1991/05/10  15:58:30  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.
 *----------------------------------------------------------------------
 */

/*
 * The threshold display is used by the user to mask out certain parts of
 * the image so that they are only looking at desired range of pixels.
 * The thres struture contains an upper and lower scrollbar from which we
 * can extract the pixel range to be threshold.
 *
 * The thres structure also contains the "pixel" that we are going to be
 * setting the threshold values to, and whether we are to accept or
 * reject that range.  The "accept" value is a boolean which tells us if we
 * are to threshold everything outside the lower & upper range or whether
 * we threshold everything inside that range.  (If accept is true then we
 * threshold everything outside the range otherwise we threshold the
 * pixels inside the range).
 *
 * The threshold works by setting the pixels in the threshold range to
 * the current threshold color (specified by pixel).  And then storing
 * these values in the xvdisplay colormap.  But in order to make sure none
 * of the other displays over-ride this threshold we set the pixel's active
 * boolean array to zero.  By setting the histogram to zero, none of the other
 * displays will update those pixels with new values, until we restore the
 * active states.
 * 
 */

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


/********************************************************
*
*  Routine Name:  run_thres
*
*       Purpose:  drives the pane 'thres'
*
*         Input:  form - pointer to the form tree 
*		  thres_info  - information structure for pane 'thres'
*        Output:  action of the application program
*
*     Called By:  run_thres_subform()
*
*   Automatically Generated By:  conductor -i viewimage.form -l 3 -b
*
********************************************************/


run_thres(form, thres_info)

xvf_form *form;
thres_subform_thres *thres_info;
{
	_xvf_get_thres(form, thres_info);

	if (thres_info->thresholding_val == Windowing)
	{
	    thres->mode = Windowing;

	    /*
	     * user clicked on 'live' logical selection 'accept'
	     */
	    if (thres_info->accept_selected)
	    {
	       thres->accept = thres_info->accept;
	    }

	    /*
	     * user clicked on 'live' integer selection 'fill_pixel'
	     */
	     if (thres_info->fill_pixel_selected)
	     {
	   	thres->fill_pixel = thres_info->fill_pixel;
	     }
	     update_thres();
	}
	else if (thres_info->thresholding_val == Thresholding)
	{
	    thres->mode = Thresholding;

	    /*
	     * user clicked on 'live' logical selection 'invert'
	     */
	    if (thres_info->invert_selected)
	    {
	       thres->invert = thres_info->invert;
	    }

	    /*
	     * user clicked on 'live' integer selection 'non_zero_pixel'
	     */
	     if (thres_info->non_zero_pixel_selected)
	     {
	   	thres->nonzero_pixel = thres_info->non_zero_pixel;
	     }
	     update_thres();
	}
}



/************************************************************
*
*  MODULE NAME: update_thres
*
*      PURPOSE: Updates the threshold display to it's current
*		upper and lower value.  Copy the current xvdisplay
*		active array into the active array used by the display
*		routines.  Then threshold out the range of pixels
*		by setting the active element to false.  We then take
*		call store_colors() to store the new masked colors and
*		update the visible displays.
*
*        INPUT: none
*
*       OUTPUT: none
*
*   WRITTEN BY: Mark Young & Danielle Argiro
*
*
*************************************************************/


update_thres()
{
	int	i, num, size, lower, upper;
	XColor  color, xcolors[MAX_PIXELS];

	int     pixelmin = xvdisplay->pixelmin;
	int     pixelmax = xvdisplay->pixelmax;


	lower = thres->lower->num;
	upper = thres->upper->num;

	size = MAX_PIXELS*sizeof(Boolean);
	bcopy(xvdisplay->active, active, size);

	if ((thres->mode == Windowing && thres->accept) ||
	    (thres->mode == Thresholding && thres->invert == False))
	{
	   for (i = pixelmin; i < lower; i++)
	      active[i] = False;

	   for (i = upper+1; i <= pixelmax; i++)
	      active[i] = False;
	}
	else
	{
	   for (i = lower; i <= upper; i++)
	      active[i] = False;
	}

	/*
	 *  Copy the correct xcolor information from the xvdisplay X color
	 *  array.  There is really three cases.  The first is that if the
	 *  pixel is not being used (the xvdisplay's histogram is zero) then
	 *  set the color flags to none.  If the local histogram is zero then
	 *  set the pixel to the threshold pixel values.  Otherwise we just
	 *  copy over the original color information.
	 */
	size = MAX_PIXELS*sizeof(XColor);
	bcopy(xvdisplay->xcolors, xcolors, size);

	if (thres->mode == Windowing)
	   color = xvdisplay->xcolors[thres->fill_pixel];
	else if (thres->mode == Thresholding)
	   color = xvdisplay->xcolors[thres->nonzero_pixel];

	for (i = pixelmin; i <= pixelmax; i++)
	{
	   if (xvdisplay->active[i] == False)
	   {
	      xcolors[i].flags = 0;
	   }
	   else if (active[i] == False)
	   {
	      if (thres->mode == Windowing)
	      {
	         xcolors[i].red   = color.red;
	         xcolors[i].green = color.green;
	         xcolors[i].blue  = color.blue;
	      }
	      else if (thres->mode == Thresholding)
	      {
	         xcolors[i].red   = 
	         xcolors[i].green = 
	         xcolors[i].blue  = 0;
	      }
	      active[i] = True;
	      xcolors[i].flags = DoRed | DoGreen | DoBlue;
	   }
	   else
	   {
	      if (thres->mode == Thresholding)
	      {
	         xcolors[i].red   = color.red;
	         xcolors[i].green = color.green;
	         xcolors[i].blue  = color.blue;
	      }
	      xcolors[i].flags = DoRed | DoGreen | DoBlue;
	   }
	}
	num = (pixelmax - pixelmin) +1;
	store_colors(xcolors, pixelmin, num);
}



/************************************************************
*
*  MODULE NAME: update_thres_cont
*
*      PURPOSE: Updates the colors of the pixel boxes in the
*		palette of the selected range as the user moves
*		the slider on the threshold lower or upper scroll bar
*		(called when the slider is used continuously)
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*
*       OUTPUT: none
*
*   WRITTEN BY: Danielle Argiro & Mark Young
*
*
*************************************************************/


void  update_thres_cont(widget, clientData, callData)

Widget	widget;
caddr_t	clientData, callData;
{
	int	num;
	float	*number = (float *) callData;
        ThresStructure *thres = (ThresStructure *) clientData;

	int  pixelmin = xvdisplay->pixelmin;
	int  pixelmax = xvdisplay->pixelmax;
	ScrollStruct   *upper = thres->upper;
	ScrollStruct   *lower = thres->lower;
	ScrollStruct   *range = thres->range;

	num = (int) ((*number) * (pixelmax - pixelmin) + pixelmin);
	if (lower->scrollbar == widget)
	{
	   lower->num = num;
	   update_int_scroll(lower, lower->num, xvdisplay->pixelmax,
			xvdisplay->pixelmin, xvdisplay->pixelmax);

	   /*
	    *  Make sure the the lower threshold is not greater than the upper
	    *  scrollbar.  If so then set the upper threshold the same as the
	    *  lower.
	    */
	   if (lower->num > upper->num)
	   {
	      upper->num = lower->num;
	      update_int_scroll(upper, upper->num, pixelmax, pixelmin,pixelmax);
	   }
	   range->num = lower->num;
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	else if (upper->scrollbar == widget)
	{
	   upper->num = num;
	   update_int_scroll(upper, upper->num, pixelmax, pixelmin, pixelmax);

	   /*
	    *  Make sure the the upper threshold is not less than the lower
	    *  scrollbar.  If so then set the lower threshold the same as the
	    *  upper.
	    */
	   if (upper->num < lower->num)
	   {
	      lower->num = upper->num;
	      update_int_scroll(lower, lower->num, pixelmax, pixelmin,pixelmax);
	   }
	   range->num = lower->num;
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	else if (range->scrollbar == widget)
	{
	   lower->num += num - range->num;
	   upper->num += num - range->num;
	   range->num = lower->num;
	   update_int_scroll(lower, lower->num, pixelmax, pixelmin, pixelmax);
	   update_int_scroll(upper, upper->num, pixelmax, pixelmin, pixelmax);
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	update_thres();
}



/************************************************************
*
*  MODULE NAME: update_thres_incr
*
*      PURPOSE: Updates the colors of the pixel boxes in the
*		palette of the selected range as the user moves
*               the slider on the threshold lower or upper scroll bar
*		(called when the slider is used incrementally)
*
*        INPUT: widget     -  the widget for the event
*               clientData -  not used
*               event      -  the event
*
*       OUTPUT: none
*
*   WRITTEN BY: Danielle Argiro & Mark Young
*
*
*************************************************************/


void  update_thres_incr(widget, clientData, callData)

Widget	widget;
caddr_t	clientData, callData;
{
	int	movement = (int) callData;
        ThresStructure *thres = (ThresStructure *) clientData;

	int  pixelmin = xvdisplay->pixelmin;
	int  pixelmax = xvdisplay->pixelmax;
	ScrollStruct   *upper = thres->upper;
	ScrollStruct   *lower = thres->lower;
	ScrollStruct   *range = thres->range;


	if (lower->scrollbar == widget)
	{
   	   if (movement > 0)
      	       lower->num -= 5; 
   	   else if (movement < 0)
      	       lower->num += 5;

	   update_int_scroll(lower, lower->num, pixelmax, pixelmin, pixelmax);

	   /*
	    *  Make sure the the lower threshold is not greater than the upper
	    *  scrollbar.  If so then set the upper threshold the same as the
	    *  lower.
	    */
	   if (lower->num > upper->num)
	   {
	      upper->num = lower->num;
	      update_int_scroll(upper, upper->num, pixelmax, pixelmin,pixelmax);
	   }
	   range->num = lower->num;
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	else if (upper->scrollbar == widget)
	{
   	   if (movement > 0)
      	       upper->num -= 5; 
   	   else if (movement < 0)
      	       upper->num += 5;

	   update_int_scroll(upper, upper->num, pixelmax, pixelmin, pixelmax);

	   /*
	    *  Make sure the the upper threshold is not less than the lower
	    *  scrollbar.  If so then set the lower threshold the same as the
	    *  upper.
	    */
	   if (upper->num < lower->num)
	   {
	      lower->num = upper->num;
	      update_int_scroll(lower, lower->num, pixelmax, pixelmin,pixelmax);
	   }
	   range->num = lower->num;
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	else if (range->scrollbar == widget)
	{
	   if (movement > 0)
	   {
	      lower->num -= 5;
	      upper->num -= 5;
	   }
	   else if (movement < 0)
	   {
	      lower->num += 5;
	      upper->num += 5;
	   }
	   range->num = lower->num;
	   update_int_scroll(lower, lower->num, pixelmax, pixelmin, pixelmax);
	   update_int_scroll(upper, upper->num, pixelmax, pixelmin, pixelmax);
	   update_int_scroll(range, lower->num, upper->num, pixelmin, pixelmax);
	}
	update_thres();
}



void thres_reset_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
      thres->lower->num = xvdisplay->pixelmin;
      update_int_scroll(thres->lower, thres->lower->num, xvdisplay->pixelmax,
			xvdisplay->pixelmin, xvdisplay->pixelmax);

      thres->upper->num = xvdisplay->pixelmax;
      update_int_scroll(thres->upper, thres->upper->num, xvdisplay->pixelmax,
			xvdisplay->pixelmin, xvdisplay->pixelmax);

      thres->range->num = xvdisplay->pixelmax;
      update_int_scroll(thres->range, thres->lower->num, thres->upper->num,
			xvdisplay->pixelmin, xvdisplay->pixelmax);

      xvf_change_input(form, edit_info.thres_subform->thres->thresholding_index,
		       xvf_toggleval_chng, "1", 0);

      thres->mode = Windowing;
      xvf_change_input(form, edit_info.thres_subform->thres->accept_index,
		       xvf_logicalval_chng, "1", 0);
      thres->accept = 1;
      update_thres();
}
