/************************************************************************/
/* Copyright 1992 MBARI							*/
/************************************************************************/
/* $Header: /usr/tiburon/unix/gui/proto/RCS/rovcall.c,v 1.1 1998/01/28 16:17:12 oreilly Exp $		*/
/* Summary  : Callbacks for ROV User Interface				*/
/* Filename : rovcall.c							*/
/* Author   : Bob Herlien (rah)						*/
/* Project  : New ROV							*/
/* $Revision: 1.1 $							*/
/* Created  : 05/21/92							*/
/************************************************************************/
/* Modification History:						*/
/* $Log: rovcall.c,v $
 * Revision 1.1  1998/01/28 16:17:12  oreilly
 * Initial revision
 *
 * Revision 2.2  96/05/15  11:15:28  11:15:28  bobh (Bob Herlien)
 * Still supporting proto during final vehicle build
 * 
 * Revision 2.0  95/09/20  14:22:56  14:22:56  hebo (Bob Herlien)
 * Support for final vehicle integration.  AC, PDU micros.
 * 
 * Revision 1.8  94/08/19  17:20:17  17:20:17  hebo (Bob Herlien)
 * Interface to Unix version of Data Manager
 * 
 * Revision 1.7  94/03/21  14:15:10  14:15:10  hebo (Bob Herlien)
 * Misc bug fixes and enhancements
 * 
 * Revision 1.6  93/12/17  15:04:47  15:04:47  hebo (Bob Herlien)
 * December Wet Test
 * 
 * Revision 1.5  93/07/08  18:10:48  18:10:48  hebo (Bob Herlien)
 * Prior to Prototype Phase I testing
 * 
 * Revision 1.4  93/05/27  15:47:55  15:47:55  hebo (Bob Herlien)
 * Data Manager Interface
 * 
 * Revision 1.2  93/01/21  10:34:12  10:34:12  hebo (Bob Herlien)
 * Changes after Level 0
 * 
 * Revision 1.0  92/11/20  12:03:25  12:03:25  hebo (Bob Herlien)
 * Initial revision
 * 
*/
/************************************************************************/

#include <mbari/types.h>
#include <mbari/const.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/MessageB.h>
#include <X11/Xc/Xc.h>
#include <X11/Xc/BarGraf.h>
#include <X11/Xc/ToggleB.h>
#include <X11/mbari/Compass.h>
#include "rov.h"
#include "tiburon.h"
#include "rdmif.h"
#include <controlDM.h>
#include "trig.h"
#include <malloc.h>

#define DM_PEER_NAMESIZE	256


/********************************/
/*	External Functions	*/
/********************************/

Extern Void	initVehicle(Void);
Extern Void	initPower(Void);
Extern Void	initCamera(Void);
Extern Void	initIbc(Void);
Extern Void	initAlarm(Void);
Extern Void	termAlarm(Void);
Extern Void	initSetup(Void);
Extern Void	initGf(Void);
Extern Void	initDm(Void);
Extern Void	selectVehicle( Select *sp );
Extern Void	unselectVehicle( Select *sp );
Extern Void	selectCameraScreen( Select *sp );
Extern Void	unselectCameraScreen( Select *sp );
Extern Void	selectSetup( Select *sp );
Extern Void	unselectSetup( Select *sp );
Extern Void	selectGf( Select *sp );
Extern Void	unselectGf( Select *sp );
Extern Void	selectDM( Select *sp );
Extern Void	unselectDM( Select *sp );
Extern MBool	graphItemInUse( DM_Item item );


/****************************************/
/*	Forward Function Declarations	*/
/****************************************/

Void		updateCompass( rovItem *itm );
Void		updateBarGraph1000( rovItem *itm );
Void		updateAlive( rovItem *itm );
Void		updatePwrOk( rovItem *itm );


/********************************/
/*	External Data		*/
/********************************/

