/************************************************************************/
/* Copyright 1993 MBARI							*/
/************************************************************************/
/* $Header: /usr/tiburon/unix/gui/proto/RCS/graphcall.c,v 1.1 1998/01/28 16:17:12 oreilly Exp $		*/
/* Summary  : Callbacks for Graph and Log module of ROV User Interface	*/
/* Filename : graphcall.c						*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : New ROV							*/
/* $Revision: 1.1 $							*/
/* Created  : 01/28/93							*/
/************************************************************************/
/* Modification History:						*/
/* $Log: graphcall.c,v $
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.0  95/09/20  14:23:06  14:23:06  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.7  94/03/21  14:15:20  14:15:20  hebo (Bob Herlien)
 * Misc bug fixes and enhancements
 * 
 * Revision 1.6  93/12/17  15:05:03  15:05:03  hebo (Bob Herlien)
 * December Wet Test
 * 
 * Revision 1.5  93/07/08  18:10:59  18:10:59  hebo (Bob Herlien)
 * Prior to Prototype Phase I testing
 * 
 * Revision 1.4  93/05/27  15:48:05  15:48:05  hebo (Bob Herlien)
 * Data Manager Interface
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include <sys/types.h>
#include <stdio.h>
#include <limits.h>
#include <time.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/DialogS.h>
#include <Xm/Label.h>
#include <Xm/TextF.h>
#include <Xm/Protocols.h>
#include <Xm/SelectioB.h>
#include <X11/Xc/Xc.h>
#include <X11/Xc/BarGraf.h>
#include </usr/tiburon/unix/gui/widgets/Xaw-5.00/X11/Xaw/StripChart.h>
#include "rov.h"
#include <datamgr.h>
#include "rdmif.h"
#include "graph.h"

#ifndef NO_PID
#define NO_PID		((Pid)0)
#endif
#ifndef CPU_LOCAL
#define CPU_LOCAL	((CPU_No)0)
#endif
#ifndef CPU_ANY
#define CPU_ANY		((CPU_No)1)
#endif


/********************************/
/*	External Functions	*/
/********************************/

Extern Void	XcBGUpdateValue( Widget w, XcVType *value );
Extern Int32	printType( DM_Type dtype, DM_Size size, char *dat, char *buff );
Extern GraphList *getGraphList( DM_Item item, DM_Size size, Nat32 ntypes );


/********************************/
/*	External Data		*/
/********************************/

Extern XtAppContext	appcontext;	/* The application context	*/
Extern Widget		topFormW;	/* Top-level form widget	*/
Extern Widget		dmFormW;	/* Form containing DM screen	*/
Extern char		buff[];		/* Misc buffer used application-wide*/
Extern GraphList	*curItem;	/* Current item displayed in DM screen*/
Extern LogItem		*loglist;	/* List of items being logged	*/
Extern char	 	*data_types[];	/* Names of data types		*/
Extern Widget		graphUBText, graphLBText;


/********************************/
/*	Module Local Data	*/
/********************************/

MLocal GraphList	*graphs = GL_NULL;
MLocal MBool		graphUpdate = FALSE;
MLocal Nat32		nextGraphPos = 0;
MLocal Widget		barGraphDialog;


/************************************************************************/
/* Function    : graphItemInUse						*/
/* Purpose     : Return Boolean to indicate if this module is using a DM_Item*/
/* Inputs      : DM_Item						*/
/* Outputs     : TRUE if this module is using item, else FALSE		*/
/************************************************************************/
     MBool
graphItemInUse( DM_Item item )
{
    Reg GraphList	*gp;
    Reg LogItem		*lp;

    if ( (curItem != GL_NULL) && (curItem->gl_item == item) )
	return( TRUE );
	
    for ( gp = graphs; gp != GL_NULL; gp = gp->gl_link )
	if ( gp->gl_item == item)
	    return( TRUE );

    for ( lp = loglist; lp != LI_NULL; lp = lp->log_link )
	if ( lp->log_dmitem == item)
	    return( TRUE );

    return( FALSE );

} /* graphItemInUse() */


