 /*
  * Khoros: $Id: utils.c,v 1.4 1992/03/20 22:40:00 dkhoros Exp $
  */

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

 /*
  * $Log: utils.c,v $
 * Revision 1.4  1992/03/20  22:40:00  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"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>         	Editimage Utilities		      <<<<
   >>>>                                                       <<<<
   >>>>			transfer_colormap()		      <<<<
   >>>>			set_colormap()			      <<<<
   >>>>			store_colors()			      <<<<
   >>>>			refresh_palette()		      <<<<
   >>>>			change_image_bands()		      <<<<
   >>>>			update_file()			      <<<<
   >>>>			combine_overlays()		      <<<<
   >>>>			image_info()			      <<<<
   >>>>			free_images()			      <<<<
   >>>>			free_overlays()			      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Module Name: transfer_colormap
*
*      Purpose: This routine is used to transfer one images maps
*		to another.
*
*        Input: source  - the source image with the maps
*		dest    - the destination image to recieve the maps
*
*       Output: none
*
*   Written By: Danielle Argiro & Mark Young
*
*************************************************************/


transfer_colormap(source, dest)

struct xvimage *source, *dest;
{
	if (dest->maps != NULL && dest->map_row_size > 0)
	   free(dest->maps);

	dest->map_scheme	= source->map_scheme;
	dest->map_storage_type  = source->map_storage_type;
	dest->map_row_size 	= source->map_row_size;
	dest->map_col_size 	= source->map_col_size;
	dest->map_subrow_size   = source->map_subrow_size;
	dest->map_enable	= source->map_enable;
	dest->maps_per_cycle 	= source->maps_per_cycle;
	dest->color_space_model = source->color_space_model;
	dest->maps 		= source->maps;

	source->maps = NULL; 
}



/************************************************************
*
*  Module Name: set_colormap
*
*      Purpose: This routine sets the colormap for each of the
*		different display widgets (raster, zoom, pixels,
*		pseudo, lut).
*
*        Input: none
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/


set_colormap()
{
	xvf_sub_form *subform;


	/*
	if (form->toplevel != NULL)
	   xvd_set_colormap(form->toplevel, xvdisplay->colormap);

	subform = form->subform;
	while (subform != NULL)
	{
	   if (subform->toplevel != NULL)
	      xvd_set_colormap(subform->toplevel, xvdisplay->colormap);
	   subform = subform->next_subform;
	}
	 */
	xvd_set_colormap(xvdisplay->raster, xvdisplay->colormap);
	xvd_set_colormap(zoom->image, xvdisplay->colormap);
	xvd_set_colormap(image_workspace, xvdisplay->colormap);
	xvd_set_colormap(pixels->pixels, xvdisplay->colormap);
	xvd_set_colormap(pseudo->pseudo, xvdisplay->colormap);
	xvd_set_colormap(lut->toplevel, xvdisplay->colormap);
	xvd_set_colormap(thres->toplevel, xvdisplay->colormap);
}



/************************************************************
*
*  Module Name: store_colors
*
*      Purpose: This routine stores the colors in the X color
*		array into the xvdisplay colormap.  The routine
*		also calls refresh_display to refresh the different
*		displays.
*
*        Input: xcolors -  the xcolors to be stored into the
*			   xvdisplay colormap.
*		num     -  the number of xcolors to be stored.
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/


store_colors(xcolors, index, num)

XColor	xcolors[];
int	index, num;
{
	int    i, j;
	XColor store[MAX_PIXELS];

	for (i = 0, j = 0; i < num; i++)
	{
	    if (active[i+index])
	       store[j++] = xcolors[i+index];
	}

	/*
	 *  Store the X colors into the colormap
	 */
	if (j > 0)
	{
	   XStoreColors(display, xvdisplay->colormap, store, j);
	   refresh_displays(index, num);
	}
}



/************************************************************
*
*  Module Name: refresh_displays
*
*      Purpose: This routine refreshes the visible displays.
*		The displays consists of "pixels", "pseudo",
*		"lut", "position".  If the widget display is
*		visible then we call it's refresh routine to
*		update it.  This routine is called when inputing
*		a new image or region of interest.  This
*		routine is also called after storing new colors
*		into the xvdisplay colormap.
*
*        Input: none
*
*       Output: Calls the different refresh routines to update
*		the different displays.
*
*   Written By: Mark Young
*
*************************************************************/


refresh_displays(index, num)