Extern XtAppContext appcontext;		/* The application context	*/
Extern AppData	appdata;		/* Application-wide resources	*/
Extern Widget	appForm;		/* Top-level application form	*/
Extern Widget	vehicleFormW;		/* App forms that go into appForm*/
Extern Widget	powerFormW;
Extern Widget	gfFormW;
Extern Widget	cameraFormW;
Extern Widget	setupFormW;
Extern Widget	instFormW;
Extern Widget	dconFormW;
Extern Widget	dmFormW;
Extern Widget	compass;		/* The compass display widget	*/
Extern Widget	headingLabel;		/* Compass heading text in degrees*/
Extern Widget	depthDrawingArea;
Extern Widget	thrustPowerBarGraph, lightPowerBarGraph;
Extern Widget	hotelPowerBarGraph, toolPowerBarGraph;
Extern Widget	thrustPowerLabel;
Extern char	buff[];			/* Misc buffer used application-wide*/

Extern SelectStatus	pwrSts, dconSts, cameraSts;


/********************************/
/*	Global Data		*/
/********************************/

Global SelectStatus	appSel;

Global Select vehicleSel =  { selectVehicle, unselectVehicle, &vehicleFormW,
			      &appSel, NULLSS, NULL, NULL };
Global Select powerSel   =  { NULLF, NULLF, &powerFormW, &appSel, &pwrSts, 
			      NULL, NULL };
Global Select cameraSel  =  { selectCameraScreen, unselectCameraScreen,
			      &cameraFormW, &appSel, &cameraSts, NULL, NULL };
Global Select dconSel     =  { NULLF, NULLF, &dconFormW, &appSel, &dconSts,
			      NULL, NULL };
Global Select setupSel   =  { selectSetup, unselectSetup, &setupFormW, 
			      &appSel, NULLSS, NULL, NULL };
Global Select instSel    =  { NULLF, NULLF, &instFormW, &appSel, NULLSS,
			      NULL, NULL };
Global Select gfSel      =  { selectGf, unselectGf, &gfFormW, &appSel, NULLSS,
			      NULL, NULL };
Global Select graphSel   =  { selectDM, unselectDM, &dmFormW, &appSel, 
			      NULLSS, NULL, NULL };

/********************************/
/*	Module Local Data	*/
/********************************/

MLocal Widget	quit_popup = (Widget)0;
MLocal Pixel	aliveOkColor, pwrOkColor;

MLocal rovItem		thrustPowerItem =
{ TIBURON_DM_PREFIX "POWER.THRUSTERS.PWR_ALLOC", DM_NAT16, 1, TRUE, NO_ITEM, 0,
  &thrustPowerBarGraph, updateBarGraph1000, 0 };

MLocal rovItem		thrustPwrOkItem =
{ TIBURON_DM_PREFIX "POWER.THRUSTERS.PWR_OK", DM_MBOOL, 1, TRUE, NO_ITEM, 0,
  &thrustPowerLabel, updatePwrOk, 0 };

MLocal rovItem		lightPowerItem =
{ TIBURON_DM_PREFIX "POWER.LIGHTS.PWR_ALLOC", DM_NAT16, 1, TRUE, NO_ITEM, 0,
  &lightPowerBarGraph, updateBarGraph1000, 0 };

MLocal rovItem		hotelPowerItem =
{ TIBURON_DM_PREFIX "POWER.HOTEL.PWR_ALLOC", DM_NAT16, 1, TRUE, NO_ITEM, 0,
  &hotelPowerBarGraph, updateBarGraph1000, 0 };

MLocal rovItem		toolPowerItem =
{ TIBURON_DM_PREFIX "POWER.TOOLS.PWR_ALLOC", DM_NAT16, 1, TRUE, NO_ITEM, 0,
  &toolPowerBarGraph, updateBarGraph1000, 0 };