/************************************************************************/
/* Function    : graphItemCnsmr						*/
/* Purpose     : Called whenever rest of GUI does a rdm_start_consumer()*/
/* Inputs      : DM_Item, Consumer period				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
graphItemCnsmr( DM_Item item, Nat32 period )
{
    Reg GraphList	*gp;
    Reg LogItem		*lp;

    if ( (curItem != GL_NULL) && (curItem->gl_item == item) )
	curItem->gl_gui_period = period;
	
    for ( gp = graphs; gp != GL_NULL; gp = gp->gl_link )
	if ( gp->gl_item == item)
	    gp->gl_gui_period = period;

    for ( lp = loglist; lp != LI_NULL; lp = lp->log_link )
	if ( lp->log_dmitem == item)
	    lp->log_gui_period = period;

} /* graphItemCnsmr() */


/************************************************************************/
/* Function    : graphDeleteCallback					*/
/* Purpose     : Callback when user deletes Graph Window		*/
/* Inputs      : Widget, GraphList ptr, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
graphDeleteCallback( Widget w, GraphList *gp, XmAnyCallbackStruct *cbs )
{
    Reg GraphList	*gp1;

    if ( graphs == gp )			/* Take gp off graphs list	*/
	graphs = gp->gl_link;
    else
	for ( gp1 = graphs; gp1 != GL_NULL; gp1 = gp1->gl_link )
	    if ( gp1->gl_link == gp )
	    {
		gp1->gl_link = gp->gl_link;
		break;
	    }

    freeGraphList( gp );		/* Free gp			*/

} /* graphDeleteCallback() */


/************************************************************************/
/* Function    : makeGraphDialog					*/
/* Purpose     : Make the MessageBox Dialog to hold a user-created graph*/
/* Inputs      : Boolean, restrict to elemental types			*/
/* Outputs     : Ptr to GraphList created				*/
/************************************************************************/
     GraphList *
makeGraphDialog( MBool elType )
{
    Widget	dialog;
    GraphList	*gp;

    if ( curItem == GL_NULL )
	return( GL_NULL );

    if (elType && 
	((curItem->gl_ntypes > 1) || (curItem->gl_types->te_type <= DM_EMPTY)))
	return( GL_NULL );

    if ( (gp = getGraphList(curItem->gl_item, curItem->gl_sts.is_size, 
			    curItem->gl_ntypes)) == GL_NULL )
	return( GL_NULL );

    dialog = XmCreateDialogShell( topFormW, gp->gl_sts.is_name,
				  (ArgList)NULL, 0);

    XtVaSetValues( dialog, XmNdeleteResponse, XmDESTROY,
		   XmNallowShellResize, True, XmNdefaultPosition, False, 
		   XmNx, nextGraphPos, XmNy, 550, NULL );

    nextGraphPos += 100;
    if ( nextGraphPos > 900 )
	nextGraphPos = 0;

    gp->gl_link = graphs;		/* Put gp on graphs list	*/
    graphs = gp;
    gp->gl_shell = dialog;		/* Store dialog shell widget	*/

    XtAddCallback( dialog, XmNdestroyCallback,
		   (XtCallbackProc)graphDeleteCallback, gp );

    return( gp );

} /* makeGraphDialog() */


/************************************************************************/
/* Function    : graphReadXcVType					*/
/* Purpose     : Read a DM Item in GraphList, return XcVType value	*/
/* Inputs      : GraphList ptr						*/
/* Outputs     : XcVType.lval value (Int32)				*/
/* Comment     : Assumes an elemental data type! (i.e., <= sizeof(Flt64))*/
/************************************************************************/
     Int32
