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

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

 /*
  * $Log: persp.c,v $
 * Revision 1.1  1991/05/10  15:59:48  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 	"xprism.h"
#include	"scrolls.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: persp.c
   >>>>               
   >>>>   description: Xprism 3D Utility  Routines
   >>>>			For Creating & Using a Selection Bar
   >>>>                 To Change the Viewing System
   >>>>              
   >>>>      routines:
   >>>>			update_persp_scroll_bar
   >>>>			display_diagram 
   >>>>			reset_absolute_cb
   >>>>			reset_relative_cb
   >>>>			use_cb 
   >>>>			exit_cb 
   >>>>			persp_incr_cb
   >>>>			persp_flow_cb
   >>>>			persp_update_val_widget
   >>>>              
   >>>> modifications:
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



#define diag_id 19
int last_sel_use = FALSE;

/************************************************************
*
* Routine Name:  update_persp_scroll_bar
*
*      Purpose:  For the scroll bars on the perspective selection bar,
*	         this is the XtActionProc that is initiated when the
*	         user enters a value directly into a value
*		 widget and hits <CR>.  It will update the scroll bar
*		 to reflect the new value.  
*
*        Input:  widget - the widget corresponding to the 
*			  particular selection's background widget
*
*	         clientData - structure used by the client (xvforms)
*		 callData -  structure used by the X toolkit  (?)
*
*
*   Written By: Danielle Argiro
*
*************************************************************/

void update_persp_scroll_bar(widget, event, params, num_params)
Widget widget;
XEvent *event;
String *params;
Cardinal *num_params;
{
   Scroll_Data *scroll_data;
   float percent;
   persp_scroll_link *persp_scroll_ptr;

   /* get the current perspective settings */
   X3D_inquire_viewpoint (diag_id, &gwin_attr->alpha, &gwin_attr->theta, 
			  &gwin_attr->eye_dist);
   X3D_inquire_view_distance (diag_id, &gwin_attr->view_dist);
   
   /* 
    * find the correct scroll_data info for scroll bar 
    * paired with this value widget
    */
   persp_scroll_ptr = persp_scroll_list;
   if (persp_scroll_ptr == NULL) 
   {
       fprintf(stderr, "update_persp_scroll: \n");
       fprintf(stderr, "something awful wrong; linking struct NULL\n");
       return;
   }
   while (persp_scroll_ptr->value_widget != widget)
	persp_scroll_ptr = persp_scroll_ptr->next;
   scroll_data = persp_scroll_ptr->scroll_info; 

   /*
    * get the float from its parameter box, update the float value 
    * stored in the scroll data, and set the perspective accordingly
    */
   scroll_data->float_value = atoi(scroll_data->buffer);

   if (scroll_data->flag == RotateX)
   {
       gwin_attr->alpha = scroll_data->float_value;
       if (((int)gwin_attr->alpha) <= 0) gwin_attr->alpha += 360;
       if (((int)gwin_attr->alpha) >= 360) gwin_attr->alpha = 360 - gwin_attr->alpha;
   }
   else if (scroll_data->flag == RotateZ)
   {
       gwin_attr->theta = scroll_data->float_value;
       if (((int)gwin_attr->theta) <= 0) gwin_attr->theta += 360;
       if (((int)gwin_attr->theta) >= 360) gwin_attr->theta = 360 - gwin_attr->theta;
   }
   X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, 
		      gwin_attr->eye_dist);

   if (gwin != NULL)
   {
            /* display axes diagram and legend */
            X3D_clear_window(diag_id);
            draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
            last_sel_use = FALSE;
    }

   /* 
    * update the thumb of the scroll bar to match
    * the new float value in the parameter box..
    */
   percent = (scroll_data->float_value - scroll_data->float_min)/
	     (scroll_data->float_max - scroll_data->float_min);
   XawScrollbarSetThumb(*scroll_data->scroll_widget, percent, 1.0);

}

/*
 *  translation tables for scroll bars on perspective selection bar
 *  Map <CR> to call incremental or flow routine
 */
void persp_incr_cb();
void persp_flow_cb();
void update_persp_scroll_bar();

char incr_rotate_table[] =
"<Key>0xff0d:   persp_incr_cb() \n\
Ctrl<Key>x:    beginning-of-file()";

char flow_rotate_table[] =
"<Key>0xff0d:   persp_flow_cb() \n\
Ctrl<Key>x:    beginning-of-file()";

char value_widget_table[]=
"<Key>0xff0d:   update_persp_scroll_bar() \n\
Ctrl<Key>x:    beginning-of-file()";


/**************************************************************
*
* MODULE NAME: create_perspective_selection() 
*
*     PURPOSE: This module is used to set up each specific widget 
*	       on the perspective selection bar.  Each has a different
*	       purpose.
*
*	INPUT: labels   -  array of strings that make up the labels
*			   (can have more than one if user wants vertical 
*			    spacing of the labels)
*	       labelnum - number of labels for the widget 
*	       parent   - the toplevel of the perspective selection bar
*	       horiz	- widget to which this widget should have relative
*			  horizontal positioning
*	       vert	- widget to which this widget should have relative
*			  vertical positioning
*	       font_width- font width of current font
*	       font_height- font width of current font
*	       width    - number of pixels wide the widget should be
*	       height   - number of pixels high the widget should be
*	       function - name of the callback for this widget
*	       font     - the desired font for the text 
*	       color    - the desired pixel value for the background 
*		
*
*      OUTPUT: the perspective selection bar widget
*
* CALLED FROM: Main
*
*      AUTHOR: Danielle Argiro
*
**************************************************************/