MLocal rovItem		compassItem =
/* Note - SENSOR_HEADING_DM reflects Gyro only, so I'm using compass
{ SENSOR_HEADING_DM, DM_FLT32, 1, TRUE, NO_ITEM, 0, &compass,
  updateCompass, 0 };
*/
{ TIBURON_DM_PREFIX "SENSOR.COMPASS.DEGREES", DM_FLT32, 1, TRUE, NO_ITEM,
  0, &compass, updateCompass, 0 };

MLocal rovItem		vehicleAliveItem =
{ TIBURON_DM_PREFIX "VEHICLE.ALIVE", DM_MBOOL, 1, TRUE, NO_ITEM, TRUE, 
  &depthDrawingArea, updateAlive, 0 };

MLocal rovItem		*rovItems[] = 
{ &compassItem, &thrustPowerItem, &thrustPwrOkItem, &lightPowerItem, 
  &hotelPowerItem, &toolPowerItem, &vehicleAliveItem, NULLR
};

MLocal TimeoutStruct	rovTimeoutStruct = 
{ &appdata.vehicle_update, 0, rovItems, 0, "Main screen", NULLF };


/************************************************************************/
/* Function    : storeWidget						*/
/* Purpose     : Callback to save Widget ID				*/
/* Inputs      : Widget ID, Pointer to Global to store it in, calldata	*/
/* Outputs     : None							*/
/************************************************************************/
    Void
storeWidget(Widget w, Widget *where, XtPointer call)
{
    *where = w;

} /* storeWidget() */


/************************************************************************/
/* Function    : screenSelect						*/
/* Purpose     : Callback to select an application screen		*/
/* Inputs      : Widget ID, Ptr to Select struct, CallbackStruct	*/
/* Outputs     : None							*/
/* Comment     : You MUST call selectButtonCreateDefault for exactly one*/
/*		 select button of each group (common SelectStatus) in 	*/
/*		 order for the screenSelect function to work properly	*/
/************************************************************************/
    Void
screenSelect( Widget w, Select *sp, XmAnyCallbackStruct *call_data )
{
    Reg Select		*old, *nsp;		/* Previous, next select*/
    Reg SelectStatus	*ssp;

    old = sp->status->current;
    if ( sp == old )				/* If in context, return */
	return;

    for ( ssp = sp->status; ssp != NULLSS; ssp = nsp->subscreen )
    {
	nsp = ssp->current;	
	if ( nsp->unselect != NULLF )		/* Call unselect function*/
	    (*nsp->unselect)(nsp);		/* for each depth of screen*/
    }

    if ( *old->display != NULLW )
	XtUnmanageChild( *old->display );	/* Unmanage old screen form*/

    sp->status->current = sp;			/* Remember current screen*/

    if ( *sp->display != NULLW )
	XtManageChild( *sp->display );		/* Manage new screen form */

    for ( ssp = sp->status; ssp != NULLSS; ssp = nsp->subscreen )
    {
	nsp = ssp->current;	
	if ( nsp->select != NULLF )		/* Call select function for */
	    (*nsp->select)(nsp);		/* each depth of new screen */
    }

    XtVaSetValues( sp->status->last_button, 	/* Set button colors	*/
		   XmNbackground, sp->status->unselect_bg, 
		   XmNforeground, sp->status->unselect_fg, NULL );

    XtVaSetValues( w, XmNbackground, appdata.select_bg,
		      XmNforeground, appdata.select_fg, NULL );

    sp->status->last_button = w;

} /* screenSelect() */


/************************************************************************/
/* Function    : selectButtonCreateDefault				*/
/* Purpose     : Callback for creating the default select button of a set*/
/* Inputs      : Widget ID, client_data, call_data			*/
/* Outputs     : None							*/
/* Comment     : You MUST call this function for exactly one select button*/
/*		 of each group (common SelectStatus) in order for the	*/
/*		 screenSelect function to work properly			*/
/************************************************************************/
    Void