graphReadXcVType( GraphList *gp )
{
    TypeUnion	dat;
    XcVType	bgdat;

    rdm_read( gp->gl_item, (char *)&dat, sizeof(TypeUnion) );

    switch( gp->gl_types->te_type )
    {
      case DM_CHAR:
	return( (Int32)dat.c );

      case DM_UCHAR:
	return( (Nat32)dat.c );

      case DM_INT16:
      case DM_MBOOL:
	return( (Int32)dat.int16 );
	    
      case DM_NAT16:
	return( (Nat32)dat.nat16 );
	    
      case DM_INT32:
      case DM_ENUM:
      case DM_NAT32:
      case DM_PTR:
	return( dat.int32 );

      case DM_FLT32:
	bgdat.fval = dat.flt32;
	return( bgdat.lval );

      case DM_FLT64:
	bgdat.fval = (Flt32)dat.flt64;
	return( bgdat.lval );

    } /* switch */

    return( TRUE );

} /* graphReadXcVType() */


/************************************************************************/
/* Function    : graphReadInt32						*/
/* Purpose     : Read a DM Item in GraphList, return Int32 value	*/
/* Inputs      : GraphList ptr						*/
/* Outputs     : Int32 result						*/
/* Comment     : Assumes an elemental data type! (i.e., <= sizeof(Flt64))*/
/************************************************************************/
     Int32
graphReadInt32( GraphList *gp )
{
    TypeUnion	dat;

    rdm_read( gp->gl_item, (char *)&dat, sizeof(TypeUnion) );

    switch( gp->gl_types->te_type )
    {
      case DM_CHAR:
	return( (Int32)dat.c );

      case DM_UCHAR:
	return( (Nat32)dat.c );

      case DM_INT16:
      case DM_MBOOL:
	return( (Int32)dat.int16 );
	    
      case DM_NAT16:
	return( (Nat32)dat.nat16 );
	    
      case DM_INT32:
      case DM_ENUM:
      case DM_NAT32:
      case DM_PTR:
	return( dat.int32 );

      case DM_FLT32:
	if ( (dat.flt32 < LONG_MAX) && (dat.flt32 > LONG_MIN) )
	    return( (Int32)dat.flt32 );
	else
	    return( 0 );

      case DM_FLT64:
	if ( (dat.flt32 < LONG_MAX) && (dat.flt32 > LONG_MIN) )
	    return( (Int32)dat.flt64 );
	else
	    return( 0 );

    } /* switch */

    return( 0 );

} /* graphReadInt32() */


/************************************************************************/
/* Function    : graphReadFlt64						*/
/* Purpose     : Read a DM Item in GraphList, return Flt64 value	*/
/* Inputs      : GraphList ptr						*/
/* Outputs     : Flt64 result						*/
/* Comment     : Assumes an elemental data type! (i.e., <= sizeof(Flt64))*/
/************************************************************************/
     Flt64
graphReadFlt64( GraphList *gp )
{
    TypeUnion	dat;

    rdm_read( gp->gl_item, (char *)&dat, sizeof(TypeUnion) );

    switch( gp->gl_types->te_type )
    {
      case DM_CHAR:
      case DM_UCHAR:
	return( (Flt64)dat.c );

      case DM_INT16:
      case DM_MBOOL:
	return( (Flt64)dat.int16 );
	    
      case DM_NAT16:
	return( (Flt64)dat.nat16 );
	    
      case DM_INT32:
	return( (Flt64)dat.int32 );

      case DM_ENUM:
      case DM_NAT32:
      case DM_PTR:
	return( (Flt64)dat.nat32 );

      case DM_FLT32:
	return( (Flt64)dat.flt32 );

      case DM_FLT64:
	return( dat.flt64 );

    } /* switch */

    return( (Flt64)0.0 );

} /* graphReadFlt64() */