int	num, index;
{

	/*
	if (xvd_check_visibility(xvdisplay->raster) == True)
	   refresh_position();
	*/

	if (xvd_check_visibility(pixels->pixels) == True)
	   refresh_pixels();

	if (xvd_check_visibility(pseudo->pseudo) == True)
	   refresh_pseudo();

	if (xvd_check_visibility(lut->toplevel) == True)
	   refresh_lut(index, num);
}



/************************************************************
*
*  Module Name: refresh_palette
*
*      Purpose: This routine is used to refresh the color palette.
*		The color palette is used to show the color ramp
*		for a few of the display windows.  The threshold
*		display uses the palette as a visual cue so that
*		the users understands what part of the palette they
*		are affecting.
*
*        Input: widget     -  the widget for the event
*		clientData -  not used
*		event      -  the event
*
*       Output: none
*
*   Written By: Mark Young
*
*************************************************************/

void refresh_palette(widget, clientData, event)

Widget widget;
caddr_t clientData;
XEvent  *event;
{
	XEvent	  next;
	Window	  root;
	double	  xfact;
	int	  status, i, j, x1, x2, num;
	unsigned  int width, height, dummy;


	/*
         *  refresh the colortable display, but first eat all the exposure
         *  events.
         */
        do
        {
           status = XCheckWindowEvent(display, XtWindow(widget), ExposureMask,
				      &next);
	} while (status);

	/*
	 *  Get the tables geometry (width & height) so that we know how
	 *  much to fill.
	 */
	if (!XGetGeometry(XtDisplay(widget), XtWindow(widget), &root, &x1, &x1,
			   &width, &height,  &dummy, &dummy))
	{
	   xvf_error_wait("Window does not exist.","redisplay_lut", NULL);
	   return;
	}
	num = xvdisplay->pixelmax - xvdisplay->pixelmin +1;
	if (num < 1) return;

	xfact = width/((double) num);
	for (i = 0, x1 = 0; i < num; i++)
	{
	   j = xvdisplay->pixelmin + i;
	   if (xvdisplay->active[j] > 0)
	   {
	      XSetForeground(display, gc, xvdisplay->xcolors[j].pixel);

	      x2 = xfact * (i+1) + 0.5;
	      width = x2 - x1;
	      XFillRectangle(display, XtWindow(widget), gc,x1,0, width, height);
	      x1 = x2;
	   }
	}
}



/********************************************************
*
*  Routine Name:  change_image_bands
*
*       Purpose:  changes the bands of the displayed image
*
*         Input:  none
*        Output:  none
*
*     Called By:  run_image()
*
*    Written By:  Mark Young & Danielle Argiro
*
********************************************************/

change_image_bands()
{
        int     i, num, current;
        char    **bandnames, temp[MAXBUF];
	XawListReturnStruct *band_list_return;
	char *prompt = "Pick Band To Be Displayed";
	char *label  = "Image Bands";


	if (images != NULL)
           num = num_bands;
	else
	   num = 0;

        if (num < 2)
        {
           xvf_error_wait("Error!  You must have an image with more than one\
 image band to use this command.", "change_image_bands", NULL);
           return;
        }
        bandnames = (char **) malloc(sizeof(char *) * num);

        for (i = 0; i < num; i++)
        {
            (void) sprintf(temp," image band %1d", i);
            bandnames[i] = xvf_strcpy(temp);
        }

	/*
	 *  Prompt the user for which band they want using a list widget
	 */
	band_list_return = xvf_run_list_wait(bandnames, num, 1, prompt,
                                             label, &current, False);
	if (band_list_return == NULL) return;

	xvdisplay->image = band[band_list_return->list_index];
	(void) update_image(NULL);

	for (i = 0; i < num; i++)
	   free(bandnames[i]);
	free(bandnames);
}



/********************************************************
*
*  Routine Name:  update_file
*
*       Purpose:  This routine is a the callback routine used
*		  by the detect routines to update an image.
*
*         Input:  id 	      - identifier for the file that has changed
*		  filename    - name of file detected.
*		  clientData  - client data structure sent back
*        Output:  none
*
*     Called By:  run_image()
*
*    Written By:  Mark Young & Danielle Argiro
*
********************************************************/

int update_file(id, filename, data)

int  id;
char *filename;
char *data;
{
	struct xvimage *image, *readimage();


	if (!(image = readimage(filename)))
	   return(False);

	update_image(image);
	return(True);
}



/********************************************************
*
*  Routine Name:  combine_overlays
*
*       Purpose:  combines overlays into displayed image
*
*         Input:  none
*        Output:  none
*
*     Called By:  run_image()
*
*    Written By:  Mark Young
*
********************************************************/