selectButtonCreateDefault( Widget w, Select *sp,
			   XmAnyCallbackStruct *call_data )
{
    sp->status->last_button = w;		/* Init default button	*/
    sp->status->current = sp;			/* Set current form	*/

    XtVaGetValues( w, XmNbackground, &sp->status->unselect_bg,
		      XmNforeground, &sp->status->unselect_fg, NULL );

    XtVaSetValues( w, XmNbackground, appdata.select_bg,
		      XmNforeground, appdata.select_fg, NULL );
    
} /* selectButtonCreateDefault() */


/************************************************************************/
/* Function    : getSelectedScreen					*/
/* Purpose     : Return Select Ptr for selected screen			*/
/* Inputs      : None							*/
/* Outputs     : Select ptr						*/
/************************************************************************/
     Select *
getSelectedScreen( Void )
{
    Reg SelectStatus	*ssp;
    Reg Select		*sp;

    for ( ssp = &appSel; ssp != NULLSS; ssp = sp->subscreen )
	sp = ssp->current;

    return( sp );

} /* getSelectedScreen() */


/************************************************************************/
/* Function    : startItems						*/
/* Purpose     : Start consuming DM Items				*/
/* Inputs      : Ptr to array of rovItems (NULL terminated), period, group*/
/* Outputs     : None							*/
/************************************************************************/
    Void
startItems( rovItem **ipp, TimeOut rate, DM_Group gid )
{
    Reg rovItem		*ip;

    for ( ; (ip = *ipp) != NULLR; ipp++ )
	if ( ip->dmitem != NO_ITEM )
	{
	    rdm_start_consumer( ip->dmitem, 1000 * rate, NULL );

	    if ( ip->update )
		(*ip->update)(ip);

	    if ( gid != NO_GROUP )
		rdm_group_add_item( gid, ip->dmitem, &ip->grpbit );
	}

} /* startItems() */


/************************************************************************/
/* Function    : stopItems						*/
/* Purpose     : Stop consuming DM Items				*/
/* Inputs      : Ptr to array of rovItems (NULL terminated)		*/
/* Outputs     : None							*/
/************************************************************************/
    Void
stopItems( rovItem **ipp, DM_Group gid )
{
    Reg rovItem		*ip;

    for ( ; (ip = *ipp) != NULLR; ipp++ )
	if ( ip->dmitem != NO_ITEM )
	{
	    if ( gid != NO_GROUP )
		rdm_group_delete_item( gid, ip->dmitem );

	    if ( (!ip->consume_always) && (!graphItemInUse(ip->dmitem)) )
		rdm_stop_consumer( ip->dmitem );
	}

} /* stopItems() */


/************************************************************************/
/* Function    : createItems						*/
/* Purpose     : Create DM Items					*/
/* Inputs      : Ptr to array of rovItems, ptr to TimeoutStruct		*/
/* Outputs     : None							*/
/* Comment     : Can be used to create only elemental types or arrays	*/
/************************************************************************/
    Void
createItems( rovItem **ipp, TimeoutStruct *tp )
{
    Reg rovItem		*ip;

    tp->grpId = rdm_create_group( tp->idStr );

    for ( ; (ip = *ipp) != NULLR; ipp++ )
	if ( ip->dmname != NULL )
	    rdm_create( ip->dmname, 1, &ip->dmitem, ip->dmtype, ip->dm_nels );

} /* createItems() */


/************************************************************************/
/* Function    : rovTimeoutProc						*/
/* Purpose     : Routine called to periodically update ROV screen	*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/* Comment     : Typically called at 5 Hz.  Be quick!			*/
/************************************************************************/
	Void
