/* most of these simple Motif routines are based on the ones in
"Power Programming... MOTIF" by Eric F. Johnson and Kevin Reichard */

#include  <X11/Intrinsic.h>
#include  <X11/StringDefs.h>
#include  <Xm/Xm.h>
#include  <Xm/RowColumn.h>
#include  <Xm/CascadeB.h>
#include  <Xm/PushB.h>
#include  <Xm/Separator.h>
#include  <Xm/List.h>
#include  <Xm/MessageB.h>
#include  <Xm/SelectioB.h>
#include  <Xm/Label.h>
#include  <Xm/PushBG.h>
#include  <Xm/SeparatoG.h>
#include  <Xm/ToggleB.h> 

#include "motif.h"

#ifdef __STDC__
static void really_quit( Widget, caddr_t, caddr_t );
static void present_help( Widget, caddr_t, caddr_t );
#else
static void really_quit();
static void present_help();
#endif

/*
 *      Str2XmString() converts a standard C-style
 *      null-terminated string into a Motif-style
 *      compound string. Newline characters (\n)
 *      in the C string become separators in the
 *      Motif string, because we use
 *      XmStringLtoRCreate().
 */

XmString Str2XmString( string )
     char    *string;
{    
  XmString        motif_string;
  motif_string = XmStringCreateLtoR( string, XmSTRING_DEFAULT_CHARSET );
  return( motif_string );
}   


/*
 *      Creates a simple pull-down menu.
 *      Uses as few hard-coded resources
 *      as possible.
 */
Widget simple_menu( menu_bar, name, mnemonic )
     Widget  menu_bar;       /* parent */
     char    *name;
     int     mnemonic;
{
  Widget  cascade_button;
  Widget  menu_widget;
  Arg     args[1];
  char    new_name[ 400 ];

  XtSetArg( args[0], XmNmnemonic, mnemonic ); 
  cascade_button = XmCreateCascadeButton( menu_bar, name, args, 1 );
  XtManageChild( cascade_button );
  
  /*
   * Check if Help, if so then
   * set up this widget for the
   * menu bar's help.
   */
  if ( strcmp( name, "Help" ) == 0 ) {
    XtSetArg( args[0], XmNmenuHelpWidget, cascade_button );
    XtSetValues( menu_bar, args, 1 );
  }
  
  /*
   * Create a new name for the
   * actual menu.
   */
  strcpy( new_name, name );
  strcat( new_name, "Menu" );
  
  menu_widget = XmCreatePulldownMenu( menu_bar, new_name, args, 0 );
  XtSetArg( args[0], XmNsubMenuId, menu_widget );
  XtSetValues( cascade_button, args, 1 );
  return( menu_widget );
}       /* simple_menu */


/*
 * Creates a push button gadget and optionally
 * a separator gadget (if NeedsSeparator == True)
 * to add to a simple menu.
 */
Widget simple_menu_item( menu_widget, name, mnemonic, NeedsSeparator )
     Widget  menu_widget;
     char    *name;
     int     mnemonic;
     Boolean NeedsSeparator; /* == True if you want a leading separator */
{
  Widget  widget, sep;
  Arg     args[1];
  
  if ( NeedsSeparator == True ) {
    sep = XmCreateSeparatorGadget( menu_widget, "sep", NULL, 0 );
    XtManageChild( sep );
  }
  
  XtSetArg( args[0], XmNmnemonic, mnemonic ); 
  widget = XmCreatePushButton( menu_widget, name, args, 1 );
  XtManageChild( widget );
  return( widget );
}       /* simple_menu_item */



/*
 * Creates a push button gadget and optionally
 * a separator gadget (if NeedsSeparator == True),
 * using simple_menu_item(). Then, this routine
 * adds in a callback function for the menu choice.
 */
Widget simple_menu_call( menu_widget, name, mnemonic, NeedsSeparator, callback )
     Widget  menu_widget;
     char    *name;
     int     mnemonic;
     Boolean NeedsSeparator; /* == True if you want a leading separator */
     void    (*callback)();
{
  Widget  widget;
  
  widget = simple_menu_item( menu_widget, name, 
			    mnemonic, NeedsSeparator );
  
  XtAddCallback( widget,
                XmNactivateCallback,
                callback, NULL );
  
  return( widget );
}       /* simple_menu_call */