/************************************************************************/
/* Function    : updateLabelGraph					*/
/* Purpose     : Callback to update a Label Graph			*/
/* Inputs      : GraphList ptr, XtIntervalId				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
updateLabelGraph( GraphList *gp, XtIntervalId *id )
{
    XmString		str;
    Reg Int32		i, n;
    Reg TypeEntry	*tp;

    rdm_read( gp->gl_item, gp->gl_data, gp->gl_sts.is_size );

    for ( i = n = 0, tp = gp->gl_types; i < gp->gl_ntypes; i++, tp++ )
    {
	n += printType( tp->te_type, tp->te_size,
		        gp->gl_data + tp->te_offset, &buff[n] );
	buff[n++] = '\n';
	buff[n] = '\0';
    }

    buff[--n] = '\0';
    str = XmStringCreateLtoR( buff, XmSTRING_DEFAULT_CHARSET );
    XtVaSetValues(gp->gl_widget, XmNlabelString, str, NULL );
    XmStringFree( str );

    gp->gl_tmoutid = XtAppAddTimeOut(appcontext, gp->gl_interval,
				     (XtTimerCallbackProc)updateLabelGraph, gp);

} /* updateLabelGraph() */


/************************************************************************/
/* Function    : makeLabelGraph						*/
/* Purpose     : Callback for PushButton to make a Label Graph		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
makeLabelGraph( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    Widget		rcW, typeW;
    Reg GraphList	*gp;
    XmString		str;
    Reg Nat32		i, n;

    if ( (gp = makeGraphDialog(FALSE)) == GL_NULL )
	return;

    rcW = XtVaCreateManagedWidget("LabelRC", xmRowColumnWidgetClass,
				  gp->gl_shell,
				  XmNorientation, XmHORIZONTAL,
				  XmNresizeWidth, True, NULL);

    gp->gl_widget = XmCreateLabel( rcW, "LabelValue", (ArgList)NULL, 0 );
    XtManageChild( gp->gl_widget );

    for ( i = n = 0; i < gp->gl_ntypes; i++ )
	n += sprintf( &buff[n], "%s\n", data_types[gp->gl_types[i].te_type] );

    buff[--n] = '\0';
    str = XmStringCreateLtoR( buff, XmSTRING_DEFAULT_CHARSET );
    typeW = XtVaCreateManagedWidget("LabelType", xmLabelWidgetClass, rcW,
				    XmNlabelString, str, NULL );
    XmStringFree( str );

    XtManageChild( gp->gl_shell );
    updateLabelGraph( gp, (XtIntervalId)0 );

} /* makeLabelGraph() */


/************************************************************************/
/* Function    : updateBarGraph						*/
/* Purpose     : Callback to update a BarGraph				*/
/* Inputs      : GraphList ptr, XtIntervalId				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
updateBarGraph( GraphList *gp, XtIntervalId *id )
{
    XcVType	bgdat;

    bgdat.lval = graphReadXcVType( gp );

    XcBGUpdateValue( gp->gl_widget, &bgdat );

    gp->gl_tmoutid = XtAppAddTimeOut( appcontext, gp->gl_interval, 
				     (XtTimerCallbackProc)updateBarGraph, gp );

} /* updateBarGraph() */


/************************************************************************/
/* Function    : makeBarGraph						*/
/* Purpose     : OK Callback from barGraphDialog			*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
makeBarGraph( Widget w, Widget ubTextF, XmSelectionBoxCallbackStruct *sbp )
{
    Reg GraphList	*gp;
    char		*p;
    XcVType		upbound, lobound;
    XcDType		dtype;

    if ( (gp = makeGraphDialog(TRUE)) == GL_NULL )
	return;

    upbound.fval = 100.;
    lobound.fval = 0.;
    p = XmTextFieldGetString( ubTextF );
    sscanf( p, "%f", &upbound.fval );
    XtFree( p );
    XmStringGetLtoR( sbp->value, XmSTRING_DEFAULT_CHARSET, &p );
    sscanf( p, "%f", &lobound.fval );
    XtFree( p );
    dtype = XcLval;

    switch( gp->gl_types->te_type )
    {
      case DM_FLT32:
      case DM_FLT64:
	dtype = XcFval;
	break;

      case DM_PTR:
	dtype = XcHval;
	/* Note fall-thru */

      default:
	upbound.lval = (Nat32)upbound.fval;
	lobound.lval = (Nat32)lobound.fval;
	break;
    }

    gp->gl_widget = XtVaCreateManagedWidget("BarGraph", xcBarGraphWidgetClass,
					    gp->gl_shell,
					    XcNdataType, dtype,
					    XcNdecimals, 
					      (upbound.fval < 100.) ? 1 : 0,
					    XcNupperBound, upbound.lval,
					    XcNlowerBound, lobound.lval, 
					    XmNwidth, 70, XmNheight, 140,
					    NULL);

    XtManageChild( gp->gl_shell );
    updateBarGraph( gp, (XtIntervalId)0 );

} /* makeBarGraph() */