#define MaxLabels 5


Widget *create_persp_sel(labels, labelnum, parent, horiz, vert, 
			 font_width, font_height, width, height,
			 function, font, color, widget_name)
char *labels[];
int  labelnum;
Widget parent, horiz, vert;
int  font_width, font_height;
int  width, height;
void (*function)();
XFontStruct *font;
unsigned long color;
char	*widget_name;
{
	int i, j;
	Arg arg[10];
	Widget *widget_back, *widget_label, *vert_offset;

	widget_back  = (Widget *)malloc(sizeof(Widget));
   	widget_label = (Widget *)malloc(sizeof(Widget));
   	vert_offset =  (Widget *)malloc(sizeof(Widget));

	 /* create back widget */
	i = 0;
   	XtSetArg(arg[i],XtNwidth,  (Dimension) width); 		i++;
   	XtSetArg(arg[i],XtNheight, (Dimension) height); 	i++;
   	XtSetArg(arg[i],XtNfromVert,  vert);			i++;
   	XtSetArg(arg[i],XtNfromHoriz, horiz);			i++;
   	XtSetArg(arg[i],XtNborderWidth, 1);			i++;
        XtSetArg(arg[i],XtNbackground,color);			i++;

	*widget_back = XtCreateManagedWidget(xvf_strcpy(widget_name), 
				             formWidgetClass, parent,arg,i);

	*vert_offset = NULL;

	/* put in label */
	for (j = 0; j < labelnum; j++)
	{
	    i = 0;
   	    XtSetArg(arg[i],XtNwidth,(Dimension)font_width);	i++;
   	    XtSetArg(arg[i],XtNheight,(Dimension)font_height);	i++;
	    if (labels[j] != NULL)
      	        XtSetArg(arg[i],XtNlabel,xvf_strcpy(labels[j]));
	    else 
      	        XtSetArg(arg[i],XtNlabel,xvf_strcpy(" "));      i++;

            XtSetArg(arg[i],XtNfromHoriz, NULL);                i++;
	    XtSetArg(arg[i],XtNfromVert,  *vert_offset);        i++;

            XtSetArg(arg[i],XtNborderWidth,0);			i++;
            XtSetArg(arg[i],XtNfont,font);			i++;
            XtSetArg(arg[i],XtNbackground,color);		i++;
	    *widget_label = XtCreateManagedWidget("persp_label", 
                	       labelWidgetClass,*widget_back,arg,i);

	    vert_offset = widget_label;
	}

	XtAddEventHandler(*widget_back, ButtonPressMask, FALSE,
                          function, NULL);

	return(widget_back);

}

/**************************************************************
*
* MODULE NAME: create_perspective_sel_bar() 
*
*     PURPOSE: This module is used to set up the selection bar widget that
*	       will allow the user to change the perspective
*
*       INPUT:  x & y - device coordinates for placement of selection bar
*
*      OUTPUT: the perspective selection bar widget
*
* CALLED FROM: Main
*
*      AUTHOR: Danielle Argiro
*
**************************************************************/

extern int ac; 
extern char **av;

#define MAX_LABEL_LENGTH 9