/*
 *      CreateHelpWidget() takes a parent (menu bar)
 *      widget and a help message (C text string) and
 *      then creates a help widget and button in the
 *      given menu bar.
 */

Widget CreateHelpWidget( parent, message )
Widget  parent;
char    message[];
{
  Widget  help_widget;
  Arg     args[ 1 ];

  /*
   * Set Meta-H as a short-cut for calling
   * up help.
   */
  XtSetArg( args[0], XmNmnemonic, 'H' );
  help_widget = XmCreateCascadeButton( parent, "Help", args, 1);
  XtManageChild( help_widget );

  /*
   * Add a help call-back,
   * to pop up help on cue.
   */
  XtAddCallback( help_widget,
                XmNactivateCallback,
                present_help,
                message );
  
  
  /*
   * Set our help widget as the
   * default Motif help widget
   */     
  XtSetArg( args[0], XmNmenuHelpWidget, help_widget );
  XtSetValues( parent, args, 1 );
  return( help_widget );
}


/*
 *      quit_callback() is called when the user
 *      chooses a quit choice.  It creates 
 *      and pops up a Dialog widget to
 *      ask the user "Are you sure?".
 */

void quit_callback( widget, client_data, call_data )
     Widget  widget;
     caddr_t client_data;
     caddr_t call_data;
{
  Widget  quit_dialog; 
  
  quit_dialog = WarningDialog( widget, 
			      "QUIT",
			      "Are you sure you\n want to quit?",
			      really_quit );  /* callback function */
  
}       /* quit_callback */

/*
 *      really_quit() quits a Motif program.
 */

static void really_quit( widget, client_data, call_data )
     Widget  widget;
     caddr_t client_data;
     caddr_t call_data;
{
  XtCloseDisplay( XtDisplay( widget ) );
  exit( 0 );
}       /* really_quit */


/*
 *      CreateQuitButton() creates a quit button
 *      as a menu choice on a Motif menu bar.
 */

Widget CreateQuitButton( parent )
     Widget  parent;
{
  Widget  quit_widget;
  Arg     args[ 1 ];
  
  /*
   * Create a quit button. Meta-Q
   * will also call the quit button.
   */
  XtSetArg( args[0], XmNmnemonic, 'Q' ); 
  
  quit_widget = XmCreateCascadeButton( parent, "Quit", args, 1 );  
  XtManageChild( quit_widget );
  
  XtAddCallback( quit_widget,
                XmNactivateCallback,
                quit_callback,  /* callback function */
                NULL ); 
  
  return( quit_widget );
  
}       /* -- CreateQuitButton */


Widget CreatePulldownMenu( parent, name_on_bar, title, mnemonic )
     Widget  parent;
     char    name_on_bar[];
     char    title[];
     int     mnemonic;
{
  Widget  cascade_widget, menu_widget;
  Arg     args[ 1 ];
  char    new_name[ 256 ];

  XtSetArg( args[0], XmNmnemonic, mnemonic ); 
  cascade_widget = XmCreateCascadeButton( parent,
					 name_on_bar, 
					 args,
					 1 );
        
  XtManageChild( cascade_widget );

  /*
   * Create the menu
   */
  strcpy( new_name, title );
  strcat( new_name, "-menu" );
  
  menu_widget = XmCreatePulldownMenu( parent,
				     new_name,
				     NULL, 
				     0 );
  
  /*
   * Fill in a title in the menu
   */
  CreateLabelWidget( menu_widget, title, title, args, 0 );


  /*
   * Add in a separator
   */
  XtCreateManagedWidget( "sep",
			xmSeparatorWidgetClass,
			menu_widget,
			NULL, 
			0 );

  /*
   * Set up button on menu bar to
   * pull down our menu.
   */
  XtSetArg( args[0], XmNsubMenuId, menu_widget );
  XtSetValues( cascade_widget, args, 1 );
  return( menu_widget );
  
}       /* CreatePulldownMenu */


Widget FillMenu( menu_widget, name, callback_func )
Widget  menu_widget;
char    name[];
void    (*callback_func)();

{
        Widget  menu_item;

        menu_item = XtCreateManagedWidget( name,
                        xmPushButtonWidgetClass,
                        menu_widget,
                        NULL,
                        0 );

        XtAddCallback( menu_item,
                XmNactivateCallback,
                callback_func,
                name );

        return( menu_item );
                        
}       /* FillMenu */