rovTimeoutProc( TimeoutStruct *tp, XtIntervalId *id )
{
    Reg rovItem		*ip, **ipp;
    Reg DWord		changes;

    if ( !rdm_exist() )
    {
	printf("Data Manager no longer exists!\n");
	exit( 1 );
    }

    changes = rdm_get_group_changes( tp->grpId );

    for ( ipp = tp->items; (ip = *ipp) != NULLR; ipp++ )
	if ( (changes & ip->grpbit) && (ip->update) )
	    (*ip->update)(ip);

    if ( tp->extraFunc != NULLF )
	(*tp->extraFunc)(tp);

    tp->tmoutId = XtAppAddTimeOut( appcontext, *tp->timeout,
				   (XtTimerCallbackProc)rovTimeoutProc, tp );

} /* rovTimeoutProc() */


/************************************************************************/
/* Function    : startTimeout						*/
/* Purpose     : Start rovTimeoutProc					*/
/* Inputs      : Ptr to TimeoutStruct					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
startTimeout( TimeoutStruct *tp )
{
    startItems( tp->items, *tp->timeout, tp->grpId );
    tp->tmoutId = XtAppAddTimeOut( appcontext, *tp->timeout,
				   (XtTimerCallbackProc)rovTimeoutProc, tp );

} /* startTimeout() */


/************************************************************************/
/* Function    : stopTimeout						*/
/* Purpose     : Stop rovTimeoutProc					*/
/* Inputs      : Ptr to TimeoutStruct					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
stopTimeout( TimeoutStruct *tp )
{
    XtRemoveTimeOut( tp->tmoutId );
    stopItems( tp->items, tp->grpId );

} /* stopTimeout() */


/************************************************************************/
/* Function    : initialize						*/
/* Purpose     : Init screen selection and callbacks			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
    Void
initialize( Void )
{
    Reg char	*p;
    char	nodename[DM_PEER_NAMESIZE];

    createItems( rovItems, &rovTimeoutStruct );

    initAlarm();
    initVehicle();
    initCamera();
    initPower();
    initIbc();
    initSetup();
    initGf();
    initDm();
    initGraph();

    XtVaGetValues( depthDrawingArea, XmNbackground, &aliveOkColor, NULL );
    XtVaGetValues( thrustPowerLabel, XmNbackground, &pwrOkColor, NULL );

    startTimeout( &rovTimeoutStruct );

    if ( vehicleSel.select != NULLF )
	(*vehicleSel.select)(&vehicleSel);	/* Call veh select func	*/

} /* initialize() */

#if ( PRINT_MALLOC_STATS )

/************************************************************************/
/* Function    : mallocInfo						*/
/* Purpose     : Print information about malloc()			*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/************************************************************************/
     Void
mallocInfo( Void )
{
    struct mallinfo	minfo;

    minfo = mallinfo();

    printf( "Total space in arena\t%d\n", minfo.arena );
    printf( "Number ordinary blocks\t%d\n", minfo.ordblks );
    printf( "Number small blocks\t%d\n", minfo.smblks );
    printf( "Space in holding block head\t%d\n", minfo.hblkhd );
    printf( "Number holding blocks\t%d\n", minfo.hblks );
    printf( "Space in used small blks\t%d\n", minfo.usmblks );
    printf( "Space in free small blks\t%d\n", minfo.fsmblks );
    printf( "Space in used ordinary blks\t%d\n", minfo.uordblks );
    printf( "Space in free ordinary blks\t%d\n", minfo.fordblks );
    printf( "Space penalty for KEEP option\t%d\n", minfo.keepcost );

} /* mallocInfo() */

#endif /* PRINT_MALLOC_STATS */


/************************************************************************/
/* Function    : terminate						*/
/* Purpose     : Terminate ROV User Interface				*/
/* Inputs      : None							*/
/* Outputs     : None							*/
/* Comments    : Never returns						*/
/************************************************************************/
     Void