Widget *create_perspective_sel_bar()
{

	int i, font_width, font_height, labelnum, comment_width;
	int ascent, descent, dir_return, n, m;
	XCharStruct ov_return;
	XFontStruct *font;
        Cursor	cursor;
	char *mesg, tmp[512];
	Arg arg[10];
	Widget *toplevel, *sel_back;
	Widget *w1, *w2, *w3, *w4, *w5, *w6, *w7, *w8;
	Widget *create_scroll_sel();
	Widget *sel_back_comment;
	
	/*  labels for the selection bar */
	static
	char *label9[2]  = { " Reset  ","last"},
	     *label10[2] = { " Reset  ","defaults"},
	     *label11[2] = {"  Use   ","   " },
	     *label12[2] = {"  EXIT  ","   "};

	labelnum = 2;

	/* create selection bar background widget */
	sel_back 	 =  (Widget *)malloc(sizeof(Widget));
   	sel_back_comment =  (Widget *)malloc(sizeof(Widget));

	/* need to make sure fonts are ok */
        if ((font = XLoadQueryFont(display, FONTNAME_R3)) == NULL)
        {
           if ((font = XLoadQueryFont(display, FONTNAME_R2)) == NULL)
           {
	      (void) sprintf(tmp, "Can't find small default fonts:\n%s\n%s",
                                 FONTNAME_R3, FONTNAME_R2);
              mesg = xvf_strcpy(tmp);
              xvf_error_wait(mesg, "create_window", NULL);
              free(mesg);
              exit(1);

           }
        }

	font_width = XTextWidth(font,"@ X  CCW",  8);
	comment_width = XTextWidth(font,"CCW: counterclockwise",  21);

	XTextExtents(font, "  absolute  ", 12, &dir_return, 
		     &ascent, &descent, &ov_return);
	font_height = ascent + descent;

	init_sel_bar_colors(12);

	/*
         * allocate room for the selection bar's toplevel 
	 *  widget & return on failure
         */
        if (!(toplevel = (Widget *) malloc(sizeof (Widget)))) 
	{
            mesg = xvf_strcpy("Could not allocate room for toplevel widget\n");
            xvf_error_wait(mesg, "create_perspective_sel_bar", NULL);
            free(mesg);
	    return(NULL);
	}
       

	/* create perspective selection bar's toplevel widget */
	i = 0;
        XtSetArg(arg[i],XtNscreen, DefaultScreenOfDisplay(display)); i++;
	XtSetArg(arg[i],XtNmappedWhenManaged,False);		       i++;
        XtSetArg(arg[i], XtNargc, ac);                                i++;
        XtSetArg(arg[i], XtNargv, av);                                i++;
        *toplevel = XtAppCreateShell("perspective","Perspective",
                                            applicationShellWidgetClass,
                                            display, arg, i);


	i = 0;
   	XtSetArg(arg[i],XtNborderWidth,1);			i++;
 
   	*sel_back = XtCreateManagedWidget("sel_back",formWidgetClass,
                    *toplevel,arg,i);

	m = font_height*(labelnum);
	n = font_width*MAX_LABEL_LENGTH;

	w1 = create_scroll_sel(*sel_back, NULL, NULL, n, m, 
			      persp_incr_cb, persp_flow_cb, 
			      0.0, 100.0, gwin_attr->eye_dist, font, sel_bar_colors[0],
			      Camera);

	w2 = create_scroll_sel(*sel_back, NULL, *w1, n, m, 
			      persp_incr_cb, persp_flow_cb, 
			      0.0, 100.0, gwin_attr->view_dist, font, sel_bar_colors[1],
			      Zoom);

	w3 = create_scroll_sel(*sel_back, NULL, *w2, n, m, 
			      persp_incr_cb, persp_flow_cb, 
			      0.0, 360.0, gwin_attr->alpha, font, sel_bar_colors[2],
			      RotateX);

	w4 = create_scroll_sel(*sel_back, NULL, *w3, n, m, 
			      persp_incr_cb, persp_flow_cb, 
			      0.0, 360.0, gwin_attr->theta, font, sel_bar_colors[5],
			      RotateZ);

 	w5 = create_persp_sel(label9, labelnum, *sel_back, *w4, NULL, 
			      font_width, font_height, n, m, 
			      reset_relative_cb, font, sel_bar_colors[8],
			      "reset_rel");

	w6 = create_persp_sel(label10, labelnum, *sel_back, *w4, *w5, 
			      font_width, font_height, n, m, 
			      reset_absolute_cb, font, sel_bar_colors[9],
			      "reset_abs");

	w7 = create_persp_sel(label11, labelnum, *sel_back, *w5, NULL, 
			       font_width, font_height, n, m, 
			       use_cb, font, sel_bar_colors[10],
			      "use");

	w8 = create_persp_sel(label12, labelnum, *sel_back, *w5, *w7, 
			       font_width, font_height, n, m, 
			       exit_cb, font, sel_bar_colors[11],
			      "exit");


	XtRealizeWidget(*toplevel);

       /* create the cursor for the form */
        cursor = XCreateFontCursor(display, XC_left_ptr);
        XDefineCursor(display, XtWindow(*toplevel), cursor);

	return(toplevel);
}



/**************************************************************
*
* MODULE NAME: create_perspective_selection() 
*
*     PURPOSE: This module is used to set up each specific widget 
*	       on the perspective selection bar.  Each has a different
*	       purpose.
*
*	INPUT: parent   - the toplevel of the perspective selection bar
*	       horiz	- widget to which this widget should have relative
*			  horizontal positioning
*	       vert	- widget to which this widget should have relative
*			  vertical positioning
*	       font_width- font width of current font
*	       font_height- font width of current font
*	       width    - number of pixels wide the widget should be
*	       height   - number of pixels high the widget should be
*	       function - name of the callback for this widget
*	       font     - the desired font for the text 
*	       color    - the desired pixel value for the background 
*
*      OUTPUT: the perspective selection bar widget
*
* CALLED FROM: Main
*
*      AUTHOR: Danielle Argiro
*
**************************************************************/

#define ScrollWidth 260
#define ScrollIncrement 5

Widget *create_scroll_sel(parent, horiz, vert, width, height,
			 incr_function, flow_function, 
			 lower_float, upper_float, float_val,
			 font, color, flag)