/*
 *      AddToList() adds a text string to a list
 *      widget at a given position in the list.
 */

void AddToList( widget, string, position )
Widget  widget;
char    string[];
int     position;
{
  XmString        motif_string;
  
  motif_string = XmStringCreateSimple( string );  
  XmListAddItemUnselected( widget, motif_string, position );
  XmStringFree( motif_string );
}       /* AddToList */

/*
 *      Creates a scrolled list widget.
 */

Widget CreateScrolledList( parent, name, args, n, list_callback )
     Widget  parent;
     char    name[];
     Arg     *args;
     int     n;
     void    (*list_callback)();     /* call back function */
{
  Widget  list_widget;
  
  /*
   * Set up size. Note that
   * n is passed as a parameter to
   * CreateScrolledList().
   */
  XtSetArg( args[n], XmNitemCount, 0 ); n++;
  XtSetArg( args[n], XmNselectionPolicy, XmSINGLE_SELECT ); n++; 
  
  list_widget = XmCreateScrolledList( parent, name, args, n );
  XtManageChild( list_widget );
  
  XtAddCallback( list_widget,
                XmNsingleSelectionCallback,
                list_callback,
                NULL );
  
  return( list_widget );
}       /* CreateScrolledList */

/*
 *      ErrorDialog() creates an XmErrorDialog
 *      widget.  This widget has no callback set up.
 *      We use this widget to present a simple error
 *      message (with no hope of un-doing the error).
 *
 *      parent = parent widget
 *      name = name of the ErrorDialog widget
 *      message = text string to be displayed.
 */

Widget ErrorDialog( parent, name, message )
Widget  parent;
char    name[];
char    message[];
{
  Arg             args[1];
  Widget          widget;
  XmString        motif_string;
  
  motif_string = Str2XmString( message );
  XtSetArg( args[0], XmNmessageString, motif_string );
  widget = XmCreateErrorDialog( parent,
                    name,
                    args,
                    1 );
  /*
   * Get rid of "Help"
   * push button.
   */
  RemoveDialButton( widget, XmDIALOG_HELP_BUTTON );
  RemoveDialButton( widget, XmDIALOG_CANCEL_BUTTON );
  
  XtManageChild( widget );
  
  XmStringFree( motif_string );
  return( widget );
}       /* ErrorDialog */

/*
 *      present_help() creates 
 *      a help_widget.
 */

static void present_help( widget, client_data, call_data )
Widget  widget;
caddr_t client_data;
caddr_t call_data;
{
        Widget  help_widget, SetUpHelp();

        help_widget = SetUpHelp( widget,
                         "Application Help",    /* name */
                         client_data );         /* message */
        
}       /* present_help */


/*
 *      SetUpHelp creates a dialog
 *      widget with your help message.
 */

Widget SetUpHelp( parent, name, message )
Widget          parent;
char            name[];
char            message[];
{
  Arg             args[1];
  Widget          help_widget;
  XmString        motif_string;
  
  motif_string = Str2XmString( message );
  
  XtSetArg( args[0], XmNmessageString, motif_string ); 
  help_widget = XmCreateInformationDialog( parent,
					  name,
					  args,
					  1 );  
  /*
   * Normally, an Information dialog
   * has three buttons: OK, Cancel
   * and Help.  Since this is the
   * help dialog, we get rid of the
   * Cancel and Help buttons, by
   * making them unmanageable.
   */
  RemoveDialButton( help_widget, XmDIALOG_CANCEL_BUTTON );
  
  RemoveDialButton( help_widget, XmDIALOG_HELP_BUTTON );
  
  XtManageChild( help_widget );
  XmStringFree( motif_string );
  return( help_widget );
  
}       /* SetUphelp */


/*
 *      Removes (unmanages) the "Help"
 *      push button from a Motif
 *      dialog widget, or other buttons.
 *      which_button should be one of:
 *              XmDIALOG_CANCEL_BUTTON
 *              XmDIALOG_OK_BUTTON
 *              XmDIALOG_HELP_BUTTON
 */

void RemoveDialButton( widget, which_button )
     Widget  widget;
     int     which_button;
{
  Widget  dead_widget;

  /*
   * Normally, an Information dialog
   * has three buttons: OK, Cancel
   * and Help.  Here, we get rid of
   * a button.
   */
  dead_widget = XmMessageBoxGetChild( widget, which_button );
  XtUnmanageChild( dead_widget );
  
}       /* RemoveDialButton */