combine_overlays()
{
        Window  window;
        Widget  widget;
        Display *display;
        int     status, screen;
        struct  xvimage  *tmp_image, *create_pixmap_image();

        widget  = xvdisplay->raster;
        window  = XtWindow(widget);
        display = XtDisplay(widget);
        screen  = XDefaultScreen(display);

	status = xvf_warn_wait("Use the window manager now to make sure that the currently displayed image is RAISED, AND NOT OBSCURED by any other windows (including this one).  NO PART OF THE WORKSPACE SHOULD BE OFF THE SCREEN. When ready, click on \"Combine\".", "combine_overlays", "Combine", "Cancel");
	if (!(status)) return;

        tmp_image = create_pixmap_image(display, screen, window,0,0,0,0,0);
        if (tmp_image == NULL)
        {
           xvf_error_wait("Could not create image", "combine_overlays", NULL);
           return;
        }
	if (xvdisplay->image != NULL)
	   strcpy(tmp_image->comment, xvdisplay->image->comment);

	/*
	 *  any annotations are now part of image; not annotations any more
	 */
	obj_list = NULL;

	/*
         *  update with the new image
         */
        (void) update_image(tmp_image);
}



/********************************************************
*
*  Routine Name:  image_info
*
*       Purpose:  prints information about the currently
*		  displayed image
*
*         Input:  none
*        Output:  none
*
*    Written By:  Mark Young
*
********************************************************/

image_info()
{
	FILE	*file;
	char	*filename, temp[MaxLength];


	/*
	 *  Make sure that there currently is an image to print info
	 *  about.
	 */
	if (xvdisplay == NULL)
	{
	   xvf_error_wait("Error!  No image found to print information about. \
Please use the 'Input / Output' form or the '-i' command line option to \
display an image before using this command.", "image_info", NULL);
	   return;
	}

	/*
	 *  Open the temporary file that will contain the help
	 *  information.
	 */
	if ((filename = vtempnam("image_info")) == NULL)
	{
	   xvf_error_wait("Unable to create temporary file to print the \
current image information", "image_info", NULL);
	   return;
	}

	if ((file = fopen(filename, "w")) == NULL)
	{
	   (void) sprintf(temp,"Unable to open the temporary file\n%s\nto \
print the current image information", filename);
	   xvf_error_wait(temp, "image_info", NULL);
	   free(filename);
	   return;
	}

	if (xvdisplay->image)
	{
	   lvfileinfo(xvdisplay->image, "Display Image", file);
	}

	if (xvdisplay->shape)
	{
	   lvfileinfo(xvdisplay->shape, "Shape Image", file);
	}

	if (xvdisplay->clip)
	{
	   lvfileinfo(xvdisplay->shape, "Clip Image", file);
	}

	if (xvdisplay->overlay)
	{
	   lvfileinfo(xvdisplay->overlay, "Overlay Image", file);
	}
	fclose(file);
	xvf_online_help_wait(filename, "Editimage Image Information");
	unlink(filename);
	free(filename);
}



/********************************************************
*
*  Routine Name:  free_images
*
*       Purpose:  frees the images and image bands associated
*		  with the multi-banded image list.
*
*         Input:  none
*        Output:  none
*
*    Written By:  Mark Young
*
********************************************************/

free_images()
{
	int	i;


	if (xvdisplay->image != xvdisplay->disp_image)
	   freeimage(xvdisplay->disp_image);

	if (images != NULL)
	{
	   if (band != NULL)
	   {
	      for (i = 0; i < num_bands; i++)
		 free(band[i]);

	      free(band);
	      band = NULL;
	   }
	   freeimage(images);
	   images = NULL;
	}
	xvdisplay->image = NULL;
	xvdisplay->disp_image = NULL;
}



/********************************************************
*
*  Routine Name:  free_overlays
*
*       Purpose:  frees the overlays and overlay bands associated
*		  with the multi-banded overlay image list.
*
*         Input:  none
*        Output:  none
*
*    Written By:  Mark Young
*
********************************************************/

free_overlays()
{
	int	i;


	if (overlays != NULL)
	{
	   if (ovband != NULL)
	   {
	      for (i = 0; i < num_ovbands; i++)
	         free(ovband[i]);
	   
	      free(ovband);
	      ovband = NULL;
	   }
	   freeimage(overlays);
	   overlays = NULL;
	}

	if (ovactive != NULL)
	   free(ovactive);
	if (xvdisplay->ovmask != NULL)
	   freeimage(xvdisplay->ovmask);

	ovactive = NULL;
	xvdisplay->overlay = NULL;
	xvdisplay->ovmask = NULL;
}