Widget parent, horiz, vert;
int  width, height;
void (*incr_function)();
void (*flow_function)();
float lower_float, upper_float, float_val;
XFontStruct *font;
unsigned long color;
int	flag;
{
	int i;
	Arg arg[10];
	Widget *widget_back, *scroll_widget, *value_widget, *label_widget;
	char scroll_name[512], val_name[512], *temp, label_name[512];
	char *label, *widget_name;
	float percent;
	XtTranslations translations;
	Scroll_Data *scroll_data;
	persp_scroll_link *persp_scroll_ptr;
	void update_persp_scroll_bar();

/*
 * Action table for updating scroll bars when a value is
 * entered into the value widget.
 */
static XtActionsRec actionTable[] =
{
  { "update_persp_scroll_bar",  update_persp_scroll_bar},
};

	if (flag == RotateX)
	{
	    label = xvf_strcpy("Rotate @ X");
	    widget_name = xvf_strcpy("rotate_x");
	}
	else if (flag == RotateZ)
	{
	    label = xvf_strcpy("Rotate @ Z");
	    widget_name = xvf_strcpy("rotate_z");
	}
	else if (flag == Camera)
	{
	    label = xvf_strcpy(" Eye Dist ");
	    widget_name = xvf_strcpy("eye_dist");
	}
	else if (flag == Zoom)
	{
	    label = xvf_strcpy(" View Dist");
	    widget_name = xvf_strcpy("view_dist");
	}
	
	widget_back  = (Widget *)malloc(sizeof(Widget));
   	scroll_widget = (Widget *)malloc(sizeof(Widget));
   	value_widget = (Widget *)malloc(sizeof(Widget));
   	label_widget = (Widget *)malloc(sizeof(Widget));

	 /* create back widget */
	i = 0;
   	XtSetArg(arg[i],XtNwidth,  (Dimension) width); 		i++;
   	XtSetArg(arg[i],XtNheight, (Dimension) height); 	i++;
   	XtSetArg(arg[i],XtNfromVert,  vert);			i++;
   	XtSetArg(arg[i],XtNfromHoriz, horiz);			i++;
   	XtSetArg(arg[i],XtNborderWidth, 1);			i++;
	*widget_back = XtCreateManagedWidget(widget_name, formWidgetClass, 
					     parent,arg,i);

	/* create label widget */
	sprintf(label_name, "%s_label", widget_name);
	i = 0;
	XtSetArg(arg[i],XtNlabel,label);			i++;
	XtSetArg(arg[i],XtNfromVert, NULL);                     i++;
      	XtSetArg(arg[i],XtNfromHoriz,NULL);                     i++;
        XtSetArg(arg[i],XtNhorizDistance, 5);     		i++;
        XtSetArg(arg[i],XtNborderWidth,0);                      i++;
	XtSetArg(arg[i],XtNfont,font);                          i++;
        XtSetArg(arg[i],XtNbackground,color);			i++;
	*label_widget =   XtCreateManagedWidget(label_name, labelWidgetClass,
                                                *widget_back,arg,i);


	/* create value widget */
	sprintf(val_name, "%s_value", widget_name);
	temp = (char *) malloc (512);
	sprintf(temp, "%f", float_val);
	i = 0;
	XtSetArg(arg[i],XtNeditType,XawtextEdit);		i++;
	XtSetArg(arg[i],XtNtype,    XawAsciiString);		i++;
        XtSetArg(arg[i],XtNstring, temp);                  	i++;
	XtSetArg(arg[i],XtNfromVert, NULL);                     i++;
      	XtSetArg(arg[i],XtNfromHoriz, *label_widget);           i++;
        XtSetArg(arg[i],XtNwidth,(Dimension) 9*xvf_font_width); i++;
/*      XtSetArg(arg[i],XtNheight, (Dimension) 14);         	i++; */
	*value_widget =  XtCreateManagedWidget(val_name,
                        asciiTextWidgetClass,*widget_back,arg,i);

	

	/* create scroll widget */
	sprintf(scroll_name, "%s_scroll", widget_name);
	i = 0;
	XtSetArg(arg[i], XtNfromVert, NULL);                     i++;
      	XtSetArg(arg[i], XtNfromHoriz, *value_widget);           i++;
        XtSetArg(arg[i], XtNorientation, XtorientHorizontal);    i++;
        XtSetArg(arg[i], XtNwidth,(Dimension) ScrollWidth);    	 i++;
	if (XDisplayPlanes(display,screen) > 1)
	{
        XtSetArg(arg[i], XtNforeground,(Dimension) color);    	 i++;
	}
	else
	{
        XtSetArg(arg[i], XtNforeground,(Dimension) 
		BlackPixel(display, DefaultScreen(display)));    	 i++;
	}
        XtSetArg(arg[i], XtNheight, (Dimension) 14);         	 i++;

        *scroll_widget = XtCreateManagedWidget(scroll_name,
                         scrollbarWidgetClass,*widget_back,arg,i);

	scroll_data = (Scroll_Data *) malloc (sizeof(Scroll_Data));
	scroll_data->float_min     = lower_float;
	scroll_data->float_max     = upper_float;
	scroll_data->float_value   = float_val;
	scroll_data->bar_width     = ScrollWidth;
	scroll_data->increment     = ScrollIncrement;
	scroll_data->buffer        = temp;
	scroll_data->flag    	   = flag;
	scroll_data->val_widget    = value_widget;
	scroll_data->scroll_widget = scroll_widget;
	

	XtAddCallback(*scroll_widget, XtNscrollProc, incr_function,
                           (caddr_t) scroll_data);
        XtAddCallback(*scroll_widget, XtNjumpProc, flow_function,
                           (caddr_t) scroll_data);

	translations = XtParseTranslationTable(value_widget_table);
	XtOverrideTranslations(*value_widget, translations);

	percent = (float_val - lower_float)/ (upper_float - lower_float);
	XawScrollbarSetThumb(*scroll_widget, percent, 1.0);

	
	if (persp_scroll_list == NULL)
	{
	       	persp_scroll_list = (persp_scroll_link *)
				   malloc (sizeof(persp_scroll_link));
	       	persp_scroll_list->value_widget = *value_widget;
	       	persp_scroll_list->scroll_info  = scroll_data;
	       	persp_scroll_list->next = NULL;
	}
	else
	{
		persp_scroll_ptr = persp_scroll_list;
		while (persp_scroll_ptr->next != NULL)
			persp_scroll_ptr = persp_scroll_ptr->next;
		persp_scroll_ptr->next = (persp_scroll_link *)
                                  	malloc (sizeof(persp_scroll_link));
            	persp_scroll_ptr->next->value_widget = *value_widget;
            	persp_scroll_ptr->next->scroll_info = scroll_data;
            	persp_scroll_ptr->next->next = NULL;
         }
		
	XtAppAddActions(xvf_app_context, actionTable, XtNumber(actionTable));
	translations = XtParseTranslationTable(value_widget_table);
	XtOverrideTranslations(*value_widget, translations);

	return(widget_back);
}