/*
 *      PromptDialog() is a convenience routine used to
 *      create a Motif Prompt Dialog.
 */
Widget PromptDialog( parent, name, message, callback_func )
     Widget  parent;
     char    name[];
     char    message[];
     void    (*callback_func)();
{
  Arg             args[1];
  Widget          widget;
  XmString        motif_string;
  
  motif_string = Str2XmString( message );

  XtSetArg( args[0], XmNselectionLabelString, motif_string ); 
  widget = XmCreatePromptDialog( parent,
                        name,
                        args,
                        1 );

        /*
         * Set up callback for activation,
         * Just for OK button.
         */
  XtAddCallback( widget,
                XmNokCallback,
                callback_func,
                NULL );
  
  XtManageChild( widget );
  XmStringFree( motif_string );
  return( widget );
}       /* PromptDialog */


/*
 *      WarningDialog() creates a warning dialog widget.
 *      It has Ok and Cancel buttons.  callback_func()
 *      is called if Ok is pressed.
 */

Widget WarningDialog( parent, name, message, callback_func )
     Widget  parent;
     char    name[];
     char    message[];
     void    (*callback_func)();
{
  Arg             args[1];
  Widget          widget;
  XmString        motif_string;
  

  motif_string = Str2XmString( message );

  XtSetArg( args[0], XmNmessageString, motif_string ); 
  widget = XmCreateWarningDialog( parent,
				 name,
				 args,
				 1 );
  /*
   * Get rid of "Help"
   * push button.
   */
  RemoveDialButton( widget, XmDIALOG_HELP_BUTTON );
  
  /*
   * Set up callback on OK
   * button.
   */
  XtAddCallback( widget,
		XmNokCallback,
		callback_func,
		NULL );
  
  XtManageChild( widget );
  XmStringFree( motif_string );
  return( widget );
}       /* WarningDialog */

/*
 *      CreateLabelWidget() creates a simple Motif
 *      label widget, with the given parent, name
 *      and message.
 */

Widget CreateLabelWidget( parent, name, message, args, n )
     Widget  parent;
     char    name[];
     char    message[];
     Arg     *args;
     int     n;
{
  Widget          label_widget;
  XmString        label_text;
  
  label_text = XmStringCreateSimple( message );
  
  /*
   * Set label_text as text for a label widget.
   * Note that n already has a value when
   * passed to CreateLabelWidget(), so
   * we don't initialize n to zero here.
   */
  XtSetArg( args[n], XmNlabelString, label_text ); n++;
  
  /*
   * Create label widget
   */
  label_widget = XtCreateManagedWidget( name,
				       xmLabelWidgetClass,
				       parent,
				       args, 
				       n );
  
  XmStringFree( label_text );
  return( label_widget );
}       /* CreateLabelWidget */

/*
 *      Sets the given label widget to
 *      have the given string
 */
void SetLabel( widget, string )
Widget  widget;
char    string[];
{
  XmString        label_text;
  Arg             args[ 1 ];

  label_text = XmStringCreateSimple( string );

  /*
   * Set label_text as text for a label widget
   */
  XtSetArg( args[0], XmNlabelString, label_text );
  XtSetValues( widget, args, 1 );
  
  XmStringFree( label_text );
  
}

Widget CreatePushButton( parent, name, label, args, n, callback_func )
     Widget  parent;
     char    name[];
     char    label[];
     Arg     *args;
     int     n;
     void    (*callback_func)();
{
  Widget  push_widget;
  XmString motif_string;
  
  motif_string = XmStringCreateSimple(label);
  XtSetArg( args[n], XmNlabelString, motif_string ); n++;
  push_widget = XtCreateManagedWidget( name,
				      xmPushButtonWidgetClass,
				      parent, 
				      args,
				      n );
  
  XtAddCallback( push_widget,
                XmNactivateCallback,
                callback_func,
                NULL );
  
  XmStringFree(motif_string);
  return( push_widget );
  
}       /* function CreatePushButton */

Widget CreateSimpleButton( parent, label, callback_func, data )
     Widget  parent;
     char    label[];
     void    (*callback_func)();
     caddr_t data;
{
  Widget  push_widget;
  XmString motif_string;
  Arg args[1];
  
  motif_string = XmStringCreateSimple(label);
  XtSetArg( args[0], XmNlabelString, motif_string );
  push_widget = XtCreateManagedWidget( "simplePB",
				      xmPushButtonWidgetClass,
				      parent, 
				      args,
				      1 );
  
  XtAddCallback( push_widget,
                XmNactivateCallback,
                callback_func,
                data );
  
  XmStringFree(motif_string);
  return( push_widget );
  
}       