terminate( Void )
{
    Reg SelectStatus	*ssp;
    Reg Select		*sp;

    for ( ssp = &appSel; ssp != NULLSS; ssp = sp->subscreen )
    {
	sp = ssp->current;
	if ( sp->unselect != NULLF )		/* Call unselect function*/
	    (sp->unselect)(sp);
    }

    termAlarm();
    stopItems( rovItems, rovTimeoutStruct.grpId );
    rdm_task_exit();
#if ( PRINT_MALLOC_STATS )
    mallocInfo();
#endif
    exit(0);

} /* terminate() */


/************************************************************************/
/* Function    : terminateCallback					*/
/* Purpose     : Callback for Close Window user action on Main window	*/
/* Inputs      : Widget, unused pointer, unused callback struct		*/
/* Outputs     : None							*/
/* Comments    : Never returns						*/
/************************************************************************/
     Void
terminateCallback( Widget w, XtPointer unused, XmAnyCallbackStruct *cbs )
{
    terminate();

} /* terminateCallback() */


/************************************************************************/
/* Function    : updateCompass						*/
/* Purpose     : Update Compass						*/
/* Inputs      : Pointer to compass rovItem				*/
/* Outputs     : None							*/
/* Comment     : Typically called at 5 Hz.  Be quick!			*/
/************************************************************************/
	Void
updateCompass( rovItem *ip )
{
    Flt32	heading;
    Int32	iheading;
    XmString	str;

    rdm_read(ip->dmitem, (char *)&heading, sizeof(heading) );

/*    iheading = (Int32) RADS_TO_DEGS(heading); */
    iheading = (Int32)heading;

    XtVaSetValues(*ip->widget, XtNheading, iheading, NULL);
    sprintf( buff, " %3d", iheading );
    str = XmStringCreateSimple( buff );
    XtVaSetValues( headingLabel, XmNlabelString, str, NULL );
    XmStringFree( str );
    ip->value = iheading;

} /* updateCompass() */


/************************************************************************/
/* Function    : updateBarGraph1000					*/
/* Purpose     : Callback for updating a Power BarGraph			*/
/* Inputs      : Pointer to rovItem					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
updateBarGraph1000( rovItem *ip )
{
    Nat16	nval;
    XcVType	vval;

    rdm_read( ip->dmitem, (char *)&nval, sizeof(Nat16) );
    if ( nval != ip->value )
    {
	vval.fval = ((float)nval)/1000.;
	XcBGUpdateValue( *ip->widget, &vval );
	ip->value = nval;
    }

} /* updateBarGraph1000() */


/************************************************************************/
/* Function    : updateToggle						*/
/* Purpose     : Update Function for a ToggleButton controlled by MBool	*/
/* Inputs      : Pointer to rovItem					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
updateToggle( rovItem *rp )
{
    MBool	state;
    
    rdm_read( rp->dmitem, (char *)&state, sizeof(MBool) );

    if ( state != rp->value )
	XcToggleSet( *rp->widget, state ? XcOn : XcOff );

    rp->value = state;

} /* updateToggle() */


/************************************************************************/
/* Function    : updateAlive						*/
/* Purpose     : Update Vehicle Alive Indicator				*/
/* Inputs      : Pointer to rovItem					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
updateAlive( rovItem *ip )
{
    MBool	state;

    rdm_read( ip->dmitem, (char *)&state, sizeof(MBool) );

    if ( state != ip->value )
    {
	if ( state )
	    XtVaSetValues( *ip->widget, XmNbackground, aliveOkColor, NULL );
	else
	    XtVaSetValues( *ip->widget, XmNbackground, appdata.stateBad, NULL );

	ip->value = state;
    }
} /* updateAlive() */


/************************************************************************/
/* Function    : updatePwrOk						*/
/* Purpose     : Update Thrust Power OK or limited indication		*/
/* Inputs      : Pointer to rovItem					*/
/* Outputs     : None							*/
/************************************************************************/
    Void