/************************************************************************/
/* Function    : barGraphCallback					*/
/* Purpose     : Callback for PushButton to make a BarGraph		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
barGraphCallback( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    XtManageChild( barGraphDialog );

} /* barGraphCallback() */


/************************************************************************/
/* Function    : updateStripChart					*/
/* Purpose     : Callback to update a StripChart			*/
/* Inputs      : GraphList ptr, ptr to Flt64 for result			*/
/* Outputs     : None							*/
/************************************************************************/
     Void
updateStripChart( Widget w, GraphList *gp, Flt64 *value )
{
    *value = graphReadFlt64( gp );

} /* updateStripChart() */


/************************************************************************/
/* Function    : makeStripChart						*/
/* Purpose     : Callback for PushButton to make a StripChart		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
makeStripChart( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    Reg GraphList	*gp;
    Int32		interval;

    if ( (gp = makeGraphDialog(TRUE)) == GL_NULL )
	return;

    interval = gp->gl_interval / 1000;

    if ( interval <= 0 )
	interval = 10;

    gp->gl_widget = XtVaCreateManagedWidget("StripChart", stripChartWidgetClass,
					    gp->gl_shell,
					    XtNupdate, interval,
					    XtNheight, 70, XtNwidth, 140,
					    XtNx, 0, XtNy, 35,
					    NULL);

    XtAddCallback( gp->gl_widget, XtNgetValue, 
		   (XtCallbackProc)updateStripChart, gp );

    XtManageChild( gp->gl_shell );

} /* makeStripChart() */


/************************************************************************/
/* Function    : updateInfoGraph					*/
/* Purpose     : Callback to update Info Dialog (dmShow info)		*/
/* Inputs      : GraphList ptr, XtIntervalId				*/
/* Outputs     : None							*/
/************************************************************************/
     Void
updateInfoGraph( GraphList *gp, XtIntervalId *id )
{
    Reg Int32		n, i, w;
    Reg TypeEntry	*tp;
    XmString		str;
    DM_Time		wtime;
    struct tm		*wtm;
    DmItemSts		connSts;

    rdm_item_status_free( &gp->gl_sts );
    rdm_item_status( gp->gl_item, &gp->gl_sts );
    rdm_readtm( gp->gl_item, gp->gl_data, gp->gl_sts.is_size, &wtime );

    n = sprintf( buff, "%s", gp->gl_sts.is_name );

    if ( gp->gl_sts.is_item_num > 0 )
	n += sprintf( &buff[n], "[%d]", gp->gl_sts.is_item_num );

    n += sprintf( &buff[n], "\nItem %#x  Type %s\n", 
		 gp->gl_item, data_types[gp->gl_sts.is_type] );

    if ( gp->gl_sts.is_connect_source != gp->gl_item )
    {
	rdm_item_status( gp->gl_sts.is_connect_source, &connSts );
	n += sprintf( &buff[n], "Connect head is %s", connSts.is_name );
	rdm_item_status_free( &connSts );
    }
    else if ( gp->gl_sts.is_prvdr == NO_PID )
	n += sprintf( &buff[n], "No Provider" );
    else
    {
	n += sprintf( &buff[n], "Provider: " );
	if ( gp->gl_sts.is_prvdr_cpu == CPU_LOCAL )
	    n += sprintf( &buff[n], "%#x", gp->gl_sts.is_prvdr );
	else if ( gp->gl_sts.is_prvdr_cpu == CPU_ANY )
	    n += sprintf( &buff[n], "MULTIPLE" );
	else
	    n += sprintf( &buff[n], "%s", inet_ntoa(gp->gl_sts.is_prvdr_cpu) );
    }

    n += sprintf( &buff[n], "\nPeriod %d  Size %d  Seq %d\nData =", 
		 gp->gl_sts.is_prvdr_period, gp->gl_sts.is_size,
		 gp->gl_sts.is_seq );

    for ( i = 0, w = n, tp = gp->gl_types; i < gp->gl_ntypes; i++, tp++ )
    {
	buff[n++] = ' ';
	n += printType( tp->te_type, tp->te_size,
		        gp->gl_data + tp->te_offset, &buff[n] );

	if ( n - w < 30 )
	    buff[n++] = ',';
	else
	{
	    buff[n++] = '\n';
	    w = n;
	}

	buff[n] = '\0';
    }

    buff[--n] = '\0';
    wtm = localtime( (time_t *)&wtime.tv_sec );
    sprintf( buff + n, "\nUpdate Time %02d:%02d:%02d.%06d", wtm->tm_hour,
	     wtm->tm_min, wtm->tm_sec, wtime.tv_usec );

    str = XmStringCreateLtoR( buff, XmSTRING_DEFAULT_CHARSET );
    XtVaSetValues(gp->gl_widget, XmNlabelString, str, NULL );
    XmStringFree( str );

    gp->gl_tmoutid = XtAppAddTimeOut(appcontext, gp->gl_interval,
				     (XtTimerCallbackProc)updateInfoGraph, gp);

} /* updateInfoGraph() */


