home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Toggle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-25  |  16.5 KB  |  604 lines

  1. /* $XConsortium: Toggle.c,v 1.24 91/07/25 14:07:48 converse Exp $ */
  2.  
  3. /*
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  */
  24.  
  25. /*
  26.  * Toggle.c - Toggle button widget
  27.  *
  28.  * Author: Chris D. Peterson
  29.  *         MIT X Consortium 
  30.  *         kit@expo.lcs.mit.edu
  31.  *  
  32.  * Date:   January 12, 1989
  33.  *
  34.  */
  35.  
  36. #include <stdio.h>
  37.  
  38. #include <X11/IntrinsicP.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/Xaw/XawInit.h>
  41. #include <X11/Xmu/Converters.h>
  42. #include <X11/Xmu/Misc.h>
  43. #include <X11/Xaw/ToggleP.h>
  44.  
  45. /****************************************************************
  46.  *
  47.  * Full class record constant
  48.  *
  49.  ****************************************************************/
  50.  
  51. /* Private Data */
  52.  
  53. /* 
  54.  * The order of toggle and notify are important, as the state has
  55.  * to be set when we call the notify proc.
  56.  */
  57.  
  58. static char defaultTranslations[] =
  59.     "<EnterWindow>:        highlight(Always)    \n\
  60.      <LeaveWindow>:        unhighlight()    \n\
  61.      <Btn1Down>,<Btn1Up>:   toggle() notify()";
  62.  
  63. #define offset(field) XtOffsetOf(ToggleRec, field)
  64.  
  65. static XtResource resources[] = { 
  66.    {XtNstate, XtCState, XtRBoolean, sizeof(Boolean), 
  67.       offset(command.set), XtRString, "off"},
  68.    {XtNradioGroup, XtCWidget, XtRWidget, sizeof(Widget), 
  69.       offset(toggle.widget), XtRWidget, (XtPointer) NULL },
  70.    {XtNradioData, XtCRadioData, XtRPointer, sizeof(XtPointer), 
  71.       offset(toggle.radio_data), XtRPointer, (XtPointer) NULL },
  72. };
  73.  
  74. #undef offset
  75.  
  76.  
  77. static void Toggle(), Initialize(), Notify(), ToggleSet();
  78. static void ToggleDestroy(), ClassInit();
  79. static Boolean SetValues();
  80.  
  81. /* Functions for handling the Radio Group. */
  82.  
  83. static RadioGroup * GetRadioGroup();
  84. static void CreateRadioGroup(), AddToRadioGroup(), TurnOffRadioSiblings();
  85. static void RemoveFromRadioGroup();
  86.  
  87. static XtActionsRec actionsList[] =
  88. {
  89.   {"toggle",            Toggle},
  90.   {"notify",            Notify},
  91.   {"set",            ToggleSet},
  92. };
  93.  
  94. #define SuperClass ((CommandWidgetClass)&commandClassRec)
  95.  
  96. ToggleClassRec toggleClassRec = {
  97.   {
  98.     (WidgetClass) SuperClass,        /* superclass          */    
  99.     "Toggle",                /* class_name          */
  100.     sizeof(ToggleRec),            /* size              */
  101.     ClassInit,                /* class_initialize      */
  102.     NULL,                /* class_part_initialize  */
  103.     FALSE,                /* class_inited          */
  104.     Initialize,                /* initialize          */
  105.     NULL,                /* initialize_hook      */
  106.     XtInheritRealize,            /* realize          */
  107.     actionsList,            /* actions          */
  108.     XtNumber(actionsList),        /* num_actions          */
  109.     resources,                /* resources          */
  110.     XtNumber(resources),        /* resource_count      */
  111.     NULLQUARK,                /* xrm_class          */
  112.     FALSE,                /* compress_motion      */
  113.     TRUE,                /* compress_exposure      */
  114.     TRUE,                /* compress_enterleave    */
  115.     FALSE,                /* visible_interest      */
  116.     NULL,                     /* destroy          */
  117.     XtInheritResize,            /* resize          */
  118.     XtInheritExpose,            /* expose          */
  119.     SetValues,                /* set_values          */
  120.     NULL,                /* set_values_hook      */
  121.     XtInheritSetValuesAlmost,        /* set_values_almost      */
  122.     NULL,                /* get_values_hook      */
  123.     NULL,                /* accept_focus          */
  124.     XtVersion,                /* version          */
  125.     NULL,                /* callback_private      */
  126.     defaultTranslations,        /* tm_table          */
  127.     XtInheritQueryGeometry,        /* query_geometry      */
  128.     XtInheritDisplayAccelerator,    /* display_accelerator      */
  129.     NULL                /* extension          */
  130.   },  /* CoreClass fields initialization */
  131.   {
  132.     XtInheritChangeSensitive        /* change_sensitive      */ 
  133.   },  /* SimpleClass fields initialization */
  134.   {
  135.     0                                     /* field not used    */
  136.   },  /* LabelClass fields initialization */
  137.   {
  138.     0                                     /* field not used    */
  139.   },  /* CommmandClass fields initialization */
  140.   {
  141.       NULL,                    /* Set Procedure. */
  142.       NULL,                    /* Unset Procedure. */
  143.       NULL                    /* extension. */
  144.   }  /* ToggleClass fields initialization */
  145. };
  146.  
  147.   /* for public consumption */
  148. WidgetClass toggleWidgetClass = (WidgetClass) &toggleClassRec;
  149.  
  150. /****************************************************************
  151.  *
  152.  * Private Procedures
  153.  *
  154.  ****************************************************************/
  155.  
  156. static void
  157. ClassInit()
  158. {
  159.   XtActionList actions;
  160.   Cardinal num_actions;
  161.   Cardinal i;
  162.   ToggleWidgetClass class = (ToggleWidgetClass) toggleWidgetClass;
  163.   static XtConvertArgRec parentCvtArgs[] = {
  164.       {XtBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.parent),
  165.        sizeof(Widget)}
  166.   };
  167.  
  168.   XawInitializeWidgetSet();
  169.   XtSetTypeConverter(XtRString, XtRWidget, XmuNewCvtStringToWidget,
  170.              parentCvtArgs, XtNumber(parentCvtArgs), XtCacheNone,
  171.              NULL);
  172. /* 
  173.  * Find the set and unset actions in the command widget's action table. 
  174.  */
  175.  
  176.   XtGetActionList(commandWidgetClass, &actions, &num_actions);
  177.  
  178.   for (i = 0 ; i < num_actions ; i++) {
  179.     if (streq(actions[i].string, "set"))
  180.     class->toggle_class.Set = actions[i].proc;
  181.     if (streq(actions[i].string, "unset")) 
  182.     class->toggle_class.Unset = actions[i].proc;
  183.  
  184.     if ( (class->toggle_class.Set != NULL) &&
  185.      (class->toggle_class.Unset != NULL) ) {
  186.     XtFree((char *) actions);
  187.     return;
  188.     }
  189.   }  
  190.  
  191. /* We should never get here. */
  192.   XtError("Aborting, due to errors resolving bindings in the Toggle widget.");
  193. }
  194.  
  195. static void Initialize(request, new)
  196.  Widget request, new;
  197. {
  198.     ToggleWidget tw = (ToggleWidget) new;
  199.     ToggleWidget tw_req = (ToggleWidget) request;
  200.  
  201.     tw->toggle.radio_group = NULL;
  202.  
  203.     if (tw->toggle.radio_data == NULL) 
  204.       tw->toggle.radio_data = (XtPointer) new->core.name;
  205.  
  206.     if (tw->toggle.widget != NULL) {
  207.       if ( GetRadioGroup(tw->toggle.widget) == NULL) 
  208.     CreateRadioGroup(new, tw->toggle.widget);
  209.       else
  210.     AddToRadioGroup( GetRadioGroup(tw->toggle.widget), new);
  211.     }      
  212.     XtAddCallback(new, XtNdestroyCallback, ToggleDestroy, NULL);
  213.  
  214. /*
  215.  * Command widget assumes that the widget is unset, so we only 
  216.  * have to handle the case where it needs to be set.
  217.  *
  218.  * If this widget is in a radio group then it may cause another
  219.  * widget to be unset, thus calling the notify proceedure.
  220.  *
  221.  * I want to set the toggle if the user set the state to "On" in 
  222.  * the resource group, reguardless of what my ancestors did.
  223.  */
  224.  
  225.     if (tw_req->command.set)
  226.       ToggleSet(new, NULL, NULL, 0);
  227. }
  228.  
  229. /************************************************************
  230.  *
  231.  *  Action Procedures
  232.  *
  233.  ************************************************************/
  234.  
  235. /* ARGSUSED */
  236. static void 
  237. ToggleSet(w,event,params,num_params)
  238. Widget w;
  239. XEvent *event;
  240. String *params;        /* unused */
  241. Cardinal *num_params;    /* unused */
  242. {
  243.     ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class;
  244.  
  245.     TurnOffRadioSiblings(w);
  246.     class->toggle_class.Set(w, event, NULL, 0);
  247. }
  248.  
  249. /* ARGSUSED */
  250. static void 
  251. Toggle(w,event,params,num_params)
  252. Widget w;
  253. XEvent *event;
  254. String *params;        /* unused */
  255. Cardinal *num_params;    /* unused */
  256. {
  257.   ToggleWidget tw = (ToggleWidget)w;
  258.   ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class;
  259.  
  260.   if (tw->command.set) 
  261.     class->toggle_class.Unset(w, event, NULL, 0);
  262.   else 
  263.     ToggleSet(w, event, params, num_params);
  264. }
  265.  
  266. /* ARGSUSED */
  267. static void Notify(w,event,params,num_params)
  268. Widget w;
  269. XEvent *event;
  270. String *params;        /* unused */
  271. Cardinal *num_params;    /* unused */
  272. {
  273.   ToggleWidget tw = (ToggleWidget) w;
  274.   XtCallCallbacks(w, XtNcallback, (XtPointer) tw->command.set);
  275. }
  276.  
  277. /************************************************************
  278.  *
  279.  * Set specified arguments into widget
  280.  *
  281.  ***********************************************************/
  282.  
  283. /* ARGSUSED */
  284. static Boolean 
  285. SetValues (current, request, new)
  286. Widget current, request, new;
  287. {
  288.     ToggleWidget oldtw = (ToggleWidget) current;
  289.     ToggleWidget tw = (ToggleWidget) new;
  290.     ToggleWidget rtw = (ToggleWidget) request;
  291.  
  292.     if (oldtw->toggle.widget != tw->toggle.widget)
  293.       XawToggleChangeRadioGroup(new, tw->toggle.widget);
  294.  
  295.     if (!tw->core.sensitive && oldtw->core.sensitive && rtw->command.set)
  296.     tw->command.set = True;
  297.  
  298.     if (oldtw->command.set != tw->command.set) {
  299.     tw->command.set = oldtw->command.set;
  300.     Toggle(new, NULL, NULL, 0); /* Does a redisplay. */
  301.     }
  302.     return(FALSE);
  303. }
  304.  
  305. /*    Function Name: ToggleDestroy
  306.  *    Description: Destroy Callback for toggle widget.
  307.  *    Arguments: w - the toggle widget that is being destroyed.
  308.  *                 junk, grabage - not used.
  309.  *    Returns: none.
  310.  */
  311.  
  312. /* ARGSUSED */
  313. static void
  314. ToggleDestroy(w, junk, garbage)
  315. Widget w;
  316. XtPointer junk, garbage;
  317. {
  318.   RemoveFromRadioGroup(w);
  319. }
  320.  
  321. /************************************************************
  322.  *
  323.  * Below are all the private proceedures that handle 
  324.  * radio toggle buttons.
  325.  *
  326.  ************************************************************/
  327.  
  328. /*    Function Name: GetRadioGroup
  329.  *    Description: Gets the radio group associated with a give toggle
  330.  *                   widget.
  331.  *    Arguments: w - the toggle widget who's radio group we are getting.
  332.  *    Returns: the radio group associated with this toggle group.
  333.  */
  334.  
  335. static RadioGroup *
  336. GetRadioGroup(w)
  337. Widget w;
  338. {
  339.   ToggleWidget tw = (ToggleWidget) w;
  340.  
  341.   if (tw == NULL) return(NULL);
  342.   return( tw->toggle.radio_group );
  343. }
  344.  
  345. /*    Function Name: CreateRadioGroup
  346.  *    Description: Creates a radio group. give two widgets.
  347.  *    Arguments: w1, w2 - the toggle widgets to add to the radio group.
  348.  *    Returns: none.
  349.  * 
  350.  *      NOTE:  A pointer to the group is added to each widget's radio_group
  351.  *             field.
  352.  */
  353.  
  354. static void
  355. CreateRadioGroup(w1, w2)
  356. Widget w1, w2;
  357. {
  358.   char error_buf[BUFSIZ];
  359.   ToggleWidget tw1 = (ToggleWidget) w1;
  360.   ToggleWidget tw2 = (ToggleWidget) w2;
  361.  
  362.   if ( (tw1->toggle.radio_group != NULL) || (tw2->toggle.radio_group != NULL) ) {
  363.     sprintf(error_buf, "%s %s", "Toggle Widget Error - Attempting",
  364.         "to create a new toggle group, when one already exists.");
  365.     XtWarning(error_buf);
  366.   }
  367.  
  368.   AddToRadioGroup( NULL, w1 );
  369.   AddToRadioGroup( GetRadioGroup(w1), w2 );
  370. }
  371.  
  372. /*    Function Name: AddToRadioGroup
  373.  *    Description: Adds a toggle to the radio group.
  374.  *    Arguments: group - any element of the radio group the we are adding to.
  375.  *                 w - the new toggle widget to add to the group.
  376.  *    Returns: none.
  377.  */
  378.  
  379. static void
  380. AddToRadioGroup(group, w)
  381. RadioGroup * group;
  382. Widget w;
  383. {
  384.   ToggleWidget tw = (ToggleWidget) w;
  385.   RadioGroup * local;
  386.  
  387.   local = (RadioGroup *) XtMalloc( sizeof(RadioGroup) );
  388.   local->widget = w;
  389.   tw->toggle.radio_group = local;
  390.  
  391.   if (group == NULL) {        /* Creating new group. */
  392.     group = local;
  393.     group->next = NULL;
  394.     group->prev = NULL;
  395.     return;
  396.   }
  397.   local->prev = group;        /* Adding to previous group. */
  398.   if ((local->next = group->next) != NULL)
  399.       local->next->prev = local;
  400.   group->next = local;
  401. }
  402.  
  403. /*    Function Name: TurnOffRadioSiblings
  404.  *    Description: Deactivates all radio siblings.
  405.  *    Arguments: widget - a toggle widget.
  406.  *    Returns: none.
  407.  */
  408.  
  409. static void
  410. TurnOffRadioSiblings(w)
  411. Widget w;
  412. {
  413.   RadioGroup * group;
  414.   ToggleWidgetClass class = (ToggleWidgetClass) w->core.widget_class;
  415.  
  416.   if ( (group = GetRadioGroup(w)) == NULL)  /* Punt if there is no group */
  417.     return;
  418.  
  419.   /* Go to the top of the group. */
  420.  
  421.   for ( ; group->prev != NULL ; group = group->prev );
  422.  
  423.   while ( group != NULL ) {
  424.     ToggleWidget local_tog = (ToggleWidget) group->widget;
  425.     if ( local_tog->command.set ) {
  426.       class->toggle_class.Unset(group->widget, NULL, NULL, 0);
  427.       Notify( group->widget, NULL, NULL, 0);
  428.     }
  429.     group = group->next;
  430.   }
  431. }
  432.  
  433. /*    Function Name: RemoveFromRadioGroup
  434.  *    Description: Removes a toggle from a RadioGroup.
  435.  *    Arguments: w - the toggle widget to remove.
  436.  *    Returns: none.
  437.  */
  438.  
  439. static void
  440. RemoveFromRadioGroup(w)
  441. Widget w;
  442. {
  443.   RadioGroup * group = GetRadioGroup(w);
  444.   if (group != NULL) {
  445.     if (group->prev != NULL)
  446.       (group->prev)->next = group->next;
  447.     if (group->next != NULL)
  448.       (group->next)->prev = group->prev;
  449.     XtFree((char *) group);
  450.   }
  451. }
  452.  
  453. /************************************************************
  454.  *
  455.  * Public Routines
  456.  *
  457.  ************************************************************/
  458.    
  459. /*    Function Name: XawToggleChangeRadioGroup
  460.  *    Description: Allows a toggle widget to change radio groups.
  461.  *    Arguments: w - The toggle widget to change groups.
  462.  *                 radio_group - any widget in the new group.
  463.  *    Returns: none.
  464.  */
  465.  
  466. void
  467. #if NeedFunctionPrototypes
  468. XawToggleChangeRadioGroup(Widget w, Widget radio_group)
  469. #else
  470. XawToggleChangeRadioGroup(w, radio_group)
  471. Widget w, radio_group;
  472. #endif
  473. {
  474.   ToggleWidget tw = (ToggleWidget) w;
  475.   RadioGroup * group;
  476.  
  477.   RemoveFromRadioGroup(w);
  478.  
  479. /*
  480.  * If the toggle that we are about to add is set then we will 
  481.  * unset all toggles in the new radio group.
  482.  */
  483.  
  484.   if ( tw->command.set && radio_group != NULL )
  485.     XawToggleUnsetCurrent(radio_group);
  486.  
  487.   if (radio_group != NULL)
  488.       if ((group = GetRadioGroup(radio_group)) == NULL)
  489.       CreateRadioGroup(w, radio_group);
  490.       else AddToRadioGroup(group, w);
  491. }
  492.  
  493. /*    Function Name: XawToggleGetCurrent
  494.  *    Description: Returns the RadioData associated with the toggle
  495.  *                   widget that is currently active in a toggle group.
  496.  *    Arguments: w - any toggle widget in the toggle group.
  497.  *    Returns: The XtNradioData associated with the toggle widget.
  498.  */
  499.  
  500. XtPointer
  501. #if NeedFunctionPrototypes
  502. XawToggleGetCurrent(Widget w)
  503. #else
  504. XawToggleGetCurrent(w)
  505. Widget w;
  506. #endif
  507. {
  508.   RadioGroup * group;
  509.  
  510.   if ( (group = GetRadioGroup(w)) == NULL) return(NULL);
  511.   for ( ; group->prev != NULL ; group = group->prev);
  512.  
  513.   while ( group != NULL ) {
  514.     ToggleWidget local_tog = (ToggleWidget) group->widget;
  515.     if ( local_tog->command.set )
  516.       return( local_tog->toggle.radio_data );
  517.     group = group->next;
  518.   }
  519.   return(NULL);
  520. }
  521.  
  522. /*    Function Name: XawToggleSetCurrent
  523.  *    Description: Sets the Toggle widget associated with the
  524.  *                   radio_data specified.
  525.  *    Arguments: radio_group - any toggle widget in the toggle group.
  526.  *                 radio_data - radio data of the toggle widget to set.
  527.  *    Returns: none.
  528.  */
  529.  
  530. void
  531. #if NeedFunctionPrototypes
  532. XawToggleSetCurrent(Widget radio_group, XtPointer radio_data)
  533. #else
  534. XawToggleSetCurrent(radio_group, radio_data)
  535. Widget radio_group;
  536. XtPointer radio_data;
  537. #endif
  538. {
  539.   RadioGroup * group;
  540.   ToggleWidget local_tog; 
  541.  
  542. /* Special case case of no radio group. */
  543.  
  544.   if ( (group = GetRadioGroup(radio_group)) == NULL) {
  545.     local_tog = (ToggleWidget) radio_group;
  546.     if ( (local_tog->toggle.radio_data == radio_data) )     
  547.       if (!local_tog->command.set) {
  548.     ToggleSet((Widget) local_tog, NULL, NULL, 0);
  549.     Notify((Widget) local_tog, NULL, NULL, 0);
  550.       }
  551.     return;
  552.   }
  553.  
  554. /*
  555.  * find top of radio_roup 
  556.  */
  557.  
  558.   for ( ; group->prev != NULL ; group = group->prev);
  559.  
  560. /*
  561.  * search for matching radio data.
  562.  */
  563.  
  564.   while ( group != NULL ) {
  565.     local_tog = (ToggleWidget) group->widget;
  566.     if ( (local_tog->toggle.radio_data == radio_data) ) {
  567.       if (!local_tog->command.set) { /* if not already set. */
  568.     ToggleSet((Widget) local_tog, NULL, NULL, 0);
  569.     Notify((Widget) local_tog, NULL, NULL, 0);
  570.       }
  571.       return;            /* found it, done */
  572.     }
  573.     group = group->next;
  574.   }
  575. }
  576.  
  577. /*    Function Name: XawToggleUnsetCurrent
  578.  *    Description: Unsets all Toggles in the radio_group specified.
  579.  *    Arguments: radio_group - any toggle widget in the toggle group.
  580.  *    Returns: none.
  581.  */
  582.  
  583. void
  584. #if NeedFunctionPrototypes
  585. XawToggleUnsetCurrent(Widget radio_group)
  586. #else
  587. XawToggleUnsetCurrent(radio_group)
  588. Widget radio_group;
  589. #endif
  590. {
  591.   ToggleWidgetClass class;
  592.   ToggleWidget local_tog = (ToggleWidget) radio_group;
  593.  
  594.   /* Special Case no radio group. */
  595.  
  596.   if (local_tog->command.set) {
  597.     class = (ToggleWidgetClass) local_tog->core.widget_class;
  598.     class->toggle_class.Unset(radio_group, NULL, NULL, 0);
  599.     Notify(radio_group, NULL, NULL, 0);
  600.   }
  601.   if ( GetRadioGroup(radio_group) == NULL) return;
  602.   TurnOffRadioSiblings(radio_group);
  603. }
  604.