updatePwrOk( rovItem *ip )
{
    MBool	state;
    XmString	str;
    rdm_read( ip->dmitem, (char *)&state, sizeof(MBool) );

    if ( state != ip->value )
    {
	if ( state )
	{
	    str = XmStringCreateSimple("Thrust Power OK");
	    XtVaSetValues( *ip->widget, XmNbackground, pwrOkColor,
			   XmNlabelString, str, NULL );
	}
	else
	{
	    str = XmStringCreateSimple("Thrust Power Limited");
	    XtVaSetValues( *ip->widget, XmNbackground, appdata.pwrLimitColor,
			   XmNlabelString, str, NULL );
	}

	XmStringFree( str );
	ip->value = state;
    }

} /* updatePwrOk() */


/************************************************************************/
/* Function    : activateToggle						*/
/* Purpose     : Activate Callback for ROV ToggleButton			*/
/* Inputs      : Widget ID, rovItem ptr, callback struct		*/
/* Outputs     : None							*/
/************************************************************************/
    Void
activateToggle( Widget w, rovItem *rp, XmAnyCallbackStruct *cbs )
{
    XcToggleState	state;
    MBool		dmstate;

    XcToggleGet( w, &state );
    dmstate = (state == XcOn) ? TRUE : FALSE;
    rp->value = dmstate;

    rdm_write_once( rp->dmitem, (char *)&dmstate, sizeof(MBool) );

} /* activateToggle() */


/************************************************************************/
/* Function    : really_quit_callback					*/
/* Purpose     : Callback when user asks to exit ROV User Interface	*/
/* Inputs      : Widget ID, Client data pointer, CallbackStruct pointer	*/
/* Outputs     : None							*/
/************************************************************************/
    Void
really_quit_callback( Widget w, XtPointer client_data, 
		      XmAnyCallbackStruct *call_data )
{
    XtCloseDisplay(XtDisplay(w));
    terminate();

} /* really_quit_callback() */


/************************************************************************/
/* Function    : deleteWidget						*/
/* Purpose     : Callback to delete a widget				*/
/* Inputs      : Widget ID, Client data pointer, CallbackStruct pointer	*/
/* Outputs     : None							*/
/************************************************************************/
    Void
deleteWidget( Widget w, XtPointer unused, XmAnyCallbackStruct *call_data )
{
    XtDestroyWidget( w );

} /* deleteWidget() */


/************************************************************************/
/* Function    : rovError						*/
/* Purpose     : Create and pop up an Error dialog			*/
/* Inputs      : Parent, Message String					*/
/* Outputs     : Dialog Widget ID					*/
/************************************************************************/
	Widget
rovError( Widget parent, char *msg )
{
    Arg    	args[10];
    Cardinal   	argcnt;
    XmString	str;
    Widget	dialog;

    argcnt = 0;
    str = XmStringCreateLtoR( msg, XmSTRING_DEFAULT_CHARSET );
    XtSetArg(args[argcnt], XmNmessageString, str); argcnt++;

    dialog = XmCreateErrorDialog(parent, "rov_error", args, argcnt);

    XmStringFree( str );

    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtAddCallback( dialog, XmNokCallback, (XtCallbackProc)deleteWidget, NULL );
    XtManageChild( dialog );

    return( dialog );

} /* rovError() */


/************************************************************************/
/* Function    : rovMalloc						*/
/* Purpose     : Alloc memory, display error message if none		*/
/* Inputs      : Number of bytes to allocate				*/
/* Outputs     : Return code from malloc()				*/
/************************************************************************/
	char *
rovMalloc( Nat32 size )
{
    char	*rtn;

    if ( (rtn = malloc(size)) == NULL )
	rovError(appForm, "Out of memory\n");

    return( rtn );

} /* rovMalloc() */


/************************************************************************/
/* Function    : rovFree						*/
/* Purpose     : Free memory allocated by rovMalloc			*/
/* Inputs      : Ptr to memory						*/
/* Outputs     : None							*/
/************************************************************************/
	Void
rovFree( char *p )
{
    free( p );

} /* rovFree() */