/************************************************************************/
/* Function    : makeInfo						*/
/* Purpose     : Callback for PushButton to make a Info (dmShow) screen	*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
makeInfo( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    Reg GraphList	*gp;

    if ( (gp = makeGraphDialog(FALSE)) == GL_NULL )
	return;

    gp->gl_widget = XtVaCreateManagedWidget("Info", xmLabelWidgetClass, 
					    gp->gl_shell,
					    XmNalignment, XmALIGNMENT_BEGINNING,
					    NULL);
    XtManageChild( gp->gl_shell );

    updateInfoGraph( gp, (XtIntervalId)0 );

} /* makeInfo() */


/************************************************************************/
/* Function    : makeGraph						*/
/* Purpose     : Callback for PushButton to make a Graph		*/
/* Inputs      : Widget, Unused pointer, Unused callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
     Void
makeGraph( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    Reg GraphList	*gp;

    if ( (gp = makeGraphDialog(FALSE)) == GL_NULL )
	return;

    XtManageChild( gp->gl_shell );

} /* makeGraph() */


/************************************************************************/
/* Function    : initGraph						*/
/* Purpose     : Initialize function for Graph Module			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
    Void
initGraph( Void )
{
    XmString	str, str1;
    Widget	rc, tf;

    barGraphDialog = XmCreatePromptDialog(dmFormW, "BarGraphDialog", 
					  (ArgList)NULL, 0);

    str  = XmStringCreateSimple("Lower Bound");
    str1 = XmStringCreateSimple("0");

    XtVaSetValues( barGraphDialog, XmNselectionLabelString, str,
		   XmNtextString, str1, NULL );

    XmStringFree( str );
    XmStringFree( str1 );

    XtUnmanageChild(XmSelectionBoxGetChild(barGraphDialog, 
					   XmDIALOG_HELP_BUTTON));

    rc = XtVaCreateManagedWidget("barGraphRowCol", xmRowColumnWidgetClass,
				 barGraphDialog, NULL);

    str  = XmStringCreateSimple("Upper Bound");
    XtVaCreateManagedWidget("barGraphLabel", xmLabelWidgetClass, rc,
			    XmNlabelString, str, NULL);
    XmStringFree( str );

    tf = XtVaCreateManagedWidget("barGraphUBTextF", xmTextFieldWidgetClass,
				 rc, XmNvalue, "100", NULL);

    XtAddCallback(barGraphDialog, XmNokCallback, 
		  (XtCallbackProc)makeBarGraph, tf);

} /* initGraph() */