/************************************************************
*  Routine Name: display_diagram 
*
*      Purpose:  displays the axes diagram & draws the legend 
*
*        Input:  widget - the widget corresponding to the
*                         particular selection's background widget
*
*                clientData - structure used by the client (xvforms)
*		 event	    - event struct that triggered callback
*
*
*   Written By: Danielle Argiro, Mark Young, Mike Lang 
*
*
*************************************************************/
display_diagram()
{
	/* inquire the current gwin id and set the diagram settings */
	X3D_inquire_viewpoint(gwin->id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist);
	X3D_inquire_view_distance(gwin->id, &gwin_attr->view_dist);
	X3D_set_viewpoint(diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
	X3D_set_view_distance(diag_id, gwin_attr->view_dist);

	/* display axes diagram and legend */
        X3D_clear_window(gwin->id);
        draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
        draw_axes_legend(gwin->workspace, gwin_attr->eye_dist, gwin_attr->view_dist, gwin_attr->alpha, gwin_attr->theta);
}


/************************************************************
*
*  MODULE NAME: Initialize_Selection_Bar_Colors
*
*      PURPOSE: To initialize and define colors for later use
*	        with the main icon window
*
*        INPUT: none
*
*       OUTPUT: none
*
*    CALLED BY: Main
*
*   WRITTEN BY: Mark Young And Danielle Argiro
*
*
*************************************************************/

init_sel_bar_colors(sel_num) 

int sel_num;
{
   int	 i, j;
   XColor exact_color_def, screen_color_def;
   XColor Colors[18];
   static char *sel_colors[] = { 
	"Yellow", "Coral", "Magenta", "Wheat", "LightGrey", "Cyan",
	"MediumSpringGreen", "Orchid", "Pink", "CadetBlue", "Green",
	"Turquoise", "Red", "Orange", "Grey", "Tan", "Red", "Blue" };


   int          num_colors = 18;

   X3D_allocate_named_colors(display, sel_colors, Colors, num_colors,
                             false, X3D_WHITE);
   for (i = 0; i < sel_num; i++)
       sel_bar_colors[i] = Colors[i].pixel;
}



/************************************************************
*  Routine Name:  reset_absolute_cb
*
*      Purpose:   Callback for the reset_absolute widget
*
*        Input:  widget - the widget corresponding to the
*                         particular selection's background widget
*
*                clientData - structure used by the client (xvforms)
*		 event	    - event struct that triggered callback
*
*
*   Written By: Danielle Argiro, Mark Young, Mike Lang 
*
*
*************************************************************/

void reset_absolute_cb(widget, clientData, event)
Widget widget;
caddr_t clientData;
XEvent  *event;
{
	float percent;
	persp_scroll_link *persp_scroll_ptr;
	Scroll_Data *scroll_data;

	gwin_attr->alpha = 63.7;   	gwin_attr->eye_dist  =  8.0;
	gwin_attr->theta = 31.8;	gwin_attr->view_dist = 16.0;

	/* 
 	 * set alpha, theta, eye_dist & view dist back to default values
	 */
	persp_scroll_ptr = persp_scroll_list;
	while (persp_scroll_ptr != NULL)
	{
		scroll_data = persp_scroll_ptr->scroll_info;
		if (scroll_data == NULL) return;

		if (scroll_data->flag == RotateX)
		    scroll_data->float_value = gwin_attr->alpha;
		else if (scroll_data->flag == RotateZ)
		     scroll_data->float_value = gwin_attr->theta;
		else if (scroll_data->flag == Camera)
		     scroll_data->float_value = gwin_attr->eye_dist;
		else if (scroll_data->flag == Zoom)
		     scroll_data->float_value = gwin_attr->view_dist;

		persp_update_val_widget(scroll_data);

   		percent = (scroll_data->float_value - scroll_data->float_min)/
	     		  (scroll_data->float_max - scroll_data->float_min);
   		XawScrollbarSetThumb(*scroll_data->scroll_widget, percent, 1.0);

		persp_scroll_ptr = persp_scroll_ptr->next;
	}
	
	/*
	 *  update perspective on both the plot & the axes diagrams
	 */
	if (gwin != NULL)
	{
	    X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
	    X3D_set_viewpoint (gwin->id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
	    X3D_set_view_distance (diag_id, gwin_attr->view_dist);
	    X3D_set_view_distance (gwin->id, gwin_attr->view_dist);
	
	    /* display axes diagram and legend */
	    X3D_clear_window(diag_id);
            draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
	    last_sel_use = FALSE;
	}
}


/************************************************************
*  Routine Name:  reset_relative_cb
*
*      Purpose:   Callback for the reset_relative widget
*
*        Input:  widget - the widget corresponding to the
*                         particular selection's background widget
*
*                clientData - structure used by the client (xvforms)
*		 event	    - event struct that triggered callback
*
*
*   Written By: Danielle Argiro, Mark Young, Mike Lang 
*
*
*************************************************************/

void reset_relative_cb(widget, clientData, event)
Widget widget;
caddr_t clientData;
XEvent  *event;
{
	persp_scroll_link *persp_scroll_ptr;
	Scroll_Data *scroll_data;
	Real percent;

	/*
	 *   plot perspective has not changed since they last hit "Use".
	 *   inquire what this perspective is and restore it to diagram
	 */  
	if (gwin != NULL)
	{
	    X3D_inquire_viewpoint (gwin->id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist);
	    X3D_inquire_view_distance (gwin->id, &gwin_attr->view_dist);
	    X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
	    X3D_set_view_distance (diag_id, gwin_attr->view_dist);

	    persp_scroll_ptr = persp_scroll_list;
	    while (persp_scroll_ptr != NULL)
	    {
		scroll_data = persp_scroll_ptr->scroll_info;
		if (scroll_data == NULL) return;

		if (scroll_data->flag == RotateX)
		    scroll_data->float_value = gwin_attr->alpha;
		else if (scroll_data->flag == RotateZ)
		     scroll_data->float_value = gwin_attr->theta;
		else if (scroll_data->flag == Camera)
		     scroll_data->float_value = gwin_attr->eye_dist;
		else if (scroll_data->flag == Zoom)
		     scroll_data->float_value = gwin_attr->view_dist;

		persp_update_val_widget(scroll_data);

   		percent = (scroll_data->float_value - scroll_data->float_min)/
	     		  (scroll_data->float_max - scroll_data->float_min);
   		XawScrollbarSetThumb(*scroll_data->scroll_widget, percent, 1.0);

		persp_scroll_ptr = persp_scroll_ptr->next;

	    }

	    /* display axes diagram and legend */
	    X3D_clear_window(diag_id);
            draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
	    last_sel_use = FALSE;
	}
}


/************************************************************
*  Routine Name: use_cb 
*
*      Purpose:   Callback for the Use widget
*
*        Input:  widget - the widget corresponding to the
*                         particular selection's background widget
*
*                clientData - structure used by the client (xvforms)
*		 event	    - event struct that triggered callback
*
*
*   Written By: Danielle Argiro, Mark Young, Mike Lang 
*
*
*************************************************************/

void use_cb(widget, clientData, event)
Widget widget;
caddr_t clientData;
XEvent  *event;
{
	/*
	 * inquire what current perspective is on diagram
	 */
	if (gwin != NULL)
	
	{ 
	    X3D_inquire_viewpoint (diag_id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist); 
	    X3D_inquire_view_distance (diag_id, &gwin_attr->view_dist);
	    /*
	     * set perspective on plots to match the diagram
	     */
	    X3D_set_viewpoint (gwin->id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
            X3D_set_view_distance (gwin->id, gwin_attr->view_dist);

	    /*
	     * redisplay plots in new perspective
	     */
            plot_routine();
	    last_sel_use = TRUE;

	}
}



/************************************************************
*  Routine Name: exit_cb 
*
*      Purpose:   Callback for the Use widget
*
*        Input:  widget - the widget corresponding to the
*                         particular selection's background widget
*
*                clientData - structure used by the client (xvforms)
*		 event	    - event struct that triggered callback
*
*
*   Written By: Danielle Argiro, Mark Young, Mike Lang 
*
*
*************************************************************/

void exit_cb(widget, clientData, event)
Widget widget;
caddr_t clientData;
XEvent  *event;
{

	/*
	 *  If their last selection was not "Use", need to re-display
	 *  the plot (in its old perspective), inquire what the old perspective
	 *  was and restore it to the axes diagram.  Also inform the user
	 *  of what's going on and what the old perspective was
	 */ 
	XtUnmapWidget(*persp_toplevel);
	if ((last_sel_use != TRUE) && (gwin != NULL))
	{
	   plot_routine();
	   X3D_inquire_viewpoint(gwin->id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist);
	   X3D_inquire_view_distance(gwin->id, &gwin_attr->view_dist);
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
           X3D_set_view_distance(diag_id, gwin_attr->view_dist);

	}

}

/************************************************************
*
* Routine Name:  persp_incr_cb
*
*      Purpose:  This is the callback for the perspective selections' 
*		 scroll bars when they are used incrementally.
*
*        Input:  widget - the widget corresponding to the 
*			  particular selection's background widget
*
*	         clientData - structure used by the client (xvforms)
*		 callData -  structure used by the X toolkit  (?)
*
*
*   Written By: Danielle Argiro
*
*************************************************************/

void persp_incr_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
   int movement, status, signif_digits;
   Scroll_Data *scroll_data;
   char temp[50], scale[50];
   XawTextBlock text_block;
   float percent;

   movement = (int) callData;
   scroll_data = (Scroll_Data *) clientData;

  /* get the current perspective settings */
   X3D_inquire_viewpoint (diag_id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist);
   X3D_inquire_view_distance (diag_id, &gwin_attr->view_dist);

   sprintf(temp, "%f", scroll_data->float_value);

   if ((scroll_data->float_value > scroll_data->float_max) ||
      (scroll_data->float_value < scroll_data->float_min))  return;

   if (movement > 0)
   {
      scroll_data->float_value -= scroll_data->increment;
      if (scroll_data->float_value < scroll_data->float_min)
           scroll_data->float_value = scroll_data->float_min;
 
      if (scroll_data->flag == RotateX)
      {
           gwin_attr->alpha = scroll_data->float_value;
           if (((int)gwin_attr->alpha) <= 0) gwin_attr->alpha += 360;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == RotateZ)
      {
           gwin_attr->theta = scroll_data->float_value;
           if (((int)gwin_attr->theta) <= 0) gwin_attr->theta += 360;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == Camera)
      {
	   gwin_attr->eye_dist = scroll_data->float_value;
	   if ((int)gwin_attr->eye_dist < 0) gwin_attr->eye_dist = 0;
	   else if ((int)gwin_attr->eye_dist > 100) gwin_attr->eye_dist = 100;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == Zoom)
      {
	   gwin_attr->view_dist = scroll_data->float_value;
	   if ((int)gwin_attr->view_dist < 0) gwin_attr->view_dist = 0;
	   else if ((int)gwin_attr->view_dist > 100) gwin_attr->view_dist = 100;
           X3D_set_view_distance (diag_id, gwin_attr->view_dist);
      }
   }
   else if (movement < 0)
   {
      scroll_data->float_value += scroll_data->increment;
      if (scroll_data->float_value > scroll_data->float_max)
           scroll_data->float_value = scroll_data->float_max;

      if (scroll_data->flag == RotateX)
      {
           gwin_attr->alpha = scroll_data->float_value;
           if (((int)gwin_attr->alpha) >= 360) gwin_attr->alpha = 360 - gwin_attr->alpha;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == RotateZ)
      {
           gwin_attr->theta = scroll_data->float_value;
           if (((int)gwin_attr->theta) >= 360) gwin_attr->theta = 360 - gwin_attr->theta;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == Camera)
      {
	    gwin_attr->eye_dist = scroll_data->float_value;
	    if ((int)gwin_attr->eye_dist < 0) gwin_attr->eye_dist = 0;
	    else if ((int)gwin_attr->eye_dist > 100) gwin_attr->eye_dist = 100;
            X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
      }
      else if (scroll_data->flag == Zoom)
      {
	    gwin_attr->view_dist = scroll_data->float_value;
	    if ((int)gwin_attr->view_dist < 0) gwin_attr->view_dist = 0;
	    else if ((int)gwin_attr->view_dist > 100) gwin_attr->view_dist = 100;
            X3D_set_view_distance (diag_id, gwin_attr->view_dist);
      }
   }

   
   signif_digits = xvf_def_number_sign_digits(scroll_data->float_max
					      - scroll_data->float_min, "0.0");
   sprintf(scale, "%%.%df", signif_digits);
   sprintf(temp,scale, scroll_data->float_value);

   text_block.firstPos = 0;
   text_block.length = xvf_strlen(temp);
   text_block.ptr = temp;
   text_block.format = FMT8BIT;

   status = XawTextReplace(*scroll_data->val_widget, (XawTextPosition)0,
                         (XawTextPosition)(10),
                         &text_block);
   XawTextDisplay(*scroll_data->val_widget);

   if (status == XawPositionError)
   {
        fprintf(stderr, "\nxvf_float_incr_scroll_cb:\n");
        fprintf(stderr,"    position error\n");
   }
   else if (status == XawEditError)
   {
        fprintf(stderr, "\nxvf_float_incr_scroll_cb:\n");
        fprintf(stderr,"    edit error\n");
   }

   percent = (scroll_data->float_value - scroll_data->float_min)/
             (scroll_data->float_max - scroll_data->float_min);
   XawScrollbarSetThumb(*scroll_data->scroll_widget, percent, 1.0);

   /* update the perspective */
	
   if (gwin != NULL)
   {
            /* display axes diagram and legend */
            X3D_clear_window(diag_id);
            draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
            last_sel_use = FALSE;
  }

}


/************************************************************
*
* Routine Name:  persp_flow_cb
*
*      Purpose:  This is the callback for the perspective selections' 
*		 scroll bars when they are used smoothly.
*
*        Input:  widget - the widget corresponding to the 
*			  particular selection's background widget
*
*	         clientData - structure used by the client (xvforms)
*		 callData -  structure used by the X toolkit  (?)
*
*
*   Written By: Danielle Argiro
*
*************************************************************/

void persp_flow_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
   Scroll_Data *scroll_data;
   char  *mesg;
   float *movement;

   movement = (float *) callData;
   scroll_data = (Scroll_Data *) clientData;

  /* get the current perspective settings */
   X3D_inquire_viewpoint (diag_id, &gwin_attr->alpha, &gwin_attr->theta, &gwin_attr->eye_dist);
   X3D_inquire_view_distance (diag_id, &gwin_attr->view_dist);
   
   scroll_data->float_value = *movement * 
			    (scroll_data->float_max-scroll_data->float_min) +
			    scroll_data->float_min;

   if (scroll_data->flag == RotateX)
   {
       gwin_attr->alpha = scroll_data->float_value;
       if (((int)gwin_attr->alpha) <= 0) gwin_attr->alpha += 360;
       if (((int)gwin_attr->alpha) >= 360) gwin_attr->alpha = 360 - gwin_attr->alpha;
       X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
   }
   else if (scroll_data->flag == RotateZ)
   {
       gwin_attr->theta = scroll_data->float_value;
       if (((int)gwin_attr->theta) <= 0) gwin_attr->theta += 360;
       if (((int)gwin_attr->theta) >= 360) gwin_attr->theta = 360 - gwin_attr->theta;
       X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
   }
   else if (scroll_data->flag == Camera)
   {
       if ((scroll_data->float_value <= 100) && 
	   (scroll_data->float_value >= 0))
       {
	   gwin_attr->eye_dist =  scroll_data->float_value;
           X3D_set_viewpoint (diag_id, gwin_attr->alpha, gwin_attr->theta, gwin_attr->eye_dist);
       }
       else 
       {
	   mesg = xvf_strcpy("Eye distance must be between 0 and 100\n");
	   xvf_error_wait(mesg, "persp_flow_cb", NULL);
           free(mesg);
           return;
       }
   }
   else if (scroll_data->flag == Zoom)
   {
       if ((scroll_data->float_value <= 100) && 
	   (scroll_data->float_value >= 0))
       {
	   gwin_attr->view_dist =  scroll_data->float_value;
   	   X3D_set_view_distance (diag_id, gwin_attr->view_dist);
       }
       else 
       {
	   mesg = xvf_strcpy("View distance must be between 0 and 100\n");
	   xvf_error_wait(mesg, "persp_flow_cb", NULL);
           free(mesg);
           return;
       }
   }

   persp_update_val_widget(scroll_data);

   if (gwin != NULL)
   {
            /* display axes diagram and legend */
            X3D_clear_window(diag_id);
            draw_axes_diag(diag_id, arrow_x, arrow_y, arrow_z);
            last_sel_use = FALSE;
    }
}

/************************************************************
*
* Routine Name:  persp_update_val_widget
*
*      Purpose:  This is a helper routine to update the value
*		 displayed in the value widget that is paired with
*		 a scroll bar.
*
*	Input:   scroll_data  - pointer to the scroll data
*
*      Output:	 new value displayed in the value widget
*
*   Written By:  Danielle Argiro
*
***************************************************************/


persp_update_val_widget(scroll_data)
Scroll_Data *scroll_data;
{
   int signif_digits, status;
   char temp[50], scale[50];
   XawTextBlock text_block;
   
   signif_digits = xvf_def_number_sign_digits(scroll_data->float_max
					      - scroll_data->float_min, "0.0");
   sprintf(scale, "%%.%df", signif_digits);
   sprintf(temp,scale, scroll_data->float_value);

   text_block.firstPos = 0;
   text_block.length = xvf_strlen(temp);
   text_block.ptr = temp;
   text_block.format = FMT8BIT;

   status = XawTextReplace(*scroll_data->val_widget, (XawTextPosition)0,
                         (XawTextPosition)(10),
                         &text_block);
   XawTextDisplay(*scroll_data->val_widget);

   if (status == XawPositionError)
   {
        fprintf(stderr, "\nxvf_float_incr_scroll_cb:\n");
        fprintf(stderr,"    position error\n");
   }
   else if (status == XawEditError)
   {
        fprintf(stderr, "\nxvf_float_incr_scroll_cb:\n");
        fprintf(stderr,"    edit error\n");
   }

}