/************************************************************************/
/* Function    : rovCreateQuestionDialog				*/
/* Purpose     : Create a question dialog without a Help Button		*/
/* Inputs      : Parent, Title String, Message String			*/
/* Outputs     : Dialog Widget ID					*/
/************************************************************************/
	Widget
rovCreateQuestionDialog( Widget parent, char *title, char *msg )
{
    Arg    	args[10];
    Cardinal   	argcnt;
    XmString	str, str1;
    Widget	dialog;

    argcnt = 0;
    str = XmStringCreateSimple( title );
    XtSetArg(args[argcnt], XmNdialogTitle, str); argcnt++;
    str1 = XmStringCreateLtoR( msg, XmSTRING_DEFAULT_CHARSET );
    XtSetArg(args[argcnt], XmNmessageString, str1); argcnt++;

    dialog = XmCreateQuestionDialog(parent, "question_popup", args, argcnt);

    XmStringFree( str );
    XmStringFree( str1 );

    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));

    return( dialog );

} /* rovCreateQuestionDialog() */


/************************************************************************/
/* Function    : quit_callback						*/
/* Purpose     : Exit ROV User Interface				*/
/* Inputs      : Widget ID, Client data pointer, CallbackStruct pointer	*/
/* Outputs     : None							*/
/************************************************************************/
    Void
quit_callback( Widget w, XtPointer client_data, XmAnyCallbackStruct *call_data )
{
    if (!quit_popup)
    {
	quit_popup = rovCreateQuestionDialog( appForm, "Confirm Quit",
					      "Really Quit?" );

	XtVaSetValues( quit_popup, XmNdialogStyle, 
		       XmDIALOG_PRIMARY_APPLICATION_MODAL, NULL );

	XtAddCallback( quit_popup, XmNokCallback, 
		       (XtCallbackProc)really_quit_callback, NULL);
    }

    XtVaSetValues( quit_popup, XmNdefaultButtonType, XmDIALOG_OK_BUTTON, NULL );
    XtManageChild( quit_popup );

} /* quit_callback() */


/************************************************************************/
/* Function    : printType						*/
/* Purpose     : Printf data of given type into buffer			*/
/* Inputs      : Type of data, Num elements (for character data only),	*/
/*		 Data to print, buffer to print into			*/
/* Outputs     : Number of characters printed				*/
/************************************************************************/
     Int32
printType( DM_Type dtype, Nat32 nels, char *dat, char *buff )
{
    TypeUnion	udat;
    Reg Int32	rtn, i;

    bzero( &udat, sizeof(udat) );
    bcopy( dat, &udat, sizeof(udat) );

    switch( dtype )
    {
      case DM_EMPTY:
	buff[0] = '\0';
	return( 0 );

      case DM_CHAR:
      case DM_UCHAR:
	for ( i = rtn = 0; i < nels; i++ )
	{
	    if ( dat[i] == '\0' )
		break;
	    if ( isprint(dat[i]) )
		buff[rtn++] = dat[i];
	    else
		rtn += sprintf( buff + rtn, "\\%x", (Nat32)dat[i] );
	}
	buff[rtn] = '\0';
	return( rtn );

      case DM_INT16:
      case DM_MBOOL:
	return( sprintf(buff, "%hd", udat.int16) );

      case DM_NAT16:
	return( sprintf(buff, "%hu", udat.nat16) );
	    
      case DM_INT32:
      case DM_ENUM:
	return( sprintf(buff, "%d", udat.int32) );

      case DM_NAT32:
	return( sprintf(buff, "%u", udat.nat32) );

      case DM_FLT32:
	return( sprintf(buff, "%g", udat.flt32) );

      case DM_FLT64:
	return( sprintf(buff, "%lg", udat.flt64) );

      case DM_PTR:
	return( sprintf(buff, "%#x", udat.ptr) );

    } /* switch */

} /* printType() */