/*
 *      BulletinDefaultButton() sets the given bulletin board
 *      dialog to have the given push button as its default
 *      button (the one that is triggered when the user presses
 *      the Return key).
 */
void BulletinDefaultButton( bulletin, button )
Widget  bulletin;
Widget  button;
{
  Arg     args[1];
  
  XtSetArg( args[0], XmNdefaultButton, button ); 
  XtSetValues( bulletin, args, 1 );
}



/*
 *      Creates and manages a toggle button widget. The initial
 *      state of the toggle button is set to state. When the
 *      state changes, callback_func() will be called. The
 *      type specifies the radio button diamond XmONE_OF_MANY or the
 *      square XmN_OF_MANY shape for the toggle button. 
 */

Widget CreateToggle( parent, name, message, state, type, callback_func )
     Widget  parent;
     char    name[];
     char    message[];              /* text to appear next to toggle */
     Boolean state;                  /* initial state */
     int     type;                   /* XmN_OF_MANY or XmONE_OF_MANY */
     void    (*callback_func)();     /* state change callback */
{       
  Widget          toggle_widget;
  Arg             args[5];
  int             n=0;
  XmString        motif_string; 
  
  motif_string = XmStringCreateSimple( message );

  XtSetArg( args[n], XmNlabelString, motif_string ); n++;
  XtSetArg( args[n], XmNindicatorType, type ); n++;
  XtSetArg( args[n], XmNindicatorOn, True ); n++;
  XtSetArg( args[n], XmNset, state ); n++; /* on or off */

  toggle_widget = XmCreateToggleButton( parent, name, args, n );

  XtManageChild( toggle_widget );
  XtAddCallback( toggle_widget,
                XmNvalueChangedCallback,
                callback_func,
                NULL );
  
  XmStringFree( motif_string );
  return( toggle_widget );

}       /* CreateToggle */


Widget CreateSimpleToggle( parent, name, state, type, callback_func, data )
     Widget  parent;
     char    name[];
     Boolean state;                  /* initial state */
     int     type;                   /* XmN_OF_MANY or XmONE_OF_MANY */
     void    (*callback_func)();     /* state change callback */
     caddr_t data;
{ 
  Widget          toggle_widget;
  Arg             args[5];
  int             n=0;
  XmString        motif_string; 
  
  motif_string = XmStringCreateSimple( name );

  XtSetArg( args[n], XmNlabelString, motif_string ); n++;
  XtSetArg( args[n], XmNindicatorType, type ); n++;
  XtSetArg( args[n], XmNindicatorOn, True ); n++;
  XtSetArg( args[n], XmNset, state ); n++; /* on or off */

  toggle_widget = XmCreateToggleButton( parent, name, args, n );
  
  XtManageChild( toggle_widget );
  XtAddCallback( toggle_widget,
                XmNvalueChangedCallback,
                callback_func,
                data );

  XmStringFree( motif_string );
  return( toggle_widget );
} 

/*
 *      Sets the value of a toggle button to
 *      True of False, depending on the 
 *      value of state. If state != 0,
 *      then the toggle is set to True.
 *      If state == 0, then the toggle is
 *      set to False.
 */

void SetToggle( widget, state )
     Widget  widget;
     int     state;
{    
  Arg     args[1];
  Boolean on = True;
  
  if ( state == 0 ) 
    on = False;

  XtSetArg( args[0], XmNset, on ); 
  XtSetValues( widget, args, 1 );
}     


/*
 *      Creates a RowColumn widget to oversee a group
 *      of radio buttons.
 */

Widget CreateRadioBox( parent, name )
     Widget  parent;
     char    name[];
{
  Widget  radio;
  Arg     args[3];
  int     n=0;
  
  XtSetArg( args[n], XmNradioBehavior,  True ); n++;
  XtSetArg( args[n], XmNradioAlwaysOne, True ); n++;  
  radio = XmCreateRowColumn( parent, name, args, n );
  XtManageChild( radio );  
  return( radio );
} 











syntax highlighted by Code2HTML, v. 0.9.1